desic-okx-agent 0.2.0 → 0.3.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 (237) hide show
  1. package/README.en.md +353 -0
  2. package/README.md +194 -190
  3. package/dist/account/private-websocket.js +4 -4
  4. package/dist/account/private-websocket.js.map +1 -1
  5. package/dist/account/service.d.ts +12 -1
  6. package/dist/account/service.js +18 -0
  7. package/dist/account/service.js.map +1 -1
  8. package/dist/bars/rate-limiter.d.ts +18 -0
  9. package/dist/bars/rate-limiter.js +84 -0
  10. package/dist/bars/rate-limiter.js.map +1 -0
  11. package/dist/bars/schema.d.ts +36 -0
  12. package/dist/bars/schema.js +134 -0
  13. package/dist/bars/schema.js.map +1 -0
  14. package/dist/bars/service.d.ts +60 -0
  15. package/dist/bars/service.js +120 -0
  16. package/dist/bars/service.js.map +1 -0
  17. package/dist/bars/store.d.ts +105 -0
  18. package/dist/bars/store.js +415 -0
  19. package/dist/bars/store.js.map +1 -0
  20. package/dist/bars/timeframe.d.ts +40 -0
  21. package/dist/bars/timeframe.js +146 -0
  22. package/dist/bars/timeframe.js.map +1 -0
  23. package/dist/bars/types.d.ts +68 -0
  24. package/dist/bars/types.js +13 -0
  25. package/dist/bars/types.js.map +1 -0
  26. package/dist/cli/data-render.d.ts +37 -0
  27. package/dist/cli/data-render.js +143 -0
  28. package/dist/cli/data-render.js.map +1 -0
  29. package/dist/cli/doctor.js +7 -3
  30. package/dist/cli/doctor.js.map +1 -1
  31. package/dist/cli/index.js +758 -27
  32. package/dist/cli/index.js.map +1 -1
  33. package/dist/cli/live-render.d.ts +24 -0
  34. package/dist/cli/live-render.js +85 -0
  35. package/dist/cli/live-render.js.map +1 -0
  36. package/dist/cli/range.d.ts +28 -0
  37. package/dist/cli/range.js +63 -0
  38. package/dist/cli/range.js.map +1 -0
  39. package/dist/cli/render.js +3 -0
  40. package/dist/cli/render.js.map +1 -1
  41. package/dist/cli/strategy-render.d.ts +36 -0
  42. package/dist/cli/strategy-render.js +391 -0
  43. package/dist/cli/strategy-render.js.map +1 -0
  44. package/dist/cli/width.d.ts +18 -0
  45. package/dist/cli/width.js +71 -0
  46. package/dist/cli/width.js.map +1 -0
  47. package/dist/config/loader.js +1 -1
  48. package/dist/config/schema.d.ts +7 -0
  49. package/dist/config/schema.js +24 -0
  50. package/dist/config/schema.js.map +1 -1
  51. package/dist/core/okx-client.d.ts +9 -1
  52. package/dist/core/okx-client.js +14 -5
  53. package/dist/core/okx-client.js.map +1 -1
  54. package/dist/i18n/locale.d.ts +24 -0
  55. package/dist/i18n/locale.js +65 -0
  56. package/dist/i18n/locale.js.map +1 -0
  57. package/dist/i18n/messages.d.ts +333 -0
  58. package/dist/i18n/messages.js +660 -0
  59. package/dist/i18n/messages.js.map +1 -0
  60. package/dist/live/account-snapshot.d.ts +30 -0
  61. package/dist/live/account-snapshot.js +130 -0
  62. package/dist/live/account-snapshot.js.map +1 -0
  63. package/dist/live/cutoff-queue.d.ts +42 -0
  64. package/dist/live/cutoff-queue.js +69 -0
  65. package/dist/live/cutoff-queue.js.map +1 -0
  66. package/dist/live/execution-key.d.ts +23 -0
  67. package/dist/live/execution-key.js +31 -0
  68. package/dist/live/execution-key.js.map +1 -0
  69. package/dist/live/failures.d.ts +37 -0
  70. package/dist/live/failures.js +57 -0
  71. package/dist/live/failures.js.map +1 -0
  72. package/dist/live/gates.d.ts +65 -0
  73. package/dist/live/gates.js +136 -0
  74. package/dist/live/gates.js.map +1 -0
  75. package/dist/live/loop.d.ts +56 -0
  76. package/dist/live/loop.js +197 -0
  77. package/dist/live/loop.js.map +1 -0
  78. package/dist/live/preconditions.d.ts +48 -0
  79. package/dist/live/preconditions.js +69 -0
  80. package/dist/live/preconditions.js.map +1 -0
  81. package/dist/live/reconcile.d.ts +46 -0
  82. package/dist/live/reconcile.js +104 -0
  83. package/dist/live/reconcile.js.map +1 -0
  84. package/dist/live/runner.d.ts +57 -0
  85. package/dist/live/runner.js +160 -0
  86. package/dist/live/runner.js.map +1 -0
  87. package/dist/live/schema.d.ts +18 -0
  88. package/dist/live/schema.js +91 -0
  89. package/dist/live/schema.js.map +1 -0
  90. package/dist/live/service.d.ts +144 -0
  91. package/dist/live/service.js +303 -0
  92. package/dist/live/service.js.map +1 -0
  93. package/dist/live/session.d.ts +85 -0
  94. package/dist/live/session.js +234 -0
  95. package/dist/live/session.js.map +1 -0
  96. package/dist/live/sizing.d.ts +62 -0
  97. package/dist/live/sizing.js +79 -0
  98. package/dist/live/sizing.js.map +1 -0
  99. package/dist/live/store.d.ts +123 -0
  100. package/dist/live/store.js +350 -0
  101. package/dist/live/store.js.map +1 -0
  102. package/dist/live/types.d.ts +82 -0
  103. package/dist/live/types.js +2 -0
  104. package/dist/live/types.js.map +1 -0
  105. package/dist/market/websocket.d.ts +16 -1
  106. package/dist/market/websocket.js +60 -5
  107. package/dist/market/websocket.js.map +1 -1
  108. package/dist/mcp/server.d.ts +1 -0
  109. package/dist/mcp/server.js +15 -1
  110. package/dist/mcp/server.js.map +1 -1
  111. package/dist/network/connectivity.d.ts +9 -1
  112. package/dist/network/connectivity.js +28 -1
  113. package/dist/network/connectivity.js.map +1 -1
  114. package/dist/report/chart-script.d.ts +12 -0
  115. package/dist/report/chart-script.js +146 -0
  116. package/dist/report/chart-script.js.map +1 -0
  117. package/dist/report/compare-html.d.ts +8 -0
  118. package/dist/report/compare-html.js +254 -0
  119. package/dist/report/compare-html.js.map +1 -0
  120. package/dist/report/compare-script.d.ts +12 -0
  121. package/dist/report/compare-script.js +109 -0
  122. package/dist/report/compare-script.js.map +1 -0
  123. package/dist/report/compare.d.ts +61 -0
  124. package/dist/report/compare.js +205 -0
  125. package/dist/report/compare.js.map +1 -0
  126. package/dist/report/fetch.d.ts +20 -0
  127. package/dist/report/fetch.js +56 -0
  128. package/dist/report/fetch.js.map +1 -0
  129. package/dist/report/html.d.ts +54 -0
  130. package/dist/report/html.js +641 -0
  131. package/dist/report/html.js.map +1 -0
  132. package/dist/report/open.d.ts +42 -0
  133. package/dist/report/open.js +114 -0
  134. package/dist/report/open.js.map +1 -0
  135. package/dist/runtime/server.d.ts +16 -1
  136. package/dist/runtime/server.js +112 -9
  137. package/dist/runtime/server.js.map +1 -1
  138. package/dist/setup/installer.d.ts +1 -0
  139. package/dist/setup/installer.js +8 -0
  140. package/dist/setup/installer.js.map +1 -1
  141. package/dist/setup/wizard.d.ts +3 -0
  142. package/dist/setup/wizard.js +131 -6
  143. package/dist/setup/wizard.js.map +1 -1
  144. package/dist/strategy/constants.d.ts +23 -0
  145. package/dist/strategy/constants.js +24 -0
  146. package/dist/strategy/constants.js.map +1 -0
  147. package/dist/strategy/environment.d.ts +52 -0
  148. package/dist/strategy/environment.js +187 -0
  149. package/dist/strategy/environment.js.map +1 -0
  150. package/dist/strategy/instrument.d.ts +29 -0
  151. package/dist/strategy/instrument.js +39 -0
  152. package/dist/strategy/instrument.js.map +1 -0
  153. package/dist/strategy/optimize.d.ts +73 -0
  154. package/dist/strategy/optimize.js +113 -0
  155. package/dist/strategy/optimize.js.map +1 -0
  156. package/dist/strategy/parameter-space.d.ts +59 -0
  157. package/dist/strategy/parameter-space.js +221 -0
  158. package/dist/strategy/parameter-space.js.map +1 -0
  159. package/dist/strategy/python-bridge.d.ts +24 -0
  160. package/dist/strategy/python-bridge.js +114 -0
  161. package/dist/strategy/python-bridge.js.map +1 -0
  162. package/dist/strategy/schema.d.ts +9 -0
  163. package/dist/strategy/schema.js +91 -0
  164. package/dist/strategy/schema.js.map +1 -0
  165. package/dist/strategy/service.d.ts +138 -0
  166. package/dist/strategy/service.js +745 -0
  167. package/dist/strategy/service.js.map +1 -0
  168. package/dist/strategy/settings.d.ts +162 -0
  169. package/dist/strategy/settings.js +243 -0
  170. package/dist/strategy/settings.js.map +1 -0
  171. package/dist/strategy/store.d.ts +96 -0
  172. package/dist/strategy/store.js +367 -0
  173. package/dist/strategy/store.js.map +1 -0
  174. package/dist/strategy/templates.d.ts +11 -0
  175. package/dist/strategy/templates.js +134 -0
  176. package/dist/strategy/templates.js.map +1 -0
  177. package/dist/strategy/types.d.ts +111 -0
  178. package/dist/strategy/types.js +2 -0
  179. package/dist/strategy/types.js.map +1 -0
  180. package/dist/tools/catalog.d.ts +16 -0
  181. package/dist/tools/catalog.js +118 -17
  182. package/dist/tools/catalog.js.map +1 -1
  183. package/dist/trade/service.d.ts +12 -0
  184. package/dist/trade/service.js +24 -7
  185. package/dist/trade/service.js.map +1 -1
  186. package/dist/tui/app.d.ts +23 -0
  187. package/dist/tui/app.js +322 -0
  188. package/dist/tui/app.js.map +1 -0
  189. package/dist/tui/commands.d.ts +70 -0
  190. package/dist/tui/commands.js +313 -0
  191. package/dist/tui/commands.js.map +1 -0
  192. package/dist/tui/entries.d.ts +17 -0
  193. package/dist/tui/entries.js +24 -0
  194. package/dist/tui/entries.js.map +1 -0
  195. package/dist/tui/execute.d.ts +26 -0
  196. package/dist/tui/execute.js +664 -0
  197. package/dist/tui/execute.js.map +1 -0
  198. package/dist/tui/history.d.ts +17 -0
  199. package/dist/tui/history.js +48 -0
  200. package/dist/tui/history.js.map +1 -0
  201. package/dist/tui/index.d.ts +8 -0
  202. package/dist/tui/index.js +48 -0
  203. package/dist/tui/index.js.map +1 -0
  204. package/dist/tui/line-editor.d.ts +44 -0
  205. package/dist/tui/line-editor.js +98 -0
  206. package/dist/tui/line-editor.js.map +1 -0
  207. package/dist/tui/progress.d.ts +23 -0
  208. package/dist/tui/progress.js +46 -0
  209. package/dist/tui/progress.js.map +1 -0
  210. package/dist/tui/settings-editor.d.ts +18 -0
  211. package/dist/tui/settings-editor.js +115 -0
  212. package/dist/tui/settings-editor.js.map +1 -0
  213. package/docs/live-trading.md +455 -0
  214. package/docs/strategy-research.md +597 -0
  215. package/package.json +11 -1
  216. package/python/desic_strategy/__init__.py +34 -0
  217. package/python/desic_strategy/actions.py +158 -0
  218. package/python/desic_strategy/context.py +164 -0
  219. package/python/desic_strategy/engine.py +614 -0
  220. package/python/desic_strategy/indicators.py +159 -0
  221. package/python/desic_strategy/live.py +253 -0
  222. package/python/desic_strategy/policy.py +193 -0
  223. package/python/desic_strategy/portfolio.py +152 -0
  224. package/python/desic_strategy/report.py +319 -0
  225. package/python/desic_strategy/runner.py +574 -0
  226. package/python/desic_strategy/timeframe.py +150 -0
  227. package/python/main.py +18 -0
  228. package/skills/okx-live-trading/SKILL.md +117 -0
  229. package/skills/okx-live-trading/agents/openai.yaml +9 -0
  230. package/skills/okx-live-trading/references/lifecycle.md +128 -0
  231. package/skills/okx-strategy-research/SKILL.md +113 -0
  232. package/skills/okx-strategy-research/agents/openai.yaml +9 -0
  233. package/skills/okx-strategy-research/references/execution-semantics.md +107 -0
  234. package/skills/okx-strategy-research/references/field-traps.md +142 -0
  235. package/skills/okx-strategy-research/references/python-api.md +121 -0
  236. package/skills/okx-strategy-research/references/tools-and-data.md +192 -0
  237. package/skills/okx-trading/SKILL.md +11 -10
