dexbot 1.4.19 → 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 +13 -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/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.js +1 -1
- package/dist/modules/dexbot_cow_runtime.d.ts +0 -7
- package/dist/modules/dexbot_cow_runtime.d.ts.map +1 -1
- package/dist/modules/dexbot_cow_runtime.js +95 -0
- 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/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/utils/math.d.ts +74 -1
- package/dist/modules/order/utils/math.d.ts.map +1 -1
- package/dist/modules/order/utils/math.js +120 -2
- package/dist/modules/order/utils/math.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/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 +8 -7
- package/docs/FUND_MOVEMENT_AND_ACCOUNTING.md +1 -1
- package/docs/README.md +1 -1
- package/package.json +2 -3
- package/scripts/lib/dexbot-paths.sh +20 -11
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
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
|
+
|
|
5
18
|
## [1.4.19] - 2026-08-21 - COW Broadcast Op Cap, Grid Divergence Rail Fix, UI Price Feedback
|
|
6
19
|
|
|
7
20
|
### 2026-08-21
|
|
@@ -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
|