Fixes tradingview/charting_library#60 Fixes tradingview/charting_library#65 Fixes tradingview/charting_library#70 Fixes tradingview/charting_library#71 Fixes tradingview/charting_library#75 Fixes tradingview/charting_library#76 Fixes tradingview/charting_library#78 Fixes tradingview/charting_library#79 Fixes tradingview/charting_library#81 Fixes tradingview/charting_library#82 Fixes tradingview/charting_library#84 Fixes tradingview/charting_library#86 Fixes tradingview/charting_library#89 Fixes tradingview/charting_library#90 Fixes tradingview/charting_library#91 Fixes tradingview/charting_library#92 Fixes tradingview/charting_library#94 Fixes tradingview/charting_library#99 Fixes tradingview/charting_library#100 Fixes tradingview/charting_library#101 Fixes tradingview/charting_library#102 Fixes tradingview/charting_library#103 Fixes tradingview/charting_library#1995 Fixes tradingview/charting_library#5726 Fixes tradingview/charting_library#6025 Fixes tradingview/charting_library#6406 Fixes tradingview/charting_library#6636 Fixes tradingview/charting_library#6767 Fixes tradingview/charting_library#6775 Fixes tradingview/charting_library#6783 Fixes tradingview/charting_library#6864 Fixes tradingview/charting_library#6926 Fixes tradingview/charting_library#7060 Fixes tradingview/charting_library#7169 Fixes tradingview/charting_library#7307
124 lines
5.1 KiB
JavaScript
124 lines
5.1 KiB
JavaScript
import { getErrorMessage, } from './helpers';
|
|
export class HistoryProvider {
|
|
constructor(datafeedUrl, requester, limitedServerResponse) {
|
|
this._datafeedUrl = datafeedUrl;
|
|
this._requester = requester;
|
|
this._limitedServerResponse = limitedServerResponse;
|
|
}
|
|
getBars(symbolInfo, resolution, periodParams) {
|
|
const requestParams = {
|
|
symbol: symbolInfo.ticker || '',
|
|
resolution: resolution,
|
|
from: periodParams.from,
|
|
to: periodParams.to,
|
|
};
|
|
if (periodParams.countBack !== undefined) {
|
|
requestParams.countback = periodParams.countBack;
|
|
}
|
|
if (symbolInfo.currency_code !== undefined) {
|
|
requestParams.currencyCode = symbolInfo.currency_code;
|
|
}
|
|
if (symbolInfo.unit_id !== undefined) {
|
|
requestParams.unitId = symbolInfo.unit_id;
|
|
}
|
|
return new Promise(async (resolve, reject) => {
|
|
try {
|
|
const initialResponse = await this._requester.sendRequest(this._datafeedUrl, 'history', requestParams);
|
|
const result = this._processHistoryResponse(initialResponse);
|
|
if (this._limitedServerResponse) {
|
|
await this._processTruncatedResponse(result, requestParams);
|
|
}
|
|
resolve(result);
|
|
}
|
|
catch (e) {
|
|
if (e instanceof Error || typeof e === 'string') {
|
|
const reasonString = getErrorMessage(e);
|
|
// tslint:disable-next-line:no-console
|
|
console.warn(`HistoryProvider: getBars() failed, error=${reasonString}`);
|
|
reject(reasonString);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
async _processTruncatedResponse(result, requestParams) {
|
|
let lastResultLength = result.bars.length;
|
|
try {
|
|
while (this._limitedServerResponse &&
|
|
this._limitedServerResponse.maxResponseLength > 0 &&
|
|
this._limitedServerResponse.maxResponseLength === lastResultLength &&
|
|
requestParams.from < requestParams.to) {
|
|
// adjust request parameters for follow-up request
|
|
if (requestParams.countback) {
|
|
requestParams.countback = requestParams.countback - lastResultLength;
|
|
}
|
|
if (this._limitedServerResponse.expectedOrder === 'earliestFirst') {
|
|
requestParams.from = Math.round(result.bars[result.bars.length - 1].time / 1000);
|
|
}
|
|
else {
|
|
requestParams.to = Math.round(result.bars[0].time / 1000);
|
|
}
|
|
const followupResponse = await this._requester.sendRequest(this._datafeedUrl, 'history', requestParams);
|
|
const followupResult = this._processHistoryResponse(followupResponse);
|
|
lastResultLength = followupResult.bars.length;
|
|
// merge result with results collected so far
|
|
if (this._limitedServerResponse.expectedOrder === 'earliestFirst') {
|
|
result.bars.push(...followupResult.bars);
|
|
}
|
|
else {
|
|
result.bars.unshift(...followupResult.bars);
|
|
}
|
|
}
|
|
}
|
|
catch (e) {
|
|
/**
|
|
* Error occurred during followup request. We won't reject the original promise
|
|
* because the initial response was valid so we will return what we've got so far.
|
|
*/
|
|
if (e instanceof Error || typeof e === 'string') {
|
|
const reasonString = getErrorMessage(e);
|
|
// tslint:disable-next-line:no-console
|
|
console.warn(`HistoryProvider: getBars() warning during followup request, error=${reasonString}`);
|
|
}
|
|
}
|
|
}
|
|
_processHistoryResponse(response) {
|
|
if (response.s !== 'ok' && response.s !== 'no_data') {
|
|
throw new Error(response.errmsg);
|
|
}
|
|
const bars = [];
|
|
const meta = {
|
|
noData: false,
|
|
};
|
|
if (response.s === 'no_data') {
|
|
meta.noData = true;
|
|
meta.nextTime = response.nextTime;
|
|
}
|
|
else {
|
|
const volumePresent = response.v !== undefined;
|
|
const ohlPresent = response.o !== undefined;
|
|
for (let i = 0; i < response.t.length; ++i) {
|
|
const barValue = {
|
|
time: response.t[i] * 1000,
|
|
close: parseFloat(response.c[i]),
|
|
open: parseFloat(response.c[i]),
|
|
high: parseFloat(response.c[i]),
|
|
low: parseFloat(response.c[i]),
|
|
};
|
|
if (ohlPresent) {
|
|
barValue.open = parseFloat(response.o[i]);
|
|
barValue.high = parseFloat(response.h[i]);
|
|
barValue.low = parseFloat(response.l[i]);
|
|
}
|
|
if (volumePresent) {
|
|
barValue.volume = parseFloat(response.v[i]);
|
|
}
|
|
bars.push(barValue);
|
|
}
|
|
}
|
|
return {
|
|
bars: bars,
|
|
meta: meta,
|
|
};
|
|
}
|
|
}
|