function normalizeCandleTime(candle: Candle): Candle {
return {
...candle,
time: Math.floor(
candle.time > 1e10 ? candle.time / 1000 : candle.time,
),
};
}
public getDataSource =
(
indicativeData?: ChartIndicativeData,
cb?: (timeframe: Timeframes) => void,
) =>
async (
timeframe: Timeframes,
symbolId: string,
until?: Candle,
): Promise<Candle[] | null> => {
const symbol = getRequestSymbol(symbolId);
if (!symbol) {
return null;
}
cb?.(timeframe);
const interval = moexChartTimeConverter(timeframe);
const cursor = until ? normalizeCandleTime(until) : undefined;
const countBack = 2000;
const to = cursor
? cursor.time - 1
: Math.floor(Date.now() / 1000);
const from = Math.max(
0,
to - countBack * getTimeframeSeconds(timeframe),
);
const data = await requestBars({
currencyPair: symbol.replaceAll(':', '.'),
interval,
periodParams: {
firstDataRequest: !cursor,
from,
to,
countBack,
},
ticker: symbol,
indicativeData,
});
const validData = data
.map(normalizeCandleTime)
.filter(isValidCandle)
.filter((candle) => !cursor || candle.time < cursor.time)
.sort((first, second) => first.time - second.time);
if (validData.length === 0) {
return null;
}
if (moexChartToIssTimeframe(timeframe) === timeframe) {
if (!until) {
const lastCandle = validData.at(-1);
this.realtimeStates.set(symbol, {
previousTime: lastCandle?.time ?? null,
candles: lastCandle ? [lastCandle] : [],
sessionStart: null,
});
}
return validData;
}
const { candles, state } = timeframeConvolution(
validData,
timeframe,
);
if (!until) {
this.realtimeStates.set(symbol, state);
}
return candles;
};
private async updateRealtimeSymbol(
symbolId: string,
timeframe: Timeframes,
update: (symbolId: string, candle: Candle) => void,
indicativeData?: ChartIndicativeData,
): Promise<void> {
const symbol = getRequestSymbol(symbolId);
if (!symbol) {
return;
}
const response = await requestRealtimeBars({
currencyPair: symbol.replaceAll(':', '.'),
interval: moexChartTimeConverter(timeframe),
ticker: symbol,
indicativeData,
});
if (!response) {
return;
}
const data = normalizeCandleTime(response);
if (!isValidCandle(data)) {
return;
}
const currentState = this.realtimeStates.get(symbol) ?? {
previousTime: null,
candles: [],
sessionStart: null,
};
const currentCandle = currentState.candles.find(
(candle) => candle.time === data.time,
);
if (isSameCandle(currentCandle, data)) {
return;
}
if (moexChartToIssTimeframe(timeframe) === timeframe) {
this.realtimeStates.set(symbol, {
previousTime: data.time,
candles: [data],
sessionStart: null,
});
update(symbol, data);
return;
}
const { candle, state } = realtimeConvolution(
timeframe,
data,
currentState,
);
this.realtimeStates.set(symbol, state);
if (candle) {
update(symbol, candle);
}
}