dexbot 1.4.19 → 1.4.21

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.
Files changed (302) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +22 -12
  3. package/analysis/ama_fitting/analyze_lambda_vs_slow.ts +2 -2
  4. package/analysis/ama_fitting/calibrate_convergence_er.ts +1 -1
  5. package/analysis/ama_fitting/optimizer_high_resolution.ts +2 -1
  6. package/analysis/ama_fitting/package.json +1 -1
  7. package/analysis/analyze_derivatives.ts +4 -2
  8. package/analysis/analyze_dynamic_weight.ts +3 -1
  9. package/analysis/analyze_kalman.ts +3 -1
  10. package/analysis/analyze_regime.ts +3 -1
  11. package/analysis/analyze_regime_windows.ts +3 -1
  12. package/analysis/analyze_volatility.ts +2 -2
  13. package/analysis/bot_fitting/backtest_ama_sweep.ts +2 -1
  14. package/analysis/bot_fitting/backtest_bot_fitting.ts +17 -12
  15. package/analysis/bot_fitting/shared_utils.ts +1 -1
  16. package/analysis/bot_key_utils.ts +1 -5
  17. package/analysis/bot_usage/kibana_bot_queries.ts +1 -256
  18. package/analysis/chart_css.ts +1 -1
  19. package/analysis/chart_utils.ts +24 -0
  20. package/analysis/derivative_chart_generator.ts +3 -2
  21. package/analysis/math_utils.ts +1 -8
  22. package/analysis/trend_detection/DYNAMIC_WEIGHT_RESEARCH.md +1 -1
  23. package/analysis/trend_detection/dynamic_weight_chart_generator.ts +91 -55
  24. package/analysis/trend_detection/package.json +1 -1
  25. package/claw/ecosystem.config.cjs +2 -3
  26. package/claw/examples/claw_profiles_example.ts +4 -1
  27. package/claw/examples/memu_integration_example.ts +17 -17
  28. package/claw/modules/chain_actions.ts +51 -54
  29. package/claw/modules/chain_broadcast.ts +66 -104
  30. package/claw/modules/claw_bridge.ts +60 -80
  31. package/claw/modules/claw_catalog.ts +48 -17
  32. package/claw/modules/claw_infra.ts +1 -5
  33. package/claw/modules/claw_launcher.ts +47 -49
  34. package/claw/modules/claw_skill_md.ts +14 -16
  35. package/claw/modules/credit_runtime_adapter.ts +2 -18
  36. package/claw/modules/decision_loop.ts +4 -0
  37. package/claw/modules/dexbot_bridge.ts +1 -1
  38. package/claw/modules/dexbot_profiles.ts +8 -22
  39. package/claw/modules/honest_ecosystem.ts +24 -8
  40. package/claw/modules/launcher_paths.ts +4 -2
  41. package/claw/modules/liquidity_pools.ts +10 -3
  42. package/claw/modules/mcp_utils.ts +109 -0
  43. package/claw/modules/memu_bridge.ts +76 -54
  44. package/claw/modules/mpa_utils.ts +26 -3
  45. package/claw/modules/position_discovery.ts +16 -27
  46. package/claw/modules/position_manager.ts +32 -41
  47. package/claw/modules/position_manager_watch.ts +3 -2
  48. package/claw/modules/short_mpa_strategy.ts +1 -9
  49. package/claw/modules/skill_utils.ts +5 -3
  50. package/claw/modules/utils.ts +9 -1
  51. package/claw/package.json +1 -1
  52. package/claw/runtimes/openclaw-plugin/index.ts +27 -10
  53. package/claw/runtimes/openclaw-plugin/openclaw.plugin.json +1 -1
  54. package/claw/runtimes/openclaw-plugin/package.json +1 -1
  55. package/claw/scripts/claw_bridge.ts +1 -1
  56. package/claw/scripts/claw_mcp_server.ts +19 -78
  57. package/claw/scripts/honest_assets_report.ts +19 -84
  58. package/claw/scripts/memu_mcp_server.ts +57 -155
  59. package/claw/tests/test_claw_bridge.ts +6 -2
  60. package/claw/tests/test_claw_mcp_transport.ts +2 -2
  61. package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.js +2 -2
  62. package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.js.map +1 -1
  63. package/dist/analysis/ama_fitting/calibrate_convergence_er.js +1 -1
  64. package/dist/analysis/ama_fitting/calibrate_convergence_er.js.map +1 -1
  65. package/dist/analysis/ama_fitting/optimizer_high_resolution.d.ts.map +1 -1
  66. package/dist/analysis/ama_fitting/optimizer_high_resolution.js +2 -1
  67. package/dist/analysis/ama_fitting/optimizer_high_resolution.js.map +1 -1
  68. package/dist/analysis/analyze_derivatives.d.ts.map +1 -1
  69. package/dist/analysis/analyze_derivatives.js +4 -2
  70. package/dist/analysis/analyze_derivatives.js.map +1 -1
  71. package/dist/analysis/analyze_dynamic_weight.js +3 -1
  72. package/dist/analysis/analyze_dynamic_weight.js.map +1 -1
  73. package/dist/analysis/analyze_kalman.js +3 -1
  74. package/dist/analysis/analyze_kalman.js.map +1 -1
  75. package/dist/analysis/analyze_regime.js +3 -1
  76. package/dist/analysis/analyze_regime.js.map +1 -1
  77. package/dist/analysis/analyze_regime_windows.js +3 -1
  78. package/dist/analysis/analyze_regime_windows.js.map +1 -1
  79. package/dist/analysis/analyze_volatility.js +2 -2
  80. package/dist/analysis/analyze_volatility.js.map +1 -1
  81. package/dist/analysis/bot_fitting/backtest_ama_sweep.d.ts.map +1 -1
  82. package/dist/analysis/bot_fitting/backtest_ama_sweep.js +2 -1
  83. package/dist/analysis/bot_fitting/backtest_ama_sweep.js.map +1 -1
  84. package/dist/analysis/bot_fitting/backtest_bot_fitting.js +18 -13
  85. package/dist/analysis/bot_fitting/backtest_bot_fitting.js.map +1 -1
  86. package/dist/analysis/bot_fitting/shared_utils.d.ts +1 -12
  87. package/dist/analysis/bot_fitting/shared_utils.d.ts.map +1 -1
  88. package/dist/analysis/bot_fitting/shared_utils.js +1 -1
  89. package/dist/analysis/bot_fitting/shared_utils.js.map +1 -1
  90. package/dist/analysis/bot_key_utils.d.ts +1 -1
  91. package/dist/analysis/bot_key_utils.d.ts.map +1 -1
  92. package/dist/analysis/bot_key_utils.js +1 -5
  93. package/dist/analysis/bot_key_utils.js.map +1 -1
  94. package/dist/analysis/bot_usage/kibana_bot_queries.d.ts +1 -337
  95. package/dist/analysis/bot_usage/kibana_bot_queries.d.ts.map +1 -1
  96. package/dist/analysis/bot_usage/kibana_bot_queries.js +1 -241
  97. package/dist/analysis/bot_usage/kibana_bot_queries.js.map +1 -1
  98. package/dist/analysis/chart_css.d.ts +1 -15
  99. package/dist/analysis/chart_css.d.ts.map +1 -1
  100. package/dist/analysis/chart_css.js +1 -1
  101. package/dist/analysis/chart_css.js.map +1 -1
  102. package/dist/analysis/chart_utils.d.ts +0 -3
  103. package/dist/analysis/chart_utils.d.ts.map +1 -1
  104. package/dist/analysis/chart_utils.js +25 -0
  105. package/dist/analysis/chart_utils.js.map +1 -1
  106. package/dist/analysis/derivative_chart_generator.d.ts.map +1 -1
  107. package/dist/analysis/derivative_chart_generator.js +3 -2
  108. package/dist/analysis/derivative_chart_generator.js.map +1 -1
  109. package/dist/analysis/math_utils.d.ts +3 -5
  110. package/dist/analysis/math_utils.d.ts.map +1 -1
  111. package/dist/analysis/math_utils.js +3 -5
  112. package/dist/analysis/math_utils.js.map +1 -1
  113. package/dist/analysis/trend_detection/dynamic_weight_chart_generator.d.ts.map +1 -1
  114. package/dist/analysis/trend_detection/dynamic_weight_chart_generator.js +82 -50
  115. package/dist/analysis/trend_detection/dynamic_weight_chart_generator.js.map +1 -1
  116. package/dist/bot.js +2 -2
  117. package/dist/bot.js.map +1 -1
  118. package/dist/credential-daemon.js +1 -1
  119. package/dist/credential-daemon.js.map +1 -1
  120. package/dist/dexbot.d.ts.map +1 -1
  121. package/dist/dexbot.js +20 -17
  122. package/dist/dexbot.js.map +1 -1
  123. package/dist/market_adapter/ama_signal_runner.js +3 -3
  124. package/dist/market_adapter/core/kibana_client.d.ts +1 -3
  125. package/dist/market_adapter/core/kibana_client.d.ts.map +1 -1
  126. package/dist/market_adapter/core/kibana_client.js +1 -1
  127. package/dist/market_adapter/core/kibana_client.js.map +1 -1
  128. package/dist/market_adapter/core/market_adapter_service.d.ts +1 -2
  129. package/dist/market_adapter/core/market_adapter_service.d.ts.map +1 -1
  130. package/dist/market_adapter/core/market_adapter_service.js +9 -4
  131. package/dist/market_adapter/core/market_adapter_service.js.map +1 -1
  132. package/dist/market_adapter/core/strategies/regime_gate.d.ts +1 -2
  133. package/dist/market_adapter/core/strategies/regime_gate.d.ts.map +1 -1
  134. package/dist/market_adapter/core/strategies/regime_gate.js +1 -1
  135. package/dist/market_adapter/core/strategies/regime_gate.js.map +1 -1
  136. package/dist/market_adapter/inputs/fetch_cex_synthetic_data.js +2 -2
  137. package/dist/market_adapter/inputs/fetch_cex_synthetic_data.js.map +1 -1
  138. package/dist/market_adapter/inputs/fetch_lp_data.d.ts +5 -5
  139. package/dist/market_adapter/inputs/fetch_lp_data.js +5 -5
  140. package/dist/market_adapter/inputs/kibana_source.d.ts +1 -2
  141. package/dist/market_adapter/inputs/kibana_source.d.ts.map +1 -1
  142. package/dist/market_adapter/inputs/kibana_source.js +1 -1
  143. package/dist/market_adapter/inputs/kibana_source.js.map +1 -1
  144. package/dist/market_adapter/lp_chart_strategy_loader.d.ts +1 -2
  145. package/dist/market_adapter/lp_chart_strategy_loader.d.ts.map +1 -1
  146. package/dist/market_adapter/lp_chart_strategy_loader.js +4 -4
  147. package/dist/market_adapter/lp_chart_strategy_loader.js.map +1 -1
  148. package/dist/market_adapter/market_adapter.d.ts.map +1 -1
  149. package/dist/market_adapter/market_adapter.js +2 -1
  150. package/dist/market_adapter/market_adapter.js.map +1 -1
  151. package/dist/modules/account_bots.d.ts +3 -0
  152. package/dist/modules/account_bots.d.ts.map +1 -1
  153. package/dist/modules/account_bots.js +156 -46
  154. package/dist/modules/account_bots.js.map +1 -1
  155. package/dist/modules/account_orders.d.ts +1 -7
  156. package/dist/modules/account_orders.d.ts.map +1 -1
  157. package/dist/modules/account_orders.js +9 -17
  158. package/dist/modules/account_orders.js.map +1 -1
  159. package/dist/modules/bitshares_client.d.ts +2 -14
  160. package/dist/modules/bitshares_client.d.ts.map +1 -1
  161. package/dist/modules/bitshares_client.js +22 -31
  162. package/dist/modules/bitshares_client.js.map +1 -1
  163. package/dist/modules/bot_settings.js +1 -1
  164. package/dist/modules/bot_settings.js.map +1 -1
  165. package/dist/modules/chain_keys.js +2 -2
  166. package/dist/modules/chain_keys.js.map +1 -1
  167. package/dist/modules/chain_orders.d.ts +2 -3
  168. package/dist/modules/chain_orders.d.ts.map +1 -1
  169. package/dist/modules/chain_orders.js +8 -25
  170. package/dist/modules/chain_orders.js.map +1 -1
  171. package/dist/modules/config.d.ts +2 -0
  172. package/dist/modules/config.d.ts.map +1 -1
  173. package/dist/modules/config.js +6 -1
  174. package/dist/modules/config.js.map +1 -1
  175. package/dist/modules/constants.d.ts +0 -1
  176. package/dist/modules/constants.d.ts.map +1 -1
  177. package/dist/modules/constants.js +1 -5
  178. package/dist/modules/constants.js.map +1 -1
  179. package/dist/modules/credential_policy.js +1 -1
  180. package/dist/modules/credential_policy.js.map +1 -1
  181. package/dist/modules/dexbot_class.d.ts.map +1 -1
  182. package/dist/modules/dexbot_class.js +3 -2
  183. package/dist/modules/dexbot_class.js.map +1 -1
  184. package/dist/modules/dexbot_cow_runtime.d.ts +0 -7
  185. package/dist/modules/dexbot_cow_runtime.d.ts.map +1 -1
  186. package/dist/modules/dexbot_cow_runtime.js +95 -0
  187. package/dist/modules/dexbot_cow_runtime.js.map +1 -1
  188. package/dist/modules/dexbot_state_recovery.d.ts.map +1 -1
  189. package/dist/modules/dexbot_state_recovery.js +22 -2
  190. package/dist/modules/dexbot_state_recovery.js.map +1 -1
  191. package/dist/modules/fund_registry.d.ts.map +1 -1
  192. package/dist/modules/fund_registry.js +5 -2
  193. package/dist/modules/fund_registry.js.map +1 -1
  194. package/dist/modules/launcher/bot_supervisor.d.ts.map +1 -1
  195. package/dist/modules/launcher/bot_supervisor.js +6 -7
  196. package/dist/modules/launcher/bot_supervisor.js.map +1 -1
  197. package/dist/modules/launcher/foreign_cred_daemon.d.ts.map +1 -1
  198. package/dist/modules/launcher/foreign_cred_daemon.js +6 -0
  199. package/dist/modules/launcher/foreign_cred_daemon.js.map +1 -1
  200. package/dist/modules/launcher/market_adapter_runtime.d.ts +2 -3
  201. package/dist/modules/launcher/market_adapter_runtime.d.ts.map +1 -1
  202. package/dist/modules/launcher/market_adapter_runtime.js +7 -15
  203. package/dist/modules/launcher/market_adapter_runtime.js.map +1 -1
  204. package/dist/modules/launcher/monolithic_runtime.d.ts.map +1 -1
  205. package/dist/modules/launcher/monolithic_runtime.js +1 -0
  206. package/dist/modules/launcher/monolithic_runtime.js.map +1 -1
  207. package/dist/modules/launcher/status_reporting.d.ts +1 -2
  208. package/dist/modules/launcher/status_reporting.d.ts.map +1 -1
  209. package/dist/modules/launcher/status_reporting.js +1 -4
  210. package/dist/modules/launcher/status_reporting.js.map +1 -1
  211. package/dist/modules/order/accounting.js +2 -2
  212. package/dist/modules/order/accounting.js.map +1 -1
  213. package/dist/modules/order/format.d.ts +0 -8
  214. package/dist/modules/order/format.d.ts.map +1 -1
  215. package/dist/modules/order/format.js +0 -8
  216. package/dist/modules/order/format.js.map +1 -1
  217. package/dist/modules/order/grid.d.ts.map +1 -1
  218. package/dist/modules/order/grid.js +146 -32
  219. package/dist/modules/order/grid.js.map +1 -1
  220. package/dist/modules/order/logger.js +1 -1
  221. package/dist/modules/order/logger.js.map +1 -1
  222. package/dist/modules/order/logger_state.d.ts +1 -13
  223. package/dist/modules/order/logger_state.d.ts.map +1 -1
  224. package/dist/modules/order/logger_state.js +1 -11
  225. package/dist/modules/order/logger_state.js.map +1 -1
  226. package/dist/modules/order/manager.d.ts +13 -0
  227. package/dist/modules/order/manager.d.ts.map +1 -1
  228. package/dist/modules/order/manager.js +75 -2
  229. package/dist/modules/order/manager.js.map +1 -1
  230. package/dist/modules/order/processed_fill_store.d.ts +0 -5
  231. package/dist/modules/order/processed_fill_store.d.ts.map +1 -1
  232. package/dist/modules/order/processed_fill_store.js +1 -12
  233. package/dist/modules/order/processed_fill_store.js.map +1 -1
  234. package/dist/modules/order/sync_engine.d.ts.map +1 -1
  235. package/dist/modules/order/sync_engine.js +10 -3
  236. package/dist/modules/order/sync_engine.js.map +1 -1
  237. package/dist/modules/order/utils/math.d.ts +80 -1
  238. package/dist/modules/order/utils/math.d.ts.map +1 -1
  239. package/dist/modules/order/utils/math.js +138 -2
  240. package/dist/modules/order/utils/math.js.map +1 -1
  241. package/dist/modules/order/utils/order.d.ts.map +1 -1
  242. package/dist/modules/order/utils/order.js +10 -2
  243. package/dist/modules/order/utils/order.js.map +1 -1
  244. package/dist/modules/paths.d.ts +26 -1
  245. package/dist/modules/paths.d.ts.map +1 -1
  246. package/dist/modules/paths.js +39 -6
  247. package/dist/modules/paths.js.map +1 -1
  248. package/dist/modules/runtime_settings.js +3 -1
  249. package/dist/modules/runtime_settings.js.map +1 -1
  250. package/dist/modules/settings_merge.d.ts.map +1 -1
  251. package/dist/modules/settings_merge.js +3 -1
  252. package/dist/modules/settings_merge.js.map +1 -1
  253. package/dist/modules/storage/browser_adapter.d.ts +8 -3
  254. package/dist/modules/storage/browser_adapter.d.ts.map +1 -1
  255. package/dist/modules/storage/browser_adapter.js +53 -4
  256. package/dist/modules/storage/browser_adapter.js.map +1 -1
  257. package/dist/modules/utils/sanitize_key.d.ts +7 -0
  258. package/dist/modules/utils/sanitize_key.d.ts.map +1 -0
  259. package/dist/modules/utils/sanitize_key.js +15 -0
  260. package/dist/modules/utils/sanitize_key.js.map +1 -0
  261. package/dist/pm2.js +6 -6
  262. package/dist/pm2.js.map +1 -1
  263. package/dist/scripts/analyze-git.js +2 -1
  264. package/dist/scripts/analyze-git.js.map +1 -1
  265. package/dist/scripts/analyze-orders.d.ts +2 -2
  266. package/dist/scripts/analyze-orders.d.ts.map +1 -1
  267. package/dist/scripts/analyze-orders.js +6 -14
  268. package/dist/scripts/analyze-orders.js.map +1 -1
  269. package/dist/scripts/runner.js +1 -1
  270. package/dist/scripts/runner.js.map +1 -1
  271. package/dist/scripts/update.js +1 -1
  272. package/dist/scripts/update.js.map +1 -1
  273. package/docs/BITSHARES_ONBOARDING.md +63 -18
  274. package/docs/COPY_ON_WRITE_MASTER_PLAN.md +5 -14
  275. package/docs/COW_INVARIANTS.md +4 -4
  276. package/docs/CREDENTIAL_SECURITY.md +0 -11
  277. package/docs/DEXBOT_COMPARISON.md +11 -11
  278. package/docs/EVOLUTION.md +12 -10
  279. package/docs/FUND_MOVEMENT_AND_ACCOUNTING.md +27 -83
  280. package/docs/GRID_RECALCULATION.md +1 -13
  281. package/docs/GRID_RECONCILE.md +24 -24
  282. package/docs/LIFECYCLE.md +4 -4
  283. package/docs/LOGGING.md +1 -1
  284. package/docs/MPA_CREDIT_USAGE.md +3 -3
  285. package/docs/README.md +2 -2
  286. package/docs/WORKFLOW.md +2 -2
  287. package/docs/architecture.md +43 -38
  288. package/docs/developer_guide.md +16 -18
  289. package/market_adapter/README.md +0 -2
  290. package/modules/README.md +2 -1
  291. package/package.json +2 -3
  292. package/scripts/README.md +1 -1
  293. package/scripts/lib/dexbot-paths.sh +20 -11
  294. package/claw/openclaw.plugin.json +0 -13
  295. package/dist/market_adapter/merge_lp_data.d.ts +0 -3
  296. package/dist/market_adapter/merge_lp_data.d.ts.map +0 -1
  297. package/dist/market_adapter/merge_lp_data.js +0 -125
  298. package/dist/market_adapter/merge_lp_data.js.map +0 -1
  299. package/dist/market_adapter/utils/paths.d.ts +0 -3
  300. package/dist/market_adapter/utils/paths.d.ts.map +0 -1
  301. package/dist/market_adapter/utils/paths.js +0 -5
  302. package/dist/market_adapter/utils/paths.js.map +0 -1
