@yuants/vendor-okx 0.24.0 → 0.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +253 -0
- package/dist/api/private-api.js.map +1 -1
- package/dist/order-actions-with-credential.js +11 -60
- package/dist/order-actions-with-credential.js.map +1 -1
- package/dist/order-actions.js +1 -1
- package/dist/order-actions.js.map +1 -1
- package/dist/orders/submitOrder.js +1 -1
- package/dist/orders/submitOrder.js.map +1 -1
- package/dist/ws.js +7 -7
- package/dist/ws.js.map +1 -1
- package/lib/api/private-api.js.map +1 -1
- package/lib/order-actions-with-credential.js +11 -60
- package/lib/order-actions-with-credential.js.map +1 -1
- package/lib/order-actions.js +1 -1
- package/lib/order-actions.js.map +1 -1
- package/lib/orders/submitOrder.d.ts +3 -1
- package/lib/orders/submitOrder.d.ts.map +1 -1
- package/lib/orders/submitOrder.js +1 -1
- package/lib/orders/submitOrder.js.map +1 -1
- package/lib/ws.d.ts.map +1 -1
- package/lib/ws.js +6 -6
- package/lib/ws.js.map +1 -1
- package/package.json +3 -3
- package/temp/package-deps.json +11 -11
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"submitOrder.js","sourceRoot":"","sources":["../../src/orders/submitOrder.ts"],"names":[],"mappings":";;;AACA,yCAAoE;AACpE,+BAA2C;AAC3C,oDAAiE;AACjE,oDAAwD;AACxD,gDAA0D;AAE1D,MAAM,uBAAuB,GAAG,CAAC,SAAkB,EAAE,EAAE;IACrD,QAAQ,SAAS,EAAE;QACjB,KAAK,WAAW,CAAC;QACjB,KAAK,aAAa;YAChB,OAAO,KAAK,CAAC;QACf,KAAK,YAAY,CAAC;QAClB,KAAK,YAAY;YACf,OAAO,MAAM,CAAC;KACjB;IACD,MAAM,IAAI,KAAK,CAAC,sBAAsB,SAAS,EAAE,CAAC,CAAC;AACrD,CAAC,CAAC;AAEF,MAAM,0BAA0B,GAAG,CAAC,SAAkB,EAAE,EAAE;IACxD,QAAQ,SAAS,EAAE;QACjB,KAAK,WAAW,CAAC;QACjB,KAAK,YAAY;YACf,OAAO,MAAM,CAAC;QAChB,KAAK,aAAa,CAAC;QACnB,KAAK,YAAY;YACf,OAAO,OAAO,CAAC;KAClB;IACD,MAAM,IAAI,KAAK,CAAC,sBAAsB,SAAS,EAAE,CAAC,CAAC;AACrD,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAAC,UAAmB,EAAE,EAAE;IACpD,QAAQ,UAAU,EAAE;QAClB,KAAK,OAAO;YACV,OAAO,OAAO,CAAC;QACjB,KAAK,QAAQ;YACX,OAAO,QAAQ,CAAC;QAClB,KAAK,OAAO;YACV,OAAO,WAAW,CAAC;KACtB;IACD,MAAM,IAAI,KAAK,CAAC,uBAAuB,UAAU,EAAE,CAAC,CAAC;AACvD,CAAC,CAAC;AAEK,MAAM,WAAW,GAAG,KAAK,EAAE,UAAuB,EAAE,KAAa,
|
|
1
|
+
{"version":3,"file":"submitOrder.js","sourceRoot":"","sources":["../../src/orders/submitOrder.ts"],"names":[],"mappings":"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","sourcesContent":["import { IOrder } from '@yuants/data-order';\nimport { decodePath, formatTime, roundToStep } from '@yuants/utils';\nimport { firstValueFrom, map } from 'rxjs';\nimport { ICredential, postTradeOrder } from '../api/private-api';\nimport { productService } from '../public-data/product';\nimport { spotMarketTickers$ } from '../public-data/quote';\n\nconst mapOrderDirectionToSide = (direction?: string) => {\n switch (direction) {\n case 'OPEN_LONG':\n case 'CLOSE_SHORT':\n return 'buy';\n case 'OPEN_SHORT':\n case 'CLOSE_LONG':\n return 'sell';\n }\n throw new Error(`Unknown direction: ${direction}`);\n};\n\nconst mapOrderDirectionToPosSide = (direction?: string) => {\n switch (direction) {\n case 'OPEN_LONG':\n case 'CLOSE_LONG':\n return 'long';\n case 'CLOSE_SHORT':\n case 'OPEN_SHORT':\n return 'short';\n }\n throw new Error(`Unknown direction: ${direction}`);\n};\n\nconst mapOrderTypeToOrdType = (order_type?: string) => {\n switch (order_type) {\n case 'LIMIT':\n return 'limit';\n case 'MARKET':\n return 'market';\n case 'MAKER':\n return 'post_only';\n }\n throw new Error(`Unknown order type: ${order_type}`);\n};\n\nexport const submitOrder = async (credential: ICredential, order: IOrder): Promise<{ order_id: string }> => {\n const [instType, instId] = decodePath(order.product_id);\n\n // 交易数量,表示要购买或者出售的数量。\n // 当币币/币币杠杆以限价买入和卖出时,指交易货币数量。\n // 当币币杠杆以市价买入时,指计价货币的数量。\n // 当币币杠杆以市价卖出时,指交易货币的数量。\n // 对于币币市价单,单位由 tgtCcy 决定\n // 当交割、永续、期权买入和卖出时,指合约张数。\n const mapOrderVolumeToSz = async (order: IOrder) => {\n if (instType === 'SWAP') {\n return order.volume;\n }\n if (instType === 'MARGIN') {\n if (order.order_type === 'LIMIT') {\n return order.volume;\n }\n if (order.order_type === 'MAKER') {\n return order.volume;\n }\n if (order.order_type === 'MARKET') {\n if (order.order_direction === 'OPEN_SHORT' || order.order_direction === 'CLOSE_LONG') {\n return order.volume;\n }\n //\n const price = await firstValueFrom(\n spotMarketTickers$.pipe(\n map((x) =>\n mapOrderDirectionToPosSide(order.order_direction) === 'long'\n ? +x[instId].askPx\n : +x[instId].bidPx,\n ),\n ),\n );\n if (!price) {\n throw new Error(`invalid tick: ${price}`);\n }\n console.info(formatTime(Date.now()), 'SubmitOrder', 'price', price);\n const theProduct = await firstValueFrom(\n productService.mapProductIdToProduct$.pipe(map((x) => x.get(order.product_id))),\n );\n if (!theProduct) {\n throw new Error(`Unknown product: ${order.position_id}`);\n }\n return roundToStep(order.volume * price, theProduct.volume_step!);\n }\n\n return 0;\n }\n\n if (instType === 'SPOT') {\n return order.volume;\n }\n\n throw new Error(`Unknown instType: ${instType}`);\n };\n\n const params = {\n instId,\n tdMode: instType === 'SPOT' ? 'cash' : 'cross',\n side: mapOrderDirectionToSide(order.order_direction),\n posSide:\n instType === 'MARGIN' || instType === 'SPOT'\n ? 'net'\n : mapOrderDirectionToPosSide(order.order_direction),\n ordType: mapOrderTypeToOrdType(order.order_type),\n sz: (await mapOrderVolumeToSz(order)).toString(),\n tgtCcy: instType === 'SPOT' && order.order_type === 'MARKET' ? 'base_ccy' : undefined,\n reduceOnly:\n instType === 'MARGIN' && ['CLOSE_LONG', 'CLOSE_SHORT'].includes(order.order_direction ?? '')\n ? 'true'\n : undefined,\n px: order.order_type === 'LIMIT' || order.order_type === 'MAKER' ? order.price!.toString() : undefined,\n ccy: instType === 'MARGIN' ? 'USDT' : undefined,\n };\n console.info(formatTime(Date.now()), 'SubmitOrder', 'params', JSON.stringify(params));\n const res = await postTradeOrder(credential, params);\n if (res.code === '0' && res.data?.[0]?.ordId) {\n return { order_id: res.data[0].ordId };\n }\n throw `Failed to submit order: ${res.code} ${res.msg}`;\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;
|
|
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"}
|
package/lib/ws.js
CHANGED
|
@@ -4,8 +4,8 @@ exports.useMarketBooks = exports.useOHLC = exports.useOpenInterest = exports.use
|
|
|
4
4
|
const protocol_1 = require("@yuants/protocol");
|
|
5
5
|
const utils_1 = require("@yuants/utils");
|
|
6
6
|
const rxjs_1 = require("rxjs");
|
|
7
|
-
const MetricsWebSocketConnectionsGauge = protocol_1.
|
|
8
|
-
const MetricsWebSocketChannelGauge = protocol_1.
|
|
7
|
+
const MetricsWebSocketConnectionsGauge = protocol_1.GlobalPrometheusRegistry.gauge('okx_websocket_connections', 'Number of active OKX WebSocket connections');
|
|
8
|
+
const MetricsWebSocketChannelGauge = protocol_1.GlobalPrometheusRegistry.gauge('okx_websocket_channel', 'Number of OKX WebSocket channels subscribed');
|
|
9
9
|
const terminal = protocol_1.Terminal.fromNodeEnv();
|
|
10
10
|
class OKXWsClient {
|
|
11
11
|
constructor(path) {
|
|
@@ -47,7 +47,7 @@ class OKXWsClient {
|
|
|
47
47
|
};
|
|
48
48
|
this.handleClose = (event) => {
|
|
49
49
|
console.error((0, utils_1.formatTime)(Date.now()), '❌ WS closed', event);
|
|
50
|
-
MetricsWebSocketConnectionsGauge.
|
|
50
|
+
MetricsWebSocketConnectionsGauge.labels({ path: this.path }).dec();
|
|
51
51
|
const closedSocket = event.target;
|
|
52
52
|
if (closedSocket !== this.ws) {
|
|
53
53
|
return;
|
|
@@ -107,7 +107,7 @@ class OKXWsClient {
|
|
|
107
107
|
initSocket() {
|
|
108
108
|
this.connectStatus = 'connecting';
|
|
109
109
|
this.ws = new WebSocket(`${this.baseURL}/${this.path}`);
|
|
110
|
-
MetricsWebSocketConnectionsGauge.
|
|
110
|
+
MetricsWebSocketConnectionsGauge.labels({ path: this.path, terminal_id: terminal.terminal_id }).inc();
|
|
111
111
|
this.ws.addEventListener('open', this.handleOpen);
|
|
112
112
|
this.ws.addEventListener('message', this.handleMessage);
|
|
113
113
|
this.ws.addEventListener('error', this.handleError);
|
|
@@ -173,7 +173,7 @@ class OKXWsClient {
|
|
|
173
173
|
return;
|
|
174
174
|
}
|
|
175
175
|
this.subscriptions.set(channelId, { channel, instId });
|
|
176
|
-
MetricsWebSocketChannelGauge.
|
|
176
|
+
MetricsWebSocketChannelGauge.labels({ channel, terminal_id: terminal.terminal_id }).inc();
|
|
177
177
|
if (handler) {
|
|
178
178
|
this.handlers[channelId] = handler;
|
|
179
179
|
}
|
|
@@ -196,7 +196,7 @@ class OKXWsClient {
|
|
|
196
196
|
this.sendUnsubscribeMessage(channel, instId);
|
|
197
197
|
}
|
|
198
198
|
this.subscriptions.delete(channelId);
|
|
199
|
-
MetricsWebSocketChannelGauge.
|
|
199
|
+
MetricsWebSocketChannelGauge.labels({ channel }).dec();
|
|
200
200
|
delete this.handlers[channelId];
|
|
201
201
|
if (this.subscriptions.size === 0) {
|
|
202
202
|
this.stopKeepAlive();
|
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 { PromRegistry, 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 = PromRegistry.create(\n 'gauge',\n 'okx_websocket_connections',\n 'Number of active OKX WebSocket connections',\n);\n\nconst MetricsWebSocketChannelGauge = PromRegistry.create(\n '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.dec({ path: this.path });\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.inc({ path: this.path, terminal_id: terminal.terminal_id });\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.inc({ channel, terminal_id: terminal.terminal_id });\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.dec({ channel });\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"]}
|
|
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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yuants/vendor-okx",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.1",
|
|
4
4
|
"bin": "lib/cli.js",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"files": [
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@yuants/protocol": "0.50.4",
|
|
13
13
|
"@yuants/transfer": "0.2.33",
|
|
14
|
-
"@yuants/data-account": "0.6.
|
|
15
|
-
"@yuants/data-order": "0.
|
|
14
|
+
"@yuants/data-account": "0.6.15",
|
|
15
|
+
"@yuants/data-order": "0.4.0",
|
|
16
16
|
"@yuants/utils": "0.11.0",
|
|
17
17
|
"@yuants/cache": "0.3.0",
|
|
18
18
|
"@yuants/sql": "0.9.24",
|
package/temp/package-deps.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
-
"apps/vendor-okx/CHANGELOG.json": "
|
|
3
|
-
"apps/vendor-okx/CHANGELOG.md": "
|
|
4
|
-
"apps/vendor-okx/README.md": "
|
|
2
|
+
"apps/vendor-okx/CHANGELOG.json": "3491e2eb31b4023a7ae171e5fb4ff86aadd76495",
|
|
3
|
+
"apps/vendor-okx/CHANGELOG.md": "c60466964727ac1537dae62fc40b068539febb79",
|
|
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": "
|
|
10
|
+
"apps/vendor-okx/package.json": "33eb2bb43086d73dad82381d6a4f5ba72aa9a32a",
|
|
11
11
|
"apps/vendor-okx/src/account.ts": "8ebbeb106e1cc935ea153af2e56303e21fd00901",
|
|
12
12
|
"apps/vendor-okx/src/accountInfos/earning.ts": "fbf76a6c2010a371dfc3bdde81dc90ae572473ed",
|
|
13
13
|
"apps/vendor-okx/src/accountInfos/funding.ts": "d9e4e1a104ec6350effc91838b5d9390bae34241",
|
|
@@ -17,17 +17,17 @@
|
|
|
17
17
|
"apps/vendor-okx/src/accountInfos/trading.ts": "febb902e2b8f0f5d0e1071244b18a90a245bfde6",
|
|
18
18
|
"apps/vendor-okx/src/accountInfos/types.ts": "c3c1096c3ad6849f6f679f1dfe0badb3ae876e41",
|
|
19
19
|
"apps/vendor-okx/src/api-service.ts": "f1d977b144b1096965c5990260d9e6c81b08cb8c",
|
|
20
|
-
"apps/vendor-okx/src/api/private-api.ts": "
|
|
20
|
+
"apps/vendor-okx/src/api/private-api.ts": "73ab6b99249ebb73769e903cc356627eaf19b433",
|
|
21
21
|
"apps/vendor-okx/src/api/public-api.ts": "05b9cddafd09b5c9f65ce4eaeab42832e7d60449",
|
|
22
22
|
"apps/vendor-okx/src/cli.ts": "9bf6b5559a6c6f33da20e74cc6c5d702c60ec891",
|
|
23
23
|
"apps/vendor-okx/src/index.ts": "9da8bd730e68bf5ab12dd9357f4214606e050eb1",
|
|
24
24
|
"apps/vendor-okx/src/loan-account.ts": "b5f656ec36d50bc0e394a2387429c59b5f4006c2",
|
|
25
|
-
"apps/vendor-okx/src/order-actions-with-credential.ts": "
|
|
26
|
-
"apps/vendor-okx/src/order-actions.ts": "
|
|
25
|
+
"apps/vendor-okx/src/order-actions-with-credential.ts": "766dfb5ba676b17b773e259d9ff2dba241d7247e",
|
|
26
|
+
"apps/vendor-okx/src/order-actions.ts": "530492e7ae5d2968270f5c4b91bd048ff9ebe9c6",
|
|
27
27
|
"apps/vendor-okx/src/order.ts": "284241de8704c75af2f085fb33b98da3ee891541",
|
|
28
28
|
"apps/vendor-okx/src/orders/cancelOrder.ts": "db8741b6f4ec9caa01bc01748ff297bb1f8b58a7",
|
|
29
29
|
"apps/vendor-okx/src/orders/modifyOrder.ts": "ab30a4b204bcf08c2762541a4bbbf01d0e0f2d1a",
|
|
30
|
-
"apps/vendor-okx/src/orders/submitOrder.ts": "
|
|
30
|
+
"apps/vendor-okx/src/orders/submitOrder.ts": "89660b6b8a2dd6231860857709d3b1cce37187be",
|
|
31
31
|
"apps/vendor-okx/src/public-data/interest_rate.ts": "cd7e761728f504e4bf2b8c791e2bde19810ec46a",
|
|
32
32
|
"apps/vendor-okx/src/public-data/market-order.ts": "c7269e9fe1f339b320e8b4cd98652854446a245c",
|
|
33
33
|
"apps/vendor-okx/src/public-data/ohlc.ts": "0b5a568e30b3070f74b0e64614e8c1cc9ba507fb",
|
|
@@ -39,13 +39,13 @@
|
|
|
39
39
|
"apps/vendor-okx/src/transfer.ts": "5ac6726abf15cd9cfd86ce03ecf8d4c6ca96edb7",
|
|
40
40
|
"apps/vendor-okx/src/utils/provideOHLCFromTimeBackwardService.ts": "3a44206410b5b73683f2395d6c551549b553d7bd",
|
|
41
41
|
"apps/vendor-okx/src/utils/provideSeriesFromTimeBackwardService.ts": "daf3c793eb4fc20e59a740bb69e50fadab5f62f0",
|
|
42
|
-
"apps/vendor-okx/src/ws.ts": "
|
|
42
|
+
"apps/vendor-okx/src/ws.ts": "67e46658d3424cc6bf98e534b86036f33607640d",
|
|
43
43
|
"apps/vendor-okx/tsconfig.json": "81da8f78196974b5d15da0edb6b2d9f48641063c",
|
|
44
44
|
"apps/vendor-okx/.rush/temp/shrinkwrap-deps.json": "d2bbb3cc7c98f79d7add8c772fbe32efcb48b7b7",
|
|
45
45
|
"libraries/protocol/temp/package-deps.json": "35bc77333a1c85db1cd130579963e8cefa00f56c",
|
|
46
46
|
"libraries/transfer/temp/package-deps.json": "708a4caf79d042cad56a39f0b00d399bca04af40",
|
|
47
|
-
"libraries/data-account/temp/package-deps.json": "
|
|
48
|
-
"libraries/data-order/temp/package-deps.json": "
|
|
47
|
+
"libraries/data-account/temp/package-deps.json": "bc6176ac72e51f5deb7f123807852a4305935bcd",
|
|
48
|
+
"libraries/data-order/temp/package-deps.json": "afb45e88841011b7abd71901cda1bda450f36dc5",
|
|
49
49
|
"libraries/utils/temp/package-deps.json": "c58f1ca8f498315d9a0219ca8c498299a41d297b",
|
|
50
50
|
"libraries/cache/temp/package-deps.json": "49789a92426969daa31f0c956bb56bd783929765",
|
|
51
51
|
"libraries/sql/temp/package-deps.json": "e3b6f24485a429fb24cacbf0d6150f55ca394706",
|