Spaces:
Running
Running
File size: 3,314 Bytes
66b7a93 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | /**
* finnhubAPI.js
* Fetches historical OHLCV candles and live quotes from Finnhub REST API
* via Vite dev proxy.
*/
const FINNHUB_BASE = '/api/finnhub/api/v1';
const FINNHUB_API_KEY = 'd7aejfpr01qn9i7kleugd7aejfpr01qn9i7klev0';
/**
* Maps local symbol names to Finnhub's expected symbol format.
*/
export const FINNHUB_SYMBOL_MAP = {
XAUUSD: 'OANDA:XAU_USD',
GBPUSD: 'OANDA:GBP_USD',
EURUSD: 'OANDA:EUR_USD',
USDCAD: 'OANDA:USD_CAD',
};
/**
* Fetch historical OHLCV candles from Finnhub.
*
* @param {string} symbol - Local symbol key, e.g. 'XAUUSD'
* @param {string} resolution - Candle resolution: '1','5','15','60','240','D'
* @param {number} from - Start unix timestamp (seconds)
* @param {number} to - End unix timestamp (seconds)
* @returns {Promise<Array<{time:number, open:number, high:number, low:number, close:number, volume:number}>>}
*/
export async function fetchCandles(symbol, resolution, from, to) {
const finnhubSymbol = FINNHUB_SYMBOL_MAP[symbol] ?? symbol;
const params = new URLSearchParams({
symbol: finnhubSymbol,
resolution,
from: String(Math.floor(from)),
to: String(Math.floor(to)),
token: FINNHUB_API_KEY,
});
const url = `${FINNHUB_BASE}/forex/candle?${params}`;
let response;
try {
response = await fetch(url);
} catch (err) {
console.error(`[finnhubAPI] Network error fetching candles for ${symbol}:`, err);
throw new Error(`Network error fetching Finnhub candles: ${err.message}`);
}
if (!response.ok) {
const body = await response.text().catch(() => '');
console.error(`[finnhubAPI] HTTP ${response.status} for ${symbol}:`, body);
throw new Error(`Finnhub API error ${response.status}: ${body}`);
}
const data = await response.json();
if (data.s === 'no_data' || !data.t || data.t.length === 0) {
console.warn(`[finnhubAPI] No data returned for ${symbol} (${resolution})`);
return [];
}
// Zip the parallel arrays into an array of candle objects
return data.t.map((timestamp, i) => ({
time: timestamp,
open: data.o[i],
high: data.h[i],
low: data.l[i],
close: data.c[i],
volume: data.v[i],
}));
}
/**
* Fetch a real-time quote for the given symbol.
*
* @param {string} symbol - Local symbol key, e.g. 'XAUUSD'
* @returns {Promise<{current:number, high:number, low:number, open:number, prevClose:number}>}
*/
export async function fetchQuote(symbol) {
const finnhubSymbol = FINNHUB_SYMBOL_MAP[symbol] ?? symbol;
const params = new URLSearchParams({
symbol: finnhubSymbol,
token: FINNHUB_API_KEY,
});
const url = `${FINNHUB_BASE}/quote?${params}`;
let response;
try {
response = await fetch(url);
} catch (err) {
console.error(`[finnhubAPI] Network error fetching quote for ${symbol}:`, err);
throw new Error(`Network error fetching Finnhub quote: ${err.message}`);
}
if (!response.ok) {
const body = await response.text().catch(() => '');
console.error(`[finnhubAPI] HTTP ${response.status} for quote ${symbol}:`, body);
throw new Error(`Finnhub quote API error ${response.status}: ${body}`);
}
const q = await response.json();
return {
current: q.c,
high: q.h,
low: q.l,
open: q.o,
prevClose: q.pc,
};
}
|