dexbot 1.4.24 → 1.5.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/CHANGELOG.md +67 -0
- package/README.md +7 -2
- package/analysis/README.md +61 -5
- package/analysis/ama_fitting/package.json +1 -1
- package/analysis/analyze_derivatives.ts +1 -1
- package/analysis/bot_key_utils.ts +272 -3
- package/analysis/bot_usage/discover_bot_accounts.ts +64 -9
- package/analysis/bot_usage/kibana_bot_queries.ts +40 -1
- package/analysis/chart_utils.ts +6 -3
- package/analysis/grid_correction_check.ts +932 -0
- package/analysis/resolve_bot_accounts.ts +199 -0
- package/analysis/trade_profitability.ts +36 -8
- package/analysis/tradingview/README.md +25 -0
- package/analysis/tradingview/analyze_tradingview.ts +2 -2
- package/analysis/trend_detection/package.json +1 -1
- package/claw/modules/claw_launcher.ts +5 -4
- package/claw/modules/credit_runtime_adapter.ts +2 -1
- package/claw/modules/dexbot_profiles.ts +4 -3
- package/claw/package.json +1 -1
- package/claw/runtimes/openclaw-plugin/openclaw.plugin.json +1 -1
- package/claw/runtimes/openclaw-plugin/package.json +1 -1
- package/claw/tests/test_claw_mcp_transport.ts +2 -2
- package/dist/analysis/analyze_derivatives.js +1 -1
- package/dist/analysis/bot_key_utils.d.ts +28 -1
- package/dist/analysis/bot_key_utils.d.ts.map +1 -1
- package/dist/analysis/bot_key_utils.js +385 -3
- package/dist/analysis/bot_key_utils.js.map +1 -1
- package/dist/analysis/bot_usage/discover_bot_accounts.js +60 -10
- package/dist/analysis/bot_usage/discover_bot_accounts.js.map +1 -1
- package/dist/analysis/bot_usage/kibana_bot_queries.d.ts +45 -1
- package/dist/analysis/bot_usage/kibana_bot_queries.d.ts.map +1 -1
- package/dist/analysis/bot_usage/kibana_bot_queries.js +39 -1
- package/dist/analysis/bot_usage/kibana_bot_queries.js.map +1 -1
- package/dist/analysis/chart_utils.d.ts +2 -1
- package/dist/analysis/chart_utils.d.ts.map +1 -1
- package/dist/analysis/chart_utils.js +4 -1
- package/dist/analysis/chart_utils.js.map +1 -1
- package/dist/analysis/grid_correction_check.d.ts +90 -0
- package/dist/analysis/grid_correction_check.d.ts.map +1 -0
- package/dist/analysis/grid_correction_check.js +901 -0
- package/dist/analysis/grid_correction_check.js.map +1 -0
- package/dist/analysis/resolve_bot_accounts.d.ts +3 -0
- package/dist/analysis/resolve_bot_accounts.d.ts.map +1 -0
- package/dist/analysis/resolve_bot_accounts.js +216 -0
- package/dist/analysis/resolve_bot_accounts.js.map +1 -0
- package/dist/analysis/trade_profitability.d.ts.map +1 -1
- package/dist/analysis/trade_profitability.js +40 -8
- package/dist/analysis/trade_profitability.js.map +1 -1
- package/dist/analysis/tradingview/analyze_tradingview.js +2 -2
- package/dist/analysis/tradingview/analyze_tradingview.js.map +1 -1
- package/dist/bot.d.ts.map +1 -1
- package/dist/bot.js +2 -1
- package/dist/bot.js.map +1 -1
- package/dist/dexbot.d.ts.map +1 -1
- package/dist/dexbot.js +134 -22
- package/dist/dexbot.js.map +1 -1
- package/dist/market_adapter/ama_signal_runner.js +2 -2
- package/dist/market_adapter/inputs/fetch_cex_synthetic_data.js +2 -1
- package/dist/market_adapter/inputs/fetch_cex_synthetic_data.js.map +1 -1
- package/dist/market_adapter/inputs/fetch_lp_data.d.ts +4 -1
- package/dist/market_adapter/inputs/fetch_lp_data.d.ts.map +1 -1
- package/dist/market_adapter/inputs/fetch_lp_data.js +3 -2
- package/dist/market_adapter/inputs/fetch_lp_data.js.map +1 -1
- package/dist/modules/account_bots.d.ts +42 -1
- package/dist/modules/account_bots.d.ts.map +1 -1
- package/dist/modules/account_bots.js +221 -22
- package/dist/modules/account_bots.js.map +1 -1
- package/dist/modules/account_orders.d.ts +7 -10
- package/dist/modules/account_orders.d.ts.map +1 -1
- package/dist/modules/account_orders.js +26 -2
- package/dist/modules/account_orders.js.map +1 -1
- package/dist/modules/bitshares_client.d.ts +4 -1
- package/dist/modules/bitshares_client.d.ts.map +1 -1
- package/dist/modules/bitshares_client.js +12 -4
- package/dist/modules/bitshares_client.js.map +1 -1
- package/dist/modules/bot_settings.d.ts.map +1 -1
- package/dist/modules/bot_settings.js +2 -1
- package/dist/modules/bot_settings.js.map +1 -1
- package/dist/modules/chain_orders.d.ts.map +1 -1
- package/dist/modules/chain_orders.js +21 -2
- package/dist/modules/chain_orders.js.map +1 -1
- package/dist/modules/cli_colors.d.ts +39 -0
- package/dist/modules/cli_colors.d.ts.map +1 -0
- package/dist/modules/cli_colors.js +42 -0
- package/dist/modules/cli_colors.js.map +1 -0
- package/dist/modules/config.d.ts.map +1 -1
- package/dist/modules/config.js +27 -0
- package/dist/modules/config.js.map +1 -1
- package/dist/modules/constants.d.ts +14 -1
- package/dist/modules/constants.d.ts.map +1 -1
- package/dist/modules/constants.js +66 -11
- package/dist/modules/constants.js.map +1 -1
- package/dist/modules/credit_pricing.d.ts +61 -0
- package/dist/modules/credit_pricing.d.ts.map +1 -0
- package/dist/modules/credit_pricing.js +237 -0
- package/dist/modules/credit_pricing.js.map +1 -0
- package/dist/modules/credit_runtime.d.ts +1 -0
- package/dist/modules/credit_runtime.d.ts.map +1 -1
- package/dist/modules/credit_runtime.js +49 -107
- package/dist/modules/credit_runtime.js.map +1 -1
- package/dist/modules/dexbot_class.d.ts +25 -0
- package/dist/modules/dexbot_class.d.ts.map +1 -1
- package/dist/modules/dexbot_class.js +82 -12
- package/dist/modules/dexbot_class.js.map +1 -1
- package/dist/modules/dexbot_cow_runtime.d.ts +39 -17
- package/dist/modules/dexbot_cow_runtime.d.ts.map +1 -1
- package/dist/modules/dexbot_cow_runtime.js +875 -134
- package/dist/modules/dexbot_cow_runtime.js.map +1 -1
- package/dist/modules/dexbot_fill_runtime.d.ts +11 -1
- package/dist/modules/dexbot_fill_runtime.d.ts.map +1 -1
- package/dist/modules/dexbot_fill_runtime.js +108 -1
- package/dist/modules/dexbot_fill_runtime.js.map +1 -1
- package/dist/modules/dexbot_maintenance_runtime.d.ts +29 -14
- package/dist/modules/dexbot_maintenance_runtime.d.ts.map +1 -1
- package/dist/modules/dexbot_maintenance_runtime.js +279 -63
- package/dist/modules/dexbot_maintenance_runtime.js.map +1 -1
- package/dist/modules/dexbot_startup_runtime.d.ts +1 -0
- package/dist/modules/dexbot_startup_runtime.d.ts.map +1 -1
- package/dist/modules/dexbot_startup_runtime.js +58 -7
- package/dist/modules/dexbot_startup_runtime.js.map +1 -1
- package/dist/modules/dexbot_state_recovery.d.ts.map +1 -1
- package/dist/modules/dexbot_state_recovery.js +55 -3
- package/dist/modules/dexbot_state_recovery.js.map +1 -1
- package/dist/modules/fund_registry.d.ts +1 -1
- package/dist/modules/fund_registry.js +1 -1
- package/dist/modules/graceful_shutdown.d.ts +12 -1
- package/dist/modules/graceful_shutdown.d.ts.map +1 -1
- package/dist/modules/graceful_shutdown.js +39 -1
- package/dist/modules/graceful_shutdown.js.map +1 -1
- package/dist/modules/key_store.d.ts.map +1 -1
- package/dist/modules/key_store.js +38 -1
- package/dist/modules/key_store.js.map +1 -1
- package/dist/modules/launcher/adapter_requirement.d.ts +38 -0
- package/dist/modules/launcher/adapter_requirement.d.ts.map +1 -0
- package/dist/modules/launcher/adapter_requirement.js +141 -0
- package/dist/modules/launcher/adapter_requirement.js.map +1 -0
- package/dist/modules/launcher/bot_supervisor.d.ts +2 -2
- package/dist/modules/launcher/bot_supervisor.d.ts.map +1 -1
- package/dist/modules/launcher/bot_supervisor.js +32 -3
- package/dist/modules/launcher/bot_supervisor.js.map +1 -1
- package/dist/modules/launcher/launch_modes.d.ts.map +1 -1
- package/dist/modules/launcher/launch_modes.js +5 -4
- package/dist/modules/launcher/launch_modes.js.map +1 -1
- package/dist/modules/launcher/monolithic_runtime.d.ts +1 -1
- package/dist/modules/launcher/monolithic_runtime.d.ts.map +1 -1
- package/dist/modules/launcher/monolithic_runtime.js +12 -8
- package/dist/modules/launcher/monolithic_runtime.js.map +1 -1
- package/dist/modules/launcher/status_reporting.d.ts +6 -6
- package/dist/modules/launcher/status_reporting.d.ts.map +1 -1
- package/dist/modules/launcher/status_reporting.js +9 -6
- package/dist/modules/launcher/status_reporting.js.map +1 -1
- package/dist/modules/order/accounting.d.ts.map +1 -1
- package/dist/modules/order/accounting.js +20 -3
- package/dist/modules/order/accounting.js.map +1 -1
- package/dist/modules/order/export.d.ts +1 -1
- package/dist/modules/order/export.js +1 -1
- package/dist/modules/order/grid.d.ts +1 -1
- package/dist/modules/order/grid.d.ts.map +1 -1
- package/dist/modules/order/grid.js +335 -43
- package/dist/modules/order/grid.js.map +1 -1
- package/dist/modules/order/grid_reconcile.d.ts +4 -2
- package/dist/modules/order/grid_reconcile.d.ts.map +1 -1
- package/dist/modules/order/grid_reconcile.js +242 -222
- package/dist/modules/order/grid_reconcile.js.map +1 -1
- package/dist/modules/order/grid_reconcile_internal.d.ts +11 -1
- package/dist/modules/order/grid_reconcile_internal.d.ts.map +1 -1
- package/dist/modules/order/grid_reconcile_internal.js +132 -6
- package/dist/modules/order/grid_reconcile_internal.js.map +1 -1
- package/dist/modules/order/logger.d.ts +23 -1
- package/dist/modules/order/logger.d.ts.map +1 -1
- package/dist/modules/order/logger.js +60 -17
- package/dist/modules/order/logger.js.map +1 -1
- package/dist/modules/order/manager.d.ts +68 -14
- package/dist/modules/order/manager.d.ts.map +1 -1
- package/dist/modules/order/manager.js +281 -52
- package/dist/modules/order/manager.js.map +1 -1
- package/dist/modules/order/strategy.d.ts.map +1 -1
- package/dist/modules/order/strategy.js +25 -8
- package/dist/modules/order/strategy.js.map +1 -1
- package/dist/modules/order/sync_engine.d.ts.map +1 -1
- package/dist/modules/order/sync_engine.js +262 -167
- package/dist/modules/order/sync_engine.js.map +1 -1
- package/dist/modules/order/utils/math.d.ts +47 -5
- package/dist/modules/order/utils/math.d.ts.map +1 -1
- package/dist/modules/order/utils/math.js +175 -11
- package/dist/modules/order/utils/math.js.map +1 -1
- package/dist/modules/order/utils/order.d.ts +16 -15
- package/dist/modules/order/utils/order.d.ts.map +1 -1
- package/dist/modules/order/utils/order.js +199 -32
- package/dist/modules/order/utils/order.js.map +1 -1
- package/dist/modules/order/utils/slot.d.ts +8 -0
- package/dist/modules/order/utils/slot.d.ts.map +1 -0
- package/dist/modules/order/utils/slot.js +16 -0
- package/dist/modules/order/utils/slot.js.map +1 -0
- package/dist/modules/order/utils/system.d.ts +52 -4
- package/dist/modules/order/utils/system.d.ts.map +1 -1
- package/dist/modules/order/utils/system.js +109 -16
- package/dist/modules/order/utils/system.js.map +1 -1
- package/dist/modules/order/utils/validate.d.ts +6 -9
- package/dist/modules/order/utils/validate.d.ts.map +1 -1
- package/dist/modules/order/utils/validate.js +107 -85
- package/dist/modules/order/utils/validate.js.map +1 -1
- package/dist/modules/order/working_grid.d.ts +5 -0
- package/dist/modules/order/working_grid.d.ts.map +1 -1
- package/dist/modules/order/working_grid.js +21 -0
- package/dist/modules/order/working_grid.js.map +1 -1
- package/dist/modules/paths.d.ts +4 -2
- package/dist/modules/paths.d.ts.map +1 -1
- package/dist/modules/paths.js +79 -24
- package/dist/modules/paths.js.map +1 -1
- package/dist/modules/utils/chain_logs.d.ts +11 -0
- package/dist/modules/utils/chain_logs.d.ts.map +1 -0
- package/dist/modules/utils/chain_logs.js +23 -0
- package/dist/modules/utils/chain_logs.js.map +1 -0
- package/dist/modules/utils/sanitize_key.d.ts +7 -0
- package/dist/modules/utils/sanitize_key.d.ts.map +1 -1
- package/dist/modules/utils/sanitize_key.js +15 -0
- package/dist/modules/utils/sanitize_key.js.map +1 -1
- package/dist/pm2.d.ts +11 -1
- package/dist/pm2.d.ts.map +1 -1
- package/dist/pm2.js +66 -15
- package/dist/pm2.js.map +1 -1
- package/dist/scripts/analyze-credit.d.ts +4 -0
- package/dist/scripts/analyze-credit.d.ts.map +1 -0
- package/dist/scripts/analyze-credit.js +760 -0
- package/dist/scripts/analyze-credit.js.map +1 -0
- package/dist/scripts/analyze-orders.d.ts +1 -10
- package/dist/scripts/analyze-orders.d.ts.map +1 -1
- package/dist/scripts/analyze-orders.js +34 -36
- package/dist/scripts/analyze-orders.js.map +1 -1
- package/dist/scripts/generate_market_adapter_whitelist.d.ts +2 -5
- package/dist/scripts/generate_market_adapter_whitelist.d.ts.map +1 -1
- package/dist/scripts/generate_market_adapter_whitelist.js +83 -1
- package/dist/scripts/generate_market_adapter_whitelist.js.map +1 -1
- package/dist/scripts/test-credit-renewal.d.ts.map +1 -1
- package/dist/scripts/test-credit-renewal.js +37 -5
- package/dist/scripts/test-credit-renewal.js.map +1 -1
- package/dist/scripts/tv.d.ts +11 -0
- package/dist/scripts/tv.d.ts.map +1 -0
- package/dist/scripts/tv.js +357 -0
- package/dist/scripts/tv.js.map +1 -0
- package/dist/scripts/update.js +77 -10
- package/dist/scripts/update.js.map +1 -1
- package/dist/unlock.d.ts.map +1 -1
- package/dist/unlock.js +20 -8
- package/dist/unlock.js.map +1 -1
- package/docs/DEXBOT_COMPARISON.md +11 -11
- package/docs/EVOLUTION.md +10 -8
- package/docs/FUND_MOVEMENT_AND_ACCOUNTING.md +1 -1
- package/docs/GRID_RECALCULATION.md +6 -0
- package/docs/MPA_CREDIT_USAGE.md +3 -1
- package/docs/README.md +2 -2
- package/docs/WORKFLOW.md +3 -1
- package/market_adapter/README.md +10 -0
- package/package.json +3 -1
- package/scripts/README.md +16 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,73 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.5.0] - 2026-09-05 - Credit Overview & Whitelist-Scoped CR, TradingView Shortcut, Reload Command, Guard & Rotation Hardening
|
|
6
|
+
|
|
7
|
+
### 2026-09-02
|
|
8
|
+
|
|
9
|
+
- **Fix(editor)**: bold Mountain weight in selector display (`modules/account_bots.ts`).
|
|
10
|
+
|
|
11
|
+
### 2026-09-03
|
|
12
|
+
|
|
13
|
+
- **Feat(cli)**: add `dexbot credit` live per-bot debt overview and centralize CLI color palette — new `scripts/analyze-credit.ts` (wired as `dexbot credit [<bot>]`) queries live `get_margin_positions` + paginated `get_credit_deals_by_borrower` per preferredAccount and prints summed debt/collateral per asset per bot (lending-asset filtered, shared accounts tagged, chain chatter muted, inclusive-pagination overlap dropped to avoid double-counting); new `modules/cli_colors.ts` (`CLI_COLORS`) is the single source of truth for every ANSI shade repo-wide with no visual change (`scripts/analyze-credit.ts`, `dexbot.ts`, `modules/cli_colors.ts`, `README.md`, `docs/WORKFLOW.md`, `tests/test_analyze_credit.ts`).
|
|
14
|
+
|
|
15
|
+
### 2026-09-04
|
|
16
|
+
|
|
17
|
+
- **Feat(credit)**: whitelist-scoped CR reporting and shared credit-pricing math — new browser-safe `modules/credit_pricing.ts` holds the canonical math (collateral-map normalization, core/legacy-reversed orientation, offer conversion rates, per-deal and value-weighted average CR, fee helpers) with `credit_runtime.ts` delegating to it (conversion-rate fallback extended offer → pool-derived → universal market price incl. BTS-bridge hops); analyzer per-pair `Curr. CR` and per-bot `Avar. CR` are now scoped to whitelisted `debtPolicy.lending` pairs priced on the current offer, color-coded vs `maxCollateralRatio`, with `Excluded` split by reason and uncapped offer pagination; new `derivePriceViaBridges`/`derivePriceWithBridges` in `modules/order/utils/system.ts` (LP legs bridge only on opt-in) (`modules/credit_pricing.ts`, `modules/credit_runtime.ts`, `modules/order/utils/system.ts`, new `tests/test_credit_pricing.ts`, `tests/test_price_bridges.ts`, `tests/test_credit_conversion_fallback.ts`).
|
|
18
|
+
- **Feat(cli)**: add `dexbot reload` that leaves the credential daemon untouched — mirrors `restart` on every runtime surface (unlock `reload-all` recycles bots + market adapter via SIGUSR2 skipping the daemon re-unlock block, supervisor `reload`/`reload-all`, `pm2 restart` with no `ensureCredentialDaemon`, `reload dexbot-cred` rejected) so bot/adapter recycling no longer costs a password prompt (`unlock.ts`, `modules/launcher/bot_supervisor.ts`, `modules/launcher/launch_modes.ts`, `modules/launcher/monolithic_runtime.ts`, `pm2.ts`, `dexbot.ts`, `README.md`, `docs/WORKFLOW.md`).
|
|
19
|
+
- **Fix(identity)**: enforce case-insensitive bot-name identity across lookups — new `isSameBotName` in `modules/utils/sanitize_key.ts` (sanitized compare with blank-input guard) used by bot_settings, dexbot, unlock, bot, pm2, claw launcher/profiles/credit adapter, maintenance runtime, market-adapter inputs and helper scripts; PM2 stop/delete/restart/reload resolve to the canonical stored name, example pair-derived bot names in comments/help/fixtures replaced with a generic placeholder (published changelog history untouched).
|
|
20
|
+
- **Fix(update)**: run `npm install` only when dependencies actually changed — new `needsDepsInstall(preUpdateHead)` gate in `scripts/update.ts` (install only when node_modules missing/incomplete, manifests changed since pre-update commit, or manifests worktree-dirty; fail-open on git errors) plus a `lockRegenerated` double-install guard (`scripts/update.ts`).
|
|
21
|
+
- **Fix(adapter)**: centralize market-adapter ownership in unlock wrapper on one 1min interval — new `modules/launcher/adapter_requirement.ts` (semantic name:gridPrice fingerprint, corrupt/unreadable bots.json reported not thrown); wrapper exports `DEXBOT_ADAPTER_OWNER=wrapper` so supervised bots skip adapter sync and create no poll timer (wrapper-less modes keep the in-bot fallback); `TIMING.BOTS_CONFIG_POLL_INTERVAL_MS` now 60s shared with the watchdog interval; fixes `''`-fingerprint false-change and corrupt-skip regressions (`modules/launcher/adapter_requirement.ts`, `unlock.ts`, `modules/constants.ts`, `modules/launcher/*`, `modules/dexbot_class.ts`).
|
|
22
|
+
- **Feat(accounts)**: cache bot account IDs in bots.json for offline resolution — byte-preserving in-place `accountId` patch in `analysis/bot_key_utils.ts` (comment/string-aware scanner, re-parse assert, atomic write, full-rewrite fallback) with `persistBotAccountId`/`getStoredBotAccountId`/`findBotKeyByAccountRef`; new `analysis/resolve_bot_accounts.ts` batch backfill CLI (`npm run analysis:resolve-accounts`, `--dry-run`/`--refresh`/`--bot-key`/`--json`); editor stamps IDs via `ensureBotAccountId`, analysis tools and `test-credit-renewal` prefer the cache with `--refresh-account` re-verify; process-wide console floor (`setGlobalConsoleLevel`) silences node-init chatter during supervised lookups (`analysis/bot_key_utils.ts`, `analysis/resolve_bot_accounts.ts`, `modules/account_bots.ts`, `modules/order/logger.ts`, `modules/bitshares_client.ts`, `tests/test_bot_account_id.js`, `tests/test_logger_console_floor.js`).
|
|
23
|
+
- **Fix(guard)**: close stale-pivot race in last-fill guard and harden spread correction — `refreshLastFillPivotFromQueue()` peeks the incoming fill queue before every COW guard check (CREATE, rotation UPDATE, fallback CREATE) and `recordLastFilledPrices()` now runs per chunk so later broadcast chunks gate on the true latest fill; per-action plan-origin stamping keeps spread-correction CREATE bypass while rotation UPDATEs never bypass; `determineOrderSideByFunds()` returns null instead of cross-asset raw-unit compare when priceless with both sides funded; spread check defers on post-gate fills with funds recalc before side decision; batch-level LAST-FILL-GUARD summary + per-batch pivot log lines added (`modules/dexbot_cow_runtime.ts`, `modules/dexbot_class.ts`, `modules/order/grid.ts`, `modules/dexbot_maintenance_runtime.ts`, `modules/order/manager.ts`, new `tests/test_stale_guard_pivot_fixes.js`).
|
|
24
|
+
|
|
25
|
+
### 2026-09-05
|
|
26
|
+
|
|
27
|
+
- **Feat(cli)**: add `dexbot tv` one-step TradingView chart command — `dexbot tv <bot|pool-id|AssetA/AssetB> [--month N]` pulls 1h candles in chunked 1-month windows and delegates rendering to the TradingView exporter, replacing the manual fetch-then-export two-step; fetcher chunking reused via exported `fetchCandlesSequentially`/`outputPath`/`buildFetchWindowsFromRange`, chain-log mute centralized in `modules/utils/chain_logs.ts`, saved-chart paths print as clickable `file://` links via `toFileUrl` (`scripts/tv.ts`, `dexbot.ts`, `market_adapter/inputs/fetch_lp_data.ts`, `modules/utils/chain_logs.ts`, `analysis/chart_utils.ts`, docs).
|
|
28
|
+
- **Fix(cow)**: clamp COW rotation size to booked remainder for partial surplus — new `clampRotationSizeForPartial` in `modules/order/utils/validate.ts` applied at both rotation-pairing sites (`pairRotations`, `optimizeRebalanceActions`) so rotations sourced from PARTIAL surplus target the booked remainder instead of the hole size, ending the plan→skip→restore loop that stranded holes and left non-contiguous rails (`modules/order/utils/validate.ts`, `modules/order/manager.ts`, `modules/order/utils/system.ts`, `tests/test_cow_master_plan.ts` COW-019).
|
|
29
|
+
- **Fix(credit)**: distinguish Avar/Curr CR lines in `dexbot credit` output — display-only: Avar. CR label orange+bold printed first, Curr. CR label grey+bold with trailing comma, values keep health colors (`scripts/analyze-credit.ts`).
|
|
30
|
+
- **Feat(discovery)**: split HIGH discovery tier into DEXBot2 vs DEXBot1-style by op-77 usage — DEXBot2 broadcasts native `limit_order_update` ops (type 77) for COW re-prices while DEXBot1-style only cancels+recreates, so presence of op 77 in-window assigns flavor; display-only split (score formula unchanged) with Updates column in HIGH tier, summary and `--output-json` carrying flavor/updates (`analysis/bot_usage/kibana_bot_queries.ts`, `analysis/bot_usage/discover_bot_accounts.ts`).
|
|
31
|
+
- **Fix(cli)**: forward `--help`/`-h` to the `credit` and `tv` sub-scripts — the CLI intercepted help flags anywhere in argv and always printed generic help, so `dexbot credit --help` / `dexbot tv --help` never reached the scripts that own their usage text; the dispatcher now resolves the requested command first and lets only scripts with offline help handling (`credit`, `tv`) keep the flag, everything else keeps the generic help (`dexbot.ts`).
|
|
32
|
+
|
|
33
|
+
## [1.4.25] - 2026-09-02 - Genesis-Frozen Price-Slot Determinism, Self-Trade & Fill-Guard Hardening, Grid Orphan & Recovery Hardening
|
|
34
|
+
|
|
35
|
+
### 2026-08-29
|
|
36
|
+
|
|
37
|
+
- **Fix(grid)**: restore strict ERROR diagnostics by fixing hidden fund-invariant and precision failures — re-enables strict diagnostics that were masked by NaN fund-invariant comparisons and float precision drift; fixes fund-invariant tolerance fallback, amount precision helpers, and related silent-failure paths so ERROR logs fire correctly (`modules/order/accounting.ts`, `modules/order/utils/math.ts`, `modules/constants.ts`, etc.).
|
|
38
|
+
- **Fix(gap-band)**: enforce gap-band invariant across COW plan, sync, reconcile and recovery (P1–P5) — introduces authoritative gap-band checks that reject placements violating the reserved gap, validates gap-band geometry in COW planning, sync adoption, startup reconcile and recovery persistence so boundaries cannot drift into the forbidden band (`modules/order/grid.ts`, `modules/order/utils/math.ts`, `modules/dexbot_cow_runtime.ts`, `modules/order/sync_engine.ts`, `modules/order/grid_reconcile*.ts`, `modules/dexbot_state_recovery.ts`).
|
|
39
|
+
- **Fix(grid)**: prevent same-slot re-placement and truncation-drop orphans after COW commit — guards against re-creating an order on a slot that was just committed and against truncation-ambiguous reads dropping live orphans; keeps slot provenance across COW commit so placed orders are not re-issued or lost on a truncated read (`modules/dexbot_cow_runtime.ts`, `modules/order/sync_engine.ts`, `modules/order/grid_reconcile_internal.ts`).
|
|
40
|
+
- **Fix(grid)**: make chain evidence authoritative and remove destructive gap-band cancellation — cancels that swept the gap band based on stale local state are removed; chain-observed orders are the sole authority for gap/rail membership and gap-band sweeps are no longer triggered from local-only evidence (`modules/order/grid_reconcile*.ts`, `modules/order/sync_engine.ts`).
|
|
41
|
+
- **Fix(grid)**: heal and prevent sized-orphan phantom orders in spread and COW commit — spread-correction and COW commit paths that left VIRTUAL slots with `size>0` and no `orderId` (sized orphans causing 2.02% vs 3.04% spread divergence) are healed on reload (virtual-size zeroing with `createUncertain` preservation) and prevented at commit (orphan exclusion from sizing denominator, durable markers) (`modules/order/grid.ts`, `modules/order/manager.ts`, `modules/account_orders.ts`, `modules/dexbot_cow_runtime.ts`).
|
|
42
|
+
|
|
43
|
+
### 2026-08-30
|
|
44
|
+
|
|
45
|
+
- **Fix(recovery)**: stop recovery re-anchoring and make orphan adoption durable — structural resync no longer re-anchors to the latest AMA center (state repair only); orphan adoption widened with `ORPHAN_ADOPTION_TOLERANCE_MULTIPLIER` (×4) on empty slots, reconcile prefers in-place price updates over pre-emptive cancels, and boundary/slot persistence is hardened (`modules/dexbot_maintenance_runtime.ts`, `modules/order/sync_engine.ts`, `modules/order/grid_reconcile.ts`, `modules/constants.ts`).
|
|
46
|
+
- **Fix(engine)**: harden order engine against orphan-cascade failure modes — closes four unvalidated local-state paths (stale-slot fill price poisoning the anchor, off-market placement, phantom virtualization from empty reads, blind unknown-fill proceed credit) via broadcast orphan gates, anchor outlier rejection, price-sanity clamp, suspect empty-read guard (3 confirms), adoption retry, and durable `createUncertain` markers; placement now wrapped in `startBroadcasting` so fill-driven rebalances cannot duplicate plans (`modules/order/grid_reconcile.ts`, `modules/order/manager.ts`, `modules/dexbot_maintenance_runtime.ts`, `modules/constants.ts`, `modules/order/utils/order.ts`, `modules/dexbot_fill_runtime.ts`, `modules/dexbot_cow_runtime.ts`).
|
|
47
|
+
- **Fix(maintenance)**: make trigger reset reliable — skip idle gate, drain stalled fills, repair infeasible boundaries — trigger-file resets now execute immediately (`skipIdle`), fill queues deferred by `batchInFlight`/`recoverySyncInFlight` are drained on pipeline clear via `_onBroadcastRegionEnd` (wired at both `OrderManager` creation sites), and `NO_FEASIBLE_BOUNDARY` (overlapping BUY/SELL inside gap) escalates to a minimal cancel ladder so placements resume instead of freezing in adoption-only mode (`modules/dexbot_maintenance_runtime.ts`, `modules/order/manager.ts`, `modules/dexbot_startup_runtime.ts`, `modules/order/utils/math.ts`, `modules/order/grid_reconcile*.ts`).
|
|
48
|
+
- **Docs**: consolidate orphan-fix plans and add grid monotonicity gate — four test-branch incident/plan docs merged into `docs/CONSOLIDATED_ORPHAN_FIX_SUMMARY.md` (LANDED/REVERTED/SUPERSEDED annotated) and new `npm run analysis:grid-check` (`analysis/grid_correction_check.ts`) validates consecutive same-direction fills are monotonic (sell rising / buy falling) via Kibana `fill_order` history (`analysis/*`, `docs/*`, `modules/constants.ts`).
|
|
49
|
+
|
|
50
|
+
### 2026-08-31
|
|
51
|
+
|
|
52
|
+
- **Fix(launcher)**: ensure bot detection within 5min and correct disable/enable active check — new `TIMING.BOTS_CONFIG_POLL_INTERVAL_MS` (5min) decouples fingerprint polling from the heavy 240min chain fetch so new/reenabled bots are observed within 5min; `dexbot.ts` `setBotActiveState` now treats `undefined` as active (`active !== false`) fixing `enable all` churn on implicit-active bots (`modules/constants.ts`, `modules/dexbot_maintenance_runtime.ts`, `modules/dexbot_class.ts`, `modules/dexbot_startup_runtime.ts`, `dexbot.ts`).
|
|
53
|
+
- **Fix(security)**: close shutdown race that wiped live signing tokens — `_shutdownImpl` no longer nulls `botHmacSecret` while deferred SAFE-REBALANCE continuations are pending; tokens are wiped only on process `exit` via `registerExitWipe`; `SOURCE_AUTH_DENIED` retries re-read `daemon-policies.json`, `OrderManager` gains `_shuttingDown`/`_awaitBroadcastIdle` abort, and monolithic mode retries failed bot startups bounded (3×30s) (`modules/dexbot_class.ts`, `modules/graceful_shutdown.ts`, `modules/key_store.ts`, `modules/order/manager.ts`, `modules/dexbot_fill_runtime.ts`, `modules/dexbot_cow_runtime.ts`, `dexbot.ts`).
|
|
54
|
+
- **Fix(grid)**: block self-trading grid placements across all broadcast paths — adds tolerance-widened crossing guard (`findCrossedOrder` in `modules/order/utils/math.ts`, `buildCrossingCandidates` merging master/pending/chain) to COW CREATE/rotation NOT-FOUND fallback and to startup reconcile/relocation/price-correction paths; rotation now uses swept-band exclusion instead of stale slot-type rotation that caused chunked-broadcast self-fills (`modules/dexbot_cow_runtime.ts`, `modules/order/utils/math.ts`, `modules/order/grid_reconcile_internal.ts`, `modules/order/utils/order.ts`, `modules/order/strategy.ts`).
|
|
55
|
+
- **Fix(fill)**: restore main fill queue handling stalled by broadcasting gate — removes `isBroadcastingActive` from `consumeFillQueue` defer gate (already serialized by `_fillProcessingLock`/stale-plan guard; defer had no reschedule and starved the queue during chunked broadcasts) and drains deferred fills when `_batchInFlight`/`_recoverySyncInFlight` clears (`modules/dexbot_fill_runtime.ts`, `modules/dexbot_maintenance_runtime.ts`, `modules/dexbot_class.ts`).
|
|
56
|
+
- **Fix(grid)**: re-price duplicate-price grid stragglers instead of cancelling them — burst re-anchor that left multiple BUYs at the same level (e.g. 902.08089 ×2, 894.01113 ×3) and self-filled is now fixed by re-pricing stragglers to the next unique ladder step away from market (clamped to `[minPrice,maxPrice]`, preserving `orderId`/`size`) via `correctOrderPriceOnChain` UPDATEs instead of virtualize→cancel; adds whole-burst swept-band caching and asymmetric multi-sell-sweep buy exclusion for chunked and unified bursts (`modules/order/strategy.ts`, `modules/dexbot_class.ts`, `tests/test_grid_robustness.ts`).
|
|
57
|
+
|
|
58
|
+
### 2026-09-01
|
|
59
|
+
|
|
60
|
+
- **Fix(engine)**: revert anchor divergence and boundary-evidence, restore last-fill guard — removes `MarketAnchor`/`BOUNDARY-EVIDENCE`/`BAND-EXCLUSION` paths that drifted from self-trade fills and cancelled stranded orders, restores `deriveTargetBoundary`/`snapRail` grid-dedupe and seeds `LAST-FILL-GUARD` from book at startup/post-fill to block BUY above last filled BUY and SELL below last filled SELL with cross-guard per-type collision checks (`modules/constants.ts`, `modules/order/utils/order.ts`, `modules/order/strategy.ts`, `modules/order/grid_reconcile.ts`, `modules/dexbot_class.ts`, `modules/order/manager.ts`, `modules/dexbot_cow_runtime.ts`).
|
|
61
|
+
- **Fix(grid)**: close duplicate-order incident class from trigger-reset phantom empty read — a trigger reset that observed a single 0-order lagging-node read rebuilt over a live order and queued the wrong duplicate for cancel (books 0.5626 vs chain 0.5626+0.6659). Fix: trigger `GRID-RESYNC` empty reads now require a 2s confirming re-read (`SYNC_EMPTY_READ_CONFIRM_DELAY_MS`), rotation/plan UPDATEs clamp or skip growing PARTIAL slots above booked remaining size, Pass 1 size-consistency tiebreak rebinds a slot to the same-price chain order matching booked size (exact), and `updateOrdersOnChainBatchCOW` drains pending price corrections before planning (`modules/dexbot_maintenance_runtime.ts`, `modules/constants.ts`, `modules/dexbot_cow_runtime.ts`, `modules/order/sync_engine.ts`, `modules/order/manager.ts`).
|
|
62
|
+
- **Fix(g guard)**: last-fill guard pivot ± halfIncrement (BUY < pivot*(1-half), SELL > pivot*(1+half)) — replaces dual-pivot + tolerance with single global pivot (most recent fill) ± half grid increment (e.g. i=0.5% @1000 → BUY<997.5, SELL>1002.5); fixes SELL 1013>1001 after BUY 1001 being wrongly blocked and closes half-step profit hole; spread-correction bypass retained (`modules/order/manager.ts`, `modules/dexbot_cow_runtime.ts`).
|
|
63
|
+
|
|
64
|
+
### 2026-09-02
|
|
65
|
+
|
|
66
|
+
- **Feat(genesis)**: implement genesis-frozen price-slot determinism (Phase 1–2, log mode) — `slot-N` becomes the single source of truth (`price = genesis.priceLevels[N]`); adds `GridGenesis`/`hashPriceLevels`/`priceLevelsForGenesis`/`priceForSlot`/`slotIndexForPrice` (binary search, lower-wins tie)/`priceSlotEqual` (int equality)/`buildGenesisFromPriceLevels`/`assertSlotPriceInvariant`, canonical `parseSlotIndex` (`modules/order/utils/slot.ts`), `createOrderGrid` dedup+genesis build, `loadGrid` genesis validation/canonical re-sort/type re-assignment via `parseSlotIndex` with legacy migration, `account_orders`/`working_grid`/`system`/`startup`/`recovery` genesis threading, and `GRID_PRICE_SLOT_DETERMINISM_PLAN.md` (`modules/order/utils/math.ts`, `modules/order/grid.ts`, `modules/account_orders.ts`, `modules/order/working_grid.ts`, `modules/order/utils/system.ts`, `modules/dexbot_startup_runtime.ts`, `modules/dexbot_state_recovery.ts`, `modules/order/grid_reconcile.ts`, `docs/*`, `tests/test_grid_price_slot_invariant.ts`).
|
|
67
|
+
- **Feat(genesis)**: complete genesis-frozen price-slot determinism (phases 3–9) — replaces all tolerance-based price matching with `slotId` equality / `priceSlotEqual`; sync engine Pass 2 adopts by nearest slot via `slotIndexForPrice` with `isSlotInRail` gap check and VIRTUAL/free slot bind; COW guards `hasSlotPriceCollision`/`validateCreateTargetSlots` use `priceSlotEqual`; fill/grid/rail paths (`isSlotInRail` fail-closed, `chainOrderMatchesSlot`, `hasDuplicatePriceLevel`, `grid_reconcile` cleanup) unified on genesis; legacy tolerance retained only for no-genesis migration (`modules/order/sync_engine.ts`, `modules/dexbot_cow_runtime.ts`, `modules/order/utils/validate.ts`, `modules/dexbot_fill_runtime.ts`, `modules/order/*`, `tests/*` 12 suites).
|
|
68
|
+
- **Feat(editor)**: add Range quality legend with tiered coloring — `RANGE_QUALITY` thresholds (`GREEN_MIN 2.0` wide / `YELLOW_MIN 1.55` efficient / `ORANGE_MIN 1.45` tight / `RED_MAX 1.45` suicidal `<1.45x`) drive a pre-entry legend and live `colorRangeValueByQuality` in `askNumberOrMultiplier`/`askMaxPrice` and summary Pair display (cyan) (`modules/constants.ts`, `modules/account_bots.ts`).
|
|
69
|
+
- **Feat(whitelist)**: add scoped `--bot` overwrite with validation and warnings — `dexbot white --bot <botKey>` overwrites only the targeted whitelist key (merge preserves unknown flags like `derivativeSignals`) while additive-only behavior is preserved without `--bot`; `parseOptions` now collects `botKeys` (`--bot`/`--bot-key`/`--botKey`, `=` and comma forms, repeatable) with missing/flag-like validation (throws, main prints usage and exits 1), `buildWhitelist` filters to targeted keys and warns when `--bot` target not found or has non-AMA `gridPrice` (`scripts/generate_market_adapter_whitelist.ts`, `dexbot.ts`, `docs/*`, `tests/test_market_adapter_fixes.ts`).
|
|
70
|
+
- **Fix(editor)**: align Range quality wording — legend `≤1.35x: suizidal` → `<1.45x: suizidal` to match `getRangeQuality` (`<1.45x` red, `1.45x–1.55x` orange) and make `RANGE_QUALITY.RED_MAX` authoritative (`modules/constants.ts`, `modules/account_bots.ts`).
|
|
71
|
+
|
|
5
72
|
## [1.4.24] - 2026-08-28 - Native Fill Gap Recovery, Eager Coalesced Retry, LP Collateral Offer-First Pricing
|
|
6
73
|
|
|
7
74
|
### 2026-08-28
|
package/README.md
CHANGED
|
@@ -178,6 +178,7 @@ Keep the default settings first, and tune these:
|
|
|
178
178
|
This writes `market_adapter_whitelist.json` in the profiles directory. New AMA bots get AMA
|
|
179
179
|
live writes and range scaling. Use `dexbot white --dynamic-weight` for
|
|
180
180
|
newly generated dynamic-weight entries; existing entries are preserved.
|
|
181
|
+
To overwrite an existing bot: `dexbot white --dynamic-weight --bot <botKey>`.
|
|
181
182
|
|
|
182
183
|
6. **Start DEXBot2** with `dexbot start`.
|
|
183
184
|
|
|
@@ -234,12 +235,13 @@ Defaults in [`modules/constants.ts`](modules/constants.ts) are overridable at gl
|
|
|
234
235
|
|
|
235
236
|
## 🎯 Zero-Dependency Process Management
|
|
236
237
|
|
|
237
|
-
`dexbot start` is the recommended production runtime (global install). Repo-root users can run `./unlock` instead. It runs the selected bot set as one monolithic bot process, with the credential daemon and market adapter in separate helper processes. Monolithic start/stop/restart controls apply to the whole runtime, not to individual bots.
|
|
238
|
+
`dexbot start` is the recommended production runtime (global install). Repo-root users can run `./unlock` instead. It runs the selected bot set as one monolithic bot process, with the credential daemon and market adapter in separate helper processes. Monolithic start/stop/reload/restart controls apply to the whole runtime, not to individual bots.
|
|
238
239
|
|
|
239
240
|
```bash
|
|
240
241
|
dexbot start/stop # Stop/start the monolithic runtime
|
|
241
242
|
dexbot start --dryrun # Dry-run (no transactions broadcast)
|
|
242
|
-
dexbot
|
|
243
|
+
dexbot reload # Reload the runtime (leaves credential daemon untouched)
|
|
244
|
+
dexbot restart # Restart the runtime (re-unlocks credential daemon)
|
|
243
245
|
dexbot delete # Shut down and clean up
|
|
244
246
|
```
|
|
245
247
|
|
|
@@ -259,6 +261,8 @@ dexbot enable {all|<bot>} # Enable bot in config
|
|
|
259
261
|
dexbot stat # Runtime status (unlock or PM2)
|
|
260
262
|
dexbot order [<bot>] # Analyze order grids
|
|
261
263
|
dexbot order --export # Export as HTML to analysis/charts/
|
|
264
|
+
dexbot tv <bot|pool|A/B> # TradingView 1h chart with AMA overlay (default: 3 months)
|
|
265
|
+
dexbot credit [<bot>] # Live summed MPA + borrowed-credit positions per asset per bot
|
|
262
266
|
|
|
263
267
|
dexbot update # Update DEXBot2
|
|
264
268
|
dexbot clear # Clear log files
|
|
@@ -271,6 +275,7 @@ PM2 is optional — `dexbot start` is the native solution.
|
|
|
271
275
|
|
|
272
276
|
```bash
|
|
273
277
|
dexbot pm2 [<bot>] # Start with PM2
|
|
278
|
+
dexbot pm2 reload {all|<bot>} # Reload managed apps, dexbot-cred untouched
|
|
274
279
|
dexbot pm2 restart {all|<bot>|dexbot-cred} # Safe restart
|
|
275
280
|
dexbot pm2 stop {all|<bot>} # Stop (via wrapper)
|
|
276
281
|
dexbot pm2 delete {all|<bot>} # Delete (via wrapper)
|
package/analysis/README.md
CHANGED
|
@@ -21,9 +21,10 @@ Tools that inspect DEXBot trading behavior and the market data it operates on. O
|
|
|
21
21
|
| Tool | Ask this when… | One-line command |
|
|
22
22
|
|------|----------------|------------------|
|
|
23
23
|
| [`trade_profitability.ts`](#trade-profitability-analyzer-trade_profitabilityts) | "Is my bot making money?" — PnL, R-multiples, drawdown | `npm run analysis:trade-pnl -- <account-id>` |
|
|
24
|
+
| [`grid_correction_check.ts`](#grid-correction-check-grid_correction_checkts) | "Is my grid placing orders monotonically?" — sell/buy price inversion detector | `npm run analysis:grid-check -- --bot-key <bot-key>` |
|
|
24
25
|
| [`analyze_risk_profile.ts`](#risk-profile-analyzer-analyze_risk_profilets) | "How wide should my Safe Range clamps be?" | `node dist/analysis/analyze_risk_profile.js --bot-key <bot-key>` |
|
|
25
26
|
| [`analyze_trade_heatmap.ts`](#trade-heatmap-analyze_trade_heatmapts) | "Where did trade volume cluster vs the AMA?" | `node dist/analysis/analyze_trade_heatmap.js --bot-key <bot-key>` |
|
|
26
|
-
| [`tradingview/analyze_tradingview.ts`](#tradingview-chart-tradingviewanalyze_tradingviewts) | "Just give me a candle chart" | `
|
|
27
|
+
| [`tradingview/analyze_tradingview.ts`](#tradingview-chart-tradingviewanalyze_tradingviewts) | "Just give me a candle chart" | `dexbot tv <bot-key>` |
|
|
27
28
|
| [`analyze_dynamic_weight.ts`](#dynamic-weight-research-analyze_dynamic_weightts) | "Are buy/sell weights tuned for this regime?" | `node dist/analysis/analyze_dynamic_weight.js --bot-key <bot-key>` |
|
|
28
29
|
| [`analyze_volatility.ts`](#volatility-analyze_volatilityts) | "Both weights clipped too hard / not enough?" | `node dist/analysis/analyze_volatility.js --bot-key <bot-key>` |
|
|
29
30
|
| [`analyze_regime.ts`](#supporting-sub-signals) | "Is the trend/chaos gate too aggressive?" | `node dist/analysis/analyze_regime.js --bot-key <bot-key>` |
|
|
@@ -137,8 +138,8 @@ Fetches `fill_order` operations for a BitShares account from Kibana within a spe
|
|
|
137
138
|
# Account by ID, last 7 days (default)
|
|
138
139
|
node dist/analysis/trade_profitability.js 1.2.123456
|
|
139
140
|
|
|
140
|
-
# Account by name
|
|
141
|
-
node dist/analysis/trade_profitability.js "my-account-name" --
|
|
141
|
+
# Account by name (auto-resolved in the background)
|
|
142
|
+
node dist/analysis/trade_profitability.js "my-account-name" --hours 720
|
|
142
143
|
|
|
143
144
|
# Absolute window with asset filter
|
|
144
145
|
node dist/analysis/trade_profitability.js 1.2.123456 \
|
|
@@ -161,7 +162,8 @@ node dist/analysis/trade_profitability.js 1.2.123456 \
|
|
|
161
162
|
| `--end <iso>` | — | End time |
|
|
162
163
|
| `--hours <n>` | `168` (7d) | Lookback hours (alternative to start/end) |
|
|
163
164
|
| `--asset <id>` | all | Filter to one base asset ID |
|
|
164
|
-
| `--lookup` | off |
|
|
165
|
+
| `--lookup` | off | Legacy (no-op): account names always resolve automatically |
|
|
166
|
+
| `--refresh-account` | off | Force re-resolution and update the stored `accountId` |
|
|
165
167
|
| `--node <url>` | first healthy from built-in pool (10 nodes) | BitShares node for account + asset resolution |
|
|
166
168
|
| `--csv <file>` | — | Export chronologically sorted trade list |
|
|
167
169
|
| `--json <file>` | — | Export full analysis with per-pair PnL data |
|
|
@@ -219,6 +221,50 @@ node dist/analysis/trade_profitability.js 1.2.123456 \
|
|
|
219
221
|
|
|
220
222
|
</details>
|
|
221
223
|
|
|
224
|
+
### Grid Correction Check (`grid_correction_check.ts`)
|
|
225
|
+
|
|
226
|
+
Validates grid discipline from the same Kibana fill pipeline as `trade_profitability.ts`: two consecutive same-direction fills on a pair must be monotonic — sell prices rising, buy prices falling (equal is OK). An inversion means the bot placed an order below its own previous sell (or above its own previous buy), e.g. an orphaned order filling outside grid accounting. Used as the external regression gate for the orphan-fix plans in `docs/CONSOLIDATED_ORPHAN_FIX_SUMMARY.md`.
|
|
227
|
+
|
|
228
|
+
**Pipeline:** Kibana `fill_order` query (paginated `search_after`) → on-chain asset precision resolution → buy/sell classification → chronological sort → per-order aggregation (multi-fill orders collapsed to weighted-avg price by default) → consecutive same-direction pair comparison → violation report with daily histogram.
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
# Per-order aggregated check (default), last 7 days
|
|
232
|
+
npm run analysis:grid-check -- --bot-key <bot-key> --hours 168
|
|
233
|
+
|
|
234
|
+
# 30 days, JSON + CSV export of violations
|
|
235
|
+
npm run analysis:grid-check -- --bot-key <bot-key> --hours 720 --json out.json --csv out.csv
|
|
236
|
+
|
|
237
|
+
# Raw fill granularity instead of per-order aggregation
|
|
238
|
+
npm run analysis:grid-check -- --bot-key <bot-key> --per-fill --hours 168
|
|
239
|
+
|
|
240
|
+
# Forgive small adverse moves within 0.1%
|
|
241
|
+
npm run analysis:grid-check -- --bot-key <bot-key> --hours 168 --tolerance 0.1
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Exit code `0` = pass, `2` = violations found, `1` = fatal error. Bot keys resolve via `profiles/bots.json` (`--list-bots` to enumerate); the account defaults to the bot's stored `accountId` when present (no chain lookup — the ID is auto-saved next to `preferredAccount` after the first successful name resolution, re-verified with `--refresh-account`), otherwise `preferredAccount` is resolved on-chain, and can be overridden with `--account <1.2.x|name>`.
|
|
245
|
+
|
|
246
|
+
<details><summary>Options (click to expand)</summary>
|
|
247
|
+
|
|
248
|
+
| Flag | Default | Description |
|
|
249
|
+
|------|---------|-------------|
|
|
250
|
+
| `--bot-key <key>` | — | Bot key or name from `profiles/bots.json` (required) |
|
|
251
|
+
| `--hours <n>` | `168` | Lookback hours from now |
|
|
252
|
+
| `--start <iso>` / `--end <iso>` | — | Absolute time window |
|
|
253
|
+
| `--account <id>` | bot `preferredAccount` | Override account ID or name |
|
|
254
|
+
| `--lookup` | off | Legacy (no-op): account names always resolve via BitShares node when no stored ID exists |
|
|
255
|
+
| `--refresh-account` | off | Force re-resolution of `preferredAccount` and update the stored `accountId` when it changed |
|
|
256
|
+
| `--node <url>` | first built-in node | Node for account/asset resolution |
|
|
257
|
+
| `--per-fill` | off | Check at fill granularity instead of per-order aggregated |
|
|
258
|
+
| `--include-cross-pair` | off | Also check consecutive fills across different pairs |
|
|
259
|
+
| `--tolerance <pct>` | `0` | Adverse price move (%) forgiven before flagging |
|
|
260
|
+
| `--json <file>` / `--csv <file>` | — | Export violations |
|
|
261
|
+
| `--verbose` | off | Print the full trade sequence |
|
|
262
|
+
| `--list-bots` | — | List available bot keys and exit |
|
|
263
|
+
|
|
264
|
+
</details>
|
|
265
|
+
|
|
266
|
+
**Notes:** strict sat-level comparison is the ground truth (`--tolerance` only forgives small inversions); multi-fill orders are collapsed to a weighted-average price for the default per-order mode, so a single order's partial fills at identical prices never count as inversions.
|
|
267
|
+
|
|
222
268
|
## Charts & Visualization
|
|
223
269
|
|
|
224
270
|
### Trade Heatmap (`analyze_trade_heatmap.ts`)
|
|
@@ -265,7 +311,12 @@ node dist/analysis/analyze_trade_heatmap.js \
|
|
|
265
311
|
Generates a standalone TradingView-style HTML chart with candle OHLC, SMA, AMA, VWMA, and volume panel. See [tradingview/README.md](tradingview/README.md) for full documentation.
|
|
266
312
|
|
|
267
313
|
```bash
|
|
268
|
-
#
|
|
314
|
+
# Recommended one-step: bot, pool, or pair (fetches candles + renders, default 3 months)
|
|
315
|
+
dexbot tv <bot-key>
|
|
316
|
+
dexbot tv 133
|
|
317
|
+
dexbot tv TOKENA/TOKENB
|
|
318
|
+
|
|
319
|
+
# Manual: bot-key (auto-resolves candle file and AMA settings)
|
|
269
320
|
npm run analysis:tradingview -- --source market_adapter --bot-key <bot-key>
|
|
270
321
|
|
|
271
322
|
# From an explicit candle file
|
|
@@ -445,6 +496,7 @@ These npm scripts wrap common analysis runners:
|
|
|
445
496
|
|--------|---------|
|
|
446
497
|
| `npm run analysis:tradingview` | `node dist/analysis/tradingview/analyze_tradingview.js` |
|
|
447
498
|
| `npm run analysis:trade-pnl` | `node dist/analysis/trade_profitability.js` |
|
|
499
|
+
| `npm run analysis:grid-check` | `node dist/analysis/grid_correction_check.js` |
|
|
448
500
|
| `npm run analysis:derivatives` | `node dist/analysis/analyze_derivatives.js` (legacy SMA/MACD/RSI layer, reference only) |
|
|
449
501
|
| `npm run ama:chart:lp-local` | `node dist/analysis/ama_fitting/generate_unified_comparison_chart.js` (chart also auto-generated by optimizer) |
|
|
450
502
|
|
|
@@ -457,6 +509,9 @@ npm run analysis:tradingview -- --source market_adapter --bot-key <bot-key>
|
|
|
457
509
|
# Trade PnL
|
|
458
510
|
npm run analysis:trade-pnl -- 1.2.123456 --hours 720
|
|
459
511
|
|
|
512
|
+
# Grid correction check (monotonicity regression gate)
|
|
513
|
+
npm run analysis:grid-check -- --bot-key <bot-key> --hours 168
|
|
514
|
+
|
|
460
515
|
# File-based
|
|
461
516
|
npm run analysis:tradingview -- --file market_adapter/data/market_adapter_<bot-key>_1h.json
|
|
462
517
|
npm run ama:chart:lp-local -- --data market_adapter/data/lp/<pair>/lp_pool_<id>_<interval>.json
|
|
@@ -465,4 +520,5 @@ npm run ama:chart:lp-local -- --data market_adapter/data/lp/<pair>/lp_pool_<id>_
|
|
|
465
520
|
## Related Docs
|
|
466
521
|
|
|
467
522
|
- [Market Adapter](../market_adapter/README.md) — live AMA pricing, grid triggers, dynamic weights, and recalc triggers
|
|
523
|
+
- [Consolidated Orphan-Fix Summary](../docs/CONSOLIDATED_ORPHAN_FIX_SUMMARY.md) — orphan/gap-band root-cause plans; `grid_correction_check` is their regression gate
|
|
468
524
|
- [DEXBot2 Tuning Cheat Sheet](../claw/docs/DEXBOT2_TUNING_CHEAT_SHEET.md) — grid tuning reference for live bots
|
|
@@ -4,7 +4,8 @@ import fs from 'node:fs';
|
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { PATHS } from '../modules/paths.js';
|
|
6
6
|
import { getStorage } from '../modules/storage/index.js';
|
|
7
|
-
const { readJSON } = getStorage();
|
|
7
|
+
const { readJSON, writeJSON } = getStorage();
|
|
8
|
+
import { parseJsonWithComments } from '../modules/order/utils/system.js';
|
|
8
9
|
import { MARKET_ADAPTER } from '../modules/constants.js';
|
|
9
10
|
import { loadMarketProfiles } from './tradingview/tradingview_uplot_chart_generator.js';
|
|
10
11
|
import { sanitizeKey } from '../modules/utils/sanitize_key.js';
|
|
@@ -22,7 +23,13 @@ function loadBotSettings(filePath = PATHS.PROFILES.BOTS_JSON) {
|
|
|
22
23
|
try {
|
|
23
24
|
return readJSON(filePath);
|
|
24
25
|
} catch (_) {
|
|
25
|
-
|
|
26
|
+
// The bot editor reads/writes through a comment-tolerant parser, so
|
|
27
|
+
// operator comments may legally exist — fall back before giving up.
|
|
28
|
+
try {
|
|
29
|
+
return parseJsonWithComments(fs.readFileSync(filePath, 'utf8'));
|
|
30
|
+
} catch (_) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
26
33
|
}
|
|
27
34
|
}
|
|
28
35
|
|
|
@@ -70,6 +77,268 @@ function loadBotMeta(botKey: any, filePath = PATHS.PROFILES.BOTS_JSON) {
|
|
|
70
77
|
return loose || null;
|
|
71
78
|
}
|
|
72
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Locate the source span of the entryIndex-th object literal inside the
|
|
82
|
+
* top-level "bots" array of a (possibly comment-bearing) JSON document.
|
|
83
|
+
* Strings and // + block comments are skipped while scanning, so braces
|
|
84
|
+
* inside them never disturb the balance count. Returns null when the
|
|
85
|
+
* document shape is unexpected — callers fall back to a full rewrite.
|
|
86
|
+
*/
|
|
87
|
+
function findBotsEntrySpan(raw: string, entryIndex: number): { start: number; end: number } | null {
|
|
88
|
+
const m = /"bots"\s*:\s*\[/.exec(raw);
|
|
89
|
+
if (!m) return null;
|
|
90
|
+
let i = m.index + m[0].length; // just past '['
|
|
91
|
+
const n = raw.length;
|
|
92
|
+
let count = 0;
|
|
93
|
+
const skipWsComments = () => {
|
|
94
|
+
while (i < n) {
|
|
95
|
+
const c = raw[i];
|
|
96
|
+
if (c === ' ' || c === '\t' || c === '\n' || c === '\r') { i++; continue; }
|
|
97
|
+
if (c === '/' && raw[i + 1] === '/') { while (i < n && raw[i] !== '\n') i++; continue; }
|
|
98
|
+
if (c === '/' && raw[i + 1] === '*') { i += 2; while (i < n && !(raw[i] === '*' && raw[i + 1] === '/')) i++; i += 2; continue; }
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
const skipString = () => {
|
|
103
|
+
const q = raw[i];
|
|
104
|
+
i++;
|
|
105
|
+
while (i < n) {
|
|
106
|
+
const c = raw[i];
|
|
107
|
+
if (c === '\\') { i += 2; continue; }
|
|
108
|
+
if (c === q) { i++; return; }
|
|
109
|
+
i++;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
// Skip one JSON value starting at raw[i]; false on malformed input.
|
|
113
|
+
const skipValue = (): boolean => {
|
|
114
|
+
skipWsComments();
|
|
115
|
+
if (i >= n) return false;
|
|
116
|
+
const c = raw[i];
|
|
117
|
+
if (c === '"' || c === "'") { skipString(); return true; }
|
|
118
|
+
if (c === '{' || c === '[') {
|
|
119
|
+
const open = c;
|
|
120
|
+
const close = c === '{' ? '}' : ']';
|
|
121
|
+
i++;
|
|
122
|
+
let depth = 1;
|
|
123
|
+
while (i < n && depth > 0) {
|
|
124
|
+
const d = raw[i];
|
|
125
|
+
if (d === '"' || d === "'") { skipString(); continue; }
|
|
126
|
+
if (d === '/' && raw[i + 1] === '/') { while (i < n && raw[i] !== '\n') i++; continue; }
|
|
127
|
+
if (d === '/' && raw[i + 1] === '*') { i += 2; while (i < n && !(raw[i] === '*' && raw[i + 1] === '/')) i++; i += 2; continue; }
|
|
128
|
+
if (d === open) depth++;
|
|
129
|
+
else if (d === close) depth--;
|
|
130
|
+
i++;
|
|
131
|
+
}
|
|
132
|
+
return depth === 0;
|
|
133
|
+
}
|
|
134
|
+
while (i < n && raw[i] !== ',' && raw[i] !== ']' && raw[i] !== '}') i++;
|
|
135
|
+
return true;
|
|
136
|
+
};
|
|
137
|
+
for (;;) {
|
|
138
|
+
skipWsComments();
|
|
139
|
+
if (i >= n) return null;
|
|
140
|
+
if (raw[i] === ']') return null; // array ended before entryIndex
|
|
141
|
+
if (raw[i] === '{') {
|
|
142
|
+
const start = i;
|
|
143
|
+
if (!skipValue()) return null;
|
|
144
|
+
if (count === entryIndex) return { start, end: i };
|
|
145
|
+
count++;
|
|
146
|
+
} else if (!skipValue()) {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
skipWsComments();
|
|
150
|
+
if (i < n && raw[i] === ',') { i++; continue; }
|
|
151
|
+
if (i < n && raw[i] === ']') return null;
|
|
152
|
+
return null; // malformed separator
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Locate the string value of a top-level key inside one bot-entry source
|
|
158
|
+
* span. Unlike a regex, this scan skips over // and block comments as well
|
|
159
|
+
* as string literals, so a key-looking fragment inside a comment (e.g.
|
|
160
|
+
* `// "accountId": "1.2.9999" (old)`) can never be mistaken for the real
|
|
161
|
+
* key. Returns the span of the quoted value (including quotes), or null
|
|
162
|
+
* when the key is absent or its value is not a string.
|
|
163
|
+
*/
|
|
164
|
+
function findEntryKeyValueSpan(entrySrc: string, key: string): { valueStart: number; valueEnd: number } | null {
|
|
165
|
+
const n = entrySrc.length;
|
|
166
|
+
const isWs = (c: string) => c === ' ' || c === '\t' || c === '\n' || c === '\r';
|
|
167
|
+
let i = 0;
|
|
168
|
+
let depth = 0;
|
|
169
|
+
while (i < n) {
|
|
170
|
+
const c = entrySrc[i];
|
|
171
|
+
if (isWs(c)) { i++; continue; }
|
|
172
|
+
if (c === '/' && entrySrc[i + 1] === '/') { while (i < n && entrySrc[i] !== '\n') i++; continue; }
|
|
173
|
+
if (c === '/' && entrySrc[i + 1] === '*') { i += 2; while (i < n && !(entrySrc[i] === '*' && entrySrc[i + 1] === '/')) i++; i += 2; continue; }
|
|
174
|
+
if (c === '{' || c === '[') { depth++; i++; continue; }
|
|
175
|
+
if (c === '}' || c === ']') { depth--; i++; continue; }
|
|
176
|
+
if (c !== '"') { i++; continue; }
|
|
177
|
+
// String literal: read it (honoring backslash escapes).
|
|
178
|
+
let j = i + 1;
|
|
179
|
+
let str = '';
|
|
180
|
+
while (j < n) {
|
|
181
|
+
const d = entrySrc[j];
|
|
182
|
+
if (d === '\\') { str += entrySrc.slice(j, j + 2); j += 2; continue; }
|
|
183
|
+
if (d === '"') break;
|
|
184
|
+
str += d; j++;
|
|
185
|
+
}
|
|
186
|
+
if (j >= n) return null;
|
|
187
|
+
const closingQuote = j;
|
|
188
|
+
if (depth !== 1 || str !== key) { i = closingQuote + 1; continue; }
|
|
189
|
+
// Candidate key at top level: expect `:` then a quoted value.
|
|
190
|
+
let k = closingQuote + 1;
|
|
191
|
+
while (k < n && isWs(entrySrc[k])) k++;
|
|
192
|
+
if (entrySrc[k] !== ':') { i = closingQuote + 1; continue; }
|
|
193
|
+
k++;
|
|
194
|
+
while (k < n && isWs(entrySrc[k])) k++;
|
|
195
|
+
if (entrySrc[k] !== '"') { i = closingQuote + 1; continue; }
|
|
196
|
+
let m = k + 1;
|
|
197
|
+
while (m < n) {
|
|
198
|
+
const e = entrySrc[m];
|
|
199
|
+
if (e === '\\') { m += 2; continue; }
|
|
200
|
+
if (e === '"') return { valueStart: k, valueEnd: m + 1 };
|
|
201
|
+
m++;
|
|
202
|
+
}
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Byte-preserving accountId update: replaces the value in place, or inserts
|
|
210
|
+
* `"accountId"` right after `"preferredAccount"` keeping the line indent, so
|
|
211
|
+
* comments, key order and formatting elsewhere in the file survive. The
|
|
212
|
+
* patched document is re-parsed (comments allowed) and the value asserted
|
|
213
|
+
* before the atomic tmp+rename write. Returns false on any uncertainty —
|
|
214
|
+
* callers fall back to a full rewrite.
|
|
215
|
+
*/
|
|
216
|
+
function patchAccountIdInRaw(filePath: string, entryIndex: number, accountId: string): boolean {
|
|
217
|
+
let raw: string;
|
|
218
|
+
try {
|
|
219
|
+
raw = fs.readFileSync(filePath, 'utf8');
|
|
220
|
+
} catch (_) {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
const span = findBotsEntrySpan(raw, entryIndex);
|
|
224
|
+
if (!span) return false;
|
|
225
|
+
const entrySrc = raw.slice(span.start, span.end);
|
|
226
|
+
let patchedEntry: string | null = null;
|
|
227
|
+
const idSpan = findEntryKeyValueSpan(entrySrc, 'accountId');
|
|
228
|
+
if (idSpan) {
|
|
229
|
+
patchedEntry = entrySrc.slice(0, idSpan.valueStart)
|
|
230
|
+
+ `"${accountId}"`
|
|
231
|
+
+ entrySrc.slice(idSpan.valueEnd);
|
|
232
|
+
} else {
|
|
233
|
+
const prefSpan = findEntryKeyValueSpan(entrySrc, 'preferredAccount');
|
|
234
|
+
if (!prefSpan) return false;
|
|
235
|
+
const lineStart = entrySrc.lastIndexOf('\n', prefSpan.valueEnd) + 1;
|
|
236
|
+
const indentMatch = /^[ \t]*/.exec(entrySrc.slice(lineStart));
|
|
237
|
+
const indent = indentMatch ? indentMatch[0] : ' ';
|
|
238
|
+
patchedEntry = entrySrc.slice(0, prefSpan.valueEnd)
|
|
239
|
+
+ `,\n${indent}"accountId": "${accountId}"`
|
|
240
|
+
+ entrySrc.slice(prefSpan.valueEnd);
|
|
241
|
+
}
|
|
242
|
+
if (!patchedEntry || patchedEntry === entrySrc) return false;
|
|
243
|
+
const patched = raw.slice(0, span.start) + patchedEntry + raw.slice(span.end);
|
|
244
|
+
try {
|
|
245
|
+
const reparsed = parseJsonWithComments(patched);
|
|
246
|
+
const checkEntries = Array.isArray(reparsed?.bots) ? reparsed.bots : [];
|
|
247
|
+
if (checkEntries[entryIndex]?.accountId !== accountId) return false;
|
|
248
|
+
} catch (_) {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
const tmpPath = `${filePath}.tmp-persist-${process.pid}-${Date.now()}`;
|
|
252
|
+
try {
|
|
253
|
+
fs.writeFileSync(tmpPath, patched, 'utf8');
|
|
254
|
+
fs.renameSync(tmpPath, filePath);
|
|
255
|
+
return true;
|
|
256
|
+
} catch (_) {
|
|
257
|
+
try { fs.unlinkSync(tmpPath); } catch (_) { /* best-effort cleanup */ }
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Persist a resolved account name → ID mapping onto the bot entry in
|
|
264
|
+
* profiles/bots.json (`accountId` next to `preferredAccount`), so analysis
|
|
265
|
+
* tools can skip the chain lookup on subsequent runs. No-op when the stored
|
|
266
|
+
* value already matches. Prefers a byte-preserving textual patch (comments,
|
|
267
|
+
* key order and formatting survive); falls back to a full rewrite using the
|
|
268
|
+
* same atomic writeJSON serialization the bot editor uses. Returns true when
|
|
269
|
+
* the file was updated.
|
|
270
|
+
*/
|
|
271
|
+
function persistBotAccountId(botKey: any, accountId: string, filePath = PATHS.PROFILES.BOTS_JSON): boolean {
|
|
272
|
+
if (!botKey || !/^1\.2\.\d+$/.test(String(accountId))) return false;
|
|
273
|
+
let settings: any = null;
|
|
274
|
+
try {
|
|
275
|
+
settings = loadBotSettings(filePath);
|
|
276
|
+
} catch (_) {
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
const entries = Array.isArray(settings?.bots) ? settings.bots : [];
|
|
280
|
+
const normalizedKey = String(botKey).toLowerCase();
|
|
281
|
+
const index = entries.findIndex((bot: any, i: number) => computeBotKey(bot, i) === normalizedKey);
|
|
282
|
+
if (index < 0 || entries[index]?.accountId === accountId) return false;
|
|
283
|
+
try {
|
|
284
|
+
if (patchAccountIdInRaw(filePath, index, String(accountId))) return true;
|
|
285
|
+
} catch (_) {
|
|
286
|
+
// Fall through to the full rewrite below.
|
|
287
|
+
}
|
|
288
|
+
entries[index].accountId = String(accountId);
|
|
289
|
+
try {
|
|
290
|
+
writeJSON(filePath, settings);
|
|
291
|
+
return true;
|
|
292
|
+
} catch (_) {
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Return the stored chain account ID for a bot key, or null when none is
|
|
299
|
+
* stamped yet. When expectedRef is given, the stored ID is only returned if
|
|
300
|
+
* the entry's current preferredAccount still matches it — a rename must
|
|
301
|
+
* never silently reuse a stale ID.
|
|
302
|
+
*/
|
|
303
|
+
function getStoredBotAccountId(botKey: any, expectedRef?: string | null, filePath = PATHS.PROFILES.BOTS_JSON): string | null {
|
|
304
|
+
if (!botKey) return null;
|
|
305
|
+
let meta: any = null;
|
|
306
|
+
try {
|
|
307
|
+
meta = loadBotMeta(botKey, filePath);
|
|
308
|
+
} catch (_) {
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
const stored = meta && /^1\.2\.\d+$/.test(String(meta.accountId ?? '')) ? String(meta.accountId) : null;
|
|
312
|
+
if (!stored) return null;
|
|
313
|
+
if (expectedRef != null && String(meta.preferredAccount ?? '').toLowerCase() !== String(expectedRef).toLowerCase()) return null;
|
|
314
|
+
return stored;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Find the bot entry whose preferredAccount matches a raw account reference
|
|
319
|
+
* (case-insensitive). Used by tools that accept a bare account name to locate
|
|
320
|
+
* the stored accountId and the persist target. Returns null for 1.2.x input
|
|
321
|
+
* or when no bot claims the name.
|
|
322
|
+
*/
|
|
323
|
+
function findBotKeyByAccountRef(ref: any, filePath = PATHS.PROFILES.BOTS_JSON): { botKey: string; meta: any } | null {
|
|
324
|
+
if (!ref || /^1\.2\.\d+$/.test(String(ref))) return null;
|
|
325
|
+
let settings: any = null;
|
|
326
|
+
try {
|
|
327
|
+
settings = loadBotSettings(filePath);
|
|
328
|
+
} catch (_) {
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
const entries = Array.isArray(settings?.bots) ? settings.bots : [];
|
|
332
|
+
const want = String(ref).toLowerCase();
|
|
333
|
+
for (let i = 0; i < entries.length; i++) {
|
|
334
|
+
const entry = entries[i];
|
|
335
|
+
if (entry && String(entry.preferredAccount ?? '').toLowerCase() === want) {
|
|
336
|
+
return { botKey: computeBotKey(entry, i), meta: entry };
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return null;
|
|
340
|
+
}
|
|
341
|
+
|
|
73
342
|
function resolveAmaConfig(botKey: any) {
|
|
74
343
|
const botMeta = loadBotMeta(botKey);
|
|
75
344
|
// Unknown bot key: fall back to the global erSmoothPeriod default (same
|
|
@@ -153,5 +422,5 @@ function resolveAmaKey(botKey: any) {
|
|
|
153
422
|
return 'AMA3';
|
|
154
423
|
}
|
|
155
424
|
|
|
156
|
-
export { loadBotSettings, sanitizeKey, computeBotKey, resolveBotKey, candleFileForBot, resolveCandleFile, loadBotMeta, resolveAmaConfig, resolveAmaKey }
|
|
425
|
+
export { loadBotSettings, sanitizeKey, computeBotKey, resolveBotKey, candleFileForBot, resolveCandleFile, loadBotMeta, getStoredBotAccountId, findBotKeyByAccountRef, persistBotAccountId, resolveAmaConfig, resolveAmaKey }
|
|
157
426
|
|