@yuants/vendor-okx 0.22.23 → 0.23.1

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.
package/dist/ohlc.js CHANGED
@@ -10,15 +10,16 @@ var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _ar
10
10
  function reject(value) { resume("throw", value); }
11
11
  function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
12
12
  };
13
- import { provideOHLCDurationService } from '@yuants/data-ohlc';
14
13
  import { createSeriesProvider } from '@yuants/data-series';
15
14
  import { Terminal } from '@yuants/protocol';
16
15
  import { writeToSQL } from '@yuants/sql';
17
16
  import { convertDurationToOffset, decodePath, formatTime } from '@yuants/utils';
18
17
  import { firstValueFrom, map, timer } from 'rxjs';
19
18
  import { client } from './api';
19
+ import { provideOHLCFromTimeBackwardService } from './provideOHLCFromTimeBackwardService';
20
20
  import { useOHLC } from './ws';
21
21
  // import { useOHLC } from './websocket';
22
+ const terminal = Terminal.fromNodeEnv();
22
23
  // 时间粒度,默认值1m
23
24
  // 如 [1m/3m/5m/15m/30m/1H/2H/4H]
24
25
  // 香港时间开盘价k线:[6H/12H/1D/1W/1M]
@@ -53,7 +54,7 @@ const DURATION_TO_OKX_CANDLE_TYPE = {
53
54
  P1W: 'candle1W',
54
55
  P1M: 'candle1M',
55
56
  };
