@yuants/vendor-okx 0.29.3 → 0.29.5

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.
@@ -2,8 +2,8 @@ import { Terminal } from '@yuants/protocol';
2
2
  import { writeToSQL } from '@yuants/sql';
3
3
  import { decodePath, encodePath, formatTime, listWatch } from '@yuants/utils';
4
4
  import { catchError, concatMap, defer, distinctUntilChanged, EMPTY, filter, first, firstValueFrom, from, groupBy, map, merge, mergeMap, reduce, repeat, retry, scan, share, shareReplay, switchMap, tap, toArray, } from 'rxjs';
5
- import { getInstruments, getMarketTickers, getOpenInterest } from '../api/public-api';
6
- import { useFundingRate, useOpenInterest, useTicker } from '../ws';
5
+ import { getFundingRate, getInstruments, getMarketTickers, getOpenInterest, } from '../api/public-api';
6
+ import { useOpenInterest, useTicker } from '../ws';
7
7
  const terminal = Terminal.fromNodeEnv();
8
8
  const swapInstruments$ = defer(() => getInstruments({ instType: 'SWAP' })).pipe(repeat({ delay: 3600000 }), retry({ delay: 10000 }), map((x) => x.data), shareReplay(1));
9
9
  const spotInstruments$ = defer(() => getInstruments({ instType: 'SPOT' })).pipe(repeat({ delay: 3600000 }), retry({ delay: 10000 }), map((x) => x.data), shareReplay(1));
@@ -79,13 +79,6 @@ const openInterestOfSwapFromWS$ = swapInstruments$.pipe(listWatch((x) => x.instI
79
79
  product_id: encodePath('OKX', 'SWAP', x[0].instId),
80
80
  open_interest: x[0].oi,
81
81
  })), share());
