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
@@ -0,0 +1,660 @@
1
+ /**
2
+ * User-facing strings for the CLI and shell.
3
+ *
4
+ * Only presentation is translated. Tool names, field names, run ids, and error
5
+ * codes stay in English so a copied message still matches the API and the
6
+ * documentation, and so a bug report reads the same in any locale.
7
+ */
8
+ export const LOCALES = ["en", "zh"];
9
+ export function isLocale(value) {
10
+ return LOCALES.includes(value);
11
+ }
12
+ const en = {
13
+ bannerTitle: "Desic OKX · strategy research",
14
+ bannerHints: "/help for commands tab completes ↑ recalls /exit leaves",
15
+ clearHint: "ctrl+c clears the line",
16
+ exitHint: "ctrl+c again to exit",
17
+ pythonNotFound: "python not found",
18
+ instrumentsWithHistory: (count) => `${count} instrument(s) with local history`,
19
+ working: "working",
20
+ cancelHint: "esc to cancel",
21
+ argumentsAsked: "Arguments you leave out are asked for.",
22
+ unknownCommand: (name) => `Unknown command '${name}'.`,
23
+ didYouMean: (name) => ` Did you mean /${name}?`,
24
+ seeHelp: " Type /help to see what is available.",
25
+ noCommandNamed: (name) => `No command named '${name}'.`,
26
+ needsTerminal: "The interactive shell needs a terminal. Use 'desic-okx <command>' for scripted use.",
27
+ needsUiPackages: "The interactive shell needs its UI packages. Install them with: npm install -g ink react",
28
+ noLocalHistory: "No local one-minute history yet.",
29
+ tryDownload: "Try: /download BTC-USDT-SWAP 30",
30
+ readingCoverage: "reading local coverage",
31
+ requestingHistory: (instId, days) => `${instId} requesting ${days} day(s) of one-minute history`,
32
+ daysMustBePositive: "Days must be a positive number, for example: /download BTC-USDT-SWAP 30",
33
+ instrumentColumn: "INSTRUMENT",
34
+ fromColumn: "FROM",
35
+ toColumn: "TO",
36
+ barsColumn: "BARS",
37
+ gapsColumn: "GAPS",
38
+ gapsNone: "none",
39
+ coverageRange: "Range",
40
+ coverageStored: (count) => `${count} one-minute bars`,
41
+ coverageMissing: (bars, gaps) => `${bars} bars in ${gaps} gaps`,
42
+ coverageMissingNone: "none",
43
+ coverageUpdated: "Updated",
44
+ coverageExchangeEnd: "Exchange end",
45
+ coverageGaps: "Gaps",
46
+ coverageMore: (count) => `… ${count} more`,
47
+ syncRange: "range",
48
+ syncExpected: "expected",
49
+ syncElapsed: "elapsed",
50
+ syncNoEarlierData: (time) => `OKX has no data before ${time} UTC`,
51
+ giveFileNew: "Give a file name: /new strategy.py [template]",
52
+ giveFileValidate: "Give a file: /validate strategy.py",
53
+ giveFileBacktest: "Give a file: /backtest strategy.py [instrument] [days]",
54
+ giveRunId: (command) => `Give a run id: /${command} bt_abc123`,
55
+ unknownTemplate: (name, available) => `Unknown template '${name}'. Available: ${available}`,
56
+ fileExists: (file) => `${file} already exists. Choose another name so nothing is overwritten.`,
57
+ fileMissing: (file) => `${file} does not exist.`,
58
+ wroteTemplate: (name, file) => `Wrote the ${name} template to ${file}`,
59
+ nextValidate: (file) => `Next: /validate ${file}`,
60
+ validating: (file) => `validating ${file}`,
61
+ policyPassed: "source policy passed",
62
+ policyViolations: (count) => `${count} violation(s)`,
63
+ violationLine: (line, message) => `line ${line} ${message}`,
64
+ backtestConfig: (file, instId, days) => `${file} ${instId} last ${days} day(s)`,
65
+ backtestWindow: (file, instId, window) => `${file} ${instId} ${window}`,
66
+ requestingWindow: (instId, window) => `${instId} requesting ${window}`,
67
+ backtestSettings: (equity, leverage, preload) => `${equity} USDT · ${leverage}x · ${preload} preload bars`,
68
+ queuing: (instId) => `${instId} queuing`,
69
+ noRuns: "No strategy runs yet.",
70
+ runsHint: "desic-okx strategy backtest --file strategy.py --inst BTC-USDT-SWAP",
71
+ forCurveAndTrades: (runId) => `/report ${runId} for the equity curve and trades`,
72
+ cancelled: (runId) => `Cancelled ${runId}`,
73
+ deleteConfirm: (runId) => `This removes ${runId} and its stored series. Repeat with --yes to confirm.`,
74
+ deleted: (runId) => `Deleted ${runId}`,
75
+ alreadyFinished: (runId) => `${runId} was already finished.`,
76
+ statusLabel: "Status",
77
+ barsLabel: "Bars",
78
+ includingPreloaded: (count) => `including ${count} preloaded`,
79
+ snapshotLabel: "Snapshot",
80
+ etaLabel: "ETA",
81
+ elapsedLabel: "Elapsed",
82
+ errorLabel: "Error",
83
+ performance: "Performance",
84
+ netProfit: "net profit",
85
+ returnLabel: "return",
86
+ annualized: "annualized",
87
+ annualizedWithheld: (days) => `needs ${days}+ days of data`,
88
+ maxDrawdown: "max drawdown",
89
+ drawdownRecovery: "longest drawdown",
90
+ riskAdjusted: "Risk adjusted",
91
+ sharpeLabel: "sharpe",
92
+ sortinoLabel: "sortino",
93
+ calmarLabel: "calmar",
94
+ activity: "Activity",
95
+ tradesLabel: "trades",
96
+ longShort: (long, short) => `${long} long / ${short} short`,
97
+ winRate: "win rate",
98
+ profitFactor: "profit factor",
99
+ netOfFees: "net of fees",
100
+ expectancy: "expectancy",
101
+ averageWinLoss: "avg win / loss",
102
+ largestWinLoss: "best / worst",
103
+ streaks: "streaks",
104
+ holdingTime: "avg holding",
105
+ costs: "Costs",
106
+ feesLabel: "fees",
107
+ feesOfGross: "of gross PnL",
108
+ turnover: "turnover",
109
+ exposure: "exposure",
110
+ tradesPerDay: "trades/day",
111
+ marginExhaustedWarning: "Margin was exhausted during this run.",
112
+ marginExhaustedDetail: "That is a research risk boundary, not an OKX liquidation estimate.",
113
+ reportOpened: "Report opened in your browser.",
114
+ reportWritten: "Report written (could not open a browser).",
115
+ hoverPrompt: "hover or use arrow keys for values",
116
+ hoverTime: "Time",
117
+ hoverEquity: "Equity",
118
+ hoverChange: "Change",
119
+ hoverDrawdown: "Drawdown",
120
+ settingsTitle: "Backtest settings",
121
+ settingsHint: "↑↓ move ⏎ edit or toggle r reset s save esc cancel",
122
+ settingsUnsaved: "unsaved changes — press s to save",
123
+ settingsSaved: "Settings saved. They apply to every backtest from now on.",
124
+ settingsCancelled: "Cancelled. Nothing was changed.",
125
+ settingsDefaultIs: "default",
126
+ settingsHeading: "Settings",
127
+ settingsHintCommand: "/backtest setting to change these",
128
+ assumptionsHeading: "Assumptions",
129
+ settingEquity: "Initial equity",
130
+ settingEquityHelp: "Starting balance in USDT. Position sizes are derived from equity, so this scales every trade.",
131
+ settingLeverage: "Leverage",
132
+ settingLeverageHelp: "Multiplies the entry budget into notional exposure. 10x on a 20% budget is 2x account notional.",
133
+ settingMarginSafety: "Margin safety",
134
+ settingMarginSafetyHelp: "Reserves this multiple of the required margin. Above 1 makes margin exhaustion less likely.",
135
+ settingBudgetPct: "Budget per entry",
136
+ settingBudgetPctHelp: "Share of current equity committed per entry. Compounds: gains raise later position sizes.",
137
+ settingBudgetUsdt: "Fixed budget",
138
+ settingBudgetUsdtHelp: "Fixed USDT per entry, overriding the percentage. Zero means use the percentage.",
139
+ settingTakerFee: "Taker fee",
140
+ settingTakerFeeHelp: "Charged on market fills. OKX standard is 5 bps; a VIP tier is lower.",
141
+ settingMakerFee: "Maker fee",
142
+ settingMakerFeeHelp: "Charged on limit fills. OKX standard is 2 bps.",
143
+ settingEntrySlippage: "Entry slippage",
144
+ settingEntrySlippageHelp: "Adverse price applied to every entry, in basis points.",
145
+ settingExitSlippage: "Exit slippage",
146
+ settingExitSlippageHelp: "Adverse price applied to every exit, in basis points.",
147
+ settingPreload: "Preload bars",
148
+ settingPreloadHelp: "Confirmed bars loaded before the evaluation start, for indicator warm-up. Excluded from results.",
149
+ settingDays: "Evaluation days",
150
+ settingDaysHelp: "Default trailing window when no explicit range is given.",
151
+ settingCloseAtEnd: "Close at end",
152
+ settingCloseAtEndHelp: "Flattens any open position on the final bar, so the result excludes an unrealized position.",
153
+ monthlyHeading: "By month",
154
+ distributionHeading: "Trade distribution",
155
+ colSide: "Side",
156
+ colQty: "Qty",
157
+ colEntry: "Entry",
158
+ colExit: "Exit",
159
+ colNetPnl: "Net PnL",
160
+ colReturn: "Ret%",
161
+ colCumulative: "Cumulative",
162
+ colFees: "Fees",
163
+ colHeld: "Held",
164
+ colOpened: "Opened",
165
+ colClosed: "Closed",
166
+ colMonth: "Month",
167
+ colOpenEquity: "Open",
168
+ colCloseEquity: "Close",
169
+ colChange: "Change",
170
+ colWorstDrop: "Worst drop",
171
+ equityHeading: "Equity",
172
+ tradesHeading: "Trades",
173
+ noClosedTrades: "(no closed trades)",
174
+ notEnoughPoints: "(not enough equity points to plot)",
175
+ simulationNote: "Simulated: fees, slippage, fills at the next bar's open, conservative limit fills.",
176
+ cmdHelp: "List commands, or explain one",
177
+ cmdData: "Show local one-minute history and its covered range",
178
+ cmdDataDetail: "Lists every instrument with stored bars, the UTC range covered, and how many bars are missing.",
179
+ cmdDownload: "Download or repair local one-minute history",
180
+ cmdDownloadDetail: "Fetches only the minutes that are absent. Higher timeframes are derived from one-minute bars, so this is the only download you need.",
181
+ cmdNew: "Write a starting strategy file",
182
+ cmdNewDetail: "Templates: blank, ema-trend, atr-breakout, bollinger-reversion.",
183
+ cmdValidate: "Statically check a strategy file",
184
+ cmdValidateDetail: "Reports policy violations with line numbers. Always cheaper than discovering them after a run.",
185
+ cmdBacktest: "Run a backtest",
186
+ cmdBacktestDetail: "Asks for anything missing, then runs. `/backtest setting` opens the assumptions form instead of starting a run.",
187
+ cmdOptimize: "Search a parameter space and rank candidates out of sample",
188
+ cmdOptimizeDetail: "Splits the window 70/30, searches the first part, and ranks by the second. A candidate that only works on the searched part is marked overfit. `/optimize report <runId>` reprints the table; add `--adopt <file>` to save the best parameters beside your strategy.",
189
+ cmdCompare: "Put two or more runs side by side",
190
+ cmdCompareDetail: "Overlays the equity curves normalized to a common start, shows only the assumptions that differ, and warns when the runs used different data. Opens in the browser; `--no-open` prints a table instead.",
191
+ cmdLive: "List live profiles, read their decisions, or stop one",
192
+ cmdLiveDetail: "Read-only apart from stopping. Creating and starting a profile stay in the CLI, because they are the two actions that commit money to a strategy — `desic-okx live create` and `desic-okx live start`.",
193
+ argLiveAction: "signals | stop; omit to list profiles",
194
+ argLiveProfileId: "profile id, for signals or stop",
195
+ cmdMarket: "Show or switch which OKX venue supplies market data",
196
+ cmdMarketDetail: "Demo and live are separate markets with different prices, so bars from one are not comparable with the other. Switching writes the setting; the runtime reads it at startup, so it applies after `desic-okx stop`. Bars already stored keep the venue they came from.",
197
+ argMarketEnv: "demo | live; omit to show the current one",
198
+ cmdSettings: "View or change the assumptions every backtest uses",
199
+ cmdSettingsDetail: "Opens the same form as `/backtest setting`. Saved to disk and applied to every later run.",
200
+ cmdCoverage: "Show one instrument's stored range and its gaps",
201
+ cmdCoverageDetail: "Lists the gaps that would make a backtest over that range fail, so they can be repaired first.",
202
+ cmdDelete: "Delete a run and its stored series",
203
+ cmdDeleteDetail: "Removes the equity curve, trades, and decisions. Asks for confirmation first.",
204
+ cmdRuns: "List recent runs",
205
+ cmdReport: "Show a run's metrics, equity curve, and trades",
206
+ cmdCancel: "Cancel a queued or running backtest",
207
+ cmdEnv: "Check the local Python environment",
208
+ cmdStatus: "Show runtime, market feed, and database status",
209
+ cmdLang: "Switch display language (en / zh)",
210
+ cmdLangDetail: "Saved to disk and reused on the next start. Tool names, field names, and error codes stay in English so a copied message still matches the API.",
211
+ cmdClear: "Clear the screen",
212
+ cmdClearDetail: "Clears the visible screen. Earlier output remains in the terminal's scrollback, because a scrolling shell writes each line once and never takes it back.",
213
+ cmdExit: "Leave the shell",
214
+ argHelpCommand: "Command to explain",
215
+ argInstrument: "OKX instrument ID",
216
+ argWindow30: "30, or 2026-07-01..2026-08-01",
217
+ argWindow90: "90, or 2026-05-01..2026-08-01",
218
+ argDestinationFile: "Destination file",
219
+ argTemplate: "blank | ema-trend | atr-breakout | bollinger-reversion",
220
+ argStrategyToCheck: "Strategy file to check",
221
+ argStrategyOrSetting: "Strategy file, or `setting` to edit assumptions",
222
+ argStrategyOrReport: "Strategy file, or `report` to reprint a finished search",
223
+ argSpaceFile: "Per-parameter { min, max, step } ranges",
224
+ argBudget: "Candidates to evaluate",
225
+ argRunsToCompare: "Two or more run ids, separated by spaces",
226
+ argNoOpen: "Print in the terminal instead of the browser",
227
+ argRunToDelete: "Run to delete",
228
+ argRowLimit: "Rows to list",
229
+ argRunToOpen: "Run to open, for example bt_abc123",
230
+ argRunToCancel: "Run to cancel",
231
+ argEnvSetup: "Create the environment instead of checking it",
232
+ argLocale: "en | zh; omit to show the current one",
233
+ argRequired: "required",
234
+ argOptional: "optional",
235
+ argDefault: (value) => `default ${value}`,
236
+ agentAccessState: (state) => `Agent access to live profiles: ${state}`,
237
+ agentAccessSet: (state) => `Agent access to live profiles set to ${state}.`,
238
+ agentAccessRestart: "Restart the MCP client to apply it — the tool list is built when that client connects.",
239
+ agentAccessWarning: "An agent can now create and enable demo profiles on its own. A real-money profile still requires its name typed back by a person.",
240
+ agentAccessUsage: "Usage: desic-okx live agent-access <on|off>",
241
+ liveNoProfiles: "No live profiles yet.",
242
+ liveCreateHint: "desic-okx live create --file ema.py --inst BTC-USDT-SWAP --account demo --entry-budget 100 --side-budget 400 --daily-loss 200",
243
+ liveNameColumn: "NAME",
244
+ liveBudgetColumn: "ENTRY/SIDE",
245
+ liveErrorColumn: "ERRORS",
246
+ liveEnabled: "enabled",
247
+ liveStopped: "stopped",
248
+ liveReady: "Ready to start.",
249
+ liveNotReady: (count) => `${count} thing(s) block starting this profile:`,
250
+ liveEvidence: (runId) => `Backtest evidence: ${runId}`,
251
+ liveRealMoneyWarning: "This profile trades with real money once started.",
252
+ liveNoSignals: "(no decisions recorded yet)",
253
+ liveCutoffColumn: "MINUTE",
254
+ liveActionColumn: "ACTION",
255
+ liveDetailColumn: "DETAIL",
256
+ liveQtyColumn: "QTY",
257
+ liveProfileCreated: (id) => `Created ${id}. It is stopped; nothing trades until you start it.`,
258
+ liveProfileStarted: (name) => `${name} is live. It now acts on every closed minute.`,
259
+ liveProfileStopped: (name) => `${name} stopped.`,
260
+ liveDeleteConfirm: (id) => `This removes ${id} and its signal history. Repeat with --yes to confirm.`,
261
+ marketEnvironmentLabel: "Market data:",
262
+ marketEnvironmentDemo: "demo (simulated)",
263
+ marketEnvironmentLive: "live",
264
+ demoDataWarning: "Prices and candles come from OKX's simulator, not the real market.",
265
+ environmentSwitched: (env) => `Market data environment set to ${env}.`,
266
+ environmentAlready: (env) => `Market data is already set to ${env}.`,
267
+ environmentRestartHint: "Run 'desic-okx stop' to apply it — the runtime reads this once at startup, and bars already stored stay with the environment they came from.",
268
+ environmentUsage: "Usage: desic-okx market env <demo|live>",
269
+ environmentUsageShell: "Usage: /market <demo|live>",
270
+ warnDifferentData: "These runs consumed different data. Metrics are not directly comparable: any difference may come from the bars rather than the strategy.",
271
+ warnDifferentInstruments: (list) => `Different instruments: ${list}. Returns reflect each market's own move, not a better strategy.`,
272
+ warnDifferentWindows: "These runs cover different evaluation windows, so their totals span different amounts of time.",
273
+ warnDifferentAssumptions: (keys) => `Different assumptions: ${keys}. A return figure means nothing without the costs behind it.`,
274
+ warnIncompleteRuns: (list) => `Not every run finished: ${list}`,
275
+ strategyColumn: "STRATEGY",
276
+ differingAssumptionsHeading: "Assumptions that differ",
277
+ assumptionsIdentical: "Every assumption matches across these runs.",
278
+ sharedAssumptionsNote: (count) => `${count} further assumptions are identical and were collapsed.`,
279
+ compareNormalizedNote: "Curves are indexed to 100 at each run's own start, so different initial equity does not change the shape.",
280
+ compareNeedsTwo: "Give at least two run ids: /compare bt_abc123 bt_def456",
281
+ compareTooMany: (limit) => `A comparison holds at most ${limit} runs.`,
282
+ comparisonHeading: "Comparison",
283
+ comparedRunsHeading: "Runs",
284
+ normalizedEquityHeading: "Normalized equity",
285
+ spaceLabel: "Space",
286
+ candidatesLabel: "Candidates",
287
+ candidatesOf: (done, budget, combinations) => `${done} of ${budget} evaluated, from ${combinations} possible`,
288
+ candidatesFailed: (count) => `${count} failed`,
289
+ trainLabel: "Train",
290
+ validationLabel: "Validate",
291
+ trainReturn: "TRAIN RET",
292
+ validationReturn: "VALID RET",
293
+ trainDrawdown: "TRAIN DD",
294
+ validationDrawdown: "VALID DD",
295
+ verdictColumn: "VERDICT",
296
+ verdictHolds: "holds",
297
+ verdictOverfit: "overfit",
298
+ verdictWeak: "weak",
299
+ verdictUnexplained: "unexplained",
300
+ overfitNote: "The validation column is the reportable one. A strong training return beside a weak validation return is fitted to noise, not an edge. Read the two columns together: a table where every candidate lost on training and won on validation says the validation segment favoured this kind of strategy, not that any candidate was confirmed.",
301
+ selectionNote: "The winner was chosen by its validation score, so that score is itself somewhat selected. Confirm on a later period before trusting the figure.",
302
+ noCandidatesYet: "(no candidate has finished yet)",
303
+ giveFileOptimize: "Give a file: /optimize strategy.py [instrument] [days | range]",
304
+ giveSpaceFile: "Give a parameter space file, for example space.json",
305
+ spaceFileMissing: (file) => `${file} does not exist. It holds { \"param\": { \"min\": 5, \"max\": 50, \"step\": 5 } }.`,
306
+ spaceFileInvalid: (file) => `${file} is not valid JSON.`,
307
+ optimizeWindow: (file, instId, window) => `${file} ${instId} ${window}`,
308
+ optimizeSearch: (candidates, combinations) => `${candidates} candidates from ${combinations} combinations`,
309
+ forCandidateTable: (runId) => `/optimize report ${runId} for the full candidate table`,
310
+ adoptedParams: (file) => `Best parameters written to ${file}`,
311
+ adoptHint: (runId) => `Backtest them on their own to confirm, then compare against ${runId}`,
312
+ noBestCandidate: "No candidate finished, so there is nothing to adopt.",
313
+ pythonLabel: "Python",
314
+ readyLabel: "Ready",
315
+ notFound: "not found",
316
+ yes: "yes",
317
+ no: "no",
318
+ fixLabel: "Fix",
319
+ checkingEnvironment: "checking the Python environment",
320
+ preparingEnvironment: "preparing the Python environment (this can take a few minutes)",
321
+ environmentReady: "Environment ready",
322
+ runtimeLabel: "Runtime",
323
+ publicWs: "Public WS",
324
+ businessWs: "Business WS",
325
+ subscribed: (count) => `${count} instrument(s)`,
326
+ databaseLabel: "Database",
327
+ readingStatus: "reading runtime status",
328
+ readingRuns: "reading recent runs",
329
+ readingRun: (runId) => `reading ${runId}`,
330
+ languageChanged: (locale) => `Language set to ${locale}. It is saved and will be used next time.`,
331
+ languageCurrent: (locale) => `Current language: ${locale}`,
332
+ languageUsage: "Usage: /lang en | /lang zh"
333
+ };
334
+ const zh = {
335
+ bannerTitle: "Desic OKX · 策略研究",
336
+ bannerHints: "/help 查看命令 tab 补全 ↑ 历史 /exit 退出",
337
+ clearHint: "ctrl+c 清空输入",
338
+ exitHint: "再按 ctrl+c 退出",
339
+ pythonNotFound: "未找到 python",
340
+ instrumentsWithHistory: (count) => `本地已有 ${count} 个合约的历史数据`,
341
+ working: "处理中",
342
+ cancelHint: "按 esc 取消",
343
+ argumentsAsked: "未填写的参数会使用默认值。",
344
+ unknownCommand: (name) => `未知命令 '${name}'。`,
345
+ didYouMean: (name) => ` 是否想输入 /${name}?`,
346
+ seeHelp: " 输入 /help 查看可用命令。",
347
+ noCommandNamed: (name) => `没有名为 '${name}' 的命令。`,
348
+ needsTerminal: "交互式界面需要终端。脚本调用请使用 'desic-okx <命令>'。",
349
+ needsUiPackages: "交互式界面需要 UI 依赖。请安装:npm install -g ink react",
350
+ noLocalHistory: "本地还没有 1 分钟历史数据。",
351
+ tryDownload: "试试:/download BTC-USDT-SWAP 30",
352
+ readingCoverage: "正在读取本地数据覆盖情况",
353
+ requestingHistory: (instId, days) => `${instId} 正在请求 ${days} 天的 1 分钟数据`,
354
+ daysMustBePositive: "天数必须是正数,例如:/download BTC-USDT-SWAP 30",
355
+ instrumentColumn: "合约",
356
+ fromColumn: "起始",
357
+ toColumn: "结束",
358
+ barsColumn: "根数",
359
+ gapsColumn: "缺口",
360
+ gapsNone: "无",
361
+ coverageRange: "区间",
362
+ coverageStored: (count) => `${count} 根 1 分钟 K 线`,
363
+ coverageMissing: (bars, gaps) => `缺 ${bars} 根,共 ${gaps} 处缺口`,
364
+ coverageMissingNone: "无",
365
+ coverageUpdated: "更新于",
366
+ coverageExchangeEnd: "交易所边界",
367
+ coverageGaps: "缺口",
368
+ coverageMore: (count) => `… 还有 ${count} 处`,
369
+ syncRange: "区间",
370
+ syncExpected: "应有",
371
+ syncElapsed: "耗时",
372
+ syncNoEarlierData: (time) => `OKX 没有 ${time} UTC 之前的数据`,
373
+ giveFileNew: "请给出文件名:/new strategy.py [模板]",
374
+ giveFileValidate: "请给出文件:/validate strategy.py",
375
+ giveFileBacktest: "请给出文件:/backtest strategy.py [合约] [天数]",
376
+ giveRunId: (command) => `请给出运行 ID:/${command} bt_abc123`,
377
+ unknownTemplate: (name, available) => `未知模板 '${name}'。可选:${available}`,
378
+ fileExists: (file) => `${file} 已存在。请换一个名字,避免覆盖。`,
379
+ fileMissing: (file) => `${file} 不存在。`,
380
+ wroteTemplate: (name, file) => `已将 ${name} 模板写入 ${file}`,
381
+ nextValidate: (file) => `下一步:/validate ${file}`,
382
+ validating: (file) => `正在校验 ${file}`,
383
+ policyPassed: "源码校验通过",
384
+ policyViolations: (count) => `${count} 处违规`,
385
+ violationLine: (line, message) => `第 ${line} 行 ${message}`,
386
+ backtestConfig: (file, instId, days) => `${file} ${instId} 最近 ${days} 天`,
387
+ backtestWindow: (file, instId, window) => `${file} ${instId} ${window}`,
388
+ requestingWindow: (instId, window) => `${instId} 正在请求 ${window}`,
389
+ backtestSettings: (equity, leverage, preload) => `${equity} USDT · ${leverage}倍 · 预热 ${preload} 根`,
390
+ queuing: (instId) => `${instId} 正在排队`,
391
+ noRuns: "还没有任何回测记录。",
392
+ runsHint: "desic-okx strategy backtest --file strategy.py --inst BTC-USDT-SWAP",
393
+ forCurveAndTrades: (runId) => `/report ${runId} 查看权益曲线与成交明细`,
394
+ cancelled: (runId) => `已取消 ${runId}`,
395
+ deleteConfirm: (runId) => `这会删除 ${runId} 及其存储的数据。加 --yes 确认。`,
396
+ deleted: (runId) => `已删除 ${runId}`,
397
+ alreadyFinished: (runId) => `${runId} 已经结束了。`,
398
+ statusLabel: "状态",
399
+ barsLabel: "K 线",
400
+ includingPreloaded: (count) => `含 ${count} 根预热`,
401
+ snapshotLabel: "数据快照",
402
+ etaLabel: "预计剩余",
403
+ elapsedLabel: "耗时",
404
+ errorLabel: "错误",
405
+ performance: "收益表现",
406
+ netProfit: "净盈亏",
407
+ returnLabel: "收益率",
408
+ annualized: "年化",
409
+ annualizedWithheld: (days) => `需要 ${days} 天以上数据`,
410
+ maxDrawdown: "最大回撤",
411
+ drawdownRecovery: "最长回撤",
412
+ riskAdjusted: "风险调整",
413
+ sharpeLabel: "夏普",
414
+ sortinoLabel: "索提诺",
415
+ calmarLabel: "卡玛",
416
+ activity: "交易活动",
417
+ tradesLabel: "成交笔数",
418
+ longShort: (long, short) => `多 ${long} / 空 ${short}`,
419
+ winRate: "胜率",
420
+ profitFactor: "盈亏比",
421
+ netOfFees: "已扣手续费",
422
+ expectancy: "单笔期望",
423
+ averageWinLoss: "平均盈利/亏损",
424
+ largestWinLoss: "最大盈利/亏损",
425
+ streaks: "连续盈亏",
426
+ holdingTime: "平均持仓",
427
+ costs: "成本",
428
+ feesLabel: "手续费",
429
+ feesOfGross: "占毛利比例",
430
+ turnover: "成交额",
431
+ exposure: "持仓占比",
432
+ tradesPerDay: "日均交易",
433
+ marginExhaustedWarning: "本次回测触发了保证金耗尽。",
434
+ marginExhaustedDetail: "这是研究用的风险边界,不是 OKX 强平价格的估算。",
435
+ reportOpened: "报告已在浏览器中打开。",
436
+ reportWritten: "报告已生成(未能自动打开浏览器)。",
437
+ hoverPrompt: "鼠标悬停或用方向键查看数值",
438
+ hoverTime: "时间",
439
+ hoverEquity: "权益",
440
+ hoverChange: "涨跌",
441
+ hoverDrawdown: "回撤",
442
+ settingsTitle: "回测参数",
443
+ settingsHint: "↑↓ 移动 ⏎ 编辑或切换 r 恢复默认 s 保存 esc 取消",
444
+ settingsUnsaved: "有未保存的修改 —— 按 s 保存",
445
+ settingsSaved: "参数已保存,之后的回测都会使用。",
446
+ settingsCancelled: "已取消,没有任何改动。",
447
+ settingsDefaultIs: "默认",
448
+ settingsHeading: "参数",
449
+ settingsHintCommand: "/backtest setting 修改这些参数",
450
+ assumptionsHeading: "本次回测参数",
451
+ settingEquity: "初始权益",
452
+ settingEquityHelp: "起始资金(USDT)。仓位按权益计算,所以这个值会等比缩放每一笔交易。",
453
+ settingLeverage: "杠杆",
454
+ settingLeverageHelp: "把入场预算放大成名义敞口。20% 预算配 10 倍 = 账户 2 倍名义敞口。",
455
+ settingMarginSafety: "保证金安全系数",
456
+ settingMarginSafetyHelp: "按所需保证金的这个倍数预留。大于 1 可降低保证金耗尽的概率。",
457
+ settingBudgetPct: "单笔预算比例",
458
+ settingBudgetPctHelp: "每笔入场投入当前权益的比例。会复利:赚了之后仓位变大。",
459
+ settingBudgetUsdt: "单笔固定预算",
460
+ settingBudgetUsdtHelp: "每笔固定投入的 USDT,优先于比例。填 0 表示用比例。",
461
+ settingTakerFee: "Taker 手续费",
462
+ settingTakerFeeHelp: "市价成交收取。OKX 标准档为 5 bps,VIP 更低。",
463
+ settingMakerFee: "Maker 手续费",
464
+ settingMakerFeeHelp: "限价成交收取。OKX 标准档为 2 bps。",
465
+ settingEntrySlippage: "入场滑点",
466
+ settingEntrySlippageHelp: "每次入场施加的不利价格偏移(基点)。",
467
+ settingExitSlippage: "出场滑点",
468
+ settingExitSlippageHelp: "每次出场施加的不利价格偏移(基点)。",
469
+ settingPreload: "预热 K 线",
470
+ settingPreloadHelp: "评估区间之前加载的已确认 K 线,用于指标预热,不计入结果。",
471
+ settingDays: "评估天数",
472
+ settingDaysHelp: "未指定具体区间时使用的默认回溯窗口。",
473
+ settingCloseAtEnd: "期末平仓",
474
+ settingCloseAtEndHelp: "在最后一根 K 线平掉未平仓位,使结果不含浮动盈亏。",
475
+ monthlyHeading: "按月表现",
476
+ distributionHeading: "单笔盈亏分布",
477
+ colSide: "方向",
478
+ colQty: "数量",
479
+ colEntry: "开仓价",
480
+ colExit: "平仓价",
481
+ colNetPnl: "净盈亏",
482
+ colReturn: "收益率",
483
+ colCumulative: "累计",
484
+ colFees: "手续费",
485
+ colHeld: "持仓",
486
+ colOpened: "开仓时间",
487
+ colClosed: "平仓时间",
488
+ colMonth: "月份",
489
+ colOpenEquity: "月初权益",
490
+ colCloseEquity: "月末权益",
491
+ colChange: "涨跌",
492
+ colWorstDrop: "最大回落",
493
+ equityHeading: "权益曲线",
494
+ tradesHeading: "成交明细",
495
+ noClosedTrades: "(没有已平仓交易)",
496
+ notEnoughPoints: "(权益点太少,无法绘图)",
497
+ simulationNote: "模拟结果:含手续费、滑点,下一根开盘成交,限价单按保守估计。",
498
+ cmdHelp: "列出所有命令,或说明其中一个",
499
+ cmdData: "查看本地 1 分钟数据及其覆盖区间",
500
+ cmdDataDetail: "列出每个已有数据的合约、覆盖的 UTC 区间,以及缺失了多少根。",
501
+ cmdDownload: "下载或补齐本地 1 分钟数据",
502
+ cmdDownloadDetail: "只请求缺失的那些分钟。更高周期都由 1 分钟数据合成,所以只需要下载这一种。",
503
+ cmdNew: "生成一个策略文件模板",
504
+ cmdNewDetail: "可选模板:blank、ema-trend、atr-breakout、bollinger-reversion。",
505
+ cmdValidate: "静态校验策略文件",
506
+ cmdValidateDetail: "报出违规位置和行号。比排队跑完才发现问题要划算得多。",
507
+ cmdBacktest: "执行一次回测",
508
+ cmdBacktestDetail: "缺少的参数会询问,然后开始运行。`/backtest setting` 打开参数表单,而不是启动回测。",
509
+ cmdOptimize: "搜索参数空间,并用样本外区间排名",
510
+ cmdOptimizeDetail: "把窗口按 7:3 切分,在前段搜索、用后段排名。只在搜索段有效的候选会被标为过拟合。`/optimize report <运行ID>` 重新打印候选表;加 `--adopt <文件>` 可把最佳参数保存到策略旁边。",
511
+ cmdCompare: "把两个或多个回测并排比较",
512
+ cmdCompareDetail: "把权益曲线归一化到同一起点后叠加,只显示有差异的参数,并在两次运行数据不同时给出警告。默认在浏览器打开;`--no-open` 则在终端打印表格。",
513
+ cmdLive: "列出实盘配置、查看决策记录,或停止某个配置",
514
+ cmdLiveDetail: "除停止外均为只读。创建和启动仍留在 CLI —— 这两个动作会把资金投入某个策略:`desic-okx live create` 和 `desic-okx live start`。",
515
+ argLiveAction: "signals | stop;留空则列出全部配置",
516
+ argLiveProfileId: "配置 ID,用于 signals 或 stop",
517
+ cmdMarket: "查看或切换行情数据来自哪个 OKX 环境",
518
+ cmdMarketDetail: "模拟盘和实盘是两个独立市场、价格不同,所以两边的 K 线不可混用。切换只写入配置;runtime 在启动时读取,因此需要执行 `desic-okx stop` 后生效。已存的 K 线仍归属它原本的环境。",
519
+ argMarketEnv: "demo | live;留空则显示当前设置",
520
+ cmdSettings: "查看或修改所有回测共用的参数",
521
+ cmdSettingsDetail: "和 `/backtest setting` 打开的是同一个表单。保存到磁盘,之后每次回测都会生效。",
522
+ cmdCoverage: "查看单个合约的数据区间与缺口",
523
+ cmdCoverageDetail: "列出会导致该区间回测失败的缺口,便于先补齐。",
524
+ cmdDelete: "删除一次运行及其存储的数据",
525
+ cmdDeleteDetail: "会删掉权益曲线、成交明细和决策记录。删除前会要求确认。",
526
+ cmdRuns: "列出最近的运行记录",
527
+ cmdReport: "查看一次运行的指标、权益曲线和成交明细",
528
+ cmdCancel: "取消排队中或正在运行的回测",
529
+ cmdEnv: "检查本地 Python 环境",
530
+ cmdStatus: "查看运行时、行情连接和数据库状态",
531
+ cmdLang: "切换显示语言(en / zh)",
532
+ cmdLangDetail: "保存到磁盘,下次启动继续生效。工具名、字段名和错误码保持英文,这样复制出来的信息仍能对应 API。",
533
+ cmdClear: "清屏",
534
+ cmdClearDetail: "只清空当前可见区域。之前的输出仍留在终端回滚缓冲里 —— 滚动式界面每行只写一次,不会收回。",
535
+ cmdExit: "退出交互界面",
536
+ argHelpCommand: "要说明的命令",
537
+ argInstrument: "OKX 合约 ID",
538
+ argWindow30: "30,或 2026-07-01..2026-08-01",
539
+ argWindow90: "90,或 2026-05-01..2026-08-01",
540
+ argDestinationFile: "目标文件",
541
+ argTemplate: "blank | ema-trend | atr-breakout | bollinger-reversion",
542
+ argStrategyToCheck: "要校验的策略文件",
543
+ argStrategyOrSetting: "策略文件,或填 `setting` 修改回测参数",
544
+ argStrategyOrReport: "策略文件,或填 `report` 重新打印已完成的搜索",
545
+ argSpaceFile: "每个参数的 { min, max, step } 范围",
546
+ argBudget: "要评估的候选数量",
547
+ argRunsToCompare: "两个或更多运行 ID,用空格分隔",
548
+ argNoOpen: "在终端打印,而不是打开浏览器",
549
+ argRunToDelete: "要删除的运行",
550
+ argRowLimit: "列出的行数",
551
+ argRunToOpen: "要查看的运行,例如 bt_abc123",
552
+ argRunToCancel: "要取消的运行",
553
+ argEnvSetup: "创建环境,而不是只做检查",
554
+ argLocale: "en | zh;留空则显示当前语言",
555
+ argRequired: "必填",
556
+ argOptional: "可选",
557
+ argDefault: (value) => `默认 ${value}`,
558
+ agentAccessState: (state) => `agent 的实盘权限:${state}`,
559
+ agentAccessSet: (state) => `agent 的实盘权限已设为 ${state}。`,
560
+ agentAccessRestart: "需重启 MCP 客户端生效 —— 工具列表在客户端连接时构建。",
561
+ agentAccessWarning: "agent 现在可以自主创建并启用模拟盘配置。真实资金的配置仍需由人手打名字确认。",
562
+ agentAccessUsage: "用法:desic-okx live agent-access <on|off>",
563
+ liveNoProfiles: "还没有实盘配置。",
564
+ liveCreateHint: "desic-okx live create --file ema.py --inst BTC-USDT-SWAP --account demo --entry-budget 100 --side-budget 400 --daily-loss 200",
565
+ liveNameColumn: "名称",
566
+ liveBudgetColumn: "单笔/同向",
567
+ liveErrorColumn: "连续错误",
568
+ liveEnabled: "已启用",
569
+ liveStopped: "已停止",
570
+ liveReady: "可以启动。",
571
+ liveNotReady: (count) => `有 ${count} 项阻碍启动:`,
572
+ liveEvidence: (runId) => `回测依据:${runId}`,
573
+ liveRealMoneyWarning: "启动后这个配置会用真实资金交易。",
574
+ liveNoSignals: "(还没有决策记录)",
575
+ liveCutoffColumn: "分钟",
576
+ liveActionColumn: "动作",
577
+ liveDetailColumn: "详情",
578
+ liveQtyColumn: "张数",
579
+ liveProfileCreated: (id) => `已创建 ${id}。当前为停止状态,启动前不会有任何交易。`,
580
+ liveProfileStarted: (name) => `${name} 已启用,之后每根收线都会执行。`,
581
+ liveProfileStopped: (name) => `${name} 已停止。`,
582
+ liveDeleteConfirm: (id) => `这会删除 ${id} 及其信号历史。加 --yes 确认。`,
583
+ marketEnvironmentLabel: "行情数据:",
584
+ marketEnvironmentDemo: "模拟盘",
585
+ marketEnvironmentLive: "实盘",
586
+ demoDataWarning: "价格与 K 线来自 OKX 模拟盘,不是真实市场。",
587
+ environmentSwitched: (env) => `行情数据环境已设为 ${env}。`,
588
+ environmentAlready: (env) => `行情数据环境已经是 ${env} 了。`,
589
+ environmentRestartHint: "执行 'desic-okx stop' 生效 —— runtime 只在启动时读一次这个配置;已存的 K 线仍归属它原本的环境。",
590
+ environmentUsage: "用法:desic-okx market env <demo|live>",
591
+ environmentUsageShell: "用法:/market <demo|live>",
592
+ warnDifferentData: "这几次运行使用的数据并不相同。指标无法直接对比:差异可能来自数据本身,而不是策略。",
593
+ warnDifferentInstruments: (list) => `合约不同:${list}。收益反映的是各自市场的涨跌,并不说明策略更好。`,
594
+ warnDifferentWindows: "这几次运行的评估区间不同,因此各项合计覆盖的时间长度也不一样。",
595
+ warnDifferentAssumptions: (keys) => `参数不同:${keys}。脱离背后的成本设定,收益率没有意义。`,
596
+ warnIncompleteRuns: (list) => `并非所有运行都已完成:${list}`,
597
+ strategyColumn: "策略",
598
+ differingAssumptionsHeading: "有差异的参数",
599
+ assumptionsIdentical: "这几次运行的参数完全一致。",
600
+ sharedAssumptionsNote: (count) => `另有 ${count} 项参数完全相同,已折叠。`,
601
+ compareNormalizedNote: "曲线按各自起点归一化到 100,因此初始权益不同不会影响形状。",
602
+ compareNeedsTwo: "请至少给出两个运行 ID:/compare bt_abc123 bt_def456",
603
+ compareTooMany: (limit) => `一次最多对比 ${limit} 个运行。`,
604
+ comparisonHeading: "对比",
605
+ comparedRunsHeading: "参与对比的运行",
606
+ normalizedEquityHeading: "归一化权益曲线",
607
+ spaceLabel: "参数空间",
608
+ candidatesLabel: "候选",
609
+ candidatesOf: (done, budget, combinations) => `已评估 ${done} / ${budget},全部组合 ${combinations} 个`,
610
+ candidatesFailed: (count) => `${count} 个失败`,
611
+ trainLabel: "训练段",
612
+ validationLabel: "验证段",
613
+ trainReturn: "训练收益",
614
+ validationReturn: "验证收益",
615
+ trainDrawdown: "训练回撤",
616
+ validationDrawdown: "验证回撤",
617
+ verdictColumn: "结论",
618
+ verdictHolds: "稳健",
619
+ verdictOverfit: "过拟合",
620
+ verdictWeak: "偏弱",
621
+ verdictUnexplained: "无从解释",
622
+ overfitNote: "应当引用的是验证段数据。训练段亮眼而验证段疲软,说明拟合的是噪声,不是真实的优势。两列要合起来读:如果整张表都是训练段亏、验证段赚,那说明验证段这段行情本身有利于这类策略,而不是某个候选得到了验证。",
623
+ selectionNote: "第一名是按验证段得分挑出来的,因此该得分本身也带有挑选成分。要相信这个数字,需在更晚的区间上再确认一次。",
624
+ noCandidatesYet: "(还没有候选跑完)",
625
+ giveFileOptimize: "请给出文件:/optimize strategy.py [合约] [天数或区间]",
626
+ giveSpaceFile: "请给出参数空间文件,例如 space.json",
627
+ spaceFileMissing: (file) => `${file} 不存在。文件内容形如 { "param": { "min": 5, "max": 50, "step": 5 } }。`,
628
+ spaceFileInvalid: (file) => `${file} 不是合法的 JSON。`,
629
+ optimizeWindow: (file, instId, window) => `${file} ${instId} ${window}`,
630
+ optimizeSearch: (candidates, combinations) => `从 ${combinations} 个组合中取 ${candidates} 个候选`,
631
+ forCandidateTable: (runId) => `/optimize report ${runId} 查看完整候选表`,
632
+ adoptedParams: (file) => `最佳参数已写入 ${file}`,
633
+ adoptHint: (runId) => `建议用这组参数单独回测确认,再与 ${runId} 对比`,
634
+ noBestCandidate: "没有候选跑完,暂无可采用的参数。",
635
+ pythonLabel: "Python",
636
+ readyLabel: "就绪",
637
+ notFound: "未找到",
638
+ yes: "是",
639
+ no: "否",
640
+ fixLabel: "修复",
641
+ checkingEnvironment: "正在检查 Python 环境",
642
+ preparingEnvironment: "正在准备 Python 环境(可能需要几分钟)",
643
+ environmentReady: "环境已就绪",
644
+ runtimeLabel: "运行时",
645
+ publicWs: "公共 WS",
646
+ businessWs: "业务 WS",
647
+ subscribed: (count) => `${count} 个合约`,
648
+ databaseLabel: "数据库",
649
+ readingStatus: "正在读取运行时状态",
650
+ readingRuns: "正在读取最近的回测",
651
+ readingRun: (runId) => `正在读取 ${runId}`,
652
+ languageChanged: (locale) => `语言已设置为 ${locale},配置已保存,下次启动继续生效。`,
653
+ languageCurrent: (locale) => `当前语言:${locale}`,
654
+ languageUsage: "用法:/lang en | /lang zh"
655
+ };
656
+ const BUNDLES = { en, zh };
657
+ export function messages(locale) {
658
+ return BUNDLES[locale];
659
+ }
660
+ //# sourceMappingURL=messages.js.map