@@ -32,6 +32,40 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
32
32
  const results = data.allResults || [];
33
33
  if (results.length === 0) throw new Error('No analysis results in input');
34
34
 
35
+ // Slider ranges — single source of truth for HTML attrs, tooltips,
36
+ // payload transport, and client paste-clamp bounds.
37
+ const LB_MIN = 1, LB_MAX = 32;
38
+ const GAIN_MIN = 0.5, GAIN_MAX = 2.0;
39
+ const AMA_MS_MIN = 0.04, AMA_MS_MAX = 0.12;
40
+ const KAL_MS_MIN = 0.5, KAL_MS_MAX = 1.5;
41
+ const CLIP_PCT_MAX = 20;
42
+ const TH_MIN = 0, TH_MAX = 0.5;
43
+ const KF_MIN = 0, KF_MAX = 200;
44
+ const KFD_MIN = 1.0, KFD_MAX = 3.0;
45
+ const DSP_MIN = 0.25, DSP_MAX = 4.0;
46
+ const KDT_MIN = 0.25, KDT_MAX = 3.0;
47
+ const KFS_MIN = 20, KFS_MAX = 200;
48
+ const CF_MIN = 0, CF_MAX = 5;
49
+ const REGI_MIN = 0, REGI_MAX = 2;
50
+ const SLIDER_RANGES = {
51
+ alpha: [0, 1],
52
+ dispWeight: [0, 1],
53
+ neutralZonePct: [0, 1],
54
+ lookbackBars: [LB_MIN, LB_MAX],
55
+ amaMaxSlopePct: [AMA_MS_MIN, AMA_MS_MAX],
56
+ kalmanMaxSlopePct: [KAL_MS_MIN, KAL_MS_MAX],
57
+ clipPct: [0, CLIP_PCT_MAX],
58
+ minOutputThreshold: [TH_MIN, TH_MAX],
59
+ kalmanSmoothPct: [KF_MIN, KF_MAX],
60
+ kalmanDispScaleMult: [KFD_MIN, KFD_MAX],
61
+ dispScaleMinPct: [DSP_MIN, DSP_MAX],
62
+ kalmanDispThresholdMult: [KDT_MIN, KDT_MAX],
63
+ kalmanSmoothSpanPct: [KFS_MIN, KFS_MAX],
64
+ signalConfirmBars: [CF_MIN, CF_MAX],
65
+ gain: [GAIN_MIN, GAIN_MAX],
66
+ regimeSensitivity: [REGI_MIN, REGI_MAX],
67
+ };
68
+
35
69
  const ma = data.marketAdapter || {};
