chart data loading

This commit is contained in:
2026-03-24 21:37:49 -04:00
parent f6bd22a8ef
commit c76887ab92
65 changed files with 6350 additions and 713 deletions

View File

@@ -2,10 +2,12 @@
import ccxt from 'ccxt';
export class CCXTFetcher {
constructor(config, logger) {
constructor(config, logger, metadataGenerator = null) {
this.config = config;
this.logger = logger;
this.exchanges = new Map();
this.metadataGenerator = metadataGenerator;
this.metadataCache = new Map(); // Cache metadata by ticker
}
/**
@@ -24,6 +26,41 @@ export class CCXTFetcher {
};
}
/**
* Get metadata for a ticker (cached or generate on-the-fly)
*/
async getMetadata(ticker) {
// Check cache first
if (this.metadataCache.has(ticker)) {
return this.metadataCache.get(ticker);
}
// Generate metadata on-the-fly
if (!this.metadataGenerator) {
throw new Error('Metadata generator not available');
}
const { exchange: exchangeName, symbol } = this.parseTicker(ticker);
const exchangeUpper = exchangeName.toUpperCase();
const exchange = this.getExchange(exchangeName);
// Load market info from CCXT
await exchange.loadMarkets();
const market = exchange.market(symbol);
if (!market) {
throw new Error(`Market not found: ${symbol} on ${exchangeUpper}`);
}
// Convert to our metadata format
const metadata = this.metadataGenerator.convertMarketToMetadata(exchangeUpper, symbol, market);
// Cache it
this.metadataCache.set(ticker, metadata);
return metadata;
}
/**
* Get or create CCXT exchange instance
*/
@@ -123,8 +160,11 @@ export class CCXTFetcher {
}
}
// Get metadata for proper denomination
const metadata = await this.getMetadata(ticker);
// Convert to our OHLC format
return allCandles.map(candle => this.convertToOHLC(candle, ticker, periodSeconds));
return allCandles.map(candle => this.convertToOHLC(candle, ticker, periodSeconds, metadata));
}
/**
@@ -148,8 +188,11 @@ export class CCXTFetcher {
'Fetched recent trades'
);
// Get metadata for proper denomination
const metadata = await this.getMetadata(ticker);
// Convert to our Tick format
return trades.map(trade => this.convertToTick(trade, ticker));
return trades.map(trade => this.convertToTick(trade, ticker, metadata));
} catch (error) {
this.logger.error(
{ error: error.message, ticker },
@@ -162,21 +205,23 @@ export class CCXTFetcher {
/**
* Convert CCXT OHLCV array to our OHLC format
* CCXT format: [timestamp, open, high, low, close, volume]
* Uses denominators from market metadata for proper integer representation
*/
convertToOHLC(candle, ticker, periodSeconds) {
convertToOHLC(candle, ticker, periodSeconds, metadata) {
const [timestamp, open, high, low, close, volume] = candle;
// Convert to fixed-point integers (using 8 decimal places = 10^8)
const DENOM = 100000000;
// Use denominators from metadata
const tickDenom = metadata.tickDenom || 100;
const baseDenom = metadata.baseDenom || 100000000;
return {
ticker,
timestamp: (timestamp * 1000).toString(), // Convert ms to microseconds
open: Math.round(open * DENOM).toString(),
high: Math.round(high * DENOM).toString(),
low: Math.round(low * DENOM).toString(),
close: Math.round(close * DENOM).toString(),
volume: Math.round(volume * DENOM).toString(),
open: Math.round(open * tickDenom).toString(),
high: Math.round(high * tickDenom).toString(),
low: Math.round(low * tickDenom).toString(),
close: Math.round(close * tickDenom).toString(),
volume: Math.round(volume * baseDenom).toString(),
open_time: (timestamp * 1000).toString(),
close_time: ((timestamp + periodSeconds * 1000) * 1000).toString()
};
@@ -184,14 +229,17 @@ export class CCXTFetcher {
/**
* Convert CCXT trade to our Tick format
* Uses denominators from market metadata for proper integer representation
*/
convertToTick(trade, ticker) {
// Convert to fixed-point integers (using 8 decimal places = 10^8)
const DENOM = 100000000;
convertToTick(trade, ticker, metadata) {
// Use denominators from metadata
const tickDenom = metadata.tickDenom || 100;
const baseDenom = metadata.baseDenom || 100000000;
const quoteDenom = metadata.quoteDenom || tickDenom;
const price = Math.round(trade.price * DENOM);
const amount = Math.round(trade.amount * DENOM);
const quoteAmount = Math.round((trade.price * trade.amount) * DENOM);
const price = Math.round(trade.price * tickDenom);
const amount = Math.round(trade.amount * baseDenom);
const quoteAmount = Math.round((trade.price * trade.amount) * quoteDenom);
return {
trade_id: trade.id || `${trade.timestamp}`,