desic-okx-agent 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +242 -0
  3. package/dist/account/private-websocket.d.ts +13 -0
  4. package/dist/account/private-websocket.js +102 -0
  5. package/dist/account/private-websocket.js.map +1 -0
  6. package/dist/account/service.d.ts +22 -0
  7. package/dist/account/service.js +118 -0
  8. package/dist/account/service.js.map +1 -0
  9. package/dist/account/store.d.ts +12 -0
  10. package/dist/account/store.js +48 -0
  11. package/dist/account/store.js.map +1 -0
  12. package/dist/cli/index.d.ts +2 -0
  13. package/dist/cli/index.js +122 -0
  14. package/dist/cli/index.js.map +1 -0
  15. package/dist/cli/prompts.d.ts +2 -0
  16. package/dist/cli/prompts.js +52 -0
  17. package/dist/cli/prompts.js.map +1 -0
  18. package/dist/config/loader.d.ts +9 -0
  19. package/dist/config/loader.js +87 -0
  20. package/dist/config/loader.js.map +1 -0
  21. package/dist/config/paths.d.ts +7 -0
  22. package/dist/config/paths.js +11 -0
  23. package/dist/config/paths.js.map +1 -0
  24. package/dist/config/schema.d.ts +42 -0
  25. package/dist/config/schema.js +30 -0
  26. package/dist/config/schema.js.map +1 -0
  27. package/dist/core/attribution.d.ts +2 -0
  28. package/dist/core/attribution.js +29 -0
  29. package/dist/core/attribution.js.map +1 -0
  30. package/dist/core/errors.d.ts +9 -0
  31. package/dist/core/errors.js +33 -0
  32. package/dist/core/errors.js.map +1 -0
  33. package/dist/core/okx-client.d.ts +13 -0
  34. package/dist/core/okx-client.js +102 -0
  35. package/dist/core/okx-client.js.map +1 -0
  36. package/dist/core/sanitize.d.ts +2 -0
  37. package/dist/core/sanitize.js +19 -0
  38. package/dist/core/sanitize.js.map +1 -0
  39. package/dist/core/types.d.ts +38 -0
  40. package/dist/core/types.js +18 -0
  41. package/dist/core/types.js.map +1 -0
  42. package/dist/derivatives/service.d.ts +28 -0
  43. package/dist/derivatives/service.js +144 -0
  44. package/dist/derivatives/service.js.map +1 -0
  45. package/dist/index.d.ts +4 -0
  46. package/dist/index.js +5 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/intelligence/service.d.ts +38 -0
  49. package/dist/intelligence/service.js +324 -0
  50. package/dist/intelligence/service.js.map +1 -0
  51. package/dist/market/indicators.d.ts +2 -0
  52. package/dist/market/indicators.js +74 -0
  53. package/dist/market/indicators.js.map +1 -0
  54. package/dist/market/service.d.ts +28 -0
  55. package/dist/market/service.js +232 -0
  56. package/dist/market/service.js.map +1 -0
  57. package/dist/market/store.d.ts +46 -0
  58. package/dist/market/store.js +158 -0
  59. package/dist/market/store.js.map +1 -0
  60. package/dist/market/websocket.d.ts +33 -0
  61. package/dist/market/websocket.js +213 -0
  62. package/dist/market/websocket.js.map +1 -0
  63. package/dist/mcp/server.d.ts +1 -0
  64. package/dist/mcp/server.js +28 -0
  65. package/dist/mcp/server.js.map +1 -0
  66. package/dist/runtime/client.d.ts +15 -0
  67. package/dist/runtime/client.js +106 -0
  68. package/dist/runtime/client.js.map +1 -0
  69. package/dist/runtime/server.d.ts +28 -0
  70. package/dist/runtime/server.js +140 -0
  71. package/dist/runtime/server.js.map +1 -0
  72. package/dist/runtime/state.d.ts +14 -0
  73. package/dist/runtime/state.js +98 -0
  74. package/dist/runtime/state.js.map +1 -0
  75. package/dist/storage/database.d.ts +23 -0
  76. package/dist/storage/database.js +106 -0
  77. package/dist/storage/database.js.map +1 -0
  78. package/dist/tools/catalog.d.ts +21 -0
  79. package/dist/tools/catalog.js +236 -0
  80. package/dist/tools/catalog.js.map +1 -0
  81. package/dist/trade/service.d.ts +128 -0
  82. package/dist/trade/service.js +470 -0
  83. package/dist/trade/service.js.map +1 -0
  84. package/examples/claude-code/mcp.json +8 -0
  85. package/examples/codex/config.toml +3 -0
  86. package/examples/config.example.json +18 -0
  87. package/package.json +71 -0
  88. package/skills/okx-account-analysis/SKILL.md +14 -0
  89. package/skills/okx-account-analysis/agents/openai.yaml +9 -0
  90. package/skills/okx-derivatives-analysis/SKILL.md +14 -0
  91. package/skills/okx-derivatives-analysis/agents/openai.yaml +9 -0
  92. package/skills/okx-market-analysis/SKILL.md +14 -0
  93. package/skills/okx-market-analysis/agents/openai.yaml +9 -0
  94. package/skills/okx-news-intelligence/SKILL.md +14 -0
  95. package/skills/okx-news-intelligence/agents/openai.yaml +9 -0
  96. package/skills/okx-smart-money-analysis/SKILL.md +15 -0
  97. package/skills/okx-smart-money-analysis/agents/openai.yaml +9 -0
  98. package/skills/okx-trading/SKILL.md +16 -0
  99. package/skills/okx-trading/agents/openai.yaml +9 -0
  100. package/skills/trading-philosophy/SKILL.md +14 -0
  101. package/skills/trading-philosophy/agents/openai.yaml +4 -0
