desic-okx-agent 0.2.1 → 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 (236) hide show
  1. package/README.en.md +90 -10
  2. package/README.md +76 -10
  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 +757 -26
  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.js +19 -22
  142. package/dist/setup/wizard.js.map +1 -1
  143. package/dist/strategy/constants.d.ts +23 -0
  144. package/dist/strategy/constants.js +24 -0
  145. package/dist/strategy/constants.js.map +1 -0
  146. package/dist/strategy/environment.d.ts +52 -0
  147. package/dist/strategy/environment.js +187 -0
  148. package/dist/strategy/environment.js.map +1 -0
  149. package/dist/strategy/instrument.d.ts +29 -0
  150. package/dist/strategy/instrument.js +39 -0
  151. package/dist/strategy/instrument.js.map +1 -0
  152. package/dist/strategy/optimize.d.ts +73 -0
  153. package/dist/strategy/optimize.js +113 -0
  154. package/dist/strategy/optimize.js.map +1 -0
  155. package/dist/strategy/parameter-space.d.ts +59 -0
  156. package/dist/strategy/parameter-space.js +221 -0
  157. package/dist/strategy/parameter-space.js.map +1 -0
  158. package/dist/strategy/python-bridge.d.ts +24 -0
  159. package/dist/strategy/python-bridge.js +114 -0
  160. package/dist/strategy/python-bridge.js.map +1 -0
  161. package/dist/strategy/schema.d.ts +9 -0
  162. package/dist/strategy/schema.js +91 -0
  163. package/dist/strategy/schema.js.map +1 -0
  164. package/dist/strategy/service.d.ts +138 -0
  165. package/dist/strategy/service.js +745 -0
  166. package/dist/strategy/service.js.map +1 -0
  167. package/dist/strategy/settings.d.ts +162 -0
  168. package/dist/strategy/settings.js +243 -0
  169. package/dist/strategy/settings.js.map +1 -0
  170. package/dist/strategy/store.d.ts +96 -0
  171. package/dist/strategy/store.js +367 -0
  172. package/dist/strategy/store.js.map +1 -0
  173. package/dist/strategy/templates.d.ts +11 -0
  174. package/dist/strategy/templates.js +134 -0
  175. package/dist/strategy/templates.js.map +1 -0
  176. package/dist/strategy/types.d.ts +111 -0
  177. package/dist/strategy/types.js +2 -0
  178. package/dist/strategy/types.js.map +1 -0
  179. package/dist/tools/catalog.d.ts +16 -0
  180. package/dist/tools/catalog.js +118 -17
  181. package/dist/tools/catalog.js.map +1 -1
  182. package/dist/trade/service.d.ts +12 -0
  183. package/dist/trade/service.js +24 -7
  184. package/dist/trade/service.js.map +1 -1
  185. package/dist/tui/app.d.ts +23 -0
  186. package/dist/tui/app.js +322 -0
  187. package/dist/tui/app.js.map +1 -0
  188. package/dist/tui/commands.d.ts +70 -0
  189. package/dist/tui/commands.js +313 -0
  190. package/dist/tui/commands.js.map +1 -0
  191. package/dist/tui/entries.d.ts +17 -0
  192. package/dist/tui/entries.js +24 -0
  193. package/dist/tui/entries.js.map +1 -0
  194. package/dist/tui/execute.d.ts +26 -0
  195. package/dist/tui/execute.js +664 -0
  196. package/dist/tui/execute.js.map +1 -0
  197. package/dist/tui/history.d.ts +17 -0
  198. package/dist/tui/history.js +48 -0
  199. package/dist/tui/history.js.map +1 -0
  200. package/dist/tui/index.d.ts +8 -0
  201. package/dist/tui/index.js +48 -0
  202. package/dist/tui/index.js.map +1 -0
  203. package/dist/tui/line-editor.d.ts +44 -0
  204. package/dist/tui/line-editor.js +98 -0
  205. package/dist/tui/line-editor.js.map +1 -0
  206. package/dist/tui/progress.d.ts +23 -0
  207. package/dist/tui/progress.js +46 -0
  208. package/dist/tui/progress.js.map +1 -0
  209. package/dist/tui/settings-editor.d.ts +18 -0
  210. package/dist/tui/settings-editor.js +115 -0
  211. package/dist/tui/settings-editor.js.map +1 -0
  212. package/docs/live-trading.md +455 -0
  213. package/docs/strategy-research.md +597 -0
  214. package/package.json +10 -1
  215. package/python/desic_strategy/__init__.py +34 -0
  216. package/python/desic_strategy/actions.py +158 -0
  217. package/python/desic_strategy/context.py +164 -0
  218. package/python/desic_strategy/engine.py +614 -0
  219. package/python/desic_strategy/indicators.py +159 -0
  220. package/python/desic_strategy/live.py +253 -0
  221. package/python/desic_strategy/policy.py +193 -0
  222. package/python/desic_strategy/portfolio.py +152 -0
  223. package/python/desic_strategy/report.py +319 -0
  224. package/python/desic_strategy/runner.py +574 -0
  225. package/python/desic_strategy/timeframe.py +150 -0
  226. package/python/main.py +18 -0
  227. package/skills/okx-live-trading/SKILL.md +117 -0
  228. package/skills/okx-live-trading/agents/openai.yaml +9 -0
  229. package/skills/okx-live-trading/references/lifecycle.md +128 -0
  230. package/skills/okx-strategy-research/SKILL.md +113 -0
  231. package/skills/okx-strategy-research/agents/openai.yaml +9 -0
  232. package/skills/okx-strategy-research/references/execution-semantics.md +107 -0
  233. package/skills/okx-strategy-research/references/field-traps.md +142 -0
  234. package/skills/okx-strategy-research/references/python-api.md +121 -0
  235. package/skills/okx-strategy-research/references/tools-and-data.md +192 -0
  236. package/skills/okx-trading/SKILL.md +11 -10
