dexbot 1.4.18 → 1.4.20
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 +24 -0
- package/README.md +1 -0
- package/analysis/ama_fitting/analyze_lambda_vs_slow.ts +2 -2
- package/analysis/ama_fitting/optimizer_high_resolution.ts +2 -1
- package/analysis/ama_fitting/package.json +1 -1
- package/analysis/analyze_derivatives.ts +4 -2
- package/analysis/analyze_dynamic_weight.ts +3 -1
- package/analysis/analyze_kalman.ts +3 -1
- package/analysis/analyze_regime.ts +3 -1
- package/analysis/analyze_regime_windows.ts +3 -1
- package/analysis/analyze_volatility.ts +2 -2
- package/analysis/bot_fitting/backtest_ama_sweep.ts +2 -1
- package/analysis/bot_fitting/backtest_bot_fitting.ts +17 -12
- package/analysis/chart_utils.ts +24 -0
- package/analysis/derivative_chart_generator.ts +3 -2
- package/analysis/trend_detection/DYNAMIC_WEIGHT_RESEARCH.md +1 -1
- package/analysis/trend_detection/dynamic_weight_chart_generator.ts +91 -55
- package/analysis/trend_detection/package.json +1 -1
- package/claw/examples/claw_profiles_example.ts +4 -1
- package/claw/modules/claw_catalog.ts +1 -1
- package/claw/modules/claw_skill_md.ts +6 -5
- package/claw/modules/dexbot_profiles.ts +3 -1
- package/claw/modules/launcher_paths.ts +4 -2
- 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/ama_fitting/analyze_lambda_vs_slow.js +2 -2
- package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.js.map +1 -1
- package/dist/analysis/ama_fitting/optimizer_high_resolution.d.ts.map +1 -1
- package/dist/analysis/ama_fitting/optimizer_high_resolution.js +2 -1
- package/dist/analysis/ama_fitting/optimizer_high_resolution.js.map +1 -1
- package/dist/analysis/analyze_derivatives.d.ts.map +1 -1
- package/dist/analysis/analyze_derivatives.js +4 -2
- package/dist/analysis/analyze_derivatives.js.map +1 -1
- package/dist/analysis/analyze_dynamic_weight.js +3 -1
- package/dist/analysis/analyze_dynamic_weight.js.map +1 -1
- package/dist/analysis/analyze_kalman.js +3 -1
- package/dist/analysis/analyze_kalman.js.map +1 -1
- package/dist/analysis/analyze_regime.js +3 -1
- package/dist/analysis/analyze_regime.js.map +1 -1
- package/dist/analysis/analyze_regime_windows.js +3 -1
- package/dist/analysis/analyze_regime_windows.js.map +1 -1
- package/dist/analysis/analyze_volatility.js +2 -2
- package/dist/analysis/analyze_volatility.js.map +1 -1
- package/dist/analysis/bot_fitting/backtest_ama_sweep.d.ts.map +1 -1
- package/dist/analysis/bot_fitting/backtest_ama_sweep.js +2 -1
- package/dist/analysis/bot_fitting/backtest_ama_sweep.js.map +1 -1
- package/dist/analysis/bot_fitting/backtest_bot_fitting.js +18 -13
- package/dist/analysis/bot_fitting/backtest_bot_fitting.js.map +1 -1
- package/dist/analysis/chart_utils.d.ts +0 -3
- package/dist/analysis/chart_utils.d.ts.map +1 -1
- package/dist/analysis/chart_utils.js +25 -0
- package/dist/analysis/chart_utils.js.map +1 -1
- package/dist/analysis/derivative_chart_generator.d.ts.map +1 -1
- package/dist/analysis/derivative_chart_generator.js +3 -2
- package/dist/analysis/derivative_chart_generator.js.map +1 -1
- package/dist/analysis/trend_detection/dynamic_weight_chart_generator.d.ts.map +1 -1
- package/dist/analysis/trend_detection/dynamic_weight_chart_generator.js +82 -50
- package/dist/analysis/trend_detection/dynamic_weight_chart_generator.js.map +1 -1
- package/dist/dexbot.d.ts.map +1 -1
- package/dist/dexbot.js +2 -3
- package/dist/dexbot.js.map +1 -1
- package/dist/market_adapter/core/market_adapter_service.d.ts.map +1 -1
- package/dist/market_adapter/core/market_adapter_service.js +8 -3
- package/dist/market_adapter/core/market_adapter_service.js.map +1 -1
- package/dist/modules/account_bots.d.ts +1 -0
- package/dist/modules/account_bots.d.ts.map +1 -1
- package/dist/modules/account_bots.js +27 -5
- package/dist/modules/account_bots.js.map +1 -1
- package/dist/modules/config.d.ts +2 -0
- package/dist/modules/config.d.ts.map +1 -1
- package/dist/modules/config.js +2 -0
- package/dist/modules/config.js.map +1 -1
- package/dist/modules/constants.d.ts +1 -0
- package/dist/modules/constants.d.ts.map +1 -1
- package/dist/modules/constants.js +13 -4
- package/dist/modules/constants.js.map +1 -1
- package/dist/modules/dexbot_class.d.ts +22 -0
- package/dist/modules/dexbot_class.d.ts.map +1 -1
- package/dist/modules/dexbot_class.js +27 -1
- package/dist/modules/dexbot_class.js.map +1 -1
- package/dist/modules/dexbot_cow_runtime.d.ts +48 -8
- package/dist/modules/dexbot_cow_runtime.d.ts.map +1 -1
- package/dist/modules/dexbot_cow_runtime.js +263 -4
- package/dist/modules/dexbot_cow_runtime.js.map +1 -1
- package/dist/modules/dexbot_state_recovery.d.ts.map +1 -1
- package/dist/modules/dexbot_state_recovery.js +20 -1
- package/dist/modules/dexbot_state_recovery.js.map +1 -1
- package/dist/modules/order/grid.d.ts.map +1 -1
- package/dist/modules/order/grid.js +146 -32
- package/dist/modules/order/grid.js.map +1 -1
- package/dist/modules/order/grid_reconcile_internal.d.ts.map +1 -1
- package/dist/modules/order/grid_reconcile_internal.js +6 -27
- package/dist/modules/order/grid_reconcile_internal.js.map +1 -1
- package/dist/modules/order/manager.d.ts +13 -0
- package/dist/modules/order/manager.d.ts.map +1 -1
- package/dist/modules/order/manager.js +75 -2
- 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 +6 -15
- package/dist/modules/order/strategy.js.map +1 -1
- package/dist/modules/order/utils/math.d.ts +102 -1
- package/dist/modules/order/utils/math.d.ts.map +1 -1
- package/dist/modules/order/utils/math.js +165 -2
- package/dist/modules/order/utils/math.js.map +1 -1
- package/dist/modules/order/utils/system.d.ts +2 -0
- package/dist/modules/order/utils/system.d.ts.map +1 -1
- package/dist/modules/order/utils/system.js +30 -2
- package/dist/modules/order/utils/system.js.map +1 -1
- package/dist/modules/paths.d.ts +26 -1
- package/dist/modules/paths.d.ts.map +1 -1
- package/dist/modules/paths.js +39 -6
- package/dist/modules/paths.js.map +1 -1
- package/dist/modules/runtime_settings.d.ts +1 -0
- package/dist/modules/runtime_settings.d.ts.map +1 -1
- package/dist/modules/runtime_settings.js +13 -2
- package/dist/modules/runtime_settings.js.map +1 -1
- package/dist/scripts/analyze-git.js +2 -1
- package/dist/scripts/analyze-git.js.map +1 -1
- package/dist/scripts/analyze-orders.js +2 -2
- package/dist/scripts/analyze-orders.js.map +1 -1
- package/docs/DEXBOT_COMPARISON.md +3 -3
- package/docs/EVOLUTION.md +27 -96
- package/docs/FUND_MOVEMENT_AND_ACCOUNTING.md +1 -1
- package/docs/LIFECYCLE.md +207 -0
- package/docs/README.md +9 -1
- package/docs/developer_guide.md +4 -3
- package/package.json +3 -3
- package/scripts/lib/dexbot-paths.sh +20 -11
- package/scripts/repo-stats.html +0 -480
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.4.20] - 2026-08-23 - Grid Boundary Hardening, Recovery Poison Gate, Analysis Path Centralization
|
|
6
|
+
|
|
7
|
+
### 2026-08-22
|
|
8
|
+
|
|
9
|
+
- **Fix(grid)**: harden boundary promotion against gap-floor violations — the spread-correction promotion path could consume every gap slot in a single call (`maxPromotable` computed the opposite rail's span and constrained nothing; `resolveGapBand` re-derived `sellStartIdx` unconditionally from the mutable committed boundary), so any one-time overrun became permanent geometry with no spread floor. Promotion is now capped at band size − MIN_SPREAD_ORDERS (disabled entirely when band ≤ reserve) and the walk hard-stops reserve slots short of the opposite rail edge independent of quota; upstream depth caps (BUY P_s−G−1−B, SELL B−P_b) prevent the slide from stranding placed opposite-rail orders; new `validateBoundaryCommit()` gates commit-time proposals in `_commitWorkingGrid` (rejected proposals keep the last valid boundary); defense-in-depth detectors add pre-broadcast crossed-book refusal (`detectCrossedBookPlan`) and post-commit gap-band intrusion detection → structural resync; new shared `resolveGapSlots()` dedups the `_gapSlots ?? calculateGapSlots(config)` pattern (`modules/order/grid.ts`, `modules/order/utils/math.ts`, `modules/order/manager.ts`, `modules/dexbot_cow_runtime.ts`, `tests/test_spread_boundary_promotion.ts`, `tests/test_spread_check_orchestration.ts`).
|
|
10
|
+
- **Fix(recovery)**: gate persisted boundary restore against overrun poison — a boundary committed and persisted by the pre-fix promotion overrun would legalize itself on every restart: `resolveGapBand` re-derives `sellStartIdx` from whatever value is restored and no runtime gate ran before restore, so structural resync "recovered" straight back into corrupted geometry. New `validatePersistedBoundary()` (stricter than commit-time validation — also rejects in-band placed orders, the poison signature only position-based geometry detects) is applied in `loadGrid` before `_restoreBoundary`; on rejection the structural center is re-derived from slot prices via `calculateIdealBoundary` (unmappable anchors degrade to a boundary-less load the next sync reconciles), and `recoverFromPersistedGrid` refuses poisoned snapshots BEFORE `loadGrid` so resync falls through to a clean `requestGridReset(refreshCenterPrice)` rebuild using config-derived `calculateGapSlots` (`modules/order/utils/math.ts`, `modules/order/grid.ts`, `modules/dexbot_state_recovery.ts`, new `tests/test_boundary_restore_validation.ts`, `tests/test_uncertain_broadcast.ts` fixtures updated).
|
|
11
|
+
- **Feat(analysis)**: centralize dynamic weight chart slider ranges, kalS% default 1.0 — the interactive research chart hardcoded its 16 knob ranges independently in four places each (HTML range attrs, tooltip text, server-side clamps, paste-clamp code), and the amaS% paste clamp had already drifted from its slider span. New `SLIDER_RANGES` constant is the single source of truth feeding HTML attrs, tooltips, payload transport, and every paste/init/latch clamp; kalS% range 0.15–1.5 → 0.5–1.5 with `DYNAMIC_WEIGHT_KALMAN_MAX_SLOPE_PCT` raised 0.8 → 1.0; fixes a TDZ crash (`const SR` declared after first use threw ReferenceError on chart load, leaving all panels blank) (`analysis/trend_detection/dynamic_weight_chart_generator.ts`, `analysis/trend_detection/DYNAMIC_WEIGHT_RESEARCH.md`, `modules/constants.ts`).
|
|
12
|
+
- **Fix(paths)**: centralize analysis output dirs and npm-install path resolution — research/chart tooling wrote generated artifacts into the package tree via `__dirname`/`import.meta.url`/cwd-relative defaults (wiped by `npm update -g`, blocked on read-only prefixes). New `PATHS.ANALYSIS.{DIR,CHARTS_DIR,RESULTS_DIR,ASSETS_DIR}` resolver keeps repo-local outputs only for repo-layout source checkouts and follows the resolved profiles dir otherwise, with a `DEXBOT_ANALYSIS_DIR` env override and `XDG_CONFIG_HOME` support; all chart generators and optimizer/backtest result writers rerouted (auto-discovery scans RESULTS_DIR first with legacy-dir fallback); `writeChartFile` materializes vendored uPlot assets next to relocated charts so relative refs keep resolving; claw profile/skill-doc resolution aligned with `modules/paths.ts` ordering; shell shim npm-package detection switched to exact-parent basename matching; generated charts/repo-stats excluded from the shipped tarball (`modules/paths.ts`, `modules/config.ts`, `analysis/*`, `scripts/lib/dexbot-paths.sh`, `claw/modules/*`, `package.json`).
|
|
13
|
+
|
|
14
|
+
### 2026-08-23
|
|
15
|
+
|
|
16
|
+
- **Fix(market-adapter)**: align dynamic weight clip logic between live service and research chart — the chart dropped zero-slope bars from the AMA clip pool, kept Kalman warmup bars that the live service sliced away, and fed different precision (rounded vs raw) into the velocity smoothing pipeline, so parameter research could mispredict live clipping behavior. The live service now feeds the smoothing pipeline unrounded velocity/displacement percentages and computes the Kalman clip percentile over the full series (no warmup slice); the chart keeps every finite slope including zeros via `Number.isFinite` and builds the payload-level initial smoothed series from raw fields to match the interactive recompute path; CLIP_PCT_MAX knob bound lowered 55 → 20. Note: at clip=10% totals shift ~−0.12% since warmup bars now count toward the percentile pool (`market_adapter/core/market_adapter_service.ts`, `analysis/trend_detection/dynamic_weight_chart_generator.ts`, `tests/test_market_adapter_service.ts`).
|
|
17
|
+
|
|
18
|
+
## [1.4.19] - 2026-08-21 - COW Broadcast Op Cap, Grid Divergence Rail Fix, UI Price Feedback
|
|
19
|
+
|
|
20
|
+
### 2026-08-21
|
|
21
|
+
|
|
22
|
+
- **Feat(cow)**: enforce a per-broadcast operation cap — a single COW rebalance can expand one fill batch into many more order operations (4 fills → 12 creates + 4 updates = 16 ops), so `FILL_PROCESSING.MAX_FILL_BATCH_SIZE` is a weak proxy for on-chain transaction size. `COW_PERFORMANCE.MAX_OPS_PER_BROADCAST` (default 4) now caps operations per broadcast; oversized batches are split into sequential transactions via `executeChunkedWithRetryOnUncertain`, restoring the original "N fills per broadcast" intent at the op level. An uncertain chunk failure continues broadcasting the remaining chunks (no order dropped); a definitively rejected chunk aborts the rest; the first failure is rethrown enriched with `partialOnChainState`, `chunksTotal`/`chunksFailed`/`chunksAborted`, and `broadcastedOperationCount`. Configurable via the runtime settings override chain (`runtimeCowPerformance`/`marketCowPerformance`/`botCowPerformance`). Covered by the new 463-line `test_cow_ops_per_broadcast.ts` (`modules/dexbot_cow_runtime.ts`, `modules/constants.ts`, `modules/dexbot_class.ts`, `modules/runtime_settings.ts`).
|
|
23
|
+
- **Fix(grid)**: exclude gap-band strays from divergence desired-window selection — a fund-driven boundary shift during `applyGridDivergenceCorrections` re-types the working grid, but the SPREAD GUARD keeps live on-chain orders inside the new spread band typed BUY/SELL, so the Phase-2 window selected "closest to market" slots purely by stored type+price and a stray SELL inside the new gap looked like the bottom of the sell rail and was never relocated, collapsing the real spread (boundary 107→110 left sells at 111–113 inside the new gap, real spread 0.5% vs the 2.0% target). New shared `MathUtils.isSlotInRail` (pure geometric rail-membership test) now filters desired-window candidates using the working boundary; the strategy window and virtual-slot selection delegate to the same helper, and gap-band strays become surplus → cancelled and relocated back onto the rail (`modules/order/utils/math.ts`, `modules/order/utils/system.ts`, `modules/order/strategy.ts`, `modules/order/grid_reconcile_internal.ts`, `tests/test_is_slot_in_rail.ts`, `tests/test_cow_divergence_correction.ts`, `tests/test_lp_chart.ts`).
|
|
24
|
+
- **Tune**: lower the AMA slope grid-reset threshold from 10 to 8 — the AMA slope delta trigger resets the grid when the slope swing exceeds (`AMA_SLOPE_DELTA_THRESHOLD_PERCENT`/100) × maxSlopePct. At 10 the XRP-BTS trend reversal (DOWN baseline → UP current, delta 0.0074%/bar) stayed below the 0.0085 threshold, leaving the grid scaled for the wrong direction. Lowering to 8 (threshold 0.0068%/bar) reacts to the reversal while still ignoring small slope noise (`modules/constants.ts`).
|
|
25
|
+
- **Feat(ui)**: green/red relative-scaling feedback for price inputs — the bot editor's Price Range displayed min/max as plain white, hiding whether relative scaling (x multipliers) is active. Range values now render green for "1.55x" multipliers and red for fixed prices, and `readInput` gains a colorize option so the typed input switches red → green live the moment the "x" is entered (`modules/account_bots.ts`, `modules/order/utils/system.ts`).
|
|
26
|
+
- **Fix(ui)**: clarify the GridPrice label in the bot editor — the Price section displayed the gridPrice reference as bare "Grid:", which was ambiguous next to "Start:"/"Pool:" and collided with the section "4) Grid". Renamed to "GridPrice:" (one word, matching the `gridPrice` config field name) to reflect the values it accepts (pool/book/ama/number/none) (`modules/account_bots.ts`).
|
|
27
|
+
- **Docs**: add an end-to-end lifecycle walkthrough — new `docs/LIFECYCLE.md` consolidates the startup, fill-driven (reactive), and maintenance/AMA-driven (periodic) flows into one newcomer-facing map with mermaid system-context and sequence diagrams (fill → `_incomingFillQueue` → `processFilledOrders` → Accounting SSOT → WorkingGrid COW → single atomic broadcast → persist; `_performPeriodicGridChecks` → `performPeriodicGridChecks` → `runGridMaintenance` → `executeMaintenanceLogic`), plus a cross-cutting invariants table and file map. Surfaced as the first read from README and the docs index, and added to the npm `files` array (`docs/LIFECYCLE.md`, `docs/developer_guide.md`, `docs/README.md`, `README.md`, `package.json`).
|
|
28
|
+
|
|
5
29
|
## [1.4.18] - 2026-08-19 - Compile-First Runtime Migration (tsx to dist)
|
|
6
30
|
|
|
7
31
|
### 2026-08-19
|
package/README.md
CHANGED
|
@@ -293,6 +293,7 @@ Logs are written to `logs/` in the profiles directory in all modes: the monolith
|
|
|
293
293
|
- **[Docs Index](docs/README.md)** - Main documentation hub
|
|
294
294
|
- **[Claw API Boundary](claw/docs/AI_BOT_LIBRARY_API.md)** - Responsibility split between the AI layer and the DEXBot2 execution layer
|
|
295
295
|
- **[Architecture](docs/architecture.md)** - System design, fill processing pipeline, and testing strategy
|
|
296
|
+
- **[Lifecycle](docs/LIFECYCLE.md)** - End-to-end walkthrough: startup, fill-driven, and AMA-driven flows with diagrams
|
|
296
297
|
- **[Developer Guide](docs/developer_guide.md)** - Development guide, environment variables, examples, and glossary
|
|
297
298
|
- **[Copy-on-Write Plan](docs/COPY_ON_WRITE_MASTER_PLAN.md)** - Copy-on-Write grid architecture
|
|
298
299
|
- **[Fund Movement & Accounting](docs/FUND_MOVEMENT_AND_ACCOUNTING.md)** - Fund accounting, grid topology, and rotation mechanics
|
|
@@ -186,8 +186,8 @@ function generateChartHtml(results: any, metricCache: any, fixEr: any, fixFast:
|
|
|
186
186
|
const cacheSlow = metricCache.map((m: any) => m.slow);
|
|
187
187
|
const cacheMove = metricCache.map((m: any) => m.movement);
|
|
188
188
|
|
|
189
|
-
const uplotCode = fs.readFileSync(path.
|
|
190
|
-
const uplotCSS = fs.readFileSync(path.
|
|
189
|
+
const uplotCode = fs.readFileSync(path.join(PATHS.ANALYSIS.ASSETS_DIR, 'uPlot.iife.min.js'), 'utf8');
|
|
190
|
+
const uplotCSS = fs.readFileSync(path.join(PATHS.ANALYSIS.ASSETS_DIR, 'uPlot.min.css'), 'utf8');
|
|
191
191
|
|
|
192
192
|
const amaAnnotations = [
|
|
193
193
|
{ label: 'AMA1', lambda: 0.0031, slow: 62.1, color: '#ef5350' },
|
|
@@ -719,7 +719,8 @@ async function run() {
|
|
|
719
719
|
const outName = dataFile
|
|
720
720
|
? `optimization_results_${path.basename(dataFile, '.json')}${lambdaSuffix}.json`
|
|
721
721
|
: `optimization_results_high_resolution${lambdaSuffix}.json`;
|
|
722
|
-
const outPath = path.join(
|
|
722
|
+
const outPath = path.join(PATHS.ANALYSIS.RESULTS_DIR, outName);
|
|
723
|
+
ensureDir(path.dirname(outPath));
|
|
723
724
|
writeJSON(outPath, {
|
|
724
725
|
meta: {
|
|
725
726
|
dataLabel,
|
|
@@ -20,10 +20,12 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
|
|
23
|
+
import path from 'node:path';
|
|
23
24
|
import { pathToFileURL } from 'node:url';
|
|
24
25
|
import { DerivativeAnalyzer } from './trend_detection/derivative_analyzer.js';
|
|
25
26
|
import { generateHTML } from './derivative_chart_generator.js';
|
|
26
27
|
import { writeChartFile } from './chart_utils.js';
|
|
28
|
+
import { PATHS } from '../modules/paths.js';
|
|
27
29
|
import { resolveSource, listAvailableBots, type SourceConfig } from './resolve_source.js';
|
|
28
30
|
'use strict';
|
|
29
31
|
|
|
@@ -85,7 +87,7 @@ function parseArgs(): CliConfig {
|
|
|
85
87
|
interpHoldBars: 3,
|
|
86
88
|
rsiZone: 10,
|
|
87
89
|
rsiExtreme: 90,
|
|
88
|
-
chartFile: '
|
|
90
|
+
chartFile: path.join(PATHS.ANALYSIS.CHARTS_DIR, 'derivative_chart.html'),
|
|
89
91
|
quiet: false,
|
|
90
92
|
listBots: false,
|
|
91
93
|
};
|
|
@@ -173,7 +175,7 @@ Analyzer options:
|
|
|
173
175
|
--file PATH JSON candle input
|
|
174
176
|
|
|
175
177
|
Output:
|
|
176
|
-
--chart FILE Chart output path (default: analysis
|
|
178
|
+
--chart FILE Chart output path (default: <analysis charts dir>/derivative_chart.html)
|
|
177
179
|
--list-bots List available bot keys from bots.json
|
|
178
180
|
--quiet Suppress log output
|
|
179
181
|
`);
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* --file market_adapter/data/lp/<path>/<to>/<lp-candles>.json
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
+
import path from 'node:path';
|
|
15
16
|
import { KalmanTrendAnalyzer } from './trend_detection/kalman_trend_analyzer.js';
|
|
16
17
|
import { HurstAnalyzer } from './trend_detection/hurst_analyzer.js';
|
|
17
18
|
import { PermutationEntropyAnalyzer } from './trend_detection/permutation_entropy_analyzer.js';
|
|
@@ -19,6 +20,7 @@ import { generateHTML } from './trend_detection/dynamic_weight_chart_generator.j
|
|
|
19
20
|
import { calculateAMA } from '../market_adapter/core/strategies/ama.js';
|
|
20
21
|
import { computeAmaSlopeWeights } from '../market_adapter/core/strategies/ama_slope_model.js';
|
|
21
22
|
import { MARKET_ADAPTER } from '../modules/constants.js';
|
|
23
|
+
import { PATHS } from '../modules/paths.js';
|
|
22
24
|
import { writeChartFile } from './chart_utils.js';
|
|
23
25
|
import { getCandleClose } from './math_utils.js';
|
|
24
26
|
import { resolveSource, listAvailableBots, type SourceConfig } from './resolve_source.js';
|
|
@@ -64,7 +66,7 @@ function parseArgs() {
|
|
|
64
66
|
dispScaleMinPct?: number;
|
|
65
67
|
} = {
|
|
66
68
|
source: { type: 'market_adapter', config: { botKey: '' } },
|
|
67
|
-
chartFile: '
|
|
69
|
+
chartFile: path.join(PATHS.ANALYSIS.CHARTS_DIR, 'dynamic_weight_chart.html'),
|
|
68
70
|
alpha: MARKET_ADAPTER.DYNAMIC_WEIGHT_ALPHA,
|
|
69
71
|
gain: MARKET_ADAPTER.DYNAMIC_WEIGHT_GAIN,
|
|
70
72
|
dispWeight: MARKET_ADAPTER.DYNAMIC_WEIGHT_DW,
|
|
@@ -11,12 +11,14 @@
|
|
|
11
11
|
* --file market_adapter/data/lp/<path>/<to>/<lp-candles>.json
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
+
import path from 'node:path';
|
|
14
15
|
import { KalmanTrendAnalyzer } from './trend_detection/kalman_trend_analyzer.js';
|
|
15
16
|
import { generateHTML } from './trend_detection/kalman_chart_generator.js';
|
|
16
17
|
import { calculateAMA } from '../market_adapter/core/strategies/ama.js';
|
|
17
18
|
import { computeAverageAmaSlopePct } from '../market_adapter/core/strategies/dynamic_weight_series.js';
|
|
18
19
|
import { getCandleClose } from './math_utils.js';
|
|
19
20
|
import { writeChartFile } from './chart_utils.js';
|
|
21
|
+
import { PATHS } from '../modules/paths.js';
|
|
20
22
|
import { resolveSource, listAvailableBots, type SourceConfig } from './resolve_source.js';
|
|
21
23
|
|
|
22
24
|
'use strict';
|
|
@@ -39,7 +41,7 @@ function parseArgs() {
|
|
|
39
41
|
source: { type: 'market_adapter', config: { botKey: '' } },
|
|
40
42
|
rNoise: 0.05,
|
|
41
43
|
qNoise: 0.005,
|
|
42
|
-
chartFile: '
|
|
44
|
+
chartFile: path.join(PATHS.ANALYSIS.CHARTS_DIR, 'kalman_chart.html'),
|
|
43
45
|
quiet: false,
|
|
44
46
|
listBots: false,
|
|
45
47
|
};
|
|
@@ -18,7 +18,9 @@
|
|
|
18
18
|
* --file market_adapter/data/lp/<path>/<to>/<lp-candles>.json
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
+
import path from 'node:path';
|
|
21
22
|
import { MARKET_ADAPTER } from '../modules/constants.js';
|
|
23
|
+
import { PATHS } from '../modules/paths.js';
|
|
22
24
|
import { HurstAnalyzer } from './trend_detection/hurst_analyzer.js';
|
|
23
25
|
import { PermutationEntropyAnalyzer } from './trend_detection/permutation_entropy_analyzer.js';
|
|
24
26
|
import { generateRegimeHTML } from './trend_detection/regime_chart_generator.js';
|
|
@@ -44,7 +46,7 @@ function parseArgs() {
|
|
|
44
46
|
listBots: boolean;
|
|
45
47
|
} = {
|
|
46
48
|
source: { type: 'market_adapter', config: { botKey: '' } },
|
|
47
|
-
chartFile: '
|
|
49
|
+
chartFile: path.join(PATHS.ANALYSIS.CHARTS_DIR, 'regime_chart.html'),
|
|
48
50
|
hurstWindow: HURST_CONFIG.window,
|
|
49
51
|
peWindow: PE_CONFIG.window,
|
|
50
52
|
peM: PE_CONFIG.m,
|
|
@@ -17,9 +17,11 @@
|
|
|
17
17
|
* --file market_adapter/data/lp/<path>/<to>/<lp-candles>.json
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
+
import path from 'node:path';
|
|
20
21
|
import { HurstAnalyzer } from './trend_detection/hurst_analyzer.js';
|
|
21
22
|
import { PermutationEntropyAnalyzer } from './trend_detection/permutation_entropy_analyzer.js';
|
|
22
23
|
import { MARKET_ADAPTER } from '../modules/constants.js';
|
|
24
|
+
import { PATHS } from '../modules/paths.js';
|
|
23
25
|
import { writeChartFile } from './chart_utils.js';
|
|
24
26
|
import { getCandleClose } from './math_utils.js';
|
|
25
27
|
import { roundTo } from '../modules/order/utils/math.js';
|
|
@@ -59,7 +61,7 @@ function parseArgs() {
|
|
|
59
61
|
listBots: boolean;
|
|
60
62
|
} = {
|
|
61
63
|
source: { type: 'market_adapter', config: { botKey: '' } },
|
|
62
|
-
chartFile: '
|
|
64
|
+
chartFile: path.join(PATHS.ANALYSIS.CHARTS_DIR, 'regime_windows_heatmap.html'),
|
|
63
65
|
quiet: false,
|
|
64
66
|
listBots: false,
|
|
65
67
|
};
|
|
@@ -21,7 +21,6 @@
|
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
import path from 'node:path';
|
|
24
|
-
import { fileURLToPath } from 'node:url';
|
|
25
24
|
|
|
26
25
|
import { calculateAMA } from '../market_adapter/core/strategies/ama.js';
|
|
27
26
|
import { computeATRSeries } from '../market_adapter/core/strategies/atr/calculator.js';
|
|
@@ -29,6 +28,7 @@ import { normalizeAtrPeriod } from '../market_adapter/core/config_normalizers.js
|
|
|
29
28
|
import { computeVolatilityShift } from '../market_adapter/core/strategies/volatility_shift.js';
|
|
30
29
|
import { generateHTML } from './trend_detection/volatility_chart_generator.js';
|
|
31
30
|
import { MARKET_ADAPTER } from '../modules/constants.js';
|
|
31
|
+
import { PATHS } from '../modules/paths.js';
|
|
32
32
|
import { getCandleClose } from './math_utils.js';
|
|
33
33
|
import { writeChartFile } from './chart_utils.js';
|
|
34
34
|
import { resolveSource, listAvailableBots, type SourceConfig } from './resolve_source.js';
|
|
@@ -40,7 +40,7 @@ const MIN_WEIGHT = MARKET_ADAPTER.DYNAMIC_WEIGHT_MIN_WEIGHT;
|
|
|
40
40
|
const MAX_WEIGHT = MARKET_ADAPTER.DYNAMIC_WEIGHT_MAX_WEIGHT;
|
|
41
41
|
const DEFAULT_THRESHOLD = MARKET_ADAPTER.DYNAMIC_WEIGHT_SYMMETRIC_SHIFT_THRESHOLD;
|
|
42
42
|
const DEFAULT_CLAMP = MARKET_ADAPTER.DYNAMIC_WEIGHT_SYMMETRIC_SHIFT_CLAMP;
|
|
43
|
-
const DEFAULT_CHART_DIR =
|
|
43
|
+
const DEFAULT_CHART_DIR = PATHS.ANALYSIS.CHARTS_DIR;
|
|
44
44
|
const DEFAULT_CHART_FILE = path.join(DEFAULT_CHART_DIR, 'volatility_chart.html');
|
|
45
45
|
|
|
46
46
|
function computeATRSeriesNormalized(candles: any[], period = DEFAULT_ATR_PERIOD) {
|
|
@@ -7,6 +7,7 @@ import { calculateAMA } from '../../market_adapter/core/strategies/ama.js';
|
|
|
7
7
|
import { range } from '../math_utils.js';
|
|
8
8
|
import { parseListOrRange, loadLpData, fmt } from './shared_utils.js';
|
|
9
9
|
import { getStorage } from '../../modules/storage/index.js';
|
|
10
|
+
import { PATHS } from '../../modules/paths.js';
|
|
10
11
|
const { readJSON, writeJSON } = getStorage();
|
|
11
12
|
'use strict';
|
|
12
13
|
|
|
@@ -759,7 +760,7 @@ async function run() {
|
|
|
759
760
|
|
|
760
761
|
// ── Save JSON ───────────────────────────────────────────────────────────
|
|
761
762
|
const outName = `ama_sweep_results_${path.basename(cfg.dataPath!, '.json')}.json`;
|
|
762
|
-
const outPath = path.join(
|
|
763
|
+
const outPath = path.join(PATHS.ANALYSIS.RESULTS_DIR, outName);
|
|
763
764
|
writeJSON(outPath, {
|
|
764
765
|
meta: {
|
|
765
766
|
generatedAt: new Date().toISOString(),
|
|
@@ -4,6 +4,7 @@ import { calculateAMA } from '../../market_adapter/core/strategies/ama.js';
|
|
|
4
4
|
import { range } from '../math_utils.js';
|
|
5
5
|
import { parseListOrRange, loadLpData, fmt } from './shared_utils.js';
|
|
6
6
|
import { getStorage } from '../../modules/storage/index.js';
|
|
7
|
+
import { PATHS } from '../../modules/paths.js';
|
|
7
8
|
const { ensureDir, readJSON, writeJSON } = getStorage();
|
|
8
9
|
|
|
9
10
|
'use strict';
|
|
@@ -125,28 +126,32 @@ function parseArgs() {
|
|
|
125
126
|
* The optimizer names results `optimization_results_<base>_w<λ1>_<λ2>_<λ3>_<λ4>.json`
|
|
126
127
|
* (per-AMA distance weights appended as a `_w...` suffix). To stay robust against
|
|
127
128
|
* weight overrides, pick the most recently written `optimization_results_<base>_w*.json`
|
|
128
|
-
* in
|
|
129
|
-
* if no suffixed file exists.
|
|
129
|
+
* in the analysis results dir (legacy ama_fitting location still scanned); fall
|
|
130
|
+
* back to the legacy `optimization_results_<base>.json` name if no suffixed file exists.
|
|
130
131
|
*/
|
|
131
132
|
function resolveAutoResultsPath(dataPath: string): string {
|
|
132
133
|
const base = path.basename(dataPath, '.json');
|
|
133
|
-
|
|
134
|
+
// Canonical results dir first, then the legacy ama_fitting location so
|
|
135
|
+
// previously generated files are still discovered.
|
|
136
|
+
const dirs = [PATHS.ANALYSIS.RESULTS_DIR, path.join(PATHS.PROJECT_ROOT, 'analysis', 'ama_fitting')];
|
|
134
137
|
const prefix = `optimization_results_${base}_w`;
|
|
135
138
|
let newest: { file: string; mtimeMs: number } | null = null;
|
|
136
139
|
try {
|
|
137
|
-
for (const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
newest
|
|
140
|
+
for (const dir of dirs) {
|
|
141
|
+
for (const entry of fs.readdirSync(dir)) {
|
|
142
|
+
if (!entry.startsWith(prefix) || !entry.endsWith('.json')) continue;
|
|
143
|
+
const full = path.join(dir, entry);
|
|
144
|
+
const stat = fs.statSync(full);
|
|
145
|
+
if (!newest || stat.mtimeMs > newest.mtimeMs) {
|
|
146
|
+
newest = { file: full, mtimeMs: stat.mtimeMs };
|
|
147
|
+
}
|
|
143
148
|
}
|
|
144
149
|
}
|
|
145
150
|
} catch {
|
|
146
151
|
// dir unreadable — fall through to legacy name check
|
|
147
152
|
}
|
|
148
153
|
if (newest) return newest.file;
|
|
149
|
-
return path.join(
|
|
154
|
+
return path.join(PATHS.ANALYSIS.RESULTS_DIR, `optimization_results_${base}.json`);
|
|
150
155
|
}
|
|
151
156
|
|
|
152
157
|
function loadAmaStrategies(resultsPath: string) {
|
|
@@ -388,8 +393,8 @@ function run() {
|
|
|
388
393
|
console.log();
|
|
389
394
|
|
|
390
395
|
const outName = `bot_fitting_results_${path.basename(cfg.dataPath!, '.json')}.json`;
|
|
391
|
-
const outPath = path.join(
|
|
392
|
-
ensureDir(
|
|
396
|
+
const outPath = path.join(PATHS.ANALYSIS.RESULTS_DIR, outName);
|
|
397
|
+
ensureDir(PATHS.ANALYSIS.RESULTS_DIR);
|
|
393
398
|
writeJSON(outPath, {
|
|
394
399
|
meta: {
|
|
395
400
|
generatedAt: new Date().toISOString(),
|
package/analysis/chart_utils.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { getStorage } from '../modules/storage/index.js';
|
|
5
|
+
import { PATHS } from '../modules/paths.js';
|
|
5
6
|
const { ensureDir } = getStorage();
|
|
6
7
|
'use strict';
|
|
7
8
|
|
|
@@ -9,6 +10,28 @@ const { ensureDir } = getStorage();
|
|
|
9
10
|
* Chart utilities for analysis HTML generators.
|
|
10
11
|
*/
|
|
11
12
|
|
|
13
|
+
// Runtime assets every generated chart references as ../uplot/* relative to
|
|
14
|
+
// its own directory (charts live in <root>/charts, assets in <root>/uplot).
|
|
15
|
+
const UPLOT_RUNTIME_FILES = ['uPlot.iife.min.js', 'uPlot.min.css'];
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Generated HTML loads uPlot from a sibling `uplot/` dir next to the charts
|
|
19
|
+
* dir. In a source checkout that dir is the vendored original; anywhere else
|
|
20
|
+
* (relocated analysis root under npm/home profiles, or a custom --chart path)
|
|
21
|
+
* materialize a copy so the relative refs keep resolving.
|
|
22
|
+
*/
|
|
23
|
+
function ensureSiblingUplotAssets(chartDir: any) {
|
|
24
|
+
const targetDir = path.join(path.dirname(path.resolve(chartDir)), 'uplot');
|
|
25
|
+
const sourceDir = PATHS.ANALYSIS.ASSETS_DIR;
|
|
26
|
+
if (targetDir === path.resolve(sourceDir)) return;
|
|
27
|
+
if (UPLOT_RUNTIME_FILES.every((f) => fs.existsSync(path.join(targetDir, f)))) return;
|
|
28
|
+
if (!fs.existsSync(sourceDir)) return;
|
|
29
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
30
|
+
for (const f of UPLOT_RUNTIME_FILES) {
|
|
31
|
+
fs.copyFileSync(path.join(sourceDir, f), path.join(targetDir, f));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
12
35
|
|
|
13
36
|
function escapeHtml(str: string) {
|
|
14
37
|
const map: Record<string, string> = {
|
|
@@ -34,6 +57,7 @@ function toEpochSeconds(ts: any, fallbackIdx: any) {
|
|
|
34
57
|
function writeChartFile(filePath: any, html: any) {
|
|
35
58
|
const chartDir = path.dirname(filePath);
|
|
36
59
|
if (!fs.existsSync(chartDir)) ensureDir(chartDir);
|
|
60
|
+
ensureSiblingUplotAssets(chartDir);
|
|
37
61
|
fs.writeFileSync(filePath, html, 'utf8');
|
|
38
62
|
}
|
|
39
63
|
|
|
@@ -8,11 +8,12 @@ import { getStorage } from '../modules/storage/index.js';
|
|
|
8
8
|
const { ensureDir, readJSON } = getStorage();
|
|
9
9
|
import { fixedTo } from '../modules/order/utils/math.js';
|
|
10
10
|
import { bindHoverStateFn, zoomResetScript } from './chart_ui.js';
|
|
11
|
+
import { PATHS } from '../modules/paths.js';
|
|
11
12
|
'use strict';
|
|
12
13
|
function parseArgs(argv = process.argv.slice(2)) {
|
|
13
14
|
const cfg: { inputFile: string | null; outputFile: string; title: string; quiet: boolean } = {
|
|
14
15
|
inputFile: null,
|
|
15
|
-
outputFile: '
|
|
16
|
+
outputFile: path.join(PATHS.ANALYSIS.CHARTS_DIR, 'derivative_chart.html'),
|
|
16
17
|
title: 'Derivative Trend Analysis',
|
|
17
18
|
quiet: false,
|
|
18
19
|
};
|
|
@@ -40,7 +41,7 @@ Derivative Chart Generator (uPlot)
|
|
|
40
41
|
Usage:
|
|
41
42
|
tsx analysis/derivative_chart_generator.ts --input <file.json> [options]
|
|
42
43
|
Options:
|
|
43
|
-
--output FILE Output HTML (default: analysis
|
|
44
|
+
--output FILE Output HTML (default: <analysis charts dir>/derivative_chart.html)
|
|
44
45
|
--title TEXT Chart title
|
|
45
46
|
--quiet Suppress output
|
|
46
47
|
`);
|
|
@@ -160,7 +160,7 @@ All panels share aligned vertical time grid lines, and the bottom output panel s
|
|
|
160
160
|
| **nz%** | 0–1 | 0.00 | Neutral zone: dead-band below which offset is forced to 0 |
|
|
161
161
|
| **lb** | 1–32 | 9 | Logarithmic. Lookback bars for AMA slope calculation |
|
|
162
162
|
| **amaS%** | 0.04–0.12 | 0.085 | Logarithmic. Gear ratio for average per-bar AMA slope saturation |
|
|
163
|
-
| **kalS%** | 0.
|
|
163
|
+
| **kalS%** | 0.5–1.5 | 1.0 | Logarithmic. Gear ratio for Kalman composite saturation |
|
|
164
164
|
| **clip%** | 0–55 | 10 | Percentile clip: filters extreme inputs (0 = off) |
|
|
165
165
|
|
|
166
166
|
### Output Controls
|