@@ -0,0 +1,19 @@
1
+ const PRIVATE_KEYS = /^(tag|api[-_]?key|secret(?:[-_]?key)?|passphrase|ok-access-(?:key|sign|passphrase))$/i;
2
+ export function sanitizeValue(value, accounts = []) {
3
+ const secrets = [...accounts].flatMap((account) => [account.apiKey, account.secretKey, account.passphrase]).filter(Boolean);
4
+ return sanitizeInner(value, secrets);
5
+ }
6
+ function sanitizeInner(value, secrets) {
7
+ if (Array.isArray(value))
8
+ return value.map((item) => sanitizeInner(item, secrets));
9
+ if (value && typeof value === "object") {
10
+ return Object.fromEntries(Object.entries(value)
11
+ .filter(([key]) => !PRIVATE_KEYS.test(key))
12
+ .map(([key, item]) => [key, sanitizeInner(item, secrets)]));
13
+ }
14
+ if (typeof value === "string") {
15
+ return secrets.reduce((text, secret) => (secret ? text.split(secret).join("[REDACTED]") : text), value);
16
+ }
17
+ return value;
18
+ }
19
+ //# sourceMappingURL=sanitize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitize.js","sourceRoot":"","sources":["../../src/core/sanitize.ts"],"names":[],"mappings":"AAEA,MAAM,YAAY,GAAG,uFAAuF,CAAC;AAE7G,MAAM,UAAU,aAAa,CAAI,KAAQ,EAAE,WAAyC,EAAE;IACpF,MAAM,OAAO,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC5H,OAAO,aAAa,CAAC,KAAK,EAAE,OAAO,CAAM,CAAC;AAC5C,CAAC;AAED,SAAS,aAAa,CAAC,KAAc,EAAE,OAAiB;IACtD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IACnF,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvC,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;aAClB,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;aAC1C,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAC7D,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;IAC1G,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,38 @@
1
+ export type OkxEnvironment = "demo" | "live";
2
+ export interface AccountCredentials {
3
+ name: string;
4
+ environment: OkxEnvironment;
5
+ apiKey: string;
6
+ secretKey: string;
7
+ passphrase: string;
8
+ }
9
+ export type DataSource = "memory" | "rest" | "websocket" | "sqlite" | "derived" | "mixed";
10
+ export interface ResultMeta {
11
+ requestId: string;
12
+ environment: OkxEnvironment | "public";
13
+ source: DataSource;
14
+ exchangeTs: number | null;
15
+ receivedAt: number;
16
+ ageMs: number | null;
17
+ warnings: string[];
18
+ account?: string;
19
+ }
20
+ export interface ToolResult<T = unknown> {
21
+ data: T;
22
+ meta: ResultMeta;
23
+ }
24
+ export interface OkxEnvelope<T = Record<string, unknown>> {
25
+ code: string;
26
+ msg: string;
27
+ data: T[];
28
+ inTime?: string;
29
+ outTime?: string;
30
+ }
31
+ export interface TimedValue<T> {
32
+ value: T;
33
+ exchangeTs: number;
34
+ receivedAt: number;
35
+ source: DataSource;
36
+ }
37
+ export declare function requestId(): string;
38
+ export declare function resultMeta(options: Partial<ResultMeta> & Pick<ResultMeta, "source">): ResultMeta;
@@ -0,0 +1,18 @@
1
+ export function requestId() {
2
+ return crypto.randomUUID();
3
+ }
4
+ export function resultMeta(options) {
5
+ const receivedAt = options.receivedAt ?? Date.now();
6
+ const exchangeTs = options.exchangeTs ?? null;
7
+ return {
8
+ requestId: options.requestId ?? requestId(),
9
+ environment: options.environment ?? "public",
10
+ source: options.source,
11
+ exchangeTs,
12
+ receivedAt,
13
+ ageMs: exchangeTs === null ? null : Math.max(0, receivedAt - exchangeTs),
14
+ warnings: options.warnings ?? [],
15
+ ...(options.account ? { account: options.account } : {})
16
+ };
17
+ }
18
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AA2CA,MAAM,UAAU,SAAS;IACvB,OAAO,MAAM,CAAC,UAAU,EAAE,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAyD;IAClF,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;IACpD,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC;IAC9C,OAAO;QACL,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,SAAS,EAAE;QAC3C,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,QAAQ;QAC5C,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,UAAU;QACV,UAAU;QACV,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;QACxE,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,EAAE;QAChC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACzD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { OkxClient } from "../core/okx-client.js";
2
+ import { type ToolResult } from "../core/types.js";
3
+ import type { RuntimeDatabase } from "../storage/database.js";
4
+ export interface DerivativesQuery {
5
+ instId: string;
6
+ period?: string;
7
+ begin?: number;
8
+ end?: number;
9
+ limit?: number;
10
+ }
11
+ export declare class DerivativesService {
12
+ private readonly client;
13
+ private readonly database;
14
+ private nextRubikAt;
15
+ private rubikChain;
16
+ constructor(client: OkxClient, database: RuntimeDatabase);
17
+ positioning(query: DerivativesQuery): Promise<ToolResult<unknown[]>>;
18
+ takerFlow(query: DerivativesQuery): Promise<ToolResult<unknown[]>>;
19
+ crowding(query: DerivativesQuery): Promise<ToolResult<Record<string, unknown>>>;
20
+ fundingBasis(query: DerivativesQuery): Promise<ToolResult<Record<string, unknown>>>;
21
+ liquidations(query: DerivativesQuery): Promise<ToolResult<unknown[]>>;
22
+ systemStress(query: DerivativesQuery): Promise<ToolResult<Record<string, unknown>>>;
23
+ positionChanges(query: DerivativesQuery): Promise<ToolResult<unknown[]>>;
24
+ consensus(query: DerivativesQuery): Promise<ToolResult<Record<string, unknown>>>;
25
+ decisionSnapshot(query: DerivativesQuery): Promise<ToolResult<Record<string, unknown>>>;
26
+ private rubik;
27
+ private persist;
28
+ }
@@ -0,0 +1,144 @@
1
+ import crypto from "node:crypto";
2
+ import { resultMeta } from "../core/types.js";
3
+ export class DerivativesService {
4
+ client;
5
+ database;
6
+ nextRubikAt = 0;
7
+ rubikChain = Promise.resolve();
8
+ constructor(client, database) {
9
+ this.client = client;
10
+ this.database = database;
11
+ }
12
+ async positioning(query) {
13
+ const data = await this.rubik("/api/v5/rubik/stat/contracts/open-interest-history", query);
14
+ this.persist("positioning", query.instId, data);
15
+ return wrap(data);
16
+ }
17
+ async takerFlow(query) {
18
+ const data = await this.rubik("/api/v5/rubik/stat/taker-volume-contract", query, { unit: "2" });
19
+ this.persist("taker_flow", query.instId, data);
20
+ return wrap(data);
21
+ }
22
+ async crowding(query) {
23
+ const paths = [
24
+ "/api/v5/rubik/stat/contracts/long-short-account-ratio-contract",
25
+ "/api/v5/rubik/stat/contracts/long-short-account-ratio-contract-top-trader",
26
+ "/api/v5/rubik/stat/contracts/long-short-position-ratio-contract-top-trader"
27
+ ];
28
+ const [accountRatio, topAccountRatio, topPositionRatio] = await Promise.all(paths.map((path) => this.rubik(path, query)));
29
+ const data = { accountRatio, topAccountRatio, topPositionRatio };
30
+ this.persist("crowding", query.instId, [data]);
31
+ return wrap(data);
32
+ }
33
+ async fundingBasis(query) {
34
+ const family = query.instId.replace(/-SWAP$/, "");
35
+ const [current, history, premium, mark, index] = await Promise.all([
36
+ this.client.publicGet("/api/v5/public/funding-rate", { instId: query.instId }),
37
+ this.client.publicGet("/api/v5/public/funding-rate-history", { instId: query.instId, limit: Math.min(query.limit ?? 100, 100) }),
38
+ this.client.publicGet("/api/v5/public/premium-history", common(query)),
39
+ this.client.publicGet("/api/v5/public/mark-price", { instType: "SWAP", instId: query.instId }),
40
+ this.client.publicGet("/api/v5/market/index-tickers", { instId: family })
41
+ ]);
42
+ const data = { current, history, premium, mark, index };
43
+ this.persist("funding_basis", query.instId, [data]);
44
+ return wrap(data);
45
+ }
46
+ async liquidations(query) {
47
+ const data = await this.client.publicGet("/api/v5/public/liquidation-orders", {
48
+ instType: "SWAP",
49
+ instFamily: query.instId.replace(/-SWAP$/, ""),
50
+ state: "filled",
51
+ limit: Math.min(query.limit ?? 100, 100)
52
+ });
53
+ this.persist("liquidations", query.instId, data);
54
+ return wrap(data);
55
+ }
56
+ async systemStress(query) {
57
+ const family = query.instId.replace(/-SWAP$/, "");
58
+ const [insuranceFund, priceLimit, positionTiers] = await Promise.all([
59
+ this.client.publicGet("/api/v5/public/insurance-fund", { instType: "SWAP", instFamily: family }),
60
+ this.client.publicGet("/api/v5/public/price-limit", { instId: query.instId }),
61
+ this.client.publicGet("/api/v5/public/position-tiers", { instType: "SWAP", tdMode: "cross", instFamily: family })
62
+ ]);
63
+ const data = { insuranceFund, priceLimit, positionTiers };
64
+ this.persist("system_stress", query.instId, [data]);
65
+ return wrap(data);
66
+ }
67
+ async positionChanges(query) {
68
+ const positioning = await this.positioning(query);
69
+ const rows = normalizeRows(positioning.data);
70
+ const data = rows.slice(1).map((row, index) => {
71
+ const previous = rows[index];
72
+ const currentOi = numeric(row[1] ?? row.oi);
73
+ const previousOi = numeric(previous[1] ?? previous.oi);
74
+ return { current: row, previous, absoluteChange: currentOi - previousOi, percentChange: previousOi ? (currentOi - previousOi) / previousOi : null };
75
+ });
76
+ return { data, meta: { ...positioning.meta, source: "derived" } };
77
+ }
78
+ async consensus(query) {
79
+ const [crowding, taker, positioning] = await Promise.all([this.crowding(query), this.takerFlow(query), this.positionChanges(query)]);
80
+ return {
81
+ data: { crowding: crowding.data, takerFlow: taker.data, positionChanges: positioning.data },
82
+ meta: resultMeta({ source: "derived" })
83
+ };
84
+ }
85
+ async decisionSnapshot(query) {
86
+ const [positioning, takerFlow, fundingBasis, liquidations, systemStress, crowding] = await Promise.all([
87
+ this.positioning(query), this.takerFlow(query), this.fundingBasis(query), this.liquidations(query), this.systemStress(query), this.crowding(query)
88
+ ]);
89
+ return {
90
+ data: { instId: query.instId, asOf: Date.now(), positioning: positioning.data, takerFlow: takerFlow.data, fundingBasis: fundingBasis.data, liquidations: liquidations.data, systemStress: systemStress.data, crowding: crowding.data },
91
+ meta: resultMeta({ source: "mixed" })
92
+ };
93
+ }
94
+ async rubik(path, query, extra = {}) {
95
+ let release;
96
+ const previous = this.rubikChain;
97
+ this.rubikChain = new Promise((resolve) => { release = resolve; });
98
+ await previous;
99
+ try {
100
+ const wait = this.nextRubikAt - Date.now();
101
+ if (wait > 0)
102
+ await new Promise((resolve) => setTimeout(resolve, wait));
103
+ return await this.client.publicGet(path, { ...common(query), ...extra });
104
+ }
105
+ finally {
106
+ this.nextRubikAt = Date.now() + 420;
107
+ release();
108
+ }
109
+ }
110
+ persist(kind, instId, values) {
111
+ for (const value of values) {
112
+ const text = JSON.stringify(value);
113
+ const id = crypto.createHash("sha256").update(`${kind}:${instId}:${text}`).digest("hex").slice(0, 24);
114
+ const timestamp = extractTimestamp(value) ?? Date.now();
115
+ this.database.upsertIntelligence(`derivatives:${kind}:${instId}`, id, timestamp, value);
116
+ }
117
+ }
118
+ }
119
+ function common(query) {
120
+ return { instId: query.instId, period: query.period ?? "5m", begin: query.begin, end: query.end, limit: Math.min(query.limit ?? 100, 100) };
121
+ }
122
+ function wrap(data) {
123
+ return { data, meta: resultMeta({ source: "rest" }) };
124
+ }
125
+ function normalizeRows(values) {
126
+ return values.filter(Array.isArray);
127
+ }
128
+ function numeric(value) {
129
+ const parsed = Number(value ?? 0);
130
+ return Number.isFinite(parsed) ? parsed : 0;
131
+ }
132
+ function extractTimestamp(value) {
133
+ if (Array.isArray(value)) {
134
+ const parsed = Number(value[0]);
135
+ return Number.isFinite(parsed) ? parsed : undefined;
136
+ }
137
+ if (value && typeof value === "object") {
138
+ const object = value;
139
+ const parsed = Number(object.ts ?? object.timestamp ?? object.fundingTime);
140
+ return Number.isFinite(parsed) ? parsed : undefined;
141
+ }
142
+ return undefined;
143
+ }
144
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/derivatives/service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export * from "./core/errors.js";
2
+ export * from "./core/types.js";
3
+ export * from "./runtime/client.js";
4
+ export * from "./tools/catalog.js";
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export * from "./core/errors.js";
2
+ export * from "./core/types.js";
3
+ export * from "./runtime/client.js";
4
+ export * from "./tools/catalog.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC"}
@@ -0,0 +1,38 @@
1
+ import type { AccountService } from "../account/service.js";
2
+ import type { ToolResult } from "../core/types.js";
3
+ import type { OkxClient } from "../core/okx-client.js";
4
+ import type { DerivativesService } from "../derivatives/service.js";
5
+ import type { MarketService } from "../market/service.js";
6
+ import type { RuntimeDatabase } from "../storage/database.js";
7
+ import type { RuntimeConfig } from "../config/schema.js";
8
+ export declare class IntelligenceService {
9
+ private readonly config;
10
+ private readonly client;
11
+ private readonly accounts;
12
+ private readonly database;
13
+ private readonly market;
14
+ private readonly derivatives;
15
+ private readonly pollTimers;
16
+ private polling;
17
+ constructor(config: RuntimeConfig, client: OkxClient, accounts: AccountService, database: RuntimeDatabase, market: MarketService, derivatives: DerivativesService);
18
+ start(): void;
19
+ stop(): void;
20
+ newsList(args: Record<string, unknown>): Promise<ToolResult<unknown[]>>;
21
+ newsDetail(args: Record<string, unknown>): Promise<ToolResult<unknown[]>>;
22
+ newsSources(args: Record<string, unknown>): Promise<ToolResult<unknown[]>>;
23
+ sentiment(args: Record<string, unknown>, trend?: boolean): Promise<ToolResult<unknown[]>>;
24
+ sentimentRanking(args: Record<string, unknown>): Promise<ToolResult<unknown[]>>;
25
+ economicCalendar(args: Record<string, unknown>): Promise<ToolResult<unknown[]>>;
26
+ listEvents(args: Record<string, unknown>): ToolResult<unknown[]>;
27
+ readEvent(args: Record<string, unknown>): ToolResult<unknown>;
28
+ marketReaction(args: Record<string, unknown>): Promise<ToolResult<Record<string, unknown>>>;
29
+ anomalies(args: Record<string, unknown>): Promise<ToolResult<unknown[]>>;
30
+ dailyBriefing(args: Record<string, unknown>): Promise<ToolResult<Record<string, unknown>>>;
31
+ smart(operation: SmartOperation, args: Record<string, unknown>): Promise<ToolResult<unknown[]>>;
32
+ private fetchExperimental;
33
+ private local;
34
+ private liveAccount;
35
+ private persist;
36
+ private schedulePoll;
37
+ }
38
+ export type SmartOperation = "list_traders" | "search_trader" | "read_performance" | "read_positions" | "read_position_history" | "read_order_history" | "read_signal_overview_by_filter" | "read_signal_overview_by_trader" | "read_signal_trend_by_filter" | "read_signal_trend_by_trader";
@@ -0,0 +1,324 @@
1
+ import crypto from "node:crypto";
2
+ import { resultMeta } from "../core/types.js";
3
+ import { RuntimeError } from "../core/errors.js";
4
+ const PATHS = {
5
+ news: "/api/v5/orbit/news-search",
6
+ newsDetail: "/api/v5/orbit/news-detail",
7
+ newsSources: "/api/v5/orbit/news-platform",
8
+ sentiment: "/api/v5/orbit/currency-sentiment-query",
9
+ sentimentRanking: "/api/v5/orbit/currency-sentiment-ranking",
10
+ calendar: "/api/v5/public/economic-calendar",
11
+ traders: "/api/v5/orbit/public/leaderboard",
12
+ traderSearch: "/api/v5/orbit/top-trader-search",
13
+ positions: "/api/v5/orbit/public/position-current",
14
+ positionHistory: "/api/v5/orbit/public/position-history",
15
+ orderHistory: "/api/v5/orbit/public/trade-records",
16
+ signalOverview: "/api/v5/journal/smartmoney/overview",
17
+ signalTrend: "/api/v5/journal/smartmoney/signal-history"
18
+ };
19
+ export class IntelligenceService {
20
+ config;
21
+ client;
22
+ accounts;
23
+ database;
24
+ market;
25
+ derivatives;
26
+ pollTimers = new Set();
27
+ polling = false;
28
+ constructor(config, client, accounts, database, market, derivatives) {
29
+ this.config = config;
30
+ this.client = client;
31
+ this.accounts = accounts;
32
+ this.database = database;
33
+ this.market = market;
34
+ this.derivatives = derivatives;
35
+ }
36
+ start() {
37
+ if (!this.config.defaultAccount || this.config.accounts[this.config.defaultAccount]?.environment !== "live")
38
+ return;
39
+ this.polling = true;
40
+ this.schedulePoll(this.config.intelligence.newsPollSeconds * 1_000, () => this.newsList({ account: this.config.defaultAccount, limit: 50 }));
41
+ this.schedulePoll(this.config.intelligence.sentimentPollMinutes * 60_000, () => this.sentimentRanking({ account: this.config.defaultAccount, limit: 50 }));
42
+ this.schedulePoll(this.config.intelligence.smartMoneyPollMinutes * 60_000, () => this.smart("list_traders", { account: this.config.defaultAccount, limit: 50 }));
43
+ }
44
+ stop() {
45
+ this.polling = false;
46
+ for (const timer of this.pollTimers)
47
+ clearTimeout(timer);
48
+ this.pollTimers.clear();
49
+ }
50
+ async newsList(args) {
51
+ return this.fetchExperimental("news", PATHS.news, args, {
52
+ sortBy: args.sortBy ?? (args.keyword ? "relevant" : "latest"),
53
+ keyword: args.keyword,
54
+ importance: args.importance,
55
+ platform: args.platform,
56
+ ccyList: csv(args.coins),
57
+ sentiment: args.sentiment,
58
+ begin: args.begin,
59
+ end: args.end,
60
+ detailLvl: args.detailLevel ?? "summary",
61
+ limit: clamp(args.limit, 1, 100, 30),
62
+ cursor: args.after
63
+ });
64
+ }
65
+ async newsDetail(args) {
66
+ if (!args.id)
67
+ throw new RuntimeError("VALIDATION", "id is required");
68
+ return this.fetchExperimental("news_detail", PATHS.newsDetail, args, { id: args.id });
69
+ }
70
+ async newsSources(args) {
71
+ return this.fetchExperimental("news_source", PATHS.newsSources, args, {});
72
+ }
73
+ async sentiment(args, trend = false) {
74
+ const coins = csv(args.coins ?? args.ccy);
75
+ if (!coins)
76
+ throw new RuntimeError("VALIDATION", "coins is required");
77
+ return this.fetchExperimental("sentiment", PATHS.sentiment, args, {
78
+ ccy: coins,
79
+ period: args.period ?? (trend ? "1h" : "24h"),
80
+ inclTrend: trend ? "true" : undefined,
81
+ limit: trend ? clamp(args.limit, 1, 500, 24) : undefined
82
+ });
83
+ }
84
+ async sentimentRanking(args) {
85
+ return this.fetchExperimental("sentiment_ranking", PATHS.sentimentRanking, args, {
86
+ period: args.period ?? "24h",
87
+ sortBy: args.sortBy ?? "hot",
88
+ limit: clamp(args.limit, 1, 50, 20)
89
+ });
90
+ }
91
+ async economicCalendar(args) {
92
+ return this.fetchExperimental("calendar", PATHS.calendar, args, {
93
+ region: args.region,
94
+ importance: args.importance,
95
+ before: args.begin,
96
+ after: args.end,
97
+ limit: clamp(args.limit, 1, 100, 50)
98
+ });
99
+ }
100
+ listEvents(args) {
101
+ const since = Number(args.since ?? Date.now() - 7 * 86_400_000);
102
+ const articles = this.database.queryIntelligence("news", 1_000, since);
103
+ const events = clusterNews(articles).slice(0, clamp(args.limit, 1, 200, 50));
104
+ return { data: events, meta: resultMeta({ source: "derived" }) };
105
+ }
106
+ readEvent(args) {
107
+ if (!args.id)
108
+ throw new RuntimeError("VALIDATION", "id is required");
109
+ const event = this.listEvents({ limit: 1_000 }).data.find((item) => item.id === args.id);
110
+ if (!event)
111
+ throw new RuntimeError("NOT_FOUND", `News event '${String(args.id)}' was not found`);
112
+ return { data: event, meta: resultMeta({ source: "derived" }) };
113
+ }
114
+ async marketReaction(args) {
115
+ const event = this.readEvent(args).data;
116
+ const coins = Array.isArray(event.coins) ? event.coins.map(String) : [];
117
+ const instId = String(args.instId ?? `${coins[0] ?? "BTC"}-USDT-SWAP`);
118
+ const candles = await this.market.getCandles(instId, String(args.bar ?? "5m"), clamp(args.limit, 20, 300, 100));
119
+ const rows = candles.data;
120
+ const first = Number(rows[0]?.[4]);
121
+ const last = Number(rows.at(-1)?.[4]);
122
+ return {
123
+ data: { event, instId, from: first, to: last, absoluteChange: last - first, percentChange: first ? (last - first) / first : null, candles: rows },
124
+ meta: { ...candles.meta, source: "derived" }
125
+ };
126
+ }
127
+ async anomalies(args) {
128
+ const instId = String(args.instId ?? "BTC-USDT-SWAP");
129
+ const changes = await this.derivatives.positionChanges({ instId, period: String(args.period ?? "5m"), limit: clamp(args.limit, 10, 100, 50) });
130
+ const threshold = Number(args.threshold ?? 0.03);
131
+ const data = changes.data.filter((item) => Math.abs(Number(item.percentChange ?? 0)) >= threshold);
132
+ return { data, meta: { ...changes.meta, source: "derived" } };
133
+ }
134
+ async dailyBriefing(args) {
135
+ const instId = String(args.instId ?? "BTC-USDT-SWAP");
136
+ const [news, ranking, derivatives] = await Promise.all([
137
+ this.newsList({ ...args, limit: clamp(args.newsLimit, 1, 100, 30) }),
138
+ this.sentimentRanking({ ...args, limit: 20 }),
139
+ this.derivatives.decisionSnapshot({ instId, period: String(args.period ?? "5m"), limit: 50 })
140
+ ]);
141
+ return { data: { asOf: Date.now(), instId, news: news.data, sentimentRanking: ranking.data, derivatives: derivatives.data }, meta: resultMeta({ source: "mixed" }) };
142
+ }
143
+ async smart(operation, args) {
144
+ const mapping = smartRequest(operation, args);
145
+ return this.fetchExperimental(`smart:${operation}`, mapping.path, args, mapping.query);
146
+ }
147
+ async fetchExperimental(kind, path, args, query) {
148
+ if (args.localOnly === true)
149
+ return this.local(kind, args);
150
+ const account = this.liveAccount(typeof args.account === "string" ? args.account : undefined);
151
+ try {
152
+ const data = await this.client.privateGet(path, account, query, {
153
+ "Accept-Language": typeof args.language === "string" ? args.language : "en-US"
154
+ });
155
+ this.persist(kind, data);
156
+ return {
157
+ data,
158
+ meta: resultMeta({ source: "rest", account: account.name, environment: account.environment })
159
+ };
160
+ }
161
+ catch (error) {
162
+ const local = this.database.queryIntelligence(kind, clamp(args.limit, 1, 1_000, 100), Number(args.since ?? 0));
163
+ if (local.length) {
164
+ return {
165
+ data: local,
166
+ meta: resultMeta({ source: "sqlite", account: account.name, environment: account.environment, warnings: ["Remote intelligence capability is unavailable; returned local history"] })
167
+ };
168
+ }
169
+ const message = error instanceof Error ? error.message : "Unknown upstream response";
170
+ throw new RuntimeError("CAPABILITY_UNAVAILABLE", `Experimental OKX intelligence capability is unavailable: ${message}`, true);
171
+ }
172
+ }
173
+ local(kind, args) {
174
+ return {
175
+ data: this.database.queryIntelligence(kind, clamp(args.limit, 1, 1_000, 100), Number(args.since ?? 0)),
176
+ meta: resultMeta({ source: "sqlite" })
177
+ };
178
+ }
179
+ liveAccount(name) {
180
+ const account = this.accounts.account(name);
181
+ if (account.environment !== "live") {
182
+ throw new RuntimeError("CAPABILITY_UNAVAILABLE", "News and Smart Money require a live read-only OKX account");
183
+ }
184
+ return account;
185
+ }
186
+ persist(kind, data) {
187
+ for (const item of flattenItems(data)) {
188
+ const timestamp = itemTimestamp(item) ?? Date.now();
189
+ const id = itemId(kind, item);
190
+ this.database.upsertIntelligence(kind, id, timestamp, item);
191
+ }
192
+ }
193
+ schedulePoll(intervalMs, operation) {
194
+ let timer;
195
+ const run = () => {
196
+ this.pollTimers.delete(timer);
197
+ void operation().catch(() => undefined).finally(() => {
198
+ if (!this.polling)
199
+ return;
200
+ timer = setTimeout(run, intervalMs);
201
+ timer.unref();
202
+ this.pollTimers.add(timer);
203
+ });
204
+ };
205
+ timer = setTimeout(run, Math.min(5_000, intervalMs));
206
+ timer.unref();
207
+ this.pollTimers.add(timer);
208
+ }
209
+ }
210
+ function smartRequest(operation, args) {
211
+ const common = {
212
+ sortType: args.sortType ?? "pnl",
213
+ period: args.period ?? "7",
214
+ pnl: args.pnl,
215
+ winRatio: args.winRatio,
216
+ maxRetreat: args.maxRetreat,
217
+ asset: args.asset,
218
+ lmtNum: args.lmtNum
219
+ };
220
+ switch (operation) {
221
+ case "list_traders":
222
+ return { path: PATHS.traders, query: { ...common, period: args.period ?? "90", after: args.after, before: args.before, limit: clamp(args.limit, 1, 100, 20) } };
223
+ case "search_trader":
224
+ return { path: PATHS.traderSearch, query: { keyword: args.keyword } };
225
+ case "read_performance":
226
+ return { path: PATHS.traders, query: { authorIds: csv(args.authorIds ?? args.authorId), sortType: args.sortType ?? "pnl", period: args.period ?? "90" } };
227
+ case "read_positions":
228
+ return { path: PATHS.positions, query: { authorId: args.authorId, instCcy: args.instId } };
229
+ case "read_position_history":
230
+ return { path: PATHS.positionHistory, query: { authorId: args.authorId, instCcy: args.instId, after: args.after, before: args.before, limit: clamp(args.limit, 1, 100, 50) } };
231
+ case "read_order_history":
232
+ return { path: PATHS.orderHistory, query: { authorId: args.authorId, instCcy: args.instId, after: args.after, before: args.before, limit: clamp(args.limit, 1, 100, 50) } };
233
+ case "read_signal_overview_by_filter":
234
+ case "read_signal_overview_by_trader":
235
+ return { path: PATHS.signalOverview, query: { ...common, authorIds: csv(args.authorIds ?? args.authorId), instCcyList: csv(args.instCcyList), topInstruments: args.topInstruments ?? 20 } };
236
+ case "read_signal_trend_by_filter":
237
+ case "read_signal_trend_by_trader":
238
+ return { path: PATHS.signalTrend, query: { ...common, authorIds: csv(args.authorIds ?? args.authorId), instId: args.instId, dataVersion: args.dataVersion, granularity: args.granularity ?? "1h", limit: clamp(args.limit, 1, 500, 24) } };
239
+ }
240
+ }
241
+ function flattenItems(data) {
242
+ const result = [];
243
+ const visit = (value) => {
244
+ if (Array.isArray(value))
245
+ value.forEach(visit);
246
+ else if (value && typeof value === "object") {
247
+ const object = value;
248
+ const nested = object.items ?? object.list ?? object.newsList ?? object.result;
249
+ if (Array.isArray(nested))
250
+ nested.forEach(visit);
251
+ else
252
+ result.push(object);
253
+ }
254
+ };
255
+ data.forEach(visit);
256
+ return result;
257
+ }
258
+ function clusterNews(articles) {
259
+ const sorted = [...articles].sort((a, b) => (itemTimestamp(b) ?? 0) - (itemTimestamp(a) ?? 0));
260
+ const events = [];
261
+ for (const article of sorted) {
262
+ const title = String(article.title ?? article.headline ?? article.name ?? "Untitled");
263
+ const timestamp = itemTimestamp(article) ?? Date.now();
264
+ const coins = values(article.coins ?? article.ccyList ?? article.ccy);
265
+ const tokens = titleTokens(title);
266
+ const match = events.find((event) => Math.abs(event.lastPublishedAt - timestamp) <= 12 * 3_600_000 && overlaps(event.coins, coins) && jaccard(event.tokens, tokens) >= 0.45);
267
+ if (match) {
268
+ match.articles.push(article);
269
+ match.firstPublishedAt = Math.min(match.firstPublishedAt, timestamp);
270
+ match.lastPublishedAt = Math.max(match.lastPublishedAt, timestamp);
271
+ match.coins = [...new Set([...match.coins, ...coins])];
272
+ }
273
+ else {
274
+ events.push({ id: itemId("event", { title, timestamp, coins }), title, coins, firstPublishedAt: timestamp, lastPublishedAt: timestamp, articles: [article], tokens });
275
+ }
276
+ }
277
+ return events.map(({ tokens: _tokens, ...event }) => ({ ...event, articleCount: event.articles.length, sourceCount: new Set(event.articles.map((item) => String(item.platform ?? item.source ?? "unknown"))).size }));
278
+ }
279
+ function titleTokens(value) {
280
+ return new Set(value.toLowerCase().replace(/[^a-z0-9\u4e00-\u9fff]+/g, " ").split(/\s+/).filter((token) => token.length > 1));
281
+ }
282
+ function jaccard(a, b) {
283
+ if (!a.size || !b.size)
284
+ return 0;
285
+ const intersection = [...a].filter((value) => b.has(value)).length;
286
+ return intersection / (a.size + b.size - intersection);
287
+ }
288
+ function overlaps(a, b) {
289
+ return a.length === 0 || b.length === 0 || a.some((value) => b.includes(value));
290
+ }
291
+ function csv(value) {
292
+ if (Array.isArray(value))
293
+ return value.map(String).filter(Boolean).join(",") || undefined;
294
+ if (value === undefined || value === null || value === "")
295
+ return undefined;
296
+ return String(value);
297
+ }
298
+ function values(value) {
299
+ if (Array.isArray(value))
300
+ return value.map(String);
301
+ if (typeof value === "string")
302
+ return value.split(",").map((item) => item.trim()).filter(Boolean);
303
+ return [];
304
+ }
305
+ function clamp(value, min, max, fallback) {
306
+ const parsed = Number(value);
307
+ if (!Number.isFinite(parsed))
308
+ return fallback;
309
+ return Math.min(max, Math.max(min, Math.floor(parsed)));
310
+ }
311
+ function itemTimestamp(item) {
312
+ const parsed = Number(item.publishTime ?? item.publishedAt ?? item.eventTime ?? item.ts ?? item.timestamp ?? item.updateTime);
313
+ return Number.isFinite(parsed) ? parsed : undefined;
314
+ }
315
+ function itemId(kind, item) {
316
+ if (item && typeof item === "object") {
317
+ const object = item;
318
+ const existing = object.id ?? object.newsId ?? object.authorId ?? object.eventId;
319
+ if (existing)
320
+ return String(existing);
321
+ }
322
+ return crypto.createHash("sha256").update(`${kind}:${JSON.stringify(item)}`).digest("hex").slice(0, 24);
323
+ }
324
+ //# sourceMappingURL=service.js.map