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.
- package/README.en.md +90 -10
- package/README.md +76 -10
- package/dist/account/private-websocket.js +4 -4
- package/dist/account/private-websocket.js.map +1 -1
- package/dist/account/service.d.ts +12 -1
- package/dist/account/service.js +18 -0
- package/dist/account/service.js.map +1 -1
- package/dist/bars/rate-limiter.d.ts +18 -0
- package/dist/bars/rate-limiter.js +84 -0
- package/dist/bars/rate-limiter.js.map +1 -0
- package/dist/bars/schema.d.ts +36 -0
- package/dist/bars/schema.js +134 -0
- package/dist/bars/schema.js.map +1 -0
- package/dist/bars/service.d.ts +60 -0
- package/dist/bars/service.js +120 -0
- package/dist/bars/service.js.map +1 -0
- package/dist/bars/store.d.ts +105 -0
- package/dist/bars/store.js +415 -0
- package/dist/bars/store.js.map +1 -0
- package/dist/bars/timeframe.d.ts +40 -0
- package/dist/bars/timeframe.js +146 -0
- package/dist/bars/timeframe.js.map +1 -0
- package/dist/bars/types.d.ts +68 -0
- package/dist/bars/types.js +13 -0
- package/dist/bars/types.js.map +1 -0
- package/dist/cli/data-render.d.ts +37 -0
- package/dist/cli/data-render.js +143 -0
- package/dist/cli/data-render.js.map +1 -0
- package/dist/cli/doctor.js +7 -3
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.js +757 -26
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/live-render.d.ts +24 -0
- package/dist/cli/live-render.js +85 -0
- package/dist/cli/live-render.js.map +1 -0
- package/dist/cli/range.d.ts +28 -0
- package/dist/cli/range.js +63 -0
- package/dist/cli/range.js.map +1 -0
- package/dist/cli/render.js +3 -0
- package/dist/cli/render.js.map +1 -1
- package/dist/cli/strategy-render.d.ts +36 -0
- package/dist/cli/strategy-render.js +391 -0
- package/dist/cli/strategy-render.js.map +1 -0
- package/dist/cli/width.d.ts +18 -0
- package/dist/cli/width.js +71 -0
- package/dist/cli/width.js.map +1 -0
- package/dist/config/loader.js +1 -1
- package/dist/config/schema.d.ts +7 -0
- package/dist/config/schema.js +24 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/core/okx-client.d.ts +9 -1
- package/dist/core/okx-client.js +14 -5
- package/dist/core/okx-client.js.map +1 -1
- package/dist/i18n/locale.d.ts +24 -0
- package/dist/i18n/locale.js +65 -0
- package/dist/i18n/locale.js.map +1 -0
- package/dist/i18n/messages.d.ts +333 -0
- package/dist/i18n/messages.js +660 -0
- package/dist/i18n/messages.js.map +1 -0
- package/dist/live/account-snapshot.d.ts +30 -0
- package/dist/live/account-snapshot.js +130 -0
- package/dist/live/account-snapshot.js.map +1 -0
- package/dist/live/cutoff-queue.d.ts +42 -0
- package/dist/live/cutoff-queue.js +69 -0
- package/dist/live/cutoff-queue.js.map +1 -0
- package/dist/live/execution-key.d.ts +23 -0
- package/dist/live/execution-key.js +31 -0
- package/dist/live/execution-key.js.map +1 -0
- package/dist/live/failures.d.ts +37 -0
- package/dist/live/failures.js +57 -0
- package/dist/live/failures.js.map +1 -0
- package/dist/live/gates.d.ts +65 -0
- package/dist/live/gates.js +136 -0
- package/dist/live/gates.js.map +1 -0
- package/dist/live/loop.d.ts +56 -0
- package/dist/live/loop.js +197 -0
- package/dist/live/loop.js.map +1 -0
- package/dist/live/preconditions.d.ts +48 -0
- package/dist/live/preconditions.js +69 -0
- package/dist/live/preconditions.js.map +1 -0
- package/dist/live/reconcile.d.ts +46 -0
- package/dist/live/reconcile.js +104 -0
- package/dist/live/reconcile.js.map +1 -0
- package/dist/live/runner.d.ts +57 -0
- package/dist/live/runner.js +160 -0
- package/dist/live/runner.js.map +1 -0
- package/dist/live/schema.d.ts +18 -0
- package/dist/live/schema.js +91 -0
- package/dist/live/schema.js.map +1 -0
- package/dist/live/service.d.ts +144 -0
- package/dist/live/service.js +303 -0
- package/dist/live/service.js.map +1 -0
- package/dist/live/session.d.ts +85 -0
- package/dist/live/session.js +234 -0
- package/dist/live/session.js.map +1 -0
- package/dist/live/sizing.d.ts +62 -0
- package/dist/live/sizing.js +79 -0
- package/dist/live/sizing.js.map +1 -0
- package/dist/live/store.d.ts +123 -0
- package/dist/live/store.js +350 -0
- package/dist/live/store.js.map +1 -0
- package/dist/live/types.d.ts +82 -0
- package/dist/live/types.js +2 -0
- package/dist/live/types.js.map +1 -0
- package/dist/market/websocket.d.ts +16 -1
- package/dist/market/websocket.js +60 -5
- package/dist/market/websocket.js.map +1 -1
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +15 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/network/connectivity.d.ts +9 -1
- package/dist/network/connectivity.js +28 -1
- package/dist/network/connectivity.js.map +1 -1
- package/dist/report/chart-script.d.ts +12 -0
- package/dist/report/chart-script.js +146 -0
- package/dist/report/chart-script.js.map +1 -0
- package/dist/report/compare-html.d.ts +8 -0
- package/dist/report/compare-html.js +254 -0
- package/dist/report/compare-html.js.map +1 -0
- package/dist/report/compare-script.d.ts +12 -0
- package/dist/report/compare-script.js +109 -0
- package/dist/report/compare-script.js.map +1 -0
- package/dist/report/compare.d.ts +61 -0
- package/dist/report/compare.js +205 -0
- package/dist/report/compare.js.map +1 -0
- package/dist/report/fetch.d.ts +20 -0
- package/dist/report/fetch.js +56 -0
- package/dist/report/fetch.js.map +1 -0
- package/dist/report/html.d.ts +54 -0
- package/dist/report/html.js +641 -0
- package/dist/report/html.js.map +1 -0
- package/dist/report/open.d.ts +42 -0
- package/dist/report/open.js +114 -0
- package/dist/report/open.js.map +1 -0
- package/dist/runtime/server.d.ts +16 -1
- package/dist/runtime/server.js +112 -9
- package/dist/runtime/server.js.map +1 -1
- package/dist/setup/installer.d.ts +1 -0
- package/dist/setup/installer.js +8 -0
- package/dist/setup/installer.js.map +1 -1
- package/dist/setup/wizard.js +19 -22
- package/dist/setup/wizard.js.map +1 -1
- package/dist/strategy/constants.d.ts +23 -0
- package/dist/strategy/constants.js +24 -0
- package/dist/strategy/constants.js.map +1 -0
- package/dist/strategy/environment.d.ts +52 -0
- package/dist/strategy/environment.js +187 -0
- package/dist/strategy/environment.js.map +1 -0
- package/dist/strategy/instrument.d.ts +29 -0
- package/dist/strategy/instrument.js +39 -0
- package/dist/strategy/instrument.js.map +1 -0
- package/dist/strategy/optimize.d.ts +73 -0
- package/dist/strategy/optimize.js +113 -0
- package/dist/strategy/optimize.js.map +1 -0
- package/dist/strategy/parameter-space.d.ts +59 -0
- package/dist/strategy/parameter-space.js +221 -0
- package/dist/strategy/parameter-space.js.map +1 -0
- package/dist/strategy/python-bridge.d.ts +24 -0
- package/dist/strategy/python-bridge.js +114 -0
- package/dist/strategy/python-bridge.js.map +1 -0
- package/dist/strategy/schema.d.ts +9 -0
- package/dist/strategy/schema.js +91 -0
- package/dist/strategy/schema.js.map +1 -0
- package/dist/strategy/service.d.ts +138 -0
- package/dist/strategy/service.js +745 -0
- package/dist/strategy/service.js.map +1 -0
- package/dist/strategy/settings.d.ts +162 -0
- package/dist/strategy/settings.js +243 -0
- package/dist/strategy/settings.js.map +1 -0
- package/dist/strategy/store.d.ts +96 -0
- package/dist/strategy/store.js +367 -0
- package/dist/strategy/store.js.map +1 -0
- package/dist/strategy/templates.d.ts +11 -0
- package/dist/strategy/templates.js +134 -0
- package/dist/strategy/templates.js.map +1 -0
- package/dist/strategy/types.d.ts +111 -0
- package/dist/strategy/types.js +2 -0
- package/dist/strategy/types.js.map +1 -0
- package/dist/tools/catalog.d.ts +16 -0
- package/dist/tools/catalog.js +118 -17
- package/dist/tools/catalog.js.map +1 -1
- package/dist/trade/service.d.ts +12 -0
- package/dist/trade/service.js +24 -7
- package/dist/trade/service.js.map +1 -1
- package/dist/tui/app.d.ts +23 -0
- package/dist/tui/app.js +322 -0
- package/dist/tui/app.js.map +1 -0
- package/dist/tui/commands.d.ts +70 -0
- package/dist/tui/commands.js +313 -0
- package/dist/tui/commands.js.map +1 -0
- package/dist/tui/entries.d.ts +17 -0
- package/dist/tui/entries.js +24 -0
- package/dist/tui/entries.js.map +1 -0
- package/dist/tui/execute.d.ts +26 -0
- package/dist/tui/execute.js +664 -0
- package/dist/tui/execute.js.map +1 -0
- package/dist/tui/history.d.ts +17 -0
- package/dist/tui/history.js +48 -0
- package/dist/tui/history.js.map +1 -0
- package/dist/tui/index.d.ts +8 -0
- package/dist/tui/index.js +48 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/tui/line-editor.d.ts +44 -0
- package/dist/tui/line-editor.js +98 -0
- package/dist/tui/line-editor.js.map +1 -0
- package/dist/tui/progress.d.ts +23 -0
- package/dist/tui/progress.js +46 -0
- package/dist/tui/progress.js.map +1 -0
- package/dist/tui/settings-editor.d.ts +18 -0
- package/dist/tui/settings-editor.js +115 -0
- package/dist/tui/settings-editor.js.map +1 -0
- package/docs/live-trading.md +455 -0
- package/docs/strategy-research.md +597 -0
- package/package.json +10 -1
- package/python/desic_strategy/__init__.py +34 -0
- package/python/desic_strategy/actions.py +158 -0
- package/python/desic_strategy/context.py +164 -0
- package/python/desic_strategy/engine.py +614 -0
- package/python/desic_strategy/indicators.py +159 -0
- package/python/desic_strategy/live.py +253 -0
- package/python/desic_strategy/policy.py +193 -0
- package/python/desic_strategy/portfolio.py +152 -0
- package/python/desic_strategy/report.py +319 -0
- package/python/desic_strategy/runner.py +574 -0
- package/python/desic_strategy/timeframe.py +150 -0
- package/python/main.py +18 -0
- package/skills/okx-live-trading/SKILL.md +117 -0
- package/skills/okx-live-trading/agents/openai.yaml +9 -0
- package/skills/okx-live-trading/references/lifecycle.md +128 -0
- package/skills/okx-strategy-research/SKILL.md +113 -0
- package/skills/okx-strategy-research/agents/openai.yaml +9 -0
- package/skills/okx-strategy-research/references/execution-semantics.md +107 -0
- package/skills/okx-strategy-research/references/field-traps.md +142 -0
- package/skills/okx-strategy-research/references/python-api.md +121 -0
- package/skills/okx-strategy-research/references/tools-and-data.md +192 -0
- package/skills/okx-trading/SKILL.md +11 -10
package/README.en.md
CHANGED
|
@@ -7,6 +7,9 @@ An independent local OKX Runtime, MCP server, CLI, and reusable agent Skills for
|
|
|
7
7
|
> [!IMPORTANT]
|
|
8
8
|
> Desic OKX Agent is an independent community project. It is not affiliated with, endorsed by, or an official product of OKX.
|
|
9
9
|
|
|
10
|
+
> [!NOTE]
|
|
11
|
+
> All trading tools in this project support OKX perpetual swaps only (`instId` must end in `-SWAP`). Spot, dated futures, options, and all other instrument types are not supported for trading. Public market data and account inspection are unaffected.
|
|
12
|
+
|
|
10
13
|
## Installation
|
|
11
14
|
|
|
12
15
|
Requires Node.js 22.12 or newer and network access to OKX, either directly or through an HTTP/HTTPS proxy.
|
|
@@ -37,10 +40,10 @@ The interactive guide:
|
|
|
37
40
|
|
|
38
41
|
1. Lets you select Codex, Claude Code, Cursor, VS Code / GitHub Copilot, Cline, or all clients.
|
|
39
42
|
2. Registers the `desic-okx` MCP server without replacing existing MCP entries.
|
|
40
|
-
3. Installs all
|
|
43
|
+
3. Installs all nine bundled Skills for Codex and Claude Code.
|
|
41
44
|
4. Checks OKX REST and WebSocket connectivity and guides you through testing and saving an HTTP proxy when needed.
|
|
42
45
|
5. Explains which features require an API key and lets you configure one now or skip it.
|
|
43
|
-
6. Masks credential input,
|
|
46
|
+
6. Masks credential input, automatically detects Live or Demo Trading, and saves the account only after successful verification.
|
|
44
47
|
|
|
45
48
|
An API account is optional. Public market and derivatives tools remain available when you skip this step. Configure an account later with:
|
|
46
49
|
|
|
@@ -59,7 +62,7 @@ desic-okx setup --targets codex --yes --skip-network-check
|
|
|
59
62
|
|
|
60
63
|
## Configure an OKX API account
|
|
61
64
|
|
|
62
|
-
Create an API key in the official OKX website or app. Live and Demo Trading accounts use keys for their respective environments
|
|
65
|
+
Create an API key in the official OKX website or app. Live and Demo Trading accounts use keys for their respective environments. Desic OKX Agent detects the environment through read-only verification, so the user does not select it.
|
|
63
66
|
|
|
64
67
|
Grant only the permissions needed for your use case:
|
|
65
68
|
|
|
@@ -68,15 +71,15 @@ Grant only the permissions needed for your use case:
|
|
|
68
71
|
| Public market data, candles, books, derivatives analysis | No | None |
|
|
69
72
|
| Balances, positions, orders, fills, and risk summaries | Yes | Read permission |
|
|
70
73
|
| Remote News and Smart Money | Yes | A `live` account; read permission is sufficient |
|
|
71
|
-
|
|
|
74
|
+
| Perpetual swap place, amend, cancel, close, and leverage operations | Yes | Trade permission on the OKX API key; `*-SWAP` only |
|
|
72
75
|
|
|
73
76
|
This project has no withdrawal, deposit, transfer, asset-movement, or API-key-management tools. Those permissions are not needed. Test trading workflows with an OKX Demo account first, and configure an IP allowlist in OKX according to your security policy.
|
|
74
77
|
|
|
75
78
|
Add an account interactively:
|
|
76
79
|
|
|
77
80
|
```bash
|
|
78
|
-
desic-okx account add --name demo
|
|
79
|
-
desic-okx account add --name main
|
|
81
|
+
desic-okx account add --name demo
|
|
82
|
+
desic-okx account add --name main
|
|
80
83
|
```
|
|
81
84
|
|
|
82
85
|
API Key, Secret Key, and Passphrase input is hidden. `account add` verifies the credentials with OKX before writing them; failed verification saves nothing. Credentials are stored in `config.json` under the system configuration directory, with Unix permissions set to `0600`:
|
|
@@ -92,10 +95,9 @@ OKX_ACCOUNT
|
|
|
92
95
|
OKX_API_KEY
|
|
93
96
|
OKX_API_SECRET
|
|
94
97
|
OKX_API_PASSPHRASE
|
|
95
|
-
OKX_ENVIRONMENT=demo|live
|
|
96
98
|
```
|
|
97
99
|
|
|
98
|
-
All three credential variables must be provided together. Trading availability is determined entirely by the permissions assigned to the API key in OKX.
|
|
100
|
+
All three credential variables must be provided together. The Runtime detects the account environment automatically. Trading availability is determined entirely by the permissions assigned to the API key in OKX.
|
|
99
101
|
|
|
100
102
|
## Ask an AI to install it
|
|
101
103
|
|
|
@@ -142,9 +144,85 @@ desic-okx update --check
|
|
|
142
144
|
- Time-aligned decision snapshots with freshness, exchange timestamps, and consistency metadata
|
|
143
145
|
- Public market data, indicators, scanning, and public derivatives analysis
|
|
144
146
|
- Account balances, positions, orders, fills, bills, and risk summaries
|
|
145
|
-
-
|
|
147
|
+
- Perpetual-swap-only ordinary orders, algo orders, leverage, amend, cancel, and close-position operations
|
|
146
148
|
- Experimental News and Smart Money capabilities with SQLite history fallback
|
|
147
149
|
- SQLite WAL persistence for closed candles, intelligence history, derived events, and execution records
|
|
150
|
+
- Python strategy research: one-minute history, backtests, parameter tuning, and run comparison
|
|
151
|
+
- Live execution: bind a backtested strategy to an account and act on every closed minute, behind eight risk gates
|
|
152
|
+
|
|
153
|
+
## One chain, not two products
|
|
154
|
+
|
|
155
|
+
The capabilities above are not a flat list — they are segments of one chain. **Working by hand and
|
|
156
|
+
delegating to an AI follow the same chain:**
|
|
157
|
+
|
|
158
|
+
```text
|
|
159
|
+
analyze ──→ write a strategy ──→ backtest ──→ tune ──→ create a profile ──→ verify on demo ──→ go live
|
|
160
|
+
market/derivatives Python 70/30 split rank on creating never real orders real
|
|
161
|
+
news/smart money source file validation starts trading money
|
|
162
|
+
(you approve)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
The only difference between the two is who presses the keys:
|
|
166
|
+
|
|
167
|
+
| | By hand | Delegated to an AI |
|
|
168
|
+
| --- | --- | --- |
|
|
169
|
+
| Find an idea | `market_*` / `news_*` tools, or the TUI | `okx-market-analysis` and related Skills |
|
|
170
|
+
| Write a strategy | `strategy new`, then edit it | the agent writes the file, `strategy_validate_source` checks it |
|
|
171
|
+
| Backtest and tune | `strategy backtest` / `optimize` / `compare` | the same MCP tools, plus the `okx-strategy-research` Skill |
|
|
172
|
+
| Create a profile | `live create` | `live_create_profile` (requires `agent-access`) |
|
|
173
|
+
| Enable live | `live start` | `live_start`, and the Skill requires **asking you first, with numbers** |
|
|
174
|
+
|
|
175
|
+
By default an agent can only read and stop; creating and enabling are absent from its tool list. To
|
|
176
|
+
let an AI run the whole chain:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
desic-okx live agent-access on # restart the MCP client to apply
|
|
180
|
+
desic-okx live agent-access # show the current setting
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Even then the Skill requires the agent to stop and ask before enabling a live profile — that
|
|
184
|
+
constraint lives in the Skill, not in a system gate. The system can verify whether a profile *can*
|
|
185
|
+
run; it cannot verify whether real money *should* be committed to it.
|
|
186
|
+
|
|
187
|
+
## Strategy research
|
|
188
|
+
|
|
189
|
+
Write strategies in Python and backtest, tune, and compare them against local
|
|
190
|
+
one-minute history:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
desic-okx strategy env --setup
|
|
194
|
+
desic-okx data download --inst BTC-USDT-SWAP --days 90
|
|
195
|
+
desic-okx strategy new --out ema.py --template ema-trend
|
|
196
|
+
desic-okx strategy backtest --file ema.py --inst BTC-USDT-SWAP --days 30 --follow
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Tuning splits the window 70/30 and ranks candidates on the part they never saw, so
|
|
200
|
+
overfitting is visible rather than buried. Comparison warns when two runs used
|
|
201
|
+
different data, instruments, windows, or costs.
|
|
202
|
+
|
|
203
|
+
Full guide: **[docs/strategy-research.md](docs/strategy-research.md)** (Chinese).
|
|
204
|
+
|
|
205
|
+
## Live execution
|
|
206
|
+
|
|
207
|
+
Run a validated strategy against a real account, acting on every closed minute:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
desic-okx live create --file ema.py --inst BTC-USDT-SWAP --account demo \
|
|
211
|
+
--environment demo --entry-budget 100 --side-budget 200 --daily-loss 500
|
|
212
|
+
desic-okx live readiness --id lp_xxxx
|
|
213
|
+
desic-okx live start --id lp_xxxx
|
|
214
|
+
desic-okx live signals --id lp_xxxx
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Enabling requires a completed backtest of that exact source on that exact instrument, matched by
|
|
218
|
+
source hash rather than filename, and writes the profile's leverage to the exchange — the entry
|
|
219
|
+
budget is sized against that figure, so a mismatch makes the budget mean something else. Eight risk
|
|
220
|
+
gates refuse rather than adjust, and every refusal is kept — those rows are the evidence risk
|
|
221
|
+
control ran. After a crash, unresolved signals are reconciled against the exchange and never
|
|
222
|
+
resubmitted.
|
|
223
|
+
|
|
224
|
+
**This places real orders.** Full guide: **[docs/live-trading.md](docs/live-trading.md)**
|
|
225
|
+
(Chinese).
|
|
148
226
|
|
|
149
227
|
## Skills
|
|
150
228
|
|
|
@@ -156,6 +234,8 @@ desic-okx update --check
|
|
|
156
234
|
- `okx-smart-money-analysis`
|
|
157
235
|
- `okx-account-analysis`
|
|
158
236
|
- `okx-trading`
|
|
237
|
+
- `okx-strategy-research`
|
|
238
|
+
- `okx-live-trading`
|
|
159
239
|
- `trading-philosophy`
|
|
160
240
|
|
|
161
241
|
Skills are synchronized after upgrades. You can also inspect or synchronize them manually; modified copies are backed up first:
|
|
@@ -268,6 +348,6 @@ Trading software can cause financial loss. This project provides no investment a
|
|
|
268
348
|
|
|
269
349
|
## Status and license
|
|
270
350
|
|
|
271
|
-
This is pre-release software at version `0.
|
|
351
|
+
This is pre-release software at version `0.3.0`. OKX Demo trading should be validated in the target network environment before a `1.0.0` release. Strategy research and live execution have been verified end to end on the OKX demo venue; **live execution has not yet run against real money over any length of time**.
|
|
272
352
|
|
|
273
353
|
MIT License. See `LICENSE`. OKX and related marks belong to their respective owners.
|
package/README.md
CHANGED
|
@@ -7,6 +7,9 @@
|
|
|
7
7
|
> [!IMPORTANT]
|
|
8
8
|
> Desic OKX Agent 是独立的社区项目,并非 OKX 官方产品,也未获得 OKX 的认可或背书。
|
|
9
9
|
|
|
10
|
+
> [!NOTE]
|
|
11
|
+
> 本项目的所有交易工具仅支持 OKX 永续合约(`instId` 必须以 `-SWAP` 结尾)。不支持现货、交割合约、期权或其他品种的交易。公共行情和账户查询不受此限制。
|
|
12
|
+
|
|
10
13
|
## 安装
|
|
11
14
|
|
|
12
15
|
要求 Node.js 22.12 或更高版本,以及能够访问 OKX 的网络或 HTTP/HTTPS 代理。
|
|
@@ -37,10 +40,10 @@ desic-okx doctor
|
|
|
37
40
|
|
|
38
41
|
1. 选择 Codex、Claude Code、Cursor、VS Code / GitHub Copilot、Cline,或全部客户端。
|
|
39
42
|
2. 注册 `desic-okx` MCP Server,保留已有 MCP 配置。
|
|
40
|
-
3. 为 Codex 和 Claude Code 自动安装全部
|
|
43
|
+
3. 为 Codex 和 Claude Code 自动安装全部 9 个 Skills。
|
|
41
44
|
4. 检查 OKX REST 与 WebSocket;连接失败时引导测试并保存 HTTP 代理。
|
|
42
45
|
5. 解释不同功能的 API Key 要求,并让用户选择“现在配置”或“以后配置”。
|
|
43
|
-
6.
|
|
46
|
+
6. 如果现在配置,隐藏凭证输入,自动识别实盘或模拟盘,验证成功后才写入本地配置。
|
|
44
47
|
|
|
45
48
|
API 账户是可选的。跳过后公共行情和公共衍生品仍可使用,以后运行下面的命令即可配置:
|
|
46
49
|
|
|
@@ -59,7 +62,7 @@ desic-okx setup --targets codex --yes --skip-network-check
|
|
|
59
62
|
|
|
60
63
|
## 配置 OKX API
|
|
61
64
|
|
|
62
|
-
在 OKX 官方网站或 App 中创建 API Key。实盘账户与模拟交易账户使用各自环境的 API Key
|
|
65
|
+
在 OKX 官方网站或 App 中创建 API Key。实盘账户与模拟交易账户使用各自环境的 API Key,Desic OKX Agent 会通过只读验证自动识别,不需要用户选择实盘或模拟盘。
|
|
63
66
|
|
|
64
67
|
按实际用途授予权限:
|
|
65
68
|
|
|
@@ -68,15 +71,15 @@ desic-okx setup --targets codex --yes --skip-network-check
|
|
|
68
71
|
| 公共行情、K 线、盘口、衍生品分析 | 否 | 无 |
|
|
69
72
|
| 余额、持仓、订单、成交、风险摘要 | 是 | 读取权限 |
|
|
70
73
|
| 远程 News、Smart Money | 是 | `live` 账户,读取权限即可 |
|
|
71
|
-
|
|
|
74
|
+
| 永续合约下单、改单、撤单、平仓、设置杠杆 | 是 | OKX API Key 具备交易权限;仅支持 `*-SWAP` |
|
|
72
75
|
|
|
73
76
|
本项目不提供提现、充值、资金划转、资产转出或 API Key 管理工具,不需要为此授予相关权限。建议先使用 OKX 模拟交易账户验证交易流程,并按自己的安全策略在 OKX 配置 IP 白名单。
|
|
74
77
|
|
|
75
78
|
交互式添加账户:
|
|
76
79
|
|
|
77
80
|
```bash
|
|
78
|
-
desic-okx account add --name demo
|
|
79
|
-
desic-okx account add --name main
|
|
81
|
+
desic-okx account add --name demo
|
|
82
|
+
desic-okx account add --name main
|
|
80
83
|
```
|
|
81
84
|
|
|
82
85
|
输入 API Key、Secret Key 和 Passphrase 时终端会隐藏文本。`account add` 会先连接 OKX 验证,验证失败不会保存凭证。凭证保存在系统配置目录的 `config.json` 中;Unix 权限为 `0600`:
|
|
@@ -92,10 +95,9 @@ OKX_ACCOUNT
|
|
|
92
95
|
OKX_API_KEY
|
|
93
96
|
OKX_API_SECRET
|
|
94
97
|
OKX_API_PASSPHRASE
|
|
95
|
-
OKX_ENVIRONMENT=demo|live
|
|
96
98
|
```
|
|
97
99
|
|
|
98
|
-
|
|
100
|
+
三个凭证变量必须同时提供。Runtime 会自动探测账户环境;能否交易完全取决于 OKX 为该 API Key 配置的官方权限。
|
|
99
101
|
|
|
100
102
|
## 让 AI 自动安装
|
|
101
103
|
|
|
@@ -142,9 +144,71 @@ desic-okx update --check
|
|
|
142
144
|
- 带新鲜度、交易所时间和一致性元数据的统一决策快照
|
|
143
145
|
- 公共行情、指标扫描和公共衍生品分析
|
|
144
146
|
- 账户余额、持仓、委托、成交、账单及风险摘要
|
|
145
|
-
-
|
|
147
|
+
- 仅限永续合约的普通单、策略单、杠杆、改单、撤单和平仓操作
|
|
146
148
|
- 实验性的 News 与 Smart Money 能力,以及 SQLite 历史回退
|
|
147
149
|
- SQLite WAL 持久化已收盘 K 线、情报历史、派生事件和执行记录
|
|
150
|
+
- Python 策略研究:1 分钟历史数据、回测、参数调优、多次回测对比
|
|
151
|
+
- 实盘执行:把已回测的策略绑到账户,每根 1 分钟收线自动决策,八道风控闸门前置
|
|
152
|
+
|
|
153
|
+
## 一条链,不是两个产品
|
|
154
|
+
|
|
155
|
+
上面的能力不是并列的清单,而是同一条链上的几段。**手动做和让 AI 做,走的是同一条链**:
|
|
156
|
+
|
|
157
|
+
```text
|
|
158
|
+
分析行情 ──→ 写成策略 ──→ 回测 ──→ 调参 ──→ 建 Profile ──→ 模拟盘验证 ──→ 实盘
|
|
159
|
+
行情/衍生品 Python 7:3 切分 验证段排名 不会开始交易 真实下单 真钱
|
|
160
|
+
News/资金流 策略文件 (需你同意)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
两种用法的区别只在谁按键:
|
|
164
|
+
|
|
165
|
+
| | 你自己做 | 交给 AI |
|
|
166
|
+
| --- | --- | --- |
|
|
167
|
+
| 找想法 | `market_*` / `news_*` 工具,或 TUI | `okx-market-analysis` 等 Skill |
|
|
168
|
+
| 写策略 | `strategy new` 起模板,自己编辑 | agent 写文件,`strategy_validate_source` 校验 |
|
|
169
|
+
| 回测调参 | `strategy backtest` / `optimize` / `compare` | 同名 MCP 工具,`okx-strategy-research` Skill |
|
|
170
|
+
| 建 Profile | `live create` | `live_create_profile`(需开 `agent-access`) |
|
|
171
|
+
| 启用实盘 | `live start` | `live_start`,且 Skill 要求**先问你并给出数字** |
|
|
172
|
+
|
|
173
|
+
默认情况下 agent 只能读和停,创建与启用不在它的工具列表里。要让 AI 跑完整条链:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
desic-okx live agent-access on # 需重启 MCP 客户端
|
|
177
|
+
desic-okx live agent-access # 查看当前设置
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
开启后 agent 仍被要求在启用实盘 Profile 前停下来问你 —— 这条约束写在 Skill 里,不是系统闸门。系统能验证的是"这个 Profile 能不能跑",不能验证"该不该投真钱"。
|
|
181
|
+
|
|
182
|
+
## 策略研究
|
|
183
|
+
|
|
184
|
+
用 Python 写策略,在本地 1 分钟历史数据上回测、调参、对比:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
desic-okx strategy env --setup
|
|
188
|
+
desic-okx data download --inst BTC-USDT-SWAP --days 90
|
|
189
|
+
desic-okx strategy new --out ema.py --template ema-trend
|
|
190
|
+
desic-okx strategy backtest --file ema.py --inst BTC-USDT-SWAP --days 30 --follow
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
调参会把窗口按 7:3 切分,用候选从未见过的那一段排名,因此过拟合是可见的而不是被埋掉的。对比会在两次运行数据、合约、区间或成本不同时给出警告。
|
|
194
|
+
|
|
195
|
+
完整说明见 **[策略研究使用指南](docs/strategy-research.md)**。
|
|
196
|
+
|
|
197
|
+
## 实盘执行
|
|
198
|
+
|
|
199
|
+
把已验证的策略接到真实账户,每根 1 分钟收线自动执行:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
desic-okx live create --file ema.py --inst BTC-USDT-SWAP --account demo \
|
|
203
|
+
--environment demo --entry-budget 100 --side-budget 200 --daily-loss 500
|
|
204
|
+
desic-okx live readiness --id lp_xxxx
|
|
205
|
+
desic-okx live start --id lp_xxxx
|
|
206
|
+
desic-okx live signals --id lp_xxxx
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
启用需要该源码 + 该合约已完成回测(按源码 hash 匹配,不是文件名),并会把 Profile 的杠杆写到交易所 —— 预算按杠杆折算张数,两边不一致预算就不成立。八道风控闸门只拒绝、不修正,被拒绝的信号会完整保留 —— 它们是风控运行过的证据。崩溃后向交易所对账,绝不重发可能已存在的订单。
|
|
210
|
+
|
|
211
|
+
**这部分会用真钱下单。** 完整说明与限制见 **[实盘执行使用指南](docs/live-trading.md)**。
|
|
148
212
|
|
|
149
213
|
## Skills
|
|
150
214
|
|
|
@@ -156,6 +220,8 @@ desic-okx update --check
|
|
|
156
220
|
- `okx-smart-money-analysis`
|
|
157
221
|
- `okx-account-analysis`
|
|
158
222
|
- `okx-trading`
|
|
223
|
+
- `okx-strategy-research`
|
|
224
|
+
- `okx-live-trading`
|
|
159
225
|
- `trading-philosophy`
|
|
160
226
|
|
|
161
227
|
升级后 Skills 会自动同步。也可手动检查或同步;被修改的旧版本会先备份:
|
|
@@ -268,6 +334,6 @@ npm link
|
|
|
268
334
|
|
|
269
335
|
## 状态与许可
|
|
270
336
|
|
|
271
|
-
当前为 `0.
|
|
337
|
+
当前为 `0.3.0` 预发布版本。正式发布 `1.0.0` 前,应在目标网络环境中完成 OKX Demo 交易验证。策略研究与实盘执行已在 OKX 模拟盘上端到端验证过,**实盘执行尚未经过长期真钱运行**。
|
|
272
338
|
|
|
273
339
|
MIT License,详见 `LICENSE`。OKX 及相关商标归其各自权利人所有。
|
|
@@ -2,6 +2,7 @@ import crypto from "node:crypto";
|
|
|
2
2
|
import WebSocket from "ws";
|
|
3
3
|
import { HttpsProxyAgent } from "https-proxy-agent";
|
|
4
4
|
import { resolveProxy } from "../network/proxy.js";
|
|
5
|
+
import { privateWsUrl } from "../network/connectivity.js";
|
|
5
6
|
export class PrivateAccountWebSockets {
|
|
6
7
|
store;
|
|
7
8
|
connections;
|
|
@@ -43,10 +44,9 @@ export class PrivateAccountWebSockets {
|
|
|
43
44
|
connect(connection) {
|
|
44
45
|
if (connection.stopping)
|
|
45
46
|
return;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const socket = new WebSocket(url, this.agent ? { agent: this.agent } : undefined);
|
|
47
|
+
// Per account, not per runtime: the private feed follows whichever environment
|
|
48
|
+
// the credentials belong to, while market data follows its own setting.
|
|
49
|
+
const socket = new WebSocket(privateWsUrl(connection.account.environment), this.agent ? { agent: this.agent } : undefined);
|
|
50
50
|
connection.socket = socket;
|
|
51
51
|
connection.authenticated = false;
|
|
52
52
|
socket.on("open", () => socket.send(JSON.stringify({ op: "login", args: [loginArgs(connection.account)] })));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"private-websocket.js","sourceRoot":"","sources":["../../src/account/private-websocket.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,SAAS,MAAM,IAAI,CAAC;AAC3B,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAIpD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"private-websocket.js","sourceRoot":"","sources":["../../src/account/private-websocket.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { RuntimeConfig } from "../config/schema.js";
|
|
2
2
|
import { OkxClient } from "../core/okx-client.js";
|
|
3
|
-
import { type AccountCredentials, type ToolResult } from "../core/types.js";
|
|
3
|
+
import { type AccountCredentials, type OkxEnvironment, type ToolResult } from "../core/types.js";
|
|
4
4
|
import type { AccountStore } from "./store.js";
|
|
5
5
|
export declare class AccountService {
|
|
6
6
|
private readonly config;
|
|
@@ -20,3 +20,14 @@ export declare class AccountService {
|
|
|
20
20
|
getRisk(name?: string): Promise<ToolResult<Record<string, unknown>>>;
|
|
21
21
|
private wrap;
|
|
22
22
|
}
|
|
23
|
+
export interface UnclassifiedAccountCredentials {
|
|
24
|
+
name: string;
|
|
25
|
+
apiKey: string;
|
|
26
|
+
secretKey: string;
|
|
27
|
+
passphrase: string;
|
|
28
|
+
}
|
|
29
|
+
export interface DetectedAccount {
|
|
30
|
+
account: AccountCredentials;
|
|
31
|
+
config: Record<string, unknown>;
|
|
32
|
+
}
|
|
33
|
+
export declare function detectAccountEnvironment(client: Pick<OkxClient, "privateGet">, credentials: UnclassifiedAccountCredentials, preferred?: OkxEnvironment): Promise<DetectedAccount>;
|
package/dist/account/service.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { resolveAccount } from "../config/loader.js";
|
|
2
|
+
import { RuntimeError } from "../core/errors.js";
|
|
2
3
|
import { resultMeta } from "../core/types.js";
|
|
3
4
|
export class AccountService {
|
|
4
5
|
config;
|
|
@@ -108,6 +109,23 @@ export class AccountService {
|
|
|
108
109
|
};
|
|
109
110
|
}
|
|
110
111
|
}
|
|
112
|
+
export async function detectAccountEnvironment(client, credentials, preferred) {
|
|
113
|
+
const environments = preferred === "demo" ? ["demo", "live"] : ["live", "demo"];
|
|
114
|
+
let lastError;
|
|
115
|
+
for (const environment of environments) {
|
|
116
|
+
const account = { ...credentials, environment };
|
|
117
|
+
try {
|
|
118
|
+
const [config] = await client.privateGet("/api/v5/account/config", account);
|
|
119
|
+
return { account, config: config ?? {} };
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
lastError = error;
|
|
123
|
+
if (error instanceof RuntimeError && !["AUTH", "PERMISSION", "OKX_REJECTED"].includes(error.code))
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
throw lastError ?? new RuntimeError("AUTH", "OKX account environment could not be detected");
|
|
128
|
+
}
|
|
111
129
|
function recent(value) {
|
|
112
130
|
return value && Date.now() - value.receivedAt <= 15_000 ? value : undefined;
|
|
113
131
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/account/service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;
|
|
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
|
+
}>;
|