@yuants/app-virtual-exchange 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/series-collector/backwards-interest-rate.js +4 -4
  2. package/dist/series-collector/backwards-interest-rate.js.map +1 -1
  3. package/dist/series-collector/backwards-ohlc.js +33 -68
  4. package/dist/series-collector/backwards-ohlc.js.map +1 -1
  5. package/dist/series-collector/discovery.js +30 -1
  6. package/dist/series-collector/discovery.js.map +1 -1
  7. package/dist/series-collector/forwards-interest-rate.js +5 -5
  8. package/dist/series-collector/forwards-interest-rate.js.map +1 -1
  9. package/dist/series-collector/forwards-ohlc.js +33 -68
  10. package/dist/series-collector/forwards-ohlc.js.map +1 -1
  11. package/dist/series-collector/index.js +1 -2
  12. package/dist/series-collector/index.js.map +1 -1
  13. package/dist/series-collector/interest-rate.js +11 -5
  14. package/dist/series-collector/interest-rate.js.map +1 -1
  15. package/dist/series-collector/ohlc.js +49 -0
  16. package/dist/series-collector/ohlc.js.map +1 -0
  17. package/dist/series-collector/patch-interest-rate.js +4 -0
  18. package/dist/series-collector/patch-interest-rate.js.map +1 -1
  19. package/dist/series-collector/patch-ohlc.js +67 -0
  20. package/dist/series-collector/patch-ohlc.js.map +1 -0
  21. package/lib/series-collector/backwards-interest-rate.d.ts.map +1 -1
  22. package/lib/series-collector/backwards-interest-rate.js +4 -4
  23. package/lib/series-collector/backwards-interest-rate.js.map +1 -1
  24. package/lib/series-collector/backwards-ohlc.d.ts +2 -1
  25. package/lib/series-collector/backwards-ohlc.d.ts.map +1 -1
  26. package/lib/series-collector/backwards-ohlc.js +34 -67
  27. package/lib/series-collector/backwards-ohlc.js.map +1 -1
  28. package/lib/series-collector/discovery.d.ts +5 -0
  29. package/lib/series-collector/discovery.d.ts.map +1 -1
  30. package/lib/series-collector/discovery.js +31 -1
  31. package/lib/series-collector/discovery.js.map +1 -1
  32. package/lib/series-collector/forwards-interest-rate.d.ts.map +1 -1
  33. package/lib/series-collector/forwards-interest-rate.js +5 -5
  34. package/lib/series-collector/forwards-interest-rate.js.map +1 -1
  35. package/lib/series-collector/forwards-ohlc.d.ts +2 -1
  36. package/lib/series-collector/forwards-ohlc.d.ts.map +1 -1
  37. package/lib/series-collector/forwards-ohlc.js +34 -67
  38. package/lib/series-collector/forwards-ohlc.js.map +1 -1
  39. package/lib/series-collector/index.d.ts +1 -2
  40. package/lib/series-collector/index.d.ts.map +1 -1
  41. package/lib/series-collector/index.js +1 -2
  42. package/lib/series-collector/index.js.map +1 -1
  43. package/lib/series-collector/interest-rate.js +9 -3
  44. package/lib/series-collector/interest-rate.js.map +1 -1
  45. package/lib/series-collector/ohlc.d.ts +2 -0
  46. package/lib/series-collector/ohlc.d.ts.map +1 -0
  47. package/lib/series-collector/ohlc.js +51 -0
  48. package/lib/series-collector/ohlc.js.map +1 -0
  49. package/lib/series-collector/patch-interest-rate.d.ts.map +1 -1
  50. package/lib/series-collector/patch-interest-rate.js +4 -0
  51. package/lib/series-collector/patch-interest-rate.js.map +1 -1
  52. package/lib/series-collector/patch-ohlc.d.ts +3 -0
  53. package/lib/series-collector/patch-ohlc.d.ts.map +1 -0
  54. package/lib/series-collector/patch-ohlc.js +71 -0
  55. package/lib/series-collector/patch-ohlc.js.map +1 -0
  56. package/package.json +1 -1
@@ -6,6 +6,9 @@ import { Terminal } from '@yuants/protocol';
6
6
  import { decodePath, formatTime, tokenBucket } from '@yuants/utils';
7
7
  import { findInterestRateStartTimeBackward } from './sql-helpers';
8
8
  const terminal = Terminal.fromNodeEnv();
9
+ const ingestCounter = terminal.metrics
10
+ .counter('series_collector_ingest_count', '')
11
+ .labels({ terminal_id: terminal.terminal_id, type: 'interest_rate', task: 'backward' });
9
12
  export const handleIngestInterestRateBackward = async (product_id, meta, signal) => {
10
13
  var _a, _b, _c, _d;
11
14
  const [datasource_id] = decodePath(product_id);
@@ -30,10 +33,7 @@ export const handleIngestInterestRateBackward = async (product_id, meta, signal)
30
33
  }
31
34
  console.info(formatTime(Date.now()), '[SeriesCollector][InterestRate][Backward]', 'Request', `product_id=${req.product_id}, direction=${req.direction}, time=${formatTime(req.time)}`);
32
35
  const res = await terminal.client.requestForResponseData('IngestInterestRate', req);
33
- terminal.metrics
34
- .counter('series_collector_ingest_count', '')
35
- .labels({ terminal_id: terminal.terminal_id, type: 'interest_rate', task: 'backward' })
36
- .inc(res.wrote_count || 0);
36
+ ingestCounter.inc(res.wrote_count || 0);
37
37
  console.info(formatTime(Date.now()), '[SeriesCollector][InterestRate][Backward]', 'Result', `series_id=${product_id}, ingested_count=${res.wrote_count}, start_time=${formatTime((_b = (_a = res.range) === null || _a === void 0 ? void 0 : _a.start_time) !== null && _b !== void 0 ? _b : NaN)}, end_time=${formatTime((_d = (_c = res.range) === null || _c === void 0 ? void 0 : _c.end_time) !== null && _d !== void 0 ? _d : NaN)}`);
38
38
  };
39
39
  //# sourceMappingURL=backwards-interest-rate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"backwards-interest-rate.js","sourceRoot":"","sources":["../../src/series-collector/backwards-interest-rate.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAC1B,6DAA6D;AAC7D,yDAAyD;AACzD,qCAAqC;AAOrC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,iCAAiC,EAAE,MAAM,eAAe,CAAC;AAElE,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;AAExC,MAAM,CAAC,MAAM,gCAAgC,GAAG,KAAK,EACnD,UAAkB,EAClB,IAAkC,EAClC,MAAmB,EACnB,EAAE;;IACF,MAAM,CAAC,aAAa,CAAC,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IAC/C,sBAAsB;IACtB,MAAM,WAAW,CAAC,0BAA0B,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAChF,IAAI,GAA+B,CAAC;IACpC,IAAI,IAAI,CAAC,SAAS,KAAK,UAAU,EAAE;QACjC,MAAM,SAAS,GAAG,MAAM,iCAAiC,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAChF,MAAM,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QAE1E,GAAG,GAAG;YACJ,UAAU,EAAE,UAAU;YACtB,SAAS,EAAE,UAAU;YACrB,IAAI,EAAE,UAAU;SACjB,CAAC;KACH;SAAM;QACL,GAAG,GAAG;YACJ,UAAU,EAAE,UAAU;YACtB,SAAS,EAAE,SAAS;YACpB,IAAI,EAAE,CAAC;SACR,CAAC;KACH;IAED,OAAO,CAAC,IAAI,CACV,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EACtB,2CAA2C,EAC3C,SAAS,EACT,cAAc,GAAG,CAAC,UAAU,eAAe,GAAG,CAAC,SAAS,UAAU,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CACzF,CAAC;IAEF,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CACtD,oBAAoB,EACpB,GAAG,CACJ,CAAC;IAEF,QAAQ,CAAC,OAAO;SACb,OAAO,CAAC,+BAA+B,EAAE,EAAE,CAAC;SAC5C,MAAM,CAAC,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;SACtF,GAAG,CAAC,GAAG,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC;IAE7B,OAAO,CAAC,IAAI,CACV,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EACtB,2CAA2C,EAC3C,QAAQ,EACR,aAAa,UAAU,oBAAoB,GAAG,CAAC,WAAW,gBAAgB,UAAU,CAClF,MAAA,MAAA,GAAG,CAAC,KAAK,0CAAE,UAAU,mCAAI,GAAG,CAC7B,cAAc,UAAU,CAAC,MAAA,MAAA,GAAG,CAAC,KAAK,0CAAE,QAAQ,mCAAI,GAAG,CAAC,EAAE,CACxD,CAAC;AACJ,CAAC,CAAC","sourcesContent":["// 解决 Backwards 拉取历史数据的调度器\n// 该文件会定期扫描所有 Terminal 的 ServiceInfo,提取出所有支持 Backwards 拉取的序列。\n// 然后对每个序列,向对应的 IngestInterestRate Service 发送拉取请求,补齐历史数据。\n// 使用 Token Bucket 控制每个数据源的请求速率,避免过载。\n\nimport {\n IIngestInterestRateRequest,\n IInterestRateServiceMetadata,\n ISeriesIngestResult,\n} from '@yuants/exchange';\nimport { Terminal } from '@yuants/protocol';\nimport { decodePath, formatTime, tokenBucket } from '@yuants/utils';\nimport { findInterestRateStartTimeBackward } from './sql-helpers';\n\nconst terminal = Terminal.fromNodeEnv();\n\nexport const handleIngestInterestRateBackward = async (\n product_id: string,\n meta: IInterestRateServiceMetadata,\n signal: AbortSignal,\n) => {\n const [datasource_id] = decodePath(product_id);\n // 控制速率:每个数据源每秒钟只能请求一次\n await tokenBucket(`interest_rate:backward:${datasource_id}`).acquire(1, signal);\n let req: IIngestInterestRateRequest;\n if (meta.direction === 'backward') {\n const startTime = await findInterestRateStartTimeBackward(terminal, product_id);\n const start_time = startTime ? new Date(startTime).getTime() : Date.now();\n\n req = {\n product_id: product_id,\n direction: 'backward',\n time: start_time,\n };\n } else {\n req = {\n product_id: product_id,\n direction: 'forward',\n time: 0,\n };\n }\n\n console.info(\n formatTime(Date.now()),\n '[SeriesCollector][InterestRate][Backward]',\n 'Request',\n `product_id=${req.product_id}, direction=${req.direction}, time=${formatTime(req.time)}`,\n );\n\n const res = await terminal.client.requestForResponseData<IIngestInterestRateRequest, ISeriesIngestResult>(\n 'IngestInterestRate',\n req,\n );\n\n terminal.metrics\n .counter('series_collector_ingest_count', '')\n .labels({ terminal_id: terminal.terminal_id, type: 'interest_rate', task: 'backward' })\n .inc(res.wrote_count || 0);\n\n console.info(\n formatTime(Date.now()),\n '[SeriesCollector][InterestRate][Backward]',\n 'Result',\n `series_id=${product_id}, ingested_count=${res.wrote_count}, start_time=${formatTime(\n res.range?.start_time ?? NaN,\n )}, end_time=${formatTime(res.range?.end_time ?? NaN)}`,\n );\n};\n"]}