36
70
  const amaWeightConfig = data.amaWeightConfig || {};
37
71
  const defaultAlpha = data.alpha ?? ma.alpha ?? MARKET_ADAPTER.DYNAMIC_WEIGHT_ALPHA;
@@ -47,30 +81,26 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
47
81
  ?? MARKET_ADAPTER.DYNAMIC_WEIGHT_KALMAN_MAX_SLOPE_PCT;
48
82
  const defaultClipPct = data.clipPct ?? ma.clipPercentile ?? MARKET_ADAPTER.DYNAMIC_WEIGHT_CLIP_PERCENTILE;
49
83
  const defaultMinOutputThresholdRaw = data.minOutputThreshold ?? ma.minOutputThreshold ?? MARKET_ADAPTER.DYNAMIC_WEIGHT_ASYMMETRIC_TREND_THRESHOLD;
50
- const defaultMinOutputThreshold = Math.min(Math.max(defaultMinOutputThresholdRaw, 0), 0.5);
84
+ const defaultMinOutputThreshold = Math.min(Math.max(defaultMinOutputThresholdRaw, TH_MIN), TH_MAX);
51
85
  const defaultOutputClamp = data.outputClamp ?? ma.outputClamp ?? MARKET_ADAPTER.DYNAMIC_WEIGHT_ASYMMETRIC_OFFSET_CLAMP;
