udf-compatible-datafeed-base.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. import { getErrorMessage, logMessage, } from './helpers';
  2. import { HistoryProvider, } from './history-provider';
  3. import { DataPulseProvider } from './data-pulse-provider';
  4. import { QuotesPulseProvider } from './quotes-pulse-provider';
  5. import { SymbolsStorage } from './symbols-storage';
  6. function extractField(data, field, arrayIndex) {
  7. var value = data[field];
  8. return Array.isArray(value) ? value[arrayIndex] : value;
  9. }
  10. /**
  11. * This class implements interaction with UDF-compatible datafeed.
  12. * See UDF protocol reference at https://github.com/tradingview/charting_library/wiki/UDF
  13. */
  14. var UDFCompatibleDatafeedBase = /** @class */ (function () {
  15. function UDFCompatibleDatafeedBase(datafeedURL, quotesProvider, requester, updateFrequency) {
  16. if (updateFrequency === void 0) { updateFrequency = 10 * 1000; }
  17. var _this = this;
  18. this._configuration = defaultConfiguration();
  19. this._symbolsStorage = null;
  20. this._datafeedURL = datafeedURL;
  21. this._requester = requester;
  22. this._historyProvider = new HistoryProvider(datafeedURL, this._requester);
  23. this._quotesProvider = quotesProvider;
  24. this._dataPulseProvider = new DataPulseProvider(this._historyProvider, updateFrequency);
  25. this._quotesPulseProvider = new QuotesPulseProvider(this._quotesProvider);
  26. this._configurationReadyPromise = this._requestConfiguration()
  27. .then(function (configuration) {
  28. if (configuration === null) {
  29. configuration = defaultConfiguration();
  30. }
  31. _this._setupWithConfiguration(configuration);
  32. });
  33. }
  34. UDFCompatibleDatafeedBase.prototype.onReady = function (callback) {
  35. var _this = this;
  36. this._configurationReadyPromise.then(function () {
  37. callback(_this._configuration);
  38. });
  39. };
  40. UDFCompatibleDatafeedBase.prototype.getQuotes = function (symbols, onDataCallback, onErrorCallback) {
  41. this._quotesProvider.getQuotes(symbols).then(onDataCallback).catch(onErrorCallback);
  42. };
  43. UDFCompatibleDatafeedBase.prototype.subscribeQuotes = function (symbols, fastSymbols, onRealtimeCallback, listenerGuid) {
  44. this._quotesPulseProvider.subscribeQuotes(symbols, fastSymbols, onRealtimeCallback, listenerGuid);
  45. };
  46. UDFCompatibleDatafeedBase.prototype.unsubscribeQuotes = function (listenerGuid) {
  47. this._quotesPulseProvider.unsubscribeQuotes(listenerGuid);
  48. };
  49. UDFCompatibleDatafeedBase.prototype.calculateHistoryDepth = function (resolution, resolutionBack, intervalBack) {
  50. return undefined;
  51. };
  52. UDFCompatibleDatafeedBase.prototype.getMarks = function (symbolInfo, from, to, onDataCallback, resolution) {
  53. if (!this._configuration.supports_marks) {
  54. return;
  55. }
  56. var requestParams = {
  57. symbol: symbolInfo.ticker || '',
  58. from: from,
  59. to: to,
  60. resolution: resolution,
  61. };
  62. this._send('marks', requestParams)
  63. .then(function (response) {
  64. if (!Array.isArray(response)) {
  65. var result = [];
  66. for (var i = 0; i < response.id.length; ++i) {
  67. result.push({
  68. id: extractField(response, 'id', i),
  69. time: extractField(response, 'time', i),
  70. color: extractField(response, 'color', i),
  71. text: extractField(response, 'text', i),
  72. label: extractField(response, 'label', i),
  73. labelFontColor: extractField(response, 'labelFontColor', i),
  74. minSize: extractField(response, 'minSize', i),
  75. });
  76. }
  77. response = result;
  78. }
  79. onDataCallback(response);
  80. })
  81. .catch(function (error) {
  82. logMessage("UdfCompatibleDatafeed: Request marks failed: " + getErrorMessage(error));
  83. onDataCallback([]);
  84. });
  85. };
  86. UDFCompatibleDatafeedBase.prototype.getTimescaleMarks = function (symbolInfo, from, to, onDataCallback, resolution) {
  87. if (!this._configuration.supports_timescale_marks) {
  88. return;
  89. }
  90. var requestParams = {
  91. symbol: symbolInfo.ticker || '',
  92. from: from,
  93. to: to,
  94. resolution: resolution,
  95. };
  96. this._send('timescale_marks', requestParams)
  97. .then(function (response) {
  98. if (!Array.isArray(response)) {
  99. var result = [];
  100. for (var i = 0; i < response.id.length; ++i) {
  101. result.push({
  102. id: extractField(response, 'id', i),
  103. time: extractField(response, 'time', i),
  104. color: extractField(response, 'color', i),
  105. label: extractField(response, 'label', i),
  106. tooltip: extractField(response, 'tooltip', i),
  107. });
  108. }
  109. response = result;
  110. }
  111. onDataCallback(response);
  112. })
  113. .catch(function (error) {
  114. logMessage("UdfCompatibleDatafeed: Request timescale marks failed: " + getErrorMessage(error));
  115. onDataCallback([]);
  116. });
  117. };
  118. UDFCompatibleDatafeedBase.prototype.getServerTime = function (callback) {
  119. if (!this._configuration.supports_time) {
  120. return;
  121. }
  122. this._send('time')
  123. .then(function (response) {
  124. var time = parseInt(response);
  125. if (!isNaN(time)) {
  126. callback(time);
  127. }
  128. })
  129. .catch(function (error) {
  130. logMessage("UdfCompatibleDatafeed: Fail to load server time, error=" + getErrorMessage(error));
  131. });
  132. };
  133. UDFCompatibleDatafeedBase.prototype.searchSymbols = function (userInput, exchange, symbolType, onResult) {
  134. if (this._configuration.supports_search) {
  135. var params = {
  136. limit: 30 /* SearchItemsLimit */,
  137. query: userInput.toUpperCase(),
  138. type: symbolType,
  139. exchange: exchange,
  140. };
  141. this._send('search', params)
  142. .then(function (response) {
  143. if (response.s !== undefined) {
  144. logMessage("UdfCompatibleDatafeed: search symbols error=" + response.errmsg);
  145. onResult([]);
  146. return;
  147. }
  148. onResult(response);
  149. })
  150. .catch(function (reason) {
  151. logMessage("UdfCompatibleDatafeed: Search symbols for '" + userInput + "' failed. Error=" + getErrorMessage(reason));
  152. onResult([]);
  153. });
  154. }
  155. else {
  156. if (this._symbolsStorage === null) {
  157. throw new Error('UdfCompatibleDatafeed: inconsistent configuration (symbols storage)');
  158. }
  159. this._symbolsStorage.searchSymbols(userInput, exchange, symbolType, 30 /* SearchItemsLimit */)
  160. .then(onResult)
  161. .catch(onResult.bind(null, []));
  162. }
  163. };
  164. UDFCompatibleDatafeedBase.prototype.resolveSymbol = function (symbolName, onResolve, onError) {
  165. logMessage('Resolve requested');
  166. var resolveRequestStartTime = Date.now();
  167. function onResultReady(symbolInfo) {
  168. logMessage("Symbol resolved: " + (Date.now() - resolveRequestStartTime) + "ms");
  169. onResolve(symbolInfo);
  170. }
  171. if (!this._configuration.supports_group_request) {
  172. var params = {
  173. symbol: symbolName,
  174. };
  175. this._send('symbols', params)
  176. .then(function (response) {
  177. if (response.s !== undefined) {
  178. onError('unknown_symbol');
  179. }
  180. else {
  181. onResultReady(response);
  182. }
  183. })
  184. .catch(function (reason) {
  185. logMessage("UdfCompatibleDatafeed: Error resolving symbol: " + getErrorMessage(reason));
  186. onError('unknown_symbol');
  187. });
  188. }
  189. else {
  190. if (this._symbolsStorage === null) {
  191. throw new Error('UdfCompatibleDatafeed: inconsistent configuration (symbols storage)');
  192. }
  193. this._symbolsStorage.resolveSymbol(symbolName).then(onResultReady).catch(onError);
  194. }
  195. };
  196. UDFCompatibleDatafeedBase.prototype.getBars = function (symbolInfo, resolution, rangeStartDate, rangeEndDate, onResult, onError) {
  197. this._historyProvider.getBars(symbolInfo, resolution, rangeStartDate, rangeEndDate)
  198. .then(function (result) {
  199. onResult(result.bars, result.meta);
  200. })
  201. .catch(onError);
  202. };
  203. UDFCompatibleDatafeedBase.prototype.subscribeBars = function (symbolInfo, resolution, onTick, listenerGuid, onResetCacheNeededCallback) {
  204. this._dataPulseProvider.subscribeBars(symbolInfo, resolution, onTick, listenerGuid);
  205. };
  206. UDFCompatibleDatafeedBase.prototype.unsubscribeBars = function (listenerGuid) {
  207. this._dataPulseProvider.unsubscribeBars(listenerGuid);
  208. };
  209. UDFCompatibleDatafeedBase.prototype._requestConfiguration = function () {
  210. return this._send('config')
  211. .catch(function (reason) {
  212. logMessage("UdfCompatibleDatafeed: Cannot get datafeed configuration - use default, error=" + getErrorMessage(reason));
  213. return null;
  214. });
  215. };
  216. UDFCompatibleDatafeedBase.prototype._send = function (urlPath, params) {
  217. return this._requester.sendRequest(this._datafeedURL, urlPath, params);
  218. };
  219. UDFCompatibleDatafeedBase.prototype._setupWithConfiguration = function (configurationData) {
  220. this._configuration = configurationData;
  221. if (configurationData.exchanges === undefined) {
  222. configurationData.exchanges = [];
  223. }
  224. if (!configurationData.supports_search && !configurationData.supports_group_request) {
  225. throw new Error('Unsupported datafeed configuration. Must either support search, or support group request');
  226. }
  227. if (configurationData.supports_group_request || !configurationData.supports_search) {
  228. this._symbolsStorage = new SymbolsStorage(this._datafeedURL, configurationData.supported_resolutions || [], this._requester);
  229. }
  230. logMessage("UdfCompatibleDatafeed: Initialized with " + JSON.stringify(configurationData));
  231. };
  232. return UDFCompatibleDatafeedBase;
  233. }());
  234. export { UDFCompatibleDatafeedBase };
  235. function defaultConfiguration() {
  236. return {
  237. supports_search: false,
  238. supports_group_request: true,
  239. supported_resolutions: ['1', '5', '15', '30', '60', '1D', '1W', '1M'],
  240. supports_marks: false,
  241. supports_timescale_marks: false,
  242. };
  243. }