56
- createSeriesProvider(Terminal.fromNodeEnv(), {
57
+ createSeriesProvider(terminal, {
57
58
  tableName: 'ohlc',
58
59
  series_id_prefix_parts: ['OKX'],
59
60
  reversed: true,
@@ -114,7 +115,7 @@ createSeriesProvider(Terminal.fromNodeEnv(), {
114
115
  });
115
116
  },
116
117
  });
117
- Terminal.fromNodeEnv().channel.publishChannel('ohlc', { pattern: `^OKX/` }, (series_id) => {
118
+ terminal.channel.publishChannel('ohlc', { pattern: `^OKX/` }, (series_id) => {
118
119
  const [datasource_id, product_id, duration] = decodePath(series_id);
119
120
  const [, instId] = decodePath(product_id);
120
121
  const offset = convertDurationToOffset(duration);
@@ -158,7 +159,48 @@ Terminal.fromNodeEnv().channel.publishChannel('ohlc', { pattern: `^OKX/` }, (ser
158
159
  terminal: Terminal.fromNodeEnv(),
159
160
  }));
160
161
  });
161
- // 提供 OKX 的K线周期服务
162
- provideOHLCDurationService(Terminal.fromNodeEnv(), 'OKX', // datasource_id
163
- () => Object.keys(DURATION_TO_OKX_BAR_TYPE));
162
+ provideOHLCFromTimeBackwardService({
163
+ terminal,
164
+ datasource_id: 'OKX',
165
+ supported_durations: Object.keys(DURATION_TO_OKX_BAR_TYPE),
166
+ queryFn: async ({ series_id, datasource_id, product_id, duration, offset, time }) => {
167
+ const [instType, instId] = decodePath(product_id);
168
+ if (!instId) {
169
+ throw `invalid product_id: ${product_id}`;
170
+ }
171
+ const bar = DURATION_TO_OKX_BAR_TYPE[duration];
172
+ if (!bar) {
173
+ throw `unsupported duration: ${duration}`;
174
+ }
175
+ // 从指定时间点向过去获取一页数据
176
+ const res = await client.getHistoryCandles({
177
+ instId,
178
+ bar,
179
+ after: `${new Date(time).getTime()}`,
180
+ limit: `300`,
181
+ });
182
+ if (res.code !== '0') {
183
+ throw `API failed: ${res.code} ${res.msg}`;
184
+ }
185
+ return res.data.map((x) => ({
186
+ series_id,
187
+ datasource_id,
188
+ product_id,
189
+ duration,
190
+ created_at: formatTime(+x[0]),
191
+ closed_at: formatTime(+x[0] + offset),
192
+ open: x[1],
193
+ high: x[2],
194
+ low: x[3],
195
+ close: x[4],
196
+ volume: x[5],
197
+ open_interest: '0',
198
+ }));
199
+ },
200
+ serviceOptions: {
201
+ // Rate limit: 20 requests per 2 seconds
202
+ egress_token_capacity: 20,
203
+ egress_token_refill_interval: 2000,
204
+ },
205
+ });
164
206
  //# sourceMappingURL=ohlc.js.map
package/dist/ohlc.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ohlc.js","sourceRoot":"","sources":["../src/ohlc.ts"],"names":[],"mappings":"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","sourcesContent":["import { IOHLC, provideOHLCDurationService } from '@yuants/data-ohlc';\nimport { createSeriesProvider } from '@yuants/data-series';\nimport { Terminal } from '@yuants/protocol';\nimport { writeToSQL } from '@yuants/sql';\nimport { convertDurationToOffset, decodePath, formatTime } from '@yuants/utils';\nimport { firstValueFrom, map, timer } from 'rxjs';\nimport { client } from './api';\nimport { useOHLC } from './ws';\n// import { useOHLC } from './websocket';\n\n// 时间粒度,默认值1m\n// 如 [1m/3m/5m/15m/30m/1H/2H/4H]\n// 香港时间开盘价k线:[6H/12H/1D/1W/1M]\n// UTC时间开盘价k线:[6Hutc/12Hutc/1Dutc/1Wutc/1Mutc]\n\nconst DURATION_TO_OKX_BAR_TYPE: Record<string, string> = {\n PT1M: '1m',\n PT3M: '3m',\n PT5M: '5m',\n PT15M: '15m',\n PT30M: '30m',\n\n PT1H: '1H',\n PT2H: '2H',\n PT4H: '4H',\n PT6H: '6H',\n PT12H: '12H',\n\n P1D: '1D',\n P1W: '1W',\n P1M: '1M',\n};\n\nconst DURATION_TO_OKX_CANDLE_TYPE: Record<string, string> = {\n PT1M: 'candle1m',\n PT3M: 'candle3m',\n PT5M: 'candle5m',\n PT15M: 'candle15m',\n PT30M: 'candle30m',\n\n PT1H: 'candle1H',\n PT2H: 'candle2H',\n PT4H: 'candle4H',\n PT6H: 'candle6H',\n PT12H: 'candle12H',\n\n P1D: 'candle1D',\n P1W: 'candle1W',\n P1M: 'candle1M',\n};\n\ncreateSeriesProvider<IOHLC>(Terminal.fromNodeEnv(), {\n tableName: 'ohlc',\n series_id_prefix_parts: ['OKX'],\n reversed: true,\n serviceOptions: { concurrent: 1 },\n queryFn: async function* ({ series_id, ended_at }) {\n const [datasource_id, product_id, duration] = decodePath(series_id);\n const offset = convertDurationToOffset(duration);\n if (!datasource_id) {\n throw 'datasource_id is required';\n }\n if (!product_id) {\n throw 'product_id is required';\n }\n if (!offset) {\n throw 'duration is invalid';\n }\n const [instType, instId] = decodePath(product_id);\n if (!instId) {\n throw `invalid product_id: ${product_id}`;\n }\n\n const bar = DURATION_TO_OKX_BAR_TYPE[duration];\n if (!bar) {\n throw `unsupported duration: ${duration}`;\n }\n\n let currentStartTime = ended_at;\n\n while (true) {\n // 向前翻页,时间降序,不含 after 时间点\n const res = await client.getHistoryCandles({\n instId,\n bar,\n after: `${currentStartTime}`,\n limit: '100',\n });\n if (res.code !== '0') {\n throw `API failed: ${res.code} ${res.msg}`;\n }\n if (res.data.length === 0) break;\n currentStartTime = +res.data[res.data.length - 1][0];\n const data = res.data.map(\n (x): IOHLC => ({\n series_id,\n datasource_id,\n product_id,\n duration,\n created_at: formatTime(+x[0]),\n closed_at: formatTime(+x[0] + offset),\n open: x[1],\n high: x[2],\n low: x[3],\n close: x[4],\n volume: x[5],\n open_interest: '0',\n }),\n );\n yield data;\n await firstValueFrom(timer(1000));\n }\n },\n});\n\nTerminal.fromNodeEnv().channel.publishChannel('ohlc', { pattern: `^OKX/` }, (series_id) => {\n const [datasource_id, product_id, duration] = decodePath(series_id);\n const [, instId] = decodePath(product_id);\n const offset = convertDurationToOffset(duration);\n if (!datasource_id) {\n throw 'datasource_id is required';\n }\n if (!product_id) {\n throw 'product_id is required';\n }\n if (!offset) {\n throw 'duration is invalid';\n }\n const candleType = DURATION_TO_OKX_CANDLE_TYPE[duration];\n console.info(formatTime(Date.now()), `subscribe`, series_id, product_id);\n\n return useOHLC(candleType, instId).pipe(\n map((data): IOHLC => {\n const created_at = Number(data[0][0]);\n const closed_at = created_at + offset;\n const open = data[0][1];\n const high = data[0][2];\n const low = data[0][3];\n const close = data[0][4];\n const volume = data[0][5];\n return {\n closed_at: formatTime(closed_at),\n created_at: formatTime(created_at),\n open,\n high,\n low,\n close,\n series_id,\n datasource_id,\n duration,\n product_id,\n volume,\n open_interest: '0',\n };\n }),\n writeToSQL({\n tableName: 'ohlc',\n conflictKeys: ['created_at', 'series_id'],\n writeInterval: 1000,\n terminal: Terminal.fromNodeEnv(),\n }),\n );\n});\n\n// 提供 OKX 的K线周期服务\nprovideOHLCDurationService(\n Terminal.fromNodeEnv(),\n 'OKX', // datasource_id\n () => Object.keys(DURATION_TO_OKX_BAR_TYPE),\n);\n"]}
1
+ {"version":3,"file":"ohlc.js","sourceRoot":"","sources":["../src/ohlc.ts"],"names":[],"mappings":"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","sourcesContent":["import { IOHLC } from '@yuants/data-ohlc';\nimport { createSeriesProvider } from '@yuants/data-series';\nimport { Terminal } from '@yuants/protocol';\nimport { writeToSQL } from '@yuants/sql';\nimport { convertDurationToOffset, decodePath, formatTime } from '@yuants/utils';\nimport { firstValueFrom, map, timer } from 'rxjs';\nimport { client } from './api';\nimport { provideOHLCFromTimeBackwardService } from './provideOHLCFromTimeBackwardService';\nimport { useOHLC } from './ws';\n// import { useOHLC } from './websocket';\n\nconst terminal = Terminal.fromNodeEnv();\n\n// 时间粒度,默认值1m\n// 如 [1m/3m/5m/15m/30m/1H/2H/4H]\n// 香港时间开盘价k线:[6H/12H/1D/1W/1M]\n// UTC时间开盘价k线:[6Hutc/12Hutc/1Dutc/1Wutc/1Mutc]\n\nconst DURATION_TO_OKX_BAR_TYPE: Record<string, string> = {\n PT1M: '1m',\n PT3M: '3m',\n PT5M: '5m',\n PT15M: '15m',\n PT30M: '30m',\n\n PT1H: '1H',\n PT2H: '2H',\n PT4H: '4H',\n PT6H: '6H',\n PT12H: '12H',\n\n P1D: '1D',\n P1W: '1W',\n P1M: '1M',\n};\n\nconst DURATION_TO_OKX_CANDLE_TYPE: Record<string, string> = {\n PT1M: 'candle1m',\n PT3M: 'candle3m',\n PT5M: 'candle5m',\n PT15M: 'candle15m',\n PT30M: 'candle30m',\n\n PT1H: 'candle1H',\n PT2H: 'candle2H',\n PT4H: 'candle4H',\n PT6H: 'candle6H',\n PT12H: 'candle12H',\n\n P1D: 'candle1D',\n P1W: 'candle1W',\n P1M: 'candle1M',\n};\n\ncreateSeriesProvider<IOHLC>(terminal, {\n tableName: 'ohlc',\n series_id_prefix_parts: ['OKX'],\n reversed: true,\n serviceOptions: { concurrent: 1 },\n queryFn: async function* ({ series_id, ended_at }) {\n const [datasource_id, product_id, duration] = decodePath(series_id);\n const offset = convertDurationToOffset(duration);\n if (!datasource_id) {\n throw 'datasource_id is required';\n }\n if (!product_id) {\n throw 'product_id is required';\n }\n if (!offset) {\n throw 'duration is invalid';\n }\n const [instType, instId] = decodePath(product_id);\n if (!instId) {\n throw `invalid product_id: ${product_id}`;\n }\n\n const bar = DURATION_TO_OKX_BAR_TYPE[duration];\n if (!bar) {\n throw `unsupported duration: ${duration}`;\n }\n\n let currentStartTime = ended_at;\n\n while (true) {\n // 向前翻页,时间降序,不含 after 时间点\n const res = await client.getHistoryCandles({\n instId,\n bar,\n after: `${currentStartTime}`,\n limit: '100',\n });\n if (res.code !== '0') {\n throw `API failed: ${res.code} ${res.msg}`;\n }\n if (res.data.length === 0) break;\n currentStartTime = +res.data[res.data.length - 1][0];\n const data = res.data.map(\n (x): IOHLC => ({\n series_id,\n datasource_id,\n product_id,\n duration,\n created_at: formatTime(+x[0]),\n closed_at: formatTime(+x[0] + offset),\n open: x[1],\n high: x[2],\n low: x[3],\n close: x[4],\n volume: x[5],\n open_interest: '0',\n }),\n );\n yield data;\n await firstValueFrom(timer(1000));\n }\n },\n});\n\nterminal.channel.publishChannel('ohlc', { pattern: `^OKX/` }, (series_id) => {\n const [datasource_id, product_id, duration] = decodePath(series_id);\n const [, instId] = decodePath(product_id);\n const offset = convertDurationToOffset(duration);\n if (!datasource_id) {\n throw 'datasource_id is required';\n }\n if (!product_id) {\n throw 'product_id is required';\n }\n if (!offset) {\n throw 'duration is invalid';\n }\n const candleType = DURATION_TO_OKX_CANDLE_TYPE[duration];\n console.info(formatTime(Date.now()), `subscribe`, series_id, product_id);\n\n return useOHLC(candleType, instId).pipe(\n map((data): IOHLC => {\n const created_at = Number(data[0][0]);\n const closed_at = created_at + offset;\n const open = data[0][1];\n const high = data[0][2];\n const low = data[0][3];\n const close = data[0][4];\n const volume = data[0][5];\n return {\n closed_at: formatTime(closed_at),\n created_at: formatTime(created_at),\n open,\n high,\n low,\n close,\n series_id,\n datasource_id,\n duration,\n product_id,\n volume,\n open_interest: '0',\n };\n }),\n writeToSQL({\n tableName: 'ohlc',\n conflictKeys: ['created_at', 'series_id'],\n writeInterval: 1000,\n terminal: Terminal.fromNodeEnv(),\n }),\n );\n});\n\nprovideOHLCFromTimeBackwardService({\n terminal,\n datasource_id: 'OKX',\n supported_durations: Object.keys(DURATION_TO_OKX_BAR_TYPE),\n queryFn: async ({ series_id, datasource_id, product_id, duration, offset, time }) => {\n const [instType, instId] = decodePath(product_id);\n if (!instId) {\n throw `invalid product_id: ${product_id}`;\n }\n\n const bar = DURATION_TO_OKX_BAR_TYPE[duration];\n if (!bar) {\n throw `unsupported duration: ${duration}`;\n }\n\n // 从指定时间点向过去获取一页数据\n const res = await client.getHistoryCandles({\n instId,\n bar,\n after: `${new Date(time).getTime()}`,\n limit: `300`,\n });\n\n if (res.code !== '0') {\n throw `API failed: ${res.code} ${res.msg}`;\n }\n\n return res.data.map(\n (x): IOHLC => ({\n series_id,\n datasource_id,\n product_id,\n duration,\n created_at: formatTime(+x[0]),\n closed_at: formatTime(+x[0] + offset),\n open: x[1],\n high: x[2],\n low: x[3],\n close: x[4],\n volume: x[5],\n open_interest: '0',\n }),\n );\n },\n serviceOptions: {\n // Rate limit: 20 requests per 2 seconds\n egress_token_capacity: 20,\n egress_token_refill_interval: 2000,\n },\n});\n"]}
@@ -0,0 +1,49 @@
1
+ import { provideOHLCDurationService } from '@yuants/data-ohlc';
2
+ import { provideSeriesFromTimeBackwardService } from './provideSeriesFromTimeBackwardService';
3
+ import { convertDurationToOffset, decodePath } from '@yuants/utils';
4
+ /**
5
+ * Provide OHLC from time backward service
6
+ *
7
+ * 提供 K线数据 按时间向后查询服务
8
+ *
9
+ * @public
10
+ */
11
+ export const provideOHLCFromTimeBackwardService = (ctx) => {
12
+ const supportedDurations = new Set(ctx.supported_durations);
13
+ provideOHLCDurationService(ctx.terminal, ctx.datasource_id, () => ctx.supported_durations);
14
+ provideSeriesFromTimeBackwardService({
15
+ terminal: ctx.terminal,
16
+ type: 'ohlc',
17
+ series_id_prefix_parts: [ctx.datasource_id],
18
+ queryFn: async ({ series_id, time }) => {
19
+ // series_id 格式: OKX/{product_id}/{duration}
20
+ // 其中 product_id 可能包含转义的 /,如 SPOT\/BTC-USDT
21
+ const [datasource_id, product_id, duration] = decodePath(series_id);
22
+ if (supportedDurations && !supportedDurations.has(duration)) {
23
+ throw `duration ${duration} is not supported`;
24
+ }
25
+ const offset = convertDurationToOffset(duration);
26
+ if (!datasource_id) {
27
+ throw 'datasource_id is required';
28
+ }
29
+ if (!product_id) {
30
+ throw 'product_id is required';
31
+ }
32
+ if (isNaN(offset)) {
33
+ throw 'duration is invalid';
34
+ }
35
+ const data = await ctx.queryFn({
36
+ //
37
+ series_id,
38
+ datasource_id,
39
+ product_id,
40
+ duration,
41
+ offset,
42
+ time,
43
+ });
44
+ return data;
45
+ },
46
+ serviceOptions: ctx.serviceOptions,
47
+ });
48
+ };
49
+ //# sourceMappingURL=provideOHLCFromTimeBackwardService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provideOHLCFromTimeBackwardService.js","sourceRoot":"","sources":["../src/provideOHLCFromTimeBackwardService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAEtE,OAAO,EAAE,oCAAoC,EAAE,MAAM,wCAAwC,CAAC;AAC9F,OAAO,EAAE,uBAAuB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEpE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,kCAAkC,GAAG,CAAC,GAalD,EAAE,EAAE;IACH,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAE5D,0BAA0B,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAE3F,oCAAoC,CAAQ;QAC1C,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,IAAI,EAAE,MAAM;QACZ,sBAAsB,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC;QAC3C,OAAO,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE;YACrC,4CAA4C;YAC5C,2CAA2C;YAC3C,MAAM,CAAC,aAAa,EAAE,UAAU,EAAE,QAAQ,CAAC,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;YAEpE,IAAI,kBAAkB,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;gBAC3D,MAAM,YAAY,QAAQ,mBAAmB,CAAC;aAC/C;YAED,MAAM,MAAM,GAAG,uBAAuB,CAAC,QAAQ,CAAC,CAAC;YACjD,IAAI,CAAC,aAAa,EAAE;gBAClB,MAAM,2BAA2B,CAAC;aACnC;YACD,IAAI,CAAC,UAAU,EAAE;gBACf,MAAM,wBAAwB,CAAC;aAChC;YACD,IAAI,KAAK,CAAC,MAAM,CAAC,EAAE;gBACjB,MAAM,qBAAqB,CAAC;aAC7B;YACD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC;gBAC7B,EAAE;gBACF,SAAS;gBACT,aAAa;gBACb,UAAU;gBACV,QAAQ;gBACR,MAAM;gBACN,IAAI;aACL,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACd,CAAC;QACD,cAAc,EAAE,GAAG,CAAC,cAAc;KACnC,CAAC,CAAC;AACL,CAAC,CAAC","sourcesContent":["import { IOHLC, provideOHLCDurationService } from '@yuants/data-ohlc';\nimport { IServiceOptions, Terminal } from '@yuants/protocol';\nimport { provideSeriesFromTimeBackwardService } from './provideSeriesFromTimeBackwardService';\nimport { convertDurationToOffset, decodePath } from '@yuants/utils';\n\n/**\n * Provide OHLC from time backward service\n *\n * 提供 K线数据 按时间向后查询服务\n *\n * @public\n */\nexport const provideOHLCFromTimeBackwardService = (ctx: {\n terminal: Terminal;\n datasource_id: string;\n supported_durations: string[];\n queryFn: (ctx: {\n series_id: string;\n datasource_id: string;\n product_id: string;\n duration: string;\n offset: number;\n time: string;\n }) => Promise<IOHLC[]>;\n serviceOptions: IServiceOptions;\n}) => {\n const supportedDurations = new Set(ctx.supported_durations);\n\n provideOHLCDurationService(ctx.terminal, ctx.datasource_id, () => ctx.supported_durations);\n\n provideSeriesFromTimeBackwardService<IOHLC>({\n terminal: ctx.terminal,\n type: 'ohlc',\n series_id_prefix_parts: [ctx.datasource_id],\n queryFn: async ({ series_id, time }) => {\n // series_id 格式: OKX/{product_id}/{duration}\n // 其中 product_id 可能包含转义的 /,如 SPOT\\/BTC-USDT\n const [datasource_id, product_id, duration] = decodePath(series_id);\n\n if (supportedDurations && !supportedDurations.has(duration)) {\n throw `duration ${duration} is not supported`;\n }\n\n const offset = convertDurationToOffset(duration);\n if (!datasource_id) {\n throw 'datasource_id is required';\n }\n if (!product_id) {\n throw 'product_id is required';\n }\n if (isNaN(offset)) {\n throw 'duration is invalid';\n }\n const data = await ctx.queryFn({\n //\n series_id,\n datasource_id,\n product_id,\n duration,\n offset,\n time,\n });\n return data;\n },\n serviceOptions: ctx.serviceOptions,\n });\n};\n"]}
@@ -0,0 +1,54 @@
1
+ import { buildInsertManyIntoTableSQL, requestSQL } from '@yuants/sql';
2
+ import { encodePath, escapeRegExp } from '@yuants/utils';
3
+ /**
4
+ * Provide series from time backward service
5
+ *
6
+ * 提供从时间点向前查询序列数据的服务
7
+ *
8
+ * @public
9
+ */
10
+ export const provideSeriesFromTimeBackwardService = (ctx) => {
11
+ ctx.terminal.server.provideService('QuerySeriesFromTimeBackward', {
12
+ type: 'object',
13
+ required: ['type', 'series_id', 'time'],
14
+ properties: {
15
+ type: { const: ctx.type },
16
+ series_id: { type: 'string', pattern: `^${escapeRegExp(encodePath(ctx.series_id_prefix_parts))}/` },
17
+ time: { type: 'string', format: 'date-time' },
18
+ },
19
+ }, async (msg) => {
20
+ const { time, series_id } = msg.req;
21
+ const data = await ctx.queryFn({ series_id, time });
22
+ return {
23
+ res: {
24
+ code: 0,
25
+ message: 'OK',
26
+ data,
27
+ },
28
+ };
29
+ }, ctx.serviceOptions);
30
+ ctx.terminal.server.provideService('UpdateSeriesFromTimeBackward', {
31
+ type: 'object',
32
+ required: ['type', 'series_id', 'time'],
33
+ properties: {
34
+ type: { const: ctx.type },
35
+ series_id: { type: 'string' },
36
+ time: { type: 'string', format: 'date-time' },
37
+ },
38
+ }, async (msg) => {
39
+ const data = await ctx.terminal.client.requestForResponseData('QuerySeriesFromTimeBackward', msg.req);
40
+ await requestSQL(ctx.terminal, buildInsertManyIntoTableSQL(data, 'ohlc', {
41
+ conflictKeys: ['series_id', 'created_at'],
42
+ }));
43
+ return {
44
+ res: {
45
+ code: 0,
46
+ message: 'OK',
47
+ data: {
48
+ count: data.length,
49
+ },
50
+ },
51
+ };
52
+ });
53
+ };
54
+ //# sourceMappingURL=provideSeriesFromTimeBackwardService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provideSeriesFromTimeBackwardService.js","sourceRoot":"","sources":["../src/provideSeriesFromTimeBackwardService.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,2BAA2B,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAEzD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,oCAAoC,GAAG,CAElD,GAMD,EAAE,EAAE;IAOH,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,cAAc,CAChC,6BAA6B,EAC7B;QACE,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC;QACvC,UAAU,EAAE;YACV,IAAI,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE;YACzB,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC,GAAG,EAAE;YACnG,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE;SAC9C;KACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC;QAEpC,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEpD,OAAO;YACL,GAAG,EAAE;gBACH,IAAI,EAAE,CAAC;gBACP,OAAO,EAAE,IAAI;gBACb,IAAI;aACL;SACF,CAAC;IACJ,CAAC,EACD,GAAG,CAAC,cAAc,CACnB,CAAC;IAEF,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,cAAc,CAChC,8BAA8B,EAC9B;QACE,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC;QACvC,UAAU,EAAE;YACV,IAAI,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE;YACzB,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC7B,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE;SAC9C;KACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CAC3D,6BAA6B,EAC7B,GAAG,CAAC,GAAG,CACR,CAAC;QAEF,MAAM,UAAU,CACd,GAAG,CAAC,QAAQ,EACZ,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE;YACxC,YAAY,EAAE,CAAC,WAAW,EAAE,YAAY,CAAC;SAC1C,CAAC,CACH,CAAC;QAEF,OAAO;YACL,GAAG,EAAE;gBACH,IAAI,EAAE,CAAC;gBACP,OAAO,EAAE,IAAI;gBACb,IAAI,EAAE;oBACJ,KAAK,EAAE,IAAI,CAAC,MAAM;iBACnB;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { IServiceOptions, Terminal } from '@yuants/protocol';\nimport { buildInsertManyIntoTableSQL, requestSQL } from '@yuants/sql';\nimport { encodePath, escapeRegExp } from '@yuants/utils';\n\n/**\n * Provide series from time backward service\n *\n * 提供从时间点向前查询序列数据的服务\n *\n * @public\n */\nexport const provideSeriesFromTimeBackwardService = <\n T extends { series_id: string; created_at: string },\n>(ctx: {\n terminal: Terminal;\n type: string;\n series_id_prefix_parts: string[];\n queryFn: (ctx: { series_id: string; time: string }) => Promise<T[]>;\n serviceOptions?: IServiceOptions;\n}) => {\n interface IQuerySeriesFromTimeBackwardReq {\n time: string;\n type: string;\n series_id: string;\n }\n\n ctx.terminal.server.provideService<IQuerySeriesFromTimeBackwardReq, T[]>(\n 'QuerySeriesFromTimeBackward',\n {\n type: 'object',\n required: ['type', 'series_id', 'time'],\n properties: {\n type: { const: ctx.type },\n series_id: { type: 'string', pattern: `^${escapeRegExp(encodePath(ctx.series_id_prefix_parts))}/` },\n time: { type: 'string', format: 'date-time' },\n },\n },\n async (msg) => {\n const { time, series_id } = msg.req;\n\n const data = await ctx.queryFn({ series_id, time });\n\n return {\n res: {\n code: 0,\n message: 'OK',\n data,\n },\n };\n },\n ctx.serviceOptions,\n );\n\n ctx.terminal.server.provideService<IQuerySeriesFromTimeBackwardReq, {}>(\n 'UpdateSeriesFromTimeBackward',\n {\n type: 'object',\n required: ['type', 'series_id', 'time'],\n properties: {\n type: { const: ctx.type },\n series_id: { type: 'string' },\n time: { type: 'string', format: 'date-time' },\n },\n },\n async (msg) => {\n const data = await ctx.terminal.client.requestForResponseData<IQuerySeriesFromTimeBackwardReq, T[]>(\n 'QuerySeriesFromTimeBackward',\n msg.req,\n );\n\n await requestSQL(\n ctx.terminal,\n buildInsertManyIntoTableSQL(data, 'ohlc', {\n conflictKeys: ['series_id', 'created_at'],\n }),\n );\n\n return {\n res: {\n code: 0,\n message: 'OK',\n data: {\n count: data.length,\n },\n },\n };\n },\n );\n};\n"]}
package/lib/ohlc.js CHANGED
@@ -12,15 +12,16 @@ var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _ar
12
12
  function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- const data_ohlc_1 = require("@yuants/data-ohlc");
16
15
  const data_series_1 = require("@yuants/data-series");
17
16
  const protocol_1 = require("@yuants/protocol");
18
17
  const sql_1 = require("@yuants/sql");
19
18
  const utils_1 = require("@yuants/utils");
20
19
  const rxjs_1 = require("rxjs");
21
20
  const api_1 = require("./api");
21
+ const provideOHLCFromTimeBackwardService_1 = require("./provideOHLCFromTimeBackwardService");
22
22
  const ws_1 = require("./ws");
23
23
  // import { useOHLC } from './websocket';
24
+ const terminal = protocol_1.Terminal.fromNodeEnv();
24
25
  // 时间粒度,默认值1m
25
26
  // 如 [1m/3m/5m/15m/30m/1H/2H/4H]
26
27
  // 香港时间开盘价k线:[6H/12H/1D/1W/1M]
@@ -55,7 +56,7 @@ const DURATION_TO_OKX_CANDLE_TYPE = {
55
56
  P1W: 'candle1W',
56
57
  P1M: 'candle1M',
57
58
  };
58
- (0, data_series_1.createSeriesProvider)(protocol_1.Terminal.fromNodeEnv(), {
59
+ (0, data_series_1.createSeriesProvider)(terminal, {
59
60
  tableName: 'ohlc',
60
61
  series_id_prefix_parts: ['OKX'],
61
62
  reversed: true,
@@ -116,7 +117,7 @@ const DURATION_TO_OKX_CANDLE_TYPE = {
116
117
  });
117
118
  },
118
119
  });
119
- protocol_1.Terminal.fromNodeEnv().channel.publishChannel('ohlc', { pattern: `^OKX/` }, (series_id) => {
120
+ terminal.channel.publishChannel('ohlc', { pattern: `^OKX/` }, (series_id) => {
120
121
  const [datasource_id, product_id, duration] = (0, utils_1.decodePath)(series_id);
121
122
  const [, instId] = (0, utils_1.decodePath)(product_id);
122
123
  const offset = (0, utils_1.convertDurationToOffset)(duration);
@@ -160,7 +161,48 @@ protocol_1.Terminal.fromNodeEnv().channel.publishChannel('ohlc', { pattern: `^OK
160
161
  terminal: protocol_1.Terminal.fromNodeEnv(),
161
162
  }));
162
163
  });
163
- // 提供 OKX 的K线周期服务
164
- (0, data_ohlc_1.provideOHLCDurationService)(protocol_1.Terminal.fromNodeEnv(), 'OKX', // datasource_id
165
- () => Object.keys(DURATION_TO_OKX_BAR_TYPE));
164
+ (0, provideOHLCFromTimeBackwardService_1.provideOHLCFromTimeBackwardService)({
165
+ terminal,
166
+ datasource_id: 'OKX',
167
+ supported_durations: Object.keys(DURATION_TO_OKX_BAR_TYPE),
168
+ queryFn: async ({ series_id, datasource_id, product_id, duration, offset, time }) => {
169
+ const [instType, instId] = (0, utils_1.decodePath)(product_id);
170
+ if (!instId) {
171
+ throw `invalid product_id: ${product_id}`;
172
+ }
173
+ const bar = DURATION_TO_OKX_BAR_TYPE[duration];
174
+ if (!bar) {
175
+ throw `unsupported duration: ${duration}`;
176
+ }
177
+ // 从指定时间点向过去获取一页数据
178
+ const res = await api_1.client.getHistoryCandles({
179
+ instId,
180
+ bar,
181
+ after: `${new Date(time).getTime()}`,
182
+ limit: `300`,
183
+ });
184
+ if (res.code !== '0') {
185
+ throw `API failed: ${res.code} ${res.msg}`;
186
+ }
187
+ return res.data.map((x) => ({
188
+ series_id,
189
+ datasource_id,
190
+ product_id,
191
+ duration,
192
+ created_at: (0, utils_1.formatTime)(+x[0]),
193
+ closed_at: (0, utils_1.formatTime)(+x[0] + offset),
194
+ open: x[1],
195
+ high: x[2],
196
+ low: x[3],
197
+ close: x[4],
198
+ volume: x[5],
199
+ open_interest: '0',
200
+ }));
201
+ },
202
+ serviceOptions: {
203
+ // Rate limit: 20 requests per 2 seconds
204
+ egress_token_capacity: 20,
205
+ egress_token_refill_interval: 2000,
206
+ },
207
+ });
166
208
  //# sourceMappingURL=ohlc.js.map
package/lib/ohlc.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ohlc.js","sourceRoot":"","sources":["../src/ohlc.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA,iDAAsE;AACtE,qDAA2D;AAC3D,+CAA4C;AAC5C,qCAAyC;AACzC,yCAAgF;AAChF,+BAAkD;AAClD,+BAA+B;AAC/B,6BAA+B;AAC/B,yCAAyC;AAEzC,aAAa;AACb,gCAAgC;AAChC,8BAA8B;AAC9B,8CAA8C;AAE9C,MAAM,wBAAwB,GAA2B;IACvD,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,KAAK;IACZ,KAAK,EAAE,KAAK;IAEZ,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,KAAK;IAEZ,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;CACV,CAAC;AAEF,MAAM,2BAA2B,GAA2B;IAC1D,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,WAAW;IAClB,KAAK,EAAE,WAAW;IAElB,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,WAAW;IAElB,GAAG,EAAE,UAAU;IACf,GAAG,EAAE,UAAU;IACf,GAAG,EAAE,UAAU;CAChB,CAAC;AAEF,IAAA,kCAAoB,EAAQ,mBAAQ,CAAC,WAAW,EAAE,EAAE;IAClD,SAAS,EAAE,MAAM;IACjB,sBAAsB,EAAE,CAAC,KAAK,CAAC;IAC/B,QAAQ,EAAE,IAAI;IACd,cAAc,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE;IACjC,OAAO,EAAE,UAAiB,EAAE,SAAS,EAAE,QAAQ,EAAE;;YAC/C,MAAM,CAAC,aAAa,EAAE,UAAU,EAAE,QAAQ,CAAC,GAAG,IAAA,kBAAU,EAAC,SAAS,CAAC,CAAC;YACpE,MAAM,MAAM,GAAG,IAAA,+BAAuB,EAAC,QAAQ,CAAC,CAAC;YACjD,IAAI,CAAC,aAAa,EAAE;gBAClB,MAAM,2BAA2B,CAAC;aACnC;YACD,IAAI,CAAC,UAAU,EAAE;gBACf,MAAM,wBAAwB,CAAC;aAChC;YACD,IAAI,CAAC,MAAM,EAAE;gBACX,MAAM,qBAAqB,CAAC;aAC7B;YACD,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,IAAA,kBAAU,EAAC,UAAU,CAAC,CAAC;YAClD,IAAI,CAAC,MAAM,EAAE;gBACX,MAAM,uBAAuB,UAAU,EAAE,CAAC;aAC3C;YAED,MAAM,GAAG,GAAG,wBAAwB,CAAC,QAAQ,CAAC,CAAC;YAC/C,IAAI,CAAC,GAAG,EAAE;gBACR,MAAM,yBAAyB,QAAQ,EAAE,CAAC;aAC3C;YAED,IAAI,gBAAgB,GAAG,QAAQ,CAAC;YAEhC,OAAO,IAAI,EAAE;gBACX,yBAAyB;gBACzB,MAAM,GAAG,GAAG,cAAM,YAAM,CAAC,iBAAiB,CAAC;oBACzC,MAAM;oBACN,GAAG;oBACH,KAAK,EAAE,GAAG,gBAAgB,EAAE;oBAC5B,KAAK,EAAE,KAAK;iBACb,CAAC,CAAA,CAAC;gBACH,IAAI,GAAG,CAAC,IAAI,KAAK,GAAG,EAAE;oBACpB,MAAM,eAAe,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,GAAG,EAAE,CAAC;iBAC5C;gBACD,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC;oBAAE,MAAM;gBACjC,gBAAgB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBACrD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,CACvB,CAAC,CAAC,EAAS,EAAE,CAAC,CAAC;oBACb,SAAS;oBACT,aAAa;oBACb,UAAU;oBACV,QAAQ;oBACR,UAAU,EAAE,IAAA,kBAAU,EAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBAC7B,SAAS,EAAE,IAAA,kBAAU,EAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC;oBACrC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;oBACV,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;oBACV,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;oBACT,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;oBACX,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;oBACZ,aAAa,EAAE,GAAG;iBACnB,CAAC,CACH,CAAC;gBACF,oBAAM,IAAI,CAAA,CAAC;gBACX,cAAM,IAAA,qBAAc,EAAC,IAAA,YAAK,EAAC,IAAI,CAAC,CAAC,CAAA,CAAC;aACnC;QACH,CAAC;KAAA;CACF,CAAC,CAAC;AAEH,mBAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,cAAc,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,SAAS,EAAE,EAAE;IACxF,MAAM,CAAC,aAAa,EAAE,UAAU,EAAE,QAAQ,CAAC,GAAG,IAAA,kBAAU,EAAC,SAAS,CAAC,CAAC;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC,GAAG,IAAA,kBAAU,EAAC,UAAU,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,IAAA,+BAAuB,EAAC,QAAQ,CAAC,CAAC;IACjD,IAAI,CAAC,aAAa,EAAE;QAClB,MAAM,2BAA2B,CAAC;KACnC;IACD,IAAI,CAAC,UAAU,EAAE;QACf,MAAM,wBAAwB,CAAC;KAChC;IACD,IAAI,CAAC,MAAM,EAAE;QACX,MAAM,qBAAqB,CAAC;KAC7B;IACD,MAAM,UAAU,GAAG,2BAA2B,CAAC,QAAQ,CAAC,CAAC;IACzD,OAAO,CAAC,IAAI,CAAC,IAAA,kBAAU,EAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IAEzE,OAAO,IAAA,YAAO,EAAC,UAAU,EAAE,MAAM,CAAC,CAAC,IAAI,CACrC,IAAA,UAAG,EAAC,CAAC,IAAI,EAAS,EAAE;QAClB,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;QACtC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACxB,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1B,OAAO;YACL,SAAS,EAAE,IAAA,kBAAU,EAAC,SAAS,CAAC;YAChC,UAAU,EAAE,IAAA,kBAAU,EAAC,UAAU,CAAC;YAClC,IAAI;YACJ,IAAI;YACJ,GAAG;YACH,KAAK;YACL,SAAS;YACT,aAAa;YACb,QAAQ;YACR,UAAU;YACV,MAAM;YACN,aAAa,EAAE,GAAG;SACnB,CAAC;IACJ,CAAC,CAAC,EACF,IAAA,gBAAU,EAAC;QACT,SAAS,EAAE,MAAM;QACjB,YAAY,EAAE,CAAC,YAAY,EAAE,WAAW,CAAC;QACzC,aAAa,EAAE,IAAI;QACnB,QAAQ,EAAE,mBAAQ,CAAC,WAAW,EAAE;KACjC,CAAC,CACH,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,iBAAiB;AACjB,IAAA,sCAA0B,EACxB,mBAAQ,CAAC,WAAW,EAAE,EACtB,KAAK,EAAE,gBAAgB;AACvB,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAC5C,CAAC","sourcesContent":["import { IOHLC, provideOHLCDurationService } from '@yuants/data-ohlc';\nimport { createSeriesProvider } from '@yuants/data-series';\nimport { Terminal } from '@yuants/protocol';\nimport { writeToSQL } from '@yuants/sql';\nimport { convertDurationToOffset, decodePath, formatTime } from '@yuants/utils';\nimport { firstValueFrom, map, timer } from 'rxjs';\nimport { client } from './api';\nimport { useOHLC } from './ws';\n// import { useOHLC } from './websocket';\n\n// 时间粒度,默认值1m\n// 如 [1m/3m/5m/15m/30m/1H/2H/4H]\n// 香港时间开盘价k线:[6H/12H/1D/1W/1M]\n// UTC时间开盘价k线:[6Hutc/12Hutc/1Dutc/1Wutc/1Mutc]\n\nconst DURATION_TO_OKX_BAR_TYPE: Record<string, string> = {\n PT1M: '1m',\n PT3M: '3m',\n PT5M: '5m',\n PT15M: '15m',\n PT30M: '30m',\n\n PT1H: '1H',\n PT2H: '2H',\n PT4H: '4H',\n PT6H: '6H',\n PT12H: '12H',\n\n P1D: '1D',\n P1W: '1W',\n P1M: '1M',\n};\n\nconst DURATION_TO_OKX_CANDLE_TYPE: Record<string, string> = {\n PT1M: 'candle1m',\n PT3M: 'candle3m',\n PT5M: 'candle5m',\n PT15M: 'candle15m',\n PT30M: 'candle30m',\n\n PT1H: 'candle1H',\n PT2H: 'candle2H',\n PT4H: 'candle4H',\n PT6H: 'candle6H',\n PT12H: 'candle12H',\n\n P1D: 'candle1D',\n P1W: 'candle1W',\n P1M: 'candle1M',\n};\n\ncreateSeriesProvider<IOHLC>(Terminal.fromNodeEnv(), {\n tableName: 'ohlc',\n series_id_prefix_parts: ['OKX'],\n reversed: true,\n serviceOptions: { concurrent: 1 },\n queryFn: async function* ({ series_id, ended_at }) {\n const [datasource_id, product_id, duration] = decodePath(series_id);\n const offset = convertDurationToOffset(duration);\n if (!datasource_id) {\n throw 'datasource_id is required';\n }\n if (!product_id) {\n throw 'product_id is required';\n }\n if (!offset) {\n throw 'duration is invalid';\n }\n const [instType, instId] = decodePath(product_id);\n if (!instId) {\n throw `invalid product_id: ${product_id}`;\n }\n\n const bar = DURATION_TO_OKX_BAR_TYPE[duration];\n if (!bar) {\n throw `unsupported duration: ${duration}`;\n }\n\n let currentStartTime = ended_at;\n\n while (true) {\n // 向前翻页,时间降序,不含 after 时间点\n const res = await client.getHistoryCandles({\n instId,\n bar,\n after: `${currentStartTime}`,\n limit: '100',\n });\n if (res.code !== '0') {\n throw `API failed: ${res.code} ${res.msg}`;\n }\n if (res.data.length === 0) break;\n currentStartTime = +res.data[res.data.length - 1][0];\n const data = res.data.map(\n (x): IOHLC => ({\n series_id,\n datasource_id,\n product_id,\n duration,\n created_at: formatTime(+x[0]),\n closed_at: formatTime(+x[0] + offset),\n open: x[1],\n high: x[2],\n low: x[3],\n close: x[4],\n volume: x[5],\n open_interest: '0',\n }),\n );\n yield data;\n await firstValueFrom(timer(1000));\n }\n },\n});\n\nTerminal.fromNodeEnv().channel.publishChannel('ohlc', { pattern: `^OKX/` }, (series_id) => {\n const [datasource_id, product_id, duration] = decodePath(series_id);\n const [, instId] = decodePath(product_id);\n const offset = convertDurationToOffset(duration);\n if (!datasource_id) {\n throw 'datasource_id is required';\n }\n if (!product_id) {\n throw 'product_id is required';\n }\n if (!offset) {\n throw 'duration is invalid';\n }\n const candleType = DURATION_TO_OKX_CANDLE_TYPE[duration];\n console.info(formatTime(Date.now()), `subscribe`, series_id, product_id);\n\n return useOHLC(candleType, instId).pipe(\n map((data): IOHLC => {\n const created_at = Number(data[0][0]);\n const closed_at = created_at + offset;\n const open = data[0][1];\n const high = data[0][2];\n const low = data[0][3];\n const close = data[0][4];\n const volume = data[0][5];\n return {\n closed_at: formatTime(closed_at),\n created_at: formatTime(created_at),\n open,\n high,\n low,\n close,\n series_id,\n datasource_id,\n duration,\n product_id,\n volume,\n open_interest: '0',\n };\n }),\n writeToSQL({\n tableName: 'ohlc',\n conflictKeys: ['created_at', 'series_id'],\n writeInterval: 1000,\n terminal: Terminal.fromNodeEnv(),\n }),\n );\n});\n\n// 提供 OKX 的K线周期服务\nprovideOHLCDurationService(\n Terminal.fromNodeEnv(),\n 'OKX', // datasource_id\n () => Object.keys(DURATION_TO_OKX_BAR_TYPE),\n);\n"]}
1
+ {"version":3,"file":"ohlc.js","sourceRoot":"","sources":["../src/ohlc.ts"],"names":[],"mappings":"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","sourcesContent":["import { IOHLC } from '@yuants/data-ohlc';\nimport { createSeriesProvider } from '@yuants/data-series';\nimport { Terminal } from '@yuants/protocol';\nimport { writeToSQL } from '@yuants/sql';\nimport { convertDurationToOffset, decodePath, formatTime } from '@yuants/utils';\nimport { firstValueFrom, map, timer } from 'rxjs';\nimport { client } from './api';\nimport { provideOHLCFromTimeBackwardService } from './provideOHLCFromTimeBackwardService';\nimport { useOHLC } from './ws';\n// import { useOHLC } from './websocket';\n\nconst terminal = Terminal.fromNodeEnv();\n\n// 时间粒度,默认值1m\n// 如 [1m/3m/5m/15m/30m/1H/2H/4H]\n// 香港时间开盘价k线:[6H/12H/1D/1W/1M]\n// UTC时间开盘价k线:[6Hutc/12Hutc/1Dutc/1Wutc/1Mutc]\n\nconst DURATION_TO_OKX_BAR_TYPE: Record<string, string> = {\n PT1M: '1m',\n PT3M: '3m',\n PT5M: '5m',\n PT15M: '15m',\n PT30M: '30m',\n\n PT1H: '1H',\n PT2H: '2H',\n PT4H: '4H',\n PT6H: '6H',\n PT12H: '12H',\n\n P1D: '1D',\n P1W: '1W',\n P1M: '1M',\n};\n\nconst DURATION_TO_OKX_CANDLE_TYPE: Record<string, string> = {\n PT1M: 'candle1m',\n PT3M: 'candle3m',\n PT5M: 'candle5m',\n PT15M: 'candle15m',\n PT30M: 'candle30m',\n\n PT1H: 'candle1H',\n PT2H: 'candle2H',\n PT4H: 'candle4H',\n PT6H: 'candle6H',\n PT12H: 'candle12H',\n\n P1D: 'candle1D',\n P1W: 'candle1W',\n P1M: 'candle1M',\n};\n\ncreateSeriesProvider<IOHLC>(terminal, {\n tableName: 'ohlc',\n series_id_prefix_parts: ['OKX'],\n reversed: true,\n serviceOptions: { concurrent: 1 },\n queryFn: async function* ({ series_id, ended_at }) {\n const [datasource_id, product_id, duration] = decodePath(series_id);\n const offset = convertDurationToOffset(duration);\n if (!datasource_id) {\n throw 'datasource_id is required';\n }\n if (!product_id) {\n throw 'product_id is required';\n }\n if (!offset) {\n throw 'duration is invalid';\n }\n const [instType, instId] = decodePath(product_id);\n if (!instId) {\n throw `invalid product_id: ${product_id}`;\n }\n\n const bar = DURATION_TO_OKX_BAR_TYPE[duration];\n if (!bar) {\n throw `unsupported duration: ${duration}`;\n }\n\n let currentStartTime = ended_at;\n\n while (true) {\n // 向前翻页,时间降序,不含 after 时间点\n const res = await client.getHistoryCandles({\n instId,\n bar,\n after: `${currentStartTime}`,\n limit: '100',\n });\n if (res.code !== '0') {\n throw `API failed: ${res.code} ${res.msg}`;\n }\n if (res.data.length === 0) break;\n currentStartTime = +res.data[res.data.length - 1][0];\n const data = res.data.map(\n (x): IOHLC => ({\n series_id,\n datasource_id,\n product_id,\n duration,\n created_at: formatTime(+x[0]),\n closed_at: formatTime(+x[0] + offset),\n open: x[1],\n high: x[2],\n low: x[3],\n close: x[4],\n volume: x[5],\n open_interest: '0',\n }),\n );\n yield data;\n await firstValueFrom(timer(1000));\n }\n },\n});\n\nterminal.channel.publishChannel('ohlc', { pattern: `^OKX/` }, (series_id) => {\n const [datasource_id, product_id, duration] = decodePath(series_id);\n const [, instId] = decodePath(product_id);\n const offset = convertDurationToOffset(duration);\n if (!datasource_id) {\n throw 'datasource_id is required';\n }\n if (!product_id) {\n throw 'product_id is required';\n }\n if (!offset) {\n throw 'duration is invalid';\n }\n const candleType = DURATION_TO_OKX_CANDLE_TYPE[duration];\n console.info(formatTime(Date.now()), `subscribe`, series_id, product_id);\n\n return useOHLC(candleType, instId).pipe(\n map((data): IOHLC => {\n const created_at = Number(data[0][0]);\n const closed_at = created_at + offset;\n const open = data[0][1];\n const high = data[0][2];\n const low = data[0][3];\n const close = data[0][4];\n const volume = data[0][5];\n return {\n closed_at: formatTime(closed_at),\n created_at: formatTime(created_at),\n open,\n high,\n low,\n close,\n series_id,\n datasource_id,\n duration,\n product_id,\n volume,\n open_interest: '0',\n };\n }),\n writeToSQL({\n tableName: 'ohlc',\n conflictKeys: ['created_at', 'series_id'],\n writeInterval: 1000,\n terminal: Terminal.fromNodeEnv(),\n }),\n );\n});\n\nprovideOHLCFromTimeBackwardService({\n terminal,\n datasource_id: 'OKX',\n supported_durations: Object.keys(DURATION_TO_OKX_BAR_TYPE),\n queryFn: async ({ series_id, datasource_id, product_id, duration, offset, time }) => {\n const [instType, instId] = decodePath(product_id);\n if (!instId) {\n throw `invalid product_id: ${product_id}`;\n }\n\n const bar = DURATION_TO_OKX_BAR_TYPE[duration];\n if (!bar) {\n throw `unsupported duration: ${duration}`;\n }\n\n // 从指定时间点向过去获取一页数据\n const res = await client.getHistoryCandles({\n instId,\n bar,\n after: `${new Date(time).getTime()}`,\n limit: `300`,\n });\n\n if (res.code !== '0') {\n throw `API failed: ${res.code} ${res.msg}`;\n }\n\n return res.data.map(\n (x): IOHLC => ({\n series_id,\n datasource_id,\n product_id,\n duration,\n created_at: formatTime(+x[0]),\n closed_at: formatTime(+x[0] + offset),\n open: x[1],\n high: x[2],\n low: x[3],\n close: x[4],\n volume: x[5],\n open_interest: '0',\n }),\n );\n },\n serviceOptions: {\n // Rate limit: 20 requests per 2 seconds\n egress_token_capacity: 20,\n egress_token_refill_interval: 2000,\n },\n});\n"]}
@@ -0,0 +1,24 @@
1
+ import { IOHLC } from '@yuants/data-ohlc';
2
+ import { IServiceOptions, Terminal } from '@yuants/protocol';
3
+ /**
4
+ * Provide OHLC from time backward service
5
+ *
6
+ * 提供 K线数据 按时间向后查询服务
7
+ *
8
+ * @public
9
+ */
10
+ export declare const provideOHLCFromTimeBackwardService: (ctx: {
11
+ terminal: Terminal;
12
+ datasource_id: string;
13
+ supported_durations: string[];
14
+ queryFn: (ctx: {
15
+ series_id: string;
16
+ datasource_id: string;
17
+ product_id: string;
18
+ duration: string;
19
+ offset: number;
20
+ time: string;
21
+ }) => Promise<IOHLC[]>;
22
+ serviceOptions: IServiceOptions;
23
+ }) => void;
24
+ //# sourceMappingURL=provideOHLCFromTimeBackwardService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provideOHLCFromTimeBackwardService.d.ts","sourceRoot":"","sources":["../src/provideOHLCFromTimeBackwardService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAA8B,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAI7D;;;;;;GAMG;AACH,eAAO,MAAM,kCAAkC;cACnC,QAAQ;mBACH,MAAM;yBACA,MAAM,EAAE;mBACd;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,EAAE,MAAM,CAAC;QACtB,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;KACd,KAAK,QAAQ,KAAK,EAAE,CAAC;oBACN,eAAe;UA0ChC,CAAC"}
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.provideOHLCFromTimeBackwardService = void 0;
4
+ const data_ohlc_1 = require("@yuants/data-ohlc");
5
+ const provideSeriesFromTimeBackwardService_1 = require("./provideSeriesFromTimeBackwardService");
6
+ const utils_1 = require("@yuants/utils");
7
+ /**
8
+ * Provide OHLC from time backward service
9
+ *
10
+ * 提供 K线数据 按时间向后查询服务
11
+ *
12
+ * @public
13
+ */
14
+ const provideOHLCFromTimeBackwardService = (ctx) => {
15
+ const supportedDurations = new Set(ctx.supported_durations);
16
+ (0, data_ohlc_1.provideOHLCDurationService)(ctx.terminal, ctx.datasource_id, () => ctx.supported_durations);
17
+ (0, provideSeriesFromTimeBackwardService_1.provideSeriesFromTimeBackwardService)({
18
+ terminal: ctx.terminal,
19
+ type: 'ohlc',
20
+ series_id_prefix_parts: [ctx.datasource_id],
21
+ queryFn: async ({ series_id, time }) => {
22
+ // series_id 格式: OKX/{product_id}/{duration}
23
+ // 其中 product_id 可能包含转义的 /,如 SPOT\/BTC-USDT
24
+ const [datasource_id, product_id, duration] = (0, utils_1.decodePath)(series_id);
25
+ if (supportedDurations && !supportedDurations.has(duration)) {
26
+ throw `duration ${duration} is not supported`;
27
+ }
28
+ const offset = (0, utils_1.convertDurationToOffset)(duration);
29
+ if (!datasource_id) {
30
+ throw 'datasource_id is required';
31
+ }
32
+ if (!product_id) {
33
+ throw 'product_id is required';
34
+ }
35
+ if (isNaN(offset)) {
36
+ throw 'duration is invalid';
37
+ }
38
+ const data = await ctx.queryFn({
39
+ //
40
+ series_id,
41
+ datasource_id,
42
+ product_id,
43
+ duration,
44
+ offset,
45
+ time,
46
+ });
47
+ return data;
48
+ },
49
+ serviceOptions: ctx.serviceOptions,
50
+ });
51
+ };
52
+ exports.provideOHLCFromTimeBackwardService = provideOHLCFromTimeBackwardService;
53
+ //# sourceMappingURL=provideOHLCFromTimeBackwardService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provideOHLCFromTimeBackwardService.js","sourceRoot":"","sources":["../src/provideOHLCFromTimeBackwardService.ts"],"names":[],"mappings":";;;AAAA,iDAAsE;AAEtE,iGAA8F;AAC9F,yCAAoE;AAEpE;;;;;;GAMG;AACI,MAAM,kCAAkC,GAAG,CAAC,GAalD,EAAE,EAAE;IACH,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAE5D,IAAA,sCAA0B,EAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAE3F,IAAA,2EAAoC,EAAQ;QAC1C,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,IAAI,EAAE,MAAM;QACZ,sBAAsB,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC;QAC3C,OAAO,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE;YACrC,4CAA4C;YAC5C,2CAA2C;YAC3C,MAAM,CAAC,aAAa,EAAE,UAAU,EAAE,QAAQ,CAAC,GAAG,IAAA,kBAAU,EAAC,SAAS,CAAC,CAAC;YAEpE,IAAI,kBAAkB,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;gBAC3D,MAAM,YAAY,QAAQ,mBAAmB,CAAC;aAC/C;YAED,MAAM,MAAM,GAAG,IAAA,+BAAuB,EAAC,QAAQ,CAAC,CAAC;YACjD,IAAI,CAAC,aAAa,EAAE;gBAClB,MAAM,2BAA2B,CAAC;aACnC;YACD,IAAI,CAAC,UAAU,EAAE;gBACf,MAAM,wBAAwB,CAAC;aAChC;YACD,IAAI,KAAK,CAAC,MAAM,CAAC,EAAE;gBACjB,MAAM,qBAAqB,CAAC;aAC7B;YACD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC;gBAC7B,EAAE;gBACF,SAAS;gBACT,aAAa;gBACb,UAAU;gBACV,QAAQ;gBACR,MAAM;gBACN,IAAI;aACL,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACd,CAAC;QACD,cAAc,EAAE,GAAG,CAAC,cAAc;KACnC,CAAC,CAAC;AACL,CAAC,CAAC;AAtDW,QAAA,kCAAkC,sCAsD7C","sourcesContent":["import { IOHLC, provideOHLCDurationService } from '@yuants/data-ohlc';\nimport { IServiceOptions, Terminal } from '@yuants/protocol';\nimport { provideSeriesFromTimeBackwardService } from './provideSeriesFromTimeBackwardService';\nimport { convertDurationToOffset, decodePath } from '@yuants/utils';\n\n/**\n * Provide OHLC from time backward service\n *\n * 提供 K线数据 按时间向后查询服务\n *\n * @public\n */\nexport const provideOHLCFromTimeBackwardService = (ctx: {\n terminal: Terminal;\n datasource_id: string;\n supported_durations: string[];\n queryFn: (ctx: {\n series_id: string;\n datasource_id: string;\n product_id: string;\n duration: string;\n offset: number;\n time: string;\n }) => Promise<IOHLC[]>;\n serviceOptions: IServiceOptions;\n}) => {\n const supportedDurations = new Set(ctx.supported_durations);\n\n provideOHLCDurationService(ctx.terminal, ctx.datasource_id, () => ctx.supported_durations);\n\n provideSeriesFromTimeBackwardService<IOHLC>({\n terminal: ctx.terminal,\n type: 'ohlc',\n series_id_prefix_parts: [ctx.datasource_id],\n queryFn: async ({ series_id, time }) => {\n // series_id 格式: OKX/{product_id}/{duration}\n // 其中 product_id 可能包含转义的 /,如 SPOT\\/BTC-USDT\n const [datasource_id, product_id, duration] = decodePath(series_id);\n\n if (supportedDurations && !supportedDurations.has(duration)) {\n throw `duration ${duration} is not supported`;\n }\n\n const offset = convertDurationToOffset(duration);\n if (!datasource_id) {\n throw 'datasource_id is required';\n }\n if (!product_id) {\n throw 'product_id is required';\n }\n if (isNaN(offset)) {\n throw 'duration is invalid';\n }\n const data = await ctx.queryFn({\n //\n series_id,\n datasource_id,\n product_id,\n duration,\n offset,\n time,\n });\n return data;\n },\n serviceOptions: ctx.serviceOptions,\n });\n};\n"]}
@@ -0,0 +1,22 @@
1
+ import { IServiceOptions, Terminal } from '@yuants/protocol';
2
+ /**
3
+ * Provide series from time backward service
4
+ *
5
+ * 提供从时间点向前查询序列数据的服务
6
+ *
7
+ * @public
8
+ */
9
+ export declare const provideSeriesFromTimeBackwardService: <T extends {
10
+ series_id: string;
11
+ created_at: string;
12
+ }>(ctx: {
13
+ terminal: Terminal;
14
+ type: string;
15
+ series_id_prefix_parts: string[];
16
+ queryFn: (ctx: {
17
+ series_id: string;
18
+ time: string;
19
+ }) => Promise<T[]>;
20
+ serviceOptions?: IServiceOptions | undefined;
21
+ }) => void;
22
+ //# sourceMappingURL=provideSeriesFromTimeBackwardService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provideSeriesFromTimeBackwardService.d.ts","sourceRoot":"","sources":["../src/provideSeriesFromTimeBackwardService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAI7D;;;;;;GAMG;AACH,eAAO,MAAM,oCAAoC;eACxB,MAAM;gBAAc,MAAM;;cAEvC,QAAQ;UACZ,MAAM;4BACY,MAAM,EAAE;mBACjB;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;;UAuEnD,CAAC"}
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.provideSeriesFromTimeBackwardService = void 0;
4
+ const sql_1 = require("@yuants/sql");
5
+ const utils_1 = require("@yuants/utils");
6
+ /**
7
+ * Provide series from time backward service
8
+ *
9
+ * 提供从时间点向前查询序列数据的服务
10
+ *
11
+ * @public
12
+ */
13
+ const provideSeriesFromTimeBackwardService = (ctx) => {
14
+ ctx.terminal.server.provideService('QuerySeriesFromTimeBackward', {
15
+ type: 'object',
16
+ required: ['type', 'series_id', 'time'],
17
+ properties: {
18
+ type: { const: ctx.type },
19
+ series_id: { type: 'string', pattern: `^${(0, utils_1.escapeRegExp)((0, utils_1.encodePath)(ctx.series_id_prefix_parts))}/` },
20
+ time: { type: 'string', format: 'date-time' },
21
+ },
22
+ }, async (msg) => {
23
+ const { time, series_id } = msg.req;
24
+ const data = await ctx.queryFn({ series_id, time });
25
+ return {
26
+ res: {
27
+ code: 0,
28
+ message: 'OK',
29
+ data,
30
+ },
31
+ };
32
+ }, ctx.serviceOptions);
33
+ ctx.terminal.server.provideService('UpdateSeriesFromTimeBackward', {
34
+ type: 'object',
35
+ required: ['type', 'series_id', 'time'],
36
+ properties: {
37
+ type: { const: ctx.type },
38
+ series_id: { type: 'string' },
39
+ time: { type: 'string', format: 'date-time' },
40
+ },
41
+ }, async (msg) => {
42
+ const data = await ctx.terminal.client.requestForResponseData('QuerySeriesFromTimeBackward', msg.req);
43
+ await (0, sql_1.requestSQL)(ctx.terminal, (0, sql_1.buildInsertManyIntoTableSQL)(data, 'ohlc', {
44
+ conflictKeys: ['series_id', 'created_at'],
45
+ }));
46
+ return {
47
+ res: {
48
+ code: 0,
49
+ message: 'OK',
50
+ data: {
51
+ count: data.length,
52
+ },
53
+ },
54
+ };
55
+ });
56
+ };
57
+ exports.provideSeriesFromTimeBackwardService = provideSeriesFromTimeBackwardService;
58
+ //# sourceMappingURL=provideSeriesFromTimeBackwardService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provideSeriesFromTimeBackwardService.js","sourceRoot":"","sources":["../src/provideSeriesFromTimeBackwardService.ts"],"names":[],"mappings":";;;AACA,qCAAsE;AACtE,yCAAyD;AAEzD;;;;;;GAMG;AACI,MAAM,oCAAoC,GAAG,CAElD,GAMD,EAAE,EAAE;IAOH,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,cAAc,CAChC,6BAA6B,EAC7B;QACE,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC;QACvC,UAAU,EAAE;YACV,IAAI,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE;YACzB,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,IAAA,oBAAY,EAAC,IAAA,kBAAU,EAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC,GAAG,EAAE;YACnG,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE;SAC9C;KACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC;QAEpC,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEpD,OAAO;YACL,GAAG,EAAE;gBACH,IAAI,EAAE,CAAC;gBACP,OAAO,EAAE,IAAI;gBACb,IAAI;aACL;SACF,CAAC;IACJ,CAAC,EACD,GAAG,CAAC,cAAc,CACnB,CAAC;IAEF,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,cAAc,CAChC,8BAA8B,EAC9B;QACE,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC;QACvC,UAAU,EAAE;YACV,IAAI,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE;YACzB,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC7B,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE;SAC9C;KACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CAC3D,6BAA6B,EAC7B,GAAG,CAAC,GAAG,CACR,CAAC;QAEF,MAAM,IAAA,gBAAU,EACd,GAAG,CAAC,QAAQ,EACZ,IAAA,iCAA2B,EAAC,IAAI,EAAE,MAAM,EAAE;YACxC,YAAY,EAAE,CAAC,WAAW,EAAE,YAAY,CAAC;SAC1C,CAAC,CACH,CAAC;QAEF,OAAO;YACL,GAAG,EAAE;gBACH,IAAI,EAAE,CAAC;gBACP,OAAO,EAAE,IAAI;gBACb,IAAI,EAAE;oBACJ,KAAK,EAAE,IAAI,CAAC,MAAM;iBACnB;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC,CAAC;AA7EW,QAAA,oCAAoC,wCA6E/C","sourcesContent":["import { IServiceOptions, Terminal } from '@yuants/protocol';\nimport { buildInsertManyIntoTableSQL, requestSQL } from '@yuants/sql';\nimport { encodePath, escapeRegExp } from '@yuants/utils';\n\n/**\n * Provide series from time backward service\n *\n * 提供从时间点向前查询序列数据的服务\n *\n * @public\n */\nexport const provideSeriesFromTimeBackwardService = <\n T extends { series_id: string; created_at: string },\n>(ctx: {\n terminal: Terminal;\n type: string;\n series_id_prefix_parts: string[];\n queryFn: (ctx: { series_id: string; time: string }) => Promise<T[]>;\n serviceOptions?: IServiceOptions;\n}) => {\n interface IQuerySeriesFromTimeBackwardReq {\n time: string;\n type: string;\n series_id: string;\n }\n\n ctx.terminal.server.provideService<IQuerySeriesFromTimeBackwardReq, T[]>(\n 'QuerySeriesFromTimeBackward',\n {\n type: 'object',\n required: ['type', 'series_id', 'time'],\n properties: {\n type: { const: ctx.type },\n series_id: { type: 'string', pattern: `^${escapeRegExp(encodePath(ctx.series_id_prefix_parts))}/` },\n time: { type: 'string', format: 'date-time' },\n },\n },\n async (msg) => {\n const { time, series_id } = msg.req;\n\n const data = await ctx.queryFn({ series_id, time });\n\n return {\n res: {\n code: 0,\n message: 'OK',\n data,\n },\n };\n },\n ctx.serviceOptions,\n );\n\n ctx.terminal.server.provideService<IQuerySeriesFromTimeBackwardReq, {}>(\n 'UpdateSeriesFromTimeBackward',\n {\n type: 'object',\n required: ['type', 'series_id', 'time'],\n properties: {\n type: { const: ctx.type },\n series_id: { type: 'string' },\n time: { type: 'string', format: 'date-time' },\n },\n },\n async (msg) => {\n const data = await ctx.terminal.client.requestForResponseData<IQuerySeriesFromTimeBackwardReq, T[]>(\n 'QuerySeriesFromTimeBackward',\n msg.req,\n );\n\n await requestSQL(\n ctx.terminal,\n buildInsertManyIntoTableSQL(data, 'ohlc', {\n conflictKeys: ['series_id', 'created_at'],\n }),\n );\n\n return {\n res: {\n code: 0,\n message: 'OK',\n data: {\n count: data.length,\n },\n },\n };\n },\n );\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuants/vendor-okx",
3
- "version": "0.22.23",
3
+ "version": "0.23.1",
4
4
  "bin": "lib/cli.js",
5
5
  "main": "lib/index.js",
6
6
  "files": [
@@ -16,7 +16,7 @@
16
16
  "@yuants/utils": "0.8.0",
17
17
  "@yuants/sql": "0.9.9",
18
18
  "@yuants/data-series": "0.3.30",
19
- "@yuants/data-product": "0.3.1",
19
+ "@yuants/data-product": "0.3.2",
20
20
  "@yuants/data-ohlc": "0.4.1",
21
21
  "@yuants/data-interest-rate": "0.1.27",
22
22
  "@yuants/data-quote": "0.2.22",
@@ -1,13 +1,13 @@
1
1
  {
2
- "apps/vendor-okx/CHANGELOG.json": "522208974cc59f9cc9f3834e429fb5a0e2ea6520",
3
- "apps/vendor-okx/CHANGELOG.md": "ed006abb5b051cbf72b996ca0f75f556af8cfa97",
2
+ "apps/vendor-okx/CHANGELOG.json": "a4ff324e7ee11859bb1cdedbc7ac1d4a0caa75f3",
3
+ "apps/vendor-okx/CHANGELOG.md": "6abdc811aa6a172175f3fc2c27bc25328b638729",
4
4
  "apps/vendor-okx/README.md": "ac3d1f6c4c8d73066664699b0bb1b01db02e67a2",
5
5
  "apps/vendor-okx/api-extractor.json": "62f4fd324425b9a235f0c117975967aab09ced0c",
6
6
  "apps/vendor-okx/config/jest.config.json": "4bb17bde3ee911163a3edb36a6eb71491d80b1bd",
7
7
  "apps/vendor-okx/config/rig.json": "f6c7b5537dc77a3170ba9f008bae3b6c3ee11956",
8
8
  "apps/vendor-okx/config/typescript.json": "854907e8a821f2050f6533368db160c649c25348",
9
9
  "apps/vendor-okx/etc/vendor-okx.api.md": "92c54ccd547d2ad81ca6088158ca193e85c208df",
10
- "apps/vendor-okx/package.json": "e7b326152daa4b4e78024cd2c2bd4cc33751b508",
10
+ "apps/vendor-okx/package.json": "42f30956c1d4084e6d87148ec6b8b34aa3c23802",
11
11
  "apps/vendor-okx/src/account.ts": "ecfbe5017d6b5d4d1bc833de9f48fe72db76bdb7",
12
12
  "apps/vendor-okx/src/api.ts": "a818895fddbfe76eab517cd0bbba9fafe6c0c2cc",
13
13
  "apps/vendor-okx/src/cli.ts": "9bf6b5559a6c6f33da20e74cc6c5d702c60ec891",
@@ -17,9 +17,11 @@
17
17
  "apps/vendor-okx/src/legacy_index.ts": "e46abcfaa52f957ce5e8c42ca26cd0fc2c576965",
18
18
  "apps/vendor-okx/src/loan-account.ts": "fa37d6e51a992443ddba130e5136de7a58c34286",
19
19
  "apps/vendor-okx/src/logger.ts": "d25d427e74f46819a601e0cb17d5358b22c8db7b",
20
- "apps/vendor-okx/src/ohlc.ts": "a861027f85cb0aed65af5d0b6b343613b4683660",
20
+ "apps/vendor-okx/src/ohlc.ts": "601739e2a2a323b2fc15b9e2f6eb4545e046fe62",
21
21
  "apps/vendor-okx/src/order.ts": "945865088271a194eb1c684af0f10e6b54d89f6b",
22
22
  "apps/vendor-okx/src/product.ts": "d5aea86778190d0a73f0a61c3b2cf178f3b57df9",
23
+ "apps/vendor-okx/src/provideOHLCFromTimeBackwardService.ts": "3a44206410b5b73683f2395d6c551549b553d7bd",
24
+ "apps/vendor-okx/src/provideSeriesFromTimeBackwardService.ts": "d943cdfb72faaeada9c1cbb4e479b92a94052742",
23
25
  "apps/vendor-okx/src/quote.ts": "e289161a274db61505efcdecfafb817e7376742f",
24
26
  "apps/vendor-okx/src/services.ts": "7b7df830a6d78b6de5cee44bbcec66f282ab53ab",
25
27
  "apps/vendor-okx/src/strategy-account.ts": "3d55c425df2688eeb3ecdd3a3ff2e428b10fa2a1",
@@ -35,7 +37,7 @@
35
37
  "libraries/utils/temp/package-deps.json": "56def945d0e67a9d0ca13447d2333155be0138f2",
36
38
  "libraries/sql/temp/package-deps.json": "adefb3abae42a2aadc8202df61264d043f9da5a8",
37
39
  "libraries/data-series/temp/package-deps.json": "df9b452ea781a20b4b612a575cf968b69a3e5c10",
38
- "libraries/data-product/temp/package-deps.json": "f6326305dcaa951322612b9817d0875544e25f5c",
40
+ "libraries/data-product/temp/package-deps.json": "fad5653ecbc27dec15bca2e317b452650985984f",
39
41
  "libraries/data-ohlc/temp/package-deps.json": "7fae1d2dbf0986572876372167d1124d581a6e72",
40
42
  "libraries/data-interest-rate/temp/package-deps.json": "04e45ea7313e52a90b746f37b6eda2e3a093d79f",
41
43
  "libraries/data-quote/temp/package-deps.json": "cbd932831cad0f4240b147f07f2dd8a046da1bf3",