52
86
  const lookbackBarsRaw = amaWeightConfig.lookbackBars ?? ma.amaLookbackBars ?? MARKET_ADAPTER.DYNAMIC_WEIGHT_AMA_LOOKBACK_BARS;
53
- const lookbackBars = Math.ceil(Math.max(1, Math.min(32, Number.isFinite(lookbackBarsRaw) ? lookbackBarsRaw : 1)));
87
+ const lookbackBars = Math.ceil(Math.max(LB_MIN, Math.min(LB_MAX, Number.isFinite(lookbackBarsRaw) ? lookbackBarsRaw : LB_MIN)));
54
88
 
55
- // Log mapping for lookback slider (1 to 32 bars)
56
- const LB_LOG_MIN_N = Math.log(1);
57
- const LB_LOG_MAX_N = Math.log(32);
58
- const clampedLb = Math.min(Math.max(lookbackBars, 1), 32);
89
+ // Log mapping for lookback slider
90
+ const LB_LOG_MIN_N = Math.log(LB_MIN);
91
+ const LB_LOG_MAX_N = Math.log(LB_MAX);
92
+ const clampedLb = Math.min(Math.max(lookbackBars, LB_MIN), LB_MAX);
59
93
  const lbInitSlider = Math.round((Math.log(clampedLb) - LB_LOG_MIN_N) / (LB_LOG_MAX_N - LB_LOG_MIN_N) * 1000);
60
94
 
61
95
  // Log mapping for gain slider
62
- const GAIN_LOG_MIN_N = Math.log(0.5);
63
- const GAIN_LOG_MAX_N = Math.log(2.0);
64
- const clampedGain = Math.min(Math.max(defaultGain, 0.5), 2.0);
96
+ const GAIN_LOG_MIN_N = Math.log(GAIN_MIN);
97
+ const GAIN_LOG_MAX_N = Math.log(GAIN_MAX);
98
+ const clampedGain = Math.min(Math.max(defaultGain, GAIN_MIN), GAIN_MAX);
65
99
  const gainInitSlider = Math.round((Math.log(clampedGain) - GAIN_LOG_MIN_N) / (GAIN_LOG_MAX_N - GAIN_LOG_MIN_N) * 1000);
66
100
 
67
101
  // Log mapping for slope saturation sliders
68
- const AMA_MS_MIN = 0.04;
69
- const AMA_MS_MAX = 0.12;
70
102
  const AMA_MS_LOG_MIN_N = Math.log(AMA_MS_MIN);
71
103
  const AMA_MS_LOG_MAX_N = Math.log(AMA_MS_MAX);
72
- const KAL_MS_MIN = 0.15;
73
- const KAL_MS_MAX = 1.5;
74
104
  const KAL_MS_LOG_MIN_N = Math.log(KAL_MS_MIN);
75
105
  const KAL_MS_LOG_MAX_N = Math.log(KAL_MS_MAX);
76
106
  const clampedAmaMs = Math.min(Math.max(defaultAmaMaxSlopePct, AMA_MS_MIN), AMA_MS_MAX);
@@ -100,12 +130,15 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
100
130
  const amaSlopePct = results.map((r: any) => r.amaSlopePct ?? null);
101
131
  const kalmanVelocityPctRaw = results.map((r: any) => r.velocityRawPct ?? r.velocityPct ?? null);
102
132
  const kalmanDisplacementPct = results.map((r: any) => r.displacementRawPct ?? r.displacementPct ?? null);
103
- const kalmanVelocityPct = buildKalmanVelocitySeries(results, {
104
- kalmanSmoothPct: defaultKalmanSmoothPct,
105
- kalmanDispScaleMult: defaultKalmanDispScaleMult,
106
- kalmanDispThresholdMult: defaultKalmanDispThresholdMult,
107
- kalmanSmoothSpanPct: defaultKalmanSmoothSpanPct,
108
- });
133
+ const kalmanVelocityPct = buildKalmanVelocitySeries(
134
+ results.map((r: any) => ({ velocityPct: r.velocityRawPct ?? r.velocityPct ?? null, displacementPct: r.displacementRawPct ?? r.displacementPct ?? null })),
135
+ {
136
+ kalmanSmoothPct: defaultKalmanSmoothPct,
137
+ kalmanDispScaleMult: defaultKalmanDispScaleMult,
138
+ kalmanDispThresholdMult: defaultKalmanDispThresholdMult,
139
+ kalmanSmoothSpanPct: defaultKalmanSmoothSpanPct,
140
+ }
141
+ );
109
142
  const kalmanIsReady = results.map((r: any) => r.isReady ?? false);
110
143
  const signals = results.map((r: any) => r.signal);
111
144
  const amaLabel = data.amaKey || 'AMA3';
@@ -317,24 +350,24 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
317
350
 
318
351
  <div class="group-sep"></div>
319
352
  <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>
320
- <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 (1-32)"><span class="val" id="lb-value">${lookbackBars}</span></div>
321
- <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 (0.04-0.12)"><span class="val" id="ama-ms-value">${defaultAmaMaxSlopePct.toFixed(4)}</span></div>
322
- <div class="ctrl clip"><label for="clip-slider">clip%</label><input type="range" id="clip-slider" min="0" max="55" value="${Math.min(defaultClipPct, 55)}" title="Outlier Clip %"><span class="val" id="clip-value">${Math.min(defaultClipPct, 55)}%</span></div>
353
+ <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>
354
+ <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>
355
+ <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>
323
356
 
324
357
  <div class="group-sep"></div>
325
- <div class="ctrl th"><label for="th-slider">th%</label><input type="range" id="th-slider" min="0" max="50" value="${Math.round(defaultMinOutputThreshold * 100)}" title="Minimum pre-gain blended output required before the signal is allowed through (0.00-0.50)"><span class="val" id="th-value">${defaultMinOutputThreshold.toFixed(2)}</span></div>
358
+ <div class="ctrl th"><label for="th-slider">th%</label><input type="range" id="th-slider" min="0" max="${TH_MAX * 100}" value="${Math.round(defaultMinOutputThreshold * 100)}" title="Minimum pre-gain blended output required before the signal is allowed through (${TH_MIN.toFixed(2)}-${TH_MAX.toFixed(2)})"><span class="val" id="th-value">${defaultMinOutputThreshold.toFixed(2)}</span></div>
326
359
 
327
360
  <div class="group-sep"></div>
328
361
  <div class="row-break"></div>