1
+ {"version":3,"file":"backwards-interest-rate.js","sourceRoot":"","sources":["../../src/series-collector/backwards-interest-rate.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAC1B,6DAA6D;AAC7D,yDAAyD;AACzD,qCAAqC;AAOrC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,iCAAiC,EAAE,MAAM,eAAe,CAAC;AAElE,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;AACxC,MAAM,aAAa,GAAG,QAAQ,CAAC,OAAO;KACnC,OAAO,CAAC,+BAA+B,EAAE,EAAE,CAAC;KAC5C,MAAM,CAAC,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;AAE1F,MAAM,CAAC,MAAM,gCAAgC,GAAG,KAAK,EACnD,UAAkB,EAClB,IAAkC,EAClC,MAAmB,EACnB,EAAE;;IACF,MAAM,CAAC,aAAa,CAAC,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IAC/C,sBAAsB;IACtB,MAAM,WAAW,CAAC,0BAA0B,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAChF,IAAI,GAA+B,CAAC;IACpC,IAAI,IAAI,CAAC,SAAS,KAAK,UAAU,EAAE;QACjC,MAAM,SAAS,GAAG,MAAM,iCAAiC,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAChF,MAAM,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QAE1E,GAAG,GAAG;YACJ,UAAU,EAAE,UAAU;YACtB,SAAS,EAAE,UAAU;YACrB,IAAI,EAAE,UAAU;SACjB,CAAC;KACH;SAAM;QACL,GAAG,GAAG;YACJ,UAAU,EAAE,UAAU;YACtB,SAAS,EAAE,SAAS;YACpB,IAAI,EAAE,CAAC;SACR,CAAC;KACH;IAED,OAAO,CAAC,IAAI,CACV,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EACtB,2CAA2C,EAC3C,SAAS,EACT,cAAc,GAAG,CAAC,UAAU,eAAe,GAAG,CAAC,SAAS,UAAU,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CACzF,CAAC;IAEF,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CACtD,oBAAoB,EACpB,GAAG,CACJ,CAAC;IAEF,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC;IAExC,OAAO,CAAC,IAAI,CACV,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EACtB,2CAA2C,EAC3C,QAAQ,EACR,aAAa,UAAU,oBAAoB,GAAG,CAAC,WAAW,gBAAgB,UAAU,CAClF,MAAA,MAAA,GAAG,CAAC,KAAK,0CAAE,UAAU,mCAAI,GAAG,CAC7B,cAAc,UAAU,CAAC,MAAA,MAAA,GAAG,CAAC,KAAK,0CAAE,QAAQ,mCAAI,GAAG,CAAC,EAAE,CACxD,CAAC;AACJ,CAAC,CAAC","sourcesContent":["// 解决 Backwards 拉取历史数据的调度器\n// 该文件会定期扫描所有 Terminal 的 ServiceInfo,提取出所有支持 Backwards 拉取的序列。\n// 然后对每个序列,向对应的 IngestInterestRate Service 发送拉取请求,补齐历史数据。\n// 使用 Token Bucket 控制每个数据源的请求速率,避免过载。\n\nimport {\n IIngestInterestRateRequest,\n IInterestRateServiceMetadata,\n ISeriesIngestResult,\n} from '@yuants/exchange';\nimport { Terminal } from '@yuants/protocol';\nimport { decodePath, formatTime, tokenBucket } from '@yuants/utils';\nimport { findInterestRateStartTimeBackward } from './sql-helpers';\n\nconst terminal = Terminal.fromNodeEnv();\nconst ingestCounter = terminal.metrics\n .counter('series_collector_ingest_count', '')\n .labels({ terminal_id: terminal.terminal_id, type: 'interest_rate', task: 'backward' });\n\nexport const handleIngestInterestRateBackward = async (\n product_id: string,\n meta: IInterestRateServiceMetadata,\n signal: AbortSignal,\n) => {\n const [datasource_id] = decodePath(product_id);\n // 控制速率:每个数据源每秒钟只能请求一次\n await tokenBucket(`interest_rate:backward:${datasource_id}`).acquire(1, signal);\n let req: IIngestInterestRateRequest;\n if (meta.direction === 'backward') {\n const startTime = await findInterestRateStartTimeBackward(terminal, product_id);\n const start_time = startTime ? new Date(startTime).getTime() : Date.now();\n\n req = {\n product_id: product_id,\n direction: 'backward',\n time: start_time,\n };\n } else {\n req = {\n product_id: product_id,\n direction: 'forward',\n time: 0,\n };\n }\n\n console.info(\n formatTime(Date.now()),\n '[SeriesCollector][InterestRate][Backward]',\n 'Request',\n `product_id=${req.product_id}, direction=${req.direction}, time=${formatTime(req.time)}`,\n );\n\n const res = await terminal.client.requestForResponseData<IIngestInterestRateRequest, ISeriesIngestResult>(\n 'IngestInterestRate',\n req,\n );\n\n ingestCounter.inc(res.wrote_count || 0);\n\n console.info(\n formatTime(Date.now()),\n '[SeriesCollector][InterestRate][Backward]',\n 'Result',\n `series_id=${product_id}, ingested_count=${res.wrote_count}, start_time=${formatTime(\n res.range?.start_time ?? NaN,\n )}, end_time=${formatTime(res.range?.end_time ?? NaN)}`,\n );\n};\n"]}
@@ -2,78 +2,43 @@
2
2
  // 该文件会定期扫描所有 Terminal 的 ServiceInfo,提取出所有支持 Backwards 拉取的序列。
3
3
  // 然后对每个序列,向对应的 IngestOHLC Service 发送拉取请求,补齐历史数据。
4
4
  // 使用 Token Bucket 控制每个数据源的请求速率,避免过载。
5
- import { decodeOHLCSeriesId, encodeOHLCSeriesId } from '@yuants/data-ohlc';
6
- import { parseOHLCServiceMetadataFromSchema, } from '@yuants/exchange';
5
+ import { decodeOHLCSeriesId } from '@yuants/data-ohlc';
7
6
  import { Terminal } from '@yuants/protocol';
8
7
  import { escapeSQL, requestSQL } from '@yuants/sql';
9
8
  import { decodePath, formatTime, tokenBucket } from '@yuants/utils';
10
- import { defer, repeat, retry } from 'rxjs';
11
9
  const terminal = Terminal.fromNodeEnv();
12
- const listBackwardSeriesIds = async () => {
13
- const product_ids = await requestSQL(terminal, `select product_id from product`);
14
- console.time('[SeriesCollector][Backwards] calc');
15
- const series_ids = new Set();
16
- for (const terminalInfo of terminal.terminalInfos) {
17
- for (const serviceInfo of Object.values(terminalInfo.serviceInfo || {})) {
18
- if (serviceInfo.method !== 'IngestOHLC')
19
- continue;
20
- try {
21
- const meta = parseOHLCServiceMetadataFromSchema(serviceInfo.schema);
22
- if (meta.direction !== 'backward')
23
- continue;
24
- for (const { product_id } of product_ids) {
25
- if (!product_id.startsWith(meta.product_id_prefix))
26
- continue;
27
- for (const duration of meta.duration_list) {
28
- const series_id = encodeOHLCSeriesId(product_id, duration);
29
- series_ids.add(series_id);
30
- }
31
- }
32
- }
33
- finally {
34
- }
35
- }
10
+ const ingestCounter = terminal.metrics
11
+ .counter('series_collector_ingest_count', '')
12
+ .labels({ terminal_id: terminal.terminal_id, type: 'ohlc', task: 'backward' });
13
+ export const handleIngestOHLCBackward = async (series_id, direction, signal) => {
14
+ var _a, _b, _c, _d;
15
+ const { product_id, duration } = decodeOHLCSeriesId(series_id);
16
+ const [datasource_id] = decodePath(product_id);
17
+ // 控制速率:每个数据源每秒钟只能请求一次
18
+ await tokenBucket(`ohlc:backward:${datasource_id}`).acquire(1, signal);
19
+ let req;
20
+ if (direction === 'backward') {
21
+ const [record] = await requestSQL(terminal, `select start_time from series_data_range where series_id = ${escapeSQL(series_id)} and table_name = 'ohlc_v2' order by start_time limit 1`);
22
+ const start_time = record ? new Date(record.start_time).getTime() : Date.now();
23
+ req = {
24
+ product_id,
25
+ duration,
26
+ direction: 'backward',
27
+ time: start_time,
28
+ };
36
29
  }
37
- console.timeEnd('[SeriesCollector][Backwards] calc');
38
- return series_ids;
30
+ else {
31
+ // forward
32
+ req = {
33
+ product_id,
34
+ duration,
35
+ direction,
36
+ time: 0,
37
+ };
38
+ }
39
+ console.info(formatTime(Date.now()), '[SeriesCollector][OHLC][Backward]', 'Request', `product_id=${req.product_id}, duration=${req.duration}, direction=${req.direction}, time=${formatTime(req.time)}`);
40
+ const res = await terminal.client.requestForResponseData('IngestOHLC', req);
41
+ ingestCounter.inc(res.wrote_count || 0);
42
+ console.info(formatTime(Date.now()), '[SeriesCollector][OHLC][Backward]', 'Response', `series_id=${series_id}, ingested_count=${res.wrote_count}, start_time=${formatTime((_b = (_a = res.range) === null || _a === void 0 ? void 0 : _a.start_time) !== null && _b !== void 0 ? _b : NaN)}, end_time=${formatTime((_d = (_c = res.range) === null || _c === void 0 ? void 0 : _c.end_time) !== null && _d !== void 0 ? _d : NaN)}`);
39
43
  };
40
- defer(async () => {
41
- const time = Date.now();
42
- const series_ids = await listBackwardSeriesIds();
43
- console.log(`[SeriesCollector][Backwards] Found ${series_ids.size} series to collect backwards data for. (${formatTime(Date.now() - time)})`);
44
- await Promise.all([...series_ids].map(async (series_id) => {
45
- var _a, _b, _c, _d;
46
- try {
47
- const { product_id, duration } = decodeOHLCSeriesId(series_id);
48
- const [datasource_id] = decodePath(product_id);
49
- // 控制速率:每个数据源每秒钟只能请求一次
50
- await tokenBucket(`backwards_target_${datasource_id}`, {
51
- refillInterval: 1000,
52
- capacity: 1,
53
- }).acquire();
54
- {
55
- const [record] = await requestSQL(terminal, `select start_time from series_data_range where series_id = ${escapeSQL(series_id)} and table_name = 'ohlc_v2' order by start_time limit 1`);
56
- const start_time = record ? new Date(record.start_time).getTime() : Date.now();
57
- const req = {
58
- product_id,
59
- duration,
60
- direction: 'backward',
61
- time: start_time,
62
- };
63
- console.info(formatTime(Date.now()), 'DispatchIngestOHLC', `product_id=${product_id}, duration=${duration}, time=${formatTime(start_time)}`);
64
- const res = await terminal.client.requestForResponseData('IngestOHLC', req);
65
- terminal.metrics
66
- .counter('series_collector_backwards_ingest_count', '')
67
- .labels({ terminal_id: terminal.terminal_id, type: 'ohlc' })
68
- .inc(res.wrote_count || 0);
69
- console.info(formatTime(Date.now()), 'DispatchIngestOHLCResult', `series_id=${series_id}, ingested_count=${res.wrote_count}, start_time=${formatTime((_b = (_a = res.range) === null || _a === void 0 ? void 0 : _a.start_time) !== null && _b !== void 0 ? _b : NaN)}, end_time=${formatTime((_d = (_c = res.range) === null || _c === void 0 ? void 0 : _c.end_time) !== null && _d !== void 0 ? _d : NaN)}`);
70
- }
71
- }
72
- catch (e) {
73
- console.info(formatTime(Date.now()), 'DispatchIngestOHLCError', `series_id=${series_id}`, e);
74
- }
75
- }));
76
- })
77
- .pipe(retry({ delay: 1000 }), repeat({ delay: 1000 }))
78
- .subscribe();
79
44
  //# sourceMappingURL=backwards-ohlc.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"backwards-ohlc.js","sourceRoot":"","sources":["../../src/series-collector/backwards-ohlc.ts"],"names":[],"mappings":"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","sourcesContent":["// 解决 Backwards 拉取历史数据的调度器\n// 该文件会定期扫描所有 Terminal 的 ServiceInfo,提取出所有支持 Backwards 拉取的序列。\n// 然后对每个序列,向对应的 IngestOHLC Service 发送拉取请求,补齐历史数据。\n// 使用 Token Bucket 控制每个数据源的请求速率,避免过载。\n\nimport { decodeOHLCSeriesId, encodeOHLCSeriesId } from '@yuants/data-ohlc';\nimport {\n IIngestOHLCRequest,\n ISeriesIngestResult,\n parseOHLCServiceMetadataFromSchema,\n} from '@yuants/exchange';\nimport { Terminal } from '@yuants/protocol';\nimport { escapeSQL, requestSQL } from '@yuants/sql';\nimport { decodePath, formatTime, tokenBucket } from '@yuants/utils';\nimport { defer, repeat, retry } from 'rxjs';\n\nconst terminal = Terminal.fromNodeEnv();\n\nconst listBackwardSeriesIds = async () => {\n const product_ids = await requestSQL<{ product_id: string }[]>(terminal, `select product_id from product`);\n\n console.time('[SeriesCollector][Backwards] calc');\n\n const series_ids = new Set<string>();\n for (const terminalInfo of terminal.terminalInfos) {\n for (const serviceInfo of Object.values(terminalInfo.serviceInfo || {})) {\n if (serviceInfo.method !== 'IngestOHLC') continue;\n try {\n const meta = parseOHLCServiceMetadataFromSchema(serviceInfo.schema);\n if (meta.direction !== 'backward') continue;\n\n for (const { product_id } of product_ids) {\n if (!product_id.startsWith(meta.product_id_prefix)) continue;\n for (const duration of meta.duration_list) {\n const series_id = encodeOHLCSeriesId(product_id, duration);\n series_ids.add(series_id);\n }\n }\n } finally {\n }\n }\n }\n\n console.timeEnd('[SeriesCollector][Backwards] calc');\n\n return series_ids;\n};\n\ndefer(async () => {\n const time = Date.now();\n const series_ids = await listBackwardSeriesIds();\n console.log(\n `[SeriesCollector][Backwards] Found ${\n series_ids.size\n } series to collect backwards data for. (${formatTime(Date.now() - time)})`,\n );\n\n await Promise.all(\n [...series_ids].map(async (series_id) => {\n try {\n const { product_id, duration } = decodeOHLCSeriesId(series_id);\n const [datasource_id] = decodePath(product_id);\n // 控制速率:每个数据源每秒钟只能请求一次\n await tokenBucket(`backwards_target_${datasource_id}`, {\n refillInterval: 1000,\n capacity: 1,\n }).acquire();\n {\n const [record] = await requestSQL<\n {\n start_time: string;\n }[]\n >(\n terminal,\n `select start_time from series_data_range where series_id = ${escapeSQL(\n series_id,\n )} and table_name = 'ohlc_v2' order by start_time limit 1`,\n );\n const start_time = record ? new Date(record.start_time).getTime() : Date.now();\n\n const req: IIngestOHLCRequest = {\n product_id,\n duration,\n direction: 'backward',\n time: start_time,\n };\n\n console.info(\n formatTime(Date.now()),\n 'DispatchIngestOHLC',\n `product_id=${product_id}, duration=${duration}, time=${formatTime(start_time)}`,\n );\n\n const res = await terminal.client.requestForResponseData<IIngestOHLCRequest, ISeriesIngestResult>(\n 'IngestOHLC',\n req,\n );\n\n terminal.metrics\n .counter('series_collector_backwards_ingest_count', '')\n .labels({ terminal_id: terminal.terminal_id, type: 'ohlc' })\n .inc(res.wrote_count || 0);\n\n console.info(\n formatTime(Date.now()),\n 'DispatchIngestOHLCResult',\n `series_id=${series_id}, ingested_count=${res.wrote_count}, start_time=${formatTime(\n res.range?.start_time ?? NaN,\n )}, end_time=${formatTime(res.range?.end_time ?? NaN)}`,\n );\n }\n } catch (e) {\n console.info(formatTime(Date.now()), 'DispatchIngestOHLCError', `series_id=${series_id}`, e);\n }\n }),\n );\n})\n .pipe(retry({ delay: 1000 }), repeat({ delay: 1000 }))\n .subscribe();\n"]}
1
+ {"version":3,"file":"backwards-ohlc.js","sourceRoot":"","sources":["../../src/series-collector/backwards-ohlc.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAC1B,6DAA6D;AAC7D,iDAAiD;AACjD,qCAAqC;AAErC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEpE,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;AAExC,MAAM,aAAa,GAAG,QAAQ,CAAC,OAAO;KACnC,OAAO,CAAC,+BAA+B,EAAE,EAAE,CAAC;KAC5C,MAAM,CAAC,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;AAEjF,MAAM,CAAC,MAAM,wBAAwB,GAAG,KAAK,EAC3C,SAAiB,EACjB,SAAiC,EACjC,MAAmB,EACnB,EAAE;;IACF,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAC/D,MAAM,CAAC,aAAa,CAAC,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IAC/C,sBAAsB;IACtB,MAAM,WAAW,CAAC,iBAAiB,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAEvE,IAAI,GAAuB,CAAC;IAC5B,IAAI,SAAS,KAAK,UAAU,EAAE;QAC5B,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,UAAU,CAK/B,QAAQ,EACR,8DAA8D,SAAS,CACrE,SAAS,CACV,yDAAyD,CAC3D,CAAC;QACF,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QAE/E,GAAG,GAAG;YACJ,UAAU;YACV,QAAQ;YACR,SAAS,EAAE,UAAU;YACrB,IAAI,EAAE,UAAU;SACjB,CAAC;KACH;SAAM;QACL,UAAU;QACV,GAAG,GAAG;YACJ,UAAU;YACV,QAAQ;YACR,SAAS;YACT,IAAI,EAAE,CAAC;SACR,CAAC;KACH;IAED,OAAO,CAAC,IAAI,CACV,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EACtB,mCAAmC,EACnC,SAAS,EACT,cAAc,GAAG,CAAC,UAAU,cAAc,GAAG,CAAC,QAAQ,eAAe,GAAG,CAAC,SAAS,UAAU,UAAU,CACpG,GAAG,CAAC,IAAI,CACT,EAAE,CACJ,CAAC;IAEF,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CACtD,YAAY,EACZ,GAAG,CACJ,CAAC;IAEF,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC;IAExC,OAAO,CAAC,IAAI,CACV,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EACtB,mCAAmC,EACnC,UAAU,EACV,aAAa,SAAS,oBAAoB,GAAG,CAAC,WAAW,gBAAgB,UAAU,CACjF,MAAA,MAAA,GAAG,CAAC,KAAK,0CAAE,UAAU,mCAAI,GAAG,CAC7B,cAAc,UAAU,CAAC,MAAA,MAAA,GAAG,CAAC,KAAK,0CAAE,QAAQ,mCAAI,GAAG,CAAC,EAAE,CACxD,CAAC;AACJ,CAAC,CAAC","sourcesContent":["// 解决 Backwards 拉取历史数据的调度器\n// 该文件会定期扫描所有 Terminal 的 ServiceInfo,提取出所有支持 Backwards 拉取的序列。\n// 然后对每个序列,向对应的 IngestOHLC Service 发送拉取请求,补齐历史数据。\n// 使用 Token Bucket 控制每个数据源的请求速率,避免过载。\n\nimport { decodeOHLCSeriesId } from '@yuants/data-ohlc';\nimport { IIngestOHLCRequest, ISeriesIngestResult } from '@yuants/exchange';\nimport { Terminal } from '@yuants/protocol';\nimport { escapeSQL, requestSQL } from '@yuants/sql';\nimport { decodePath, formatTime, tokenBucket } from '@yuants/utils';\n\nconst terminal = Terminal.fromNodeEnv();\n\nconst ingestCounter = terminal.metrics\n .counter('series_collector_ingest_count', '')\n .labels({ terminal_id: terminal.terminal_id, type: 'ohlc', task: 'backward' });\n\nexport const handleIngestOHLCBackward = async (\n series_id: string,\n direction: 'forward' | 'backward',\n signal: AbortSignal,\n) => {\n const { product_id, duration } = decodeOHLCSeriesId(series_id);\n const [datasource_id] = decodePath(product_id);\n // 控制速率:每个数据源每秒钟只能请求一次\n await tokenBucket(`ohlc:backward:${datasource_id}`).acquire(1, signal);\n\n let req: IIngestOHLCRequest;\n if (direction === 'backward') {\n const [record] = await requestSQL<\n {\n start_time: string;\n }[]\n >(\n terminal,\n `select start_time from series_data_range where series_id = ${escapeSQL(\n series_id,\n )} and table_name = 'ohlc_v2' order by start_time limit 1`,\n );\n const start_time = record ? new Date(record.start_time).getTime() : Date.now();\n\n req = {\n product_id,\n duration,\n direction: 'backward',\n time: start_time,\n };\n } else {\n // forward\n req = {\n product_id,\n duration,\n direction,\n time: 0,\n };\n }\n\n console.info(\n formatTime(Date.now()),\n '[SeriesCollector][OHLC][Backward]',\n 'Request',\n `product_id=${req.product_id}, duration=${req.duration}, direction=${req.direction}, time=${formatTime(\n req.time,\n )}`,\n );\n\n const res = await terminal.client.requestForResponseData<IIngestOHLCRequest, ISeriesIngestResult>(\n 'IngestOHLC',\n req,\n );\n\n ingestCounter.inc(res.wrote_count || 0);\n\n console.info(\n formatTime(Date.now()),\n '[SeriesCollector][OHLC][Backward]',\n 'Response',\n `series_id=${series_id}, ingested_count=${res.wrote_count}, start_time=${formatTime(\n res.range?.start_time ?? NaN,\n )}, end_time=${formatTime(res.range?.end_time ?? NaN)}`,\n );\n};\n"]}
@@ -1,5 +1,6 @@
1
1
  // 发现所有支持利率的品种系列ID
2
- import { parseInterestRateServiceMetadataFromSchema } from '@yuants/exchange';
2
+ import { encodeOHLCSeriesId } from '@yuants/data-ohlc';
3
+ import { parseInterestRateServiceMetadataFromSchema, parseOHLCServiceMetadataFromSchema, } from '@yuants/exchange';
3
4
  import { Terminal } from '@yuants/protocol';
4
5
  import { requestSQL } from '@yuants/sql';
5
6
  const terminal = Terminal.fromNodeEnv();
@@ -30,4 +31,32 @@ export const listInterestRateSeriesIds = async () => {
30
31
  }
31
32
  return series_ids;
32
33
  };
34
+ /**
35
+ *
36
+ * @returns
37
+ */
38
+ export const listOHLCSeriesIds = async () => {
39
+ const product_ids = await requestSQL(terminal, `select product_id from product`);
40
+ const series_ids = new Map();
41
+ for (const terminalInfo of terminal.terminalInfos) {
42
+ for (const serviceInfo of Object.values(terminalInfo.serviceInfo || {})) {
43
+ if (serviceInfo.method !== 'IngestOHLC')
44
+ continue;
45
+ try {
46
+ const meta = parseOHLCServiceMetadataFromSchema(serviceInfo.schema);
47
+ for (const { product_id } of product_ids) {
48
+ if (!product_id.startsWith(meta.product_id_prefix))
49
+ continue;
50
+ for (const duration of meta.duration_list) {
51
+ const series_id = encodeOHLCSeriesId(product_id, duration);
52
+ series_ids.set(series_id, meta.direction);
53
+ }
54
+ }
55
+ }
56
+ finally {
57
+ }
58
+ }
59
+ }
60
+ return series_ids;
61
+ };
33
62
  //# sourceMappingURL=discovery.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/series-collector/discovery.ts"],"names":[],"mappings":"AAAA,kBAAkB;AAElB,OAAO,EAAgC,0CAA0C,EAAE,MAAM,kBAAkB,CAAC;AAC5G,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;AAExC;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,KAAK,IAAI,EAAE;IAClD,MAAM,WAAW,GAAG,MAAM,UAAU,CAClC,QAAQ;IACR,aAAa;IACb,+DAA+D,CAChE,CAAC;IAEF,MAAM,UAAU,GAAG,IAAI,GAAG,EAAwC,CAAC;IACnE,KAAK,MAAM,YAAY,IAAI,QAAQ,CAAC,aAAa,EAAE;QACjD,KAAK,MAAM,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,WAAW,IAAI,EAAE,CAAC,EAAE;YACvE,IAAI,WAAW,CAAC,MAAM,KAAK,oBAAoB;gBAAE,SAAS;YAC1D,IAAI;gBACF,MAAM,IAAI,GAAG,0CAA0C,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;gBAE5E,KAAK,MAAM,EAAE,UAAU,EAAE,IAAI,WAAW,EAAE;oBACxC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,iBAAiB,CAAC;wBAAE,SAAS;oBAC7D,UAAU,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;iBAClC;aACF;oBAAS;aACT;SACF;KACF;IAED,OAAO,UAAU,CAAC;AACpB,CAAC,CAAC","sourcesContent":["// 发现所有支持利率的品种系列ID\n\nimport { IInterestRateServiceMetadata, parseInterestRateServiceMetadataFromSchema } from '@yuants/exchange';\nimport { Terminal } from '@yuants/protocol';\nimport { requestSQL } from '@yuants/sql';\n\nconst terminal = Terminal.fromNodeEnv();\n\n/**\n * 列出所有支持利率的品种系列ID以及对应的 Service Metadata\n * @returns\n */\nexport const listInterestRateSeriesIds = async () => {\n const product_ids = await requestSQL<{ product_id: string }[]>(\n terminal,\n // 必须是支持利率的品种\n `select product_id from product where no_interest_rate = false`,\n );\n\n const series_ids = new Map<string, IInterestRateServiceMetadata>();\n for (const terminalInfo of terminal.terminalInfos) {\n for (const serviceInfo of Object.values(terminalInfo.serviceInfo || {})) {\n if (serviceInfo.method !== 'IngestInterestRate') continue;\n try {\n const meta = parseInterestRateServiceMetadataFromSchema(serviceInfo.schema);\n\n for (const { product_id } of product_ids) {\n if (!product_id.startsWith(meta.product_id_prefix)) continue;\n series_ids.set(product_id, meta);\n }\n } finally {\n }\n }\n }\n\n return series_ids;\n};\n"]}
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/series-collector/discovery.ts"],"names":[],"mappings":"AAAA,kBAAkB;AAElB,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAEL,0CAA0C,EAC1C,kCAAkC,GACnC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;AAExC;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,KAAK,IAAI,EAAE;IAClD,MAAM,WAAW,GAAG,MAAM,UAAU,CAClC,QAAQ;IACR,aAAa;IACb,+DAA+D,CAChE,CAAC;IAEF,MAAM,UAAU,GAAG,IAAI,GAAG,EAAwC,CAAC;IACnE,KAAK,MAAM,YAAY,IAAI,QAAQ,CAAC,aAAa,EAAE;QACjD,KAAK,MAAM,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,WAAW,IAAI,EAAE,CAAC,EAAE;YACvE,IAAI,WAAW,CAAC,MAAM,KAAK,oBAAoB;gBAAE,SAAS;YAC1D,IAAI;gBACF,MAAM,IAAI,GAAG,0CAA0C,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;gBAE5E,KAAK,MAAM,EAAE,UAAU,EAAE,IAAI,WAAW,EAAE;oBACxC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,iBAAiB,CAAC;wBAAE,SAAS;oBAC7D,UAAU,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;iBAClC;aACF;oBAAS;aACT;SACF;KACF;IAED,OAAO,UAAU,CAAC;AACpB,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,IAAI,EAAE;IAC1C,MAAM,WAAW,GAAG,MAAM,UAAU,CAA2B,QAAQ,EAAE,gCAAgC,CAAC,CAAC;IAE3G,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkC,CAAC;IAC7D,KAAK,MAAM,YAAY,IAAI,QAAQ,CAAC,aAAa,EAAE;QACjD,KAAK,MAAM,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,WAAW,IAAI,EAAE,CAAC,EAAE;YACvE,IAAI,WAAW,CAAC,MAAM,KAAK,YAAY;gBAAE,SAAS;YAClD,IAAI;gBACF,MAAM,IAAI,GAAG,kCAAkC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;gBAEpE,KAAK,MAAM,EAAE,UAAU,EAAE,IAAI,WAAW,EAAE;oBACxC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,iBAAiB,CAAC;wBAAE,SAAS;oBAC7D,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,aAAa,EAAE;wBACzC,MAAM,SAAS,GAAG,kBAAkB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;wBAC3D,UAAU,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;qBAC3C;iBACF;aACF;oBAAS;aACT;SACF;KACF;IAED,OAAO,UAAU,CAAC;AACpB,CAAC,CAAC","sourcesContent":["// 发现所有支持利率的品种系列ID\n\nimport { encodeOHLCSeriesId } from '@yuants/data-ohlc';\nimport {\n IInterestRateServiceMetadata,\n parseInterestRateServiceMetadataFromSchema,\n parseOHLCServiceMetadataFromSchema,\n} from '@yuants/exchange';\nimport { Terminal } from '@yuants/protocol';\nimport { requestSQL } from '@yuants/sql';\n\nconst terminal = Terminal.fromNodeEnv();\n\n/**\n * 列出所有支持利率的品种系列ID以及对应的 Service Metadata\n * @returns\n */\nexport const listInterestRateSeriesIds = async () => {\n const product_ids = await requestSQL<{ product_id: string }[]>(\n terminal,\n // 必须是支持利率的品种\n `select product_id from product where no_interest_rate = false`,\n );\n\n const series_ids = new Map<string, IInterestRateServiceMetadata>();\n for (const terminalInfo of terminal.terminalInfos) {\n for (const serviceInfo of Object.values(terminalInfo.serviceInfo || {})) {\n if (serviceInfo.method !== 'IngestInterestRate') continue;\n try {\n const meta = parseInterestRateServiceMetadataFromSchema(serviceInfo.schema);\n\n for (const { product_id } of product_ids) {\n if (!product_id.startsWith(meta.product_id_prefix)) continue;\n series_ids.set(product_id, meta);\n }\n } finally {\n }\n }\n }\n\n return series_ids;\n};\n\n/**\n *\n * @returns\n */\nexport const listOHLCSeriesIds = async () => {\n const product_ids = await requestSQL<{ product_id: string }[]>(terminal, `select product_id from product`);\n\n const series_ids = new Map<string, 'forward' | 'backward'>();\n for (const terminalInfo of terminal.terminalInfos) {\n for (const serviceInfo of Object.values(terminalInfo.serviceInfo || {})) {\n if (serviceInfo.method !== 'IngestOHLC') continue;\n try {\n const meta = parseOHLCServiceMetadataFromSchema(serviceInfo.schema);\n\n for (const { product_id } of product_ids) {\n if (!product_id.startsWith(meta.product_id_prefix)) continue;\n for (const duration of meta.duration_list) {\n const series_id = encodeOHLCSeriesId(product_id, duration);\n series_ids.set(series_id, meta.direction);\n }\n }\n } finally {\n }\n }\n }\n\n return series_ids;\n};\n"]}
@@ -6,11 +6,14 @@ import { Terminal } from '@yuants/protocol';
6
6
  import { decodePath, formatTime, tokenBucket } from '@yuants/utils';
7
7
  import { findInterestRateEndTimeForward } from './sql-helpers';
8
8
  const terminal = Terminal.fromNodeEnv();
9
+ const ingestCounter = terminal.metrics
10
+ .counter('series_collector_ingest_count', '')
11
+ .labels({ terminal_id: terminal.terminal_id, type: 'interest_rate', task: 'forward' });
9
12
  export const handleIngestInterestRateForward = async (product_id, meta, signal) => {
10
13
  var _a, _b, _c, _d;
11
14
  const [datasource_id] = decodePath(product_id);
12
15
  // 控制速率:每个数据源每秒钟只能请求一次
13
- await tokenBucket(`interest_rate_forwards:${datasource_id}`).acquire(1, signal);
16
+ await tokenBucket(`interest_rate:forwards:${datasource_id}`).acquire(1, signal);
14
17
  {
15
18
  let req;
16
19
  if (meta.direction === 'forward') {
@@ -32,10 +35,7 @@ export const handleIngestInterestRateForward = async (product_id, meta, signal)
32
35
  }
33
36
  console.info(formatTime(Date.now()), '[SeriesCollector][InterestRate][Forward]', 'Request', `product_id=${req.product_id}, direction=${req.direction}, time=${formatTime(req.time)}`);
34
37
  const res = await terminal.client.requestForResponseData('IngestInterestRate', req);
35
- terminal.metrics
36
- .counter('series_collector_forwards_ingest_count', '')
37
- .labels({ terminal_id: terminal.terminal_id, type: 'interest_rate' })
38
- .inc(res.wrote_count || 0);
38
+ ingestCounter.inc(res.wrote_count || 0);
39
39
  console.info(formatTime(Date.now()), '[SeriesCollector][InterestRate][Forward]', 'Result', `series_id=${product_id}, ingested_count=${res.wrote_count}, start_time=${formatTime((_b = (_a = res.range) === null || _a === void 0 ? void 0 : _a.start_time) !== null && _b !== void 0 ? _b : NaN)}, end_time=${formatTime((_d = (_c = res.range) === null || _c === void 0 ? void 0 : _c.end_time) !== null && _d !== void 0 ? _d : NaN)}`);
40
40
  }
41
41
  };
@@ -1 +1 @@
1
- {"version":3,"file":"forwards-interest-rate.js","sourceRoot":"","sources":["../../src/series-collector/forwards-interest-rate.ts"],"names":[],"mappings":"AAAA,yBAAyB;AACzB,4DAA4D;AAC5D,yDAAyD;AACzD,qCAAqC;AAOrC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,8BAA8B,EAAE,MAAM,eAAe,CAAC;AAE/D,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;AAExC,MAAM,CAAC,MAAM,+BAA+B,GAAG,KAAK,EAClD,UAAkB,EAClB,IAAkC,EAClC,MAAmB,EACnB,EAAE;;IACF,MAAM,CAAC,aAAa,CAAC,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IAC/C,sBAAsB;IACtB,MAAM,WAAW,CAAC,0BAA0B,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAEhF;QACE,IAAI,GAA+B,CAAC;QACpC,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,EAAE;YAChC,MAAM,OAAO,GAAG,MAAM,8BAA8B,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;YAC3E,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAEvD,GAAG,GAAG;gBACJ,UAAU,EAAE,UAAU;gBACtB,SAAS,EAAE,SAAS;gBACpB,IAAI;aACL,CAAC;SACH;aAAM;YACL,WAAW;YACX,GAAG,GAAG;gBACJ,UAAU;gBACV,SAAS,EAAE,UAAU;gBACrB,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE;aACjB,CAAC;SACH;QAED,OAAO,CAAC,IAAI,CACV,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EACtB,0CAA0C,EAC1C,SAAS,EACT,cAAc,GAAG,CAAC,UAAU,eAAe,GAAG,CAAC,SAAS,UAAU,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CACzF,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CACtD,oBAAoB,EACpB,GAAG,CACJ,CAAC;QAEF,QAAQ,CAAC,OAAO;aACb,OAAO,CAAC,wCAAwC,EAAE,EAAE,CAAC;aACrD,MAAM,CAAC,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC;aACpE,GAAG,CAAC,GAAG,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC;QAE7B,OAAO,CAAC,IAAI,CACV,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EACtB,0CAA0C,EAC1C,QAAQ,EACR,aAAa,UAAU,oBAAoB,GAAG,CAAC,WAAW,gBAAgB,UAAU,CAClF,MAAA,MAAA,GAAG,CAAC,KAAK,0CAAE,UAAU,mCAAI,GAAG,CAC7B,cAAc,UAAU,CAAC,MAAA,MAAA,GAAG,CAAC,KAAK,0CAAE,QAAQ,mCAAI,GAAG,CAAC,EAAE,CACxD,CAAC;KACH;AACH,CAAC,CAAC","sourcesContent":["// 解决 Forwards 拉取历史数据的调度器\n// 该文件会定期扫描所有 Terminal 的 ServiceInfo,提取出所有支持 Forwards 拉取的序列。\n// 然后对每个序列,向对应的 IngestInterestRate Service 发送拉取请求,补齐历史数据。\n// 使用 Token Bucket 控制每个数据源的请求速率,避免过载。\n\nimport {\n IIngestInterestRateRequest,\n IInterestRateServiceMetadata,\n ISeriesIngestResult,\n} from '@yuants/exchange';\nimport { Terminal } from '@yuants/protocol';\nimport { decodePath, formatTime, tokenBucket } from '@yuants/utils';\nimport { findInterestRateEndTimeForward } from './sql-helpers';\n\nconst terminal = Terminal.fromNodeEnv();\n\nexport const handleIngestInterestRateForward = async (\n product_id: string,\n meta: IInterestRateServiceMetadata,\n signal: AbortSignal,\n) => {\n const [datasource_id] = decodePath(product_id);\n // 控制速率:每个数据源每秒钟只能请求一次\n await tokenBucket(`interest_rate_forwards:${datasource_id}`).acquire(1, signal);\n\n {\n let req: IIngestInterestRateRequest;\n if (meta.direction === 'forward') {\n const endTime = await findInterestRateEndTimeForward(terminal, product_id);\n const time = endTime ? new Date(endTime).getTime() : 0;\n\n req = {\n product_id: product_id,\n direction: 'forward',\n time,\n };\n } else {\n // backward\n req = {\n product_id,\n direction: 'backward',\n time: Date.now(),\n };\n }\n\n console.info(\n formatTime(Date.now()),\n '[SeriesCollector][InterestRate][Forward]',\n 'Request',\n `product_id=${req.product_id}, direction=${req.direction}, time=${formatTime(req.time)}`,\n );\n const res = await terminal.client.requestForResponseData<IIngestInterestRateRequest, ISeriesIngestResult>(\n 'IngestInterestRate',\n req,\n );\n\n terminal.metrics\n .counter('series_collector_forwards_ingest_count', '')\n .labels({ terminal_id: terminal.terminal_id, type: 'interest_rate' })\n .inc(res.wrote_count || 0);\n\n console.info(\n formatTime(Date.now()),\n '[SeriesCollector][InterestRate][Forward]',\n 'Result',\n `series_id=${product_id}, ingested_count=${res.wrote_count}, start_time=${formatTime(\n res.range?.start_time ?? NaN,\n )}, end_time=${formatTime(res.range?.end_time ?? NaN)}`,\n );\n }\n};\n"]}
1
+ {"version":3,"file":"forwards-interest-rate.js","sourceRoot":"","sources":["../../src/series-collector/forwards-interest-rate.ts"],"names":[],"mappings":"AAAA,yBAAyB;AACzB,4DAA4D;AAC5D,yDAAyD;AACzD,qCAAqC;AAOrC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,8BAA8B,EAAE,MAAM,eAAe,CAAC;AAE/D,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;AAExC,MAAM,aAAa,GAAG,QAAQ,CAAC,OAAO;KACnC,OAAO,CAAC,+BAA+B,EAAE,EAAE,CAAC;KAC5C,MAAM,CAAC,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;AAEzF,MAAM,CAAC,MAAM,+BAA+B,GAAG,KAAK,EAClD,UAAkB,EAClB,IAAkC,EAClC,MAAmB,EACnB,EAAE;;IACF,MAAM,CAAC,aAAa,CAAC,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IAC/C,sBAAsB;IACtB,MAAM,WAAW,CAAC,0BAA0B,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAEhF;QACE,IAAI,GAA+B,CAAC;QACpC,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,EAAE;YAChC,MAAM,OAAO,GAAG,MAAM,8BAA8B,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;YAC3E,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAEvD,GAAG,GAAG;gBACJ,UAAU,EAAE,UAAU;gBACtB,SAAS,EAAE,SAAS;gBACpB,IAAI;aACL,CAAC;SACH;aAAM;YACL,WAAW;YACX,GAAG,GAAG;gBACJ,UAAU;gBACV,SAAS,EAAE,UAAU;gBACrB,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE;aACjB,CAAC;SACH;QAED,OAAO,CAAC,IAAI,CACV,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EACtB,0CAA0C,EAC1C,SAAS,EACT,cAAc,GAAG,CAAC,UAAU,eAAe,GAAG,CAAC,SAAS,UAAU,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CACzF,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CACtD,oBAAoB,EACpB,GAAG,CACJ,CAAC;QAEF,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC;QAExC,OAAO,CAAC,IAAI,CACV,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EACtB,0CAA0C,EAC1C,QAAQ,EACR,aAAa,UAAU,oBAAoB,GAAG,CAAC,WAAW,gBAAgB,UAAU,CAClF,MAAA,MAAA,GAAG,CAAC,KAAK,0CAAE,UAAU,mCAAI,GAAG,CAC7B,cAAc,UAAU,CAAC,MAAA,MAAA,GAAG,CAAC,KAAK,0CAAE,QAAQ,mCAAI,GAAG,CAAC,EAAE,CACxD,CAAC;KACH;AACH,CAAC,CAAC","sourcesContent":["// 解决 Forwards 拉取历史数据的调度器\n// 该文件会定期扫描所有 Terminal 的 ServiceInfo,提取出所有支持 Forwards 拉取的序列。\n// 然后对每个序列,向对应的 IngestInterestRate Service 发送拉取请求,补齐历史数据。\n// 使用 Token Bucket 控制每个数据源的请求速率,避免过载。\n\nimport {\n IIngestInterestRateRequest,\n IInterestRateServiceMetadata,\n ISeriesIngestResult,\n} from '@yuants/exchange';\nimport { Terminal } from '@yuants/protocol';\nimport { decodePath, formatTime, tokenBucket } from '@yuants/utils';\nimport { findInterestRateEndTimeForward } from './sql-helpers';\n\nconst terminal = Terminal.fromNodeEnv();\n\nconst ingestCounter = terminal.metrics\n .counter('series_collector_ingest_count', '')\n .labels({ terminal_id: terminal.terminal_id, type: 'interest_rate', task: 'forward' });\n\nexport const handleIngestInterestRateForward = async (\n product_id: string,\n meta: IInterestRateServiceMetadata,\n signal: AbortSignal,\n) => {\n const [datasource_id] = decodePath(product_id);\n // 控制速率:每个数据源每秒钟只能请求一次\n await tokenBucket(`interest_rate:forwards:${datasource_id}`).acquire(1, signal);\n\n {\n let req: IIngestInterestRateRequest;\n if (meta.direction === 'forward') {\n const endTime = await findInterestRateEndTimeForward(terminal, product_id);\n const time = endTime ? new Date(endTime).getTime() : 0;\n\n req = {\n product_id: product_id,\n direction: 'forward',\n time,\n };\n } else {\n // backward\n req = {\n product_id,\n direction: 'backward',\n time: Date.now(),\n };\n }\n\n console.info(\n formatTime(Date.now()),\n '[SeriesCollector][InterestRate][Forward]',\n 'Request',\n `product_id=${req.product_id}, direction=${req.direction}, time=${formatTime(req.time)}`,\n );\n const res = await terminal.client.requestForResponseData<IIngestInterestRateRequest, ISeriesIngestResult>(\n 'IngestInterestRate',\n req,\n );\n\n ingestCounter.inc(res.wrote_count || 0);\n\n console.info(\n formatTime(Date.now()),\n '[SeriesCollector][InterestRate][Forward]',\n 'Result',\n `series_id=${product_id}, ingested_count=${res.wrote_count}, start_time=${formatTime(\n res.range?.start_time ?? NaN,\n )}, end_time=${formatTime(res.range?.end_time ?? NaN)}`,\n );\n }\n};\n"]}
@@ -2,78 +2,43 @@
2
2
  // 该文件会定期扫描所有 Terminal 的 ServiceInfo,提取出所有支持 Forwards 拉取的序列。
3
3
  // 然后对每个序列,向对应的 IngestOHLC Service 发送拉取请求,补齐历史数据。
4
4
  // 使用 Token Bucket 控制每个数据源的请求速率,避免过载。
5
- import { decodeOHLCSeriesId, encodeOHLCSeriesId } from '@yuants/data-ohlc';
6
- import { parseOHLCServiceMetadataFromSchema, } from '@yuants/exchange';
5
+ import { decodeOHLCSeriesId } from '@yuants/data-ohlc';
7
6
  import { Terminal } from '@yuants/protocol';
8
7
  import { escapeSQL, requestSQL } from '@yuants/sql';
9
8
  import { decodePath, formatTime, tokenBucket } from '@yuants/utils';
10
- import { defer, repeat, retry } from 'rxjs';
11
9
  const terminal = Terminal.fromNodeEnv();
12
- const listForwardSeriesIds = async () => {
13
- const product_ids = await requestSQL(terminal, `select product_id from product`);
14
- console.time('[SeriesCollector][OHLC][Forwards] calc');
15
- const series_ids = new Set();
16
- for (const terminalInfo of terminal.terminalInfos) {
17
- for (const serviceInfo of Object.values(terminalInfo.serviceInfo || {})) {
18
- if (serviceInfo.method !== 'IngestOHLC')
19
- continue;
20
- try {
21
- const meta = parseOHLCServiceMetadataFromSchema(serviceInfo.schema);
22
- if (meta.direction !== 'forward')
23
- continue;
24
- for (const { product_id } of product_ids) {
25
- if (!product_id.startsWith(meta.product_id_prefix))
26
- continue;
27
- for (const duration of meta.duration_list) {
28
- const series_id = encodeOHLCSeriesId(product_id, duration);
29
- series_ids.add(series_id);
30
- }
31
- }
32
- }
33
- finally {
34
- }
35
- }
10
+ const ingestCounter = terminal.metrics
11
+ .counter('series_collector_ingest_count', '')
12
+ .labels({ terminal_id: terminal.terminal_id, type: 'ohlc', task: 'forward' });
13
+ export const handleIngestOHLCForward = async (series_id, direction, signal) => {
14
+ var _a, _b, _c, _d;
15
+ const { product_id, duration } = decodeOHLCSeriesId(series_id);
16
+ const [datasource_id] = decodePath(product_id);
17
+ // 控制速率:每个数据源每秒钟只能请求一次
18
+ await tokenBucket(`ohlc:forward:${datasource_id}`).acquire();
19
+ let req;
20
+ if (direction === 'forward') {
21
+ const [record] = await requestSQL(terminal, `select end_time from series_data_range where series_id = ${escapeSQL(series_id)} and table_name = 'ohlc_v2' order by end_time desc limit 1`);
22
+ const time = record ? new Date(record.end_time).getTime() : 0;
23
+ req = {
24
+ product_id,
25
+ duration,
26
+ direction: 'forward',
27
+ time,
28
+ };
36
29
  }
37
- console.timeEnd('[SeriesCollector][OHLC][Forwards] calc');
38
- return series_ids;
30
+ else {
31
+ // backward
32
+ req = {
33
+ product_id,
34
+ duration,
35
+ direction,
36
+ time: Date.now(),
37
+ };
38
+ }
39
+ console.info(formatTime(Date.now()), '[SeriesCollector][OHLC][Forward]', 'Request', `product_id=${req.product_id}, duration=${req.duration}, direction=${req.direction}, time=${formatTime(req.time)}`);
40
+ const res = await terminal.client.requestForResponseData('IngestOHLC', req);
41
+ ingestCounter.inc(res.wrote_count || 0);
42
+ console.info(formatTime(Date.now()), '[SeriesCollector][OHLC][Forward]', 'Response', `series_id=${series_id}, ingested_count=${res.wrote_count}, start_time=${formatTime((_b = (_a = res.range) === null || _a === void 0 ? void 0 : _a.start_time) !== null && _b !== void 0 ? _b : NaN)}, end_time=${formatTime((_d = (_c = res.range) === null || _c === void 0 ? void 0 : _c.end_time) !== null && _d !== void 0 ? _d : NaN)}`);
39
43
  };
40
- defer(async () => {
41
- const time = Date.now();
42
- const series_ids = await listForwardSeriesIds();
43
- console.log(`[SeriesCollector][OHLC][Forwards] Found ${series_ids.size} series to collect forwards data for. (${formatTime(Date.now() - time)})`);
44
- await Promise.all([...series_ids].map(async (series_id) => {
45
- var _a, _b, _c, _d;
46
- try {
47
- const { product_id, duration } = decodeOHLCSeriesId(series_id);
48
- const [datasource_id] = decodePath(product_id);
49
- // 控制速率:每个数据源每秒钟只能请求一次
50
- await tokenBucket(`ohlc_forwards_target_${datasource_id}`, {
51
- refillInterval: 1000,
52
- capacity: 1,
53
- }).acquire();
54
- {
55
- const [record] = await requestSQL(terminal, `select end_time from series_data_range where series_id = ${escapeSQL(series_id)} and table_name = 'ohlc_v2' order by end_time desc limit 1`);
56
- const time = record ? new Date(record.end_time).getTime() : 0;
57
- const req = {
58
- product_id,
59
- duration,
60
- direction: 'forward',
61
- time,
62
- };
63
- console.info(formatTime(Date.now()), 'DispatchIngestOHLC_Forwards', `product_id=${product_id}, duration=${duration}, time=${formatTime(time)}`);
64
- const res = await terminal.client.requestForResponseData('IngestOHLC', req);
65
- terminal.metrics
66
- .counter('series_collector_forwards_ingest_count', '')
67
- .labels({ terminal_id: terminal.terminal_id, type: 'ohlc' })
68
- .inc(res.wrote_count || 0);
69
- console.info(formatTime(Date.now()), 'DispatchIngestOHLCResult_Forwards', `series_id=${series_id}, ingested_count=${res.wrote_count}, start_time=${formatTime((_b = (_a = res.range) === null || _a === void 0 ? void 0 : _a.start_time) !== null && _b !== void 0 ? _b : NaN)}, end_time=${formatTime((_d = (_c = res.range) === null || _c === void 0 ? void 0 : _c.end_time) !== null && _d !== void 0 ? _d : NaN)}`);
70
- }
71
- }
72
- catch (e) {
73
- console.info(formatTime(Date.now()), 'DispatchIngestOHLCError_Forwards', `series_id=${series_id}`, e);
74
- }
75
- }));
76
- })
77
- .pipe(retry({ delay: 1000 }), repeat({ delay: 1000 }))
78
- .subscribe();
79
44
  //# sourceMappingURL=forwards-ohlc.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"forwards-ohlc.js","sourceRoot":"","sources":["../../src/series-collector/forwards-ohlc.ts"],"names":[],"mappings":"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","sourcesContent":["// 解决 Forwards 拉取历史数据的调度器\n// 该文件会定期扫描所有 Terminal 的 ServiceInfo,提取出所有支持 Forwards 拉取的序列。\n// 然后对每个序列,向对应的 IngestOHLC Service 发送拉取请求,补齐历史数据。\n// 使用 Token Bucket 控制每个数据源的请求速率,避免过载。\n\nimport { decodeOHLCSeriesId, encodeOHLCSeriesId } from '@yuants/data-ohlc';\nimport {\n IIngestOHLCRequest,\n ISeriesIngestResult,\n parseOHLCServiceMetadataFromSchema,\n} from '@yuants/exchange';\nimport { Terminal } from '@yuants/protocol';\nimport { escapeSQL, requestSQL } from '@yuants/sql';\nimport { decodePath, formatTime, tokenBucket } from '@yuants/utils';\nimport { defer, repeat, retry } from 'rxjs';\n\nconst terminal = Terminal.fromNodeEnv();\n\nconst listForwardSeriesIds = async () => {\n const product_ids = await requestSQL<{ product_id: string }[]>(terminal, `select product_id from product`);\n\n console.time('[SeriesCollector][OHLC][Forwards] calc');\n\n const series_ids = new Set<string>();\n for (const terminalInfo of terminal.terminalInfos) {\n for (const serviceInfo of Object.values(terminalInfo.serviceInfo || {})) {\n if (serviceInfo.method !== 'IngestOHLC') continue;\n try {\n const meta = parseOHLCServiceMetadataFromSchema(serviceInfo.schema);\n if (meta.direction !== 'forward') continue;\n\n for (const { product_id } of product_ids) {\n if (!product_id.startsWith(meta.product_id_prefix)) continue;\n for (const duration of meta.duration_list) {\n const series_id = encodeOHLCSeriesId(product_id, duration);\n series_ids.add(series_id);\n }\n }\n } finally {\n }\n }\n }\n\n console.timeEnd('[SeriesCollector][OHLC][Forwards] calc');\n\n return series_ids;\n};\n\ndefer(async () => {\n const time = Date.now();\n const series_ids = await listForwardSeriesIds();\n console.log(\n `[SeriesCollector][OHLC][Forwards] Found ${\n series_ids.size\n } series to collect forwards data for. (${formatTime(Date.now() - time)})`,\n );\n\n await Promise.all(\n [...series_ids].map(async (series_id) => {\n try {\n const { product_id, duration } = decodeOHLCSeriesId(series_id);\n const [datasource_id] = decodePath(product_id);\n // 控制速率:每个数据源每秒钟只能请求一次\n await tokenBucket(`ohlc_forwards_target_${datasource_id}`, {\n refillInterval: 1000,\n capacity: 1,\n }).acquire();\n {\n const [record] = await requestSQL<\n {\n end_time: string;\n }[]\n >(\n terminal,\n `select end_time from series_data_range where series_id = ${escapeSQL(\n series_id,\n )} and table_name = 'ohlc_v2' order by end_time desc limit 1`,\n );\n\n const time = record ? new Date(record.end_time).getTime() : 0;\n\n const req: IIngestOHLCRequest = {\n product_id,\n duration,\n direction: 'forward',\n time,\n };\n\n console.info(\n formatTime(Date.now()),\n 'DispatchIngestOHLC_Forwards',\n `product_id=${product_id}, duration=${duration}, time=${formatTime(time)}`,\n );\n\n const res = await terminal.client.requestForResponseData<IIngestOHLCRequest, ISeriesIngestResult>(\n 'IngestOHLC',\n req,\n );\n\n terminal.metrics\n .counter('series_collector_forwards_ingest_count', '')\n .labels({ terminal_id: terminal.terminal_id, type: 'ohlc' })\n .inc(res.wrote_count || 0);\n\n console.info(\n formatTime(Date.now()),\n 'DispatchIngestOHLCResult_Forwards',\n `series_id=${series_id}, ingested_count=${res.wrote_count}, start_time=${formatTime(\n res.range?.start_time ?? NaN,\n )}, end_time=${formatTime(res.range?.end_time ?? NaN)}`,\n );\n }\n } catch (e) {\n console.info(formatTime(Date.now()), 'DispatchIngestOHLCError_Forwards', `series_id=${series_id}`, e);\n }\n }),\n );\n})\n .pipe(retry({ delay: 1000 }), repeat({ delay: 1000 }))\n .subscribe();\n"]}
1
+ {"version":3,"file":"forwards-ohlc.js","sourceRoot":"","sources":["../../src/series-collector/forwards-ohlc.ts"],"names":[],"mappings":"AAAA,yBAAyB;AACzB,4DAA4D;AAC5D,iDAAiD;AACjD,qCAAqC;AAErC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEpE,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;AAExC,MAAM,aAAa,GAAG,QAAQ,CAAC,OAAO;KACnC,OAAO,CAAC,+BAA+B,EAAE,EAAE,CAAC;KAC5C,MAAM,CAAC,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;AAEhF,MAAM,CAAC,MAAM,uBAAuB,GAAG,KAAK,EAC1C,SAAiB,EACjB,SAAiC,EACjC,MAAmB,EACnB,EAAE;;IACF,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAC/D,MAAM,CAAC,aAAa,CAAC,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IAC/C,sBAAsB;IACtB,MAAM,WAAW,CAAC,gBAAgB,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;IAC7D,IAAI,GAAuB,CAAC;IAC5B,IAAI,SAAS,KAAK,SAAS,EAAE;QAC3B,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,UAAU,CAK/B,QAAQ,EACR,4DAA4D,SAAS,CACnE,SAAS,CACV,4DAA4D,CAC9D,CAAC;QAEF,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAE9D,GAAG,GAAG;YACJ,UAAU;YACV,QAAQ;YACR,SAAS,EAAE,SAAS;YACpB,IAAI;SACL,CAAC;KACH;SAAM;QACL,WAAW;QACX,GAAG,GAAG;YACJ,UAAU;YACV,QAAQ;YACR,SAAS;YACT,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE;SACjB,CAAC;KACH;IAED,OAAO,CAAC,IAAI,CACV,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EACtB,kCAAkC,EAClC,SAAS,EACT,cAAc,GAAG,CAAC,UAAU,cAAc,GAAG,CAAC,QAAQ,eAAe,GAAG,CAAC,SAAS,UAAU,UAAU,CACpG,GAAG,CAAC,IAAI,CACT,EAAE,CACJ,CAAC;IAEF,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CACtD,YAAY,EACZ,GAAG,CACJ,CAAC;IAEF,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC;IAExC,OAAO,CAAC,IAAI,CACV,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EACtB,kCAAkC,EAClC,UAAU,EACV,aAAa,SAAS,oBAAoB,GAAG,CAAC,WAAW,gBAAgB,UAAU,CACjF,MAAA,MAAA,GAAG,CAAC,KAAK,0CAAE,UAAU,mCAAI,GAAG,CAC7B,cAAc,UAAU,CAAC,MAAA,MAAA,GAAG,CAAC,KAAK,0CAAE,QAAQ,mCAAI,GAAG,CAAC,EAAE,CACxD,CAAC;AACJ,CAAC,CAAC","sourcesContent":["// 解决 Forwards 拉取历史数据的调度器\n// 该文件会定期扫描所有 Terminal 的 ServiceInfo,提取出所有支持 Forwards 拉取的序列。\n// 然后对每个序列,向对应的 IngestOHLC Service 发送拉取请求,补齐历史数据。\n// 使用 Token Bucket 控制每个数据源的请求速率,避免过载。\n\nimport { decodeOHLCSeriesId } from '@yuants/data-ohlc';\nimport { IIngestOHLCRequest, ISeriesIngestResult } from '@yuants/exchange';\nimport { Terminal } from '@yuants/protocol';\nimport { escapeSQL, requestSQL } from '@yuants/sql';\nimport { decodePath, formatTime, tokenBucket } from '@yuants/utils';\n\nconst terminal = Terminal.fromNodeEnv();\n\nconst ingestCounter = terminal.metrics\n .counter('series_collector_ingest_count', '')\n .labels({ terminal_id: terminal.terminal_id, type: 'ohlc', task: 'forward' });\n\nexport const handleIngestOHLCForward = async (\n series_id: string,\n direction: 'forward' | 'backward',\n signal: AbortSignal,\n) => {\n const { product_id, duration } = decodeOHLCSeriesId(series_id);\n const [datasource_id] = decodePath(product_id);\n // 控制速率:每个数据源每秒钟只能请求一次\n await tokenBucket(`ohlc:forward:${datasource_id}`).acquire();\n let req: IIngestOHLCRequest;\n if (direction === 'forward') {\n const [record] = await requestSQL<\n {\n end_time: string;\n }[]\n >(\n terminal,\n `select end_time from series_data_range where series_id = ${escapeSQL(\n series_id,\n )} and table_name = 'ohlc_v2' order by end_time desc limit 1`,\n );\n\n const time = record ? new Date(record.end_time).getTime() : 0;\n\n req = {\n product_id,\n duration,\n direction: 'forward',\n time,\n };\n } else {\n // backward\n req = {\n product_id,\n duration,\n direction,\n time: Date.now(),\n };\n }\n\n console.info(\n formatTime(Date.now()),\n '[SeriesCollector][OHLC][Forward]',\n 'Request',\n `product_id=${req.product_id}, duration=${req.duration}, direction=${req.direction}, time=${formatTime(\n req.time,\n )}`,\n );\n\n const res = await terminal.client.requestForResponseData<IIngestOHLCRequest, ISeriesIngestResult>(\n 'IngestOHLC',\n req,\n );\n\n ingestCounter.inc(res.wrote_count || 0);\n\n console.info(\n formatTime(Date.now()),\n '[SeriesCollector][OHLC][Forward]',\n 'Response',\n `series_id=${series_id}, ingested_count=${res.wrote_count}, start_time=${formatTime(\n res.range?.start_time ?? NaN,\n )}, end_time=${formatTime(res.range?.end_time ?? NaN)}`,\n );\n};\n"]}
@@ -1,4 +1,3 @@
1
- import './backwards-ohlc';
2
- import './forwards-ohlc';
3
1
  import './interest-rate';
2
+ import './ohlc';
4
3
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/series-collector/index.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,iBAAiB,CAAC;AACzB,OAAO,iBAAiB,CAAC","sourcesContent":["import './backwards-ohlc';\nimport './forwards-ohlc';\nimport './interest-rate';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/series-collector/index.ts"],"names":[],"mappings":"AAAA,OAAO,iBAAiB,CAAC;AACzB,OAAO,QAAQ,CAAC","sourcesContent":["import './interest-rate';\nimport './ohlc';\n"]}
@@ -1,5 +1,5 @@
1
- import { listWatch } from '@yuants/utils';
2
- import { defer, map, Observable, repeat, retry } from 'rxjs';
1
+ import { formatTime, listWatch } from '@yuants/utils';
2
+ import { defer, map, Observable, repeat, retry, tap } from 'rxjs';
3
3
  import { handleIngestInterestRateBackward } from './backwards-interest-rate';
4
4
  import { listInterestRateSeriesIds } from './discovery';
5
5
  import { handleIngestInterestRateForward } from './forwards-interest-rate';
@@ -15,7 +15,9 @@ defer(() => listInterestRateSeriesIds())
15
15
  const forwardTask = defer(async () => {
16
16
  await handleIngestInterestRateForward(product_id, meta, abortController.signal);
17
17
  })
18
- .pipe(retry(), repeat())
18
+ .pipe(tap({
19
+ error: (err) => console.info(formatTime(Date.now()), `[SeriesCollector][InterestRate][Forward]`, 'Error', err),
20
+ }), retry(), repeat())
19
21
  .subscribe();
20
22
  sub.add(() => {
21
23
  forwardTask.unsubscribe();
@@ -24,7 +26,9 @@ defer(() => listInterestRateSeriesIds())
24
26
  const backwardTask = defer(async () => {
25
27
  await handleIngestInterestRateBackward(product_id, meta, abortController.signal);
26
28
  })
27
- .pipe(retry(), repeat())
29
+ .pipe(tap({
30
+ error: (err) => console.info(formatTime(Date.now()), `[SeriesCollector][InterestRate][Backward]`, 'Error', err),
31
+ }), retry(), repeat())
28
32
  .subscribe();
29
33
  sub.add(() => {
30
34
  backwardTask.unsubscribe();
@@ -33,7 +37,9 @@ defer(() => listInterestRateSeriesIds())
33
37
  const patchTask = defer(async () => {
34
38
  await handleInterestRatePatch(product_id, meta, abortController.signal);
35
39
  })
36
- .pipe(retry(), repeat())
40
+ .pipe(tap({
41
+ error: (err) => console.info(formatTime(Date.now()), `[SeriesCollector][InterestRate][Patch]`, 'Error', err),
42
+ }), retry(), repeat())
37
43
  .subscribe();
38
44
  sub.add(() => {
39
45
  patchTask.unsubscribe();
@@ -1 +1 @@
1
- {"version":3,"file":"interest-rate.js","sourceRoot":"","sources":["../../src/series-collector/interest-rate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAC7D,OAAO,EAAE,gCAAgC,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,+BAA+B,EAAE,MAAM,0BAA0B,CAAC;AAC3E,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,KAAK,CAAC,GAAG,EAAE,CAAC,yBAAyB,EAAE,CAAC;KACrC,IAAI,CACH,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EACtB,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EACxB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,EACnC,SAAS,CACP,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EACX,CAAC,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,EAAE,CACrB,IAAI,UAAU,CAAC,CAAC,GAAG,EAAE,EAAE;IACrB,mDAAmD;IACnD,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;IAE9C,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE;QACX,eAAe,CAAC,KAAK,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,UAAU;IACV,MAAM,WAAW,GAAG,KAAK,CAAC,KAAK,IAAI,EAAE;QACnC,MAAM,+BAA+B,CAAC,UAAU,EAAE,IAAI,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;IAClF,CAAC,CAAC;SACC,IAAI,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC;SACvB,SAAS,EAAE,CAAC;IAEf,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE;QACX,WAAW,CAAC,WAAW,EAAE,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,SAAS;IACT,MAAM,YAAY,GAAG,KAAK,CAAC,KAAK,IAAI,EAAE;QACpC,MAAM,gCAAgC,CAAC,UAAU,EAAE,IAAI,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;IACnF,CAAC,CAAC;SACC,IAAI,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC;SACvB,SAAS,EAAE,CAAC;IAEf,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE;QACX,YAAY,CAAC,WAAW,EAAE,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,SAAS;IACT,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,IAAI,EAAE;QACjC,MAAM,uBAAuB,CAAC,UAAU,EAAE,IAAI,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;IAC1E,CAAC,CAAC;SACC,IAAI,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC;SACvB,SAAS,EAAE,CAAC;IAEf,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE;QACX,SAAS,CAAC,WAAW,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CACL,CACF;KACA,SAAS,EAAE,CAAC","sourcesContent":["import { listWatch } from '@yuants/utils';\nimport { defer, map, Observable, repeat, retry } from 'rxjs';\nimport { handleIngestInterestRateBackward } from './backwards-interest-rate';\nimport { listInterestRateSeriesIds } from './discovery';\nimport { handleIngestInterestRateForward } from './forwards-interest-rate';\nimport { handleInterestRatePatch } from './patch-interest-rate';\n\ndefer(() => listInterestRateSeriesIds())\n .pipe(\n retry({ delay: 1000 }),\n repeat({ delay: 60000 }),\n map((x) => Array.from(x.entries())),\n listWatch(\n (x) => x[0],\n ([product_id, meta]) =>\n new Observable((sub) => {\n // 处理每个利率品种任务: (forward / backward / patch),都需要独立调度\n const abortController = new AbortController();\n\n sub.add(() => {\n abortController.abort();\n });\n\n // 先处理前向任务\n const forwardTask = defer(async () => {\n await handleIngestInterestRateForward(product_id, meta, abortController.signal);\n })\n .pipe(retry(), repeat())\n .subscribe();\n\n sub.add(() => {\n forwardTask.unsubscribe();\n });\n\n // 设置后向任务\n const backwardTask = defer(async () => {\n await handleIngestInterestRateBackward(product_id, meta, abortController.signal);\n })\n .pipe(retry(), repeat())\n .subscribe();\n\n sub.add(() => {\n backwardTask.unsubscribe();\n });\n\n // 设置补齐任务\n const patchTask = defer(async () => {\n await handleInterestRatePatch(product_id, meta, abortController.signal);\n })\n .pipe(retry(), repeat())\n .subscribe();\n\n sub.add(() => {\n patchTask.unsubscribe();\n });\n }),\n ),\n )\n .subscribe();\n"]}
1
+ {"version":3,"file":"interest-rate.js","sourceRoot":"","sources":["../../src/series-collector/interest-rate.ts"],"names":[],"mappings":"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","sourcesContent":["import { formatTime, listWatch } from '@yuants/utils';\nimport { defer, map, Observable, repeat, retry, tap } from 'rxjs';\nimport { handleIngestInterestRateBackward } from './backwards-interest-rate';\nimport { listInterestRateSeriesIds } from './discovery';\nimport { handleIngestInterestRateForward } from './forwards-interest-rate';\nimport { handleInterestRatePatch } from './patch-interest-rate';\n\ndefer(() => listInterestRateSeriesIds())\n .pipe(\n retry({ delay: 1000 }),\n repeat({ delay: 60000 }),\n map((x) => Array.from(x.entries())),\n listWatch(\n (x) => x[0],\n ([product_id, meta]) =>\n new Observable((sub) => {\n // 处理每个利率品种任务: (forward / backward / patch),都需要独立调度\n const abortController = new AbortController();\n\n sub.add(() => {\n abortController.abort();\n });\n\n // 先处理前向任务\n const forwardTask = defer(async () => {\n await handleIngestInterestRateForward(product_id, meta, abortController.signal);\n })\n .pipe(\n tap({\n error: (err) =>\n console.info(\n formatTime(Date.now()),\n `[SeriesCollector][InterestRate][Forward]`,\n 'Error',\n err,\n ),\n }),\n\n retry(),\n repeat(),\n )\n .subscribe();\n\n sub.add(() => {\n forwardTask.unsubscribe();\n });\n\n // 设置后向任务\n const backwardTask = defer(async () => {\n await handleIngestInterestRateBackward(product_id, meta, abortController.signal);\n })\n .pipe(\n tap({\n error: (err) =>\n console.info(\n formatTime(Date.now()),\n `[SeriesCollector][InterestRate][Backward]`,\n 'Error',\n err,\n ),\n }),\n retry(),\n repeat(),\n )\n .subscribe();\n\n sub.add(() => {\n backwardTask.unsubscribe();\n });\n\n // 设置补齐任务\n const patchTask = defer(async () => {\n await handleInterestRatePatch(product_id, meta, abortController.signal);\n })\n .pipe(\n tap({\n error: (err) =>\n console.info(\n formatTime(Date.now()),\n `[SeriesCollector][InterestRate][Patch]`,\n 'Error',\n err,\n ),\n }),\n retry(),\n repeat(),\n )\n .subscribe();\n\n sub.add(() => {\n patchTask.unsubscribe();\n });\n }),\n ),\n )\n .subscribe();\n"]}
@@ -0,0 +1,49 @@
1
+ import { formatTime, listWatch } from '@yuants/utils';
2
+ import { defer, map, Observable, repeat, retry, tap } from 'rxjs';
3
+ import { listOHLCSeriesIds } from './discovery';
4
+ import { handleIngestOHLCForward } from './forwards-ohlc';
5
+ import { handleIngestOHLCBackward } from './backwards-ohlc';
6
+ import { handleOHLCPatch } from './patch-ohlc';
7
+ defer(() => listOHLCSeriesIds())
8
+ .pipe(retry({ delay: 1000 }), repeat({ delay: 60000 }), map((x) => Array.from(x.entries())), listWatch((x) => x[0], ([product_id, direction]) => new Observable((sub) => {
9
+ // 处理每个利率品种任务: (forward / backward / patch),都需要独立调度
10
+ const abortController = new AbortController();
11
+ sub.add(() => {
12
+ abortController.abort();
13
+ });
14
+ // 先处理前向任务
15
+ const forwardTask = defer(async () => {
16
+ await handleIngestOHLCForward(product_id, direction, abortController.signal);
17
+ })
18
+ .pipe(tap({
19
+ error: (err) => console.info(formatTime(Date.now()), `[SeriesCollector][OHLC][Forward]`, 'Error', err),
20
+ }), retry(), repeat())
21
+ .subscribe();
22
+ sub.add(() => {
23
+ forwardTask.unsubscribe();
24
+ });
25
+ // 设置后向任务
26
+ const backwardTask = defer(async () => {
27
+ await handleIngestOHLCBackward(product_id, direction, abortController.signal);
28
+ })
29
+ .pipe(tap({
30
+ error: (err) => console.info(formatTime(Date.now()), `[SeriesCollector][OHLC][Backward]`, 'Error', err),
31
+ }), retry(), repeat())
32
+ .subscribe();
33
+ sub.add(() => {
34
+ backwardTask.unsubscribe();
35
+ });
36
+ // 设置补齐任务
37
+ const patchTask = defer(async () => {
38
+ await handleOHLCPatch(product_id, direction, abortController.signal);
39
+ })
40
+ .pipe(tap({
41
+ error: (err) => console.info(formatTime(Date.now()), `[SeriesCollector][OHLC][Patch]`, 'Error', err),
42
+ }), retry(), repeat())
43
+ .subscribe();
44
+ sub.add(() => {
45
+ patchTask.unsubscribe();
46
+ });
47
+ })))
48
+ .subscribe();
49
+ //# sourceMappingURL=ohlc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ohlc.js","sourceRoot":"","sources":["../../src/series-collector/ohlc.ts"],"names":[],"mappings":"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","sourcesContent":["import { formatTime, listWatch } from '@yuants/utils';\nimport { defer, map, Observable, repeat, retry, tap } from 'rxjs';\nimport { handleIngestInterestRateBackward } from './backwards-interest-rate';\nimport { listOHLCSeriesIds } from './discovery';\nimport { handleIngestInterestRateForward } from './forwards-interest-rate';\nimport { handleInterestRatePatch } from './patch-interest-rate';\nimport { handleIngestOHLCForward } from './forwards-ohlc';\nimport { handleIngestOHLCBackward } from './backwards-ohlc';\nimport { handleOHLCPatch } from './patch-ohlc';\n\ndefer(() => listOHLCSeriesIds())\n .pipe(\n retry({ delay: 1000 }),\n repeat({ delay: 60000 }),\n map((x) => Array.from(x.entries())),\n listWatch(\n (x) => x[0],\n ([product_id, direction]) =>\n new Observable((sub) => {\n // 处理每个利率品种任务: (forward / backward / patch),都需要独立调度\n const abortController = new AbortController();\n\n sub.add(() => {\n abortController.abort();\n });\n\n // 先处理前向任务\n const forwardTask = defer(async () => {\n await handleIngestOHLCForward(product_id, direction, abortController.signal);\n })\n .pipe(\n tap({\n error: (err) =>\n console.info(formatTime(Date.now()), `[SeriesCollector][OHLC][Forward]`, 'Error', err),\n }),\n\n retry(),\n repeat(),\n )\n .subscribe();\n\n sub.add(() => {\n forwardTask.unsubscribe();\n });\n\n // 设置后向任务\n const backwardTask = defer(async () => {\n await handleIngestOHLCBackward(product_id, direction, abortController.signal);\n })\n .pipe(\n tap({\n error: (err) =>\n console.info(formatTime(Date.now()), `[SeriesCollector][OHLC][Backward]`, 'Error', err),\n }),\n retry(),\n repeat(),\n )\n .subscribe();\n\n sub.add(() => {\n backwardTask.unsubscribe();\n });\n\n // 设置补齐任务\n const patchTask = defer(async () => {\n await handleOHLCPatch(product_id, direction, abortController.signal);\n })\n .pipe(\n tap({\n error: (err) =>\n console.info(formatTime(Date.now()), `[SeriesCollector][OHLC][Patch]`, 'Error', err),\n }),\n retry(),\n repeat(),\n )\n .subscribe();\n\n sub.add(() => {\n patchTask.unsubscribe();\n });\n }),\n ),\n )\n .subscribe();\n"]}