dexbot 1.6.3 → 1.6.5
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 +78 -2
- package/README.md +23 -19
- package/analysis/README.md +26 -13
- package/analysis/account_resolver.ts +171 -0
- package/analysis/ama_fitting/analyze_lambda_vs_slow.ts +2 -5
- package/analysis/ama_fitting/package.json +1 -1
- package/analysis/analyze_dynamic_weight.ts +9 -3
- package/analysis/bot_usage/discover_bot_accounts.ts +20 -27
- package/analysis/chain_pool.ts +47 -0
- package/analysis/chart_utils.ts +33 -20
- package/analysis/derivative_chart_generator.ts +2 -3
- package/analysis/fills_source.ts +234 -0
- package/analysis/grid_correction_check.ts +38 -251
- package/analysis/trade_profitability.ts +169 -304
- package/analysis/tradingview/README.md +2 -2
- package/analysis/tradingview/analyze_tradingview.ts +5 -0
- package/analysis/tradingview/tradingview_uplot_chart_generator.ts +5 -6
- package/analysis/trend_detection/DYNAMIC_WEIGHT_RESEARCH.md +35 -2
- package/analysis/trend_detection/dynamic_weight_chart_generator.ts +84 -13
- package/analysis/trend_detection/kalman_chart_generator.ts +2 -3
- package/analysis/trend_detection/package.json +1 -1
- package/analysis/trend_detection/regime_chart_generator.ts +2 -3
- package/analysis/trend_detection/volatility_chart_generator.ts +2 -3
- 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/claw/tests/test_dexbot_profiles.ts +18 -1
- package/dist/analysis/account_resolver.d.ts +43 -0
- package/dist/analysis/account_resolver.d.ts.map +1 -0
- package/dist/analysis/account_resolver.js +137 -0
- package/dist/analysis/account_resolver.js.map +1 -0
- package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.d.ts.map +1 -1
- package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.js +2 -4
- package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.js.map +1 -1
- package/dist/analysis/analyze_dynamic_weight.js +9 -3
- package/dist/analysis/analyze_dynamic_weight.js.map +1 -1
- package/dist/analysis/bot_usage/discover_bot_accounts.js +20 -28
- package/dist/analysis/bot_usage/discover_bot_accounts.js.map +1 -1
- package/dist/analysis/chain_pool.d.ts +10 -0
- package/dist/analysis/chain_pool.d.ts.map +1 -0
- package/dist/analysis/chain_pool.js +47 -0
- package/dist/analysis/chain_pool.js.map +1 -0
- package/dist/analysis/chart_utils.d.ts +14 -1
- package/dist/analysis/chart_utils.d.ts.map +1 -1
- package/dist/analysis/chart_utils.js +32 -22
- 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 +2 -3
- package/dist/analysis/derivative_chart_generator.js.map +1 -1
- package/dist/analysis/fills_source.d.ts +79 -0
- package/dist/analysis/fills_source.d.ts.map +1 -0
- package/dist/analysis/fills_source.js +186 -0
- package/dist/analysis/fills_source.js.map +1 -0
- package/dist/analysis/grid_correction_check.d.ts +1 -21
- package/dist/analysis/grid_correction_check.d.ts.map +1 -1
- package/dist/analysis/grid_correction_check.js +30 -257
- package/dist/analysis/grid_correction_check.js.map +1 -1
- package/dist/analysis/trade_profitability.d.ts +18 -19
- package/dist/analysis/trade_profitability.d.ts.map +1 -1
- package/dist/analysis/trade_profitability.js +136 -280
- package/dist/analysis/trade_profitability.js.map +1 -1
- package/dist/analysis/tradingview/analyze_tradingview.d.ts.map +1 -1
- package/dist/analysis/tradingview/analyze_tradingview.js +5 -0
- package/dist/analysis/tradingview/analyze_tradingview.js.map +1 -1
- package/dist/analysis/tradingview/tradingview_uplot_chart_generator.d.ts.map +1 -1
- package/dist/analysis/tradingview/tradingview_uplot_chart_generator.js +5 -6
- package/dist/analysis/tradingview/tradingview_uplot_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 +84 -13
- package/dist/analysis/trend_detection/dynamic_weight_chart_generator.js.map +1 -1
- package/dist/analysis/trend_detection/kalman_chart_generator.d.ts.map +1 -1
- package/dist/analysis/trend_detection/kalman_chart_generator.js +2 -3
- package/dist/analysis/trend_detection/kalman_chart_generator.js.map +1 -1
- package/dist/analysis/trend_detection/regime_chart_generator.d.ts.map +1 -1
- package/dist/analysis/trend_detection/regime_chart_generator.js +2 -3
- package/dist/analysis/trend_detection/regime_chart_generator.js.map +1 -1
- package/dist/analysis/trend_detection/volatility_chart_generator.d.ts.map +1 -1
- package/dist/analysis/trend_detection/volatility_chart_generator.js +2 -3
- package/dist/analysis/trend_detection/volatility_chart_generator.js.map +1 -1
- package/dist/dexbot.d.ts.map +1 -1
- package/dist/dexbot.js +27 -68
- package/dist/dexbot.js.map +1 -1
- package/dist/market_adapter/core/asymmetric_bounds.d.ts +2 -2
- package/dist/market_adapter/core/asymmetric_bounds.d.ts.map +1 -1
- package/dist/market_adapter/core/asymmetric_bounds.js +15 -12
- package/dist/market_adapter/core/asymmetric_bounds.js.map +1 -1
- package/dist/market_adapter/interval_utils.d.ts +1 -1
- package/dist/market_adapter/interval_utils.js +1 -1
- package/dist/market_adapter/lp_chart_core.d.ts.map +1 -1
- package/dist/market_adapter/lp_chart_core.js +2 -3
- package/dist/market_adapter/lp_chart_core.js.map +1 -1
- package/dist/modules/account_bots.d.ts +51 -18
- package/dist/modules/account_bots.d.ts.map +1 -1
- package/dist/modules/account_bots.js +258 -117
- package/dist/modules/account_bots.js.map +1 -1
- package/dist/modules/bitshares-native/serial/operations.d.ts +1 -84
- package/dist/modules/bitshares-native/serial/operations.d.ts.map +1 -1
- package/dist/modules/bitshares-native/serial/operations.js +1 -38
- package/dist/modules/bitshares-native/serial/operations.js.map +1 -1
- package/dist/modules/bot_defaults.d.ts +98 -0
- package/dist/modules/bot_defaults.d.ts.map +1 -0
- package/dist/modules/bot_defaults.js +169 -0
- package/dist/modules/bot_defaults.js.map +1 -0
- package/dist/modules/bot_settings.d.ts.map +1 -1
- package/dist/modules/bot_settings.js +4 -1
- package/dist/modules/bot_settings.js.map +1 -1
- package/dist/modules/cli_colors.d.ts +0 -1
- package/dist/modules/cli_colors.d.ts.map +1 -1
- package/dist/modules/config.d.ts +1 -0
- package/dist/modules/config.d.ts.map +1 -1
- package/dist/modules/config.js +1 -0
- package/dist/modules/config.js.map +1 -1
- package/dist/modules/constants.d.ts +11 -2
- package/dist/modules/constants.d.ts.map +1 -1
- package/dist/modules/constants.js +45 -32
- package/dist/modules/constants.js.map +1 -1
- package/dist/modules/credential_policy.d.ts +1 -25
- package/dist/modules/credential_policy.d.ts.map +1 -1
- package/dist/modules/credential_policy.js +1 -1
- package/dist/modules/credential_policy.js.map +1 -1
- package/dist/modules/credential_runtime.d.ts +1 -6
- package/dist/modules/credential_runtime.d.ts.map +1 -1
- package/dist/modules/credential_runtime.js +1 -1
- package/dist/modules/credential_runtime.js.map +1 -1
- package/dist/modules/credential_session_cache.d.ts +1 -5
- package/dist/modules/credential_session_cache.d.ts.map +1 -1
- package/dist/modules/credential_session_cache.js +1 -1
- package/dist/modules/credential_session_cache.js.map +1 -1
- package/dist/modules/crypto/pure_secp256k1.d.ts +1 -2
- package/dist/modules/crypto/pure_secp256k1.d.ts.map +1 -1
- package/dist/modules/crypto/pure_secp256k1.js +1 -1
- package/dist/modules/crypto/pure_secp256k1.js.map +1 -1
- package/dist/modules/dexbot_class.d.ts +8 -7
- package/dist/modules/dexbot_class.d.ts.map +1 -1
- package/dist/modules/dexbot_class.js +9 -8
- package/dist/modules/dexbot_class.js.map +1 -1
- package/dist/modules/dexbot_cow_runtime.d.ts +7 -6
- package/dist/modules/dexbot_cow_runtime.d.ts.map +1 -1
- package/dist/modules/dexbot_cow_runtime.js +8 -7
- package/dist/modules/dexbot_cow_runtime.js.map +1 -1
- package/dist/modules/dexbot_fill_runtime.d.ts +1 -17
- package/dist/modules/dexbot_fill_runtime.d.ts.map +1 -1
- package/dist/modules/dexbot_fill_runtime.js +1 -1
- package/dist/modules/dexbot_fill_runtime.js.map +1 -1
- package/dist/modules/dexbot_maintenance_runtime.d.ts +2 -2
- package/dist/modules/dexbot_maintenance_runtime.d.ts.map +1 -1
- package/dist/modules/dexbot_maintenance_runtime.js +24 -8
- package/dist/modules/dexbot_maintenance_runtime.js.map +1 -1
- package/dist/modules/dexbot_state_recovery.d.ts +1 -7
- package/dist/modules/dexbot_state_recovery.d.ts.map +1 -1
- package/dist/modules/dexbot_state_recovery.js +1 -1
- package/dist/modules/dexbot_state_recovery.js.map +1 -1
- package/dist/modules/launcher/adapter_requirement.d.ts +1 -5
- package/dist/modules/launcher/adapter_requirement.d.ts.map +1 -1
- package/dist/modules/launcher/adapter_requirement.js +2 -2
- package/dist/modules/launcher/adapter_requirement.js.map +1 -1
- package/dist/modules/launcher/bot_supervisor.d.ts +1 -6
- package/dist/modules/launcher/bot_supervisor.d.ts.map +1 -1
- package/dist/modules/launcher/bot_supervisor.js +1 -1
- package/dist/modules/launcher/bot_supervisor.js.map +1 -1
- package/dist/modules/launcher/foreign_cred_daemon.d.ts +1 -3
- package/dist/modules/launcher/foreign_cred_daemon.d.ts.map +1 -1
- package/dist/modules/launcher/foreign_cred_daemon.js +1 -1
- package/dist/modules/launcher/foreign_cred_daemon.js.map +1 -1
- package/dist/modules/launcher/launch_modes.d.ts +17 -2
- package/dist/modules/launcher/launch_modes.d.ts.map +1 -1
- package/dist/modules/launcher/launch_modes.js +18 -1
- package/dist/modules/launcher/launch_modes.js.map +1 -1
- package/dist/modules/launcher/market_adapter_runtime.d.ts +1 -3
- package/dist/modules/launcher/market_adapter_runtime.d.ts.map +1 -1
- package/dist/modules/launcher/market_adapter_runtime.js +1 -1
- package/dist/modules/launcher/market_adapter_runtime.js.map +1 -1
- package/dist/modules/launcher/monolithic_runtime.d.ts +1 -5
- package/dist/modules/launcher/monolithic_runtime.d.ts.map +1 -1
- package/dist/modules/launcher/monolithic_runtime.js +9 -2
- package/dist/modules/launcher/monolithic_runtime.js.map +1 -1
- package/dist/modules/launcher/status_reporting.d.ts +1 -2
- package/dist/modules/launcher/status_reporting.d.ts.map +1 -1
- package/dist/modules/launcher/status_reporting.js +1 -1
- package/dist/modules/launcher/status_reporting.js.map +1 -1
- package/dist/modules/market_adapter_whitelist.d.ts +40 -1
- package/dist/modules/market_adapter_whitelist.d.ts.map +1 -1
- package/dist/modules/market_adapter_whitelist.js +161 -11
- package/dist/modules/market_adapter_whitelist.js.map +1 -1
- package/dist/modules/order/export.d.ts +1 -8
- package/dist/modules/order/export.d.ts.map +1 -1
- package/dist/modules/order/export.js +1 -1
- package/dist/modules/order/export.js.map +1 -1
- package/dist/modules/order/grid.d.ts +16 -0
- package/dist/modules/order/grid.d.ts.map +1 -1
- package/dist/modules/order/grid.js +75 -103
- package/dist/modules/order/grid.js.map +1 -1
- package/dist/modules/order/grid_reconcile_internal.d.ts +1 -10
- package/dist/modules/order/grid_reconcile_internal.d.ts.map +1 -1
- package/dist/modules/order/grid_reconcile_internal.js +2 -2
- package/dist/modules/order/grid_reconcile_internal.js.map +1 -1
- package/dist/modules/order/manager.d.ts +10 -2
- package/dist/modules/order/manager.d.ts.map +1 -1
- package/dist/modules/order/manager.js +20 -8
- package/dist/modules/order/manager.js.map +1 -1
- package/dist/modules/order/sync_engine.d.ts.map +1 -1
- package/dist/modules/order/sync_engine.js +8 -15
- package/dist/modules/order/sync_engine.js.map +1 -1
- package/dist/modules/order/utils/math.d.ts +1 -10
- package/dist/modules/order/utils/math.d.ts.map +1 -1
- package/dist/modules/order/utils/math.js +1 -1
- package/dist/modules/order/utils/math.js.map +1 -1
- package/dist/modules/order/utils/system.d.ts +5 -16
- package/dist/modules/order/utils/system.d.ts.map +1 -1
- package/dist/modules/order/utils/system.js +7 -4
- package/dist/modules/order/utils/system.js.map +1 -1
- package/dist/modules/process_discovery.d.ts +0 -3
- package/dist/modules/process_discovery.d.ts.map +1 -1
- package/dist/modules/process_discovery.js +1 -1
- package/dist/modules/process_discovery.js.map +1 -1
- package/dist/modules/settings_merge.d.ts +10 -1
- package/dist/modules/settings_merge.d.ts.map +1 -1
- package/dist/modules/settings_merge.js +27 -17
- package/dist/modules/settings_merge.js.map +1 -1
- package/dist/modules/utils/chain_logs.d.ts +1 -2
- package/dist/modules/utils/chain_logs.d.ts.map +1 -1
- package/dist/modules/utils/chain_logs.js +1 -1
- package/dist/modules/utils/chain_logs.js.map +1 -1
- package/dist/modules/validate_profiles.d.ts.map +1 -1
- package/dist/modules/validate_profiles.js +4 -3
- package/dist/modules/validate_profiles.js.map +1 -1
- package/dist/scripts/analyze-git.js +2 -2
- package/dist/scripts/analyze-git.js.map +1 -1
- package/dist/scripts/chart_command.d.ts +48 -0
- package/dist/scripts/chart_command.d.ts.map +1 -0
- package/dist/scripts/chart_command.js +504 -0
- package/dist/scripts/chart_command.js.map +1 -0
- package/dist/scripts/dw.d.ts +3 -0
- package/dist/scripts/dw.d.ts.map +1 -0
- package/dist/scripts/dw.js +30 -0
- package/dist/scripts/dw.js.map +1 -0
- package/dist/scripts/tv.d.ts +1 -31
- package/dist/scripts/tv.d.ts.map +1 -1
- package/dist/scripts/tv.js +10 -463
- package/dist/scripts/tv.js.map +1 -1
- package/dist/scripts/update.js +145 -93
- package/dist/scripts/update.js.map +1 -1
- package/dist/scripts/update_dist_freshness.d.ts +46 -0
- package/dist/scripts/update_dist_freshness.d.ts.map +1 -0
- package/dist/scripts/update_dist_freshness.js +115 -0
- package/dist/scripts/update_dist_freshness.js.map +1 -0
- package/dist/unlock.js +1 -1
- package/dist/unlock.js.map +1 -1
- package/docs/BITSHARES_ONBOARDING.md +117 -44
- package/docs/COPY_ON_WRITE_MASTER_PLAN.md +10 -207
- package/docs/COW_INVARIANTS.md +16 -10
- package/docs/DEXBOT_COMPARISON.md +3 -3
- package/docs/EVOLUTION.md +76 -30
- package/docs/FUND_MOVEMENT_AND_ACCOUNTING.md +9 -9
- package/docs/GRID_RECALCULATION.md +34 -30
- package/docs/GRID_RECONCILE.md +30 -27
- package/docs/LIFECYCLE.md +12 -11
- package/docs/LOGGING.md +1 -0
- package/docs/README.md +58 -52
- package/docs/WORKFLOW.md +1 -2
- package/docs/architecture.md +21 -32
- package/docs/developer_guide.md +4 -3
- package/market_adapter/README.md +36 -60
- package/modules/README.md +2 -1
- package/package.json +1 -2
- package/scripts/README.md +18 -25
- package/scripts/git-viewer.sh +1 -1
- package/scripts/reset-settings.sh +1 -1
- package/tests/README.md +10 -1
- package/dist/scripts/generate_market_adapter_whitelist.d.ts +0 -15
- package/dist/scripts/generate_market_adapter_whitelist.d.ts.map +0 -1
- package/dist/scripts/generate_market_adapter_whitelist.js +0 -191
- package/dist/scripts/generate_market_adapter_whitelist.js.map +0 -1
|
@@ -236,6 +236,11 @@ async function main() {
|
|
|
236
236
|
},
|
|
237
237
|
smaPeriod: config.smaPeriod,
|
|
238
238
|
amaDefaults: {
|
|
239
|
+
// Intentionally the 3-param AMA (er/fast/slow) only: the in-page
|
|
240
|
+
// recomputation has no erSmoothPeriod input by decision — `dexbot tv`
|
|
241
|
+
// stays a plain candle chart. The dw research chart and the live
|
|
242
|
+
// adapter are the mirrors of the full bot AMA config (incl.
|
|
243
|
+
// ama.erSmoothPeriod); the knob is inert by default (global 0).
|
|
239
244
|
erPeriod: config.amaErPeriod ?? amaConfig.erPeriod,
|
|
240
245
|
fastPeriod: config.amaFastPeriod ?? amaConfig.fastPeriod,
|
|
241
246
|
slowPeriod: config.amaSlowPeriod ?? amaConfig.slowPeriod,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import fs from 'node:fs';
|
|
4
4
|
import { MARKET_ADAPTER } from '../../modules/constants.js';
|
|
5
|
-
import { escapeHtml, serializeJsonForScript, UPLOT_SHARED_SCRIPT, embedFunctionSources } from '../chart_utils.js';
|
|
5
|
+
import { escapeHtml, serializeJsonForScript, UPLOT_SHARED_SCRIPT, embedFunctionSources, uplotInlineTags } from '../chart_utils.js';
|
|
6
6
|
import { cursorCSS, uplotBgCSS } from '../chart_css.js';
|
|
7
7
|
import { zoomResetScript } from '../chart_ui.js';
|
|
8
8
|
import { normalizeCandle } from '../math_utils.js';
|
|
@@ -240,8 +240,7 @@ function generateHTML(data: any, title: any = 'TradingView Style Research') {
|
|
|
240
240
|
<meta name="darkreader-lock">
|
|
241
241
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
242
242
|
<title>${escapeHtml(title)}</title>
|
|
243
|
-
|
|
244
|
-
<script src="../uplot/uPlot.iife.min.js"></script>
|
|
243
|
+
${uplotInlineTags()}
|
|
245
244
|
<style>
|
|
246
245
|
* { box-sizing: border-box; }
|
|
247
246
|
:root { color-scheme: dark; }
|
|
@@ -584,7 +583,7 @@ function generateHTML(data: any, title: any = 'TradingView Style Research') {
|
|
|
584
583
|
</span>
|
|
585
584
|
</div>
|
|
586
585
|
<div class="indicator">
|
|
587
|
-
<label><input type="checkbox" id="ama-init-offset-toggle">
|
|
586
|
+
<label title="Init Offset"><input type="checkbox" id="ama-init-offset-toggle"> Offset</label>
|
|
588
587
|
<input type="range" id="ama-init-offset" min="-50" max="50" value="0" step="1" style="width:90px;vertical-align:middle" disabled>
|
|
589
588
|
<span id="ama-init-offset-val" style="font-size:11px;color:#8b949e;width:32px;display:inline-block;text-align:right">0%</span>
|
|
590
589
|
</div>
|
|
@@ -1470,7 +1469,7 @@ function generateHTML(data: any, title: any = 'TradingView Style Research') {
|
|
|
1470
1469
|
const maxSlopeOffset = Number(slopeCfg.maxSlopeOffset) > 0 ? Number(slopeCfg.maxSlopeOffset) : 0.5;
|
|
1471
1470
|
const maxAsym = gridCfg && Number(gridCfg.maxAsymmetryFactor) > 0
|
|
1472
1471
|
? Number(gridCfg.maxAsymmetryFactor)
|
|
1473
|
-
: (Number(slopeCfg.maxAsymmetryFactor) > 0 ? Number(slopeCfg.maxAsymmetryFactor) : 0.
|
|
1472
|
+
: (Number(slopeCfg.maxAsymmetryFactor) > 0 ? Number(slopeCfg.maxAsymmetryFactor) : 0.333);
|
|
1474
1473
|
const inc = gridCfg && Number(gridCfg.incrementPercent) > 0 ? Number(gridCfg.incrementPercent) : null;
|
|
1475
1474
|
const minSlots = Math.floor(Number(gridCfg && gridCfg.minScaleSlots) > 0 ? Number(gridCfg.minScaleSlots) : (Number(slopeCfg.minScaleSlots) || 0));
|
|
1476
1475
|
// User x-range span (slider 1.2x–2.0x, default 1.55x): the only
|
|
@@ -3067,7 +3066,7 @@ function generateHTML(data: any, title: any = 'TradingView Style Research') {
|
|
|
3067
3066
|
}
|
|
3068
3067
|
makeStepper('sma-period', 1, 1, 0);
|
|
3069
3068
|
makeStepper('vwap-bars', 1, 24, 0);
|
|
3070
|
-
makeStepper('ama-er',
|
|
3069
|
+
makeStepper('ama-er', 10, 1, 0);
|
|
3071
3070
|
makeStepper('ama-fast', 0.1, 0.1, 1);
|
|
3072
3071
|
makeStepper('ama-slow', 1, 0.1, 1);
|
|
3073
3072
|
document.getElementById('ama-init-offset').addEventListener('input', () => {
|
|
@@ -63,6 +63,11 @@ On top of this blend, **Hurst Exponent** and **Permutation Entropy** act as a re
|
|
|
63
63
|
## Quick Start
|
|
64
64
|
|
|
65
65
|
```bash
|
|
66
|
+
# One-step (recommended): same fetch pipeline as `dexbot tv` — bot, pool, or pair
|
|
67
|
+
dexbot dw <bot-key>
|
|
68
|
+
dexbot dw 133 --month 6
|
|
69
|
+
dexbot dw TOKENA/TOKENB --month 1
|
|
70
|
+
|
|
66
71
|
# From JSON candle file
|
|
67
72
|
node dist/analysis/analyze_dynamic_weight.js \
|
|
68
73
|
--file market_adapter/data/lp/<pair>/lp_pool_<id>_<interval>.json
|
|
@@ -77,6 +82,8 @@ node dist/analysis/analyze_dynamic_weight.js \
|
|
|
77
82
|
|
|
78
83
|
Output: `analysis/charts/dynamic_weight_chart.html` (open in browser)
|
|
79
84
|
|
|
85
|
+
`dexbot dw` writes an auto-named chart instead: `analysis/charts/dw_<bot|pool_<id>|<a>_<b>>_1h_<N>m.html`.
|
|
86
|
+
|
|
80
87
|
**Note**: Hurst requires 256 bars and PE requires 58 bars before their regime signals become active. The first portion of the chart will show the full weight without regime gating.
|
|
81
88
|
|
|
82
89
|
## CLI Flags
|
|
@@ -90,6 +97,7 @@ Output: `analysis/charts/dynamic_weight_chart.html` (open in browser)
|
|
|
90
97
|
| `--alpha` | `0.5` | Initial α blend (0 = pure Kalman, 1 = pure AMA) |
|
|
91
98
|
| `--dw` | `0.50` | Initial displacement weight (0 = pure velocity, 1 = full displacement) |
|
|
92
99
|
| `--lb` | `9` | Initial lookback bars (1-32) for AMA slope calculation |
|
|
100
|
+
| `--ema` | `0` | Initial AMA input EMA span in bars (0 = off, 0-32) |
|
|
93
101
|
| `--gain` | `1.0` | Initial gain multiplier |
|
|
94
102
|
| `--clip` | `10` | Initial clip percentile |
|
|
95
103
|
| `--quiet` | `false` | Suppress console output |
|
|
@@ -107,6 +115,7 @@ All panels share aligned vertical time grid lines, and the bottom output panel s
|
|
|
107
115
|
|
|
108
116
|
### Panel 2 — AMA Slope Input (14%)
|
|
109
117
|
- **Orange line**: AMA3 slope percentage
|
|
118
|
+
- **Gray dashed line**: raw (unfiltered) slope — the reference when the `ema` knob > 0
|
|
110
119
|
- Shows the directional strength of the slow KAMA's trend movement
|
|
111
120
|
- Values outside the clip threshold are flattened before entering the offset formula
|
|
112
121
|
- Background shading mirrors the output signal direction
|
|
@@ -159,6 +168,7 @@ All panels share aligned vertical time grid lines, and the bottom output panel s
|
|
|
159
168
|
|------|-------|---------|---------|
|
|
160
169
|
| **nz%** | 0–1 | 0.00 | Neutral zone: dead-band below which offset is forced to 0 |
|
|
161
170
|
| **lb** | 1–32 | 9 | Logarithmic. Lookback bars for AMA slope calculation |
|
|
171
|
+
| **ema** | 0–32 | 0 | AMA input EMA span in bars (0 = off). Low-pass filters the AMA before the slope is taken; the gray dashed Raw‰ line shows the unfiltered slope for comparison |
|
|
162
172
|
| **amaS%** | 0.06–0.12 | 0.09 | Logarithmic. Gear ratio for average per-bar AMA slope saturation |
|
|
163
173
|
| **kalS%** | 0.5–1.5 | 1.0 | Logarithmic. Gear ratio for Kalman composite saturation |
|
|
164
174
|
| **clip%** | 0–55 | 10 | Percentile clip: filters extreme inputs (0 = off) |
|
|
@@ -172,7 +182,7 @@ All panels share aligned vertical time grid lines, and the bottom output panel s
|
|
|
172
182
|
|
|
173
183
|
## Copy / Paste Parameters
|
|
174
184
|
|
|
175
|
-
The **copy** button serializes all knob values (α, dw, kf, kfd, dsp, kdt, kfs, cf, lb, amaS%, kalS%, th%, gain, clip%, nz%, regi) to JSON and writes them to both the clipboard and `localStorage`.
|
|
185
|
+
The **copy** button serializes all knob values (α, dw, kf, kfd, dsp, kdt, kfs, cf, lb, ema, amaS%, kalS%, th%, gain, clip%, nz%, regi) to JSON and writes them to both the clipboard and `localStorage`.
|
|
176
186
|
|
|
177
187
|
The **paste** button first checks `localStorage` for parameters from a previous copy in the same browser session. If none found, it prompts for Ctrl+V input. A confirmation popup shows the parsed values before applying them. Click **Apply** to set the knobs, **Cancel** or press **Escape** to dismiss.
|
|
178
188
|
|
|
@@ -182,7 +192,7 @@ The **paste** button first checks `localStorage` for parameters from a previous
|
|
|
182
192
|
|
|
183
193
|
### AMA slope
|
|
184
194
|
|
|
185
|
-
Taking the slope of the AMA produces a signal that is already noise-filtered at the source — a near-zero slope genuinely means sideways, not oscillation that happened to average out. The neutral zone (`nz%` knob) dead-bands any remaining micro-slope residuals
|
|
195
|
+
Taking the slope of the AMA produces a signal that is already noise-filtered at the source — a near-zero slope genuinely means sideways, not oscillation that happened to average out. The neutral zone (`nz%` knob) dead-bands any remaining micro-slope residuals. When that is still too jumpy, the optional `ema` knob low-pass filters the AMA input itself before the slope is taken (0 = off keeps the raw input).
|
|
186
196
|
|
|
187
197
|
### Kalman filter
|
|
188
198
|
|
|
@@ -277,6 +287,7 @@ The lookup table can be customized per-market or per-bot (see [Custom Configurat
|
|
|
277
287
|
## Formulas
|
|
278
288
|
|
|
279
289
|
### AMA Offset
|
|
290
|
+
With `ema` > 0, `AMA_now` / `AMA_lb_bars_ago` below are read from the EMA-filtered AMA input instead of the raw AMA series (everything else identical):
|
|
280
291
|
```
|
|
281
292
|
amaSlope% = ((AMA_now − AMA_lb_bars_ago) / AMA_lb_bars_ago × 100) / lb
|
|
282
293
|
amaClip = clamp(amaSlope%, ±clipThreshold) // percentile-based clip
|
|
@@ -354,6 +365,27 @@ Number of bars to look back when computing AMA slope:
|
|
|
354
365
|
|
|
355
366
|
AMA slope is normalized to an average percent per bar, not the cumulative move across the full lookback. Lower values = more noise, faster reaction. Higher values = smoother signals, more lag without adding gain just because the measurement window is longer.
|
|
356
367
|
|
|
368
|
+
### ema (AMA input EMA span)
|
|
369
|
+
Optional low-pass EMA over the AMA values before the slope is taken (span in bars, α = 2/(span+1), `0` = off). Because differencing and an EMA are both linear filters, they commute — smoothing the AMA input produces exactly the smoothed slope series, modulo the seeding transient.
|
|
370
|
+
|
|
371
|
+
| `ema` | noise reduction* | added lag | verdict |
|
|
372
|
+
|---|---|---|---|
|
|
373
|
+
| 0 | 1× (off) | 0 bars | default, current behavior |
|
|
374
|
+
| 4 | ~2× | ~+1.5 bars | light |
|
|
375
|
+
| 9 (= lb) | ~3× | ~+4 bars | sweet spot |
|
|
376
|
+
| 16 | ~4× | ~+7.5 bars | heavy but usable |
|
|
377
|
+
| 32 | ~5.7× | ~+15.5 bars | upper-bound demo, too laggy to trade |
|
|
378
|
+
|
|
379
|
+
\* standard-deviation reduction for white-ish noise ≈ `sqrt(span)`; lag ≈ `(span-1)/2` bars (EMA group delay) on top of the slope window's `(lb-1)/2`.
|
|
380
|
+
|
|
381
|
+
Measured on ~8.7k hourly bars with the default AMA profile (`lb = 9`): the slow AMA's slope is dominated by low-frequency moves rather than white noise, so the `sqrt(span)` rule overstates the standard-deviation gain — `ema = 9` cut slope std only ~3% but trimmed the largest peaks ~22% and zero-crossings 86 → 74; `ema = 32` cut std ~11%, peaks ~48%, crossings 86 → 44, with a measured lag of ~3 bars at span 9 (theory 4). On this input the knob acts mainly as a peak-trimmer and sign-flip reducer, not as a general noise killer.
|
|
382
|
+
|
|
383
|
+
Effects while tuning:
|
|
384
|
+
- Zero-crossings get rarer, so the `cf` latch matters less and the `nz%` dead-band sits on a smooth curve instead of on noise.
|
|
385
|
+
- |slope| peaks shrink, so the same `amaS%` reaches full offset strength less often — expect to lower `amaS%` (or raise `gain`) to restore output amplitude. The `clip%` percentile pool is rebuilt from the filtered input, which partially self-compensates.
|
|
386
|
+
- Keep total lag in mind: ~`lb/2 + ema/2` bars before the slope reflects a move; at defaults that is ~8 bars (~8 h on the 1 h chart).
|
|
387
|
+
- Panel 2 plots the smoothed slope (orange) over the raw slope (gray dashed) so the noise/lag trade-off is directly visible.
|
|
388
|
+
|
|
357
389
|
### regi (regime sensitivity)
|
|
358
390
|
- 0 = regime multiplier is always 1.0 (Hurst+PE ignored)
|
|
359
391
|
- 1 = default table values used as-is
|
|
@@ -383,6 +415,7 @@ The 3×3 regime multiplier table can be customized per-market or per-bot (defaul
|
|
|
383
415
|
Candle Data
|
|
384
416
|
├── AMA3 (slow KAMA, erPeriod=781)
|
|
385
417
|
│ ├── calculateAMA() → AMA3 values per bar [price panel overlay]
|
|
418
|
+
│ ├── `ema` knob (0 = off) → EMA-filtered AMA input [research chart only]
|
|
386
419
|
│ ├── computeAmaSlopeWeights() → slope%
|
|
387
420
|
│ └── Percentile clip → amaClip → amaOff
|
|
388
421
|
│
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
resolveKalmanVelocitySmoothingConfig,
|
|
11
11
|
smoothKalmanVelocityPoint,
|
|
12
12
|
} from '../../market_adapter/core/signals/kalman_velocity_smoothing.js';
|
|
13
|
-
import { embedFunctionSources, escapeHtml, serializeJsonForScript, toEpochSeconds, UPLOT_SHARED_SCRIPT } from '../chart_utils.js';
|
|
13
|
+
import { embedFunctionSources, escapeHtml, serializeJsonForScript, toEpochSeconds, UPLOT_SHARED_SCRIPT, uplotInlineTags } from '../chart_utils.js';
|
|
14
14
|
import { sharedChartCSS } from '../chart_css.js';
|
|
15
15
|
import { Y_AXIS_SIZE, makeCursorConfig, bindHoverStateFn, wireChartEvents, zoomResetScript, sizeChartsFn } from '../chart_ui.js';
|
|
16
16
|
|
|
@@ -40,6 +40,7 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
|
|
|
40
40
|
const AMA_MS_MIN = 0.06, AMA_MS_MAX = 0.12;
|
|
41
41
|
const KAL_MS_MIN = 0.5, KAL_MS_MAX = 1.5;
|
|
42
42
|
const CLIP_PCT_MAX = 20;
|
|
43
|
+
const EMA_MIN = 0, EMA_MAX = 32;
|
|
43
44
|
const TH_MIN = 0, TH_MAX = 0.5;
|
|
44
45
|
const KF_MIN = 0, KF_MAX = 200;
|
|
45
46
|
const KFD_MIN = 1.0, KFD_MAX = 3.0;
|
|
@@ -53,6 +54,7 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
|
|
|
53
54
|
dispWeight: [0, 1],
|
|
54
55
|
neutralZonePct: [0, 1],
|
|
55
56
|
lookbackBars: [LB_MIN, LB_MAX],
|
|
57
|
+
amaEmaSpan: [EMA_MIN, EMA_MAX],
|
|
56
58
|
amaMaxSlopePct: [AMA_MS_MIN, AMA_MS_MAX],
|
|
57
59
|
kalmanMaxSlopePct: [KAL_MS_MIN, KAL_MS_MAX],
|
|
58
60
|
clipPct: [0, CLIP_PCT_MAX],
|
|
@@ -117,6 +119,10 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
|
|
|
117
119
|
const defaultKalmanDispThresholdMult = data.kalmanDispThresholdMult ?? MARKET_ADAPTER.DYNAMIC_WEIGHT_KALMAN_DISP_THRESHOLD_MULT_DEFAULT;
|
|
118
120
|
const defaultKalmanSmoothSpanPct = data.kalmanSmoothSpanPct ?? MARKET_ADAPTER.DYNAMIC_WEIGHT_KALMAN_SMOOTH_SPAN_PCT_DEFAULT;
|
|
119
121
|
const defaultSignalConfirmBars = data.signalConfirmBars ?? MARKET_ADAPTER.DYNAMIC_WEIGHT_SIGNAL_CONFIRM_BARS_DEFAULT;
|
|
122
|
+
// Research-only `ema` knob: EMA span in bars over the AMA input before the
|
|
123
|
+
// slope is taken. 0 (default) = off, keeps the raw AMA input.
|
|
124
|
+
const defaultAmaEmaSpanRaw = data.amaEmaSpan ?? ma.amaEmaSpan ?? 0;
|
|
125
|
+
const defaultAmaEmaSpan = Math.round(Math.min(EMA_MAX, Math.max(EMA_MIN, Number.isFinite(defaultAmaEmaSpanRaw) ? defaultAmaEmaSpanRaw : EMA_MIN)));
|
|
120
126
|
const regimeInitSlider = Math.round(defaultRegimeSensitivity * 100);
|
|
121
127
|
|
|
122
128
|
const interval = results.length > 1 ?
|
|
@@ -224,8 +230,7 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
|
|
|
224
230
|
<head>
|
|
225
231
|
<meta charset="UTF-8">
|
|
226
232
|
<title>${escapeHtml(title)}</title>
|
|
227
|
-
|
|
228
|
-
<script src="../uplot/uPlot.iife.min.js"></script>
|
|
233
|
+
${uplotInlineTags()}
|
|
229
234
|
<style>
|
|
230
235
|
${sharedChartCSS()}
|
|
231
236
|
#price-panel { flex: 0 0 34%; min-height: 0; position: relative; border-bottom: 1px solid #30363d; }
|
|
@@ -236,7 +241,7 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
|
|
|
236
241
|
.legend-item { gap: 3px; }
|
|
237
242
|
.legend-val { font-family: monospace; display: inline-block; text-align: right; min-width: 45px; }
|
|
238
243
|
#l-price, #l-ama3 { min-width: 62px; }
|
|
239
|
-
#l-ama-slope, #l-kal-vel, #l-kal-disp { min-width: 54px; }
|
|
244
|
+
#l-ama-slope, #l-ama-slope-raw, #l-kal-vel, #l-kal-disp { min-width: 54px; }
|
|
240
245
|
#l-signal, #l-signal-latched { min-width: 70px; text-align: left; }
|
|
241
246
|
#l-combined-raw, #l-combined-echo { min-width: 42px; }
|
|
242
247
|
#l-mult { min-width: 38px; }
|
|
@@ -281,6 +286,9 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
|
|
|
281
286
|
.ctrl.lb label { min-width: 20px; }
|
|
282
287
|
.ctrl.lb input[type="range"] { accent-color: #39d0d8; width: 80px; }
|
|
283
288
|
.ctrl.lb .val { color: #39d0d8; }
|
|
289
|
+
.ctrl.ema label { min-width: 20px; }
|
|
290
|
+
.ctrl.ema input[type="range"] { accent-color: #f0a000; width: 80px; }
|
|
291
|
+
.ctrl.ema .val { color: #f0a000; }
|
|
284
292
|
.ctrl.off input[type="range"] { accent-color: #3fb950; }
|
|
285
293
|
.ctrl.off .val { color: #3fb950; }
|
|
286
294
|
.ctrl.nz input[type="range"] { accent-color: #8b949e; }
|
|
@@ -326,6 +334,7 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
|
|
|
326
334
|
<div class="section-label">AMA SLOPE INPUT</div>
|
|
327
335
|
<div class="legend">
|
|
328
336
|
<div class="legend-item"><div class="dot" style="background:#f0a000;"></div>Slope‰: <span id="l-ama-slope" class="legend-val" style="font-weight:bold;">-</span></div>
|
|
337
|
+
<div class="legend-item"><div class="dot" style="background:#8b949e;"></div>Raw‰: <span id="l-ama-slope-raw" class="legend-val">-</span></div>
|
|
329
338
|
</div>
|
|
330
339
|
<div id="ama-chart"></div>
|
|
331
340
|
</div>
|
|
@@ -356,6 +365,7 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
|
|
|
356
365
|
<div class="group-sep"></div>
|
|
357
366
|
<div class="ctrl nz"><label for="nz-slider">nz%</label><input type="range" id="nz-slider" min="0" max="100" value="${Math.round(defaultNeutralZone * 100)}" title="Neutral Zone %"><span class="val" id="nz-value">${defaultNeutralZone.toFixed(2)}</span></div>
|
|
358
367
|
<div class="ctrl lb"><label for="lb-slider">lb</label><input type="range" id="lb-slider" min="0" max="1000" value="${lbInitSlider}" title="Lookback Bars (${LB_MIN}-${LB_MAX})"><span class="val" id="lb-value">${lookbackBars}</span></div>
|
|
368
|
+
<div class="ctrl ema"><label for="ema-slider">ema</label><input type="range" id="ema-slider" min="${EMA_MIN}" max="${EMA_MAX}" value="${defaultAmaEmaSpan}" title="AMA input EMA span in bars (${EMA_MIN} = off; noise std ~ 1/sqrt(span), lag ~ (span-1)/2 bars; span ~ lb is the balance point)"><span class="val" id="ema-value">${defaultAmaEmaSpan}</span></div>
|
|
359
369
|
<div class="ctrl ms-ama"><label for="ama-ms-slider">amaS%</label><input type="range" id="ama-ms-slider" min="0" max="1000" value="${amaMsInitSlider}" title="AMA Max Slope % per bar (${AMA_MS_MIN}-${AMA_MS_MAX})"><span class="val" id="ama-ms-value">${defaultAmaMaxSlopePct.toFixed(4)}</span></div>
|
|
360
370
|
<div class="ctrl clip"><label for="clip-slider">clip%</label><input type="range" id="clip-slider" min="0" max="${CLIP_PCT_MAX}" value="${Math.min(defaultClipPct, CLIP_PCT_MAX)}" title="Outlier Clip %"><span class="val" id="clip-value">${Math.min(defaultClipPct, CLIP_PCT_MAX)}%</span></div>
|
|
361
371
|
|
|
@@ -389,7 +399,7 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
|
|
|
389
399
|
</div>
|
|
390
400
|
</div>
|
|
391
401
|
|
|
392
|
-
<script id="payload" type="application/json">${serializeJsonForScript({ dates, prices, hurstArr, peArr, hurstSegments, peSegments, ama3Prices, amaSeedSmaLine, amaSlopePct, kalmanVelocityPctRaw, kalmanVelocityPct, kalmanDisplacementPct, kalmanIsReady, signals, alpha: defaultAlpha, gain: defaultGain, kalmanSmoothPct: defaultKalmanSmoothPct, kalmanDispScaleMult: defaultKalmanDispScaleMult, kalmanDispThresholdMult: defaultKalmanDispThresholdMult, kalmanSmoothSpanPct: defaultKalmanSmoothSpanPct, signalConfirmBars: defaultSignalConfirmBars, neutralZonePct: defaultNeutralZone, dispWeight: defaultDispWeight, amaMaxSlopePct: defaultAmaMaxSlopePct, kalmanMaxSlopePct: defaultKalmanMaxSlopePct, maxDispPct, clipPct: defaultClipPct, minOutputThreshold: defaultMinOutputThreshold, outputClamp: defaultOutputClamp, regimeSensitivity: defaultRegimeSensitivity, absoluteThreshold: defaultAbsoluteThreshold, lookbackBars, amaErPeriod, amaSlowPeriod, amaWarmupBars, amaSlopeReadyBars, realBarCount, amaPctMax, kalPctMax, amaPercentiles, kalPercentiles, amaSlopeLogMin: AMA_MS_LOG_MIN_N, amaSlopeLogMax: AMA_MS_LOG_MAX_N, kalSlopeLogMin: KAL_MS_LOG_MIN_N, kalSlopeLogMax: KAL_MS_LOG_MAX_N, lbLogMin: LB_LOG_MIN_N, lbLogMax: LB_LOG_MAX_N, gainLogMin: GAIN_LOG_MIN_N, gainLogMax: GAIN_LOG_MAX_N, sliderRanges: SLIDER_RANGES, dispScaleMinPct: defaultDispScaleMinPct, weightMin: MARKET_ADAPTER.DYNAMIC_WEIGHT_MIN_WEIGHT, weightMax: MARKET_ADAPTER.DYNAMIC_WEIGHT_MAX_WEIGHT, marketAdapter: ma, amaWeightConfig, hNodes: [0.5 + MARKET_ADAPTER.HURST_ZONE_BAND, 0.5, 0.5 - MARKET_ADAPTER.HURST_ZONE_BAND], pNodes: MARKET_ADAPTER.PE_NODES, regimeTable: MARKET_ADAPTER.REGIME_TABLE })}</script>
|
|
402
|
+
<script id="payload" type="application/json">${serializeJsonForScript({ dates, prices, hurstArr, peArr, hurstSegments, peSegments, ama3Prices, amaSeedSmaLine, amaSlopePct, kalmanVelocityPctRaw, kalmanVelocityPct, kalmanDisplacementPct, kalmanIsReady, signals, alpha: defaultAlpha, gain: defaultGain, kalmanSmoothPct: defaultKalmanSmoothPct, kalmanDispScaleMult: defaultKalmanDispScaleMult, kalmanDispThresholdMult: defaultKalmanDispThresholdMult, kalmanSmoothSpanPct: defaultKalmanSmoothSpanPct, signalConfirmBars: defaultSignalConfirmBars, neutralZonePct: defaultNeutralZone, dispWeight: defaultDispWeight, amaMaxSlopePct: defaultAmaMaxSlopePct, kalmanMaxSlopePct: defaultKalmanMaxSlopePct, maxDispPct, clipPct: defaultClipPct, minOutputThreshold: defaultMinOutputThreshold, outputClamp: defaultOutputClamp, regimeSensitivity: defaultRegimeSensitivity, absoluteThreshold: defaultAbsoluteThreshold, lookbackBars, amaErPeriod, amaSlowPeriod, amaWarmupBars, amaSlopeReadyBars, realBarCount, amaPctMax, kalPctMax, amaPercentiles, kalPercentiles, amaSlopeLogMin: AMA_MS_LOG_MIN_N, amaSlopeLogMax: AMA_MS_LOG_MAX_N, kalSlopeLogMin: KAL_MS_LOG_MIN_N, kalSlopeLogMax: KAL_MS_LOG_MAX_N, lbLogMin: LB_LOG_MIN_N, lbLogMax: LB_LOG_MAX_N, amaEmaSpan: defaultAmaEmaSpan, gainLogMin: GAIN_LOG_MIN_N, gainLogMax: GAIN_LOG_MAX_N, sliderRanges: SLIDER_RANGES, dispScaleMinPct: defaultDispScaleMinPct, weightMin: MARKET_ADAPTER.DYNAMIC_WEIGHT_MIN_WEIGHT, weightMax: MARKET_ADAPTER.DYNAMIC_WEIGHT_MAX_WEIGHT, marketAdapter: ma, amaWeightConfig, hNodes: [0.5 + MARKET_ADAPTER.HURST_ZONE_BAND, 0.5, 0.5 - MARKET_ADAPTER.HURST_ZONE_BAND], pNodes: MARKET_ADAPTER.PE_NODES, regimeTable: MARKET_ADAPTER.REGIME_TABLE })}</script>
|
|
393
403
|
|
|
394
404
|
<script>
|
|
395
405
|
const data = JSON.parse(document.getElementById('payload').textContent);
|
|
@@ -431,6 +441,8 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
|
|
|
431
441
|
const kalMsSliderToVal = (pos) => Math.exp(KAL_MS_LOG_MIN + (pos / 1000) * (KAL_MS_LOG_MAX - KAL_MS_LOG_MIN));
|
|
432
442
|
|
|
433
443
|
let currentLookbackBars = data.lookbackBars ?? ${JSON.stringify(lookbackBars)};
|
|
444
|
+
let currentAmaEmaSpan = Math.max(SR.amaEmaSpan[0], Math.min(SR.amaEmaSpan[1], Math.round(data.amaEmaSpan ?? 0)));
|
|
445
|
+
let currentAmaSource = data.ama3Prices;
|
|
434
446
|
const LB_LOG_MIN = data.lbLogMin;
|
|
435
447
|
const LB_LOG_MAX = data.lbLogMax;
|
|
436
448
|
const lbSliderToVal = (pos) => Math.round(Math.exp(LB_LOG_MIN + (pos / 1000) * (LB_LOG_MAX - LB_LOG_MIN)));
|
|
@@ -469,6 +481,7 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
|
|
|
469
481
|
const currentLatchedSignals = new Array(data.dates.length).fill(null);
|
|
470
482
|
const dynamicAmaOff = new Array(data.dates.length).fill(null);
|
|
471
483
|
const dynamicAmaSlopePct = new Array(data.dates.length).fill(null);
|
|
484
|
+
const dynamicAmaSlopePctRaw = new Array(data.dates.length).fill(null);
|
|
472
485
|
const dynamicKalOff = new Array(data.dates.length).fill(null);
|
|
473
486
|
const combinedOff = new Array(data.dates.length).fill(null);
|
|
474
487
|
const combinedSell = new Array(data.dates.length).fill(null);
|
|
@@ -583,9 +596,40 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
|
|
|
583
596
|
}
|
|
584
597
|
}
|
|
585
598
|
|
|
586
|
-
|
|
599
|
+
/**
|
|
600
|
+
* Research-only ema knob — EMA low-pass over the AMA input before the
|
|
601
|
+
* slope is taken (EMA-then-difference == difference-then-EMA, both are
|
|
602
|
+
* linear filters). span bars, alpha = 2/(span+1): noise std shrinks ~
|
|
603
|
+
* 1/sqrt(span), lag grows ~ (span-1)/2 bars. Seeded with an SMA over the
|
|
604
|
+
* first 'span' finite values (mirrors the AMA seed SMA) so the transient
|
|
605
|
+
* is gone before any slope bar can go ready. Nulls (warmup / trailing
|
|
606
|
+
* padding) stay null so no fabricated values reach the clip-percentile
|
|
607
|
+
* pool or the offset pipeline. span <= 0 returns the input untouched.
|
|
608
|
+
*/
|
|
609
|
+
function buildEmaSeries(values, span) {
|
|
610
|
+
if (!(span > 0) || !Array.isArray(values)) return values;
|
|
611
|
+
const n = values.length;
|
|
612
|
+
const out = new Array(n);
|
|
613
|
+
const alpha = 2 / (span + 1);
|
|
614
|
+
let seedSum = 0, seedCount = 0;
|
|
615
|
+
for (let i = 0; i < n && seedCount < span; i++) {
|
|
616
|
+
const v = values[i];
|
|
617
|
+
if (v == null || !Number.isFinite(v)) continue;
|
|
618
|
+
seedSum += v; seedCount++;
|
|
619
|
+
}
|
|
620
|
+
let prev = seedCount > 0 ? seedSum / seedCount : null;
|
|
621
|
+
for (let i = 0; i < n; i++) {
|
|
622
|
+
const v = values[i];
|
|
623
|
+
if (v == null || !Number.isFinite(v)) { out[i] = null; continue; }
|
|
624
|
+
prev = prev == null ? v : alpha * v + (1 - alpha) * prev;
|
|
625
|
+
out[i] = prev;
|
|
626
|
+
}
|
|
627
|
+
return out;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
function computeSlopeAtIndex(idx, lb, values) {
|
|
587
631
|
// Canonical AMA slope % (computeAverageAmaSlopePct injected above).
|
|
588
|
-
const sp = computeAverageAmaSlopePct(
|
|
632
|
+
const sp = computeAverageAmaSlopePct(values[idx], values[idx - lb], lb);
|
|
589
633
|
return sp == null ? 0 : sp;
|
|
590
634
|
}
|
|
591
635
|
|
|
@@ -593,6 +637,7 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
|
|
|
593
637
|
recalcKalmanVelocity();
|
|
594
638
|
recalcKalmanClipThreshold();
|
|
595
639
|
recalcLatchedSignals();
|
|
640
|
+
currentAmaSource = buildEmaSeries(data.ama3Prices, currentAmaEmaSpan);
|
|
596
641
|
const lb = currentLookbackBars;
|
|
597
642
|
const amaErWarmup = Math.max(0, Number.isFinite(data.amaErPeriod) ? Math.ceil(data.amaErPeriod) : ${JSON.stringify(MARKET_ADAPTER.AMAS[MARKET_ADAPTER.DEFAULT_AMA_KEY as keyof typeof MARKET_ADAPTER.AMAS].erPeriod)});
|
|
598
643
|
const amaReadyBar = Math.max(lb, amaErWarmup + lb);
|
|
@@ -601,14 +646,20 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
|
|
|
601
646
|
// implementation (computeAmaSlopeClipThreshold injected above),
|
|
602
647
|
// shared with the live market adapter service. Trailing padded
|
|
603
648
|
// nulls beyond realBarCount are skipped by its finiteness guards.
|
|
604
|
-
|
|
649
|
+
// Clip pool follows the (possibly EMA-filtered) AMA input so the
|
|
650
|
+
// percentile threshold matches the series the offsets derive from.
|
|
651
|
+
dynamicClipThreshold = computeAmaSlopeClipThreshold(currentAmaSource, amaErWarmup, lb, currentClipPct);
|
|
605
652
|
|
|
606
653
|
for (let i = 0; i < data.realBarCount; i++) {
|
|
607
|
-
// AMA
|
|
608
|
-
|
|
654
|
+
// AMA slope % for the display panel (offsets computed in
|
|
655
|
+
// recalcWeights): the raw reference line from the unfiltered AMA
|
|
656
|
+
// input, the plotted series from the EMA-filtered input.
|
|
657
|
+
dynamicAmaSlopePctRaw[i] = i < amaReadyBar ? null : computeSlopeAtIndex(i, lb, data.ama3Prices);
|
|
658
|
+
dynamicAmaSlopePct[i] = i < amaReadyBar ? null : computeSlopeAtIndex(i, lb, currentAmaSource);
|
|
609
659
|
}
|
|
610
660
|
for (let i = data.realBarCount; i < data.dates.length; i++) {
|
|
611
661
|
dynamicAmaSlopePct[i] = null;
|
|
662
|
+
dynamicAmaSlopePctRaw[i] = null;
|
|
612
663
|
}
|
|
613
664
|
}
|
|
614
665
|
|
|
@@ -634,7 +685,7 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
|
|
|
634
685
|
// Per-bar offset pipeline — canonical implementation (computeDynamicWeightSeries
|
|
635
686
|
// injected above), shared with the live market adapter service.
|
|
636
687
|
const res = computeDynamicWeightSeries({
|
|
637
|
-
amaValues:
|
|
688
|
+
amaValues: currentAmaSource,
|
|
638
689
|
kalmanVelocityPct: currentKalmanVelocityPct,
|
|
639
690
|
kalmanDisplacementPct: data.kalmanDisplacementPct,
|
|
640
691
|
kalmanIsReady: data.kalmanIsReady,
|
|
@@ -718,7 +769,7 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
|
|
|
718
769
|
max: Number.isFinite(xs.max) ? xs.max : xMax,
|
|
719
770
|
} : null;
|
|
720
771
|
|
|
721
|
-
amaChart.setData([data.dates, dynamicAmaSlopePct], false);
|
|
772
|
+
amaChart.setData([data.dates, dynamicAmaSlopePctRaw, dynamicAmaSlopePct], false);
|
|
722
773
|
kalmanChart.setData([data.dates, currentKalmanVelocityPct, data.kalmanDisplacementPct], false);
|
|
723
774
|
outputChart.setData([data.dates, combinedOff, echoCombinedOff], false);
|
|
724
775
|
|
|
@@ -753,6 +804,11 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
|
|
|
753
804
|
if (sp == null) { spEl.textContent = '-'; spEl.style.color = '#8b949e'; }
|
|
754
805
|
else { spEl.textContent = (sp >= 0 ? '+' : '') + (sp * 10).toFixed(3) + '‰'; spEl.style.color = sp > 0.01 ? '#2ea043' : sp < -0.01 ? '#f85149' : '#8b949e'; }
|
|
755
806
|
|
|
807
|
+
const spRaw = dynamicAmaSlopePctRaw[idx];
|
|
808
|
+
const spRawEl = document.getElementById('l-ama-slope-raw');
|
|
809
|
+
if (spRaw == null) { spRawEl.textContent = '-'; spRawEl.style.color = '#8b949e'; }
|
|
810
|
+
else { spRawEl.textContent = (spRaw >= 0 ? '+' : '') + (spRaw * 10).toFixed(3) + '‰'; spRawEl.style.color = '#8b949e'; }
|
|
811
|
+
|
|
756
812
|
const vp = currentKalmanVelocityPct[idx];
|
|
757
813
|
const vpEl = document.getElementById('l-kal-vel');
|
|
758
814
|
if (vp == null) { vpEl.textContent = '-'; vpEl.style.color = '#8b949e'; }
|
|
@@ -976,6 +1032,7 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
|
|
|
976
1032
|
document.getElementById('clip-slider').value = currentClipPct;
|
|
977
1033
|
document.getElementById('nz-slider').value = Math.round(currentNz * 100);
|
|
978
1034
|
document.getElementById('lb-slider').value = lbValToSlider(currentLookbackBars);
|
|
1035
|
+
document.getElementById('ema-slider').value = currentAmaEmaSpan;
|
|
979
1036
|
|
|
980
1037
|
const priceEl = document.getElementById('price-panel');
|
|
981
1038
|
const amaEl = document.getElementById('ama-panel');
|
|
@@ -1011,6 +1068,7 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
|
|
|
1011
1068
|
scales: { x: { time: true }, p: { auto: true } },
|
|
1012
1069
|
series: [
|
|
1013
1070
|
{ label: 'Time' },
|
|
1071
|
+
{ label: 'Raw‰', stroke: '#8b949e', width: 1, dash: [3, 3], scale: 'p', points: { show: false } },
|
|
1014
1072
|
{ label: 'Slope‰', stroke: '#f0a000', width: 2, scale: 'p', points: { show: false } },
|
|
1015
1073
|
],
|
|
1016
1074
|
axes: [
|
|
@@ -1020,7 +1078,7 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
|
|
|
1020
1078
|
],
|
|
1021
1079
|
cursor: cursorCfg,
|
|
1022
1080
|
hooks: { draw: [makePctFillHook(dynamicAmaSlopePct, 'p', 'rgba(46,160,67,0.20)', 'rgba(248,81,73,0.20)'), makeSignalBgHook('p')] }
|
|
1023
|
-
}, [data.dates, dynamicAmaSlopePct], document.getElementById('ama-chart'));
|
|
1081
|
+
}, [data.dates, dynamicAmaSlopePctRaw, dynamicAmaSlopePct], document.getElementById('ama-chart'));
|
|
1024
1082
|
|
|
1025
1083
|
kalmanChart = new uPlot({
|
|
1026
1084
|
width: kalmanEl.offsetWidth, height: kalmanEl.offsetHeight,
|
|
@@ -1182,6 +1240,12 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
|
|
|
1182
1240
|
onSliderChange();
|
|
1183
1241
|
});
|
|
1184
1242
|
|
|
1243
|
+
document.getElementById('ema-slider').addEventListener('input', (e) => {
|
|
1244
|
+
currentAmaEmaSpan = parseInt(e.target.value, 10);
|
|
1245
|
+
document.getElementById('ema-value').textContent = currentAmaEmaSpan;
|
|
1246
|
+
onSliderChange();
|
|
1247
|
+
});
|
|
1248
|
+
|
|
1185
1249
|
document.getElementById('regime-slider').addEventListener('input', (e) => {
|
|
1186
1250
|
currentRegimeSensitivity = parseInt(e.target.value, 10) / 100;
|
|
1187
1251
|
document.getElementById('regime-value').textContent = currentRegimeSensitivity.toFixed(2);
|
|
@@ -1277,6 +1341,11 @@ function applyParams(p, btn) {
|
|
|
1277
1341
|
document.getElementById('lb-slider').value = lbValToSlider(currentLookbackBars);
|
|
1278
1342
|
document.getElementById('lb-value').textContent = currentLookbackBars;
|
|
1279
1343
|
}
|
|
1344
|
+
if (p.amaEmaSpan != null) {
|
|
1345
|
+
currentAmaEmaSpan = Math.max(SR.amaEmaSpan[0], Math.min(SR.amaEmaSpan[1], Math.round(p.amaEmaSpan)));
|
|
1346
|
+
document.getElementById('ema-slider').value = currentAmaEmaSpan;
|
|
1347
|
+
document.getElementById('ema-value').textContent = currentAmaEmaSpan;
|
|
1348
|
+
}
|
|
1280
1349
|
recalcInputs();
|
|
1281
1350
|
recalcWeights();
|
|
1282
1351
|
refreshChartsPreservingZoom();
|
|
@@ -1303,6 +1372,7 @@ function applyParams(p, btn) {
|
|
|
1303
1372
|
regimeSensitivity: 'regime',
|
|
1304
1373
|
dispWeight: 'dw',
|
|
1305
1374
|
lookbackBars: 'lb',
|
|
1375
|
+
amaEmaSpan: 'ema',
|
|
1306
1376
|
};
|
|
1307
1377
|
document.getElementById('paste-confirm-vals').innerHTML = Object.entries(labels)
|
|
1308
1378
|
.filter(([k]) => p[k] != null)
|
|
@@ -1356,6 +1426,7 @@ function applyParams(p, btn) {
|
|
|
1356
1426
|
regimeSensitivity: +currentRegimeSensitivity.toFixed(2),
|
|
1357
1427
|
dispWeight: +currentDw.toFixed(2),
|
|
1358
1428
|
lookbackBars: currentLookbackBars,
|
|
1429
|
+
amaEmaSpan: currentAmaEmaSpan,
|
|
1359
1430
|
};
|
|
1360
1431
|
const json = JSON.stringify(params, null, 2);
|
|
1361
1432
|
localStorage.setItem(LS_KEY, json);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { MARKET_ADAPTER } from '../../modules/constants.js';
|
|
4
4
|
import { computeDynamicWeightSeries } from '../../market_adapter/core/strategies/dynamic_weight_series.js';
|
|
5
5
|
import { computeAbsolutePercentileThreshold } from '../../market_adapter/core/signals/kalman_velocity_smoothing.js';
|
|
6
|
-
import { escapeHtml, serializeJsonForScript, toEpochSeconds, UPLOT_SHARED_SCRIPT } from '../chart_utils.js';
|
|
6
|
+
import { escapeHtml, serializeJsonForScript, toEpochSeconds, UPLOT_SHARED_SCRIPT, uplotInlineTags } from '../chart_utils.js';
|
|
7
7
|
import { sharedChartCSS } from '../chart_css.js';
|
|
8
8
|
import { Y_AXIS_SIZE, makeCursorConfig, bindHoverStateFn, wireChartEvents, zoomResetScript, sizeChartsFn } from '../chart_ui.js';
|
|
9
9
|
|
|
@@ -94,8 +94,7 @@ function generateHTML(data: any, title = 'Kalman Trajectory Analysis') {
|
|
|
94
94
|
<head>
|
|
95
95
|
<meta charset="UTF-8">
|
|
96
96
|
<title>${escapeHtml(title)}</title>
|
|
97
|
-
|
|
98
|
-
<script src="../uplot/uPlot.iife.min.js"></script>
|
|
97
|
+
${uplotInlineTags()}
|
|
99
98
|
<style>
|
|
100
99
|
${sharedChartCSS()}
|
|
101
100
|
#price-panel { flex: 0 0 55%; min-height: 0; position: relative; border-bottom: 1px solid #30363d; }
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
import { MARKET_ADAPTER } from '../../modules/constants.js';
|
|
4
|
-
import { escapeHtml, serializeJsonForScript, toEpochSeconds, UPLOT_SHARED_SCRIPT } from '../chart_utils.js';
|
|
4
|
+
import { escapeHtml, serializeJsonForScript, toEpochSeconds, UPLOT_SHARED_SCRIPT, uplotInlineTags } from '../chart_utils.js';
|
|
5
5
|
import { sharedChartCSS } from '../chart_css.js';
|
|
6
6
|
import { Y_AXIS_SIZE, makeCursorConfig, bindHoverStateFn, wireChartEvents, zoomResetScript, sizeChartsFn, fmtDateFn } from '../chart_ui.js';
|
|
7
7
|
|
|
@@ -91,8 +91,7 @@ function generateRegimeHTML(data: any, title = 'Regime Analysis') {
|
|
|
91
91
|
<head>
|
|
92
92
|
<meta charset="UTF-8">
|
|
93
93
|
<title>${escapeHtml(title)}</title>
|
|
94
|
-
|
|
95
|
-
<script src="../uplot/uPlot.iife.min.js"></script>
|
|
94
|
+
${uplotInlineTags()}
|
|
96
95
|
<style>
|
|
97
96
|
${sharedChartCSS()}
|
|
98
97
|
#price-panel { flex: 0 0 34%; min-height: 0; position: relative; border-bottom: 1px solid #30363d; }
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { MARKET_ADAPTER } from '../../modules/constants.js';
|
|
4
4
|
import { computeATRSeries } from '../../market_adapter/core/strategies/atr/calculator.js';
|
|
5
5
|
import { computeVolatilityShift } from '../../market_adapter/core/strategies/volatility_shift.js';
|
|
6
|
-
import { embedFunctionSources, escapeHtml, serializeJsonForScript, toEpochSeconds, UPLOT_SHARED_SCRIPT } from '../chart_utils.js';
|
|
6
|
+
import { embedFunctionSources, escapeHtml, serializeJsonForScript, toEpochSeconds, UPLOT_SHARED_SCRIPT, uplotInlineTags } from '../chart_utils.js';
|
|
7
7
|
import { sharedChartCSS } from '../chart_css.js';
|
|
8
8
|
import { Y_AXIS_SIZE, makeCursorConfig, bindHoverStateFn, wireChartEvents, zoomResetScript, sizeChartsFn } from '../chart_ui.js';
|
|
9
9
|
|
|
@@ -66,8 +66,7 @@ function generateHTML(data: any, title = 'ATR Volatility Research') {
|
|
|
66
66
|
<meta name="color-scheme" content="dark">
|
|
67
67
|
<meta name="darkreader-lock">
|
|
68
68
|
<title>${escapeHtml(title)}</title>
|
|
69
|
-
|
|
70
|
-
<script src="../uplot/uPlot.iife.min.js"></script>
|
|
69
|
+
${uplotInlineTags()}
|
|
71
70
|
<style>
|
|
72
71
|
${sharedChartCSS()}
|
|
73
72
|
:root { color-scheme: dark; }
|
|
@@ -7,7 +7,7 @@ import { Config } from '../../modules/config.js';
|
|
|
7
7
|
import { PATHS } from '../../modules/paths.js';
|
|
8
8
|
import { writeJsonFileAtomic as baseWriteJsonFileAtomic } from '../../modules/bots_file_lock.js';
|
|
9
9
|
import { acquireFileLock } from '../../market_adapter/utils/file_lock.js';
|
|
10
|
-
import { assertNoDuplicateBotKeys } from '../../modules/bot_settings.js';
|
|
10
|
+
import { assertNoDuplicateBotKeys, normalizeBotEntry } from '../../modules/bot_settings.js';
|
|
11
11
|
import { BOT_LIVE_CONFIG_KEYS } from '../../modules/runtime_settings.js';
|
|
12
12
|
import { clone } from './utils.js';
|
|
13
13
|
import { createBotKey, sanitizeKey } from '../../modules/account_orders.js';
|
|
@@ -682,8 +682,9 @@ async function normalizeBotEntries(rawEntries: Record<string, any>[], options: P
|
|
|
682
682
|
if (logger) {
|
|
683
683
|
validateBotEntry(entry, index, logger);
|
|
684
684
|
}
|
|
685
|
-
|
|
686
|
-
|
|
685
|
+
// Shared seeder semantics with modules/bot_settings.normalizeBotEntry:
|
|
686
|
+
// missing active → DEFAULT_CONFIG.active, present values pass through raw.
|
|
687
|
+
results.push(normalizeBotEntry(entry, index));
|
|
687
688
|
}
|
|
688
689
|
return results;
|
|
689
690
|
}
|
package/claw/package.json
CHANGED
|
@@ -30,7 +30,7 @@ async function testParserAcceptsJsonlAcrossChunksAndSingleBuffer() {
|
|
|
30
30
|
capabilities: {},
|
|
31
31
|
clientInfo: {
|
|
32
32
|
name: 'claw-mcp-transport-test',
|
|
33
|
-
version: '1.6.
|
|
33
|
+
version: '1.6.5'
|
|
34
34
|
},
|
|
35
35
|
protocolVersion: '2024-11-05'
|
|
36
36
|
}
|
|
@@ -187,7 +187,7 @@ async function testMainEntrypointHandlesRealProcessInitialize() {
|
|
|
187
187
|
capabilities: {},
|
|
188
188
|
clientInfo: {
|
|
189
189
|
name: 'claw-mcp-transport-test',
|
|
190
|
-
version: '1.6.
|
|
190
|
+
version: '1.6.5'
|
|
191
191
|
},
|
|
192
192
|
protocolVersion: '2024-11-05'
|
|
193
193
|
}
|
|
@@ -4,7 +4,7 @@ const assert = require('assert');
|
|
|
4
4
|
const fs = require('fs/promises');
|
|
5
5
|
const os = require('os');
|
|
6
6
|
const path = require('path');
|
|
7
|
-
const { GRID_LIMITS } = require('../../modules/constants');
|
|
7
|
+
const { GRID_LIMITS, DEFAULT_CONFIG } = require('../../modules/constants');
|
|
8
8
|
|
|
9
9
|
const {
|
|
10
10
|
createBotKey,
|
|
@@ -608,8 +608,25 @@ async function testGeometryPatchKeepsTriggerByDefault() {
|
|
|
608
608
|
await fs.access(result.triggerPath);
|
|
609
609
|
}
|
|
610
610
|
|
|
611
|
+
async function testNormalizeBotEntriesDelegatesToSharedSeeder() {
|
|
612
|
+
console.log(' - Testing normalizeBotEntries delegates to shared bot defaults...');
|
|
613
|
+
const entries = await normalizeBotEntries([
|
|
614
|
+
{ name: 'missing-active' },
|
|
615
|
+
{ name: 'null-active', active: null },
|
|
616
|
+
{ name: 'false-active', active: false },
|
|
617
|
+
]);
|
|
618
|
+
assert.strictEqual(entries[0].active, DEFAULT_CONFIG.active,
|
|
619
|
+
'missing active → DEFAULT_CONFIG.active (shared seeder, was hardcoded true)');
|
|
620
|
+
assert.strictEqual(entries[1].active, null,
|
|
621
|
+
'present null passes through raw (claw used to coerce to false — unified in Phase 3)');
|
|
622
|
+
assert.strictEqual(entries[2].active, false, 'active:false preserved');
|
|
623
|
+
assert.strictEqual(entries[0].botIndex, 0, 'index stamped');
|
|
624
|
+
assert.ok(entries[0].botKey, 'botKey generated');
|
|
625
|
+
}
|
|
626
|
+
|
|
611
627
|
async function main() {
|
|
612
628
|
await testNormalizeAcceptsAssetIdAliases();
|
|
629
|
+
await testNormalizeBotEntriesDelegatesToSharedSeeder();
|
|
613
630
|
testCreateBotKeyFallsBackToAssetIds();
|
|
614
631
|
await testMatchBotIdentifierHandlesIdOnlyBots();
|
|
615
632
|
await testAtomicWriteFailsFastWhenLockCannotBeAcquired();
|