329
- <div class="ctrl ms-kal"><label for="kal-ms-slider">kalS%</label><input type="range" id="kal-ms-slider" min="0" max="1000" value="${kalMsInitSlider}" title="Kalman Max Slope % (0.15-1.5)"><span class="val" id="kal-ms-value">${clampedKalMs.toFixed(2)}</span></div>
330
- <div class="ctrl kf"><label for="kf-slider">kf</label><input type="range" id="kf-slider" min="0" max="200" value="${defaultKalmanSmoothPct}" title="Kalman smoothing blend (0 = raw, 100 = current adaptive smoothing, 200 = stronger smoothing)"><span class="val" id="kf-value">${defaultKalmanSmoothPct}%</span></div>
331
- <div class="ctrl kfd"><label for="kfd-slider">kfd</label><input type="range" id="kfd-slider" min="100" max="300" value="${Math.round(defaultKalmanDispScaleMult * 100)}" title="Kalman displacement scale multiplier (1x to 3x)"><span class="val" id="kfd-value">${defaultKalmanDispScaleMult.toFixed(2)}x</span></div>
332
- <div class="ctrl dsp"><label for="dsp-slider">dsp</label><input type="range" id="dsp-slider" min="25" max="400" value="${Math.round(defaultDispScaleMinPct * 100)}" title="Minimum displacement scale floor (0.25x to 4.0x)"><span class="val" id="dsp-value">${defaultDispScaleMinPct.toFixed(2)}x</span></div>
333
- <div class="ctrl kdt"><label for="kdt-slider">kdt</label><input type="range" id="kdt-slider" min="25" max="300" value="${Math.round(defaultKalmanDispThresholdMult * 100)}" title="Kalman displacement threshold multiplier (0.25x to 3x)"><span class="val" id="kdt-value">${defaultKalmanDispThresholdMult.toFixed(2)}x</span></div>
334
- <div class="ctrl kfs"><label for="kfs-slider">kfs</label><input type="range" id="kfs-slider" min="20" max="200" value="${defaultKalmanSmoothSpanPct}" title="Adaptive EMA span ratio (20% span / 200% span; floor fixed at 0)"><span class="val" id="kfs-value">${defaultKalmanSmoothSpanPct}%</span></div>
335
- <div class="ctrl cf"><label for="cf-slider">cf</label><input type="range" id="cf-slider" min="0" max="5" value="${defaultSignalConfirmBars}" title="Signal confirmation bars (0 disables latching; otherwise flips after N opposite echo bars)"><span class="val" id="cf-value">${defaultSignalConfirmBars}</span></div>
336
- <div class="ctrl off"><label for="gain-slider">gain</label><input type="range" id="gain-slider" min="0" max="1000" value="${gainInitSlider}" title="Output Gain (0.5-2.0)"><span class="val" id="gain-value">${clampedGain.toFixed(3)}</span></div>
337
- <div class="ctrl regime"><label for="regime-slider">regi</label><input type="range" id="regime-slider" min="0" max="200" value="${regimeInitSlider}" title="Regime Sensitivity"><span class="val" id="regime-value">${defaultRegimeSensitivity.toFixed(2)}</span></div>
362
+ <div class="ctrl ms-kal"><label for="kal-ms-slider">kalS%</label><input type="range" id="kal-ms-slider" min="0" max="1000" value="${kalMsInitSlider}" title="Kalman Max Slope % (${KAL_MS_MIN}-${KAL_MS_MAX})"><span class="val" id="kal-ms-value">${clampedKalMs.toFixed(2)}</span></div>
363
+ <div class="ctrl kf"><label for="kf-slider">kf</label><input type="range" id="kf-slider" min="${KF_MIN}" max="${KF_MAX}" value="${defaultKalmanSmoothPct}" title="Kalman smoothing blend (${KF_MIN} = raw, 100 = current adaptive smoothing, ${KF_MAX} = stronger smoothing)"><span class="val" id="kf-value">${defaultKalmanSmoothPct}%</span></div>
364
+ <div class="ctrl kfd"><label for="kfd-slider">kfd</label><input type="range" id="kfd-slider" min="${KFD_MIN * 100}" max="${KFD_MAX * 100}" value="${Math.round(defaultKalmanDispScaleMult * 100)}" title="Kalman displacement scale multiplier (${KFD_MIN}x to ${KFD_MAX}x)"><span class="val" id="kfd-value">${defaultKalmanDispScaleMult.toFixed(2)}x</span></div>
365
+ <div class="ctrl dsp"><label for="dsp-slider">dsp</label><input type="range" id="dsp-slider" min="${DSP_MIN * 100}" max="${DSP_MAX * 100}" value="${Math.round(defaultDispScaleMinPct * 100)}" title="Minimum displacement scale floor (${DSP_MIN}x to ${DSP_MAX.toFixed(1)}x)"><span class="val" id="dsp-value">${defaultDispScaleMinPct.toFixed(2)}x</span></div>
366
+ <div class="ctrl kdt"><label for="kdt-slider">kdt</label><input type="range" id="kdt-slider" min="${KDT_MIN * 100}" max="${KDT_MAX * 100}" value="${Math.round(defaultKalmanDispThresholdMult * 100)}" title="Kalman displacement threshold multiplier (${KDT_MIN}x to ${KDT_MAX}x)"><span class="val" id="kdt-value">${defaultKalmanDispThresholdMult.toFixed(2)}x</span></div>
367
+ <div class="ctrl kfs"><label for="kfs-slider">kfs</label><input type="range" id="kfs-slider" min="${KFS_MIN}" max="${KFS_MAX}" value="${defaultKalmanSmoothSpanPct}" title="Adaptive EMA span ratio (${KFS_MIN}% span / ${KFS_MAX}% span; floor fixed at 0)"><span class="val" id="kfs-value">${defaultKalmanSmoothSpanPct}%</span></div>
368
+ <div class="ctrl cf"><label for="cf-slider">cf</label><input type="range" id="cf-slider" min="${CF_MIN}" max="${CF_MAX}" value="${defaultSignalConfirmBars}" title="Signal confirmation bars (0 disables latching; otherwise flips after N opposite echo bars)"><span class="val" id="cf-value">${defaultSignalConfirmBars}</span></div>
369
+ <div class="ctrl off"><label for="gain-slider">gain</label><input type="range" id="gain-slider" min="0" max="1000" value="${gainInitSlider}" title="Output Gain (${GAIN_MIN.toFixed(1)}-${GAIN_MAX.toFixed(1)})"><span class="val" id="gain-value">${clampedGain.toFixed(3)}</span></div>
370
+ <div class="ctrl regime"><label for="regime-slider">regi</label><input type="range" id="regime-slider" min="0" max="${REGI_MAX * 100}" value="${regimeInitSlider}" title="Regime Sensitivity"><span class="val" id="regime-value">${defaultRegimeSensitivity.toFixed(2)}</span></div>
338
371
  <button class="copy-btn" id="copy-params-btn">copy</button>
339
372
  <button class="paste-btn" id="paste-params-btn">paste</button>
340
373
  </div>
@@ -351,7 +384,7 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
351
384
  </div>
352
385
  </div>
353
386
 
354
- <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, 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>
387
+ <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>
355
388
 
356
389
  <script>
357
390
  const data = JSON.parse(document.getElementById('payload').textContent);
@@ -362,6 +395,7 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
362
395
  const Y_AXIS_SIZE = ${Y_AXIS_SIZE};
363
396
  const ma = data.marketAdapter || {};
364
397
  const amaWeightConfig = data.amaWeightConfig || {};
398
+ const SR = data.sliderRanges ?? ${serializeJsonForScript(SLIDER_RANGES)};
365
399
 
366
400
  const ABSOLUTE_THRESHOLD = data.absoluteThreshold ?? ${JSON.stringify(defaultAbsoluteThreshold)};
367
401
  const WEIGHT_MIN = data.weightMin ?? ${JSON.stringify(MARKET_ADAPTER.DYNAMIC_WEIGHT_MIN_WEIGHT)};
@@ -373,7 +407,7 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
373
407
 
374
408
  let currentAlpha = data.alpha ?? ${JSON.stringify(defaultAlpha)};
375
409
  let currentGain = data.gain ?? ${JSON.stringify(defaultGain)};
376
- let currentMinOutputThreshold = Math.min(Math.max(data.minOutputThreshold ?? ${JSON.stringify(defaultMinOutputThreshold)}, 0), 0.5);
410
+ let currentMinOutputThreshold = Math.min(Math.max(data.minOutputThreshold ?? ${JSON.stringify(defaultMinOutputThreshold)}, SR.minOutputThreshold[0]), SR.minOutputThreshold[1]);
377
411
  let currentKalmanSmoothPct = data.kalmanSmoothPct ?? ${JSON.stringify(defaultKalmanSmoothPct)};
378
412
  let currentKalmanDispScaleMult = data.kalmanDispScaleMult ?? ${JSON.stringify(defaultKalmanDispScaleMult)};
379
413
  let currentKalmanDispThresholdMult = data.kalmanDispThresholdMult ?? ${JSON.stringify(defaultKalmanDispThresholdMult)};
