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.
- package/LICENSE +21 -0
- package/README.md +242 -0
- package/dist/account/private-websocket.d.ts +13 -0
- package/dist/account/private-websocket.js +102 -0
- package/dist/account/private-websocket.js.map +1 -0
- package/dist/account/service.d.ts +22 -0
- package/dist/account/service.js +118 -0
- package/dist/account/service.js.map +1 -0
- package/dist/account/store.d.ts +12 -0
- package/dist/account/store.js +48 -0
- package/dist/account/store.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +122 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/prompts.d.ts +2 -0
- package/dist/cli/prompts.js +52 -0
- package/dist/cli/prompts.js.map +1 -0
- package/dist/config/loader.d.ts +9 -0
- package/dist/config/loader.js +87 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/paths.d.ts +7 -0
- package/dist/config/paths.js +11 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/config/schema.d.ts +42 -0
- package/dist/config/schema.js +30 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/core/attribution.d.ts +2 -0
- package/dist/core/attribution.js +29 -0
- package/dist/core/attribution.js.map +1 -0
- package/dist/core/errors.d.ts +9 -0
- package/dist/core/errors.js +33 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/okx-client.d.ts +13 -0
- package/dist/core/okx-client.js +102 -0
- package/dist/core/okx-client.js.map +1 -0
- package/dist/core/sanitize.d.ts +2 -0
- package/dist/core/sanitize.js +19 -0
- package/dist/core/sanitize.js.map +1 -0
- package/dist/core/types.d.ts +38 -0
- package/dist/core/types.js +18 -0
- package/dist/core/types.js.map +1 -0
- package/dist/derivatives/service.d.ts +28 -0
- package/dist/derivatives/service.js +144 -0
- package/dist/derivatives/service.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/intelligence/service.d.ts +38 -0
- package/dist/intelligence/service.js +324 -0
- package/dist/intelligence/service.js.map +1 -0
- package/dist/market/indicators.d.ts +2 -0
- package/dist/market/indicators.js +74 -0
- package/dist/market/indicators.js.map +1 -0
- package/dist/market/service.d.ts +28 -0
- package/dist/market/service.js +232 -0
- package/dist/market/service.js.map +1 -0
- package/dist/market/store.d.ts +46 -0
- package/dist/market/store.js +158 -0
- package/dist/market/store.js.map +1 -0
- package/dist/market/websocket.d.ts +33 -0
- package/dist/market/websocket.js +213 -0
- package/dist/market/websocket.js.map +1 -0
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +28 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/runtime/client.d.ts +15 -0
- package/dist/runtime/client.js +106 -0
- package/dist/runtime/client.js.map +1 -0
- package/dist/runtime/server.d.ts +28 -0
- package/dist/runtime/server.js +140 -0
- package/dist/runtime/server.js.map +1 -0
- package/dist/runtime/state.d.ts +14 -0
- package/dist/runtime/state.js +98 -0
- package/dist/runtime/state.js.map +1 -0
- package/dist/storage/database.d.ts +23 -0
- package/dist/storage/database.js +106 -0
- package/dist/storage/database.js.map +1 -0
- package/dist/tools/catalog.d.ts +21 -0
- package/dist/tools/catalog.js +236 -0
- package/dist/tools/catalog.js.map +1 -0
- package/dist/trade/service.d.ts +128 -0
- package/dist/trade/service.js +470 -0
- package/dist/trade/service.js.map +1 -0
- package/examples/claude-code/mcp.json +8 -0
- package/examples/codex/config.toml +3 -0
- package/examples/config.example.json +18 -0
- package/package.json +71 -0
- package/skills/okx-account-analysis/SKILL.md +14 -0
- package/skills/okx-account-analysis/agents/openai.yaml +9 -0
- package/skills/okx-derivatives-analysis/SKILL.md +14 -0
- package/skills/okx-derivatives-analysis/agents/openai.yaml +9 -0
- package/skills/okx-market-analysis/SKILL.md +14 -0
- package/skills/okx-market-analysis/agents/openai.yaml +9 -0
- package/skills/okx-news-intelligence/SKILL.md +14 -0
- package/skills/okx-news-intelligence/agents/openai.yaml +9 -0
- package/skills/okx-smart-money-analysis/SKILL.md +15 -0
- package/skills/okx-smart-money-analysis/agents/openai.yaml +9 -0
- package/skills/okx-trading/SKILL.md +16 -0
- package/skills/okx-trading/agents/openai.yaml +9 -0
- package/skills/trading-philosophy/SKILL.md +14 -0
- package/skills/trading-philosophy/agents/openai.yaml +4 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { accountSummaries, loadConfig, loadStoredConfig, saveConfig } from "../config/loader.js";
|
|
4
|
+
import { CONFIG_PATH } from "../config/paths.js";
|
|
5
|
+
import { OkxClient } from "../core/okx-client.js";
|
|
6
|
+
import { publicError } from "../core/errors.js";
|
|
7
|
+
import { AccountService } from "../account/service.js";
|
|
8
|
+
import { runMcpServer } from "../mcp/server.js";
|
|
9
|
+
import { RuntimeClient } from "../runtime/client.js";
|
|
10
|
+
import { runRuntimeServer } from "../runtime/server.js";
|
|
11
|
+
import { ask, askSecret } from "./prompts.js";
|
|
12
|
+
const program = new Command()
|
|
13
|
+
.name("desic-okx")
|
|
14
|
+
.description("Independent Desic runtime, MCP server, CLI, and skills for OKX")
|
|
15
|
+
.version("0.1.0");
|
|
16
|
+
program.command("start")
|
|
17
|
+
.description("Start or reuse the local runtime")
|
|
18
|
+
.action(async () => {
|
|
19
|
+
const client = await RuntimeClient.connect();
|
|
20
|
+
print(await client.health());
|
|
21
|
+
});
|
|
22
|
+
program.command("daemon", { hidden: true })
|
|
23
|
+
.action(async () => runRuntimeServer());
|
|
24
|
+
program.command("stop")
|
|
25
|
+
.description("Stop the local runtime")
|
|
26
|
+
.action(async () => {
|
|
27
|
+
const client = await RuntimeClient.connect({ start: false });
|
|
28
|
+
await client.stop();
|
|
29
|
+
print({ stopped: true });
|
|
30
|
+
});
|
|
31
|
+
program.command("status")
|
|
32
|
+
.description("Show local runtime status")
|
|
33
|
+
.action(async () => {
|
|
34
|
+
const client = await RuntimeClient.connect({ start: false });
|
|
35
|
+
print(await client.health());
|
|
36
|
+
});
|
|
37
|
+
program.command("mcp")
|
|
38
|
+
.description("Run the stdio MCP adapter")
|
|
39
|
+
.action(async () => runMcpServer());
|
|
40
|
+
program.command("call")
|
|
41
|
+
.description("Call one runtime tool")
|
|
42
|
+
.argument("<tool>", "tool name")
|
|
43
|
+
.option("--json <json>", "JSON input", "{}")
|
|
44
|
+
.action(async (tool, options) => {
|
|
45
|
+
const input = JSON.parse(options.json);
|
|
46
|
+
const client = await RuntimeClient.connect();
|
|
47
|
+
print(await client.call(tool, input));
|
|
48
|
+
});
|
|
49
|
+
program.command("tools")
|
|
50
|
+
.description("List available runtime tools")
|
|
51
|
+
.action(async () => {
|
|
52
|
+
const client = await RuntimeClient.connect();
|
|
53
|
+
print(await client.tools());
|
|
54
|
+
});
|
|
55
|
+
program.command("config-path")
|
|
56
|
+
.description("Print the active configuration path")
|
|
57
|
+
.action(() => {
|
|
58
|
+
process.stdout.write(`${CONFIG_PATH}\n`);
|
|
59
|
+
});
|
|
60
|
+
const account = program.command("account").description("Manage named OKX accounts");
|
|
61
|
+
account.command("add")
|
|
62
|
+
.description("Add or replace a named account")
|
|
63
|
+
.option("--name <name>", "account alias")
|
|
64
|
+
.option("--environment <environment>", "demo or live")
|
|
65
|
+
.action(async (options) => {
|
|
66
|
+
const name = options.name?.trim() || await ask("Account name", "default");
|
|
67
|
+
const environmentValue = options.environment?.trim() || await ask("Environment (demo/live)", "demo");
|
|
68
|
+
if (environmentValue !== "demo" && environmentValue !== "live")
|
|
69
|
+
throw new Error("Environment must be demo or live");
|
|
70
|
+
const apiKey = await askSecret("API Key");
|
|
71
|
+
const secretKey = await askSecret("Secret Key");
|
|
72
|
+
const passphrase = await askSecret("Passphrase");
|
|
73
|
+
if (!apiKey || !secretKey || !passphrase)
|
|
74
|
+
throw new Error("All three credential fields are required");
|
|
75
|
+
const config = loadStoredConfig();
|
|
76
|
+
config.accounts[name] = { environment: environmentValue, apiKey, secretKey, passphrase };
|
|
77
|
+
config.defaultAccount ??= name;
|
|
78
|
+
saveConfig(config);
|
|
79
|
+
await stopForReload();
|
|
80
|
+
print({ saved: true, name, environment: environmentValue, configPath: CONFIG_PATH });
|
|
81
|
+
});
|
|
82
|
+
account.command("list")
|
|
83
|
+
.description("List configured account aliases")
|
|
84
|
+
.action(() => print(accountSummaries(loadConfig())));
|
|
85
|
+
account.command("verify")
|
|
86
|
+
.description("Verify one account and show OKX-reported permissions")
|
|
87
|
+
.option("--name <name>", "account alias")
|
|
88
|
+
.action(async (options) => {
|
|
89
|
+
const config = loadConfig();
|
|
90
|
+
const client = new OkxClient("https://www.okx.com", config.proxy.url);
|
|
91
|
+
const service = new AccountService(config, client);
|
|
92
|
+
print(await service.verify(options.name));
|
|
93
|
+
});
|
|
94
|
+
account.command("remove")
|
|
95
|
+
.description("Remove one account")
|
|
96
|
+
.argument("<name>", "account alias")
|
|
97
|
+
.action(async (name) => {
|
|
98
|
+
const config = loadStoredConfig();
|
|
99
|
+
if (!config.accounts[name])
|
|
100
|
+
throw new Error(`Account '${name}' was not found`);
|
|
101
|
+
delete config.accounts[name];
|
|
102
|
+
if (config.defaultAccount === name)
|
|
103
|
+
config.defaultAccount = Object.keys(config.accounts)[0];
|
|
104
|
+
saveConfig(config);
|
|
105
|
+
await stopForReload();
|
|
106
|
+
print({ removed: true, name });
|
|
107
|
+
});
|
|
108
|
+
program.parseAsync(process.argv).catch((error) => {
|
|
109
|
+
process.stderr.write(`${JSON.stringify({ error: publicError(error) })}\n`);
|
|
110
|
+
process.exitCode = 1;
|
|
111
|
+
});
|
|
112
|
+
async function stopForReload() {
|
|
113
|
+
try {
|
|
114
|
+
const client = await RuntimeClient.connect({ start: false });
|
|
115
|
+
await client.stop();
|
|
116
|
+
}
|
|
117
|
+
catch { }
|
|
118
|
+
}
|
|
119
|
+
function print(value) {
|
|
120
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import readline from "node:readline/promises";
|
|
2
|
+
export async function ask(question, fallback) {
|
|
3
|
+
const suffix = fallback ? ` [${fallback}]` : "";
|
|
4
|
+
const interface_ = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
5
|
+
try {
|
|
6
|
+
const answer = await interface_.question(`${question}${suffix}: `);
|
|
7
|
+
return answer.trim() || fallback || "";
|
|
8
|
+
}
|
|
9
|
+
finally {
|
|
10
|
+
interface_.close();
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export async function askSecret(question) {
|
|
14
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY || typeof process.stdin.setRawMode !== "function") {
|
|
15
|
+
return ask(question);
|
|
16
|
+
}
|
|
17
|
+
process.stdout.write(`${question}: `);
|
|
18
|
+
process.stdin.setRawMode(true);
|
|
19
|
+
process.stdin.resume();
|
|
20
|
+
process.stdin.setEncoding("utf8");
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
let value = "";
|
|
23
|
+
const cleanup = () => {
|
|
24
|
+
process.stdin.off("data", onData);
|
|
25
|
+
process.stdin.setRawMode(false);
|
|
26
|
+
process.stdin.pause();
|
|
27
|
+
process.stdout.write("\n");
|
|
28
|
+
};
|
|
29
|
+
const onData = (chunk) => {
|
|
30
|
+
for (const character of chunk) {
|
|
31
|
+
if (character === "\r" || character === "\n") {
|
|
32
|
+
cleanup();
|
|
33
|
+
resolve(value);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (character === "\u0003") {
|
|
37
|
+
cleanup();
|
|
38
|
+
reject(new Error("Canceled"));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (character === "\u007f" || character === "\b") {
|
|
42
|
+
value = value.slice(0, -1);
|
|
43
|
+
}
|
|
44
|
+
else if (character >= " ") {
|
|
45
|
+
value += character;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
process.stdin.on("data", onData);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/cli/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,wBAAwB,CAAC;AAE9C,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,QAAgB,EAAE,QAAiB;IAC3D,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,QAAQ,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAChD,MAAM,UAAU,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9F,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,GAAG,QAAQ,GAAG,MAAM,IAAI,CAAC,CAAC;QACnE,OAAO,MAAM,CAAC,IAAI,EAAE,IAAI,QAAQ,IAAI,EAAE,CAAC;IACzC,CAAC;YAAS,CAAC;QACT,UAAU,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,QAAgB;IAC9C,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,OAAO,OAAO,CAAC,KAAK,CAAC,UAAU,KAAK,UAAU,EAAE,CAAC;QACpG,OAAO,GAAG,CAAC,QAAQ,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,QAAQ,IAAI,CAAC,CAAC;IACtC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAC/B,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;IACvB,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IAClC,OAAO,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC7C,IAAI,KAAK,GAAG,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,GAAS,EAAE;YACzB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAClC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YAChC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7B,CAAC,CAAC;QACF,MAAM,MAAM,GAAG,CAAC,KAAa,EAAQ,EAAE;YACrC,KAAK,MAAM,SAAS,IAAI,KAAK,EAAE,CAAC;gBAC9B,IAAI,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;oBAC7C,OAAO,EAAE,CAAC;oBACV,OAAO,CAAC,KAAK,CAAC,CAAC;oBACf,OAAO;gBACT,CAAC;gBACD,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;oBAC3B,OAAO,EAAE,CAAC;oBACV,MAAM,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;oBAC9B,OAAO;gBACT,CAAC;gBACD,IAAI,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;oBACjD,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC7B,CAAC;qBAAM,IAAI,SAAS,IAAI,GAAG,EAAE,CAAC;oBAC5B,KAAK,IAAI,SAAS,CAAC;gBACrB,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QACF,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AccountCredentials } from "../core/types.js";
|
|
2
|
+
import { type RuntimeConfig, type StoredAccount } from "./schema.js";
|
|
3
|
+
export declare function loadConfig(configPath?: string): RuntimeConfig;
|
|
4
|
+
export declare function loadStoredConfig(configPath?: string): RuntimeConfig;
|
|
5
|
+
export declare function applyEnvironment(config: RuntimeConfig, env: NodeJS.ProcessEnv): RuntimeConfig;
|
|
6
|
+
export declare function saveConfig(config: RuntimeConfig, configPath?: string): void;
|
|
7
|
+
export declare function resolveAccount(config: RuntimeConfig, requested?: string): AccountCredentials;
|
|
8
|
+
export declare function toStoredAccount(account: AccountCredentials): StoredAccount;
|
|
9
|
+
export declare function accountSummaries(config: RuntimeConfig): Array<Record<string, unknown>>;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { RuntimeError } from "../core/errors.js";
|
|
4
|
+
import { CONFIG_PATH } from "./paths.js";
|
|
5
|
+
import { DEFAULT_CONFIG, RuntimeConfigSchema } from "./schema.js";
|
|
6
|
+
export function loadConfig(configPath = CONFIG_PATH) {
|
|
7
|
+
let raw = {};
|
|
8
|
+
if (fs.existsSync(configPath)) {
|
|
9
|
+
try {
|
|
10
|
+
raw = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
throw new RuntimeError("VALIDATION", `Cannot read config: ${error instanceof Error ? error.message : "invalid JSON"}`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
const parsed = RuntimeConfigSchema.parse(raw);
|
|
17
|
+
return applyEnvironment(parsed, process.env);
|
|
18
|
+
}
|
|
19
|
+
export function loadStoredConfig(configPath = CONFIG_PATH) {
|
|
20
|
+
if (!fs.existsSync(configPath))
|
|
21
|
+
return structuredClone(DEFAULT_CONFIG);
|
|
22
|
+
return RuntimeConfigSchema.parse(JSON.parse(fs.readFileSync(configPath, "utf8")));
|
|
23
|
+
}
|
|
24
|
+
export function applyEnvironment(config, env) {
|
|
25
|
+
const fields = [env.OKX_API_KEY, env.OKX_API_SECRET, env.OKX_API_PASSPHRASE];
|
|
26
|
+
const supplied = fields.filter((value) => Boolean(value?.trim())).length;
|
|
27
|
+
if (supplied > 0 && supplied < 3) {
|
|
28
|
+
throw new RuntimeError("VALIDATION", "OKX_API_KEY, OKX_API_SECRET, and OKX_API_PASSPHRASE must be provided together");
|
|
29
|
+
}
|
|
30
|
+
if (supplied === 0)
|
|
31
|
+
return config;
|
|
32
|
+
const name = env.OKX_ACCOUNT?.trim() || "default";
|
|
33
|
+
const environment = env.OKX_ENVIRONMENT === "live" ? "live" : "demo";
|
|
34
|
+
return RuntimeConfigSchema.parse({
|
|
35
|
+
...config,
|
|
36
|
+
defaultAccount: name,
|
|
37
|
+
accounts: {
|
|
38
|
+
...config.accounts,
|
|
39
|
+
[name]: {
|
|
40
|
+
environment,
|
|
41
|
+
apiKey: env.OKX_API_KEY,
|
|
42
|
+
secretKey: env.OKX_API_SECRET,
|
|
43
|
+
passphrase: env.OKX_API_PASSPHRASE
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
export function saveConfig(config, configPath = CONFIG_PATH) {
|
|
49
|
+
const normalized = RuntimeConfigSchema.parse(config);
|
|
50
|
+
fs.mkdirSync(path.dirname(configPath), { recursive: true, mode: 0o700 });
|
|
51
|
+
const temporary = `${configPath}.${process.pid}.${Date.now()}.tmp`;
|
|
52
|
+
fs.writeFileSync(temporary, `${JSON.stringify(normalized, null, 2)}\n`, { mode: 0o600 });
|
|
53
|
+
fs.chmodSync(temporary, 0o600);
|
|
54
|
+
fs.renameSync(temporary, configPath);
|
|
55
|
+
fs.chmodSync(configPath, 0o600);
|
|
56
|
+
}
|
|
57
|
+
export function resolveAccount(config, requested) {
|
|
58
|
+
const name = requested?.trim() || config.defaultAccount;
|
|
59
|
+
if (!name)
|
|
60
|
+
throw new RuntimeError("AUTH", "No OKX account is configured");
|
|
61
|
+
const account = config.accounts[name];
|
|
62
|
+
if (!account)
|
|
63
|
+
throw new RuntimeError("NOT_FOUND", `OKX account '${name}' was not found`);
|
|
64
|
+
return { name, ...account };
|
|
65
|
+
}
|
|
66
|
+
export function toStoredAccount(account) {
|
|
67
|
+
return {
|
|
68
|
+
environment: account.environment,
|
|
69
|
+
apiKey: account.apiKey,
|
|
70
|
+
secretKey: account.secretKey,
|
|
71
|
+
passphrase: account.passphrase
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export function accountSummaries(config) {
|
|
75
|
+
return Object.entries(config.accounts).map(([name, account]) => ({
|
|
76
|
+
name,
|
|
77
|
+
environment: account.environment,
|
|
78
|
+
default: config.defaultAccount === name,
|
|
79
|
+
apiKey: mask(account.apiKey)
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
function mask(value) {
|
|
83
|
+
if (value.length <= 8)
|
|
84
|
+
return "****";
|
|
85
|
+
return `${value.slice(0, 4)}...${value.slice(-4)}`;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const CONFIG_DIR: string;
|
|
2
|
+
export declare const DATA_DIR: string;
|
|
3
|
+
export declare const RUNTIME_DIR: string;
|
|
4
|
+
export declare const CONFIG_PATH: string;
|
|
5
|
+
export declare const DATABASE_PATH: string;
|
|
6
|
+
export declare const RUNTIME_STATE_PATH: string;
|
|
7
|
+
export declare const RUNTIME_LOCK_PATH: string;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import envPaths from "env-paths";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
const paths = envPaths("desic-okx-agent", { suffix: "" });
|
|
4
|
+
export const CONFIG_DIR = paths.config;
|
|
5
|
+
export const DATA_DIR = paths.data;
|
|
6
|
+
export const RUNTIME_DIR = path.join(paths.data, "run");
|
|
7
|
+
export const CONFIG_PATH = path.join(CONFIG_DIR, "config.json");
|
|
8
|
+
export const DATABASE_PATH = path.join(DATA_DIR, "runtime.sqlite");
|
|
9
|
+
export const RUNTIME_STATE_PATH = path.join(RUNTIME_DIR, "runtime.json");
|
|
10
|
+
export const RUNTIME_LOCK_PATH = path.join(RUNTIME_DIR, "runtime.lock");
|
|
11
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/config/paths.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,WAAW,CAAC;AACjC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,KAAK,GAAG,QAAQ,CAAC,iBAAiB,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;AAE1D,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC;AACvC,MAAM,CAAC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC;AACnC,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AACxD,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAChE,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;AACnE,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;AACzE,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const AccountSchema: z.ZodObject<{
|
|
3
|
+
environment: z.ZodDefault<z.ZodEnum<{
|
|
4
|
+
demo: "demo";
|
|
5
|
+
live: "live";
|
|
6
|
+
}>>;
|
|
7
|
+
apiKey: z.ZodString;
|
|
8
|
+
secretKey: z.ZodString;
|
|
9
|
+
passphrase: z.ZodString;
|
|
10
|
+
}, z.core.$strict>;
|
|
11
|
+
export declare const RuntimeConfigSchema: z.ZodObject<{
|
|
12
|
+
defaultAccount: z.ZodOptional<z.ZodString>;
|
|
13
|
+
accounts: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
14
|
+
environment: z.ZodDefault<z.ZodEnum<{
|
|
15
|
+
demo: "demo";
|
|
16
|
+
live: "live";
|
|
17
|
+
}>>;
|
|
18
|
+
apiKey: z.ZodString;
|
|
19
|
+
secretKey: z.ZodString;
|
|
20
|
+
passphrase: z.ZodString;
|
|
21
|
+
}, z.core.$strict>>>;
|
|
22
|
+
market: z.ZodPrefault<z.ZodObject<{
|
|
23
|
+
prewarm: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
24
|
+
bars: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
25
|
+
idleSubscriptionMs: z.ZodDefault<z.ZodNumber>;
|
|
26
|
+
maxSnapshotSkewMs: z.ZodDefault<z.ZodNumber>;
|
|
27
|
+
orderBookDepth: z.ZodDefault<z.ZodNumber>;
|
|
28
|
+
recentTradeLimit: z.ZodDefault<z.ZodNumber>;
|
|
29
|
+
}, z.core.$strict>>;
|
|
30
|
+
proxy: z.ZodDefault<z.ZodObject<{
|
|
31
|
+
url: z.ZodOptional<z.ZodString>;
|
|
32
|
+
}, z.core.$strict>>;
|
|
33
|
+
intelligence: z.ZodPrefault<z.ZodObject<{
|
|
34
|
+
newsPollSeconds: z.ZodDefault<z.ZodNumber>;
|
|
35
|
+
sentimentPollMinutes: z.ZodDefault<z.ZodNumber>;
|
|
36
|
+
smartMoneyPollMinutes: z.ZodDefault<z.ZodNumber>;
|
|
37
|
+
retentionDays: z.ZodDefault<z.ZodNumber>;
|
|
38
|
+
}, z.core.$strict>>;
|
|
39
|
+
}, z.core.$strict>;
|
|
40
|
+
export type RuntimeConfig = z.infer<typeof RuntimeConfigSchema>;
|
|
41
|
+
export type StoredAccount = z.infer<typeof AccountSchema>;
|
|
42
|
+
export declare const DEFAULT_CONFIG: RuntimeConfig;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const AccountSchema = z.strictObject({
|
|
3
|
+
environment: z.enum(["demo", "live"]).default("demo"),
|
|
4
|
+
apiKey: z.string().min(1),
|
|
5
|
+
secretKey: z.string().min(1),
|
|
6
|
+
passphrase: z.string().min(1)
|
|
7
|
+
});
|
|
8
|
+
export const RuntimeConfigSchema = z.strictObject({
|
|
9
|
+
defaultAccount: z.string().min(1).optional(),
|
|
10
|
+
accounts: z.record(z.string(), AccountSchema).default({}),
|
|
11
|
+
market: z.strictObject({
|
|
12
|
+
prewarm: z.array(z.string().min(1)).default(["BTC-USDT-SWAP", "ETH-USDT-SWAP"]),
|
|
13
|
+
bars: z.array(z.string().min(1)).default(["1m", "5m", "15m", "1H", "4H", "1D"]),
|
|
14
|
+
idleSubscriptionMs: z.number().int().min(60_000).default(900_000),
|
|
15
|
+
maxSnapshotSkewMs: z.number().int().positive().default(1_000),
|
|
16
|
+
orderBookDepth: z.number().int().min(5).max(400).default(50),
|
|
17
|
+
recentTradeLimit: z.number().int().min(10).max(10_000).default(1_000)
|
|
18
|
+
}).prefault({}),
|
|
19
|
+
proxy: z.strictObject({
|
|
20
|
+
url: z.string().url().optional()
|
|
21
|
+
}).default({}),
|
|
22
|
+
intelligence: z.strictObject({
|
|
23
|
+
newsPollSeconds: z.number().int().min(30).default(120),
|
|
24
|
+
sentimentPollMinutes: z.number().int().min(1).default(15),
|
|
25
|
+
smartMoneyPollMinutes: z.number().int().min(1).default(15),
|
|
26
|
+
retentionDays: z.number().int().min(1).default(30)
|
|
27
|
+
}).prefault({})
|
|
28
|
+
});
|
|
29
|
+
export const DEFAULT_CONFIG = RuntimeConfigSchema.parse({});
|
|
30
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,YAAY,CAAC;IAC1C,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IACrD,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACzB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CAC9B,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,YAAY,CAAC;IAChD,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC5C,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,aAAa,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACzD,MAAM,EAAE,CAAC,CAAC,YAAY,CAAC;QACrB,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC;QAC/E,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAC/E,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;QACjE,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;QAC7D,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5D,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;KACtE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC;IACf,KAAK,EAAE,CAAC,CAAC,YAAY,CAAC;QACpB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;KACjC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACd,YAAY,EAAE,CAAC,CAAC,YAAY,CAAC;QAC3B,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;QACtD,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;QACzD,qBAAqB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1D,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;KACnD,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC;CAChB,CAAC,CAAC;AAKH,MAAM,CAAC,MAAM,cAAc,GAAkB,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { RuntimeError } from "./errors.js";
|
|
2
|
+
const ORDER_ATTRIBUTION = "e74f403d5361BCDE";
|
|
3
|
+
const ATTRIBUTED_PATHS = new Set([
|
|
4
|
+
"/api/v5/trade/order",
|
|
5
|
+
"/api/v5/trade/batch-orders",
|
|
6
|
+
"/api/v5/trade/order-algo",
|
|
7
|
+
"/api/v5/trade/close-position"
|
|
8
|
+
]);
|
|
9
|
+
export function applyOrderAttribution(path, body) {
|
|
10
|
+
if (!ATTRIBUTED_PATHS.has(path))
|
|
11
|
+
return body;
|
|
12
|
+
if (Array.isArray(body))
|
|
13
|
+
return body.map((item) => attributedObject(item));
|
|
14
|
+
return attributedObject(body);
|
|
15
|
+
}
|
|
16
|
+
function attributedObject(value) {
|
|
17
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
18
|
+
throw new RuntimeError("VALIDATION", "Attributed OKX requests require an object body");
|
|
19
|
+
}
|
|
20
|
+
const object = value;
|
|
21
|
+
if (Object.keys(object).some((key) => key.toLowerCase() === "tag")) {
|
|
22
|
+
throw new RuntimeError("VALIDATION", "Unsupported order request field");
|
|
23
|
+
}
|
|
24
|
+
return { ...object, tag: ORDER_ATTRIBUTION };
|
|
25
|
+
}
|
|
26
|
+
export function isAttributedPath(path) {
|
|
27
|
+
return ATTRIBUTED_PATHS.has(path);
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=attribution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attribution.js","sourceRoot":"","sources":["../../src/core/attribution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,iBAAiB,GAAG,kBAAkB,CAAC;AAC7C,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;IAC/B,qBAAqB;IACrB,4BAA4B;IAC5B,0BAA0B;IAC1B,8BAA8B;CAC/B,CAAC,CAAC;AAEH,MAAM,UAAU,qBAAqB,CAAC,IAAY,EAAE,IAAa;IAC/D,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7C,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3E,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,YAAY,CAAC,YAAY,EAAE,gDAAgD,CAAC,CAAC;IACzF,CAAC;IACD,MAAM,MAAM,GAAG,KAAgC,CAAC;IAChD,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,EAAE,CAAC;QACnE,MAAM,IAAI,YAAY,CAAC,YAAY,EAAE,iCAAiC,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,iBAAiB,EAAE,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type RuntimeErrorCode = "AUTH" | "PERMISSION" | "RATE_LIMIT" | "STALE_DATA" | "VALIDATION" | "OKX_REJECTED" | "NETWORK" | "AMBIGUOUS_WRITE" | "CAPABILITY_UNAVAILABLE" | "NOT_FOUND" | "INTERNAL";
|
|
2
|
+
export declare class RuntimeError extends Error {
|
|
3
|
+
readonly code: RuntimeErrorCode;
|
|
4
|
+
readonly retryable: boolean;
|
|
5
|
+
readonly details?: Record<string, unknown> | undefined;
|
|
6
|
+
constructor(code: RuntimeErrorCode, message: string, retryable?: boolean, details?: Record<string, unknown> | undefined);
|
|
7
|
+
}
|
|
8
|
+
export declare function classifyOkxError(code: string, message: string): RuntimeError;
|
|
9
|
+
export declare function publicError(error: unknown): Record<string, unknown>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export class RuntimeError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
retryable;
|
|
4
|
+
details;
|
|
5
|
+
constructor(code, message, retryable = false, details) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.code = code;
|
|
8
|
+
this.retryable = retryable;
|
|
9
|
+
this.details = details;
|
|
10
|
+
this.name = "RuntimeError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function classifyOkxError(code, message) {
|
|
14
|
+
const lower = message.toLowerCase();
|
|
15
|
+
if (code === "50011")
|
|
16
|
+
return new RuntimeError("RATE_LIMIT", "OKX rate limit exceeded", true);
|
|
17
|
+
if (code === "50102")
|
|
18
|
+
return new RuntimeError("AUTH", "OKX request timestamp expired", true);
|
|
19
|
+
if (code.startsWith("501") || /api key|passphrase|signature|permission/.test(lower)) {
|
|
20
|
+
return new RuntimeError(lower.includes("permission") ? "PERMISSION" : "AUTH", "OKX authentication or permission rejected");
|
|
21
|
+
}
|
|
22
|
+
if (/timeout|timed out|network|socket|fetch failed/.test(lower)) {
|
|
23
|
+
return new RuntimeError("NETWORK", "OKX is temporarily unreachable", true);
|
|
24
|
+
}
|
|
25
|
+
return new RuntimeError("OKX_REJECTED", `OKX rejected the request (${code})`, false, { okxCode: code });
|
|
26
|
+
}
|
|
27
|
+
export function publicError(error) {
|
|
28
|
+
if (error instanceof RuntimeError) {
|
|
29
|
+
return { code: error.code, message: error.message, retryable: error.retryable, details: error.details ?? {} };
|
|
30
|
+
}
|
|
31
|
+
return { code: "INTERNAL", message: error instanceof Error ? error.message : "Unknown runtime error", retryable: false };
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAaA,MAAM,OAAO,YAAa,SAAQ,KAAK;IAE1B;IAEA;IACA;IAJX,YACW,IAAsB,EAC/B,OAAe,EACN,YAAY,KAAK,EACjB,OAAiC;QAE1C,KAAK,CAAC,OAAO,CAAC,CAAC;QALN,SAAI,GAAJ,IAAI,CAAkB;QAEtB,cAAS,GAAT,SAAS,CAAQ;QACjB,YAAO,GAAP,OAAO,CAA0B;QAG1C,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;IAC7B,CAAC;CACF;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,OAAe;IAC5D,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IACpC,IAAI,IAAI,KAAK,OAAO;QAAE,OAAO,IAAI,YAAY,CAAC,YAAY,EAAE,yBAAyB,EAAE,IAAI,CAAC,CAAC;IAC7F,IAAI,IAAI,KAAK,OAAO;QAAE,OAAO,IAAI,YAAY,CAAC,MAAM,EAAE,+BAA+B,EAAE,IAAI,CAAC,CAAC;IAC7F,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,yCAAyC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACpF,OAAO,IAAI,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,EAAE,2CAA2C,CAAC,CAAC;IAC7H,CAAC;IACD,IAAI,+CAA+C,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAChE,OAAO,IAAI,YAAY,CAAC,SAAS,EAAE,gCAAgC,EAAE,IAAI,CAAC,CAAC;IAC7E,CAAC;IACD,OAAO,IAAI,YAAY,CAAC,cAAc,EAAE,6BAA6B,IAAI,GAAG,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;AAC1G,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IAAI,KAAK,YAAY,YAAY,EAAE,CAAC;QAClC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;IAChH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,uBAAuB,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AAC3H,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AccountCredentials } from "./types.js";
|
|
2
|
+
export declare class OkxClient {
|
|
3
|
+
private readonly baseUrl;
|
|
4
|
+
private timeOffsetMs;
|
|
5
|
+
private readonly dispatcher?;
|
|
6
|
+
constructor(baseUrl?: string, proxyUrl?: string);
|
|
7
|
+
publicGet<T = Record<string, unknown>>(path: string, query?: Record<string, unknown>): Promise<T[]>;
|
|
8
|
+
privateGet<T = Record<string, unknown>>(path: string, account: AccountCredentials, query?: Record<string, unknown>, headers?: Record<string, string>): Promise<T[]>;
|
|
9
|
+
privatePost<T = Record<string, unknown>>(path: string, account: AccountCredentials, body: unknown, attributed?: boolean): Promise<T[]>;
|
|
10
|
+
syncTime(): Promise<void>;
|
|
11
|
+
private request;
|
|
12
|
+
private sign;
|
|
13
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import { ProxyAgent } from "undici";
|
|
3
|
+
import { applyOrderAttribution } from "./attribution.js";
|
|
4
|
+
import { classifyOkxError, RuntimeError } from "./errors.js";
|
|
5
|
+
import { sanitizeValue } from "./sanitize.js";
|
|
6
|
+
export class OkxClient {
|
|
7
|
+
baseUrl;
|
|
8
|
+
timeOffsetMs = 0;
|
|
9
|
+
dispatcher;
|
|
10
|
+
constructor(baseUrl = "https://www.okx.com", proxyUrl) {
|
|
11
|
+
this.baseUrl = baseUrl;
|
|
12
|
+
this.dispatcher = proxyUrl ? new ProxyAgent(proxyUrl) : undefined;
|
|
13
|
+
}
|
|
14
|
+
async publicGet(path, query) {
|
|
15
|
+
return this.request("GET", path, { query });
|
|
16
|
+
}
|
|
17
|
+
async privateGet(path, account, query, headers) {
|
|
18
|
+
return this.request("GET", path, { query, account, headers });
|
|
19
|
+
}
|
|
20
|
+
async privatePost(path, account, body, attributed = false) {
|
|
21
|
+
return this.request("POST", path, { body, account, attributed });
|
|
22
|
+
}
|
|
23
|
+
async syncTime() {
|
|
24
|
+
const sent = Date.now();
|
|
25
|
+
const response = await this.request("GET", "/api/v5/public/time", { timeoutMs: 5_000 });
|
|
26
|
+
const received = Date.now();
|
|
27
|
+
const server = Number(response[0]?.ts);
|
|
28
|
+
if (Number.isFinite(server))
|
|
29
|
+
this.timeOffsetMs = server - Math.round((sent + received) / 2);
|
|
30
|
+
}
|
|
31
|
+
async request(method, path, options, retried = false) {
|
|
32
|
+
const query = buildQuery(options.query);
|
|
33
|
+
const requestPath = `${path}${query}`;
|
|
34
|
+
const attributedBody = options.attributed ? applyOrderAttribution(path, options.body) : options.body;
|
|
35
|
+
const body = method === "POST" ? JSON.stringify(attributedBody ?? {}) : "";
|
|
36
|
+
const headers = { "content-type": "application/json", accept: "application/json", ...options.headers };
|
|
37
|
+
if (options.account)
|
|
38
|
+
this.sign(headers, method, requestPath, body, options.account);
|
|
39
|
+
try {
|
|
40
|
+
const response = await fetch(`${this.baseUrl}${requestPath}`, {
|
|
41
|
+
method,
|
|
42
|
+
headers,
|
|
43
|
+
...(body ? { body } : {}),
|
|
44
|
+
signal: AbortSignal.timeout(options.timeoutMs ?? 12_000),
|
|
45
|
+
...(this.dispatcher ? { dispatcher: this.dispatcher } : {})
|
|
46
|
+
});
|
|
47
|
+
const text = await response.text();
|
|
48
|
+
let envelope;
|
|
49
|
+
try {
|
|
50
|
+
envelope = JSON.parse(text);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
throw new RuntimeError("NETWORK", `OKX returned HTTP ${response.status} with an invalid response`, response.status >= 500);
|
|
54
|
+
}
|
|
55
|
+
const intelligenceSuccess = (path.startsWith("/api/v5/orbit/") || path.startsWith("/api/v5/journal/")) && envelope.code === "1";
|
|
56
|
+
if (!response.ok || (envelope.code !== "0" && !intelligenceSuccess)) {
|
|
57
|
+
if (envelope.code === "50102" && options.account && !retried) {
|
|
58
|
+
await this.syncTime();
|
|
59
|
+
return this.request(method, path, options, true);
|
|
60
|
+
}
|
|
61
|
+
throw classifyOkxError(envelope.code || String(response.status), envelope.msg || text);
|
|
62
|
+
}
|
|
63
|
+
const rows = Array.isArray(envelope.data) ? envelope.data : [envelope.data];
|
|
64
|
+
return sanitizeValue(rows, options.account ? [options.account] : []);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
if (error instanceof RuntimeError)
|
|
68
|
+
throw error;
|
|
69
|
+
const message = error instanceof Error ? error.message : "Unknown network failure";
|
|
70
|
+
throw classifyOkxError("network", message);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
sign(headers, method, requestPath, body, account) {
|
|
74
|
+
const timestamp = new Date(Date.now() + this.timeOffsetMs).toISOString();
|
|
75
|
+
const signature = crypto
|
|
76
|
+
.createHmac("sha256", account.secretKey)
|
|
77
|
+
.update(`${timestamp}${method}${requestPath}${body}`)
|
|
78
|
+
.digest("base64");
|
|
79
|
+
headers["OK-ACCESS-KEY"] = account.apiKey;
|
|
80
|
+
headers["OK-ACCESS-SIGN"] = signature;
|
|
81
|
+
headers["OK-ACCESS-TIMESTAMP"] = timestamp;
|
|
82
|
+
headers["OK-ACCESS-PASSPHRASE"] = account.passphrase;
|
|
83
|
+
if (account.environment === "demo")
|
|
84
|
+
headers["x-simulated-trading"] = "1";
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function buildQuery(query) {
|
|
88
|
+
if (!query)
|
|
89
|
+
return "";
|
|
90
|
+
const params = new URLSearchParams();
|
|
91
|
+
for (const [key, value] of Object.entries(query)) {
|
|
92
|
+
if (value === undefined || value === null || value === "")
|
|
93
|
+
continue;
|
|
94
|
+
if (Array.isArray(value))
|
|
95
|
+
params.set(key, value.join(","));
|
|
96
|
+
else
|
|
97
|
+
params.set(key, String(value));
|
|
98
|
+
}
|
|
99
|
+
const encoded = params.toString();
|
|
100
|
+
return encoded ? `?${encoded}` : "";
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=okx-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"okx-client.js","sourceRoot":"","sources":["../../src/core/okx-client.ts"],"names":[],"mappings":"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"}
|