@@ -1 +1 @@
1
- {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/account/service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/account/service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ export declare class PublicRestLimiter {
2
+ private readonly maxConcurrent;
3
+ private readonly now;
4
+ private readonly sleep;
5
+ private readonly buckets;
6
+ private active;
7
+ private readonly waiting;
8
+ constructor(maxConcurrent?: number, now?: () => number, sleep?: (ms: number) => Promise<void>);
9
+ /**
10
+ * Runs `task` once a concurrency slot is free and the endpoint's minimum
11
+ * spacing has elapsed. The slot is always released, so a rejected task
12
+ * cannot wedge the limiter.
13
+ */
14
+ run<T>(path: string, task: () => Promise<T>): Promise<T>;
15
+ private acquire;
16
+ private release;
17
+ private waitForBucket;
18
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Minimum spacing and concurrency ceiling for OKX public REST reads.
3
+ *
4
+ * A full backfill issues thousands of `history-candles` pages back to back,
5
+ * which trips OKX rate limiting long before it finishes. These values are the
6
+ * ones that proved stable in production use of the desktop terminal: spacing
7
+ * is applied per endpoint bucket, and a global semaphore caps concurrency
8
+ * across all buckets.
9
+ */
10
+ const DEFAULT_MIN_INTERVAL_MS = 80;
11
+ const MARKET_CANDLES_MIN_INTERVAL_MS = 60;
12
+ const HISTORY_CANDLES_MIN_INTERVAL_MS = 120;
13
+ const MAX_CONCURRENT = 4;
14
+ export class PublicRestLimiter {
15
+ maxConcurrent;
16
+ now;
17
+ sleep;
18
+ buckets = new Map();
19
+ active = 0;
20
+ waiting = [];
21
+ constructor(maxConcurrent = MAX_CONCURRENT, now = Date.now, sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))) {
22
+ this.maxConcurrent = maxConcurrent;
23
+ this.now = now;
24
+ this.sleep = sleep;
25
+ }
26
+ /**
27
+ * Runs `task` once a concurrency slot is free and the endpoint's minimum
28
+ * spacing has elapsed. The slot is always released, so a rejected task
29
+ * cannot wedge the limiter.
30
+ */
31
+ async run(path, task) {
32
+ await this.acquire();
33
+ try {
34
+ await this.waitForBucket(path);
35
+ return await task();
36
+ }
37
+ finally {
38
+ this.release();
39
+ }
40
+ }
41
+ async acquire() {
42
+ if (this.active < this.maxConcurrent) {
43
+ this.active += 1;
44
+ return;
45
+ }
46
+ await new Promise((resolve) => this.waiting.push(resolve));
47
+ this.active += 1;
48
+ }
49
+ release() {
50
+ this.active -= 1;
51
+ const next = this.waiting.shift();
52
+ if (next)
53
+ next();
54
+ }
55
+ async waitForBucket(path) {
56
+ const key = bucketKey(path);
57
+ const minIntervalMs = minIntervalFor(key);
58
+ const bucket = this.buckets.get(key) ?? { minIntervalMs, nextAllowedAt: 0 };
59
+ const now = this.now();
60
+ // Reserve this bucket's slot before awaiting so concurrent callers queue
61
+ // behind each other instead of all reading the same stale timestamp.
62
+ const startAt = Math.max(now, bucket.nextAllowedAt);
63
+ bucket.nextAllowedAt = startAt + minIntervalMs;
64
+ this.buckets.set(key, bucket);
65
+ const delay = startAt - now;
66
+ if (delay > 0)
67
+ await this.sleep(delay);
68
+ }
69
+ }
70
+ function bucketKey(path) {
71
+ if (path.startsWith("/api/v5/market/history-candles"))
72
+ return "history-candles";
73
+ if (path.startsWith("/api/v5/market/candles"))
74
+ return "candles";
75
+ return "default";
76
+ }
77
+ function minIntervalFor(key) {
78
+ if (key === "history-candles")
79
+ return HISTORY_CANDLES_MIN_INTERVAL_MS;
80
+ if (key === "candles")
81
+ return MARKET_CANDLES_MIN_INTERVAL_MS;
82
+ return DEFAULT_MIN_INTERVAL_MS;
83
+ }
84
+ //# sourceMappingURL=rate-limiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/bars/rate-limiter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Strategy-research storage schema.
3
+ *
4
+ * Only confirmed one-minute bars are persisted. Every higher timeframe is
5
+ * derived by aggregating this single source, so a backtest and a live
6
+ * evaluation can never disagree about a bucket boundary.
7
+ *
8
+ * Prices are stored as TEXT exactly as OKX returned them. Parsing them into
9
+ * IEEE-754 doubles before storage would make `dataHash` unstable across
10
+ * platforms and would silently lose precision that the exchange reported.
11
+ */
12
+ export declare const BAR_SCHEMA_SQL = "\nCREATE TABLE IF NOT EXISTS bars_1m (\n -- demo | live. Part of the key because the two are separate matching venues with\n -- separate feeds: the same instrument and minute genuinely has different OHLCV in\n -- each, so one row per (environment, instrument, minute) is the only way both can\n -- be stored without one overwriting the other.\n environment TEXT NOT NULL DEFAULT 'live',\n inst_id TEXT NOT NULL,\n open_time INTEGER NOT NULL,\n close_time INTEGER NOT NULL,\n open TEXT NOT NULL,\n high TEXT NOT NULL,\n low TEXT NOT NULL,\n close TEXT NOT NULL,\n volume TEXT NOT NULL,\n source TEXT NOT NULL,\n updated_at INTEGER NOT NULL,\n PRIMARY KEY(environment, inst_id, open_time)\n) WITHOUT ROWID;\n\nCREATE TABLE IF NOT EXISTS bar_coverage (\n environment TEXT NOT NULL DEFAULT 'live',\n inst_id TEXT NOT NULL,\n oldest_open INTEGER NOT NULL,\n newest_open INTEGER NOT NULL,\n bar_count INTEGER NOT NULL,\n exhausted_before INTEGER,\n updated_at INTEGER NOT NULL,\n PRIMARY KEY(environment, inst_id)\n);\n\nCREATE TABLE IF NOT EXISTS bar_sync_runs (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n environment TEXT NOT NULL DEFAULT 'live',\n inst_id TEXT NOT NULL,\n status TEXT NOT NULL,\n start_open INTEGER NOT NULL,\n end_open INTEGER NOT NULL,\n expected INTEGER NOT NULL,\n existing INTEGER NOT NULL,\n missing INTEGER NOT NULL,\n fetched INTEGER NOT NULL,\n inserted INTEGER NOT NULL,\n started_at INTEGER NOT NULL,\n finished_at INTEGER,\n message TEXT NOT NULL\n);\n\n";
13
+ /**
14
+ * Indexes that name the environment column.
15
+ *
16
+ * Applied after migration rather than with the tables above: on a pre-environment
17
+ * database the column does not exist yet, and `CREATE INDEX IF NOT EXISTS` still fails
18
+ * on an unknown column — which would abort the whole schema statement before the
19
+ * migration that adds it ever ran.
20
+ */
21
+ export declare const BAR_INDEX_SQL = "\nCREATE INDEX IF NOT EXISTS idx_bar_sync_runs_inst\n ON bar_sync_runs(environment, inst_id, started_at DESC);\n";
22
+ /**
23
+ * Adds the environment column to databases created before it existed.
24
+ *
25
+ * `bars_1m` and `bar_coverage` are keyed on it, and SQLite cannot add a column to an
26
+ * existing primary key, so those two are rebuilt. Existing rows become `live`, which
27
+ * is where they actually came from: demo is opt-in and nothing could have written
28
+ * demo bars before this column existed.
29
+ *
30
+ * Each rebuild runs in one transaction. A failure rolls back rather than leaving a
31
+ * half-migrated store, and the whole thing is a no-op once the column is present.
32
+ */
33
+ export declare const BAR_MIGRATION_STEPS: ReadonlyArray<{
34
+ table: string;
35
+ sql: string;
36
+ }>;
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Strategy-research storage schema.
3
+ *
4
+ * Only confirmed one-minute bars are persisted. Every higher timeframe is
5
+ * derived by aggregating this single source, so a backtest and a live
6
+ * evaluation can never disagree about a bucket boundary.
7
+ *
8
+ * Prices are stored as TEXT exactly as OKX returned them. Parsing them into
9
+ * IEEE-754 doubles before storage would make `dataHash` unstable across
10
+ * platforms and would silently lose precision that the exchange reported.
11
+ */
12
+ export const BAR_SCHEMA_SQL = `
13
+ CREATE TABLE IF NOT EXISTS bars_1m (
14
+ -- demo | live. Part of the key because the two are separate matching venues with
15
+ -- separate feeds: the same instrument and minute genuinely has different OHLCV in
16
+ -- each, so one row per (environment, instrument, minute) is the only way both can
17
+ -- be stored without one overwriting the other.
18
+ environment TEXT NOT NULL DEFAULT 'live',
19
+ inst_id TEXT NOT NULL,
20
+ open_time INTEGER NOT NULL,
21
+ close_time INTEGER NOT NULL,
22
+ open TEXT NOT NULL,
23
+ high TEXT NOT NULL,
24
+ low TEXT NOT NULL,
25
+ close TEXT NOT NULL,
26
+ volume TEXT NOT NULL,
27
+ source TEXT NOT NULL,
28
+ updated_at INTEGER NOT NULL,
29
+ PRIMARY KEY(environment, inst_id, open_time)
30
+ ) WITHOUT ROWID;
31
+
32
+ CREATE TABLE IF NOT EXISTS bar_coverage (
33
+ environment TEXT NOT NULL DEFAULT 'live',
34
+ inst_id TEXT NOT NULL,
35
+ oldest_open INTEGER NOT NULL,
36
+ newest_open INTEGER NOT NULL,
37
+ bar_count INTEGER NOT NULL,
38
+ exhausted_before INTEGER,
39
+ updated_at INTEGER NOT NULL,
40
+ PRIMARY KEY(environment, inst_id)
41
+ );
42
+
43
+ CREATE TABLE IF NOT EXISTS bar_sync_runs (
44
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
45
+ environment TEXT NOT NULL DEFAULT 'live',
46
+ inst_id TEXT NOT NULL,
47
+ status TEXT NOT NULL,
48
+ start_open INTEGER NOT NULL,
49
+ end_open INTEGER NOT NULL,
50
+ expected INTEGER NOT NULL,
51
+ existing INTEGER NOT NULL,
52
+ missing INTEGER NOT NULL,
53
+ fetched INTEGER NOT NULL,
54
+ inserted INTEGER NOT NULL,
55
+ started_at INTEGER NOT NULL,
56
+ finished_at INTEGER,
57
+ message TEXT NOT NULL
58
+ );
59
+
60
+ `;
61
+ /**
62
+ * Indexes that name the environment column.
63
+ *
64
+ * Applied after migration rather than with the tables above: on a pre-environment
65
+ * database the column does not exist yet, and `CREATE INDEX IF NOT EXISTS` still fails
66
+ * on an unknown column — which would abort the whole schema statement before the
67
+ * migration that adds it ever ran.
68
+ */
69
+ export const BAR_INDEX_SQL = `
70
+ CREATE INDEX IF NOT EXISTS idx_bar_sync_runs_inst
71
+ ON bar_sync_runs(environment, inst_id, started_at DESC);
72
+ `;
73
+ /**
74
+ * Adds the environment column to databases created before it existed.
75
+ *
76
+ * `bars_1m` and `bar_coverage` are keyed on it, and SQLite cannot add a column to an
77
+ * existing primary key, so those two are rebuilt. Existing rows become `live`, which
78
+ * is where they actually came from: demo is opt-in and nothing could have written
79
+ * demo bars before this column existed.
80
+ *
81
+ * Each rebuild runs in one transaction. A failure rolls back rather than leaving a
82
+ * half-migrated store, and the whole thing is a no-op once the column is present.
83
+ */
84
+ export const BAR_MIGRATION_STEPS = [
85
+ {
86
+ table: "bars_1m",
87
+ sql: `
88
+ CREATE TABLE bars_1m_migrated (
89
+ environment TEXT NOT NULL DEFAULT 'live',
90
+ inst_id TEXT NOT NULL,
91
+ open_time INTEGER NOT NULL,
92
+ close_time INTEGER NOT NULL,
93
+ open TEXT NOT NULL,
94
+ high TEXT NOT NULL,
95
+ low TEXT NOT NULL,
96
+ close TEXT NOT NULL,
97
+ volume TEXT NOT NULL,
98
+ source TEXT NOT NULL,
99
+ updated_at INTEGER NOT NULL,
100
+ PRIMARY KEY(environment, inst_id, open_time)
101
+ ) WITHOUT ROWID;
102
+ -- Columns named explicitly on both sides: a positional SELECT here silently
103
+ -- shifts every price by one column if the lists ever drift.
104
+ INSERT INTO bars_1m_migrated
105
+ (environment, inst_id, open_time, close_time, open, high, low, close, volume, source, updated_at)
106
+ SELECT 'live', inst_id, open_time, close_time, open, high, low, close, volume, source, updated_at
107
+ FROM bars_1m;
108
+ DROP TABLE bars_1m;
109
+ ALTER TABLE bars_1m_migrated RENAME TO bars_1m;
110
+ `
111
+ },
112
+ {
113
+ table: "bar_coverage",
114
+ sql: `
115
+ CREATE TABLE bar_coverage_migrated (
116
+ environment TEXT NOT NULL DEFAULT 'live',
117
+ inst_id TEXT NOT NULL,
118
+ oldest_open INTEGER NOT NULL,
119
+ newest_open INTEGER NOT NULL,
120
+ bar_count INTEGER NOT NULL,
121
+ exhausted_before INTEGER,
122
+ updated_at INTEGER NOT NULL,
123
+ PRIMARY KEY(environment, inst_id)
124
+ );
125
+ INSERT INTO bar_coverage_migrated
126
+ (environment, inst_id, oldest_open, newest_open, bar_count, exhausted_before, updated_at)
127
+ SELECT 'live', inst_id, oldest_open, newest_open, bar_count, exhausted_before, updated_at
128
+ FROM bar_coverage;
129
+ DROP TABLE bar_coverage;
130
+ ALTER TABLE bar_coverage_migrated RENAME TO bar_coverage;
131
+ `
132
+ }
133
+ ];
134
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/bars/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgD7B,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;;;CAG5B,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAkD;IAChF;QACE,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE;;;;;;;;;;;;;;;;;;;;;;;KAuBJ;KACF;IACD;QACE,KAAK,EAAE,cAAc;QACrB,GAAG,EAAE;;;;;;;;;;;;;;;;;KAiBJ;KACF;CACF,CAAC"}
@@ -0,0 +1,60 @@
1
+ import { type ToolResult } from "../core/types.js";
2
+ import { BarStore } from "./store.js";
3
+ import { type CoverageRow, type SyncProgress, type SyncReport } from "./types.js";
4
+ export interface DownloadRequest {
5
+ instId: string;
6
+ /** Trailing window in days, relative to the newest closed minute. */
7
+ days?: number;
8
+ /** Absolute inclusive bounds in Unix milliseconds; override `days`. */
9
+ fromMs?: number;
10
+ toMs?: number;
11
+ }
12
+ export interface ResolvedRange {
13
+ startOpen: number;
14
+ endOpen: number;
15
+ expected: number;
16
+ }
17
+ export interface CoverageDetail extends CoverageRow {
18
+ gaps: Array<{
19
+ fromMs: number;
20
+ toMs: number;
21
+ bars: number;
22
+ }>;
23
+ gapCount: number;
24
+ }
25
+ /**
26
+ * Read and repair operations over the local one-minute history.
27
+ *
28
+ * Only one-minute bars are stored; every higher timeframe is derived, so this
29
+ * service has no `bar` parameter anywhere.
30
+ */
31
+ export declare class BarService {
32
+ readonly store: BarStore;
33
+ private readonly now;
34
+ /**
35
+ * Latest progress per instrument, so a client polling during a download can
36
+ * draw a bar. A download holds one HTTP request open for as long as it runs,
37
+ * which is why progress is published here instead of streamed on that request.
38
+ */
39
+ private readonly progress;
40
+ constructor(store: BarStore, now?: () => number);
41
+ /** Current or most recent download progress for one instrument. */
42
+ downloadProgress(instId: string): ToolResult<(SyncProgress & {
43
+ updatedAt: number;
44
+ active: boolean;
45
+ }) | null>;
46
+ /** Newest closed minute that is safe to treat as final. */
47
+ latestClosedOpen(): number;
48
+ /** Which venue this store holds bars for. */
49
+ get environment(): string;
50
+ listInstruments(): ToolResult<CoverageRow[]>;
51
+ coverage(instId: string, gapLimit?: number): ToolResult<CoverageDetail | null>;
52
+ /**
53
+ * Resolves a download request into an exact inclusive one-minute range.
54
+ *
55
+ * The end is clamped to the newest closed minute so a request never targets
56
+ * a bar that has not finished forming.
57
+ */
58
+ resolveRange(request: DownloadRequest): ResolvedRange;
59
+ download(request: DownloadRequest, onProgress?: (progress: SyncProgress) => void): Promise<ToolResult<SyncReport>>;
60
+ }
@@ -0,0 +1,120 @@
1
+ import { RuntimeError } from "../core/errors.js";
2
+ import { resultMeta } from "../core/types.js";
3
+ import { ONE_MINUTE_MS, alignMinuteOpen, expectedBarCount } from "./types.js";
4
+ /**
5
+ * A download longer than this is rejected outright. 3 years of one-minute bars
6
+ * is already ~1.6M rows per instrument; a wider request is far more likely to
7
+ * be a typo than an intent.
8
+ */
9
+ const MAX_DOWNLOAD_DAYS = 1_095;
10
+ /**
11
+ * Read and repair operations over the local one-minute history.
12
+ *
13
+ * Only one-minute bars are stored; every higher timeframe is derived, so this
14
+ * service has no `bar` parameter anywhere.
15
+ */
16
+ export class BarService {
17
+ store;
18
+ now;
19
+ /**
20
+ * Latest progress per instrument, so a client polling during a download can
21
+ * draw a bar. A download holds one HTTP request open for as long as it runs,
22
+ * which is why progress is published here instead of streamed on that request.
23
+ */
24
+ progress = new Map();
25
+ constructor(store, now = Date.now) {
26
+ this.store = store;
27
+ this.now = now;
28
+ }
29
+ /** Current or most recent download progress for one instrument. */
30
+ downloadProgress(instId) {
31
+ return { data: this.progress.get(instId) ?? null, meta: resultMeta({ source: "memory" }) };
32
+ }
33
+ /** Newest closed minute that is safe to treat as final. */
34
+ latestClosedOpen() {
35
+ return alignMinuteOpen(this.now()) - ONE_MINUTE_MS;
36
+ }
37
+ /** Which venue this store holds bars for. */
38
+ get environment() {
39
+ return this.store.environment;
40
+ }
41
+ listInstruments() {
42
+ return {
43
+ data: this.store.coverageAll(),
44
+ // Carried in the metadata so every caller — CLI, shell, and agent — can say
45
+ // which market the counts describe without asking separately.
46
+ meta: resultMeta({ source: "sqlite", environment: this.store.environment })
47
+ };
48
+ }
49
+ coverage(instId, gapLimit = 50) {
50
+ const coverage = this.store.coverage(instId);
51
+ if (!coverage) {
52
+ return { data: null, meta: resultMeta({ source: "sqlite", environment: this.store.environment }) };
53
+ }
54
+ const gaps = this.store.gaps(instId, coverage.oldestOpen, coverage.newestOpen);
55
+ return {
56
+ data: {
57
+ ...coverage,
58
+ gapCount: gaps.length,
59
+ gaps: gaps.slice(0, gapLimit).map(([fromMs, toMs]) => ({
60
+ fromMs,
61
+ toMs,
62
+ bars: expectedBarCount(fromMs, toMs)
63
+ }))
64
+ },
65
+ meta: resultMeta({ source: "sqlite", environment: this.store.environment })
66
+ };
67
+ }
68
+ /**
69
+ * Resolves a download request into an exact inclusive one-minute range.
70
+ *
71
+ * The end is clamped to the newest closed minute so a request never targets
72
+ * a bar that has not finished forming.
73
+ */
74
+ resolveRange(request) {
75
+ const latest = this.latestClosedOpen();
76
+ const endOpen = request.toMs === undefined ? latest : Math.min(alignMinuteOpen(request.toMs), latest);
77
+ const startOpen = request.fromMs === undefined
78
+ ? endOpen - (request.days ?? 30) * 1_440 * ONE_MINUTE_MS
79
+ : alignMinuteOpen(request.fromMs);
80
+ if (endOpen < startOpen) {
81
+ throw new RuntimeError("VALIDATION", "Download range must end at or after it starts", false, {
82
+ startOpen,
83
+ endOpen
84
+ });
85
+ }
86
+ const expected = expectedBarCount(startOpen, endOpen);
87
+ if (expected > MAX_DOWNLOAD_DAYS * 1_440) {
88
+ throw new RuntimeError("VALIDATION", `Download range covers ${expected} one-minute bars, above the ${MAX_DOWNLOAD_DAYS}-day limit`, false, { expected, maxDays: MAX_DOWNLOAD_DAYS });
89
+ }
90
+ return { startOpen, endOpen, expected };
91
+ }
92
+ async download(request, onProgress) {
93
+ const range = this.resolveRange(request);
94
+ // Publish an initial figure before the first page returns, so a client that
95
+ // polls immediately sees the expected total rather than nothing.
96
+ this.progress.set(request.instId, {
97
+ instId: request.instId,
98
+ expected: range.expected,
99
+ present: 0,
100
+ fetched: 0,
101
+ inserted: 0,
102
+ updatedAt: this.now(),
103
+ active: true
104
+ });
105
+ const publish = (progress) => {
106
+ this.progress.set(progress.instId, { ...progress, updatedAt: this.now(), active: true });
107
+ onProgress?.(progress);
108
+ };
109
+ try {
110
+ const report = await this.store.syncWindow(request.instId, range.startOpen, range.endOpen, publish);
111
+ return { data: report, meta: resultMeta({ source: "mixed" }) };
112
+ }
113
+ finally {
114
+ const last = this.progress.get(request.instId);
115
+ if (last)
116
+ this.progress.set(request.instId, { ...last, updatedAt: this.now(), active: false });
117
+ }
118
+ }
119
+ }
120
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/bars/service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,105 @@
1
+ import type Database from "better-sqlite3";
2
+ import type { OkxClient } from "../core/okx-client.js";
3
+ import { PublicRestLimiter } from "./rate-limiter.js";
4
+ import { type OkxEnvironment } from "../network/connectivity.js";
5
+ import { type Bar, type CoverageRow, type SyncProgress, type SyncReport } from "./types.js";
6
+ type RawCandleRow = string[];
7
+ export interface BarStoreOptions {
8
+ client: OkxClient;
9
+ limiter?: PublicRestLimiter;
10
+ now?: () => number;
11
+ /**
12
+ * Which OKX feed this store holds bars for. Defaults to `live`.
13
+ *
14
+ * Bound once at construction rather than passed per call: one store serves one
15
+ * environment, so the chance of omitting it drops from every query to a single
16
+ * place.
17
+ */
18
+ environment?: OkxEnvironment;
19
+ }
20
+ /** Called for each bar arriving from the live feed, after it is committed. */
21
+ export type ConfirmedBarListener = (instId: string, bar: Bar) => void;
22
+ /**
23
+ * Persists confirmed one-minute bars and repairs an exact closed window.
24
+ *
25
+ * `syncWindow` deliberately targets an exact inclusive range instead of a
26
+ * rolling retention period: a reproducible backtest needs the bars belonging
27
+ * to its own snapshot repaired, and nothing else.
28
+ */
29
+ export declare class BarStore {
30
+ private readonly db;
31
+ private readonly client;
32
+ private readonly limiter;
33
+ private readonly now;
34
+ private readonly confirmedListeners;
35
+ readonly environment: OkxEnvironment;
36
+ constructor(db: Database.Database, options: BarStoreOptions);
37
+ /**
38
+ * Brings a pre-environment database up to the current schema.
39
+ *
40
+ * `bars_1m` and `bar_coverage` are keyed on the environment and SQLite cannot add a
41
+ * column to an existing primary key, so both are rebuilt. Existing rows become
42
+ * `live`, which is where they came from — demo is opt-in and could not have been
43
+ * written before this column existed.
44
+ */
45
+ private migrate;
46
+ /**
47
+ * Subscribes to bars arriving from the live feed.
48
+ *
49
+ * Only `appendConfirmed` notifies, which is the websocket's path. Backfill uses
50
+ * a bulk insert and stays silent on purpose: repairing history must not look
51
+ * like a minute that just closed, or downloading three months of data would
52
+ * emit three months of trading decisions.
53
+ *
54
+ * Returns a function that removes the listener.
55
+ */
56
+ onConfirmed(listener: ConfirmedBarListener): () => void;
57
+ /**
58
+ * Records one confirmed bar arriving from the live websocket feed.
59
+ *
60
+ * This writes synchronously. A deferred write would let a live evaluation
61
+ * read a window that is missing the minute that just triggered it.
62
+ */
63
+ appendConfirmed(instId: string, bar: Bar, source?: string): void;
64
+ private notifyConfirmed;
65
+ /** Every instrument with locally stored history, newest coverage first. */
66
+ coverageAll(): CoverageRow[];
67
+ coverage(instId: string): CoverageRow | undefined;
68
+ /**
69
+ * Contiguous ranges of missing open times inside an inclusive window, each
70
+ * returned as `[firstMissingOpen, lastMissingOpen]`.
71
+ */
72
+ gaps(instId: string, startOpen: number, endOpen: number): Array<[number, number]>;
73
+ /**
74
+ * Loads an exact inclusive window and verifies it is contiguous.
75
+ *
76
+ * This fails closed. A backtest that silently skipped an absent minute would
77
+ * report performance for a timeline that never happened.
78
+ */
79
+ loadWindow(instId: string, startOpen: number, endOpen: number): Bar[];
80
+ /**
81
+ * Repairs an exact inclusive one-minute window, fetching only the bars that
82
+ * are actually absent.
83
+ */
84
+ syncWindow(instId: string, startOpenInput: number, endOpenInput: number, onProgress?: (progress: SyncProgress) => void): Promise<SyncReport>;
85
+ /**
86
+ * Backfills one contiguous gap by paging `history-candles` backwards from
87
+ * just past `gapEnd` until the requested lower bound is reached.
88
+ */
89
+ private fillGap;
90
+ private fetchHistoryPage;
91
+ /** Inserts bars in one transaction and returns how many rows were new. */
92
+ private insertBars;
93
+ private presentOpenTimes;
94
+ private countInRange;
95
+ /** Recomputes the derived coverage row from the stored bars. */
96
+ private refreshCoverage;
97
+ private beginSyncRun;
98
+ private finishSyncRun;
99
+ }
100
+ /**
101
+ * OKX candle row: `[ts, o, h, l, c, vol, volCcy, volCcyQuote, confirm]`.
102
+ * Unconfirmed rows are rejected — only closed bars belong in storage.
103
+ */
104
+ export declare function normalizeCandle(row: RawCandleRow): Bar | undefined;
105
+ export {};