@@ -395,7 +429,7 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
395
429
  const LB_LOG_MIN = data.lbLogMin;
396
430
  const LB_LOG_MAX = data.lbLogMax;
397
431
  const lbSliderToVal = (pos) => Math.round(Math.exp(LB_LOG_MIN + (pos / 1000) * (LB_LOG_MAX - LB_LOG_MIN)));
398
- const lbValToSlider = (val) => Math.round((Math.log(Math.max(1, val)) - LB_LOG_MIN) / (LB_LOG_MAX - LB_LOG_MIN) * 1000);
432
+ const lbValToSlider = (val) => Math.round((Math.log(Math.max(SR.lookbackBars[0], val)) - LB_LOG_MIN) / (LB_LOG_MAX - LB_LOG_MIN) * 1000);
399
433
 
400
434
  const GAIN_LOG_MIN = data.gainLogMin;
401
435
  const GAIN_LOG_MAX = data.gainLogMax;
@@ -482,7 +516,7 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
482
516
  }
483
517
 
484
518
  function recalcLatchedSignals() {
485
- const confirmBars = Math.max(0, Math.min(5, currentSignalConfirmBars));
519
+ const confirmBars = Math.max(SR.signalConfirmBars[0], Math.min(SR.signalConfirmBars[1], currentSignalConfirmBars));
486
520
  if (confirmBars === 0) {
487
521
  for (let i = 0; i < data.dates.length; i++) {
488
522
  currentLatchedSignals[i] = data.signals[i] || null;
@@ -560,8 +594,10 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
560
594
  if (currentClipPct > 0) {
561
595
  const slopes = [];
562
596
  for (let i = amaReadyBar; i < data.realBarCount; i++) {
563
- const s = computeSlopeAtIndex(i, lb);
564
- if (s !== 0) slopes.push(Math.abs(s));
597
+ // Keep every finite slope (zeros included) — matches the live
598
+ // market adapter service clip pool exactly.
599
+ const s = computeAverageAmaSlopePct(data.ama3Prices[i], data.ama3Prices[i - lb], lb);
600
+ if (Number.isFinite(s)) slopes.push(Math.abs(s));
565
601
  }
566
602
  if (slopes.length > 0) {
567
603
  slopes.sort((a, b) => a - b);
@@ -1079,7 +1115,7 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
1079
1115
  });
1080
1116
 
1081
1117
  document.getElementById('th-slider').addEventListener('input', (e) => {
1082
- currentMinOutputThreshold = Math.min(Math.max(parseInt(e.target.value, 10) / 100, 0), 0.5);
1118
+ currentMinOutputThreshold = Math.min(Math.max(parseInt(e.target.value, 10) / 100, SR.minOutputThreshold[0]), SR.minOutputThreshold[1]);
1083
1119
  document.getElementById('th-value').textContent = currentMinOutputThreshold.toFixed(2);
1084
1120
  recalcWeights();
1085
1121
  refreshChartsPreservingZoom();
@@ -1157,67 +1193,67 @@ function generateHTML(data: any, title = 'Dynamic Weight Research') {
1157
1193
  function applyParams(p, btn) {
1158
1194
  if (typeof p !== 'object' || p === null) throw new Error('not an object');
1159
1195
  if (p.alpha != null) {
1160
- currentAlpha = Math.max(0, Math.min(1, p.alpha));
1196
+ currentAlpha = Math.max(SR.alpha[0], Math.min(SR.alpha[1], p.alpha));
1161
1197
  document.getElementById('alpha-slider').value = Math.round(currentAlpha * 100);
1162
1198
  document.getElementById('alpha-value').textContent = currentAlpha.toFixed(2);
1163
1199
  }
1164
1200
  if (p.dispWeight != null) {
1165
- currentDw = Math.max(0, Math.min(1, p.dispWeight));
1201
+ currentDw = Math.max(SR.dispWeight[0], Math.min(SR.dispWeight[1], p.dispWeight));
1166
1202
  document.getElementById('dw-slider').value = Math.round(currentDw * 100);
1167
1203
  document.getElementById('dw-value').textContent = currentDw.toFixed(2);
1168
1204
  }
1169
1205
  if (p.amaMaxSlopePct != null) {
1170
- currentAmaMaxSlopePct = Math.max(0.01, Math.min(0.5, p.amaMaxSlopePct));
1206
+ currentAmaMaxSlopePct = Math.max(SR.amaMaxSlopePct[0], Math.min(SR.amaMaxSlopePct[1], p.amaMaxSlopePct));
1171
1207
  document.getElementById('ama-ms-slider').value = Math.round((Math.log(currentAmaMaxSlopePct) - AMA_MS_LOG_MIN) / (AMA_MS_LOG_MAX - AMA_MS_LOG_MIN) * 1000);
1172
1208
  document.getElementById('ama-ms-value').textContent = currentAmaMaxSlopePct.toFixed(4);
1173
1209
  }
1174
1210
  if (p.kalmanMaxSlopePct != null) {
1175
- currentKalmanMaxSlopePct = Math.max(0.15, Math.min(1.5, p.kalmanMaxSlopePct));
1211
+ currentKalmanMaxSlopePct = Math.max(SR.kalmanMaxSlopePct[0], Math.min(SR.kalmanMaxSlopePct[1], p.kalmanMaxSlopePct));
1176
1212
  document.getElementById('kal-ms-slider').value = Math.round((Math.log(currentKalmanMaxSlopePct) - KAL_MS_LOG_MIN) / (KAL_MS_LOG_MAX - KAL_MS_LOG_MIN) * 1000);
1177
1213
  document.getElementById('kal-ms-value').textContent = currentKalmanMaxSlopePct.toFixed(2);
1178
1214
  }
1179
1215
  if (p.gain != null) {
1180
- currentGain = Math.max(0.5, Math.min(2.0, p.gain));
1216
+ currentGain = Math.max(SR.gain[0], Math.min(SR.gain[1], p.gain));
1181
1217
  document.getElementById('gain-slider').value = gainValToSlider(currentGain);
1182
1218
  document.getElementById('gain-value').textContent = currentGain.toFixed(3);
1183
1219
  }
1184
1220
  if (p.minOutputThreshold != null) {
1185
- currentMinOutputThreshold = Math.max(0, Math.min(0.5, p.minOutputThreshold));
1221
+ currentMinOutputThreshold = Math.max(SR.minOutputThreshold[0], Math.min(SR.minOutputThreshold[1], p.minOutputThreshold));
1186
1222
  document.getElementById('th-slider').value = Math.round(currentMinOutputThreshold * 100);
1187
1223
  document.getElementById('th-value').textContent = currentMinOutputThreshold.toFixed(2);
1188
1224
  }
1189
1225
  if (p.kalmanSmoothPct != null) {
1190
- currentKalmanSmoothPct = Math.max(0, Math.min(200, Math.round(p.kalmanSmoothPct)));
1226
+ currentKalmanSmoothPct = Math.max(SR.kalmanSmoothPct[0], Math.min(SR.kalmanSmoothPct[1], Math.round(p.kalmanSmoothPct)));
1191
1227
  document.getElementById('kf-slider').value = currentKalmanSmoothPct;
1192
1228
  document.getElementById('kf-value').textContent = currentKalmanSmoothPct + '%';
1193
1229
  }
1194
1230
  if (p.kalmanDispScaleMult != null) {
1195
- currentKalmanDispScaleMult = Math.max(1.0, Math.min(3.0, p.kalmanDispScaleMult));
1231
+ currentKalmanDispScaleMult = Math.max(SR.kalmanDispScaleMult[0], Math.min(SR.kalmanDispScaleMult[1], p.kalmanDispScaleMult));
1196
1232
  document.getElementById('kfd-slider').value = Math.round(currentKalmanDispScaleMult * 100);
1197
1233
  document.getElementById('kfd-value').textContent = currentKalmanDispScaleMult.toFixed(2) + 'x';
1198
1234
  }
1199
1235
  if (p.dispScaleMinPct != null) {
1200
- currentDispScaleMinPct = Math.max(0.25, Math.min(4.0, p.dispScaleMinPct));
1236
+ currentDispScaleMinPct = Math.max(SR.dispScaleMinPct[0], Math.min(SR.dispScaleMinPct[1], p.dispScaleMinPct));
1201
1237
  document.getElementById('dsp-slider').value = Math.round(currentDispScaleMinPct * 100);
1202
1238
  document.getElementById('dsp-value').textContent = currentDispScaleMinPct.toFixed(2) + 'x';
1203
1239
  }
1204
1240
  if (p.kalmanDispThresholdMult != null) {
1205
- currentKalmanDispThresholdMult = Math.max(0.25, Math.min(3.0, p.kalmanDispThresholdMult));
1241
+ currentKalmanDispThresholdMult = Math.max(SR.kalmanDispThresholdMult[0], Math.min(SR.kalmanDispThresholdMult[1], p.kalmanDispThresholdMult));
1206
1242
  document.getElementById('kdt-slider').value = Math.round(currentKalmanDispThresholdMult * 100);
1207
1243
  document.getElementById('kdt-value').textContent = currentKalmanDispThresholdMult.toFixed(2) + 'x';
1208
1244
  }
1209
1245
  if (p.kalmanSmoothSpanPct != null) {
1210
- currentKalmanSmoothSpanPct = Math.max(20, Math.min(200, Math.round(p.kalmanSmoothSpanPct)));
1246
+ currentKalmanSmoothSpanPct = Math.max(SR.kalmanSmoothSpanPct[0], Math.min(SR.kalmanSmoothSpanPct[1], Math.round(p.kalmanSmoothSpanPct)));
1211
1247
  document.getElementById('kfs-slider').value = currentKalmanSmoothSpanPct;
1212
1248
  document.getElementById('kfs-value').textContent = currentKalmanSmoothSpanPct + '%';
1213
1249
  }
1214
1250
  if (p.signalConfirmBars != null) {
1215
- currentSignalConfirmBars = Math.max(0, Math.min(5, Math.round(p.signalConfirmBars)));
1251
+ currentSignalConfirmBars = Math.max(SR.signalConfirmBars[0], Math.min(SR.signalConfirmBars[1], Math.round(p.signalConfirmBars)));
1216
1252
  document.getElementById('cf-slider').value = currentSignalConfirmBars;
1217
1253
  document.getElementById('cf-value').textContent = currentSignalConfirmBars;
1218
1254
  }
1219
1255
  if (p.clipPct != null) {
1220
- currentClipPct = Math.max(0, Math.min(55, Math.round(p.clipPct)));
1256
+ currentClipPct = Math.max(SR.clipPct[0], Math.min(SR.clipPct[1], Math.round(p.clipPct)));
1221
1257
  document.getElementById('clip-slider').value = currentClipPct;
1222
1258
  document.getElementById('clip-value').textContent = currentClipPct + '%';
1223
1259
  if (currentClipPct === 0) {
@@ -1229,17 +1265,17 @@ function applyParams(p, btn) {
1229
1265
  }
1230
1266
  }
1231
1267
  if (p.neutralZonePct != null) {
1232
- currentNz = Math.max(0, Math.min(1, p.neutralZonePct));
1268
+ currentNz = Math.max(SR.neutralZonePct[0], Math.min(SR.neutralZonePct[1], p.neutralZonePct));
1233
1269
  document.getElementById('nz-slider').value = Math.round(currentNz * 100);
1234
1270
  document.getElementById('nz-value').textContent = currentNz.toFixed(2);
1235
1271
  }
1236
1272
  if (p.regimeSensitivity != null) {
1237
- currentRegimeSensitivity = Math.max(0, Math.min(2, p.regimeSensitivity));
1273
+ currentRegimeSensitivity = Math.max(SR.regimeSensitivity[0], Math.min(SR.regimeSensitivity[1], p.regimeSensitivity));
1238
1274
  document.getElementById('regime-slider').value = Math.round(currentRegimeSensitivity * 100);
1239
1275
  document.getElementById('regime-value').textContent = currentRegimeSensitivity.toFixed(2);
1240
1276
  }
1241
1277
  if (p.lookbackBars != null) {
1242
- currentLookbackBars = Math.max(1, Math.min(32, Math.round(p.lookbackBars)));
1278
+ currentLookbackBars = Math.max(SR.lookbackBars[0], Math.min(SR.lookbackBars[1], Math.round(p.lookbackBars)));
1243
1279
  document.getElementById('lb-slider').value = lbValToSlider(currentLookbackBars);
1244
1280
  document.getElementById('lb-value').textContent = currentLookbackBars;
1245
1281
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trend-detection",
3
- "version": "1.4.19",
3
+ "version": "1.4.21",
4
4
  "description": "Kalman filter trend detection with tactical/modal state tracking",
5
5
  "main": "../../dist/analysis/trend_detection/kalman_trend_analyzer.js",
6
6
  "scripts": {
@@ -2,9 +2,8 @@
2
2
 
3
3
  const path = require('node:path');
4
4
 
5
- // The compiled ecosystem config (claw/ecosystem.config.ts → dist/claw/) anchors
6
- // all paths to the dist/claw build output. This committed .cjs mirrors that
7
- // layout so `pm2 start ecosystem.config.cjs` works from the claw/ package root.
5
+ // This ecosystem config anchors all paths to the dist/claw build output so
6
+ // `pm2 start ecosystem.config.cjs` works from the claw/ package root.
8
7
  const DIST_CLAW = path.join(__dirname, '..', 'dist', 'claw');
9
8
 
10
9
  module.exports = {
@@ -5,7 +5,10 @@ const { createClawInfrastructure } = require('../modules/claw_infra');
5
5
  const { getErrorMessage } = require('../../modules/utils/errors');
6
6
 
7
7
  async function main() {
8
- const profileRoot = process.argv[2] || process.env.DEXBOT_PROFILE_ROOT || null;
8
+ // Pass an explicit profile root via argv[2], or null to let the shared
9
+ // resolver decide (env override → home config → legacy layouts). Reading
10
+ // DEXBOT_PROFILE_ROOT here directly would bypass that priority order.
11
+ const profileRoot = process.argv[2] || null;
9
12
  const botRef = process.argv[3] || null;
10
13
 
11
14
  const claw = createClawInfrastructure({
@@ -6,26 +6,26 @@ const { createMemuBridge } = require('../modules/memu_bridge');
6
6
  async function main() {
7
7
  console.log('=== memU + DEXBot2 Integration Example ===\n');
8
8
 
9
- const memu = createMemuBridge({
10
- memuDir: process.env.MEMU_DIR || undefined,
11
- llmProfiles: process.env.OPENAI_API_KEY
12
- ? {
13
- default: {
14
- base_url: process.env.OPENAI_BASE_URL || 'https://api.openai.com/v1',
15
- api_key: process.env.OPENAI_API_KEY,
16
- chat_model: process.env.OPENAI_CHAT_MODEL || 'gpt-4o',
17
- embed_model: process.env.OPENAI_EMBED_MODEL || 'text-embedding-3-small',
18
- client_backend: 'sdk'
9
+ try {
10
+ const memu = createMemuBridge({
11
+ memuDir: process.env.MEMU_DIR || undefined,
12
+ llmProfiles: process.env.OPENAI_API_KEY
13
+ ? {
14
+ default: {
15
+ base_url: process.env.OPENAI_BASE_URL || 'https://api.openai.com/v1',
16
+ api_key: process.env.OPENAI_API_KEY,
17
+ chat_model: process.env.OPENAI_CHAT_MODEL || 'gpt-4o',
18
+ embed_model: process.env.OPENAI_EMBED_MODEL || 'text-embedding-3-small',
19
+ client_backend: 'sdk'
20
+ }
19
21
  }
20
- }
21
- : undefined
22
- });
22
+ : undefined
23
+ });
23
24
 
24
- console.log('memU bridge created');
25
- console.log(` memuDir: ${memu.memuDir}`);
26
- console.log(` stateDir: ${memu.stateDir}\n`);
25
+ console.log('memU bridge created');
26
+ console.log(` memuDir: ${memu.memuDir}`);
27
+ console.log(` stateDir: ${memu.stateDir}\n`);
27
28
 
28
- try {
29
29
  console.log('--- Step 1: Check memU status ---');
30
30
  const status = await memu.getStatus();
31
31
  console.log('Status:', JSON.stringify(status, null, 2));
@@ -3,11 +3,12 @@ import * as client from './bitshares_client.js';
3
3
  const { BitShares } = client;
4
4
  import { executeOperations } from './chain_broadcast.js';
5
5
  import { loadDexbotOrderUtils, requireDexbot2Module, loadDexbotOrderConstants } from './dexbot_bridge.js';
6
- import { requireBtsBackedMpa, CORE_SYMBOL } from './mpa_utils.js';
7
- import { getAsset, getBackingAsset, getFullAccount, readOpenOrders, resolveAccountId, resolveAccountName } from './chain_queries.js';
6
+ import { requireBtsBackedMpa } from './mpa_utils.js';
7
+ import { getAsset, getFullAccount, readOpenOrders, resolveAccountId, resolveAccountName } from './chain_queries.js';
8
8
  import { getErrorMessage } from '../../modules/utils/errors.js';
9
9
 
10
- // Graphene protocol constant: operation type 4 = limit_order_create (fill events carry op[0] = 4 for matched orders)
10
+ // Graphene protocol constant: operation type 4 = fill_order (limit_order_create
11
+ // is type 1). Account history subscriptions emit op[0] = 4 for matched fills.
11
12
  const FILL_ORDER_OPERATION_TYPE = 4;
12
13
  const accountSubscriptions = new Map();
13
14
 
@@ -134,18 +135,7 @@ async function buildBorrowMpaOperation({
134
135
  throw new Error(`Account not found: ${accountName}`);
135
136
  }
136
137
 
137
- const mpaMeta = await resolveAssetMeta(mpaAsset);
138
- if (!mpaMeta.bitasset_data_id) {
139
- throw new Error(`${mpaAsset} is not a market-issued asset`);
140
- }
141
-
142
- const backingAsset = await getBackingAsset(mpaAsset);
143
- if (!backingAsset) {
144
- throw new Error(`Could not resolve backing asset for ${mpaAsset}`);
145
- }
146
- if (backingAsset.symbol !== CORE_SYMBOL) {
147
- throw new Error(`${mpaAsset} is backed by ${backingAsset.symbol}, not ${CORE_SYMBOL}; use short_mpa_strategy for non-BTS MPAs`);
148
- }
138
+ const { backingAsset, mpaAsset: mpaMeta } = await requireBtsBackedMpa(mpaAsset, 'use short_mpa_strategy for non-BTS MPAs');
149
139
 
150
140
  const floatToBlockchainInt = getFloatToBlockchainInt();
151
141
  const debtInt = floatToBlockchainInt(debtDelta, mpaMeta.precision);
@@ -179,18 +169,7 @@ async function buildSettleMpaOperation({ accountName, mpaAsset, amount }: any) {
179
169
  throw new Error(`Account not found: ${accountName}`);
180
170
  }
181
171
 
182
- const mpaMeta = await resolveAssetMeta(mpaAsset);
183
- if (!mpaMeta.bitasset_data_id) {
184
- throw new Error(`${mpaAsset} is not a market-issued asset`);
185
- }
186
-
187
- const backingAsset = await getBackingAsset(mpaAsset);
188
- if (!backingAsset) {
189
- throw new Error(`Could not resolve backing asset for ${mpaAsset}`);
190
- }
191
- if (backingAsset.symbol !== CORE_SYMBOL) {
192
- throw new Error(`${mpaAsset} is backed by ${backingAsset.symbol}, not ${CORE_SYMBOL}`);
193
- }
172
+ const { mpaAsset: mpaMeta } = await requireBtsBackedMpa(mpaAsset);
194
173
 
195
174
  const floatToBlockchainInt = getFloatToBlockchainInt();
196
175
  const settleAmountInt = floatToBlockchainInt(amount, mpaMeta.precision);
@@ -304,36 +283,19 @@ async function listenForFills(accountNameOrId: any, callback: any) {
304
283
 
305
284
  if (!accountSubscriptions.has(accountName)) {
306
285
  const callbacks: Set<Function> = new Set();
307
- const bsCallback = (updates: any[] = []) => {
308
- const fills = updates.filter((update) => update?.op && update.op[0] === FILL_ORDER_OPERATION_TYPE);
309
- if (fills.length === 0) {
310
- return;
311
- }
312
-
313
- for (const fn of Array.from(callbacks)) {
314
- // The callback may be async. Run it synchronously so sync throws are
315
- // caught here, and attach a catch for async rejections so a rejected
316
- // handler cannot become an unhandled promise rejection (crash on
317
- // Node >= 15).
318
- try {
319
- const result = fn(fills);
320
- if (result && typeof result.then === 'function') {
321
- result.catch((err: any) => {
322
- console.error('listenForFills callback error:', getErrorMessage(err));
323
- });
324
- }
325
- } catch (err: any) {
326
- console.error('listenForFills callback error:', getErrorMessage(err));
327
- }
328
- }
329
- };
330
-
331
- BitShares.subscribe('account', bsCallback, accountName);
286
+ let bsCallback: Function | null = null;
287
+ try {
288
+ bsCallback = await subscribeAccountFills(accountName, callbacks);
289
+ } catch (err: any) {
290
+ throw new Error(`Failed to subscribe to account updates for ${accountName}: ${getErrorMessage(err)}`);
291
+ }
292
+ // Register only after the remote subscription succeeded so callers never
293
+ // believe they are subscribed when setup actually failed.
332
294
  accountSubscriptions.set(accountName, { callbacks, bsCallback });
333
295
  }
334
296
 
335
297
  const entry = accountSubscriptions.get(accountName);
336
- if (!entry) {
298
+ if (!entry || !entry.bsCallback) {
337
299
  throw new Error(`Subscription entry not found for ${accountName}`);
338
300
  }
339
301
  entry.callbacks.add(callback);
@@ -357,5 +319,40 @@ async function listenForFills(accountNameOrId: any, callback: any) {
357
319
  };
358
320
  }
359
321
 
360
- export { adjustMpaCollateral, borrowMpa, buildBorrowMpaOperation, buildCancelLimitOrderOperation, buildCreateLimitOrderOperation, buildUpdateLimitOrderOperation, buildSettleMpaOperation, cancelLimitOrder, createLimitOrder, executeBatch, getMpaPosition, getOpenOrders, listenForFills, repayMpaDebt, updateLimitOrder, settleMpa }
322
+ /**
323
+ * Subscribe to account history fills and fan them out to every registered
324
+ * callback. The underlying subscription call is async and can reject (network
325
+ * error, unknown account); the promise is awaited by listenForFills so a
326
+ * failure surfaces instead of becoming an unhandled rejection.
327
+ */
328
+ async function subscribeAccountFills(accountName: string, callbacks: Set<Function>) {
329
+ const bsCallback = (updates: any[] = []) => {
330
+ const fills = updates.filter((update) => update?.op && update.op[0] === FILL_ORDER_OPERATION_TYPE);
331
+ if (fills.length === 0) {
332
+ return;
333
+ }
334
+
335
+ for (const fn of Array.from(callbacks)) {
336
+ // The callback may be async. Run it synchronously so sync throws are
337
+ // caught here, and attach a catch for async rejections so a rejected
338
+ // handler cannot become an unhandled promise rejection (crash on
339
+ // Node >= 15).
340
+ try {
341
+ const result = fn(fills);
342
+ if (result && typeof result.then === 'function') {
343
+ result.catch((err: any) => {
344
+ console.error('listenForFills callback error:', getErrorMessage(err));
345
+ });
346
+ }
347
+ } catch (err: any) {
348
+ console.error('listenForFills callback error:', getErrorMessage(err));
349
+ }
350
+ }
351
+ };
352
+
353
+ await BitShares.subscribe('account', bsCallback, accountName);
354
+ return bsCallback;
355
+ }
356
+
357
+ export { adjustMpaCollateral, borrowMpa, buildBorrowMpaOperation, buildCreateLimitOrderOperation, buildUpdateLimitOrderOperation, buildSettleMpaOperation, cancelLimitOrder, createLimitOrder, executeBatch, getMpaPosition, getOpenOrders, listenForFills, repayMpaDebt, updateLimitOrder, settleMpa }
361
358