82
- const interestRateOfSwapFromWS$ = swapInstruments$.pipe(listWatch((x) => x.instId, (x) => useFundingRate(x.instId), () => true), map((x) => ({
83
- datasource_id: 'OKX',
84
- product_id: encodePath('OKX', 'SWAP', x[0].instId),
85
- interest_rate_long: `${-+x[0].fundingRate}`,
86
- interest_rate_short: x[0].fundingRate,
87
- interest_rate_next_settled_at: x[0].fundingTime,
88
- })), share());
89
82
  const marginPositionTiersMap$ = defer(() => spotInstIds$.pipe(first(), map((instIds) => instIds.filter((id) => id.endsWith('USDT') || id.endsWith('USDC'))), switchMap((instIds) => {
90
83
  const total = instIds.length;
91
84
  let processed = 0;
@@ -150,7 +143,15 @@ const marginOpenInterest$ = spotInstIds$.pipe(mergeMap((instIds) => from(instIds
150
143
  }
151
144
  return partial;
152
145
  }), share());
153
- marginOpenInterest$.subscribe();
146
+ const fundingRate$ = defer(() => getFundingRate({ instId: 'ANY' })).pipe(map((data) => data.data), repeat({ delay: 50000 }), retry({ delay: 5000 }), shareReplay({ bufferSize: 1, refCount: true }));
147
+ // Convert funding rate data to quote format
148
+ const interestRateOfSwap$ = fundingRate$.pipe(mergeMap((premiumDataArray) => premiumDataArray), map((premiumData) => ({
149
+ datasource_id: 'OKX',
150
+ product_id: encodePath('OKX', 'SWAP', premiumData.instId),
151
+ interest_rate_long: premiumData.fundingRate ? `${-+premiumData.fundingRate}` : undefined,
152
+ interest_rate_short: premiumData.fundingRate,
153
+ interest_rate_next_settled_at: formatTime(+premiumData.fundingTime),
154
+ })));
154
155
  const quoteSources$ = [
155
156
  quoteOfSwapFromWs$,
156
157
  openInterestOfSwapFromWS$,
@@ -158,7 +159,7 @@ const quoteSources$ = [
158
159
  quoteOfSpotAndMarginFromWs$,
159
160
  quoteOfSpotAndMarginFromRest$,
160
161
  marginOpenInterest$,
161
- interestRateOfSwapFromWS$,
162
+ interestRateOfSwap$,
162
163
  ];
163
164
  const quote$ = defer(() => merge(...quoteSources$.map((x$) => defer(() => x$).pipe(
164
165
  // 防止单个流关闭导致整体关闭
@@ -189,4 +190,9 @@ if (process.env.WRITE_QUOTE_TO_SQL === 'true') {
189
190
  .subscribe();
190
191
  }
191
192
  export const swapOpenInterest$ = defer(() => swapOpenInterests$).pipe(map((x) => new Map(x.data.map((x) => [x.instId, +x.oi]))), shareReplay(1));
193
+ quote$
194
+ .pipe(tap((quote) => {
195
+ console.log(quote);
196
+ }))
197
+ .subscribe();
192
198
  //# sourceMappingURL=new-quote.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"new-quote.js","sourceRoot":"","sources":["../../src/public-data/new-quote.ts"],"names":[],"mappings":"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","sourcesContent":["import { IQuote } from '@yuants/data-quote';\nimport { Terminal } from '@yuants/protocol';\nimport { writeToSQL } from '@yuants/sql';\nimport { decodePath, encodePath, formatTime, listWatch } from '@yuants/utils';\nimport {\n catchError,\n concatMap,\n defer,\n distinctUntilChanged,\n EMPTY,\n filter,\n first,\n firstValueFrom,\n from,\n groupBy,\n map,\n merge,\n mergeMap,\n reduce,\n repeat,\n retry,\n scan,\n share,\n shareReplay,\n switchMap,\n tap,\n toArray,\n} from 'rxjs';\nimport { getInstruments, getMarketTickers, getOpenInterest, getPositionTiers } from '../api/public-api';\nimport { useFundingRate, useOpenInterest, useTicker } from '../ws';\n\nconst terminal = Terminal.fromNodeEnv();\n\nconst swapInstruments$ = defer(() => getInstruments({ instType: 'SWAP' })).pipe(\n repeat({ delay: 3600_000 }),\n retry({ delay: 10_000 }),\n map((x) => x.data),\n shareReplay(1),\n);\nconst spotInstruments$ = defer(() => getInstruments({ instType: 'SPOT' })).pipe(\n repeat({ delay: 3600_000 }),\n retry({ delay: 10_000 }),\n map((x) => x.data),\n shareReplay(1),\n);\n\nconst shallowEqual = (a: string[], b: string[]) => a.length === b.length && a.every((v, i) => v === b[i]);\n\nconst spotInstIds$ = spotInstruments$.pipe(\n map((items) => items.map((item) => item.instId)),\n distinctUntilChanged(shallowEqual),\n shareReplay(1),\n);\n\nconst spotTickers$ = defer(() => getMarketTickers({ instType: 'SPOT' })).pipe(\n repeat({ delay: 5000 }),\n retry({ delay: 5000 }),\n shareReplay(1),\n);\n\n// depend by SubmitOrders\nexport const spotMarketTickers$ = defer(() => spotTickers$).pipe(\n mergeMap((x) =>\n from(x.data).pipe(\n map((x) => [x.instId, x] as const),\n toArray(),\n map((x) => Object.fromEntries(x)),\n ),\n ),\n repeat({ delay: 5000 }),\n retry({ delay: 5000 }),\n shareReplay(1),\n);\n\nconst spotTicker$ = spotInstruments$.pipe(\n tap((x) => {\n console.info('SPOT INSTRUMENTS', x.length);\n }),\n listWatch(\n (x) => x.instId,\n (x) => useTicker(x.instId),\n () => true,\n ),\n share(),\n);\n\nconst quoteOfSwapFromRest$ = defer(() => getMarketTickers({ instType: 'SWAP' })).pipe(\n mergeMap((x) => x.data || []),\n map(\n (x): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('OKX', x.instType, x.instId),\n last_price: x.last,\n ask_price: x.askPx,\n bid_price: x.bidPx,\n ask_volume: x.askSz,\n bid_volume: x.bidSz,\n }),\n ),\n repeat({ delay: 1000 }),\n retry({ delay: 1000 }),\n);\n\nconst quoteOfSpotAndMarginFromRest$ = defer(() => getMarketTickers({ instType: 'SPOT' })).pipe(\n mergeMap((x) => x.data || []),\n mergeMap((x): Partial<IQuote>[] => [\n {\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'SPOT', x.instId),\n last_price: x.last,\n ask_price: x.askPx,\n bid_price: x.bidPx,\n ask_volume: x.askSz,\n bid_volume: x.bidSz,\n },\n {\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'MARGIN', x.instId),\n last_price: x.last,\n ask_price: x.askPx,\n bid_price: x.bidPx,\n ask_volume: x.askSz,\n bid_volume: x.bidSz,\n },\n ]),\n repeat({ delay: 1000 }),\n retry({ delay: 1000 }),\n);\n\nconst quoteOfSwapFromWs$ = swapInstruments$.pipe(\n listWatch(\n (x) => x.instId,\n (x) => useTicker(x.instId),\n () => true,\n ),\n map(\n (ticker): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'SWAP', ticker[0].instId),\n last_price: ticker[0].last,\n ask_price: ticker[0].askPx,\n bid_price: ticker[0].bidPx,\n ask_volume: ticker[0].askSz,\n bid_volume: ticker[0].bidSz,\n }),\n ),\n);\n\nconst quoteOfSpotAndMarginFromWs$ = spotTicker$.pipe(\n mergeMap((ticker): Partial<IQuote>[] => [\n {\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'SPOT', ticker[0].instId),\n last_price: ticker[0].last,\n ask_price: ticker[0].askPx,\n bid_price: ticker[0].bidPx,\n ask_volume: ticker[0].askSz,\n bid_volume: ticker[0].bidSz,\n },\n {\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'MARGIN', ticker[0].instId),\n last_price: ticker[0].last,\n ask_price: ticker[0].askPx,\n bid_price: ticker[0].bidPx,\n ask_volume: ticker[0].askSz,\n bid_volume: ticker[0].bidSz,\n },\n ]),\n);\n\nconst swapOpenInterests$ = defer(() => getOpenInterest({ instType: 'SWAP' })).pipe(\n repeat({ delay: 10_000 }),\n retry({ delay: 10_000 }),\n shareReplay(1),\n);\n\nconst openInterestOfSwapFromWS$ = swapInstruments$.pipe(\n listWatch(\n (x) => x.instId,\n (x) => useOpenInterest(x.instId),\n () => true,\n ),\n map(\n (x): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'SWAP', x[0].instId),\n open_interest: x[0].oi,\n }),\n ),\n share(),\n);\n\nconst interestRateOfSwapFromWS$ = swapInstruments$.pipe(\n listWatch(\n (x) => x.instId,\n (x) => useFundingRate(x.instId),\n () => true,\n ),\n map(\n (x): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'SWAP', x[0].instId),\n interest_rate_long: `${-+x[0].fundingRate}`,\n interest_rate_short: x[0].fundingRate,\n interest_rate_next_settled_at: x[0].fundingTime,\n }),\n ),\n share(),\n);\n\ntype PositionTiersResponse = Awaited<ReturnType<typeof getPositionTiers>>;\ntype PositionTiersEntry = PositionTiersResponse['data'];\n\nconst marginPositionTiersMap$ = defer(() =>\n spotInstIds$.pipe(\n first(),\n map((instIds) => instIds.filter((id) => id.endsWith('USDT') || id.endsWith('USDC'))),\n switchMap((instIds) => {\n const total = instIds.length;\n let processed = 0;\n return from(instIds).pipe(\n concatMap((instId) =>\n defer(async () => {\n const tiers = await terminal.client.requestForResponseData<\n { instType: string; tdMode: string; instId: string },\n PositionTiersResponse\n >('OKX/PositionTiers', {\n instType: 'MARGIN',\n tdMode: 'cross',\n instId,\n });\n if (!tiers?.data) {\n throw new Error(`Failed to load position tiers for ${instId}: ${tiers.msg}`);\n }\n return {\n instId,\n tiers,\n };\n }).pipe(retry({ delay: 2000 })),\n ),\n reduce((map, { instId, tiers }) => {\n processed += 1;\n console.info(\n formatTime(Date.now()),\n `Loaded margin position tiers ${processed}/${total} (${instId})`,\n );\n if (tiers?.data) {\n map.set(instId, tiers.data);\n }\n return map;\n }, new Map<string, PositionTiersEntry>()),\n );\n }),\n ),\n).pipe(\n //\n retry({ delay: 60_000 }),\n repeat({ delay: 86400_000 }),\n shareReplay(1),\n);\n\n// Margin 的 open interest 只依赖 position-tier:\n// 1) 启动时先拉全量 MARGIN 仓位档位并缓存,下次直接命中;\n// 2) 档位内只保留同 tier 杠杆最高的记录;\n// 3) 当前策略只使用 tier=1 的 quoteMaxLoan 作为持仓上限,不再混合 /account/max-size;\n// 4) 每个 instId 60 秒刷新一次,并在接口报错时 10 秒重试。\nconst marginOpenInterest$ = spotInstIds$.pipe(\n mergeMap((instIds) =>\n from(instIds).pipe(\n mergeMap((instId) =>\n defer(async () => {\n const tiersMap = await firstValueFrom(marginPositionTiersMap$);\n const tiers = tiersMap.get(instId);\n if (!tiers?.length) {\n return null;\n }\n\n const tierByLevel = tiers\n .filter((tier) => !tier.instId || tier.instId === instId)\n .reduce((mapTierToTierInfo, tierInfo) => {\n const existing = mapTierToTierInfo.get(tierInfo.tier);\n if (!existing || +tierInfo.maxLever > +existing.maxLever) {\n mapTierToTierInfo.set(tierInfo.tier, tierInfo);\n }\n return mapTierToTierInfo;\n }, new Map<string, (typeof tiers)[number]>());\n // 获取一级杠杆的最大可借贷额度作为持仓量\n const openInterest = +(tierByLevel.get('1')?.quoteMaxLoan || 0);\n\n return {\n instId,\n openInterest,\n };\n }).pipe(retry({ delay: 10_000 }), repeat({ delay: 60_000 })),\n ),\n ),\n ),\n filter((result): result is { instId: string; openInterest: number } => result !== null),\n map(({ instId, openInterest }) => {\n const partial: Partial<IQuote> = {\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'MARGIN', instId),\n };\n if (typeof openInterest === 'number' && Number.isFinite(openInterest)) {\n partial.open_interest = `${openInterest}`;\n }\n return partial;\n }),\n share(),\n);\n\nmarginOpenInterest$.subscribe();\n\nconst quoteSources$ = [\n quoteOfSwapFromWs$,\n openInterestOfSwapFromWS$,\n quoteOfSwapFromRest$,\n quoteOfSpotAndMarginFromWs$,\n quoteOfSpotAndMarginFromRest$,\n marginOpenInterest$,\n interestRateOfSwapFromWS$,\n];\n\nconst quote$ = defer(() =>\n merge(\n ...quoteSources$.map((x$) =>\n defer(() => x$).pipe(\n // 防止单个流关闭导致整体关闭\n catchError(() => EMPTY),\n ),\n ),\n ),\n).pipe(\n groupBy((x) => encodePath(x.datasource_id, x.product_id)),\n mergeMap((group$) => {\n return group$.pipe(\n //\n scan((acc, cur) => Object.assign(acc, cur), {} as Partial<IQuote>),\n );\n }),\n share(),\n);\n\n// 合并不同来源的数据并进行合并,避免死锁\nif (process.env.WRITE_QUOTE_TO_SQL === 'true') {\n terminal.channel.publishChannel('quote', { pattern: `^OKX/` }, (channel_id) => {\n const [datasource_id, product_id] = decodePath(channel_id);\n if (!datasource_id) {\n throw 'datasource_id is required';\n }\n if (!product_id) {\n throw 'product_id is required';\n }\n return quote$.pipe(filter((x) => x.product_id === product_id));\n });\n\n quote$\n .pipe(\n writeToSQL({\n terminal,\n writeInterval: 1000,\n tableName: 'quote',\n conflictKeys: ['datasource_id', 'product_id'],\n }),\n )\n .subscribe();\n}\n\nexport const swapOpenInterest$ = defer(() => swapOpenInterests$).pipe(\n map((x) => new Map(x.data.map((x) => [x.instId, +x.oi] as const))),\n shareReplay(1),\n);\n"]}
1
+ {"version":3,"file":"new-quote.js","sourceRoot":"","sources":["../../src/public-data/new-quote.ts"],"names":[],"mappings":"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","sourcesContent":["import { IQuote } from '@yuants/data-quote';\nimport { Terminal } from '@yuants/protocol';\nimport { writeToSQL } from '@yuants/sql';\nimport { decodePath, encodePath, formatTime, listWatch } from '@yuants/utils';\nimport {\n catchError,\n concatMap,\n defer,\n distinctUntilChanged,\n EMPTY,\n filter,\n first,\n firstValueFrom,\n from,\n groupBy,\n map,\n merge,\n mergeMap,\n reduce,\n repeat,\n retry,\n scan,\n share,\n shareReplay,\n switchMap,\n tap,\n toArray,\n} from 'rxjs';\nimport {\n getFundingRate,\n getInstruments,\n getMarketTickers,\n getOpenInterest,\n getPositionTiers,\n} from '../api/public-api';\nimport { useOpenInterest, useTicker } from '../ws';\n\nconst terminal = Terminal.fromNodeEnv();\n\nconst swapInstruments$ = defer(() => getInstruments({ instType: 'SWAP' })).pipe(\n repeat({ delay: 3600_000 }),\n retry({ delay: 10_000 }),\n map((x) => x.data),\n shareReplay(1),\n);\nconst spotInstruments$ = defer(() => getInstruments({ instType: 'SPOT' })).pipe(\n repeat({ delay: 3600_000 }),\n retry({ delay: 10_000 }),\n map((x) => x.data),\n shareReplay(1),\n);\n\nconst shallowEqual = (a: string[], b: string[]) => a.length === b.length && a.every((v, i) => v === b[i]);\n\nconst spotInstIds$ = spotInstruments$.pipe(\n map((items) => items.map((item) => item.instId)),\n distinctUntilChanged(shallowEqual),\n shareReplay(1),\n);\n\nconst spotTickers$ = defer(() => getMarketTickers({ instType: 'SPOT' })).pipe(\n repeat({ delay: 5000 }),\n retry({ delay: 5000 }),\n shareReplay(1),\n);\n\n// depend by SubmitOrders\nexport const spotMarketTickers$ = defer(() => spotTickers$).pipe(\n mergeMap((x) =>\n from(x.data).pipe(\n map((x) => [x.instId, x] as const),\n toArray(),\n map((x) => Object.fromEntries(x)),\n ),\n ),\n repeat({ delay: 5000 }),\n retry({ delay: 5000 }),\n shareReplay(1),\n);\n\nconst spotTicker$ = spotInstruments$.pipe(\n tap((x) => {\n console.info('SPOT INSTRUMENTS', x.length);\n }),\n listWatch(\n (x) => x.instId,\n (x) => useTicker(x.instId),\n () => true,\n ),\n share(),\n);\n\nconst quoteOfSwapFromRest$ = defer(() => getMarketTickers({ instType: 'SWAP' })).pipe(\n mergeMap((x) => x.data || []),\n map(\n (x): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('OKX', x.instType, x.instId),\n last_price: x.last,\n ask_price: x.askPx,\n bid_price: x.bidPx,\n ask_volume: x.askSz,\n bid_volume: x.bidSz,\n }),\n ),\n repeat({ delay: 1000 }),\n retry({ delay: 1000 }),\n);\n\nconst quoteOfSpotAndMarginFromRest$ = defer(() => getMarketTickers({ instType: 'SPOT' })).pipe(\n mergeMap((x) => x.data || []),\n mergeMap((x): Partial<IQuote>[] => [\n {\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'SPOT', x.instId),\n last_price: x.last,\n ask_price: x.askPx,\n bid_price: x.bidPx,\n ask_volume: x.askSz,\n bid_volume: x.bidSz,\n },\n {\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'MARGIN', x.instId),\n last_price: x.last,\n ask_price: x.askPx,\n bid_price: x.bidPx,\n ask_volume: x.askSz,\n bid_volume: x.bidSz,\n },\n ]),\n repeat({ delay: 1000 }),\n retry({ delay: 1000 }),\n);\n\nconst quoteOfSwapFromWs$ = swapInstruments$.pipe(\n listWatch(\n (x) => x.instId,\n (x) => useTicker(x.instId),\n () => true,\n ),\n map(\n (ticker): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'SWAP', ticker[0].instId),\n last_price: ticker[0].last,\n ask_price: ticker[0].askPx,\n bid_price: ticker[0].bidPx,\n ask_volume: ticker[0].askSz,\n bid_volume: ticker[0].bidSz,\n }),\n ),\n);\n\nconst quoteOfSpotAndMarginFromWs$ = spotTicker$.pipe(\n mergeMap((ticker): Partial<IQuote>[] => [\n {\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'SPOT', ticker[0].instId),\n last_price: ticker[0].last,\n ask_price: ticker[0].askPx,\n bid_price: ticker[0].bidPx,\n ask_volume: ticker[0].askSz,\n bid_volume: ticker[0].bidSz,\n },\n {\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'MARGIN', ticker[0].instId),\n last_price: ticker[0].last,\n ask_price: ticker[0].askPx,\n bid_price: ticker[0].bidPx,\n ask_volume: ticker[0].askSz,\n bid_volume: ticker[0].bidSz,\n },\n ]),\n);\n\nconst swapOpenInterests$ = defer(() => getOpenInterest({ instType: 'SWAP' })).pipe(\n repeat({ delay: 10_000 }),\n retry({ delay: 10_000 }),\n shareReplay(1),\n);\n\nconst openInterestOfSwapFromWS$ = swapInstruments$.pipe(\n listWatch(\n (x) => x.instId,\n (x) => useOpenInterest(x.instId),\n () => true,\n ),\n map(\n (x): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'SWAP', x[0].instId),\n open_interest: x[0].oi,\n }),\n ),\n share(),\n);\n\n// const interestRateOfSwapFromWS$ = swapInstruments$.pipe(\n// listWatch(\n// (x) => x.instId,\n// (x) => useFundingRate(x.instId),\n// () => true,\n// ),\n// map(\n// (x): Partial<IQuote> => ({\n// datasource_id: 'OKX',\n// product_id: encodePath('OKX', 'SWAP', x[0].instId),\n// interest_rate_long: `-${x[0].fundingRate}`,\n// interest_rate_short: x[0].fundingRate,\n// interest_rate_next_settled_at: x[0].fundingTime,\n// }),\n// ),\n// share(),\n// );\n\ntype PositionTiersResponse = Awaited<ReturnType<typeof getPositionTiers>>;\ntype PositionTiersEntry = PositionTiersResponse['data'];\n\nconst marginPositionTiersMap$ = defer(() =>\n spotInstIds$.pipe(\n first(),\n map((instIds) => instIds.filter((id) => id.endsWith('USDT') || id.endsWith('USDC'))),\n switchMap((instIds) => {\n const total = instIds.length;\n let processed = 0;\n return from(instIds).pipe(\n concatMap((instId) =>\n defer(async () => {\n const tiers = await terminal.client.requestForResponseData<\n { instType: string; tdMode: string; instId: string },\n PositionTiersResponse\n >('OKX/PositionTiers', {\n instType: 'MARGIN',\n tdMode: 'cross',\n instId,\n });\n if (!tiers?.data) {\n throw new Error(`Failed to load position tiers for ${instId}: ${tiers.msg}`);\n }\n return {\n instId,\n tiers,\n };\n }).pipe(retry({ delay: 2000 })),\n ),\n reduce((map, { instId, tiers }) => {\n processed += 1;\n console.info(\n formatTime(Date.now()),\n `Loaded margin position tiers ${processed}/${total} (${instId})`,\n );\n if (tiers?.data) {\n map.set(instId, tiers.data);\n }\n return map;\n }, new Map<string, PositionTiersEntry>()),\n );\n }),\n ),\n).pipe(\n //\n retry({ delay: 60_000 }),\n repeat({ delay: 86400_000 }),\n shareReplay(1),\n);\n\n// Margin 的 open interest 只依赖 position-tier:\n// 1) 启动时先拉全量 MARGIN 仓位档位并缓存,下次直接命中;\n// 2) 档位内只保留同 tier 杠杆最高的记录;\n// 3) 当前策略只使用 tier=1 的 quoteMaxLoan 作为持仓上限,不再混合 /account/max-size;\n// 4) 每个 instId 60 秒刷新一次,并在接口报错时 10 秒重试。\nconst marginOpenInterest$ = spotInstIds$.pipe(\n mergeMap((instIds) =>\n from(instIds).pipe(\n mergeMap((instId) =>\n defer(async () => {\n const tiersMap = await firstValueFrom(marginPositionTiersMap$);\n const tiers = tiersMap.get(instId);\n if (!tiers?.length) {\n return null;\n }\n\n const tierByLevel = tiers\n .filter((tier) => !tier.instId || tier.instId === instId)\n .reduce((mapTierToTierInfo, tierInfo) => {\n const existing = mapTierToTierInfo.get(tierInfo.tier);\n if (!existing || +tierInfo.maxLever > +existing.maxLever) {\n mapTierToTierInfo.set(tierInfo.tier, tierInfo);\n }\n return mapTierToTierInfo;\n }, new Map<string, (typeof tiers)[number]>());\n // 获取一级杠杆的最大可借贷额度作为持仓量\n const openInterest = +(tierByLevel.get('1')?.quoteMaxLoan || 0);\n\n return {\n instId,\n openInterest,\n };\n }).pipe(retry({ delay: 10_000 }), repeat({ delay: 60_000 })),\n ),\n ),\n ),\n filter((result): result is { instId: string; openInterest: number } => result !== null),\n map(({ instId, openInterest }) => {\n const partial: Partial<IQuote> = {\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'MARGIN', instId),\n };\n if (typeof openInterest === 'number' && Number.isFinite(openInterest)) {\n partial.open_interest = `${openInterest}`;\n }\n return partial;\n }),\n share(),\n);\n\nconst fundingRate$ = defer(() => getFundingRate({ instId: 'ANY' })).pipe(\n map((data) => data.data),\n repeat({ delay: 50_000 }),\n retry({ delay: 5000 }),\n shareReplay({ bufferSize: 1, refCount: true }),\n);\n\n// Convert funding rate data to quote format\nconst interestRateOfSwap$ = fundingRate$.pipe(\n mergeMap((premiumDataArray) => premiumDataArray),\n map(\n (premiumData): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'SWAP', premiumData.instId),\n interest_rate_long: premiumData.fundingRate ? `${-+premiumData.fundingRate}` : undefined,\n interest_rate_short: premiumData.fundingRate,\n interest_rate_next_settled_at: formatTime(+premiumData.fundingTime),\n }),\n ),\n);\n\nconst quoteSources$ = [\n quoteOfSwapFromWs$,\n openInterestOfSwapFromWS$,\n quoteOfSwapFromRest$,\n quoteOfSpotAndMarginFromWs$,\n quoteOfSpotAndMarginFromRest$,\n marginOpenInterest$,\n interestRateOfSwap$,\n];\n\nconst quote$ = defer(() =>\n merge(\n ...quoteSources$.map((x$) =>\n defer(() => x$).pipe(\n // 防止单个流关闭导致整体关闭\n catchError(() => EMPTY),\n ),\n ),\n ),\n).pipe(\n groupBy((x) => encodePath(x.datasource_id, x.product_id)),\n mergeMap((group$) => {\n return group$.pipe(\n //\n scan((acc, cur) => Object.assign(acc, cur), {} as Partial<IQuote>),\n );\n }),\n share(),\n);\n\n// 合并不同来源的数据并进行合并,避免死锁\nif (process.env.WRITE_QUOTE_TO_SQL === 'true') {\n terminal.channel.publishChannel('quote', { pattern: `^OKX/` }, (channel_id) => {\n const [datasource_id, product_id] = decodePath(channel_id);\n if (!datasource_id) {\n throw 'datasource_id is required';\n }\n if (!product_id) {\n throw 'product_id is required';\n }\n return quote$.pipe(filter((x) => x.product_id === product_id));\n });\n\n quote$\n .pipe(\n writeToSQL({\n terminal,\n writeInterval: 1000,\n tableName: 'quote',\n conflictKeys: ['datasource_id', 'product_id'],\n }),\n )\n .subscribe();\n}\n\nexport const swapOpenInterest$ = defer(() => swapOpenInterests$).pipe(\n map((x) => new Map(x.data.map((x) => [x.instId, +x.oi] as const))),\n shareReplay(1),\n);\n\nquote$\n .pipe(\n tap((quote) => {\n console.log(quote);\n }),\n )\n .subscribe();\n"]}
@@ -3,7 +3,7 @@ import { writeToSQL } from '@yuants/sql';
3
3
  import { decodePath, encodePath, formatTime, listWatch } from '@yuants/utils';
4
4
  import { catchError, concatMap, defer, distinctUntilChanged, EMPTY, filter, first, firstValueFrom, from, groupBy, map, merge, mergeMap, reduce, repeat, retry, scan, share, shareReplay, switchMap, tap, toArray, } from 'rxjs';
5
5
  import { getInstruments, getMarketTickers, getOpenInterest } from '../api/public-api';
6
- import { useFundingRate, useOpenInterest, useTicker } from '../ws';
6
+ import { useOpenInterest, useTicker } from '../ws';
7
7
  const terminal = Terminal.fromNodeEnv();
8
8
  const swapInstruments$ = defer(() => getInstruments({ instType: 'SWAP' })).pipe(repeat({ delay: 3600000 }), retry({ delay: 10000 }), map((x) => x.data), shareReplay(1));
9
9
  const spotInstruments$ = defer(() => getInstruments({ instType: 'SPOT' })).pipe(repeat({ delay: 3600000 }), retry({ delay: 10000 }), map((x) => x.data), shareReplay(1));
@@ -79,13 +79,6 @@ const openInterestOfSwapFromWS$ = swapInstruments$.pipe(listWatch((x) => x.instI
79
79
  product_id: encodePath('SWAP', x[0].instId),
80
80
  open_interest: x[0].oi,
81
81
  })), share());
82
- const interestRateOfSwapFromWS$ = swapInstruments$.pipe(listWatch((x) => x.instId, (x) => useFundingRate(x.instId), () => true), map((x) => ({
83
- datasource_id: 'OKX',
84
- product_id: encodePath('SWAP', x[0].instId),
85
- interest_rate_long: `-${x[0].fundingRate}`,
86
- interest_rate_short: x[0].fundingRate,
87
- interest_rate_next_settled_at: x[0].fundingTime,
88
- })), share());
89
82
  const marginPositionTiersMap$ = defer(() => spotInstIds$.pipe(first(), map((instIds) => instIds.filter((id) => id.endsWith('USDT') || id.endsWith('USDC'))), switchMap((instIds) => {
90
83
  const total = instIds.length;
91
84
  let processed = 0;
@@ -150,7 +143,6 @@ const marginOpenInterest$ = spotInstIds$.pipe(mergeMap((instIds) => from(instIds
150
143
  }
151
144
  return partial;
152
145
  }), share());
153
- marginOpenInterest$.subscribe();
154
146
  const quoteSources$ = [
155
147
  quoteOfSwapFromWs$,
156
148
  openInterestOfSwapFromWS$,
@@ -158,7 +150,6 @@ const quoteSources$ = [
158
150
  quoteOfSpotAndMarginFromWs$,
159
151
  quoteOfSpotAndMarginFromRest$,
160
152
  marginOpenInterest$,
161
- interestRateOfSwapFromWS$,
162
153
  ];
163
154
  const quote$ = defer(() => merge(...quoteSources$.map((x$) => defer(() => x$).pipe(
164
155
  // 防止单个流关闭导致整体关闭
@@ -1 +1 @@
1
- {"version":3,"file":"quote.js","sourceRoot":"","sources":["../../src/public-data/quote.ts"],"names":[],"mappings":"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","sourcesContent":["import { IQuote } from '@yuants/data-quote';\nimport { Terminal } from '@yuants/protocol';\nimport { writeToSQL } from '@yuants/sql';\nimport { decodePath, encodePath, formatTime, listWatch } from '@yuants/utils';\nimport {\n catchError,\n concatMap,\n defer,\n distinctUntilChanged,\n EMPTY,\n filter,\n first,\n firstValueFrom,\n from,\n groupBy,\n map,\n merge,\n mergeMap,\n reduce,\n repeat,\n retry,\n scan,\n share,\n shareReplay,\n switchMap,\n tap,\n toArray,\n} from 'rxjs';\nimport { getInstruments, getMarketTickers, getOpenInterest, getPositionTiers } from '../api/public-api';\nimport { useFundingRate, useOpenInterest, useTicker } from '../ws';\n\nconst terminal = Terminal.fromNodeEnv();\n\nconst swapInstruments$ = defer(() => getInstruments({ instType: 'SWAP' })).pipe(\n repeat({ delay: 3600_000 }),\n retry({ delay: 10_000 }),\n map((x) => x.data),\n shareReplay(1),\n);\nconst spotInstruments$ = defer(() => getInstruments({ instType: 'SPOT' })).pipe(\n repeat({ delay: 3600_000 }),\n retry({ delay: 10_000 }),\n map((x) => x.data),\n shareReplay(1),\n);\n\nconst shallowEqual = (a: string[], b: string[]) => a.length === b.length && a.every((v, i) => v === b[i]);\n\nconst spotInstIds$ = spotInstruments$.pipe(\n map((items) => items.map((item) => item.instId)),\n distinctUntilChanged(shallowEqual),\n shareReplay(1),\n);\n\nconst spotTickers$ = defer(() => getMarketTickers({ instType: 'SPOT' })).pipe(\n repeat({ delay: 5000 }),\n retry({ delay: 5000 }),\n shareReplay(1),\n);\n\n// depend by SubmitOrders\nexport const spotMarketTickers$ = defer(() => spotTickers$).pipe(\n mergeMap((x) =>\n from(x.data).pipe(\n map((x) => [x.instId, x] as const),\n toArray(),\n map((x) => Object.fromEntries(x)),\n ),\n ),\n repeat({ delay: 5000 }),\n retry({ delay: 5000 }),\n shareReplay(1),\n);\n\nconst spotTicker$ = spotInstruments$.pipe(\n tap((x) => {\n console.info('SPOT INSTRUMENTS', x.length);\n }),\n listWatch(\n (x) => x.instId,\n (x) => useTicker(x.instId),\n () => true,\n ),\n share(),\n);\n\nconst quoteOfSwapFromRest$ = defer(() => getMarketTickers({ instType: 'SWAP' })).pipe(\n mergeMap((x) => x.data || []),\n map(\n (x): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath(x.instType, x.instId),\n last_price: x.last,\n ask_price: x.askPx,\n bid_price: x.bidPx,\n ask_volume: x.askSz,\n bid_volume: x.bidSz,\n }),\n ),\n repeat({ delay: 1000 }),\n retry({ delay: 1000 }),\n);\n\nconst quoteOfSpotAndMarginFromRest$ = defer(() => getMarketTickers({ instType: 'SPOT' })).pipe(\n mergeMap((x) => x.data || []),\n mergeMap((x): Partial<IQuote>[] => [\n {\n datasource_id: 'OKX',\n product_id: encodePath('SPOT', x.instId),\n last_price: x.last,\n ask_price: x.askPx,\n bid_price: x.bidPx,\n ask_volume: x.askSz,\n bid_volume: x.bidSz,\n },\n {\n datasource_id: 'OKX',\n product_id: encodePath('MARGIN', x.instId),\n last_price: x.last,\n ask_price: x.askPx,\n bid_price: x.bidPx,\n ask_volume: x.askSz,\n bid_volume: x.bidSz,\n },\n ]),\n repeat({ delay: 1000 }),\n retry({ delay: 1000 }),\n);\n\nconst quoteOfSwapFromWs$ = swapInstruments$.pipe(\n listWatch(\n (x) => x.instId,\n (x) => useTicker(x.instId),\n () => true,\n ),\n map(\n (ticker): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('SWAP', ticker[0].instId),\n last_price: ticker[0].last,\n ask_price: ticker[0].askPx,\n bid_price: ticker[0].bidPx,\n ask_volume: ticker[0].askSz,\n bid_volume: ticker[0].bidSz,\n }),\n ),\n);\n\nconst quoteOfSpotAndMarginFromWs$ = spotTicker$.pipe(\n mergeMap((ticker): Partial<IQuote>[] => [\n {\n datasource_id: 'OKX',\n product_id: encodePath('SPOT', ticker[0].instId),\n last_price: ticker[0].last,\n ask_price: ticker[0].askPx,\n bid_price: ticker[0].bidPx,\n ask_volume: ticker[0].askSz,\n bid_volume: ticker[0].bidSz,\n },\n {\n datasource_id: 'OKX',\n product_id: encodePath('MARGIN', ticker[0].instId),\n last_price: ticker[0].last,\n ask_price: ticker[0].askPx,\n bid_price: ticker[0].bidPx,\n ask_volume: ticker[0].askSz,\n bid_volume: ticker[0].bidSz,\n },\n ]),\n);\n\nconst swapOpenInterests$ = defer(() => getOpenInterest({ instType: 'SWAP' })).pipe(\n repeat({ delay: 10_000 }),\n retry({ delay: 10_000 }),\n shareReplay(1),\n);\n\nconst openInterestOfSwapFromWS$ = swapInstruments$.pipe(\n listWatch(\n (x) => x.instId,\n (x) => useOpenInterest(x.instId),\n () => true,\n ),\n map(\n (x): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('SWAP', x[0].instId),\n open_interest: x[0].oi,\n }),\n ),\n share(),\n);\n\nconst interestRateOfSwapFromWS$ = swapInstruments$.pipe(\n listWatch(\n (x) => x.instId,\n (x) => useFundingRate(x.instId),\n () => true,\n ),\n map(\n (x): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('SWAP', x[0].instId),\n interest_rate_long: `-${x[0].fundingRate}`,\n interest_rate_short: x[0].fundingRate,\n interest_rate_next_settled_at: x[0].fundingTime,\n }),\n ),\n share(),\n);\n\ntype PositionTiersResponse = Awaited<ReturnType<typeof getPositionTiers>>;\ntype PositionTiersEntry = PositionTiersResponse['data'];\n\nconst marginPositionTiersMap$ = defer(() =>\n spotInstIds$.pipe(\n first(),\n map((instIds) => instIds.filter((id) => id.endsWith('USDT') || id.endsWith('USDC'))),\n switchMap((instIds) => {\n const total = instIds.length;\n let processed = 0;\n return from(instIds).pipe(\n concatMap((instId) =>\n defer(async () => {\n const tiers = await terminal.client.requestForResponseData<\n { instType: string; tdMode: string; instId: string },\n PositionTiersResponse\n >('OKX/PositionTiers', {\n instType: 'MARGIN',\n tdMode: 'cross',\n instId,\n });\n if (!tiers?.data) {\n throw new Error(`Failed to load position tiers for ${instId}: ${tiers.msg}`);\n }\n return {\n instId,\n tiers,\n };\n }).pipe(retry({ delay: 2000 })),\n ),\n reduce((map, { instId, tiers }) => {\n processed += 1;\n console.info(\n formatTime(Date.now()),\n `Loaded margin position tiers ${processed}/${total} (${instId})`,\n );\n if (tiers?.data) {\n map.set(instId, tiers.data);\n }\n return map;\n }, new Map<string, PositionTiersEntry>()),\n );\n }),\n ),\n).pipe(\n //\n retry({ delay: 60_000 }),\n repeat({ delay: 86400_000 }),\n shareReplay(1),\n);\n\n// Margin 的 open interest 只依赖 position-tier:\n// 1) 启动时先拉全量 MARGIN 仓位档位并缓存,下次直接命中;\n// 2) 档位内只保留同 tier 杠杆最高的记录;\n// 3) 当前策略只使用 tier=1 的 quoteMaxLoan 作为持仓上限,不再混合 /account/max-size;\n// 4) 每个 instId 60 秒刷新一次,并在接口报错时 10 秒重试。\nconst marginOpenInterest$ = spotInstIds$.pipe(\n mergeMap((instIds) =>\n from(instIds).pipe(\n mergeMap((instId) =>\n defer(async () => {\n const tiersMap = await firstValueFrom(marginPositionTiersMap$);\n const tiers = tiersMap.get(instId);\n if (!tiers?.length) {\n return null;\n }\n\n const tierByLevel = tiers\n .filter((tier) => !tier.instId || tier.instId === instId)\n .reduce((mapTierToTierInfo, tierInfo) => {\n const existing = mapTierToTierInfo.get(tierInfo.tier);\n if (!existing || +tierInfo.maxLever > +existing.maxLever) {\n mapTierToTierInfo.set(tierInfo.tier, tierInfo);\n }\n return mapTierToTierInfo;\n }, new Map<string, (typeof tiers)[number]>());\n // 获取一级杠杆的最大可借贷额度作为持仓量\n const openInterest = +(tierByLevel.get('1')?.quoteMaxLoan || 0);\n\n return {\n instId,\n openInterest,\n };\n }).pipe(retry({ delay: 10_000 }), repeat({ delay: 60_000 })),\n ),\n ),\n ),\n filter((result): result is { instId: string; openInterest: number } => result !== null),\n map(({ instId, openInterest }) => {\n const partial: Partial<IQuote> = {\n datasource_id: 'OKX',\n product_id: encodePath('MARGIN', instId),\n };\n if (typeof openInterest === 'number' && Number.isFinite(openInterest)) {\n partial.open_interest = `${openInterest}`;\n }\n return partial;\n }),\n share(),\n);\n\nmarginOpenInterest$.subscribe();\n\nconst quoteSources$ = [\n quoteOfSwapFromWs$,\n openInterestOfSwapFromWS$,\n quoteOfSwapFromRest$,\n quoteOfSpotAndMarginFromWs$,\n quoteOfSpotAndMarginFromRest$,\n marginOpenInterest$,\n interestRateOfSwapFromWS$,\n];\n\nconst quote$ = defer(() =>\n merge(\n ...quoteSources$.map((x$) =>\n defer(() => x$).pipe(\n // 防止单个流关闭导致整体关闭\n catchError(() => EMPTY),\n ),\n ),\n ),\n).pipe(\n groupBy((x) => encodePath(x.datasource_id, x.product_id)),\n mergeMap((group$) => {\n return group$.pipe(\n //\n scan((acc, cur) => Object.assign(acc, cur), {} as Partial<IQuote>),\n );\n }),\n share(),\n);\n\n// 合并不同来源的数据并进行合并,避免死锁\nif (process.env.WRITE_QUOTE_TO_SQL === 'true') {\n terminal.channel.publishChannel('quote', { pattern: `^OKX/` }, (channel_id) => {\n const [datasource_id, product_id] = decodePath(channel_id);\n if (!datasource_id) {\n throw 'datasource_id is required';\n }\n if (!product_id) {\n throw 'product_id is required';\n }\n return quote$.pipe(filter((x) => x.product_id === product_id));\n });\n\n quote$\n .pipe(\n writeToSQL({\n terminal,\n writeInterval: 1000,\n tableName: 'quote',\n conflictKeys: ['datasource_id', 'product_id'],\n }),\n )\n .subscribe();\n}\n\nexport const swapOpenInterest$ = defer(() => swapOpenInterests$).pipe(\n map((x) => new Map(x.data.map((x) => [x.instId, +x.oi] as const))),\n shareReplay(1),\n);\n"]}
1
+ {"version":3,"file":"quote.js","sourceRoot":"","sources":["../../src/public-data/quote.ts"],"names":[],"mappings":"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","sourcesContent":["import { IQuote } from '@yuants/data-quote';\nimport { Terminal } from '@yuants/protocol';\nimport { writeToSQL } from '@yuants/sql';\nimport { decodePath, encodePath, formatTime, listWatch } from '@yuants/utils';\nimport {\n catchError,\n concatMap,\n defer,\n distinctUntilChanged,\n EMPTY,\n filter,\n first,\n firstValueFrom,\n from,\n groupBy,\n map,\n merge,\n mergeMap,\n reduce,\n repeat,\n retry,\n scan,\n share,\n shareReplay,\n switchMap,\n tap,\n toArray,\n} from 'rxjs';\nimport { getInstruments, getMarketTickers, getOpenInterest, getPositionTiers } from '../api/public-api';\nimport { useOpenInterest, useTicker } from '../ws';\n\nconst terminal = Terminal.fromNodeEnv();\n\nconst swapInstruments$ = defer(() => getInstruments({ instType: 'SWAP' })).pipe(\n repeat({ delay: 3600_000 }),\n retry({ delay: 10_000 }),\n map((x) => x.data),\n shareReplay(1),\n);\nconst spotInstruments$ = defer(() => getInstruments({ instType: 'SPOT' })).pipe(\n repeat({ delay: 3600_000 }),\n retry({ delay: 10_000 }),\n map((x) => x.data),\n shareReplay(1),\n);\n\nconst shallowEqual = (a: string[], b: string[]) => a.length === b.length && a.every((v, i) => v === b[i]);\n\nconst spotInstIds$ = spotInstruments$.pipe(\n map((items) => items.map((item) => item.instId)),\n distinctUntilChanged(shallowEqual),\n shareReplay(1),\n);\n\nconst spotTickers$ = defer(() => getMarketTickers({ instType: 'SPOT' })).pipe(\n repeat({ delay: 5000 }),\n retry({ delay: 5000 }),\n shareReplay(1),\n);\n\n// depend by SubmitOrders\nexport const spotMarketTickers$ = defer(() => spotTickers$).pipe(\n mergeMap((x) =>\n from(x.data).pipe(\n map((x) => [x.instId, x] as const),\n toArray(),\n map((x) => Object.fromEntries(x)),\n ),\n ),\n repeat({ delay: 5000 }),\n retry({ delay: 5000 }),\n shareReplay(1),\n);\n\nconst spotTicker$ = spotInstruments$.pipe(\n tap((x) => {\n console.info('SPOT INSTRUMENTS', x.length);\n }),\n listWatch(\n (x) => x.instId,\n (x) => useTicker(x.instId),\n () => true,\n ),\n share(),\n);\n\nconst quoteOfSwapFromRest$ = defer(() => getMarketTickers({ instType: 'SWAP' })).pipe(\n mergeMap((x) => x.data || []),\n map(\n (x): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath(x.instType, x.instId),\n last_price: x.last,\n ask_price: x.askPx,\n bid_price: x.bidPx,\n ask_volume: x.askSz,\n bid_volume: x.bidSz,\n }),\n ),\n repeat({ delay: 1000 }),\n retry({ delay: 1000 }),\n);\n\nconst quoteOfSpotAndMarginFromRest$ = defer(() => getMarketTickers({ instType: 'SPOT' })).pipe(\n mergeMap((x) => x.data || []),\n mergeMap((x): Partial<IQuote>[] => [\n {\n datasource_id: 'OKX',\n product_id: encodePath('SPOT', x.instId),\n last_price: x.last,\n ask_price: x.askPx,\n bid_price: x.bidPx,\n ask_volume: x.askSz,\n bid_volume: x.bidSz,\n },\n {\n datasource_id: 'OKX',\n product_id: encodePath('MARGIN', x.instId),\n last_price: x.last,\n ask_price: x.askPx,\n bid_price: x.bidPx,\n ask_volume: x.askSz,\n bid_volume: x.bidSz,\n },\n ]),\n repeat({ delay: 1000 }),\n retry({ delay: 1000 }),\n);\n\nconst quoteOfSwapFromWs$ = swapInstruments$.pipe(\n listWatch(\n (x) => x.instId,\n (x) => useTicker(x.instId),\n () => true,\n ),\n map(\n (ticker): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('SWAP', ticker[0].instId),\n last_price: ticker[0].last,\n ask_price: ticker[0].askPx,\n bid_price: ticker[0].bidPx,\n ask_volume: ticker[0].askSz,\n bid_volume: ticker[0].bidSz,\n }),\n ),\n);\n\nconst quoteOfSpotAndMarginFromWs$ = spotTicker$.pipe(\n mergeMap((ticker): Partial<IQuote>[] => [\n {\n datasource_id: 'OKX',\n product_id: encodePath('SPOT', ticker[0].instId),\n last_price: ticker[0].last,\n ask_price: ticker[0].askPx,\n bid_price: ticker[0].bidPx,\n ask_volume: ticker[0].askSz,\n bid_volume: ticker[0].bidSz,\n },\n {\n datasource_id: 'OKX',\n product_id: encodePath('MARGIN', ticker[0].instId),\n last_price: ticker[0].last,\n ask_price: ticker[0].askPx,\n bid_price: ticker[0].bidPx,\n ask_volume: ticker[0].askSz,\n bid_volume: ticker[0].bidSz,\n },\n ]),\n);\n\nconst swapOpenInterests$ = defer(() => getOpenInterest({ instType: 'SWAP' })).pipe(\n repeat({ delay: 10_000 }),\n retry({ delay: 10_000 }),\n shareReplay(1),\n);\n\nconst openInterestOfSwapFromWS$ = swapInstruments$.pipe(\n listWatch(\n (x) => x.instId,\n (x) => useOpenInterest(x.instId),\n () => true,\n ),\n map(\n (x): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('SWAP', x[0].instId),\n open_interest: x[0].oi,\n }),\n ),\n share(),\n);\n\ntype PositionTiersResponse = Awaited<ReturnType<typeof getPositionTiers>>;\ntype PositionTiersEntry = PositionTiersResponse['data'];\n\nconst marginPositionTiersMap$ = defer(() =>\n spotInstIds$.pipe(\n first(),\n map((instIds) => instIds.filter((id) => id.endsWith('USDT') || id.endsWith('USDC'))),\n switchMap((instIds) => {\n const total = instIds.length;\n let processed = 0;\n return from(instIds).pipe(\n concatMap((instId) =>\n defer(async () => {\n const tiers = await terminal.client.requestForResponseData<\n { instType: string; tdMode: string; instId: string },\n PositionTiersResponse\n >('OKX/PositionTiers', {\n instType: 'MARGIN',\n tdMode: 'cross',\n instId,\n });\n if (!tiers?.data) {\n throw new Error(`Failed to load position tiers for ${instId}: ${tiers.msg}`);\n }\n return {\n instId,\n tiers,\n };\n }).pipe(retry({ delay: 2000 })),\n ),\n reduce((map, { instId, tiers }) => {\n processed += 1;\n console.info(\n formatTime(Date.now()),\n `Loaded margin position tiers ${processed}/${total} (${instId})`,\n );\n if (tiers?.data) {\n map.set(instId, tiers.data);\n }\n return map;\n }, new Map<string, PositionTiersEntry>()),\n );\n }),\n ),\n).pipe(\n //\n retry({ delay: 60_000 }),\n repeat({ delay: 86400_000 }),\n shareReplay(1),\n);\n\n// Margin 的 open interest 只依赖 position-tier:\n// 1) 启动时先拉全量 MARGIN 仓位档位并缓存,下次直接命中;\n// 2) 档位内只保留同 tier 杠杆最高的记录;\n// 3) 当前策略只使用 tier=1 的 quoteMaxLoan 作为持仓上限,不再混合 /account/max-size;\n// 4) 每个 instId 60 秒刷新一次,并在接口报错时 10 秒重试。\nconst marginOpenInterest$ = spotInstIds$.pipe(\n mergeMap((instIds) =>\n from(instIds).pipe(\n mergeMap((instId) =>\n defer(async () => {\n const tiersMap = await firstValueFrom(marginPositionTiersMap$);\n const tiers = tiersMap.get(instId);\n if (!tiers?.length) {\n return null;\n }\n\n const tierByLevel = tiers\n .filter((tier) => !tier.instId || tier.instId === instId)\n .reduce((mapTierToTierInfo, tierInfo) => {\n const existing = mapTierToTierInfo.get(tierInfo.tier);\n if (!existing || +tierInfo.maxLever > +existing.maxLever) {\n mapTierToTierInfo.set(tierInfo.tier, tierInfo);\n }\n return mapTierToTierInfo;\n }, new Map<string, (typeof tiers)[number]>());\n // 获取一级杠杆的最大可借贷额度作为持仓量\n const openInterest = +(tierByLevel.get('1')?.quoteMaxLoan || 0);\n\n return {\n instId,\n openInterest,\n };\n }).pipe(retry({ delay: 10_000 }), repeat({ delay: 60_000 })),\n ),\n ),\n ),\n filter((result): result is { instId: string; openInterest: number } => result !== null),\n map(({ instId, openInterest }) => {\n const partial: Partial<IQuote> = {\n datasource_id: 'OKX',\n product_id: encodePath('MARGIN', instId),\n };\n if (typeof openInterest === 'number' && Number.isFinite(openInterest)) {\n partial.open_interest = `${openInterest}`;\n }\n return partial;\n }),\n share(),\n);\n\nconst quoteSources$ = [\n quoteOfSwapFromWs$,\n openInterestOfSwapFromWS$,\n quoteOfSwapFromRest$,\n quoteOfSpotAndMarginFromWs$,\n quoteOfSpotAndMarginFromRest$,\n marginOpenInterest$,\n];\n\nconst quote$ = defer(() =>\n merge(\n ...quoteSources$.map((x$) =>\n defer(() => x$).pipe(\n // 防止单个流关闭导致整体关闭\n catchError(() => EMPTY),\n ),\n ),\n ),\n).pipe(\n groupBy((x) => encodePath(x.datasource_id, x.product_id)),\n mergeMap((group$) => {\n return group$.pipe(\n //\n scan((acc, cur) => Object.assign(acc, cur), {} as Partial<IQuote>),\n );\n }),\n share(),\n);\n\n// 合并不同来源的数据并进行合并,避免死锁\nif (process.env.WRITE_QUOTE_TO_SQL === 'true') {\n terminal.channel.publishChannel('quote', { pattern: `^OKX/` }, (channel_id) => {\n const [datasource_id, product_id] = decodePath(channel_id);\n if (!datasource_id) {\n throw 'datasource_id is required';\n }\n if (!product_id) {\n throw 'product_id is required';\n }\n return quote$.pipe(filter((x) => x.product_id === product_id));\n });\n\n quote$\n .pipe(\n writeToSQL({\n terminal,\n writeInterval: 1000,\n tableName: 'quote',\n conflictKeys: ['datasource_id', 'product_id'],\n }),\n )\n .subscribe();\n}\n\nexport const swapOpenInterest$ = defer(() => swapOpenInterests$).pipe(\n map((x) => new Map(x.data.map((x) => [x.instId, +x.oi] as const))),\n shareReplay(1),\n);\n"]}
package/dist/ws.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { GlobalPrometheusRegistry, Terminal } from '@yuants/protocol';
2
2
  import { encodePath, formatTime } from '@yuants/utils';
3
- import { catchError, defer, EMPTY, filter, interval, Observable, tap, timeout } from 'rxjs';
3
+ import { catchError, EMPTY, filter, interval, Observable, shareReplay, tap, timeout, } from 'rxjs';
4
4
  const MetricsWebSocketConnectionsGauge = GlobalPrometheusRegistry.gauge('okx_websocket_connections', 'Number of active OKX WebSocket connections');
5
5
  const MetricsWebSocketChannelGauge = GlobalPrometheusRegistry.gauge('okx_websocket_channel', 'Number of OKX WebSocket channels subscribed');
6
6
  const terminal = Terminal.fromNodeEnv();
@@ -204,32 +204,61 @@ class OKXWsClient {
204
204
  }
205
205
  }
206
206
  OKXWsClient.pool = [];
207
- const fromWsChannelAndInstId = (path, channel, instId) => defer(() => new Observable((subscriber) => {
208
- const client = OKXWsClient.GetWsClient(path);
209
- client.subscribe(channel, instId, (data) => {
210
- subscriber.next(data);
211
- });
212
- const removeError = client.addConnectionListener('error', (err) => {
213
- subscriber.error(err);
214
- });
215
- const removeClose = client.addConnectionListener('close', () => {
216
- subscriber.error('WS Connection Closed');
217
- });
218
- subscriber.add(() => {
219
- removeError();
220
- removeClose();
221
- client.unsubscribe(channel, instId);
222
- });
223
- })).pipe(
224
- // 防止单个连接断开导致数据流关闭
225
- timeout(60000), tap({
226
- error: (err) => {
227
- console.info(formatTime(Date.now()), 'WS_SUBSCRIBE_ERROR', channel, instId, err);
228
- },
229
- }),
230
- // 暂时不太确定是否能支持 retry
231
- // retry({ delay: 1000 }),
232
- catchError(() => EMPTY));
207
+ // 全局缓存:存储已创建的 WebSocket Observable,实现订阅复用
208
+ // key: encodePath(path, channel, instId)
209
+ // value: shared Observable
210
+ const wsObservableCache = new Map();
211
+ const fromWsChannelAndInstId = (path, channel, instId) => {
212
+ const cacheKey = encodePath(path, channel, instId);
213
+ // 检查缓存中是否已存在该订阅
214
+ const cached = wsObservableCache.get(cacheKey);
215
+ if (cached) {
216
+ console.info(formatTime(Date.now()), `♻️ Reusing cached subscription: ${cacheKey}`);
217
+ return cached;
218
+ }
219
+ // 创建新的 Observable
220
+ const observable$ = new Observable((subscriber) => {
221
+ const client = OKXWsClient.GetWsClient(path);
222
+ client.subscribe(channel, instId, (data) => {
223
+ subscriber.next(data);
224
+ });
225
+ const removeError = client.addConnectionListener('error', (err) => {
226
+ subscriber.error(err);
227
+ });
228
+ const removeClose = client.addConnectionListener('close', () => {
229
+ subscriber.error('WS Connection Closed');
230
+ });
231
+ subscriber.add(() => {
232
+ removeError();
233
+ removeClose();
234
+ client.unsubscribe(channel, instId);
235
+ });
236
+ }).pipe(
237
+ // 防止单个连接断开导致数据流关闭
238
+ timeout(60000), tap({
239
+ error: (err) => {
240
+ console.info(formatTime(Date.now()), 'WS_SUBSCRIBE_ERROR', channel, instId, err);
241
+ },
242
+ }),
243
+ // 暂时不太确定是否能支持 retry
244
+ // retry({ delay: 1000 }),
245
+ catchError(() => EMPTY),
246
+ // 🔑 关键:使用 shareReplay 实现订阅复用
247
+ // - bufferSize: 1 - 缓存最新的一个值,新订阅者可以立即获得最新数据
248
+ // - refCount: true - 当所有订阅者都取消订阅时,自动取消上游订阅并清理资源
249
+ shareReplay({ bufferSize: 1, refCount: true }),
250
+ // 当订阅完全结束时,从缓存中移除
251
+ tap({
252
+ finalize: () => {
253
+ console.info(formatTime(Date.now()), `🗑️ Removing from cache: ${cacheKey}`);
254
+ wsObservableCache.delete(cacheKey);
255
+ },
256
+ }));
257
+ // 存入缓存
258
+ wsObservableCache.set(cacheKey, observable$);
259
+ console.info(formatTime(Date.now()), `📦 Cached new subscription: ${cacheKey}`);
260
+ return observable$;
261
+ };
233
262
  export const useTicker = (instId) => fromWsChannelAndInstId('ws/v5/public', 'tickers', instId).pipe(
234
263
  //
235
264
  filter((data) => data.length > 0));
package/dist/ws.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ws.js","sourceRoot":"","sources":["../src/ws.ts"],"names":[],"mappings":"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","sourcesContent":["import { GlobalPrometheusRegistry, Terminal } from '@yuants/protocol';\nimport { encodePath, formatTime } from '@yuants/utils';\nimport { catchError, defer, EMPTY, filter, interval, Observable, Subscription, tap, timeout } from 'rxjs';\nimport { IWSOrderBook } from './public-data/market-order';\n\nconst MetricsWebSocketConnectionsGauge = GlobalPrometheusRegistry.gauge(\n 'okx_websocket_connections',\n 'Number of active OKX WebSocket connections',\n);\n\nconst MetricsWebSocketChannelGauge = GlobalPrometheusRegistry.gauge(\n 'okx_websocket_channel',\n 'Number of OKX WebSocket channels subscribed',\n);\n\ntype ConnectStatus = 'connecting' | 'connected' | 'closed' | 'reconnecting';\nconst terminal = Terminal.fromNodeEnv();\n\nclass OKXWsClient {\n private static readonly pool: {\n path: string;\n client: OKXWsClient;\n requests: number;\n isFull: boolean;\n }[] = [];\n\n // ISSUE: 连接限制:3 次/秒 (基于IP)\n // https://www.okx.com/docs-v5/zh/#overview-websocket-connect\n // 每个连接 对于 订阅/取消订阅/登录 请求的总次数限制为 480 次/小时\n static GetWsClient(path: string): OKXWsClient {\n const existing = OKXWsClient.pool.find((item) => item.path === path && !item.isFull);\n if (existing && !existing.client.isClosed()) {\n existing.requests++;\n if (existing.requests >= 480) {\n existing.isFull = true;\n }\n return existing.client;\n }\n\n const client = existing?.client?.isClosed() ? existing.client.revive() : new OKXWsClient(path);\n if (existing) {\n existing.client = client;\n existing.requests = 1;\n existing.isFull = false;\n } else {\n OKXWsClient.pool.push({ path, client, requests: 1, isFull: false });\n }\n return client;\n }\n\n private readonly baseURL: string = `wss://ws.okx.com:8443`;\n private readonly path: string;\n private ws!: WebSocket;\n private connectStatus: ConnectStatus = 'closed';\n private keepAlive?: Subscription;\n private readonly subscriptions = new Map<\n string,\n {\n channel: string;\n instId?: string;\n }\n >();\n private readonly handlers: Record<string, Function> = {};\n private readonly connectionListeners: Record<'error' | 'close', Set<EventListener>> = {\n error: new Set(),\n close: new Set(),\n };\n\n private readonly handleOpen = () => {\n this.connectStatus = 'connected';\n console.info(formatTime(Date.now()), '✅ WS connected');\n for (const { channel, instId } of this.subscriptions.values()) {\n this.sendSubscribeMessage(channel, instId);\n }\n };\n\n private readonly handleMessage = (raw: MessageEvent) => {\n if (raw.data === 'pong') {\n return;\n }\n const msg = JSON.parse(raw.data);\n if (msg.arg?.channel) {\n const channelId = encodePath(msg.arg.channel, msg.arg.instId);\n const data = msg.data;\n const handler = this.handlers[channelId];\n if (data && handler) {\n handler(data, msg.arg);\n }\n } else if (msg.event) {\n console.info(formatTime(Date.now()), 'Event:', msg);\n }\n };\n\n private readonly handleError = (event: Event) => {\n console.error(formatTime(Date.now()), '❌ WS error', event);\n };\n\n private readonly handleClose = (event: CloseEvent) => {\n console.error(formatTime(Date.now()), '❌ WS closed', event);\n MetricsWebSocketConnectionsGauge.labels({ path: this.path }).dec();\n\n const closedSocket = event.target as WebSocket;\n if (closedSocket !== this.ws) {\n return;\n }\n\n if (this.connectStatus === 'reconnecting') {\n return;\n }\n\n this.connectStatus = 'closed';\n\n if (this.subscriptions.size === 0) {\n return;\n }\n\n this.connectStatus = 'reconnecting';\n setTimeout(() => {\n if (this.connectStatus === 'connecting' || this.connectStatus === 'connected') {\n return;\n }\n if (this.subscriptions.size === 0) {\n this.connectStatus = 'closed';\n return;\n }\n this.initSocket();\n }, 1000);\n };\n\n constructor(path: string) {\n this.path = path;\n this.initSocket();\n this.startKeepAlive();\n }\n\n private revive(): OKXWsClient {\n this.initSocket();\n this.startKeepAlive();\n return this;\n }\n\n private initSocket() {\n this.connectStatus = 'connecting';\n this.ws = new WebSocket(`${this.baseURL}/${this.path}`);\n MetricsWebSocketConnectionsGauge.labels({ path: this.path, terminal_id: terminal.terminal_id }).inc();\n\n this.ws.addEventListener('open', this.handleOpen);\n this.ws.addEventListener('message', this.handleMessage);\n this.ws.addEventListener('error', this.handleError);\n this.ws.addEventListener('close', this.handleClose);\n\n for (const listener of this.connectionListeners.error) {\n this.ws.addEventListener('error', listener);\n }\n for (const listener of this.connectionListeners.close) {\n this.ws.addEventListener('close', listener);\n }\n }\n\n private startKeepAlive() {\n if (this.keepAlive && !this.keepAlive.closed) {\n return;\n }\n this.keepAlive = interval(25_000)\n .pipe(\n tap(() => {\n if (this.connectStatus === 'connected') {\n this.ws.send('ping');\n }\n }),\n )\n .subscribe();\n }\n\n private stopKeepAlive() {\n if (this.keepAlive && !this.keepAlive.closed) {\n this.keepAlive.unsubscribe();\n }\n }\n\n private isClosed() {\n return this.ws?.readyState === WebSocket.CLOSING || this.ws?.readyState === WebSocket.CLOSED;\n }\n\n private sendSubscribeMessage(channel: string, instId?: string) {\n const message = {\n op: 'subscribe',\n args: [{ channel, instId }],\n };\n this.ws.send(JSON.stringify(message));\n const channelId = encodePath(channel, instId);\n console.info(formatTime(Date.now()), `📩 Sent subscribe for ${channelId}`);\n }\n\n private sendUnsubscribeMessage(channel: string, instId?: string) {\n const message = {\n op: 'unsubscribe',\n args: [{ channel, instId }],\n };\n this.ws.send(JSON.stringify(message));\n const channelId = encodePath(channel, instId);\n console.info(formatTime(Date.now()), `📩 Sent unsubscribe for ${channelId}`);\n }\n\n addConnectionListener(type: 'error' | 'close', listener: EventListener): () => void {\n this.connectionListeners[type].add(listener);\n this.ws.addEventListener(type, listener);\n return () => {\n this.connectionListeners[type].delete(listener);\n this.ws.removeEventListener(type, listener);\n };\n }\n\n subscribe(channel: string, instId?: string, handler?: Function) {\n const channelId = encodePath(channel, instId);\n if (this.subscriptions.has(channelId)) {\n console.info(formatTime(Date.now()), `⚠️ Already subscribed: ${channelId}`);\n return;\n }\n\n this.subscriptions.set(channelId, { channel, instId });\n MetricsWebSocketChannelGauge.labels({ channel, terminal_id: terminal.terminal_id }).inc();\n\n if (handler) {\n this.handlers[channelId] = handler;\n }\n\n this.startKeepAlive();\n\n if (this.connectStatus === 'connected') {\n this.sendSubscribeMessage(channel, instId);\n } else if (this.isClosed()) {\n this.initSocket();\n } else {\n console.info(formatTime(Date.now()), `📩 Queued subscribe for ${channelId} waiting for connection`);\n }\n }\n\n unsubscribe(channel: string, instId?: string) {\n const channelId = encodePath(channel, instId);\n if (!this.subscriptions.has(channelId)) return;\n\n if (this.connectStatus === 'connected') {\n this.sendUnsubscribeMessage(channel, instId);\n }\n this.subscriptions.delete(channelId);\n MetricsWebSocketChannelGauge.labels({ channel }).dec();\n delete this.handlers[channelId];\n\n if (this.subscriptions.size === 0) {\n this.stopKeepAlive();\n if (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING) {\n this.ws.close();\n }\n }\n }\n}\n\nconst fromWsChannelAndInstId = <T>(path: string, channel: string, instId: string) =>\n defer(\n () =>\n new Observable<T>((subscriber) => {\n const client = OKXWsClient.GetWsClient(path);\n client.subscribe(channel, instId, (data: T) => {\n subscriber.next(data);\n });\n const removeError = client.addConnectionListener('error', (err) => {\n subscriber.error(err);\n });\n const removeClose = client.addConnectionListener('close', () => {\n subscriber.error('WS Connection Closed');\n });\n subscriber.add(() => {\n removeError();\n removeClose();\n client.unsubscribe(channel, instId);\n });\n }),\n ).pipe(\n // 防止单个连接断开导致数据流关闭\n timeout(60_000),\n tap({\n error: (err) => {\n console.info(formatTime(Date.now()), 'WS_SUBSCRIBE_ERROR', channel, instId, err);\n },\n }),\n // 暂时不太确定是否能支持 retry\n // retry({ delay: 1000 }),\n catchError(() => EMPTY),\n );\n\nexport const useTicker = (instId: string) =>\n fromWsChannelAndInstId<\n {\n instId: string;\n last: string;\n askPx: string;\n bidPx: string;\n askSz: string;\n bidSz: string;\n }[]\n >('ws/v5/public', 'tickers', instId).pipe(\n //\n filter((data) => data.length > 0),\n );\n\nexport const useOpenInterest = (instId: string) =>\n fromWsChannelAndInstId<\n {\n instId: string;\n oi: string; // open interest\n }[]\n >('ws/v5/public', 'open-interest', instId).pipe(\n //\n filter((data) => data.length > 0),\n );\n\nexport const useOHLC = (candleType: string, instId: string) =>\n fromWsChannelAndInstId<string[][]>('ws/v5/business', candleType, instId).pipe(\n //\n filter((data) => data.length > 0),\n );\n\nexport const useMarketBooks = (\n channel: 'books' | 'books5' | 'bbo-tbt' | 'books-l2-tbt' | 'books50-l2-tbt',\n instId: string,\n) =>\n fromWsChannelAndInstId<IWSOrderBook[]>('ws/v5/public', channel, instId).pipe(\n //\n filter((data) => data.length > 0),\n );\n\nexport const useFundingRate = (instId: string) =>\n fromWsChannelAndInstId<\n {\n fundingRate: string;\n fundingTime: string;\n instId: string;\n instType: string;\n method: string;\n maxFundingRate: string;\n minFundingRate: string;\n nextFundingRate: string;\n nextFundingTime: string;\n premium: string;\n settFundingRate: string;\n settState: string;\n ts: string;\n }[]\n >('ws/v5/public', 'funding-rate', instId).pipe(\n //\n filter((data) => data.length > 0),\n );\n"]}
1
+ {"version":3,"file":"ws.js","sourceRoot":"","sources":["../src/ws.ts"],"names":[],"mappings":"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","sourcesContent":["import { GlobalPrometheusRegistry, Terminal } from '@yuants/protocol';\nimport { encodePath, formatTime } from '@yuants/utils';\nimport {\n catchError,\n EMPTY,\n filter,\n interval,\n Observable,\n shareReplay,\n Subscription,\n tap,\n timeout,\n} from 'rxjs';\nimport { IWSOrderBook } from './public-data/market-order';\n\nconst MetricsWebSocketConnectionsGauge = GlobalPrometheusRegistry.gauge(\n 'okx_websocket_connections',\n 'Number of active OKX WebSocket connections',\n);\n\nconst MetricsWebSocketChannelGauge = GlobalPrometheusRegistry.gauge(\n 'okx_websocket_channel',\n 'Number of OKX WebSocket channels subscribed',\n);\n\ntype ConnectStatus = 'connecting' | 'connected' | 'closed' | 'reconnecting';\nconst terminal = Terminal.fromNodeEnv();\n\nclass OKXWsClient {\n private static readonly pool: {\n path: string;\n client: OKXWsClient;\n requests: number;\n isFull: boolean;\n }[] = [];\n\n // ISSUE: 连接限制:3 次/秒 (基于IP)\n // https://www.okx.com/docs-v5/zh/#overview-websocket-connect\n // 每个连接 对于 订阅/取消订阅/登录 请求的总次数限制为 480 次/小时\n static GetWsClient(path: string): OKXWsClient {\n const existing = OKXWsClient.pool.find((item) => item.path === path && !item.isFull);\n if (existing && !existing.client.isClosed()) {\n existing.requests++;\n if (existing.requests >= 480) {\n existing.isFull = true;\n }\n return existing.client;\n }\n\n const client = existing?.client?.isClosed() ? existing.client.revive() : new OKXWsClient(path);\n if (existing) {\n existing.client = client;\n existing.requests = 1;\n existing.isFull = false;\n } else {\n OKXWsClient.pool.push({ path, client, requests: 1, isFull: false });\n }\n return client;\n }\n\n private readonly baseURL: string = `wss://ws.okx.com:8443`;\n private readonly path: string;\n private ws!: WebSocket;\n private connectStatus: ConnectStatus = 'closed';\n private keepAlive?: Subscription;\n private readonly subscriptions = new Map<\n string,\n {\n channel: string;\n instId?: string;\n }\n >();\n private readonly handlers: Record<string, Function> = {};\n private readonly connectionListeners: Record<'error' | 'close', Set<EventListener>> = {\n error: new Set(),\n close: new Set(),\n };\n\n private readonly handleOpen = () => {\n this.connectStatus = 'connected';\n console.info(formatTime(Date.now()), '✅ WS connected');\n for (const { channel, instId } of this.subscriptions.values()) {\n this.sendSubscribeMessage(channel, instId);\n }\n };\n\n private readonly handleMessage = (raw: MessageEvent) => {\n if (raw.data === 'pong') {\n return;\n }\n const msg = JSON.parse(raw.data);\n if (msg.arg?.channel) {\n const channelId = encodePath(msg.arg.channel, msg.arg.instId);\n const data = msg.data;\n const handler = this.handlers[channelId];\n if (data && handler) {\n handler(data, msg.arg);\n }\n } else if (msg.event) {\n console.info(formatTime(Date.now()), 'Event:', msg);\n }\n };\n\n private readonly handleError = (event: Event) => {\n console.error(formatTime(Date.now()), '❌ WS error', event);\n };\n\n private readonly handleClose = (event: CloseEvent) => {\n console.error(formatTime(Date.now()), '❌ WS closed', event);\n MetricsWebSocketConnectionsGauge.labels({ path: this.path }).dec();\n\n const closedSocket = event.target as WebSocket;\n if (closedSocket !== this.ws) {\n return;\n }\n\n if (this.connectStatus === 'reconnecting') {\n return;\n }\n\n this.connectStatus = 'closed';\n\n if (this.subscriptions.size === 0) {\n return;\n }\n\n this.connectStatus = 'reconnecting';\n setTimeout(() => {\n if (this.connectStatus === 'connecting' || this.connectStatus === 'connected') {\n return;\n }\n if (this.subscriptions.size === 0) {\n this.connectStatus = 'closed';\n return;\n }\n this.initSocket();\n }, 1000);\n };\n\n constructor(path: string) {\n this.path = path;\n this.initSocket();\n this.startKeepAlive();\n }\n\n private revive(): OKXWsClient {\n this.initSocket();\n this.startKeepAlive();\n return this;\n }\n\n private initSocket() {\n this.connectStatus = 'connecting';\n this.ws = new WebSocket(`${this.baseURL}/${this.path}`);\n MetricsWebSocketConnectionsGauge.labels({ path: this.path, terminal_id: terminal.terminal_id }).inc();\n\n this.ws.addEventListener('open', this.handleOpen);\n this.ws.addEventListener('message', this.handleMessage);\n this.ws.addEventListener('error', this.handleError);\n this.ws.addEventListener('close', this.handleClose);\n\n for (const listener of this.connectionListeners.error) {\n this.ws.addEventListener('error', listener);\n }\n for (const listener of this.connectionListeners.close) {\n this.ws.addEventListener('close', listener);\n }\n }\n\n private startKeepAlive() {\n if (this.keepAlive && !this.keepAlive.closed) {\n return;\n }\n this.keepAlive = interval(25_000)\n .pipe(\n tap(() => {\n if (this.connectStatus === 'connected') {\n this.ws.send('ping');\n }\n }),\n )\n .subscribe();\n }\n\n private stopKeepAlive() {\n if (this.keepAlive && !this.keepAlive.closed) {\n this.keepAlive.unsubscribe();\n }\n }\n\n private isClosed() {\n return this.ws?.readyState === WebSocket.CLOSING || this.ws?.readyState === WebSocket.CLOSED;\n }\n\n private sendSubscribeMessage(channel: string, instId?: string) {\n const message = {\n op: 'subscribe',\n args: [{ channel, instId }],\n };\n this.ws.send(JSON.stringify(message));\n const channelId = encodePath(channel, instId);\n console.info(formatTime(Date.now()), `📩 Sent subscribe for ${channelId}`);\n }\n\n private sendUnsubscribeMessage(channel: string, instId?: string) {\n const message = {\n op: 'unsubscribe',\n args: [{ channel, instId }],\n };\n this.ws.send(JSON.stringify(message));\n const channelId = encodePath(channel, instId);\n console.info(formatTime(Date.now()), `📩 Sent unsubscribe for ${channelId}`);\n }\n\n addConnectionListener(type: 'error' | 'close', listener: EventListener): () => void {\n this.connectionListeners[type].add(listener);\n this.ws.addEventListener(type, listener);\n return () => {\n this.connectionListeners[type].delete(listener);\n this.ws.removeEventListener(type, listener);\n };\n }\n\n subscribe(channel: string, instId?: string, handler?: Function) {\n const channelId = encodePath(channel, instId);\n if (this.subscriptions.has(channelId)) {\n console.info(formatTime(Date.now()), `⚠️ Already subscribed: ${channelId}`);\n return;\n }\n\n this.subscriptions.set(channelId, { channel, instId });\n MetricsWebSocketChannelGauge.labels({ channel, terminal_id: terminal.terminal_id }).inc();\n\n if (handler) {\n this.handlers[channelId] = handler;\n }\n\n this.startKeepAlive();\n\n if (this.connectStatus === 'connected') {\n this.sendSubscribeMessage(channel, instId);\n } else if (this.isClosed()) {\n this.initSocket();\n } else {\n console.info(formatTime(Date.now()), `📩 Queued subscribe for ${channelId} waiting for connection`);\n }\n }\n\n unsubscribe(channel: string, instId?: string) {\n const channelId = encodePath(channel, instId);\n if (!this.subscriptions.has(channelId)) return;\n\n if (this.connectStatus === 'connected') {\n this.sendUnsubscribeMessage(channel, instId);\n }\n this.subscriptions.delete(channelId);\n MetricsWebSocketChannelGauge.labels({ channel }).dec();\n delete this.handlers[channelId];\n\n if (this.subscriptions.size === 0) {\n this.stopKeepAlive();\n if (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING) {\n this.ws.close();\n }\n }\n }\n}\n\n// 全局缓存:存储已创建的 WebSocket Observable,实现订阅复用\n// key: encodePath(path, channel, instId)\n// value: shared Observable\nconst wsObservableCache = new Map<string, Observable<any>>();\n\nconst fromWsChannelAndInstId = <T>(path: string, channel: string, instId: string) => {\n const cacheKey = encodePath(path, channel, instId);\n\n // 检查缓存中是否已存在该订阅\n const cached = wsObservableCache.get(cacheKey);\n if (cached) {\n console.info(formatTime(Date.now()), `♻️ Reusing cached subscription: ${cacheKey}`);\n return cached as Observable<T>;\n }\n\n // 创建新的 Observable\n const observable$ = new Observable<T>((subscriber) => {\n const client = OKXWsClient.GetWsClient(path);\n client.subscribe(channel, instId, (data: T) => {\n subscriber.next(data);\n });\n const removeError = client.addConnectionListener('error', (err) => {\n subscriber.error(err);\n });\n const removeClose = client.addConnectionListener('close', () => {\n subscriber.error('WS Connection Closed');\n });\n subscriber.add(() => {\n removeError();\n removeClose();\n client.unsubscribe(channel, instId);\n });\n }).pipe(\n // 防止单个连接断开导致数据流关闭\n timeout(60_000),\n tap({\n error: (err) => {\n console.info(formatTime(Date.now()), 'WS_SUBSCRIBE_ERROR', channel, instId, err);\n },\n }),\n // 暂时不太确定是否能支持 retry\n // retry({ delay: 1000 }),\n catchError(() => EMPTY),\n // 🔑 关键:使用 shareReplay 实现订阅复用\n // - bufferSize: 1 - 缓存最新的一个值,新订阅者可以立即获得最新数据\n // - refCount: true - 当所有订阅者都取消订阅时,自动取消上游订阅并清理资源\n shareReplay({ bufferSize: 1, refCount: true }),\n // 当订阅完全结束时,从缓存中移除\n tap({\n finalize: () => {\n console.info(formatTime(Date.now()), `🗑️ Removing from cache: ${cacheKey}`);\n wsObservableCache.delete(cacheKey);\n },\n }),\n );\n\n // 存入缓存\n wsObservableCache.set(cacheKey, observable$);\n console.info(formatTime(Date.now()), `📦 Cached new subscription: ${cacheKey}`);\n\n return observable$;\n};\n\nexport const useTicker = (instId: string) =>\n fromWsChannelAndInstId<\n {\n instId: string;\n last: string;\n askPx: string;\n bidPx: string;\n askSz: string;\n bidSz: string;\n }[]\n >('ws/v5/public', 'tickers', instId).pipe(\n //\n filter((data) => data.length > 0),\n );\n\nexport const useOpenInterest = (instId: string) =>\n fromWsChannelAndInstId<\n {\n instId: string;\n oi: string; // open interest\n }[]\n >('ws/v5/public', 'open-interest', instId).pipe(\n //\n filter((data) => data.length > 0),\n );\n\nexport const useOHLC = (candleType: string, instId: string) =>\n fromWsChannelAndInstId<string[][]>('ws/v5/business', candleType, instId).pipe(\n //\n filter((data) => data.length > 0),\n );\n\nexport const useMarketBooks = (\n channel: 'books' | 'books5' | 'bbo-tbt' | 'books-l2-tbt' | 'books50-l2-tbt',\n instId: string,\n) =>\n fromWsChannelAndInstId<IWSOrderBook[]>('ws/v5/public', channel, instId).pipe(\n //\n filter((data) => data.length > 0),\n );\n\nexport const useFundingRate = (instId: string) =>\n fromWsChannelAndInstId<\n {\n fundingRate: string;\n fundingTime: string;\n instId: string;\n instType: string;\n method: string;\n maxFundingRate: string;\n minFundingRate: string;\n nextFundingRate: string;\n nextFundingTime: string;\n premium: string;\n settFundingRate: string;\n settState: string;\n ts: string;\n }[]\n >('ws/v5/public', 'funding-rate', instId).pipe(\n //\n filter((data) => data.length > 0),\n );\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"new-quote.d.ts","sourceRoot":"","sources":["../../src/public-data/new-quote.ts"],"names":[],"mappings":"AA6DA,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;EAW9B,CAAC;AAySF,eAAO,MAAM,iBAAiB,gDAG7B,CAAC"}
1
+ {"version":3,"file":"new-quote.d.ts","sourceRoot":"","sources":["../../src/public-data/new-quote.ts"],"names":[],"mappings":"AAmEA,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;EAW9B,CAAC;AA4TF,eAAO,MAAM,iBAAiB,gDAG7B,CAAC"}
@@ -82,13 +82,6 @@ const openInterestOfSwapFromWS$ = swapInstruments$.pipe((0, utils_1.listWatch)((
82
82
  product_id: (0, utils_1.encodePath)('OKX', 'SWAP', x[0].instId),
83
83
  open_interest: x[0].oi,
84
84
  })), (0, rxjs_1.share)());
85
- const interestRateOfSwapFromWS$ = swapInstruments$.pipe((0, utils_1.listWatch)((x) => x.instId, (x) => (0, ws_1.useFundingRate)(x.instId), () => true), (0, rxjs_1.map)((x) => ({
86
- datasource_id: 'OKX',
87
- product_id: (0, utils_1.encodePath)('OKX', 'SWAP', x[0].instId),
88
- interest_rate_long: `${-+x[0].fundingRate}`,
89
- interest_rate_short: x[0].fundingRate,
90
- interest_rate_next_settled_at: x[0].fundingTime,
91
- })), (0, rxjs_1.share)());
92
85
  const marginPositionTiersMap$ = (0, rxjs_1.defer)(() => spotInstIds$.pipe((0, rxjs_1.first)(), (0, rxjs_1.map)((instIds) => instIds.filter((id) => id.endsWith('USDT') || id.endsWith('USDC'))), (0, rxjs_1.switchMap)((instIds) => {
93
86
  const total = instIds.length;
94
87
  let processed = 0;
@@ -153,7 +146,15 @@ const marginOpenInterest$ = spotInstIds$.pipe((0, rxjs_1.mergeMap)((instIds) =>
153
146
  }
154
147
  return partial;
155
148
  }), (0, rxjs_1.share)());
156
- marginOpenInterest$.subscribe();
149
+ const fundingRate$ = (0, rxjs_1.defer)(() => (0, public_api_1.getFundingRate)({ instId: 'ANY' })).pipe((0, rxjs_1.map)((data) => data.data), (0, rxjs_1.repeat)({ delay: 50000 }), (0, rxjs_1.retry)({ delay: 5000 }), (0, rxjs_1.shareReplay)({ bufferSize: 1, refCount: true }));
150
+ // Convert funding rate data to quote format
151
+ const interestRateOfSwap$ = fundingRate$.pipe((0, rxjs_1.mergeMap)((premiumDataArray) => premiumDataArray), (0, rxjs_1.map)((premiumData) => ({
152
+ datasource_id: 'OKX',
153
+ product_id: (0, utils_1.encodePath)('OKX', 'SWAP', premiumData.instId),
154
+ interest_rate_long: premiumData.fundingRate ? `${-+premiumData.fundingRate}` : undefined,
155
+ interest_rate_short: premiumData.fundingRate,
156
+ interest_rate_next_settled_at: (0, utils_1.formatTime)(+premiumData.fundingTime),
157
+ })));
157
158
  const quoteSources$ = [
158
159
  quoteOfSwapFromWs$,
159
160
  openInterestOfSwapFromWS$,
@@ -161,7 +162,7 @@ const quoteSources$ = [
161
162
  quoteOfSpotAndMarginFromWs$,
162
163
  quoteOfSpotAndMarginFromRest$,
163
164
  marginOpenInterest$,
164
- interestRateOfSwapFromWS$,
165
+ interestRateOfSwap$,
165
166
  ];
166
167
  const quote$ = (0, rxjs_1.defer)(() => (0, rxjs_1.merge)(...quoteSources$.map((x$) => (0, rxjs_1.defer)(() => x$).pipe(
167
168
  // 防止单个流关闭导致整体关闭
@@ -192,4 +193,9 @@ if (process.env.WRITE_QUOTE_TO_SQL === 'true') {
192
193
  .subscribe();
193
194
  }
194
195
  exports.swapOpenInterest$ = (0, rxjs_1.defer)(() => swapOpenInterests$).pipe((0, rxjs_1.map)((x) => new Map(x.data.map((x) => [x.instId, +x.oi]))), (0, rxjs_1.shareReplay)(1));
196
+ quote$
197
+ .pipe((0, rxjs_1.tap)((quote) => {
198
+ console.log(quote);
199
+ }))
200
+ .subscribe();
195
201
  //# sourceMappingURL=new-quote.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"new-quote.js","sourceRoot":"","sources":["../../src/public-data/new-quote.ts"],"names":[],"mappings":"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","sourcesContent":["import { IQuote } from '@yuants/data-quote';\nimport { Terminal } from '@yuants/protocol';\nimport { writeToSQL } from '@yuants/sql';\nimport { decodePath, encodePath, formatTime, listWatch } from '@yuants/utils';\nimport {\n catchError,\n concatMap,\n defer,\n distinctUntilChanged,\n EMPTY,\n filter,\n first,\n firstValueFrom,\n from,\n groupBy,\n map,\n merge,\n mergeMap,\n reduce,\n repeat,\n retry,\n scan,\n share,\n shareReplay,\n switchMap,\n tap,\n toArray,\n} from 'rxjs';\nimport { getInstruments, getMarketTickers, getOpenInterest, getPositionTiers } from '../api/public-api';\nimport { useFundingRate, useOpenInterest, useTicker } from '../ws';\n\nconst terminal = Terminal.fromNodeEnv();\n\nconst swapInstruments$ = defer(() => getInstruments({ instType: 'SWAP' })).pipe(\n repeat({ delay: 3600_000 }),\n retry({ delay: 10_000 }),\n map((x) => x.data),\n shareReplay(1),\n);\nconst spotInstruments$ = defer(() => getInstruments({ instType: 'SPOT' })).pipe(\n repeat({ delay: 3600_000 }),\n retry({ delay: 10_000 }),\n map((x) => x.data),\n shareReplay(1),\n);\n\nconst shallowEqual = (a: string[], b: string[]) => a.length === b.length && a.every((v, i) => v === b[i]);\n\nconst spotInstIds$ = spotInstruments$.pipe(\n map((items) => items.map((item) => item.instId)),\n distinctUntilChanged(shallowEqual),\n shareReplay(1),\n);\n\nconst spotTickers$ = defer(() => getMarketTickers({ instType: 'SPOT' })).pipe(\n repeat({ delay: 5000 }),\n retry({ delay: 5000 }),\n shareReplay(1),\n);\n\n// depend by SubmitOrders\nexport const spotMarketTickers$ = defer(() => spotTickers$).pipe(\n mergeMap((x) =>\n from(x.data).pipe(\n map((x) => [x.instId, x] as const),\n toArray(),\n map((x) => Object.fromEntries(x)),\n ),\n ),\n repeat({ delay: 5000 }),\n retry({ delay: 5000 }),\n shareReplay(1),\n);\n\nconst spotTicker$ = spotInstruments$.pipe(\n tap((x) => {\n console.info('SPOT INSTRUMENTS', x.length);\n }),\n listWatch(\n (x) => x.instId,\n (x) => useTicker(x.instId),\n () => true,\n ),\n share(),\n);\n\nconst quoteOfSwapFromRest$ = defer(() => getMarketTickers({ instType: 'SWAP' })).pipe(\n mergeMap((x) => x.data || []),\n map(\n (x): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('OKX', x.instType, x.instId),\n last_price: x.last,\n ask_price: x.askPx,\n bid_price: x.bidPx,\n ask_volume: x.askSz,\n bid_volume: x.bidSz,\n }),\n ),\n repeat({ delay: 1000 }),\n retry({ delay: 1000 }),\n);\n\nconst quoteOfSpotAndMarginFromRest$ = defer(() => getMarketTickers({ instType: 'SPOT' })).pipe(\n mergeMap((x) => x.data || []),\n mergeMap((x): Partial<IQuote>[] => [\n {\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'SPOT', x.instId),\n last_price: x.last,\n ask_price: x.askPx,\n bid_price: x.bidPx,\n ask_volume: x.askSz,\n bid_volume: x.bidSz,\n },\n {\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'MARGIN', x.instId),\n last_price: x.last,\n ask_price: x.askPx,\n bid_price: x.bidPx,\n ask_volume: x.askSz,\n bid_volume: x.bidSz,\n },\n ]),\n repeat({ delay: 1000 }),\n retry({ delay: 1000 }),\n);\n\nconst quoteOfSwapFromWs$ = swapInstruments$.pipe(\n listWatch(\n (x) => x.instId,\n (x) => useTicker(x.instId),\n () => true,\n ),\n map(\n (ticker): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'SWAP', ticker[0].instId),\n last_price: ticker[0].last,\n ask_price: ticker[0].askPx,\n bid_price: ticker[0].bidPx,\n ask_volume: ticker[0].askSz,\n bid_volume: ticker[0].bidSz,\n }),\n ),\n);\n\nconst quoteOfSpotAndMarginFromWs$ = spotTicker$.pipe(\n mergeMap((ticker): Partial<IQuote>[] => [\n {\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'SPOT', ticker[0].instId),\n last_price: ticker[0].last,\n ask_price: ticker[0].askPx,\n bid_price: ticker[0].bidPx,\n ask_volume: ticker[0].askSz,\n bid_volume: ticker[0].bidSz,\n },\n {\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'MARGIN', ticker[0].instId),\n last_price: ticker[0].last,\n ask_price: ticker[0].askPx,\n bid_price: ticker[0].bidPx,\n ask_volume: ticker[0].askSz,\n bid_volume: ticker[0].bidSz,\n },\n ]),\n);\n\nconst swapOpenInterests$ = defer(() => getOpenInterest({ instType: 'SWAP' })).pipe(\n repeat({ delay: 10_000 }),\n retry({ delay: 10_000 }),\n shareReplay(1),\n);\n\nconst openInterestOfSwapFromWS$ = swapInstruments$.pipe(\n listWatch(\n (x) => x.instId,\n (x) => useOpenInterest(x.instId),\n () => true,\n ),\n map(\n (x): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'SWAP', x[0].instId),\n open_interest: x[0].oi,\n }),\n ),\n share(),\n);\n\nconst interestRateOfSwapFromWS$ = swapInstruments$.pipe(\n listWatch(\n (x) => x.instId,\n (x) => useFundingRate(x.instId),\n () => true,\n ),\n map(\n (x): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'SWAP', x[0].instId),\n interest_rate_long: `${-+x[0].fundingRate}`,\n interest_rate_short: x[0].fundingRate,\n interest_rate_next_settled_at: x[0].fundingTime,\n }),\n ),\n share(),\n);\n\ntype PositionTiersResponse = Awaited<ReturnType<typeof getPositionTiers>>;\ntype PositionTiersEntry = PositionTiersResponse['data'];\n\nconst marginPositionTiersMap$ = defer(() =>\n spotInstIds$.pipe(\n first(),\n map((instIds) => instIds.filter((id) => id.endsWith('USDT') || id.endsWith('USDC'))),\n switchMap((instIds) => {\n const total = instIds.length;\n let processed = 0;\n return from(instIds).pipe(\n concatMap((instId) =>\n defer(async () => {\n const tiers = await terminal.client.requestForResponseData<\n { instType: string; tdMode: string; instId: string },\n PositionTiersResponse\n >('OKX/PositionTiers', {\n instType: 'MARGIN',\n tdMode: 'cross',\n instId,\n });\n if (!tiers?.data) {\n throw new Error(`Failed to load position tiers for ${instId}: ${tiers.msg}`);\n }\n return {\n instId,\n tiers,\n };\n }).pipe(retry({ delay: 2000 })),\n ),\n reduce((map, { instId, tiers }) => {\n processed += 1;\n console.info(\n formatTime(Date.now()),\n `Loaded margin position tiers ${processed}/${total} (${instId})`,\n );\n if (tiers?.data) {\n map.set(instId, tiers.data);\n }\n return map;\n }, new Map<string, PositionTiersEntry>()),\n );\n }),\n ),\n).pipe(\n //\n retry({ delay: 60_000 }),\n repeat({ delay: 86400_000 }),\n shareReplay(1),\n);\n\n// Margin 的 open interest 只依赖 position-tier:\n// 1) 启动时先拉全量 MARGIN 仓位档位并缓存,下次直接命中;\n// 2) 档位内只保留同 tier 杠杆最高的记录;\n// 3) 当前策略只使用 tier=1 的 quoteMaxLoan 作为持仓上限,不再混合 /account/max-size;\n// 4) 每个 instId 60 秒刷新一次,并在接口报错时 10 秒重试。\nconst marginOpenInterest$ = spotInstIds$.pipe(\n mergeMap((instIds) =>\n from(instIds).pipe(\n mergeMap((instId) =>\n defer(async () => {\n const tiersMap = await firstValueFrom(marginPositionTiersMap$);\n const tiers = tiersMap.get(instId);\n if (!tiers?.length) {\n return null;\n }\n\n const tierByLevel = tiers\n .filter((tier) => !tier.instId || tier.instId === instId)\n .reduce((mapTierToTierInfo, tierInfo) => {\n const existing = mapTierToTierInfo.get(tierInfo.tier);\n if (!existing || +tierInfo.maxLever > +existing.maxLever) {\n mapTierToTierInfo.set(tierInfo.tier, tierInfo);\n }\n return mapTierToTierInfo;\n }, new Map<string, (typeof tiers)[number]>());\n // 获取一级杠杆的最大可借贷额度作为持仓量\n const openInterest = +(tierByLevel.get('1')?.quoteMaxLoan || 0);\n\n return {\n instId,\n openInterest,\n };\n }).pipe(retry({ delay: 10_000 }), repeat({ delay: 60_000 })),\n ),\n ),\n ),\n filter((result): result is { instId: string; openInterest: number } => result !== null),\n map(({ instId, openInterest }) => {\n const partial: Partial<IQuote> = {\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'MARGIN', instId),\n };\n if (typeof openInterest === 'number' && Number.isFinite(openInterest)) {\n partial.open_interest = `${openInterest}`;\n }\n return partial;\n }),\n share(),\n);\n\nmarginOpenInterest$.subscribe();\n\nconst quoteSources$ = [\n quoteOfSwapFromWs$,\n openInterestOfSwapFromWS$,\n quoteOfSwapFromRest$,\n quoteOfSpotAndMarginFromWs$,\n quoteOfSpotAndMarginFromRest$,\n marginOpenInterest$,\n interestRateOfSwapFromWS$,\n];\n\nconst quote$ = defer(() =>\n merge(\n ...quoteSources$.map((x$) =>\n defer(() => x$).pipe(\n // 防止单个流关闭导致整体关闭\n catchError(() => EMPTY),\n ),\n ),\n ),\n).pipe(\n groupBy((x) => encodePath(x.datasource_id, x.product_id)),\n mergeMap((group$) => {\n return group$.pipe(\n //\n scan((acc, cur) => Object.assign(acc, cur), {} as Partial<IQuote>),\n );\n }),\n share(),\n);\n\n// 合并不同来源的数据并进行合并,避免死锁\nif (process.env.WRITE_QUOTE_TO_SQL === 'true') {\n terminal.channel.publishChannel('quote', { pattern: `^OKX/` }, (channel_id) => {\n const [datasource_id, product_id] = decodePath(channel_id);\n if (!datasource_id) {\n throw 'datasource_id is required';\n }\n if (!product_id) {\n throw 'product_id is required';\n }\n return quote$.pipe(filter((x) => x.product_id === product_id));\n });\n\n quote$\n .pipe(\n writeToSQL({\n terminal,\n writeInterval: 1000,\n tableName: 'quote',\n conflictKeys: ['datasource_id', 'product_id'],\n }),\n )\n .subscribe();\n}\n\nexport const swapOpenInterest$ = defer(() => swapOpenInterests$).pipe(\n map((x) => new Map(x.data.map((x) => [x.instId, +x.oi] as const))),\n shareReplay(1),\n);\n"]}
1
+ {"version":3,"file":"new-quote.js","sourceRoot":"","sources":["../../src/public-data/new-quote.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAC5C,qCAAyC;AACzC,yCAA8E;AAC9E,+BAuBc;AACd,kDAM2B;AAC3B,8BAAmD;AAEnD,MAAM,QAAQ,GAAG,mBAAQ,CAAC,WAAW,EAAE,CAAC;AAExC,MAAM,gBAAgB,GAAG,IAAA,YAAK,EAAC,GAAG,EAAE,CAAC,IAAA,2BAAc,EAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAC7E,IAAA,aAAM,EAAC,EAAE,KAAK,EAAE,OAAQ,EAAE,CAAC,EAC3B,IAAA,YAAK,EAAC,EAAE,KAAK,EAAE,KAAM,EAAE,CAAC,EACxB,IAAA,UAAG,EAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAClB,IAAA,kBAAW,EAAC,CAAC,CAAC,CACf,CAAC;AACF,MAAM,gBAAgB,GAAG,IAAA,YAAK,EAAC,GAAG,EAAE,CAAC,IAAA,2BAAc,EAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAC7E,IAAA,aAAM,EAAC,EAAE,KAAK,EAAE,OAAQ,EAAE,CAAC,EAC3B,IAAA,YAAK,EAAC,EAAE,KAAK,EAAE,KAAM,EAAE,CAAC,EACxB,IAAA,UAAG,EAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAClB,IAAA,kBAAW,EAAC,CAAC,CAAC,CACf,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,CAAW,EAAE,CAAW,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAE1G,MAAM,YAAY,GAAG,gBAAgB,CAAC,IAAI,CACxC,IAAA,UAAG,EAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAChD,IAAA,2BAAoB,EAAC,YAAY,CAAC,EAClC,IAAA,kBAAW,EAAC,CAAC,CAAC,CACf,CAAC;AAEF,MAAM,YAAY,GAAG,IAAA,YAAK,EAAC,GAAG,EAAE,CAAC,IAAA,6BAAgB,EAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAC3E,IAAA,aAAM,EAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EACvB,IAAA,YAAK,EAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EACtB,IAAA,kBAAW,EAAC,CAAC,CAAC,CACf,CAAC;AAEF,yBAAyB;AACZ,QAAA,kBAAkB,GAAG,IAAA,YAAK,EAAC,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC,IAAI,CAC9D,IAAA,eAAQ,EAAC,CAAC,CAAC,EAAE,EAAE,CACb,IAAA,WAAI,EAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CACf,IAAA,UAAG,EAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAU,CAAC,EAClC,IAAA,cAAO,GAAE,EACT,IAAA,UAAG,EAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAClC,CACF,EACD,IAAA,aAAM,EAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EACvB,IAAA,YAAK,EAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EACtB,IAAA,kBAAW,EAAC,CAAC,CAAC,CACf,CAAC;AAEF,MAAM,WAAW,GAAG,gBAAgB,CAAC,IAAI,CACvC,IAAA,UAAG,EAAC,CAAC,CAAC,EAAE,EAAE;IACR,OAAO,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;AAC7C,CAAC,CAAC,EACF,IAAA,iBAAS,EACP,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,EACf,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,cAAS,EAAC,CAAC,CAAC,MAAM,CAAC,EAC1B,GAAG,EAAE,CAAC,IAAI,CACX,EACD,IAAA,YAAK,GAAE,CACR,CAAC;AAEF,MAAM,oBAAoB,GAAG,IAAA,YAAK,EAAC,GAAG,EAAE,CAAC,IAAA,6BAAgB,EAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CACnF,IAAA,eAAQ,EAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,EAC7B,IAAA,UAAG,EACD,CAAC,CAAC,EAAmB,EAAE,CAAC,CAAC;IACvB,aAAa,EAAE,KAAK;IACpB,UAAU,EAAE,IAAA,kBAAU,EAAC,KAAK,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC;IACnD,UAAU,EAAE,CAAC,CAAC,IAAI;IAClB,SAAS,EAAE,CAAC,CAAC,KAAK;IAClB,SAAS,EAAE,CAAC,CAAC,KAAK;IAClB,UAAU,EAAE,CAAC,CAAC,KAAK;IACnB,UAAU,EAAE,CAAC,CAAC,KAAK;CACpB,CAAC,CACH,EACD,IAAA,aAAM,EAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EACvB,IAAA,YAAK,EAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CACvB,CAAC;AAEF,MAAM,6BAA6B,GAAG,IAAA,YAAK,EAAC,GAAG,EAAE,CAAC,IAAA,6BAAgB,EAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAC5F,IAAA,eAAQ,EAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,EAC7B,IAAA,eAAQ,EAAC,CAAC,CAAC,EAAqB,EAAE,CAAC;IACjC;QACE,aAAa,EAAE,KAAK;QACpB,UAAU,EAAE,IAAA,kBAAU,EAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QAC/C,UAAU,EAAE,CAAC,CAAC,IAAI;QAClB,SAAS,EAAE,CAAC,CAAC,KAAK;QAClB,SAAS,EAAE,CAAC,CAAC,KAAK;QAClB,UAAU,EAAE,CAAC,CAAC,KAAK;QACnB,UAAU,EAAE,CAAC,CAAC,KAAK;KACpB;IACD;QACE,aAAa,EAAE,KAAK;QACpB,UAAU,EAAE,IAAA,kBAAU,EAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC;QACjD,UAAU,EAAE,CAAC,CAAC,IAAI;QAClB,SAAS,EAAE,CAAC,CAAC,KAAK;QAClB,SAAS,EAAE,CAAC,CAAC,KAAK;QAClB,UAAU,EAAE,CAAC,CAAC,KAAK;QACnB,UAAU,EAAE,CAAC,CAAC,KAAK;KACpB;CACF,CAAC,EACF,IAAA,aAAM,EAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EACvB,IAAA,YAAK,EAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CACvB,CAAC;AAEF,MAAM,kBAAkB,GAAG,gBAAgB,CAAC,IAAI,CAC9C,IAAA,iBAAS,EACP,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,EACf,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,cAAS,EAAC,CAAC,CAAC,MAAM,CAAC,EAC1B,GAAG,EAAE,CAAC,IAAI,CACX,EACD,IAAA,UAAG,EACD,CAAC,MAAM,EAAmB,EAAE,CAAC,CAAC;IAC5B,aAAa,EAAE,KAAK;IACpB,UAAU,EAAE,IAAA,kBAAU,EAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACvD,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI;IAC1B,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;IAC1B,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;IAC1B,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;IAC3B,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;CAC5B,CAAC,CACH,CACF,CAAC;AAEF,MAAM,2BAA2B,GAAG,WAAW,CAAC,IAAI,CAClD,IAAA,eAAQ,EAAC,CAAC,MAAM,EAAqB,EAAE,CAAC;IACtC;QACE,aAAa,EAAE,KAAK;QACpB,UAAU,EAAE,IAAA,kBAAU,EAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QACvD,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI;QAC1B,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;QAC1B,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;QAC1B,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;QAC3B,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;KAC5B;IACD;QACE,aAAa,EAAE,KAAK;QACpB,UAAU,EAAE,IAAA,kBAAU,EAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QACzD,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI;QAC1B,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;QAC1B,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;QAC1B,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;QAC3B,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;KAC5B;CACF,CAAC,CACH,CAAC;AAEF,MAAM,kBAAkB,GAAG,IAAA,YAAK,EAAC,GAAG,EAAE,CAAC,IAAA,4BAAe,EAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAChF,IAAA,aAAM,EAAC,EAAE,KAAK,EAAE,KAAM,EAAE,CAAC,EACzB,IAAA,YAAK,EAAC,EAAE,KAAK,EAAE,KAAM,EAAE,CAAC,EACxB,IAAA,kBAAW,EAAC,CAAC,CAAC,CACf,CAAC;AAEF,MAAM,yBAAyB,GAAG,gBAAgB,CAAC,IAAI,CACrD,IAAA,iBAAS,EACP,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,EACf,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,oBAAe,EAAC,CAAC,CAAC,MAAM,CAAC,EAChC,GAAG,EAAE,CAAC,IAAI,CACX,EACD,IAAA,UAAG,EACD,CAAC,CAAC,EAAmB,EAAE,CAAC,CAAC;IACvB,aAAa,EAAE,KAAK;IACpB,UAAU,EAAE,IAAA,kBAAU,EAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAClD,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;CACvB,CAAC,CACH,EACD,IAAA,YAAK,GAAE,CACR,CAAC;AAuBF,MAAM,uBAAuB,GAAG,IAAA,YAAK,EAAC,GAAG,EAAE,CACzC,YAAY,CAAC,IAAI,CACf,IAAA,YAAK,GAAE,EACP,IAAA,UAAG,EAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EACpF,IAAA,gBAAS,EAAC,CAAC,OAAO,EAAE,EAAE;IACpB,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC;IAC7B,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,OAAO,IAAA,WAAI,EAAC,OAAO,CAAC,CAAC,IAAI,CACvB,IAAA,gBAAS,EAAC,CAAC,MAAM,EAAE,EAAE,CACnB,IAAA,YAAK,EAAC,KAAK,IAAI,EAAE;QACf,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CAGxD,mBAAmB,EAAE;YACrB,QAAQ,EAAE,QAAQ;YAClB,MAAM,EAAE,OAAO;YACf,MAAM;SACP,CAAC,CAAC;QACH,IAAI,CAAC,CAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,IAAI,CAAA,EAAE;YAChB,MAAM,IAAI,KAAK,CAAC,qCAAqC,MAAM,KAAK,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;SAC9E;QACD,OAAO;YACL,MAAM;YACN,KAAK;SACN,CAAC;IACJ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAA,YAAK,EAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAChC,EACD,IAAA,aAAM,EAAC,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE;QAChC,SAAS,IAAI,CAAC,CAAC;QACf,OAAO,CAAC,IAAI,CACV,IAAA,kBAAU,EAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EACtB,gCAAgC,SAAS,IAAI,KAAK,KAAK,MAAM,GAAG,CACjE,CAAC;QACF,IAAI,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,IAAI,EAAE;YACf,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;SAC7B;QACD,OAAO,GAAG,CAAC;IACb,CAAC,EAAE,IAAI,GAAG,EAA8B,CAAC,CAC1C,CAAC;AACJ,CAAC,CAAC,CACH,CACF,CAAC,IAAI;AACJ,EAAE;AACF,IAAA,YAAK,EAAC,EAAE,KAAK,EAAE,KAAM,EAAE,CAAC,EACxB,IAAA,aAAM,EAAC,EAAE,KAAK,EAAE,QAAS,EAAE,CAAC,EAC5B,IAAA,kBAAW,EAAC,CAAC,CAAC,CACf,CAAC;AAEF,4CAA4C;AAC5C,oCAAoC;AACpC,2BAA2B;AAC3B,kEAAkE;AAClE,wCAAwC;AACxC,MAAM,mBAAmB,GAAG,YAAY,CAAC,IAAI,CAC3C,IAAA,eAAQ,EAAC,CAAC,OAAO,EAAE,EAAE,CACnB,IAAA,WAAI,EAAC,OAAO,CAAC,CAAC,IAAI,CAChB,IAAA,eAAQ,EAAC,CAAC,MAAM,EAAE,EAAE,CAClB,IAAA,YAAK,EAAC,KAAK,IAAI,EAAE;;IACf,MAAM,QAAQ,GAAG,MAAM,IAAA,qBAAc,EAAC,uBAAuB,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACnC,IAAI,CAAC,CAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,MAAM,CAAA,EAAE;QAClB,OAAO,IAAI,CAAC;KACb;IAED,MAAM,WAAW,GAAG,KAAK;SACtB,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC;SACxD,MAAM,CAAC,CAAC,iBAAiB,EAAE,QAAQ,EAAE,EAAE;QACtC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACtD,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,QAAQ,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE;YACxD,iBAAiB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;SAChD;QACD,OAAO,iBAAiB,CAAC;IAC3B,CAAC,EAAE,IAAI,GAAG,EAAkC,CAAC,CAAC;IAChD,sBAAsB;IACtB,MAAM,YAAY,GAAG,CAAC,CAAC,CAAA,MAAA,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,0CAAE,YAAY,KAAI,CAAC,CAAC,CAAC;IAEhE,OAAO;QACL,MAAM;QACN,YAAY;KACb,CAAC;AACJ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAA,YAAK,EAAC,EAAE,KAAK,EAAE,KAAM,EAAE,CAAC,EAAE,IAAA,aAAM,EAAC,EAAE,KAAK,EAAE,KAAM,EAAE,CAAC,CAAC,CAC7D,CACF,CACF,EACD,IAAA,aAAM,EAAC,CAAC,MAAM,EAAsD,EAAE,CAAC,MAAM,KAAK,IAAI,CAAC,EACvF,IAAA,UAAG,EAAC,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,EAAE;IAC/B,MAAM,OAAO,GAAoB;QAC/B,aAAa,EAAE,KAAK;QACpB,UAAU,EAAE,IAAA,kBAAU,EAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC;KAChD,CAAC;IACF,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE;QACrE,OAAO,CAAC,aAAa,GAAG,GAAG,YAAY,EAAE,CAAC;KAC3C;IACD,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC,EACF,IAAA,YAAK,GAAE,CACR,CAAC;AAEF,MAAM,YAAY,GAAG,IAAA,YAAK,EAAC,GAAG,EAAE,CAAC,IAAA,2BAAc,EAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CACtE,IAAA,UAAG,EAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EACxB,IAAA,aAAM,EAAC,EAAE,KAAK,EAAE,KAAM,EAAE,CAAC,EACzB,IAAA,YAAK,EAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EACtB,IAAA,kBAAW,EAAC,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAC/C,CAAC;AAEF,4CAA4C;AAC5C,MAAM,mBAAmB,GAAG,YAAY,CAAC,IAAI,CAC3C,IAAA,eAAQ,EAAC,CAAC,gBAAgB,EAAE,EAAE,CAAC,gBAAgB,CAAC,EAChD,IAAA,UAAG,EACD,CAAC,WAAW,EAAmB,EAAE,CAAC,CAAC;IACjC,aAAa,EAAE,KAAK;IACpB,UAAU,EAAE,IAAA,kBAAU,EAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC;IACzD,kBAAkB,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS;IACxF,mBAAmB,EAAE,WAAW,CAAC,WAAW;IAC5C,6BAA6B,EAAE,IAAA,kBAAU,EAAC,CAAC,WAAW,CAAC,WAAW,CAAC;CACpE,CAAC,CACH,CACF,CAAC;AAEF,MAAM,aAAa,GAAG;IACpB,kBAAkB;IAClB,yBAAyB;IACzB,oBAAoB;IACpB,2BAA2B;IAC3B,6BAA6B;IAC7B,mBAAmB;IACnB,mBAAmB;CACpB,CAAC;AAEF,MAAM,MAAM,GAAG,IAAA,YAAK,EAAC,GAAG,EAAE,CACxB,IAAA,YAAK,EACH,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAC1B,IAAA,YAAK,EAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI;AAClB,gBAAgB;AAChB,IAAA,iBAAU,EAAC,GAAG,EAAE,CAAC,YAAK,CAAC,CACxB,CACF,CACF,CACF,CAAC,IAAI,CACJ,IAAA,cAAO,EAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,kBAAU,EAAC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,EACzD,IAAA,eAAQ,EAAC,CAAC,MAAM,EAAE,EAAE;IAClB,OAAO,MAAM,CAAC,IAAI;IAChB,EAAE;IACF,IAAA,WAAI,EAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAqB,CAAC,CACnE,CAAC;AACJ,CAAC,CAAC,EACF,IAAA,YAAK,GAAE,CACR,CAAC;AAEF,sBAAsB;AACtB,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,MAAM,EAAE;IAC7C,QAAQ,CAAC,OAAO,CAAC,cAAc,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,UAAU,EAAE,EAAE;QAC5E,MAAM,CAAC,aAAa,EAAE,UAAU,CAAC,GAAG,IAAA,kBAAU,EAAC,UAAU,CAAC,CAAC;QAC3D,IAAI,CAAC,aAAa,EAAE;YAClB,MAAM,2BAA2B,CAAC;SACnC;QACD,IAAI,CAAC,UAAU,EAAE;YACf,MAAM,wBAAwB,CAAC;SAChC;QACD,OAAO,MAAM,CAAC,IAAI,CAAC,IAAA,aAAM,EAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,MAAM;SACH,IAAI,CACH,IAAA,gBAAU,EAAC;QACT,QAAQ;QACR,aAAa,EAAE,IAAI;QACnB,SAAS,EAAE,OAAO;QAClB,YAAY,EAAE,CAAC,eAAe,EAAE,YAAY,CAAC;KAC9C,CAAC,CACH;SACA,SAAS,EAAE,CAAC;CAChB;AAEY,QAAA,iBAAiB,GAAG,IAAA,YAAK,EAAC,GAAG,EAAE,CAAC,kBAAkB,CAAC,CAAC,IAAI,CACnE,IAAA,UAAG,EAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAU,CAAC,CAAC,CAAC,EAClE,IAAA,kBAAW,EAAC,CAAC,CAAC,CACf,CAAC;AAEF,MAAM;KACH,IAAI,CACH,IAAA,UAAG,EAAC,CAAC,KAAK,EAAE,EAAE;IACZ,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACrB,CAAC,CAAC,CACH;KACA,SAAS,EAAE,CAAC","sourcesContent":["import { IQuote } from '@yuants/data-quote';\nimport { Terminal } from '@yuants/protocol';\nimport { writeToSQL } from '@yuants/sql';\nimport { decodePath, encodePath, formatTime, listWatch } from '@yuants/utils';\nimport {\n catchError,\n concatMap,\n defer,\n distinctUntilChanged,\n EMPTY,\n filter,\n first,\n firstValueFrom,\n from,\n groupBy,\n map,\n merge,\n mergeMap,\n reduce,\n repeat,\n retry,\n scan,\n share,\n shareReplay,\n switchMap,\n tap,\n toArray,\n} from 'rxjs';\nimport {\n getFundingRate,\n getInstruments,\n getMarketTickers,\n getOpenInterest,\n getPositionTiers,\n} from '../api/public-api';\nimport { useOpenInterest, useTicker } from '../ws';\n\nconst terminal = Terminal.fromNodeEnv();\n\nconst swapInstruments$ = defer(() => getInstruments({ instType: 'SWAP' })).pipe(\n repeat({ delay: 3600_000 }),\n retry({ delay: 10_000 }),\n map((x) => x.data),\n shareReplay(1),\n);\nconst spotInstruments$ = defer(() => getInstruments({ instType: 'SPOT' })).pipe(\n repeat({ delay: 3600_000 }),\n retry({ delay: 10_000 }),\n map((x) => x.data),\n shareReplay(1),\n);\n\nconst shallowEqual = (a: string[], b: string[]) => a.length === b.length && a.every((v, i) => v === b[i]);\n\nconst spotInstIds$ = spotInstruments$.pipe(\n map((items) => items.map((item) => item.instId)),\n distinctUntilChanged(shallowEqual),\n shareReplay(1),\n);\n\nconst spotTickers$ = defer(() => getMarketTickers({ instType: 'SPOT' })).pipe(\n repeat({ delay: 5000 }),\n retry({ delay: 5000 }),\n shareReplay(1),\n);\n\n// depend by SubmitOrders\nexport const spotMarketTickers$ = defer(() => spotTickers$).pipe(\n mergeMap((x) =>\n from(x.data).pipe(\n map((x) => [x.instId, x] as const),\n toArray(),\n map((x) => Object.fromEntries(x)),\n ),\n ),\n repeat({ delay: 5000 }),\n retry({ delay: 5000 }),\n shareReplay(1),\n);\n\nconst spotTicker$ = spotInstruments$.pipe(\n tap((x) => {\n console.info('SPOT INSTRUMENTS', x.length);\n }),\n listWatch(\n (x) => x.instId,\n (x) => useTicker(x.instId),\n () => true,\n ),\n share(),\n);\n\nconst quoteOfSwapFromRest$ = defer(() => getMarketTickers({ instType: 'SWAP' })).pipe(\n mergeMap((x) => x.data || []),\n map(\n (x): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('OKX', x.instType, x.instId),\n last_price: x.last,\n ask_price: x.askPx,\n bid_price: x.bidPx,\n ask_volume: x.askSz,\n bid_volume: x.bidSz,\n }),\n ),\n repeat({ delay: 1000 }),\n retry({ delay: 1000 }),\n);\n\nconst quoteOfSpotAndMarginFromRest$ = defer(() => getMarketTickers({ instType: 'SPOT' })).pipe(\n mergeMap((x) => x.data || []),\n mergeMap((x): Partial<IQuote>[] => [\n {\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'SPOT', x.instId),\n last_price: x.last,\n ask_price: x.askPx,\n bid_price: x.bidPx,\n ask_volume: x.askSz,\n bid_volume: x.bidSz,\n },\n {\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'MARGIN', x.instId),\n last_price: x.last,\n ask_price: x.askPx,\n bid_price: x.bidPx,\n ask_volume: x.askSz,\n bid_volume: x.bidSz,\n },\n ]),\n repeat({ delay: 1000 }),\n retry({ delay: 1000 }),\n);\n\nconst quoteOfSwapFromWs$ = swapInstruments$.pipe(\n listWatch(\n (x) => x.instId,\n (x) => useTicker(x.instId),\n () => true,\n ),\n map(\n (ticker): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'SWAP', ticker[0].instId),\n last_price: ticker[0].last,\n ask_price: ticker[0].askPx,\n bid_price: ticker[0].bidPx,\n ask_volume: ticker[0].askSz,\n bid_volume: ticker[0].bidSz,\n }),\n ),\n);\n\nconst quoteOfSpotAndMarginFromWs$ = spotTicker$.pipe(\n mergeMap((ticker): Partial<IQuote>[] => [\n {\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'SPOT', ticker[0].instId),\n last_price: ticker[0].last,\n ask_price: ticker[0].askPx,\n bid_price: ticker[0].bidPx,\n ask_volume: ticker[0].askSz,\n bid_volume: ticker[0].bidSz,\n },\n {\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'MARGIN', ticker[0].instId),\n last_price: ticker[0].last,\n ask_price: ticker[0].askPx,\n bid_price: ticker[0].bidPx,\n ask_volume: ticker[0].askSz,\n bid_volume: ticker[0].bidSz,\n },\n ]),\n);\n\nconst swapOpenInterests$ = defer(() => getOpenInterest({ instType: 'SWAP' })).pipe(\n repeat({ delay: 10_000 }),\n retry({ delay: 10_000 }),\n shareReplay(1),\n);\n\nconst openInterestOfSwapFromWS$ = swapInstruments$.pipe(\n listWatch(\n (x) => x.instId,\n (x) => useOpenInterest(x.instId),\n () => true,\n ),\n map(\n (x): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'SWAP', x[0].instId),\n open_interest: x[0].oi,\n }),\n ),\n share(),\n);\n\n// const interestRateOfSwapFromWS$ = swapInstruments$.pipe(\n// listWatch(\n// (x) => x.instId,\n// (x) => useFundingRate(x.instId),\n// () => true,\n// ),\n// map(\n// (x): Partial<IQuote> => ({\n// datasource_id: 'OKX',\n// product_id: encodePath('OKX', 'SWAP', x[0].instId),\n// interest_rate_long: `-${x[0].fundingRate}`,\n// interest_rate_short: x[0].fundingRate,\n// interest_rate_next_settled_at: x[0].fundingTime,\n// }),\n// ),\n// share(),\n// );\n\ntype PositionTiersResponse = Awaited<ReturnType<typeof getPositionTiers>>;\ntype PositionTiersEntry = PositionTiersResponse['data'];\n\nconst marginPositionTiersMap$ = defer(() =>\n spotInstIds$.pipe(\n first(),\n map((instIds) => instIds.filter((id) => id.endsWith('USDT') || id.endsWith('USDC'))),\n switchMap((instIds) => {\n const total = instIds.length;\n let processed = 0;\n return from(instIds).pipe(\n concatMap((instId) =>\n defer(async () => {\n const tiers = await terminal.client.requestForResponseData<\n { instType: string; tdMode: string; instId: string },\n PositionTiersResponse\n >('OKX/PositionTiers', {\n instType: 'MARGIN',\n tdMode: 'cross',\n instId,\n });\n if (!tiers?.data) {\n throw new Error(`Failed to load position tiers for ${instId}: ${tiers.msg}`);\n }\n return {\n instId,\n tiers,\n };\n }).pipe(retry({ delay: 2000 })),\n ),\n reduce((map, { instId, tiers }) => {\n processed += 1;\n console.info(\n formatTime(Date.now()),\n `Loaded margin position tiers ${processed}/${total} (${instId})`,\n );\n if (tiers?.data) {\n map.set(instId, tiers.data);\n }\n return map;\n }, new Map<string, PositionTiersEntry>()),\n );\n }),\n ),\n).pipe(\n //\n retry({ delay: 60_000 }),\n repeat({ delay: 86400_000 }),\n shareReplay(1),\n);\n\n// Margin 的 open interest 只依赖 position-tier:\n// 1) 启动时先拉全量 MARGIN 仓位档位并缓存,下次直接命中;\n// 2) 档位内只保留同 tier 杠杆最高的记录;\n// 3) 当前策略只使用 tier=1 的 quoteMaxLoan 作为持仓上限,不再混合 /account/max-size;\n// 4) 每个 instId 60 秒刷新一次,并在接口报错时 10 秒重试。\nconst marginOpenInterest$ = spotInstIds$.pipe(\n mergeMap((instIds) =>\n from(instIds).pipe(\n mergeMap((instId) =>\n defer(async () => {\n const tiersMap = await firstValueFrom(marginPositionTiersMap$);\n const tiers = tiersMap.get(instId);\n if (!tiers?.length) {\n return null;\n }\n\n const tierByLevel = tiers\n .filter((tier) => !tier.instId || tier.instId === instId)\n .reduce((mapTierToTierInfo, tierInfo) => {\n const existing = mapTierToTierInfo.get(tierInfo.tier);\n if (!existing || +tierInfo.maxLever > +existing.maxLever) {\n mapTierToTierInfo.set(tierInfo.tier, tierInfo);\n }\n return mapTierToTierInfo;\n }, new Map<string, (typeof tiers)[number]>());\n // 获取一级杠杆的最大可借贷额度作为持仓量\n const openInterest = +(tierByLevel.get('1')?.quoteMaxLoan || 0);\n\n return {\n instId,\n openInterest,\n };\n }).pipe(retry({ delay: 10_000 }), repeat({ delay: 60_000 })),\n ),\n ),\n ),\n filter((result): result is { instId: string; openInterest: number } => result !== null),\n map(({ instId, openInterest }) => {\n const partial: Partial<IQuote> = {\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'MARGIN', instId),\n };\n if (typeof openInterest === 'number' && Number.isFinite(openInterest)) {\n partial.open_interest = `${openInterest}`;\n }\n return partial;\n }),\n share(),\n);\n\nconst fundingRate$ = defer(() => getFundingRate({ instId: 'ANY' })).pipe(\n map((data) => data.data),\n repeat({ delay: 50_000 }),\n retry({ delay: 5000 }),\n shareReplay({ bufferSize: 1, refCount: true }),\n);\n\n// Convert funding rate data to quote format\nconst interestRateOfSwap$ = fundingRate$.pipe(\n mergeMap((premiumDataArray) => premiumDataArray),\n map(\n (premiumData): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('OKX', 'SWAP', premiumData.instId),\n interest_rate_long: premiumData.fundingRate ? `${-+premiumData.fundingRate}` : undefined,\n interest_rate_short: premiumData.fundingRate,\n interest_rate_next_settled_at: formatTime(+premiumData.fundingTime),\n }),\n ),\n);\n\nconst quoteSources$ = [\n quoteOfSwapFromWs$,\n openInterestOfSwapFromWS$,\n quoteOfSwapFromRest$,\n quoteOfSpotAndMarginFromWs$,\n quoteOfSpotAndMarginFromRest$,\n marginOpenInterest$,\n interestRateOfSwap$,\n];\n\nconst quote$ = defer(() =>\n merge(\n ...quoteSources$.map((x$) =>\n defer(() => x$).pipe(\n // 防止单个流关闭导致整体关闭\n catchError(() => EMPTY),\n ),\n ),\n ),\n).pipe(\n groupBy((x) => encodePath(x.datasource_id, x.product_id)),\n mergeMap((group$) => {\n return group$.pipe(\n //\n scan((acc, cur) => Object.assign(acc, cur), {} as Partial<IQuote>),\n );\n }),\n share(),\n);\n\n// 合并不同来源的数据并进行合并,避免死锁\nif (process.env.WRITE_QUOTE_TO_SQL === 'true') {\n terminal.channel.publishChannel('quote', { pattern: `^OKX/` }, (channel_id) => {\n const [datasource_id, product_id] = decodePath(channel_id);\n if (!datasource_id) {\n throw 'datasource_id is required';\n }\n if (!product_id) {\n throw 'product_id is required';\n }\n return quote$.pipe(filter((x) => x.product_id === product_id));\n });\n\n quote$\n .pipe(\n writeToSQL({\n terminal,\n writeInterval: 1000,\n tableName: 'quote',\n conflictKeys: ['datasource_id', 'product_id'],\n }),\n )\n .subscribe();\n}\n\nexport const swapOpenInterest$ = defer(() => swapOpenInterests$).pipe(\n map((x) => new Map(x.data.map((x) => [x.instId, +x.oi] as const))),\n shareReplay(1),\n);\n\nquote$\n .pipe(\n tap((quote) => {\n console.log(quote);\n }),\n )\n .subscribe();\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"quote.d.ts","sourceRoot":"","sources":["../../src/public-data/quote.ts"],"names":[],"mappings":"AA6DA,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;EAW9B,CAAC;AAySF,eAAO,MAAM,iBAAiB,gDAG7B,CAAC"}
1
+ {"version":3,"file":"quote.d.ts","sourceRoot":"","sources":["../../src/public-data/quote.ts"],"names":[],"mappings":"AA6DA,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;EAW9B,CAAC;AAoRF,eAAO,MAAM,iBAAiB,gDAG7B,CAAC"}
@@ -82,13 +82,6 @@ const openInterestOfSwapFromWS$ = swapInstruments$.pipe((0, utils_1.listWatch)((
82
82
  product_id: (0, utils_1.encodePath)('SWAP', x[0].instId),
83
83
  open_interest: x[0].oi,
84
84
  })), (0, rxjs_1.share)());
85
- const interestRateOfSwapFromWS$ = swapInstruments$.pipe((0, utils_1.listWatch)((x) => x.instId, (x) => (0, ws_1.useFundingRate)(x.instId), () => true), (0, rxjs_1.map)((x) => ({
86
- datasource_id: 'OKX',
87
- product_id: (0, utils_1.encodePath)('SWAP', x[0].instId),
88
- interest_rate_long: `-${x[0].fundingRate}`,
89
- interest_rate_short: x[0].fundingRate,
90
- interest_rate_next_settled_at: x[0].fundingTime,
91
- })), (0, rxjs_1.share)());
92
85
  const marginPositionTiersMap$ = (0, rxjs_1.defer)(() => spotInstIds$.pipe((0, rxjs_1.first)(), (0, rxjs_1.map)((instIds) => instIds.filter((id) => id.endsWith('USDT') || id.endsWith('USDC'))), (0, rxjs_1.switchMap)((instIds) => {
93
86
  const total = instIds.length;
94
87
  let processed = 0;
@@ -153,7 +146,6 @@ const marginOpenInterest$ = spotInstIds$.pipe((0, rxjs_1.mergeMap)((instIds) =>
153
146
  }
154
147
  return partial;
155
148
  }), (0, rxjs_1.share)());
156
- marginOpenInterest$.subscribe();
157
149
  const quoteSources$ = [
158
150
  quoteOfSwapFromWs$,
159
151
  openInterestOfSwapFromWS$,
@@ -161,7 +153,6 @@ const quoteSources$ = [
161
153
  quoteOfSpotAndMarginFromWs$,
162
154
  quoteOfSpotAndMarginFromRest$,
163
155
  marginOpenInterest$,
164
- interestRateOfSwapFromWS$,
165
156
  ];
166
157
  const quote$ = (0, rxjs_1.defer)(() => (0, rxjs_1.merge)(...quoteSources$.map((x$) => (0, rxjs_1.defer)(() => x$).pipe(
167
158
  // 防止单个流关闭导致整体关闭
@@ -1 +1 @@
1
- {"version":3,"file":"quote.js","sourceRoot":"","sources":["../../src/public-data/quote.ts"],"names":[],"mappings":"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","sourcesContent":["import { IQuote } from '@yuants/data-quote';\nimport { Terminal } from '@yuants/protocol';\nimport { writeToSQL } from '@yuants/sql';\nimport { decodePath, encodePath, formatTime, listWatch } from '@yuants/utils';\nimport {\n catchError,\n concatMap,\n defer,\n distinctUntilChanged,\n EMPTY,\n filter,\n first,\n firstValueFrom,\n from,\n groupBy,\n map,\n merge,\n mergeMap,\n reduce,\n repeat,\n retry,\n scan,\n share,\n shareReplay,\n switchMap,\n tap,\n toArray,\n} from 'rxjs';\nimport { getInstruments, getMarketTickers, getOpenInterest, getPositionTiers } from '../api/public-api';\nimport { useFundingRate, useOpenInterest, useTicker } from '../ws';\n\nconst terminal = Terminal.fromNodeEnv();\n\nconst swapInstruments$ = defer(() => getInstruments({ instType: 'SWAP' })).pipe(\n repeat({ delay: 3600_000 }),\n retry({ delay: 10_000 }),\n map((x) => x.data),\n shareReplay(1),\n);\nconst spotInstruments$ = defer(() => getInstruments({ instType: 'SPOT' })).pipe(\n repeat({ delay: 3600_000 }),\n retry({ delay: 10_000 }),\n map((x) => x.data),\n shareReplay(1),\n);\n\nconst shallowEqual = (a: string[], b: string[]) => a.length === b.length && a.every((v, i) => v === b[i]);\n\nconst spotInstIds$ = spotInstruments$.pipe(\n map((items) => items.map((item) => item.instId)),\n distinctUntilChanged(shallowEqual),\n shareReplay(1),\n);\n\nconst spotTickers$ = defer(() => getMarketTickers({ instType: 'SPOT' })).pipe(\n repeat({ delay: 5000 }),\n retry({ delay: 5000 }),\n shareReplay(1),\n);\n\n// depend by SubmitOrders\nexport const spotMarketTickers$ = defer(() => spotTickers$).pipe(\n mergeMap((x) =>\n from(x.data).pipe(\n map((x) => [x.instId, x] as const),\n toArray(),\n map((x) => Object.fromEntries(x)),\n ),\n ),\n repeat({ delay: 5000 }),\n retry({ delay: 5000 }),\n shareReplay(1),\n);\n\nconst spotTicker$ = spotInstruments$.pipe(\n tap((x) => {\n console.info('SPOT INSTRUMENTS', x.length);\n }),\n listWatch(\n (x) => x.instId,\n (x) => useTicker(x.instId),\n () => true,\n ),\n share(),\n);\n\nconst quoteOfSwapFromRest$ = defer(() => getMarketTickers({ instType: 'SWAP' })).pipe(\n mergeMap((x) => x.data || []),\n map(\n (x): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath(x.instType, x.instId),\n last_price: x.last,\n ask_price: x.askPx,\n bid_price: x.bidPx,\n ask_volume: x.askSz,\n bid_volume: x.bidSz,\n }),\n ),\n repeat({ delay: 1000 }),\n retry({ delay: 1000 }),\n);\n\nconst quoteOfSpotAndMarginFromRest$ = defer(() => getMarketTickers({ instType: 'SPOT' })).pipe(\n mergeMap((x) => x.data || []),\n mergeMap((x): Partial<IQuote>[] => [\n {\n datasource_id: 'OKX',\n product_id: encodePath('SPOT', x.instId),\n last_price: x.last,\n ask_price: x.askPx,\n bid_price: x.bidPx,\n ask_volume: x.askSz,\n bid_volume: x.bidSz,\n },\n {\n datasource_id: 'OKX',\n product_id: encodePath('MARGIN', x.instId),\n last_price: x.last,\n ask_price: x.askPx,\n bid_price: x.bidPx,\n ask_volume: x.askSz,\n bid_volume: x.bidSz,\n },\n ]),\n repeat({ delay: 1000 }),\n retry({ delay: 1000 }),\n);\n\nconst quoteOfSwapFromWs$ = swapInstruments$.pipe(\n listWatch(\n (x) => x.instId,\n (x) => useTicker(x.instId),\n () => true,\n ),\n map(\n (ticker): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('SWAP', ticker[0].instId),\n last_price: ticker[0].last,\n ask_price: ticker[0].askPx,\n bid_price: ticker[0].bidPx,\n ask_volume: ticker[0].askSz,\n bid_volume: ticker[0].bidSz,\n }),\n ),\n);\n\nconst quoteOfSpotAndMarginFromWs$ = spotTicker$.pipe(\n mergeMap((ticker): Partial<IQuote>[] => [\n {\n datasource_id: 'OKX',\n product_id: encodePath('SPOT', ticker[0].instId),\n last_price: ticker[0].last,\n ask_price: ticker[0].askPx,\n bid_price: ticker[0].bidPx,\n ask_volume: ticker[0].askSz,\n bid_volume: ticker[0].bidSz,\n },\n {\n datasource_id: 'OKX',\n product_id: encodePath('MARGIN', ticker[0].instId),\n last_price: ticker[0].last,\n ask_price: ticker[0].askPx,\n bid_price: ticker[0].bidPx,\n ask_volume: ticker[0].askSz,\n bid_volume: ticker[0].bidSz,\n },\n ]),\n);\n\nconst swapOpenInterests$ = defer(() => getOpenInterest({ instType: 'SWAP' })).pipe(\n repeat({ delay: 10_000 }),\n retry({ delay: 10_000 }),\n shareReplay(1),\n);\n\nconst openInterestOfSwapFromWS$ = swapInstruments$.pipe(\n listWatch(\n (x) => x.instId,\n (x) => useOpenInterest(x.instId),\n () => true,\n ),\n map(\n (x): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('SWAP', x[0].instId),\n open_interest: x[0].oi,\n }),\n ),\n share(),\n);\n\nconst interestRateOfSwapFromWS$ = swapInstruments$.pipe(\n listWatch(\n (x) => x.instId,\n (x) => useFundingRate(x.instId),\n () => true,\n ),\n map(\n (x): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('SWAP', x[0].instId),\n interest_rate_long: `-${x[0].fundingRate}`,\n interest_rate_short: x[0].fundingRate,\n interest_rate_next_settled_at: x[0].fundingTime,\n }),\n ),\n share(),\n);\n\ntype PositionTiersResponse = Awaited<ReturnType<typeof getPositionTiers>>;\ntype PositionTiersEntry = PositionTiersResponse['data'];\n\nconst marginPositionTiersMap$ = defer(() =>\n spotInstIds$.pipe(\n first(),\n map((instIds) => instIds.filter((id) => id.endsWith('USDT') || id.endsWith('USDC'))),\n switchMap((instIds) => {\n const total = instIds.length;\n let processed = 0;\n return from(instIds).pipe(\n concatMap((instId) =>\n defer(async () => {\n const tiers = await terminal.client.requestForResponseData<\n { instType: string; tdMode: string; instId: string },\n PositionTiersResponse\n >('OKX/PositionTiers', {\n instType: 'MARGIN',\n tdMode: 'cross',\n instId,\n });\n if (!tiers?.data) {\n throw new Error(`Failed to load position tiers for ${instId}: ${tiers.msg}`);\n }\n return {\n instId,\n tiers,\n };\n }).pipe(retry({ delay: 2000 })),\n ),\n reduce((map, { instId, tiers }) => {\n processed += 1;\n console.info(\n formatTime(Date.now()),\n `Loaded margin position tiers ${processed}/${total} (${instId})`,\n );\n if (tiers?.data) {\n map.set(instId, tiers.data);\n }\n return map;\n }, new Map<string, PositionTiersEntry>()),\n );\n }),\n ),\n).pipe(\n //\n retry({ delay: 60_000 }),\n repeat({ delay: 86400_000 }),\n shareReplay(1),\n);\n\n// Margin 的 open interest 只依赖 position-tier:\n// 1) 启动时先拉全量 MARGIN 仓位档位并缓存,下次直接命中;\n// 2) 档位内只保留同 tier 杠杆最高的记录;\n// 3) 当前策略只使用 tier=1 的 quoteMaxLoan 作为持仓上限,不再混合 /account/max-size;\n// 4) 每个 instId 60 秒刷新一次,并在接口报错时 10 秒重试。\nconst marginOpenInterest$ = spotInstIds$.pipe(\n mergeMap((instIds) =>\n from(instIds).pipe(\n mergeMap((instId) =>\n defer(async () => {\n const tiersMap = await firstValueFrom(marginPositionTiersMap$);\n const tiers = tiersMap.get(instId);\n if (!tiers?.length) {\n return null;\n }\n\n const tierByLevel = tiers\n .filter((tier) => !tier.instId || tier.instId === instId)\n .reduce((mapTierToTierInfo, tierInfo) => {\n const existing = mapTierToTierInfo.get(tierInfo.tier);\n if (!existing || +tierInfo.maxLever > +existing.maxLever) {\n mapTierToTierInfo.set(tierInfo.tier, tierInfo);\n }\n return mapTierToTierInfo;\n }, new Map<string, (typeof tiers)[number]>());\n // 获取一级杠杆的最大可借贷额度作为持仓量\n const openInterest = +(tierByLevel.get('1')?.quoteMaxLoan || 0);\n\n return {\n instId,\n openInterest,\n };\n }).pipe(retry({ delay: 10_000 }), repeat({ delay: 60_000 })),\n ),\n ),\n ),\n filter((result): result is { instId: string; openInterest: number } => result !== null),\n map(({ instId, openInterest }) => {\n const partial: Partial<IQuote> = {\n datasource_id: 'OKX',\n product_id: encodePath('MARGIN', instId),\n };\n if (typeof openInterest === 'number' && Number.isFinite(openInterest)) {\n partial.open_interest = `${openInterest}`;\n }\n return partial;\n }),\n share(),\n);\n\nmarginOpenInterest$.subscribe();\n\nconst quoteSources$ = [\n quoteOfSwapFromWs$,\n openInterestOfSwapFromWS$,\n quoteOfSwapFromRest$,\n quoteOfSpotAndMarginFromWs$,\n quoteOfSpotAndMarginFromRest$,\n marginOpenInterest$,\n interestRateOfSwapFromWS$,\n];\n\nconst quote$ = defer(() =>\n merge(\n ...quoteSources$.map((x$) =>\n defer(() => x$).pipe(\n // 防止单个流关闭导致整体关闭\n catchError(() => EMPTY),\n ),\n ),\n ),\n).pipe(\n groupBy((x) => encodePath(x.datasource_id, x.product_id)),\n mergeMap((group$) => {\n return group$.pipe(\n //\n scan((acc, cur) => Object.assign(acc, cur), {} as Partial<IQuote>),\n );\n }),\n share(),\n);\n\n// 合并不同来源的数据并进行合并,避免死锁\nif (process.env.WRITE_QUOTE_TO_SQL === 'true') {\n terminal.channel.publishChannel('quote', { pattern: `^OKX/` }, (channel_id) => {\n const [datasource_id, product_id] = decodePath(channel_id);\n if (!datasource_id) {\n throw 'datasource_id is required';\n }\n if (!product_id) {\n throw 'product_id is required';\n }\n return quote$.pipe(filter((x) => x.product_id === product_id));\n });\n\n quote$\n .pipe(\n writeToSQL({\n terminal,\n writeInterval: 1000,\n tableName: 'quote',\n conflictKeys: ['datasource_id', 'product_id'],\n }),\n )\n .subscribe();\n}\n\nexport const swapOpenInterest$ = defer(() => swapOpenInterests$).pipe(\n map((x) => new Map(x.data.map((x) => [x.instId, +x.oi] as const))),\n shareReplay(1),\n);\n"]}
1
+ {"version":3,"file":"quote.js","sourceRoot":"","sources":["../../src/public-data/quote.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAC5C,qCAAyC;AACzC,yCAA8E;AAC9E,+BAuBc;AACd,kDAAwG;AACxG,8BAAmD;AAEnD,MAAM,QAAQ,GAAG,mBAAQ,CAAC,WAAW,EAAE,CAAC;AAExC,MAAM,gBAAgB,GAAG,IAAA,YAAK,EAAC,GAAG,EAAE,CAAC,IAAA,2BAAc,EAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAC7E,IAAA,aAAM,EAAC,EAAE,KAAK,EAAE,OAAQ,EAAE,CAAC,EAC3B,IAAA,YAAK,EAAC,EAAE,KAAK,EAAE,KAAM,EAAE,CAAC,EACxB,IAAA,UAAG,EAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAClB,IAAA,kBAAW,EAAC,CAAC,CAAC,CACf,CAAC;AACF,MAAM,gBAAgB,GAAG,IAAA,YAAK,EAAC,GAAG,EAAE,CAAC,IAAA,2BAAc,EAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAC7E,IAAA,aAAM,EAAC,EAAE,KAAK,EAAE,OAAQ,EAAE,CAAC,EAC3B,IAAA,YAAK,EAAC,EAAE,KAAK,EAAE,KAAM,EAAE,CAAC,EACxB,IAAA,UAAG,EAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAClB,IAAA,kBAAW,EAAC,CAAC,CAAC,CACf,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,CAAW,EAAE,CAAW,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAE1G,MAAM,YAAY,GAAG,gBAAgB,CAAC,IAAI,CACxC,IAAA,UAAG,EAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAChD,IAAA,2BAAoB,EAAC,YAAY,CAAC,EAClC,IAAA,kBAAW,EAAC,CAAC,CAAC,CACf,CAAC;AAEF,MAAM,YAAY,GAAG,IAAA,YAAK,EAAC,GAAG,EAAE,CAAC,IAAA,6BAAgB,EAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAC3E,IAAA,aAAM,EAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EACvB,IAAA,YAAK,EAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EACtB,IAAA,kBAAW,EAAC,CAAC,CAAC,CACf,CAAC;AAEF,yBAAyB;AACZ,QAAA,kBAAkB,GAAG,IAAA,YAAK,EAAC,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC,IAAI,CAC9D,IAAA,eAAQ,EAAC,CAAC,CAAC,EAAE,EAAE,CACb,IAAA,WAAI,EAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CACf,IAAA,UAAG,EAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAU,CAAC,EAClC,IAAA,cAAO,GAAE,EACT,IAAA,UAAG,EAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAClC,CACF,EACD,IAAA,aAAM,EAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EACvB,IAAA,YAAK,EAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EACtB,IAAA,kBAAW,EAAC,CAAC,CAAC,CACf,CAAC;AAEF,MAAM,WAAW,GAAG,gBAAgB,CAAC,IAAI,CACvC,IAAA,UAAG,EAAC,CAAC,CAAC,EAAE,EAAE;IACR,OAAO,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;AAC7C,CAAC,CAAC,EACF,IAAA,iBAAS,EACP,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,EACf,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,cAAS,EAAC,CAAC,CAAC,MAAM,CAAC,EAC1B,GAAG,EAAE,CAAC,IAAI,CACX,EACD,IAAA,YAAK,GAAE,CACR,CAAC;AAEF,MAAM,oBAAoB,GAAG,IAAA,YAAK,EAAC,GAAG,EAAE,CAAC,IAAA,6BAAgB,EAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CACnF,IAAA,eAAQ,EAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,EAC7B,IAAA,UAAG,EACD,CAAC,CAAC,EAAmB,EAAE,CAAC,CAAC;IACvB,aAAa,EAAE,KAAK;IACpB,UAAU,EAAE,IAAA,kBAAU,EAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC;IAC5C,UAAU,EAAE,CAAC,CAAC,IAAI;IAClB,SAAS,EAAE,CAAC,CAAC,KAAK;IAClB,SAAS,EAAE,CAAC,CAAC,KAAK;IAClB,UAAU,EAAE,CAAC,CAAC,KAAK;IACnB,UAAU,EAAE,CAAC,CAAC,KAAK;CACpB,CAAC,CACH,EACD,IAAA,aAAM,EAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EACvB,IAAA,YAAK,EAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CACvB,CAAC;AAEF,MAAM,6BAA6B,GAAG,IAAA,YAAK,EAAC,GAAG,EAAE,CAAC,IAAA,6BAAgB,EAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAC5F,IAAA,eAAQ,EAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,EAC7B,IAAA,eAAQ,EAAC,CAAC,CAAC,EAAqB,EAAE,CAAC;IACjC;QACE,aAAa,EAAE,KAAK;QACpB,UAAU,EAAE,IAAA,kBAAU,EAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACxC,UAAU,EAAE,CAAC,CAAC,IAAI;QAClB,SAAS,EAAE,CAAC,CAAC,KAAK;QAClB,SAAS,EAAE,CAAC,CAAC,KAAK;QAClB,UAAU,EAAE,CAAC,CAAC,KAAK;QACnB,UAAU,EAAE,CAAC,CAAC,KAAK;KACpB;IACD;QACE,aAAa,EAAE,KAAK;QACpB,UAAU,EAAE,IAAA,kBAAU,EAAC,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC;QAC1C,UAAU,EAAE,CAAC,CAAC,IAAI;QAClB,SAAS,EAAE,CAAC,CAAC,KAAK;QAClB,SAAS,EAAE,CAAC,CAAC,KAAK;QAClB,UAAU,EAAE,CAAC,CAAC,KAAK;QACnB,UAAU,EAAE,CAAC,CAAC,KAAK;KACpB;CACF,CAAC,EACF,IAAA,aAAM,EAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EACvB,IAAA,YAAK,EAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CACvB,CAAC;AAEF,MAAM,kBAAkB,GAAG,gBAAgB,CAAC,IAAI,CAC9C,IAAA,iBAAS,EACP,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,EACf,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,cAAS,EAAC,CAAC,CAAC,MAAM,CAAC,EAC1B,GAAG,EAAE,CAAC,IAAI,CACX,EACD,IAAA,UAAG,EACD,CAAC,MAAM,EAAmB,EAAE,CAAC,CAAC;IAC5B,aAAa,EAAE,KAAK;IACpB,UAAU,EAAE,IAAA,kBAAU,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAChD,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI;IAC1B,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;IAC1B,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;IAC1B,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;IAC3B,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;CAC5B,CAAC,CACH,CACF,CAAC;AAEF,MAAM,2BAA2B,GAAG,WAAW,CAAC,IAAI,CAClD,IAAA,eAAQ,EAAC,CAAC,MAAM,EAAqB,EAAE,CAAC;IACtC;QACE,aAAa,EAAE,KAAK;QACpB,UAAU,EAAE,IAAA,kBAAU,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAChD,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI;QAC1B,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;QAC1B,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;QAC1B,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;QAC3B,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;KAC5B;IACD;QACE,aAAa,EAAE,KAAK;QACpB,UAAU,EAAE,IAAA,kBAAU,EAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAClD,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI;QAC1B,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;QAC1B,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;QAC1B,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;QAC3B,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;KAC5B;CACF,CAAC,CACH,CAAC;AAEF,MAAM,kBAAkB,GAAG,IAAA,YAAK,EAAC,GAAG,EAAE,CAAC,IAAA,4BAAe,EAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAChF,IAAA,aAAM,EAAC,EAAE,KAAK,EAAE,KAAM,EAAE,CAAC,EACzB,IAAA,YAAK,EAAC,EAAE,KAAK,EAAE,KAAM,EAAE,CAAC,EACxB,IAAA,kBAAW,EAAC,CAAC,CAAC,CACf,CAAC;AAEF,MAAM,yBAAyB,GAAG,gBAAgB,CAAC,IAAI,CACrD,IAAA,iBAAS,EACP,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,EACf,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,oBAAe,EAAC,CAAC,CAAC,MAAM,CAAC,EAChC,GAAG,EAAE,CAAC,IAAI,CACX,EACD,IAAA,UAAG,EACD,CAAC,CAAC,EAAmB,EAAE,CAAC,CAAC;IACvB,aAAa,EAAE,KAAK;IACpB,UAAU,EAAE,IAAA,kBAAU,EAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC3C,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;CACvB,CAAC,CACH,EACD,IAAA,YAAK,GAAE,CACR,CAAC;AAKF,MAAM,uBAAuB,GAAG,IAAA,YAAK,EAAC,GAAG,EAAE,CACzC,YAAY,CAAC,IAAI,CACf,IAAA,YAAK,GAAE,EACP,IAAA,UAAG,EAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EACpF,IAAA,gBAAS,EAAC,CAAC,OAAO,EAAE,EAAE;IACpB,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC;IAC7B,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,OAAO,IAAA,WAAI,EAAC,OAAO,CAAC,CAAC,IAAI,CACvB,IAAA,gBAAS,EAAC,CAAC,MAAM,EAAE,EAAE,CACnB,IAAA,YAAK,EAAC,KAAK,IAAI,EAAE;QACf,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CAGxD,mBAAmB,EAAE;YACrB,QAAQ,EAAE,QAAQ;YAClB,MAAM,EAAE,OAAO;YACf,MAAM;SACP,CAAC,CAAC;QACH,IAAI,CAAC,CAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,IAAI,CAAA,EAAE;YAChB,MAAM,IAAI,KAAK,CAAC,qCAAqC,MAAM,KAAK,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;SAC9E;QACD,OAAO;YACL,MAAM;YACN,KAAK;SACN,CAAC;IACJ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAA,YAAK,EAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAChC,EACD,IAAA,aAAM,EAAC,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE;QAChC,SAAS,IAAI,CAAC,CAAC;QACf,OAAO,CAAC,IAAI,CACV,IAAA,kBAAU,EAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EACtB,gCAAgC,SAAS,IAAI,KAAK,KAAK,MAAM,GAAG,CACjE,CAAC;QACF,IAAI,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,IAAI,EAAE;YACf,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;SAC7B;QACD,OAAO,GAAG,CAAC;IACb,CAAC,EAAE,IAAI,GAAG,EAA8B,CAAC,CAC1C,CAAC;AACJ,CAAC,CAAC,CACH,CACF,CAAC,IAAI;AACJ,EAAE;AACF,IAAA,YAAK,EAAC,EAAE,KAAK,EAAE,KAAM,EAAE,CAAC,EACxB,IAAA,aAAM,EAAC,EAAE,KAAK,EAAE,QAAS,EAAE,CAAC,EAC5B,IAAA,kBAAW,EAAC,CAAC,CAAC,CACf,CAAC;AAEF,4CAA4C;AAC5C,oCAAoC;AACpC,2BAA2B;AAC3B,kEAAkE;AAClE,wCAAwC;AACxC,MAAM,mBAAmB,GAAG,YAAY,CAAC,IAAI,CAC3C,IAAA,eAAQ,EAAC,CAAC,OAAO,EAAE,EAAE,CACnB,IAAA,WAAI,EAAC,OAAO,CAAC,CAAC,IAAI,CAChB,IAAA,eAAQ,EAAC,CAAC,MAAM,EAAE,EAAE,CAClB,IAAA,YAAK,EAAC,KAAK,IAAI,EAAE;;IACf,MAAM,QAAQ,GAAG,MAAM,IAAA,qBAAc,EAAC,uBAAuB,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACnC,IAAI,CAAC,CAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,MAAM,CAAA,EAAE;QAClB,OAAO,IAAI,CAAC;KACb;IAED,MAAM,WAAW,GAAG,KAAK;SACtB,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC;SACxD,MAAM,CAAC,CAAC,iBAAiB,EAAE,QAAQ,EAAE,EAAE;QACtC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACtD,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,QAAQ,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE;YACxD,iBAAiB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;SAChD;QACD,OAAO,iBAAiB,CAAC;IAC3B,CAAC,EAAE,IAAI,GAAG,EAAkC,CAAC,CAAC;IAChD,sBAAsB;IACtB,MAAM,YAAY,GAAG,CAAC,CAAC,CAAA,MAAA,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,0CAAE,YAAY,KAAI,CAAC,CAAC,CAAC;IAEhE,OAAO;QACL,MAAM;QACN,YAAY;KACb,CAAC;AACJ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAA,YAAK,EAAC,EAAE,KAAK,EAAE,KAAM,EAAE,CAAC,EAAE,IAAA,aAAM,EAAC,EAAE,KAAK,EAAE,KAAM,EAAE,CAAC,CAAC,CAC7D,CACF,CACF,EACD,IAAA,aAAM,EAAC,CAAC,MAAM,EAAsD,EAAE,CAAC,MAAM,KAAK,IAAI,CAAC,EACvF,IAAA,UAAG,EAAC,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,EAAE;IAC/B,MAAM,OAAO,GAAoB;QAC/B,aAAa,EAAE,KAAK;QACpB,UAAU,EAAE,IAAA,kBAAU,EAAC,QAAQ,EAAE,MAAM,CAAC;KACzC,CAAC;IACF,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE;QACrE,OAAO,CAAC,aAAa,GAAG,GAAG,YAAY,EAAE,CAAC;KAC3C;IACD,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC,EACF,IAAA,YAAK,GAAE,CACR,CAAC;AAEF,MAAM,aAAa,GAAG;IACpB,kBAAkB;IAClB,yBAAyB;IACzB,oBAAoB;IACpB,2BAA2B;IAC3B,6BAA6B;IAC7B,mBAAmB;CACpB,CAAC;AAEF,MAAM,MAAM,GAAG,IAAA,YAAK,EAAC,GAAG,EAAE,CACxB,IAAA,YAAK,EACH,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAC1B,IAAA,YAAK,EAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI;AAClB,gBAAgB;AAChB,IAAA,iBAAU,EAAC,GAAG,EAAE,CAAC,YAAK,CAAC,CACxB,CACF,CACF,CACF,CAAC,IAAI,CACJ,IAAA,cAAO,EAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,kBAAU,EAAC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,EACzD,IAAA,eAAQ,EAAC,CAAC,MAAM,EAAE,EAAE;IAClB,OAAO,MAAM,CAAC,IAAI;IAChB,EAAE;IACF,IAAA,WAAI,EAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAqB,CAAC,CACnE,CAAC;AACJ,CAAC,CAAC,EACF,IAAA,YAAK,GAAE,CACR,CAAC;AAEF,sBAAsB;AACtB,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,MAAM,EAAE;IAC7C,QAAQ,CAAC,OAAO,CAAC,cAAc,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,UAAU,EAAE,EAAE;QAC5E,MAAM,CAAC,aAAa,EAAE,UAAU,CAAC,GAAG,IAAA,kBAAU,EAAC,UAAU,CAAC,CAAC;QAC3D,IAAI,CAAC,aAAa,EAAE;YAClB,MAAM,2BAA2B,CAAC;SACnC;QACD,IAAI,CAAC,UAAU,EAAE;YACf,MAAM,wBAAwB,CAAC;SAChC;QACD,OAAO,MAAM,CAAC,IAAI,CAAC,IAAA,aAAM,EAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,MAAM;SACH,IAAI,CACH,IAAA,gBAAU,EAAC;QACT,QAAQ;QACR,aAAa,EAAE,IAAI;QACnB,SAAS,EAAE,OAAO;QAClB,YAAY,EAAE,CAAC,eAAe,EAAE,YAAY,CAAC;KAC9C,CAAC,CACH;SACA,SAAS,EAAE,CAAC;CAChB;AAEY,QAAA,iBAAiB,GAAG,IAAA,YAAK,EAAC,GAAG,EAAE,CAAC,kBAAkB,CAAC,CAAC,IAAI,CACnE,IAAA,UAAG,EAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAU,CAAC,CAAC,CAAC,EAClE,IAAA,kBAAW,EAAC,CAAC,CAAC,CACf,CAAC","sourcesContent":["import { IQuote } from '@yuants/data-quote';\nimport { Terminal } from '@yuants/protocol';\nimport { writeToSQL } from '@yuants/sql';\nimport { decodePath, encodePath, formatTime, listWatch } from '@yuants/utils';\nimport {\n catchError,\n concatMap,\n defer,\n distinctUntilChanged,\n EMPTY,\n filter,\n first,\n firstValueFrom,\n from,\n groupBy,\n map,\n merge,\n mergeMap,\n reduce,\n repeat,\n retry,\n scan,\n share,\n shareReplay,\n switchMap,\n tap,\n toArray,\n} from 'rxjs';\nimport { getInstruments, getMarketTickers, getOpenInterest, getPositionTiers } from '../api/public-api';\nimport { useOpenInterest, useTicker } from '../ws';\n\nconst terminal = Terminal.fromNodeEnv();\n\nconst swapInstruments$ = defer(() => getInstruments({ instType: 'SWAP' })).pipe(\n repeat({ delay: 3600_000 }),\n retry({ delay: 10_000 }),\n map((x) => x.data),\n shareReplay(1),\n);\nconst spotInstruments$ = defer(() => getInstruments({ instType: 'SPOT' })).pipe(\n repeat({ delay: 3600_000 }),\n retry({ delay: 10_000 }),\n map((x) => x.data),\n shareReplay(1),\n);\n\nconst shallowEqual = (a: string[], b: string[]) => a.length === b.length && a.every((v, i) => v === b[i]);\n\nconst spotInstIds$ = spotInstruments$.pipe(\n map((items) => items.map((item) => item.instId)),\n distinctUntilChanged(shallowEqual),\n shareReplay(1),\n);\n\nconst spotTickers$ = defer(() => getMarketTickers({ instType: 'SPOT' })).pipe(\n repeat({ delay: 5000 }),\n retry({ delay: 5000 }),\n shareReplay(1),\n);\n\n// depend by SubmitOrders\nexport const spotMarketTickers$ = defer(() => spotTickers$).pipe(\n mergeMap((x) =>\n from(x.data).pipe(\n map((x) => [x.instId, x] as const),\n toArray(),\n map((x) => Object.fromEntries(x)),\n ),\n ),\n repeat({ delay: 5000 }),\n retry({ delay: 5000 }),\n shareReplay(1),\n);\n\nconst spotTicker$ = spotInstruments$.pipe(\n tap((x) => {\n console.info('SPOT INSTRUMENTS', x.length);\n }),\n listWatch(\n (x) => x.instId,\n (x) => useTicker(x.instId),\n () => true,\n ),\n share(),\n);\n\nconst quoteOfSwapFromRest$ = defer(() => getMarketTickers({ instType: 'SWAP' })).pipe(\n mergeMap((x) => x.data || []),\n map(\n (x): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath(x.instType, x.instId),\n last_price: x.last,\n ask_price: x.askPx,\n bid_price: x.bidPx,\n ask_volume: x.askSz,\n bid_volume: x.bidSz,\n }),\n ),\n repeat({ delay: 1000 }),\n retry({ delay: 1000 }),\n);\n\nconst quoteOfSpotAndMarginFromRest$ = defer(() => getMarketTickers({ instType: 'SPOT' })).pipe(\n mergeMap((x) => x.data || []),\n mergeMap((x): Partial<IQuote>[] => [\n {\n datasource_id: 'OKX',\n product_id: encodePath('SPOT', x.instId),\n last_price: x.last,\n ask_price: x.askPx,\n bid_price: x.bidPx,\n ask_volume: x.askSz,\n bid_volume: x.bidSz,\n },\n {\n datasource_id: 'OKX',\n product_id: encodePath('MARGIN', x.instId),\n last_price: x.last,\n ask_price: x.askPx,\n bid_price: x.bidPx,\n ask_volume: x.askSz,\n bid_volume: x.bidSz,\n },\n ]),\n repeat({ delay: 1000 }),\n retry({ delay: 1000 }),\n);\n\nconst quoteOfSwapFromWs$ = swapInstruments$.pipe(\n listWatch(\n (x) => x.instId,\n (x) => useTicker(x.instId),\n () => true,\n ),\n map(\n (ticker): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('SWAP', ticker[0].instId),\n last_price: ticker[0].last,\n ask_price: ticker[0].askPx,\n bid_price: ticker[0].bidPx,\n ask_volume: ticker[0].askSz,\n bid_volume: ticker[0].bidSz,\n }),\n ),\n);\n\nconst quoteOfSpotAndMarginFromWs$ = spotTicker$.pipe(\n mergeMap((ticker): Partial<IQuote>[] => [\n {\n datasource_id: 'OKX',\n product_id: encodePath('SPOT', ticker[0].instId),\n last_price: ticker[0].last,\n ask_price: ticker[0].askPx,\n bid_price: ticker[0].bidPx,\n ask_volume: ticker[0].askSz,\n bid_volume: ticker[0].bidSz,\n },\n {\n datasource_id: 'OKX',\n product_id: encodePath('MARGIN', ticker[0].instId),\n last_price: ticker[0].last,\n ask_price: ticker[0].askPx,\n bid_price: ticker[0].bidPx,\n ask_volume: ticker[0].askSz,\n bid_volume: ticker[0].bidSz,\n },\n ]),\n);\n\nconst swapOpenInterests$ = defer(() => getOpenInterest({ instType: 'SWAP' })).pipe(\n repeat({ delay: 10_000 }),\n retry({ delay: 10_000 }),\n shareReplay(1),\n);\n\nconst openInterestOfSwapFromWS$ = swapInstruments$.pipe(\n listWatch(\n (x) => x.instId,\n (x) => useOpenInterest(x.instId),\n () => true,\n ),\n map(\n (x): Partial<IQuote> => ({\n datasource_id: 'OKX',\n product_id: encodePath('SWAP', x[0].instId),\n open_interest: x[0].oi,\n }),\n ),\n share(),\n);\n\ntype PositionTiersResponse = Awaited<ReturnType<typeof getPositionTiers>>;\ntype PositionTiersEntry = PositionTiersResponse['data'];\n\nconst marginPositionTiersMap$ = defer(() =>\n spotInstIds$.pipe(\n first(),\n map((instIds) => instIds.filter((id) => id.endsWith('USDT') || id.endsWith('USDC'))),\n switchMap((instIds) => {\n const total = instIds.length;\n let processed = 0;\n return from(instIds).pipe(\n concatMap((instId) =>\n defer(async () => {\n const tiers = await terminal.client.requestForResponseData<\n { instType: string; tdMode: string; instId: string },\n PositionTiersResponse\n >('OKX/PositionTiers', {\n instType: 'MARGIN',\n tdMode: 'cross',\n instId,\n });\n if (!tiers?.data) {\n throw new Error(`Failed to load position tiers for ${instId}: ${tiers.msg}`);\n }\n return {\n instId,\n tiers,\n };\n }).pipe(retry({ delay: 2000 })),\n ),\n reduce((map, { instId, tiers }) => {\n processed += 1;\n console.info(\n formatTime(Date.now()),\n `Loaded margin position tiers ${processed}/${total} (${instId})`,\n );\n if (tiers?.data) {\n map.set(instId, tiers.data);\n }\n return map;\n }, new Map<string, PositionTiersEntry>()),\n );\n }),\n ),\n).pipe(\n //\n retry({ delay: 60_000 }),\n repeat({ delay: 86400_000 }),\n shareReplay(1),\n);\n\n// Margin 的 open interest 只依赖 position-tier:\n// 1) 启动时先拉全量 MARGIN 仓位档位并缓存,下次直接命中;\n// 2) 档位内只保留同 tier 杠杆最高的记录;\n// 3) 当前策略只使用 tier=1 的 quoteMaxLoan 作为持仓上限,不再混合 /account/max-size;\n// 4) 每个 instId 60 秒刷新一次,并在接口报错时 10 秒重试。\nconst marginOpenInterest$ = spotInstIds$.pipe(\n mergeMap((instIds) =>\n from(instIds).pipe(\n mergeMap((instId) =>\n defer(async () => {\n const tiersMap = await firstValueFrom(marginPositionTiersMap$);\n const tiers = tiersMap.get(instId);\n if (!tiers?.length) {\n return null;\n }\n\n const tierByLevel = tiers\n .filter((tier) => !tier.instId || tier.instId === instId)\n .reduce((mapTierToTierInfo, tierInfo) => {\n const existing = mapTierToTierInfo.get(tierInfo.tier);\n if (!existing || +tierInfo.maxLever > +existing.maxLever) {\n mapTierToTierInfo.set(tierInfo.tier, tierInfo);\n }\n return mapTierToTierInfo;\n }, new Map<string, (typeof tiers)[number]>());\n // 获取一级杠杆的最大可借贷额度作为持仓量\n const openInterest = +(tierByLevel.get('1')?.quoteMaxLoan || 0);\n\n return {\n instId,\n openInterest,\n };\n }).pipe(retry({ delay: 10_000 }), repeat({ delay: 60_000 })),\n ),\n ),\n ),\n filter((result): result is { instId: string; openInterest: number } => result !== null),\n map(({ instId, openInterest }) => {\n const partial: Partial<IQuote> = {\n datasource_id: 'OKX',\n product_id: encodePath('MARGIN', instId),\n };\n if (typeof openInterest === 'number' && Number.isFinite(openInterest)) {\n partial.open_interest = `${openInterest}`;\n }\n return partial;\n }),\n share(),\n);\n\nconst quoteSources$ = [\n quoteOfSwapFromWs$,\n openInterestOfSwapFromWS$,\n quoteOfSwapFromRest$,\n quoteOfSpotAndMarginFromWs$,\n quoteOfSpotAndMarginFromRest$,\n marginOpenInterest$,\n];\n\nconst quote$ = defer(() =>\n merge(\n ...quoteSources$.map((x$) =>\n defer(() => x$).pipe(\n // 防止单个流关闭导致整体关闭\n catchError(() => EMPTY),\n ),\n ),\n ),\n).pipe(\n groupBy((x) => encodePath(x.datasource_id, x.product_id)),\n mergeMap((group$) => {\n return group$.pipe(\n //\n scan((acc, cur) => Object.assign(acc, cur), {} as Partial<IQuote>),\n );\n }),\n share(),\n);\n\n// 合并不同来源的数据并进行合并,避免死锁\nif (process.env.WRITE_QUOTE_TO_SQL === 'true') {\n terminal.channel.publishChannel('quote', { pattern: `^OKX/` }, (channel_id) => {\n const [datasource_id, product_id] = decodePath(channel_id);\n if (!datasource_id) {\n throw 'datasource_id is required';\n }\n if (!product_id) {\n throw 'product_id is required';\n }\n return quote$.pipe(filter((x) => x.product_id === product_id));\n });\n\n quote$\n .pipe(\n writeToSQL({\n terminal,\n writeInterval: 1000,\n tableName: 'quote',\n conflictKeys: ['datasource_id', 'product_id'],\n }),\n )\n .subscribe();\n}\n\nexport const swapOpenInterest$ = defer(() => swapOpenInterests$).pipe(\n map((x) => new Map(x.data.map((x) => [x.instId, +x.oi] as const))),\n shareReplay(1),\n);\n"]}
package/lib/ws.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../src/ws.ts"],"names":[],"mappings":"AAEA,OAAO,EAA8C,UAAU,EAA8B,MAAM,MAAM,CAAC;AAC1G,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAgS1D,eAAO,MAAM,SAAS,WAAY,MAAM;YAG1B,MAAM;UACR,MAAM;WACL,MAAM;WACN,MAAM;WACN,MAAM;WACN,MAAM;IAKhB,CAAC;AAEJ,eAAO,MAAM,eAAe,WAAY,MAAM;YAGhC,MAAM;QACV,MAAM;IAKb,CAAC;AAEJ,eAAO,MAAM,OAAO,eAAgB,MAAM,UAAU,MAAM,2BAIvD,CAAC;AAEJ,eAAO,MAAM,cAAc,YAChB,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,cAAc,GAAG,gBAAgB,UACnE,MAAM,+BAKb,CAAC;AAEJ,eAAO,MAAM,cAAc,WAAY,MAAM;iBAG1B,MAAM;iBACN,MAAM;YACX,MAAM;cACJ,MAAM;YACR,MAAM;oBACE,MAAM;oBACN,MAAM;qBACL,MAAM;qBACN,MAAM;aACd,MAAM;qBACE,MAAM;eACZ,MAAM;QACb,MAAM;IAKb,CAAC"}
1
+ {"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../src/ws.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,UAAU,EAKX,MAAM,MAAM,CAAC;AACd,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AA8T1D,eAAO,MAAM,SAAS,WAAY,MAAM;YAG1B,MAAM;UACR,MAAM;WACL,MAAM;WACN,MAAM;WACN,MAAM;WACN,MAAM;IAKhB,CAAC;AAEJ,eAAO,MAAM,eAAe,WAAY,MAAM;YAGhC,MAAM;QACV,MAAM;IAKb,CAAC;AAEJ,eAAO,MAAM,OAAO,eAAgB,MAAM,UAAU,MAAM,2BAIvD,CAAC;AAEJ,eAAO,MAAM,cAAc,YAChB,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,cAAc,GAAG,gBAAgB,UACnE,MAAM,+BAKb,CAAC;AAEJ,eAAO,MAAM,cAAc,WAAY,MAAM;iBAG1B,MAAM;iBACN,MAAM;YACX,MAAM;cACJ,MAAM;YACR,MAAM;oBACE,MAAM;oBACN,MAAM;qBACL,MAAM;qBACN,MAAM;aACd,MAAM;qBACE,MAAM;eACZ,MAAM;QACb,MAAM;IAKb,CAAC"}
package/lib/ws.js CHANGED
@@ -207,32 +207,61 @@ class OKXWsClient {
207
207
  }
208
208
  }
209
209
  OKXWsClient.pool = [];
210
- const fromWsChannelAndInstId = (path, channel, instId) => (0, rxjs_1.defer)(() => new rxjs_1.Observable((subscriber) => {
211
- const client = OKXWsClient.GetWsClient(path);
212
- client.subscribe(channel, instId, (data) => {
213
- subscriber.next(data);
214
- });
215
- const removeError = client.addConnectionListener('error', (err) => {
216
- subscriber.error(err);
217
- });
218
- const removeClose = client.addConnectionListener('close', () => {
219
- subscriber.error('WS Connection Closed');
220
- });
221
- subscriber.add(() => {
222
- removeError();
223
- removeClose();
224
- client.unsubscribe(channel, instId);
225
- });
226
- })).pipe(
227
- // 防止单个连接断开导致数据流关闭
228
- (0, rxjs_1.timeout)(60000), (0, rxjs_1.tap)({
229
- error: (err) => {
230
- console.info((0, utils_1.formatTime)(Date.now()), 'WS_SUBSCRIBE_ERROR', channel, instId, err);
231
- },
232
- }),
233
- // 暂时不太确定是否能支持 retry
234
- // retry({ delay: 1000 }),
235
- (0, rxjs_1.catchError)(() => rxjs_1.EMPTY));
210
+ // 全局缓存:存储已创建的 WebSocket Observable,实现订阅复用
211
+ // key: encodePath(path, channel, instId)
212
+ // value: shared Observable
213
+ const wsObservableCache = new Map();
214
+ const fromWsChannelAndInstId = (path, channel, instId) => {
215
+ const cacheKey = (0, utils_1.encodePath)(path, channel, instId);
216
+ // 检查缓存中是否已存在该订阅
217
+ const cached = wsObservableCache.get(cacheKey);
218
+ if (cached) {
219
+ console.info((0, utils_1.formatTime)(Date.now()), `♻️ Reusing cached subscription: ${cacheKey}`);
220
+ return cached;
221
+ }
222
+ // 创建新的 Observable
223
+ const observable$ = new rxjs_1.Observable((subscriber) => {
224
+ const client = OKXWsClient.GetWsClient(path);
225
+ client.subscribe(channel, instId, (data) => {
226
+ subscriber.next(data);
227
+ });
228
+ const removeError = client.addConnectionListener('error', (err) => {
229
+ subscriber.error(err);
230
+ });
231
+ const removeClose = client.addConnectionListener('close', () => {
232
+ subscriber.error('WS Connection Closed');
233
+ });
234
+ subscriber.add(() => {
235
+ removeError();
236
+ removeClose();
237
+ client.unsubscribe(channel, instId);
238
+ });
239
+ }).pipe(
240
+ // 防止单个连接断开导致数据流关闭
241
+ (0, rxjs_1.timeout)(60000), (0, rxjs_1.tap)({
242
+ error: (err) => {
243
+ console.info((0, utils_1.formatTime)(Date.now()), 'WS_SUBSCRIBE_ERROR', channel, instId, err);
244
+ },
245
+ }),
246
+ // 暂时不太确定是否能支持 retry
247
+ // retry({ delay: 1000 }),
248
+ (0, rxjs_1.catchError)(() => rxjs_1.EMPTY),
249
+ // 🔑 关键:使用 shareReplay 实现订阅复用
250
+ // - bufferSize: 1 - 缓存最新的一个值,新订阅者可以立即获得最新数据
251
+ // - refCount: true - 当所有订阅者都取消订阅时,自动取消上游订阅并清理资源
252
+ (0, rxjs_1.shareReplay)({ bufferSize: 1, refCount: true }),
253
+ // 当订阅完全结束时,从缓存中移除
254
+ (0, rxjs_1.tap)({
255
+ finalize: () => {
256
+ console.info((0, utils_1.formatTime)(Date.now()), `🗑️ Removing from cache: ${cacheKey}`);
257
+ wsObservableCache.delete(cacheKey);
258
+ },
259
+ }));
260
+ // 存入缓存
261
+ wsObservableCache.set(cacheKey, observable$);
262
+ console.info((0, utils_1.formatTime)(Date.now()), `📦 Cached new subscription: ${cacheKey}`);
263
+ return observable$;
264
+ };
236
265
  const useTicker = (instId) => fromWsChannelAndInstId('ws/v5/public', 'tickers', instId).pipe(
237
266
  //
238
267
  (0, rxjs_1.filter)((data) => data.length > 0));
package/lib/ws.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ws.js","sourceRoot":"","sources":["../src/ws.ts"],"names":[],"mappings":"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","sourcesContent":["import { GlobalPrometheusRegistry, Terminal } from '@yuants/protocol';\nimport { encodePath, formatTime } from '@yuants/utils';\nimport { catchError, defer, EMPTY, filter, interval, Observable, Subscription, tap, timeout } from 'rxjs';\nimport { IWSOrderBook } from './public-data/market-order';\n\nconst MetricsWebSocketConnectionsGauge = GlobalPrometheusRegistry.gauge(\n 'okx_websocket_connections',\n 'Number of active OKX WebSocket connections',\n);\n\nconst MetricsWebSocketChannelGauge = GlobalPrometheusRegistry.gauge(\n 'okx_websocket_channel',\n 'Number of OKX WebSocket channels subscribed',\n);\n\ntype ConnectStatus = 'connecting' | 'connected' | 'closed' | 'reconnecting';\nconst terminal = Terminal.fromNodeEnv();\n\nclass OKXWsClient {\n private static readonly pool: {\n path: string;\n client: OKXWsClient;\n requests: number;\n isFull: boolean;\n }[] = [];\n\n // ISSUE: 连接限制:3 次/秒 (基于IP)\n // https://www.okx.com/docs-v5/zh/#overview-websocket-connect\n // 每个连接 对于 订阅/取消订阅/登录 请求的总次数限制为 480 次/小时\n static GetWsClient(path: string): OKXWsClient {\n const existing = OKXWsClient.pool.find((item) => item.path === path && !item.isFull);\n if (existing && !existing.client.isClosed()) {\n existing.requests++;\n if (existing.requests >= 480) {\n existing.isFull = true;\n }\n return existing.client;\n }\n\n const client = existing?.client?.isClosed() ? existing.client.revive() : new OKXWsClient(path);\n if (existing) {\n existing.client = client;\n existing.requests = 1;\n existing.isFull = false;\n } else {\n OKXWsClient.pool.push({ path, client, requests: 1, isFull: false });\n }\n return client;\n }\n\n private readonly baseURL: string = `wss://ws.okx.com:8443`;\n private readonly path: string;\n private ws!: WebSocket;\n private connectStatus: ConnectStatus = 'closed';\n private keepAlive?: Subscription;\n private readonly subscriptions = new Map<\n string,\n {\n channel: string;\n instId?: string;\n }\n >();\n private readonly handlers: Record<string, Function> = {};\n private readonly connectionListeners: Record<'error' | 'close', Set<EventListener>> = {\n error: new Set(),\n close: new Set(),\n };\n\n private readonly handleOpen = () => {\n this.connectStatus = 'connected';\n console.info(formatTime(Date.now()), '✅ WS connected');\n for (const { channel, instId } of this.subscriptions.values()) {\n this.sendSubscribeMessage(channel, instId);\n }\n };\n\n private readonly handleMessage = (raw: MessageEvent) => {\n if (raw.data === 'pong') {\n return;\n }\n const msg = JSON.parse(raw.data);\n if (msg.arg?.channel) {\n const channelId = encodePath(msg.arg.channel, msg.arg.instId);\n const data = msg.data;\n const handler = this.handlers[channelId];\n if (data && handler) {\n handler(data, msg.arg);\n }\n } else if (msg.event) {\n console.info(formatTime(Date.now()), 'Event:', msg);\n }\n };\n\n private readonly handleError = (event: Event) => {\n console.error(formatTime(Date.now()), '❌ WS error', event);\n };\n\n private readonly handleClose = (event: CloseEvent) => {\n console.error(formatTime(Date.now()), '❌ WS closed', event);\n MetricsWebSocketConnectionsGauge.labels({ path: this.path }).dec();\n\n const closedSocket = event.target as WebSocket;\n if (closedSocket !== this.ws) {\n return;\n }\n\n if (this.connectStatus === 'reconnecting') {\n return;\n }\n\n this.connectStatus = 'closed';\n\n if (this.subscriptions.size === 0) {\n return;\n }\n\n this.connectStatus = 'reconnecting';\n setTimeout(() => {\n if (this.connectStatus === 'connecting' || this.connectStatus === 'connected') {\n return;\n }\n if (this.subscriptions.size === 0) {\n this.connectStatus = 'closed';\n return;\n }\n this.initSocket();\n }, 1000);\n };\n\n constructor(path: string) {\n this.path = path;\n this.initSocket();\n this.startKeepAlive();\n }\n\n private revive(): OKXWsClient {\n this.initSocket();\n this.startKeepAlive();\n return this;\n }\n\n private initSocket() {\n this.connectStatus = 'connecting';\n this.ws = new WebSocket(`${this.baseURL}/${this.path}`);\n MetricsWebSocketConnectionsGauge.labels({ path: this.path, terminal_id: terminal.terminal_id }).inc();\n\n this.ws.addEventListener('open', this.handleOpen);\n this.ws.addEventListener('message', this.handleMessage);\n this.ws.addEventListener('error', this.handleError);\n this.ws.addEventListener('close', this.handleClose);\n\n for (const listener of this.connectionListeners.error) {\n this.ws.addEventListener('error', listener);\n }\n for (const listener of this.connectionListeners.close) {\n this.ws.addEventListener('close', listener);\n }\n }\n\n private startKeepAlive() {\n if (this.keepAlive && !this.keepAlive.closed) {\n return;\n }\n this.keepAlive = interval(25_000)\n .pipe(\n tap(() => {\n if (this.connectStatus === 'connected') {\n this.ws.send('ping');\n }\n }),\n )\n .subscribe();\n }\n\n private stopKeepAlive() {\n if (this.keepAlive && !this.keepAlive.closed) {\n this.keepAlive.unsubscribe();\n }\n }\n\n private isClosed() {\n return this.ws?.readyState === WebSocket.CLOSING || this.ws?.readyState === WebSocket.CLOSED;\n }\n\n private sendSubscribeMessage(channel: string, instId?: string) {\n const message = {\n op: 'subscribe',\n args: [{ channel, instId }],\n };\n this.ws.send(JSON.stringify(message));\n const channelId = encodePath(channel, instId);\n console.info(formatTime(Date.now()), `📩 Sent subscribe for ${channelId}`);\n }\n\n private sendUnsubscribeMessage(channel: string, instId?: string) {\n const message = {\n op: 'unsubscribe',\n args: [{ channel, instId }],\n };\n this.ws.send(JSON.stringify(message));\n const channelId = encodePath(channel, instId);\n console.info(formatTime(Date.now()), `📩 Sent unsubscribe for ${channelId}`);\n }\n\n addConnectionListener(type: 'error' | 'close', listener: EventListener): () => void {\n this.connectionListeners[type].add(listener);\n this.ws.addEventListener(type, listener);\n return () => {\n this.connectionListeners[type].delete(listener);\n this.ws.removeEventListener(type, listener);\n };\n }\n\n subscribe(channel: string, instId?: string, handler?: Function) {\n const channelId = encodePath(channel, instId);\n if (this.subscriptions.has(channelId)) {\n console.info(formatTime(Date.now()), `⚠️ Already subscribed: ${channelId}`);\n return;\n }\n\n this.subscriptions.set(channelId, { channel, instId });\n MetricsWebSocketChannelGauge.labels({ channel, terminal_id: terminal.terminal_id }).inc();\n\n if (handler) {\n this.handlers[channelId] = handler;\n }\n\n this.startKeepAlive();\n\n if (this.connectStatus === 'connected') {\n this.sendSubscribeMessage(channel, instId);\n } else if (this.isClosed()) {\n this.initSocket();\n } else {\n console.info(formatTime(Date.now()), `📩 Queued subscribe for ${channelId} waiting for connection`);\n }\n }\n\n unsubscribe(channel: string, instId?: string) {\n const channelId = encodePath(channel, instId);\n if (!this.subscriptions.has(channelId)) return;\n\n if (this.connectStatus === 'connected') {\n this.sendUnsubscribeMessage(channel, instId);\n }\n this.subscriptions.delete(channelId);\n MetricsWebSocketChannelGauge.labels({ channel }).dec();\n delete this.handlers[channelId];\n\n if (this.subscriptions.size === 0) {\n this.stopKeepAlive();\n if (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING) {\n this.ws.close();\n }\n }\n }\n}\n\nconst fromWsChannelAndInstId = <T>(path: string, channel: string, instId: string) =>\n defer(\n () =>\n new Observable<T>((subscriber) => {\n const client = OKXWsClient.GetWsClient(path);\n client.subscribe(channel, instId, (data: T) => {\n subscriber.next(data);\n });\n const removeError = client.addConnectionListener('error', (err) => {\n subscriber.error(err);\n });\n const removeClose = client.addConnectionListener('close', () => {\n subscriber.error('WS Connection Closed');\n });\n subscriber.add(() => {\n removeError();\n removeClose();\n client.unsubscribe(channel, instId);\n });\n }),\n ).pipe(\n // 防止单个连接断开导致数据流关闭\n timeout(60_000),\n tap({\n error: (err) => {\n console.info(formatTime(Date.now()), 'WS_SUBSCRIBE_ERROR', channel, instId, err);\n },\n }),\n // 暂时不太确定是否能支持 retry\n // retry({ delay: 1000 }),\n catchError(() => EMPTY),\n );\n\nexport const useTicker = (instId: string) =>\n fromWsChannelAndInstId<\n {\n instId: string;\n last: string;\n askPx: string;\n bidPx: string;\n askSz: string;\n bidSz: string;\n }[]\n >('ws/v5/public', 'tickers', instId).pipe(\n //\n filter((data) => data.length > 0),\n );\n\nexport const useOpenInterest = (instId: string) =>\n fromWsChannelAndInstId<\n {\n instId: string;\n oi: string; // open interest\n }[]\n >('ws/v5/public', 'open-interest', instId).pipe(\n //\n filter((data) => data.length > 0),\n );\n\nexport const useOHLC = (candleType: string, instId: string) =>\n fromWsChannelAndInstId<string[][]>('ws/v5/business', candleType, instId).pipe(\n //\n filter((data) => data.length > 0),\n );\n\nexport const useMarketBooks = (\n channel: 'books' | 'books5' | 'bbo-tbt' | 'books-l2-tbt' | 'books50-l2-tbt',\n instId: string,\n) =>\n fromWsChannelAndInstId<IWSOrderBook[]>('ws/v5/public', channel, instId).pipe(\n //\n filter((data) => data.length > 0),\n );\n\nexport const useFundingRate = (instId: string) =>\n fromWsChannelAndInstId<\n {\n fundingRate: string;\n fundingTime: string;\n instId: string;\n instType: string;\n method: string;\n maxFundingRate: string;\n minFundingRate: string;\n nextFundingRate: string;\n nextFundingTime: string;\n premium: string;\n settFundingRate: string;\n settState: string;\n ts: string;\n }[]\n >('ws/v5/public', 'funding-rate', instId).pipe(\n //\n filter((data) => data.length > 0),\n );\n"]}
1
+ {"version":3,"file":"ws.js","sourceRoot":"","sources":["../src/ws.ts"],"names":[],"mappings":"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","sourcesContent":["import { GlobalPrometheusRegistry, Terminal } from '@yuants/protocol';\nimport { encodePath, formatTime } from '@yuants/utils';\nimport {\n catchError,\n EMPTY,\n filter,\n interval,\n Observable,\n shareReplay,\n Subscription,\n tap,\n timeout,\n} from 'rxjs';\nimport { IWSOrderBook } from './public-data/market-order';\n\nconst MetricsWebSocketConnectionsGauge = GlobalPrometheusRegistry.gauge(\n 'okx_websocket_connections',\n 'Number of active OKX WebSocket connections',\n);\n\nconst MetricsWebSocketChannelGauge = GlobalPrometheusRegistry.gauge(\n 'okx_websocket_channel',\n 'Number of OKX WebSocket channels subscribed',\n);\n\ntype ConnectStatus = 'connecting' | 'connected' | 'closed' | 'reconnecting';\nconst terminal = Terminal.fromNodeEnv();\n\nclass OKXWsClient {\n private static readonly pool: {\n path: string;\n client: OKXWsClient;\n requests: number;\n isFull: boolean;\n }[] = [];\n\n // ISSUE: 连接限制:3 次/秒 (基于IP)\n // https://www.okx.com/docs-v5/zh/#overview-websocket-connect\n // 每个连接 对于 订阅/取消订阅/登录 请求的总次数限制为 480 次/小时\n static GetWsClient(path: string): OKXWsClient {\n const existing = OKXWsClient.pool.find((item) => item.path === path && !item.isFull);\n if (existing && !existing.client.isClosed()) {\n existing.requests++;\n if (existing.requests >= 480) {\n existing.isFull = true;\n }\n return existing.client;\n }\n\n const client = existing?.client?.isClosed() ? existing.client.revive() : new OKXWsClient(path);\n if (existing) {\n existing.client = client;\n existing.requests = 1;\n existing.isFull = false;\n } else {\n OKXWsClient.pool.push({ path, client, requests: 1, isFull: false });\n }\n return client;\n }\n\n private readonly baseURL: string = `wss://ws.okx.com:8443`;\n private readonly path: string;\n private ws!: WebSocket;\n private connectStatus: ConnectStatus = 'closed';\n private keepAlive?: Subscription;\n private readonly subscriptions = new Map<\n string,\n {\n channel: string;\n instId?: string;\n }\n >();\n private readonly handlers: Record<string, Function> = {};\n private readonly connectionListeners: Record<'error' | 'close', Set<EventListener>> = {\n error: new Set(),\n close: new Set(),\n };\n\n private readonly handleOpen = () => {\n this.connectStatus = 'connected';\n console.info(formatTime(Date.now()), '✅ WS connected');\n for (const { channel, instId } of this.subscriptions.values()) {\n this.sendSubscribeMessage(channel, instId);\n }\n };\n\n private readonly handleMessage = (raw: MessageEvent) => {\n if (raw.data === 'pong') {\n return;\n }\n const msg = JSON.parse(raw.data);\n if (msg.arg?.channel) {\n const channelId = encodePath(msg.arg.channel, msg.arg.instId);\n const data = msg.data;\n const handler = this.handlers[channelId];\n if (data && handler) {\n handler(data, msg.arg);\n }\n } else if (msg.event) {\n console.info(formatTime(Date.now()), 'Event:', msg);\n }\n };\n\n private readonly handleError = (event: Event) => {\n console.error(formatTime(Date.now()), '❌ WS error', event);\n };\n\n private readonly handleClose = (event: CloseEvent) => {\n console.error(formatTime(Date.now()), '❌ WS closed', event);\n MetricsWebSocketConnectionsGauge.labels({ path: this.path }).dec();\n\n const closedSocket = event.target as WebSocket;\n if (closedSocket !== this.ws) {\n return;\n }\n\n if (this.connectStatus === 'reconnecting') {\n return;\n }\n\n this.connectStatus = 'closed';\n\n if (this.subscriptions.size === 0) {\n return;\n }\n\n this.connectStatus = 'reconnecting';\n setTimeout(() => {\n if (this.connectStatus === 'connecting' || this.connectStatus === 'connected') {\n return;\n }\n if (this.subscriptions.size === 0) {\n this.connectStatus = 'closed';\n return;\n }\n this.initSocket();\n }, 1000);\n };\n\n constructor(path: string) {\n this.path = path;\n this.initSocket();\n this.startKeepAlive();\n }\n\n private revive(): OKXWsClient {\n this.initSocket();\n this.startKeepAlive();\n return this;\n }\n\n private initSocket() {\n this.connectStatus = 'connecting';\n this.ws = new WebSocket(`${this.baseURL}/${this.path}`);\n MetricsWebSocketConnectionsGauge.labels({ path: this.path, terminal_id: terminal.terminal_id }).inc();\n\n this.ws.addEventListener('open', this.handleOpen);\n this.ws.addEventListener('message', this.handleMessage);\n this.ws.addEventListener('error', this.handleError);\n this.ws.addEventListener('close', this.handleClose);\n\n for (const listener of this.connectionListeners.error) {\n this.ws.addEventListener('error', listener);\n }\n for (const listener of this.connectionListeners.close) {\n this.ws.addEventListener('close', listener);\n }\n }\n\n private startKeepAlive() {\n if (this.keepAlive && !this.keepAlive.closed) {\n return;\n }\n this.keepAlive = interval(25_000)\n .pipe(\n tap(() => {\n if (this.connectStatus === 'connected') {\n this.ws.send('ping');\n }\n }),\n )\n .subscribe();\n }\n\n private stopKeepAlive() {\n if (this.keepAlive && !this.keepAlive.closed) {\n this.keepAlive.unsubscribe();\n }\n }\n\n private isClosed() {\n return this.ws?.readyState === WebSocket.CLOSING || this.ws?.readyState === WebSocket.CLOSED;\n }\n\n private sendSubscribeMessage(channel: string, instId?: string) {\n const message = {\n op: 'subscribe',\n args: [{ channel, instId }],\n };\n this.ws.send(JSON.stringify(message));\n const channelId = encodePath(channel, instId);\n console.info(formatTime(Date.now()), `📩 Sent subscribe for ${channelId}`);\n }\n\n private sendUnsubscribeMessage(channel: string, instId?: string) {\n const message = {\n op: 'unsubscribe',\n args: [{ channel, instId }],\n };\n this.ws.send(JSON.stringify(message));\n const channelId = encodePath(channel, instId);\n console.info(formatTime(Date.now()), `📩 Sent unsubscribe for ${channelId}`);\n }\n\n addConnectionListener(type: 'error' | 'close', listener: EventListener): () => void {\n this.connectionListeners[type].add(listener);\n this.ws.addEventListener(type, listener);\n return () => {\n this.connectionListeners[type].delete(listener);\n this.ws.removeEventListener(type, listener);\n };\n }\n\n subscribe(channel: string, instId?: string, handler?: Function) {\n const channelId = encodePath(channel, instId);\n if (this.subscriptions.has(channelId)) {\n console.info(formatTime(Date.now()), `⚠️ Already subscribed: ${channelId}`);\n return;\n }\n\n this.subscriptions.set(channelId, { channel, instId });\n MetricsWebSocketChannelGauge.labels({ channel, terminal_id: terminal.terminal_id }).inc();\n\n if (handler) {\n this.handlers[channelId] = handler;\n }\n\n this.startKeepAlive();\n\n if (this.connectStatus === 'connected') {\n this.sendSubscribeMessage(channel, instId);\n } else if (this.isClosed()) {\n this.initSocket();\n } else {\n console.info(formatTime(Date.now()), `📩 Queued subscribe for ${channelId} waiting for connection`);\n }\n }\n\n unsubscribe(channel: string, instId?: string) {\n const channelId = encodePath(channel, instId);\n if (!this.subscriptions.has(channelId)) return;\n\n if (this.connectStatus === 'connected') {\n this.sendUnsubscribeMessage(channel, instId);\n }\n this.subscriptions.delete(channelId);\n MetricsWebSocketChannelGauge.labels({ channel }).dec();\n delete this.handlers[channelId];\n\n if (this.subscriptions.size === 0) {\n this.stopKeepAlive();\n if (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING) {\n this.ws.close();\n }\n }\n }\n}\n\n// 全局缓存:存储已创建的 WebSocket Observable,实现订阅复用\n// key: encodePath(path, channel, instId)\n// value: shared Observable\nconst wsObservableCache = new Map<string, Observable<any>>();\n\nconst fromWsChannelAndInstId = <T>(path: string, channel: string, instId: string) => {\n const cacheKey = encodePath(path, channel, instId);\n\n // 检查缓存中是否已存在该订阅\n const cached = wsObservableCache.get(cacheKey);\n if (cached) {\n console.info(formatTime(Date.now()), `♻️ Reusing cached subscription: ${cacheKey}`);\n return cached as Observable<T>;\n }\n\n // 创建新的 Observable\n const observable$ = new Observable<T>((subscriber) => {\n const client = OKXWsClient.GetWsClient(path);\n client.subscribe(channel, instId, (data: T) => {\n subscriber.next(data);\n });\n const removeError = client.addConnectionListener('error', (err) => {\n subscriber.error(err);\n });\n const removeClose = client.addConnectionListener('close', () => {\n subscriber.error('WS Connection Closed');\n });\n subscriber.add(() => {\n removeError();\n removeClose();\n client.unsubscribe(channel, instId);\n });\n }).pipe(\n // 防止单个连接断开导致数据流关闭\n timeout(60_000),\n tap({\n error: (err) => {\n console.info(formatTime(Date.now()), 'WS_SUBSCRIBE_ERROR', channel, instId, err);\n },\n }),\n // 暂时不太确定是否能支持 retry\n // retry({ delay: 1000 }),\n catchError(() => EMPTY),\n // 🔑 关键:使用 shareReplay 实现订阅复用\n // - bufferSize: 1 - 缓存最新的一个值,新订阅者可以立即获得最新数据\n // - refCount: true - 当所有订阅者都取消订阅时,自动取消上游订阅并清理资源\n shareReplay({ bufferSize: 1, refCount: true }),\n // 当订阅完全结束时,从缓存中移除\n tap({\n finalize: () => {\n console.info(formatTime(Date.now()), `🗑️ Removing from cache: ${cacheKey}`);\n wsObservableCache.delete(cacheKey);\n },\n }),\n );\n\n // 存入缓存\n wsObservableCache.set(cacheKey, observable$);\n console.info(formatTime(Date.now()), `📦 Cached new subscription: ${cacheKey}`);\n\n return observable$;\n};\n\nexport const useTicker = (instId: string) =>\n fromWsChannelAndInstId<\n {\n instId: string;\n last: string;\n askPx: string;\n bidPx: string;\n askSz: string;\n bidSz: string;\n }[]\n >('ws/v5/public', 'tickers', instId).pipe(\n //\n filter((data) => data.length > 0),\n );\n\nexport const useOpenInterest = (instId: string) =>\n fromWsChannelAndInstId<\n {\n instId: string;\n oi: string; // open interest\n }[]\n >('ws/v5/public', 'open-interest', instId).pipe(\n //\n filter((data) => data.length > 0),\n );\n\nexport const useOHLC = (candleType: string, instId: string) =>\n fromWsChannelAndInstId<string[][]>('ws/v5/business', candleType, instId).pipe(\n //\n filter((data) => data.length > 0),\n );\n\nexport const useMarketBooks = (\n channel: 'books' | 'books5' | 'bbo-tbt' | 'books-l2-tbt' | 'books50-l2-tbt',\n instId: string,\n) =>\n fromWsChannelAndInstId<IWSOrderBook[]>('ws/v5/public', channel, instId).pipe(\n //\n filter((data) => data.length > 0),\n );\n\nexport const useFundingRate = (instId: string) =>\n fromWsChannelAndInstId<\n {\n fundingRate: string;\n fundingTime: string;\n instId: string;\n instType: string;\n method: string;\n maxFundingRate: string;\n minFundingRate: string;\n nextFundingRate: string;\n nextFundingTime: string;\n premium: string;\n settFundingRate: string;\n settState: string;\n ts: string;\n }[]\n >('ws/v5/public', 'funding-rate', instId).pipe(\n //\n filter((data) => data.length > 0),\n );\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuants/vendor-okx",
3
- "version": "0.29.3",
3
+ "version": "0.29.5",
4
4
  "main": "lib/index.js",
5
5
  "files": [
6
6
  "dist",
@@ -1,13 +1,13 @@
1
1
  {
2
- "apps/vendor-okx/CHANGELOG.json": "bdad91c7a85236b7c03f9d9b4abd20f259a863ad",
3
- "apps/vendor-okx/CHANGELOG.md": "0a58ccbc18047e4e99bad810de5751de728c5c4f",
2
+ "apps/vendor-okx/CHANGELOG.json": "8432a1a0d744334101ef0465c4108c8b7385d23e",
3
+ "apps/vendor-okx/CHANGELOG.md": "fed9dc3b7d4b7fc6fee7392d3c4aceb57e66ac77",
4
4
  "apps/vendor-okx/README.md": "68caeb8e383d77ece973cd70f4b167b86abb54c3",
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": "b07c8112a8c5d938cd285e3ad6e79a165db4a417",
10
+ "apps/vendor-okx/package.json": "3a46cbd9b6430ddf9c89559f95cdd3f3805b846e",
11
11
  "apps/vendor-okx/src/account-actions-with-credential.ts": "1a2de787b588e98ceef60b3ffb951f298504bf12",
12
12
  "apps/vendor-okx/src/account.ts": "672014c974457b438cf026f763d6eecfe585c82b",
13
13
  "apps/vendor-okx/src/accountInfos/earning.ts": "62aaeb3b62fa9197d07ee14155625530cdb9b1cd",
@@ -35,17 +35,17 @@
35
35
  "apps/vendor-okx/src/orders/submitOrder.ts": "564c8a659091dfb9676de753f0fceef1ec8ee168",
36
36
  "apps/vendor-okx/src/public-data/interest_rate.ts": "f3171f2753955d500ae00ce7e263ea26e05e5421",
37
37
  "apps/vendor-okx/src/public-data/market-order.ts": "c7269e9fe1f339b320e8b4cd98652854446a245c",
38
- "apps/vendor-okx/src/public-data/new-quote.ts": "703eaa20f74b20365e598666a946a840e015fbe9",
38
+ "apps/vendor-okx/src/public-data/new-quote.ts": "dcfc532ee523247f1c0a8d4f236b9eb81e5b2ece",
39
39
  "apps/vendor-okx/src/public-data/ohlc.ts": "0b5a568e30b3070f74b0e64614e8c1cc9ba507fb",
40
40
  "apps/vendor-okx/src/public-data/product.ts": "9caa1b0d9fa621800870ef47086767f6f5810ad9",
41
- "apps/vendor-okx/src/public-data/quote.ts": "e6a73bb79acbdd57fc5bd0f422a335dc64bf5df3",
41
+ "apps/vendor-okx/src/public-data/quote.ts": "84db94c5af399e03b630037eb13382eb38b8c1e4",
42
42
  "apps/vendor-okx/src/services.ts": "aeaf5f9d0a87347be6150b28961c5a7c0886b1d8",
43
43
  "apps/vendor-okx/src/strategy-account.ts": "2d8f913e19c4402eab249291aaab0b77bc4d9ff8",
44
44
  "apps/vendor-okx/src/trade.ts": "cbb88bc535b8377ecd54a18e39082923fd5a4fda",
45
45
  "apps/vendor-okx/src/transfer.ts": "381e4bf18846c8f79d3e970277d8800a2f94dacd",
46
46
  "apps/vendor-okx/src/utils/provideOHLCFromTimeBackwardService.ts": "3a44206410b5b73683f2395d6c551549b553d7bd",
47
47
  "apps/vendor-okx/src/utils/provideSeriesFromTimeBackwardService.ts": "daf3c793eb4fc20e59a740bb69e50fadab5f62f0",
48
- "apps/vendor-okx/src/ws.ts": "c3e29df777a8d900b0ee2e28ff77c32e0fc541ee",
48
+ "apps/vendor-okx/src/ws.ts": "5e8fe8c97c7da92c08ddf07ab47faf7976433ca3",
49
49
  "apps/vendor-okx/tsconfig.json": "81da8f78196974b5d15da0edb6b2d9f48641063c",
50
50
  "apps/vendor-okx/.rush/temp/shrinkwrap-deps.json": "38417f6f35b760ade667d08782f1175046c7b64d",
51
51
  "libraries/protocol/temp/package-deps.json": "0bd43721e96039b52d7b59c834dc6df45cf75e3f",