@@ -0,0 +1,62 @@
1
+ import type { ContractSpec } from "../strategy/instrument.js";
2
+ /**
3
+ * Converts a budget into a legal contract count.
4
+ *
5
+ * This mirrors the backtest engine's `_entry_quantity` and `_align_lot` exactly. The
6
+ * two implementations exist because the backtest owns a virtual account in Python
7
+ * while live sizing happens on the host — and a divergence between them would mean a
8
+ * strategy trades a different size live than the size its backtest reported, with
9
+ * every metric still looking plausible. A shared fixture drives both and compares
10
+ * value by value.
11
+ *
12
+ * Kept free of any I/O or account lookup so it can be tested as pure arithmetic.
13
+ */
14
+ export interface SizingInput {
15
+ /** USDT of margin to commit to this entry. */
16
+ budgetUsdt: number;
17
+ /** Price the order is sized against. */
18
+ price: number;
19
+ leverage: number;
20
+ /** Reserves this multiple of the required margin. 1 means no extra reserve. */
21
+ marginSafetyMultiplier: number;
22
+ contract: Pick<ContractSpec, "contractValue" | "contractMultiplier" | "lotSize" | "minSize">;
23
+ }
24
+ export interface SizingResult {
25
+ /** Contracts to order, aligned down to a legal lot. Zero means "do not order". */
26
+ contracts: number;
27
+ /** Notional the aligned quantity represents, in USDT. */
28
+ notionalUsdt: number;
29
+ /** Margin the aligned quantity actually commits, in USDT. */
30
+ marginUsdt: number;
31
+ /** Set when the result is zero, naming which limit produced that. */
32
+ refusedBecause?: "non_positive_budget" | "below_minimum_size";
33
+ }
34
+ /** Base-currency units one contract represents. */
35
+ export declare function basePerContract(contract: SizingInput["contract"]): number;
36
+ export declare function sizeEntry(input: SizingInput): SizingResult;
37
+ /**
38
+ * Aligns a quantity down to a whole number of lots.
39
+ *
40
+ * Always downward: rounding up would place an order larger than the budget allows.
41
+ * Below `minSize` the result is zero rather than the minimum, because ordering more
42
+ * than the budget permits is the thing the budget exists to prevent.
43
+ *
44
+ * The `1e-9` matches the Python engine. Without it a quantity that is exactly a lot
45
+ * multiple can land a hair below it in floating point and lose a whole lot.
46
+ */
47
+ export declare function alignLot(quantity: number, contract: Pick<ContractSpec, "lotSize" | "minSize">): number;
48
+ /**
49
+ * Rounds to the decimal places the step itself carries.
50
+ *
51
+ * OKX rejects a size with more precision than `lotSz` allows, and float arithmetic
52
+ * routinely produces exactly that.
53
+ */
54
+ export declare function roundToStep(value: number, step: number): number;
55
+ /**
56
+ * Margin currently committed to one side of an instrument.
57
+ *
58
+ * Read from the exchange's own position rows: the side budget has to measure what is
59
+ * actually at risk, and a locally accumulated figure would drift from the exchange
60
+ * after a partial fill, a manual close, or a liquidation.
61
+ */
62
+ export declare function committedMarginUsdt(positions: Array<Record<string, unknown>>, side: "long" | "short"): number;
@@ -0,0 +1,79 @@
1
+ /** Base-currency units one contract represents. */
2
+ export function basePerContract(contract) {
3
+ return contract.contractValue * contract.contractMultiplier;
4
+ }
5
+ export function sizeEntry(input) {
6
+ const base = basePerContract(input.contract);
7
+ if (!(input.budgetUsdt > 0) || !(input.price > 0) || !(base > 0)) {
8
+ return { contracts: 0, notionalUsdt: 0, marginUsdt: 0, refusedBecause: "non_positive_budget" };
9
+ }
10
+ const notional = (input.budgetUsdt * input.leverage) / input.marginSafetyMultiplier;
11
+ const raw = notional / (input.price * base);
12
+ const contracts = alignLot(raw, input.contract);
13
+ if (contracts <= 0) {
14
+ return { contracts: 0, notionalUsdt: 0, marginUsdt: 0, refusedBecause: "below_minimum_size" };
15
+ }
16
+ const alignedNotional = contracts * base * input.price;
17
+ return {
18
+ contracts,
19
+ notionalUsdt: alignedNotional,
20
+ // Recomputed from the aligned quantity rather than reusing the budget: aligning
21
+ // down means the order commits slightly less than requested, and reporting the
22
+ // request would overstate what is actually at risk.
23
+ marginUsdt: (alignedNotional / input.leverage) * input.marginSafetyMultiplier
24
+ };
25
+ }
26
+ /**
27
+ * Aligns a quantity down to a whole number of lots.
28
+ *
29
+ * Always downward: rounding up would place an order larger than the budget allows.
30
+ * Below `minSize` the result is zero rather than the minimum, because ordering more
31
+ * than the budget permits is the thing the budget exists to prevent.
32
+ *
33
+ * The `1e-9` matches the Python engine. Without it a quantity that is exactly a lot
34
+ * multiple can land a hair below it in floating point and lose a whole lot.
35
+ */
36
+ export function alignLot(quantity, contract) {
37
+ if (!(quantity > 0))
38
+ return 0;
39
+ if (!(contract.lotSize > 0))
40
+ return quantity;
41
+ const steps = Math.floor(quantity / contract.lotSize + 1e-9);
42
+ const aligned = steps * contract.lotSize;
43
+ if (aligned < contract.minSize)
44
+ return 0;
45
+ // Re-derived from the step count and rounded to the lot's own precision, so a
46
+ // multiply like 3 * 0.1 does not reach the exchange as 0.30000000000000004.
47
+ return roundToStep(aligned, contract.lotSize);
48
+ }
49
+ /**
50
+ * Rounds to the decimal places the step itself carries.
51
+ *
52
+ * OKX rejects a size with more precision than `lotSz` allows, and float arithmetic
53
+ * routinely produces exactly that.
54
+ */
55
+ export function roundToStep(value, step) {
56
+ const text = String(step);
57
+ const dot = text.indexOf(".");
58
+ const decimals = dot === -1 ? 0 : text.length - dot - 1;
59
+ return Number(value.toFixed(Math.min(decimals, 12)));
60
+ }
61
+ /**
62
+ * Margin currently committed to one side of an instrument.
63
+ *
64
+ * Read from the exchange's own position rows: the side budget has to measure what is
65
+ * actually at risk, and a locally accumulated figure would drift from the exchange
66
+ * after a partial fill, a manual close, or a liquidation.
67
+ */
68
+ export function committedMarginUsdt(positions, side) {
69
+ let total = 0;
70
+ for (const position of positions) {
71
+ if (String(position.side ?? "") !== side)
72
+ continue;
73
+ const margin = Number(position.usedMarginUsdt ?? 0);
74
+ if (Number.isFinite(margin) && margin > 0)
75
+ total += margin;
76
+ }
77
+ return total;
78
+ }
79
+ //# sourceMappingURL=sizing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sizing.js","sourceRoot":"","sources":["../../src/live/sizing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,123 @@
1
+ import type Database from "better-sqlite3";
2
+ import type { CreateProfileInput, GateName, LiveProfile, LiveSignal, ProfileStatus } from "./types.js";
3
+ export declare class LiveStore {
4
+ private readonly db;
5
+ private readonly now;
6
+ constructor(db: Database.Database, now?: () => number);
7
+ /**
8
+ * Adds columns introduced after a database was first created.
9
+ *
10
+ * `CREATE TABLE IF NOT EXISTS` does nothing to an existing table, so a new column
11
+ * is invisible to anyone upgrading and every read fails with "no such column"
12
+ * until the file is deleted.
13
+ */
14
+ private migrate;
15
+ /**
16
+ * Marks profiles left running by a previous process as stopped.
17
+ *
18
+ * Their worker is gone, so a `running` row would show a profile that will never
19
+ * evaluate anything — and would let a reader believe a strategy is trading when
20
+ * nothing is. The generation is bumped so any action decided by the dead worker is
21
+ * refused if it somehow still arrives.
22
+ */
23
+ failInterruptedProfiles(): number;
24
+ createProfile(input: CreateProfileInput): LiveProfile;
25
+ profile(id: string): LiveProfile | undefined;
26
+ requireProfile(id: string): LiveProfile;
27
+ /** The stored source snapshot, which is what a session is built from. */
28
+ profileSource(id: string): string | undefined;
29
+ listProfiles(options?: {
30
+ enabledOnly?: boolean;
31
+ instId?: string;
32
+ }): LiveProfile[];
33
+ /**
34
+ * Enables a profile and returns the generation it is now running under.
35
+ *
36
+ * The generation is bumped here and on every disable. An evaluation captures it
37
+ * when it starts and re-checks it before submitting, so a stop that lands
38
+ * mid-evaluation still blocks the order.
39
+ */
40
+ enableProfile(id: string, backtestRunId: string | null): LiveProfile;
41
+ /**
42
+ * Disables a profile.
43
+ *
44
+ * Bumping the generation is the point: it invalidates any action already decided
45
+ * but not yet submitted.
46
+ */
47
+ disableProfile(id: string, reason?: string | null): LiveProfile;
48
+ setProfileStatus(id: string, status: ProfileStatus): void;
49
+ /**
50
+ * Records an error and returns the resulting streak.
51
+ *
52
+ * One failure does not stop a profile: the risk gates still refuse anything
53
+ * unsafe, and a single network hiccup is not a reason to stop trading. A run of
54
+ * them is different — it means something systemic, and the caller disables the
55
+ * profile once the streak reaches its threshold.
56
+ */
57
+ recordError(id: string, message: string): number;
58
+ /**
59
+ * Records what went wrong without advancing the streak.
60
+ *
61
+ * For a failure that will fix itself: the reader still sees it, but a run of dropped
62
+ * connections does not accumulate toward stopping the profile.
63
+ */
64
+ setLastError(id: string, message: string): void;
65
+ clearErrorStreak(id: string): void;
66
+ deleteProfile(id: string): boolean;
67
+ /**
68
+ * Claims one closed minute for one profile, before anything is evaluated.
69
+ *
70
+ * Returns the new signal's id, or `undefined` when that minute is already taken.
71
+ * The claim has to come first: the unique constraint can only prevent a duplicate
72
+ * order if the row exists before the order is sent. Restarts, redelivered bars,
73
+ * and coalesced bursts all converge on the same outcome — one minute, one signal,
74
+ * at most one order.
75
+ */
76
+ reserveSignal(profileId: string, cutoffAt: number): string | undefined;
77
+ /** Records a decision that asked for nothing. */
78
+ settleNoAction(signalId: string, reason: string): void;
79
+ /**
80
+ * Records an intent a risk gate refused.
81
+ *
82
+ * `blockedBy` is always stored. These rows are the evidence that risk control
83
+ * ran: without them, a day with no orders is indistinguishable from a loop that
84
+ * silently stopped evaluating.
85
+ */
86
+ settleBlocked(signalId: string, input: {
87
+ action: string;
88
+ reason: string;
89
+ blockedBy: GateName;
90
+ details?: Record<string, unknown>;
91
+ }): void;
92
+ /** Records an order that reached the exchange. */
93
+ settleSubmitted(signalId: string, input: {
94
+ action: string;
95
+ reason: string;
96
+ quantity: number;
97
+ orderId: string | null;
98
+ executionKey: string;
99
+ details?: Record<string, unknown>;
100
+ }): void;
101
+ settleError(signalId: string, message: string, action?: string): void;
102
+ /**
103
+ * Marks a signal whose remote outcome could not be determined.
104
+ *
105
+ * Deliberately terminal and deliberately not retried: re-sending an order that may
106
+ * already exist is the one mistake worse than missing one. It waits for a person.
107
+ */
108
+ settleAmbiguous(signalId: string, message: string): void;
109
+ signal(id: string): LiveSignal | undefined;
110
+ signalAt(profileId: string, cutoffAt: number): LiveSignal | undefined;
111
+ listSignals(profileId: string, limit?: number): LiveSignal[];
112
+ /**
113
+ * Signals whose outcome is unresolved, for startup reconciliation.
114
+ *
115
+ * `submitted` rows may or may not have reached the exchange, and `reserved` rows
116
+ * were claimed by a worker that then died — both need checking against the
117
+ * exchange rather than assuming either outcome.
118
+ */
119
+ unresolvedSignals(limit?: number): LiveSignal[];
120
+ /** The most recent minute at which this profile actually submitted an order. */
121
+ lastSubmittedAt(profileId: string): number | undefined;
122
+ countByStatus(profileId: string): Record<string, number>;
123
+ }
@@ -0,0 +1,350 @@
1
+ import crypto from "node:crypto";
2
+ import { RuntimeError } from "../core/errors.js";
3
+ import { MAX_PAGE_ROWS } from "../strategy/constants.js";
4
+ import { sourceHash } from "../strategy/store.js";
5
+ import { LIVE_SCHEMA_SQL } from "./schema.js";
6
+ export class LiveStore {
7
+ db;
8
+ now;
9
+ constructor(db, now = Date.now) {
10
+ this.db = db;
11
+ this.now = now;
12
+ this.db.exec(LIVE_SCHEMA_SQL);
13
+ this.migrate();
14
+ }
15
+ /**
16
+ * Adds columns introduced after a database was first created.
17
+ *
18
+ * `CREATE TABLE IF NOT EXISTS` does nothing to an existing table, so a new column
19
+ * is invisible to anyone upgrading and every read fails with "no such column"
20
+ * until the file is deleted.
21
+ */
22
+ migrate() {
23
+ for (const [table, additions] of [
24
+ ["live_profiles", [
25
+ ["backtest_run_id", "TEXT"],
26
+ ["generation", "INTEGER NOT NULL DEFAULT 0"],
27
+ ["origin", "TEXT NOT NULL DEFAULT 'operator'"],
28
+ ["rationale", "TEXT"]
29
+ ]],
30
+ ["live_signals", [["blocked_by", "TEXT"], ["updated_at", "INTEGER NOT NULL DEFAULT 0"]]]
31
+ ]) {
32
+ const columns = new Set(this.db.prepare(`PRAGMA table_info(${table})`).all().map((row) => row.name));
33
+ for (const [name, type] of additions) {
34
+ if (!columns.has(name))
35
+ this.db.exec(`ALTER TABLE ${table} ADD COLUMN ${name} ${type}`);
36
+ }
37
+ }
38
+ }
39
+ /**
40
+ * Marks profiles left running by a previous process as stopped.
41
+ *
42
+ * Their worker is gone, so a `running` row would show a profile that will never
43
+ * evaluate anything — and would let a reader believe a strategy is trading when
44
+ * nothing is. The generation is bumped so any action decided by the dead worker is
45
+ * refused if it somehow still arrives.
46
+ */
47
+ failInterruptedProfiles() {
48
+ const result = this.db
49
+ .prepare(`UPDATE live_profiles
50
+ SET status='stopped', enabled=0, generation=generation+1,
51
+ last_error='The runtime restarted while this profile was running', updated_at=?
52
+ WHERE status IN ('starting','running')`)
53
+ .run(this.now());
54
+ return result.changes;
55
+ }
56
+ createProfile(input) {
57
+ if (!input.source.trim())
58
+ throw new RuntimeError("VALIDATION", "A live profile requires strategy source");
59
+ const id = `lp_${crypto.randomBytes(6).toString("hex")}`;
60
+ const timestamp = this.now();
61
+ try {
62
+ this.db
63
+ .prepare(`INSERT INTO live_profiles(
64
+ id,name,strategy_source,strategy_hash,params_json,inst_id,account,environment,
65
+ leverage,margin_mode,entry_budget_usdt,side_budget_usdt,daily_loss_limit_usdt,
66
+ cooldown_seconds,allow_long,allow_short,origin,rationale,created_at,updated_at
67
+ ) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`)
68
+ .run(id, input.name, input.source, sourceHash(input.source), JSON.stringify(input.params ?? {}), input.instId, input.account, input.environment, input.leverage, input.marginMode ?? "cross", input.entryBudgetUsdt, input.sideBudgetUsdt, input.dailyLossLimitUsdt, input.cooldownSeconds ?? 0, input.allowLong === false ? 0 : 1, input.allowShort === false ? 0 : 1, input.origin ?? "operator", input.rationale ?? null, timestamp, timestamp);
69
+ }
70
+ catch (error) {
71
+ // The unique constraint is the useful error here, so it is named rather than
72
+ // surfaced as a raw SQLite message.
73
+ if (String(error).includes("UNIQUE")) {
74
+ throw new RuntimeError("VALIDATION", `A profile already exists for ${input.account}/${input.environment} on ${input.instId}. Two profiles on one contract would each size against a position the other opened.`);
75
+ }
76
+ throw error;
77
+ }
78
+ return this.requireProfile(id);
79
+ }
80
+ profile(id) {
81
+ const row = this.db.prepare(`SELECT ${PROFILE_COLUMNS} FROM live_profiles WHERE id=?`).get(id);
82
+ return row ? toProfile(row) : undefined;
83
+ }
84
+ requireProfile(id) {
85
+ const profile = this.profile(id);
86
+ if (!profile)
87
+ throw new RuntimeError("NOT_FOUND", `Unknown live profile '${id}'`);
88
+ return profile;
89
+ }
90
+ /** The stored source snapshot, which is what a session is built from. */
91
+ profileSource(id) {
92
+ const row = this.db.prepare("SELECT strategy_source FROM live_profiles WHERE id=?").get(id);
93
+ return row?.strategy_source;
94
+ }
95
+ listProfiles(options = {}) {
96
+ const clauses = [];
97
+ const values = [];
98
+ if (options.enabledOnly)
99
+ clauses.push("enabled=1");
100
+ if (options.instId) {
101
+ clauses.push("inst_id=?");
102
+ values.push(options.instId);
103
+ }
104
+ const where = clauses.length ? `WHERE ${clauses.join(" AND ")}` : "";
105
+ const rows = this.db
106
+ .prepare(`SELECT ${PROFILE_COLUMNS} FROM live_profiles ${where} ORDER BY created_at ASC`)
107
+ .all(...values);
108
+ return rows.map(toProfile);
109
+ }
110
+ /**
111
+ * Enables a profile and returns the generation it is now running under.
112
+ *
113
+ * The generation is bumped here and on every disable. An evaluation captures it
114
+ * when it starts and re-checks it before submitting, so a stop that lands
115
+ * mid-evaluation still blocks the order.
116
+ */
117
+ enableProfile(id, backtestRunId) {
118
+ this.db
119
+ .prepare(`UPDATE live_profiles
120
+ SET enabled=1, status='starting', generation=generation+1, error_streak=0, last_error=NULL,
121
+ backtest_run_id=COALESCE(?, backtest_run_id), updated_at=?
122
+ WHERE id=?`)
123
+ .run(backtestRunId, this.now(), id);
124
+ return this.requireProfile(id);
125
+ }
126
+ /**
127
+ * Disables a profile.
128
+ *
129
+ * Bumping the generation is the point: it invalidates any action already decided
130
+ * but not yet submitted.
131
+ */
132
+ disableProfile(id, reason = null) {
133
+ this.db
134
+ .prepare(`UPDATE live_profiles
135
+ SET enabled=0, status='stopped', generation=generation+1,
136
+ last_error=COALESCE(?, last_error), updated_at=?
137
+ WHERE id=?`)
138
+ .run(reason, this.now(), id);
139
+ return this.requireProfile(id);
140
+ }
141
+ setProfileStatus(id, status) {
142
+ this.db.prepare("UPDATE live_profiles SET status=?, updated_at=? WHERE id=?").run(status, this.now(), id);
143
+ }
144
+ /**
145
+ * Records an error and returns the resulting streak.
146
+ *
147
+ * One failure does not stop a profile: the risk gates still refuse anything
148
+ * unsafe, and a single network hiccup is not a reason to stop trading. A run of
149
+ * them is different — it means something systemic, and the caller disables the
150
+ * profile once the streak reaches its threshold.
151
+ */
152
+ recordError(id, message) {
153
+ this.db
154
+ .prepare("UPDATE live_profiles SET error_streak=error_streak+1, last_error=?, updated_at=? WHERE id=?")
155
+ .run(message.slice(0, 2_000), this.now(), id);
156
+ return this.requireProfile(id).errorStreak;
157
+ }
158
+ /**
159
+ * Records what went wrong without advancing the streak.
160
+ *
161
+ * For a failure that will fix itself: the reader still sees it, but a run of dropped
162
+ * connections does not accumulate toward stopping the profile.
163
+ */
164
+ setLastError(id, message) {
165
+ this.db
166
+ .prepare("UPDATE live_profiles SET last_error=?, updated_at=? WHERE id=?")
167
+ .run(message.slice(0, 2_000), this.now(), id);
168
+ }
169
+ clearErrorStreak(id) {
170
+ this.db
171
+ .prepare("UPDATE live_profiles SET error_streak=0, last_error=NULL, updated_at=? WHERE id=?")
172
+ .run(this.now(), id);
173
+ }
174
+ deleteProfile(id) {
175
+ const transaction = this.db.transaction(() => {
176
+ this.db.prepare("DELETE FROM live_signals WHERE profile_id=?").run(id);
177
+ return this.db.prepare("DELETE FROM live_profiles WHERE id=?").run(id).changes > 0;
178
+ });
179
+ return transaction();
180
+ }
181
+ // ----- signals ---------------------------------------------------------
182
+ /**
183
+ * Claims one closed minute for one profile, before anything is evaluated.
184
+ *
185
+ * Returns the new signal's id, or `undefined` when that minute is already taken.
186
+ * The claim has to come first: the unique constraint can only prevent a duplicate
187
+ * order if the row exists before the order is sent. Restarts, redelivered bars,
188
+ * and coalesced bursts all converge on the same outcome — one minute, one signal,
189
+ * at most one order.
190
+ */
191
+ reserveSignal(profileId, cutoffAt) {
192
+ const id = `ls_${crypto.randomBytes(6).toString("hex")}`;
193
+ const timestamp = this.now();
194
+ const result = this.db
195
+ .prepare(`INSERT INTO live_signals(
196
+ id,profile_id,cutoff_at,action,reason,status,created_at,updated_at
197
+ ) VALUES(?,?,?,'pending','reserved','reserved',?,?)
198
+ ON CONFLICT(profile_id,cutoff_at) DO NOTHING`)
199
+ .run(id, profileId, cutoffAt, timestamp, timestamp);
200
+ return result.changes > 0 ? id : undefined;
201
+ }
202
+ /** Records a decision that asked for nothing. */
203
+ settleNoAction(signalId, reason) {
204
+ this.db
205
+ .prepare("UPDATE live_signals SET action='no_action', reason=?, status='no_action', updated_at=? WHERE id=?")
206
+ .run(reason, this.now(), signalId);
207
+ }
208
+ /**
209
+ * Records an intent a risk gate refused.
210
+ *
211
+ * `blockedBy` is always stored. These rows are the evidence that risk control
212
+ * ran: without them, a day with no orders is indistinguishable from a loop that
213
+ * silently stopped evaluating.
214
+ */
215
+ settleBlocked(signalId, input) {
216
+ this.db
217
+ .prepare(`UPDATE live_signals
218
+ SET action=?, reason=?, status='blocked', blocked_by=?, details_json=?, updated_at=?
219
+ WHERE id=?`)
220
+ .run(input.action, input.reason, input.blockedBy, JSON.stringify(input.details ?? {}), this.now(), signalId);
221
+ }
222
+ /** Records an order that reached the exchange. */
223
+ settleSubmitted(signalId, input) {
224
+ this.db
225
+ .prepare(`UPDATE live_signals
226
+ SET action=?, reason=?, status='submitted', quantity=?, order_id=?, execution_key=?,
227
+ details_json=?, updated_at=?
228
+ WHERE id=?`)
229
+ .run(input.action, input.reason, input.quantity, input.orderId, input.executionKey, JSON.stringify(input.details ?? {}), this.now(), signalId);
230
+ }
231
+ settleError(signalId, message, action = "error") {
232
+ this.db
233
+ .prepare(`UPDATE live_signals SET action=?, reason='evaluation failed', status='error', error=?, updated_at=?
234
+ WHERE id=?`)
235
+ .run(action, message.slice(0, 2_000), this.now(), signalId);
236
+ }
237
+ /**
238
+ * Marks a signal whose remote outcome could not be determined.
239
+ *
240
+ * Deliberately terminal and deliberately not retried: re-sending an order that may
241
+ * already exist is the one mistake worse than missing one. It waits for a person.
242
+ */
243
+ settleAmbiguous(signalId, message) {
244
+ this.db
245
+ .prepare("UPDATE live_signals SET status='ambiguous', error=?, updated_at=? WHERE id=? ")
246
+ .run(message.slice(0, 2_000), this.now(), signalId);
247
+ }
248
+ signal(id) {
249
+ const row = this.db.prepare(`SELECT ${SIGNAL_COLUMNS} FROM live_signals WHERE id=?`).get(id);
250
+ return row ? toSignal(row) : undefined;
251
+ }
252
+ signalAt(profileId, cutoffAt) {
253
+ const row = this.db
254
+ .prepare(`SELECT ${SIGNAL_COLUMNS} FROM live_signals WHERE profile_id=? AND cutoff_at=?`)
255
+ .get(profileId, cutoffAt);
256
+ return row ? toSignal(row) : undefined;
257
+ }
258
+ listSignals(profileId, limit = 50) {
259
+ const bounded = Math.max(1, Math.min(limit, MAX_PAGE_ROWS));
260
+ const rows = this.db
261
+ .prepare(`SELECT ${SIGNAL_COLUMNS} FROM live_signals WHERE profile_id=?
262
+ ORDER BY cutoff_at DESC LIMIT ?`)
263
+ .all(profileId, bounded);
264
+ return rows.map(toSignal);
265
+ }
266
+ /**
267
+ * Signals whose outcome is unresolved, for startup reconciliation.
268
+ *
269
+ * `submitted` rows may or may not have reached the exchange, and `reserved` rows
270
+ * were claimed by a worker that then died — both need checking against the
271
+ * exchange rather than assuming either outcome.
272
+ */
273
+ unresolvedSignals(limit = 200) {
274
+ const rows = this.db
275
+ .prepare(`SELECT ${SIGNAL_COLUMNS} FROM live_signals WHERE status IN ('reserved','submitted')
276
+ ORDER BY cutoff_at ASC LIMIT ?`)
277
+ .all(Math.max(1, Math.min(limit, MAX_PAGE_ROWS)));
278
+ return rows.map(toSignal);
279
+ }
280
+ /** The most recent minute at which this profile actually submitted an order. */
281
+ lastSubmittedAt(profileId) {
282
+ const row = this.db
283
+ .prepare("SELECT MAX(cutoff_at) AS cutoff FROM live_signals WHERE profile_id=? AND status='submitted'")
284
+ .get(profileId);
285
+ return row.cutoff === null ? undefined : Number(row.cutoff);
286
+ }
287
+ countByStatus(profileId) {
288
+ const rows = this.db
289
+ .prepare("SELECT status, COUNT(*) AS count FROM live_signals WHERE profile_id=? GROUP BY status")
290
+ .all(profileId);
291
+ const counts = {};
292
+ for (const row of rows)
293
+ counts[row.status] = Number(row.count);
294
+ return counts;
295
+ }
296
+ }
297
+ const PROFILE_COLUMNS = `id,name,strategy_hash,params_json,inst_id,account,environment,enabled,status,
298
+ generation,leverage,margin_mode,entry_budget_usdt,side_budget_usdt,daily_loss_limit_usdt,
299
+ cooldown_seconds,allow_long,allow_short,error_streak,last_error,backtest_run_id,origin,rationale,
300
+ created_at,updated_at`;
301
+ const SIGNAL_COLUMNS = `id,profile_id,cutoff_at,action,reason,status,blocked_by,quantity,order_id,
302
+ execution_key,error,details_json,created_at,updated_at`;
303
+ function toSignal(row) {
304
+ return {
305
+ id: String(row.id),
306
+ profileId: String(row.profile_id),
307
+ cutoffAt: Number(row.cutoff_at),
308
+ action: String(row.action),
309
+ reason: String(row.reason),
310
+ status: String(row.status),
311
+ blockedBy: row.blocked_by === null || row.blocked_by === undefined ? null : String(row.blocked_by),
312
+ quantity: row.quantity === null || row.quantity === undefined ? null : Number(row.quantity),
313
+ orderId: row.order_id === null || row.order_id === undefined ? null : String(row.order_id),
314
+ executionKey: row.execution_key === null || row.execution_key === undefined ? null : String(row.execution_key),
315
+ error: row.error === null || row.error === undefined ? null : String(row.error),
316
+ details: JSON.parse(String(row.details_json ?? "{}")),
317
+ createdAt: Number(row.created_at),
318
+ updatedAt: Number(row.updated_at)
319
+ };
320
+ }
321
+ function toProfile(row) {
322
+ return {
323
+ id: String(row.id),
324
+ name: String(row.name),
325
+ strategyHash: String(row.strategy_hash),
326
+ params: JSON.parse(String(row.params_json ?? "{}")),
327
+ instId: String(row.inst_id),
328
+ account: String(row.account),
329
+ environment: String(row.environment),
330
+ enabled: Number(row.enabled) === 1,
331
+ status: String(row.status),
332
+ generation: Number(row.generation),
333
+ leverage: Number(row.leverage),
334
+ marginMode: String(row.margin_mode),
335
+ entryBudgetUsdt: Number(row.entry_budget_usdt),
336
+ sideBudgetUsdt: Number(row.side_budget_usdt),
337
+ dailyLossLimitUsdt: Number(row.daily_loss_limit_usdt),
338
+ cooldownSeconds: Number(row.cooldown_seconds),
339
+ allowLong: Number(row.allow_long) === 1,
340
+ allowShort: Number(row.allow_short) === 1,
341
+ errorStreak: Number(row.error_streak),
342
+ lastError: row.last_error === null || row.last_error === undefined ? null : String(row.last_error),
343
+ backtestRunId: row.backtest_run_id === null || row.backtest_run_id === undefined ? null : String(row.backtest_run_id),
344
+ origin: String(row.origin ?? "operator"),
345
+ rationale: row.rationale === null || row.rationale === undefined ? null : String(row.rationale),
346
+ createdAt: Number(row.created_at),
347
+ updatedAt: Number(row.updated_at)
348
+ };
349
+ }
350
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/live/store.ts"],"names":[],"mappings":"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"}