dexbot 1.4.21 → 1.4.22

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 (595) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +1 -1
  3. package/analysis/ama_fitting/analyze_ama_price_changes.ts +7 -3
  4. package/analysis/ama_fitting/analyze_lambda_vs_slow.ts +3 -3
  5. package/analysis/ama_fitting/calibrate_convergence_er.ts +7 -5
  6. package/analysis/ama_fitting/fetch_lp_candles.ts +8 -3
  7. package/analysis/ama_fitting/generate_unified_comparison_chart.ts +30 -67
  8. package/analysis/ama_fitting/optimizer_high_resolution.ts +22 -13
  9. package/analysis/ama_fitting/package.json +1 -1
  10. package/analysis/analyze_derivatives.ts +4 -4
  11. package/analysis/analyze_dynamic_weight.ts +21 -5
  12. package/analysis/analyze_kalman.ts +54 -25
  13. package/analysis/analyze_regime.ts +2 -2
  14. package/analysis/analyze_regime_windows.ts +27 -19
  15. package/analysis/analyze_risk_profile.ts +3 -3
  16. package/analysis/analyze_trade_heatmap.ts +3 -3
  17. package/analysis/analyze_volatility.ts +2 -2
  18. package/analysis/bot_fitting/README.md +93 -19
  19. package/analysis/bot_fitting/backtest_ama_sweep.ts +316 -199
  20. package/analysis/bot_fitting/backtest_bot_fitting.ts +520 -85
  21. package/analysis/bot_fitting/shared_utils.ts +15 -9
  22. package/analysis/bot_key_utils.ts +13 -6
  23. package/analysis/bot_usage/discover_bot_accounts.ts +5 -3
  24. package/analysis/bot_usage/kibana_bot_queries.ts +1 -1
  25. package/analysis/chart_css.ts +6 -4
  26. package/analysis/chart_ui.ts +0 -1
  27. package/analysis/chart_utils.ts +11 -2
  28. package/analysis/derivative_chart_generator.ts +2 -2
  29. package/analysis/price_sources.ts +8 -2
  30. package/analysis/resolve_source.ts +1 -1
  31. package/analysis/results/ama_sweep_results_lp_pool_133_1h.json +2455 -0
  32. package/analysis/results/bot_fitting_results_lp_pool_133_1h.json +218 -0
  33. package/analysis/trade_profitability.ts +61 -28
  34. package/analysis/tradingview/analyze_tradingview.ts +1 -1
  35. package/analysis/tradingview/h-bts_tradingview.html +1570 -0
  36. package/analysis/tradingview/t-bts_tradingview.html +1570 -0
  37. package/analysis/tradingview/tradingview_uplot_chart_generator.ts +302 -74
  38. package/analysis/trend_detection/DYNAMIC_WEIGHT_RESEARCH.md +1 -1
  39. package/analysis/trend_detection/derivative_analyzer.ts +12 -3
  40. package/analysis/trend_detection/dynamic_weight_chart_generator.ts +25 -27
  41. package/analysis/trend_detection/hurst_analyzer.ts +1 -1
  42. package/analysis/trend_detection/kalman_chart_generator.ts +42 -14
  43. package/analysis/trend_detection/package.json +1 -1
  44. package/analysis/trend_detection/regime_chart_generator.ts +39 -19
  45. package/analysis/trend_detection/tests/test_kalman_trend.ts +1 -1
  46. package/analysis/trend_detection/tests/test_kalman_velocity_smoothing.ts +1 -1
  47. package/analysis/trend_detection/volatility_chart_generator.ts +1 -1
  48. package/claw/index.ts +1 -1
  49. package/claw/modules/claw_bridge.ts +3 -3
  50. package/claw/modules/claw_catalog.ts +1 -1
  51. package/claw/modules/claw_launcher.ts +1 -1
  52. package/claw/modules/claw_skill_md.ts +7 -10
  53. package/claw/modules/credit_runtime_adapter.ts +1 -1
  54. package/claw/modules/decision_loop.ts +5 -9
  55. package/claw/modules/dexbot_bridge.ts +7 -7
  56. package/claw/modules/feed_price_source.ts +1 -1
  57. package/claw/modules/kibana_price_source.ts +1 -1
  58. package/claw/modules/launcher_mode_detector.ts +1 -1
  59. package/claw/modules/launcher_paths.ts +1 -1
  60. package/claw/modules/position_discovery.ts +1 -1
  61. package/claw/modules/position_health.ts +1 -1
  62. package/claw/package.json +3 -3
  63. package/claw/runtimes/openclaw-plugin/openclaw.plugin.json +1 -1
  64. package/claw/runtimes/openclaw-plugin/package.json +1 -1
  65. package/claw/skills/launcher-ops/references/launcher-workflow.md +2 -2
  66. package/claw/tests/package.json +1 -1
  67. package/claw/tests/test_claw_bridge.ts +45 -21
  68. package/claw/tests/test_claw_catalog_and_credentials.ts +8 -4
  69. package/claw/tests/test_claw_chain_layer.ts +39 -19
  70. package/claw/tests/test_claw_data_flow.ts +28 -20
  71. package/claw/tests/test_claw_domain_logic.ts +25 -19
  72. package/claw/tests/test_claw_manifest_and_matrix.ts +23 -3
  73. package/claw/tests/test_claw_mcp_transport.ts +13 -8
  74. package/claw/tests/test_claw_regressions.ts +254 -128
  75. package/claw/tests/test_claw_skill_generation.ts +1 -1
  76. package/claw/tests/test_nullclaw_tmp_integration.ts +2 -3
  77. package/claw/tests/test_position_health.ts +1 -77
  78. package/claw/tests/test_position_manager.ts +20 -18
  79. package/claw/tests/test_position_manager_watch_health.ts +39 -43
  80. package/claw/tests/test_short_mpa_strategy.ts +20 -17
  81. package/claw/tsconfig.json +4 -3
  82. package/dist/analysis/ama_fitting/analyze_ama_price_changes.js +7 -3
  83. package/dist/analysis/ama_fitting/analyze_ama_price_changes.js.map +1 -1
  84. package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.js +3 -3
  85. package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.js.map +1 -1
  86. package/dist/analysis/ama_fitting/calibrate_convergence_er.js +7 -5
  87. package/dist/analysis/ama_fitting/calibrate_convergence_er.js.map +1 -1
  88. package/dist/analysis/ama_fitting/fetch_lp_candles.js +8 -3
  89. package/dist/analysis/ama_fitting/fetch_lp_candles.js.map +1 -1
  90. package/dist/analysis/ama_fitting/generate_unified_comparison_chart.d.ts +2 -2
  91. package/dist/analysis/ama_fitting/generate_unified_comparison_chart.d.ts.map +1 -1
  92. package/dist/analysis/ama_fitting/generate_unified_comparison_chart.js +31 -75
  93. package/dist/analysis/ama_fitting/generate_unified_comparison_chart.js.map +1 -1
  94. package/dist/analysis/ama_fitting/optimizer_high_resolution.d.ts.map +1 -1
  95. package/dist/analysis/ama_fitting/optimizer_high_resolution.js +21 -13
  96. package/dist/analysis/ama_fitting/optimizer_high_resolution.js.map +1 -1
  97. package/dist/analysis/analyze_derivatives.d.ts +0 -18
  98. package/dist/analysis/analyze_derivatives.d.ts.map +1 -1
  99. package/dist/analysis/analyze_derivatives.js +4 -4
  100. package/dist/analysis/analyze_derivatives.js.map +1 -1
  101. package/dist/analysis/analyze_dynamic_weight.d.ts +0 -11
  102. package/dist/analysis/analyze_dynamic_weight.d.ts.map +1 -1
  103. package/dist/analysis/analyze_dynamic_weight.js +19 -5
  104. package/dist/analysis/analyze_dynamic_weight.js.map +1 -1
  105. package/dist/analysis/analyze_kalman.d.ts +0 -10
  106. package/dist/analysis/analyze_kalman.d.ts.map +1 -1
  107. package/dist/analysis/analyze_kalman.js +51 -26
  108. package/dist/analysis/analyze_kalman.js.map +1 -1
  109. package/dist/analysis/analyze_regime.d.ts +0 -17
  110. package/dist/analysis/analyze_regime.d.ts.map +1 -1
  111. package/dist/analysis/analyze_regime.js +2 -2
  112. package/dist/analysis/analyze_regime.js.map +1 -1
  113. package/dist/analysis/analyze_regime_windows.d.ts +0 -16
  114. package/dist/analysis/analyze_regime_windows.d.ts.map +1 -1
  115. package/dist/analysis/analyze_regime_windows.js +28 -21
  116. package/dist/analysis/analyze_regime_windows.js.map +1 -1
  117. package/dist/analysis/analyze_risk_profile.js +3 -3
  118. package/dist/analysis/analyze_risk_profile.js.map +1 -1
  119. package/dist/analysis/analyze_trade_heatmap.js +3 -3
  120. package/dist/analysis/analyze_trade_heatmap.js.map +1 -1
  121. package/dist/analysis/analyze_volatility.d.ts +0 -19
  122. package/dist/analysis/analyze_volatility.d.ts.map +1 -1
  123. package/dist/analysis/analyze_volatility.js +2 -2
  124. package/dist/analysis/analyze_volatility.js.map +1 -1
  125. package/dist/analysis/bot_fitting/backtest_ama_sweep.d.ts +30 -14
  126. package/dist/analysis/bot_fitting/backtest_ama_sweep.d.ts.map +1 -1
  127. package/dist/analysis/bot_fitting/backtest_ama_sweep.js +330 -193
  128. package/dist/analysis/bot_fitting/backtest_ama_sweep.js.map +1 -1
  129. package/dist/analysis/bot_fitting/backtest_bot_fitting.d.ts +136 -1
  130. package/dist/analysis/bot_fitting/backtest_bot_fitting.d.ts.map +1 -1
  131. package/dist/analysis/bot_fitting/backtest_bot_fitting.js +527 -83
  132. package/dist/analysis/bot_fitting/backtest_bot_fitting.js.map +1 -1
  133. package/dist/analysis/bot_fitting/shared_utils.d.ts +1 -1
  134. package/dist/analysis/bot_fitting/shared_utils.d.ts.map +1 -1
  135. package/dist/analysis/bot_fitting/shared_utils.js +14 -8
  136. package/dist/analysis/bot_fitting/shared_utils.js.map +1 -1
  137. package/dist/analysis/bot_key_utils.d.ts.map +1 -1
  138. package/dist/analysis/bot_key_utils.js +13 -6
  139. package/dist/analysis/bot_key_utils.js.map +1 -1
  140. package/dist/analysis/bot_usage/discover_bot_accounts.js +5 -3
  141. package/dist/analysis/bot_usage/discover_bot_accounts.js.map +1 -1
  142. package/dist/analysis/bot_usage/kibana_bot_queries.d.ts.map +1 -1
  143. package/dist/analysis/bot_usage/kibana_bot_queries.js +1 -1
  144. package/dist/analysis/bot_usage/kibana_bot_queries.js.map +1 -1
  145. package/dist/analysis/chart_css.d.ts +3 -1
  146. package/dist/analysis/chart_css.d.ts.map +1 -1
  147. package/dist/analysis/chart_css.js +6 -3
  148. package/dist/analysis/chart_css.js.map +1 -1
  149. package/dist/analysis/chart_ui.d.ts.map +1 -1
  150. package/dist/analysis/chart_ui.js.map +1 -1
  151. package/dist/analysis/chart_utils.d.ts.map +1 -1
  152. package/dist/analysis/chart_utils.js +15 -2
  153. package/dist/analysis/chart_utils.js.map +1 -1
  154. package/dist/analysis/derivative_chart_generator.js +2 -2
  155. package/dist/analysis/derivative_chart_generator.js.map +1 -1
  156. package/dist/analysis/price_sources.d.ts +1 -0
  157. package/dist/analysis/price_sources.d.ts.map +1 -1
  158. package/dist/analysis/price_sources.js +8 -2
  159. package/dist/analysis/price_sources.js.map +1 -1
  160. package/dist/analysis/resolve_source.d.ts.map +1 -1
  161. package/dist/analysis/resolve_source.js +1 -1
  162. package/dist/analysis/resolve_source.js.map +1 -1
  163. package/dist/analysis/trade_profitability.d.ts.map +1 -1
  164. package/dist/analysis/trade_profitability.js +58 -29
  165. package/dist/analysis/trade_profitability.js.map +1 -1
  166. package/dist/analysis/tradingview/analyze_tradingview.js +1 -1
  167. package/dist/analysis/tradingview/analyze_tradingview.js.map +1 -1
  168. package/dist/analysis/tradingview/tradingview_uplot_chart_generator.d.ts.map +1 -1
  169. package/dist/analysis/tradingview/tradingview_uplot_chart_generator.js +302 -74
  170. package/dist/analysis/tradingview/tradingview_uplot_chart_generator.js.map +1 -1
  171. package/dist/analysis/trend_detection/derivative_analyzer.d.ts +1 -0
  172. package/dist/analysis/trend_detection/derivative_analyzer.d.ts.map +1 -1
  173. package/dist/analysis/trend_detection/derivative_analyzer.js +12 -3
  174. package/dist/analysis/trend_detection/derivative_analyzer.js.map +1 -1
  175. package/dist/analysis/trend_detection/dynamic_weight_chart_generator.d.ts.map +1 -1
  176. package/dist/analysis/trend_detection/dynamic_weight_chart_generator.js +26 -27
  177. package/dist/analysis/trend_detection/dynamic_weight_chart_generator.js.map +1 -1
  178. package/dist/analysis/trend_detection/hurst_analyzer.d.ts +1 -1
  179. package/dist/analysis/trend_detection/hurst_analyzer.d.ts.map +1 -1
  180. package/dist/analysis/trend_detection/hurst_analyzer.js +1 -1
  181. package/dist/analysis/trend_detection/hurst_analyzer.js.map +1 -1
  182. package/dist/analysis/trend_detection/kalman_chart_generator.d.ts.map +1 -1
  183. package/dist/analysis/trend_detection/kalman_chart_generator.js +41 -13
  184. package/dist/analysis/trend_detection/kalman_chart_generator.js.map +1 -1
  185. package/dist/analysis/trend_detection/regime_chart_generator.d.ts.map +1 -1
  186. package/dist/analysis/trend_detection/regime_chart_generator.js +38 -19
  187. package/dist/analysis/trend_detection/regime_chart_generator.js.map +1 -1
  188. package/dist/analysis/trend_detection/tests/test_kalman_trend.js +1 -1
  189. package/dist/analysis/trend_detection/tests/test_kalman_trend.js.map +1 -1
  190. package/dist/analysis/trend_detection/tests/test_kalman_velocity_smoothing.js +1 -1
  191. package/dist/analysis/trend_detection/tests/test_kalman_velocity_smoothing.js.map +1 -1
  192. package/dist/analysis/trend_detection/volatility_chart_generator.js +1 -1
  193. package/dist/analysis/trend_detection/volatility_chart_generator.js.map +1 -1
  194. package/dist/bot.js +1 -1
  195. package/dist/bot.js.map +1 -1
  196. package/dist/credential-daemon.d.ts +1 -1
  197. package/dist/credential-daemon.js +1 -1
  198. package/dist/dexbot.d.ts.map +1 -1
  199. package/dist/dexbot.js +7 -8
  200. package/dist/dexbot.js.map +1 -1
  201. package/dist/market_adapter/ama_signal_runner.js +3 -1
  202. package/dist/market_adapter/ama_signal_runner.js.map +1 -1
  203. package/dist/market_adapter/candle_utils.d.ts +1 -3
  204. package/dist/market_adapter/candle_utils.d.ts.map +1 -1
  205. package/dist/market_adapter/candle_utils.js +1 -11
  206. package/dist/market_adapter/candle_utils.js.map +1 -1
  207. package/dist/market_adapter/core/asymmetric_bounds.d.ts.map +1 -1
  208. package/dist/market_adapter/core/asymmetric_bounds.js +33 -30
  209. package/dist/market_adapter/core/asymmetric_bounds.js.map +1 -1
  210. package/dist/market_adapter/core/config_normalizers.d.ts.map +1 -1
  211. package/dist/market_adapter/core/config_normalizers.js +10 -1
  212. package/dist/market_adapter/core/config_normalizers.js.map +1 -1
  213. package/dist/market_adapter/core/kibana_candles.d.ts +18 -42
  214. package/dist/market_adapter/core/kibana_candles.d.ts.map +1 -1
  215. package/dist/market_adapter/core/kibana_candles.js +101 -7
  216. package/dist/market_adapter/core/kibana_candles.js.map +1 -1
  217. package/dist/market_adapter/core/kibana_client.d.ts +0 -14
  218. package/dist/market_adapter/core/kibana_client.d.ts.map +1 -1
  219. package/dist/market_adapter/core/kibana_client.js +39 -6
  220. package/dist/market_adapter/core/kibana_client.js.map +1 -1
  221. package/dist/market_adapter/core/kibana_market_candles.d.ts +0 -27
  222. package/dist/market_adapter/core/kibana_market_candles.d.ts.map +1 -1
  223. package/dist/market_adapter/core/kibana_market_candles.js +1 -1
  224. package/dist/market_adapter/core/kibana_market_candles.js.map +1 -1
  225. package/dist/market_adapter/core/market_adapter_service.d.ts +21 -11
  226. package/dist/market_adapter/core/market_adapter_service.d.ts.map +1 -1
  227. package/dist/market_adapter/core/market_adapter_service.js +95 -37
  228. package/dist/market_adapter/core/market_adapter_service.js.map +1 -1
  229. package/dist/market_adapter/core/signals/hurst_analyzer.d.ts +10 -1
  230. package/dist/market_adapter/core/signals/hurst_analyzer.d.ts.map +1 -1
  231. package/dist/market_adapter/core/signals/hurst_analyzer.js +28 -17
  232. package/dist/market_adapter/core/signals/hurst_analyzer.js.map +1 -1
  233. package/dist/market_adapter/core/signals/kalman_trend_analyzer.d.ts +5 -0
  234. package/dist/market_adapter/core/signals/kalman_trend_analyzer.d.ts.map +1 -1
  235. package/dist/market_adapter/core/signals/kalman_trend_analyzer.js +24 -24
  236. package/dist/market_adapter/core/signals/kalman_trend_analyzer.js.map +1 -1
  237. package/dist/market_adapter/core/signals/kalman_velocity_smoothing.d.ts.map +1 -1
  238. package/dist/market_adapter/core/signals/kalman_velocity_smoothing.js +5 -1
  239. package/dist/market_adapter/core/signals/kalman_velocity_smoothing.js.map +1 -1
  240. package/dist/market_adapter/core/signals/permutation_entropy_analyzer.d.ts.map +1 -1
  241. package/dist/market_adapter/core/signals/permutation_entropy_analyzer.js +20 -3
  242. package/dist/market_adapter/core/signals/permutation_entropy_analyzer.js.map +1 -1
  243. package/dist/market_adapter/core/strategies/ama.js +1 -1
  244. package/dist/market_adapter/core/strategies/ama.js.map +1 -1
  245. package/dist/market_adapter/core/strategies/ama_slope_model.d.ts +2 -2
  246. package/dist/market_adapter/core/strategies/ama_slope_model.d.ts.map +1 -1
  247. package/dist/market_adapter/core/strategies/ama_slope_model.js +16 -4
  248. package/dist/market_adapter/core/strategies/ama_slope_model.js.map +1 -1
  249. package/dist/market_adapter/core/strategies/atr/calculator.d.ts +4 -3
  250. package/dist/market_adapter/core/strategies/atr/calculator.d.ts.map +1 -1
  251. package/dist/market_adapter/core/strategies/atr/calculator.js +16 -8
  252. package/dist/market_adapter/core/strategies/atr/calculator.js.map +1 -1
  253. package/dist/market_adapter/core/strategies/collateral_manager.d.ts.map +1 -1
  254. package/dist/market_adapter/core/strategies/collateral_manager.js +8 -3
  255. package/dist/market_adapter/core/strategies/collateral_manager.js.map +1 -1
  256. package/dist/market_adapter/core/strategies/dynamic_weight_series.d.ts +40 -1
  257. package/dist/market_adapter/core/strategies/dynamic_weight_series.d.ts.map +1 -1
  258. package/dist/market_adapter/core/strategies/dynamic_weight_series.js +116 -2
  259. package/dist/market_adapter/core/strategies/dynamic_weight_series.js.map +1 -1
  260. package/dist/market_adapter/core/strategies/regime_gate.d.ts.map +1 -1
  261. package/dist/market_adapter/core/strategies/regime_gate.js +26 -20
  262. package/dist/market_adapter/core/strategies/regime_gate.js.map +1 -1
  263. package/dist/market_adapter/core/strategies/volatility_shift.d.ts.map +1 -1
  264. package/dist/market_adapter/core/strategies/volatility_shift.js +3 -0
  265. package/dist/market_adapter/core/strategies/volatility_shift.js.map +1 -1
  266. package/dist/market_adapter/inputs/fetch_cex_synthetic_data.js +69 -55
  267. package/dist/market_adapter/inputs/fetch_cex_synthetic_data.js.map +1 -1
  268. package/dist/market_adapter/inputs/fetch_lp_data.d.ts +0 -26
  269. package/dist/market_adapter/inputs/fetch_lp_data.d.ts.map +1 -1
  270. package/dist/market_adapter/inputs/fetch_lp_data.js +67 -14
  271. package/dist/market_adapter/inputs/fetch_lp_data.js.map +1 -1
  272. package/dist/market_adapter/inputs/kibana_source.d.ts +4 -28
  273. package/dist/market_adapter/inputs/kibana_source.d.ts.map +1 -1
  274. package/dist/market_adapter/inputs/kibana_source.js +5 -2
  275. package/dist/market_adapter/inputs/kibana_source.js.map +1 -1
  276. package/dist/market_adapter/lp_chart_core.js +1 -1
  277. package/dist/market_adapter/lp_chart_core.js.map +1 -1
  278. package/dist/market_adapter/lp_chart_runner.d.ts +10 -1
  279. package/dist/market_adapter/lp_chart_runner.d.ts.map +1 -1
  280. package/dist/market_adapter/lp_chart_runner.js +2 -2
  281. package/dist/market_adapter/lp_chart_runner.js.map +1 -1
  282. package/dist/market_adapter/lp_chart_strategy_loader.js +1 -1
  283. package/dist/market_adapter/lp_chart_strategy_loader.js.map +1 -1
  284. package/dist/market_adapter/market_adapter.d.ts +1 -2
  285. package/dist/market_adapter/market_adapter.d.ts.map +1 -1
  286. package/dist/market_adapter/market_adapter.js +3 -6
  287. package/dist/market_adapter/market_adapter.js.map +1 -1
  288. package/dist/market_adapter/test_helpers.d.ts +3 -3
  289. package/dist/market_adapter/test_helpers.d.ts.map +1 -1
  290. package/dist/market_adapter/test_helpers.js +3 -3
  291. package/dist/market_adapter/test_helpers.js.map +1 -1
  292. package/dist/market_adapter/utils/adapter_client.js +1 -1
  293. package/dist/market_adapter/utils/adapter_client.js.map +1 -1
  294. package/dist/market_adapter/utils/atomic_write.js +1 -1
  295. package/dist/market_adapter/utils/atomic_write.js.map +1 -1
  296. package/dist/market_adapter/utils/chain.d.ts +0 -2
  297. package/dist/market_adapter/utils/chain.d.ts.map +1 -1
  298. package/dist/market_adapter/utils/chain.js +2 -3
  299. package/dist/market_adapter/utils/chain.js.map +1 -1
  300. package/dist/market_adapter/utils/data_discovery.d.ts.map +1 -1
  301. package/dist/market_adapter/utils/data_discovery.js +24 -8
  302. package/dist/market_adapter/utils/data_discovery.js.map +1 -1
  303. package/dist/market_adapter/utils/dynamic_grid_snapshot.d.ts.map +1 -1
  304. package/dist/market_adapter/utils/dynamic_grid_snapshot.js +2 -5
  305. package/dist/market_adapter/utils/dynamic_grid_snapshot.js.map +1 -1
  306. package/dist/market_adapter/utils/file_lock.d.ts +4 -1
  307. package/dist/market_adapter/utils/file_lock.d.ts.map +1 -1
  308. package/dist/market_adapter/utils/file_lock.js +89 -25
  309. package/dist/market_adapter/utils/file_lock.js.map +1 -1
  310. package/dist/market_adapter/utils/native_history.d.ts.map +1 -1
  311. package/dist/market_adapter/utils/native_history.js +5 -1
  312. package/dist/market_adapter/utils/native_history.js.map +1 -1
  313. package/dist/modules/account_bots.js +1 -1
  314. package/dist/modules/account_bots.js.map +1 -1
  315. package/dist/modules/authority_resolver.js +1 -1
  316. package/dist/modules/authority_resolver.js.map +1 -1
  317. package/dist/modules/bitshares-native/chain_client.js +1 -1
  318. package/dist/modules/bitshares-native/chain_client.js.map +1 -1
  319. package/dist/modules/bitshares-native/crypto/ecc.browser.d.ts +0 -12
  320. package/dist/modules/bitshares-native/crypto/ecc.browser.d.ts.map +1 -1
  321. package/dist/modules/bitshares-native/crypto/ecc.browser.js +1 -1
  322. package/dist/modules/bitshares-native/crypto/ecc.browser.js.map +1 -1
  323. package/dist/modules/bitshares-native/crypto/ecc_selector.js +1 -1
  324. package/dist/modules/bitshares-native/crypto/ecc_selector.js.map +1 -1
  325. package/dist/modules/bitshares-native/index.d.ts.map +1 -1
  326. package/dist/modules/bitshares-native/index.js +1 -1
  327. package/dist/modules/bitshares-native/index.js.map +1 -1
  328. package/dist/modules/bitshares-native/lru_cache.js +1 -1
  329. package/dist/modules/bitshares-native/lru_cache.js.map +1 -1
  330. package/dist/modules/bitshares-native/resolvers.d.ts +0 -2
  331. package/dist/modules/bitshares-native/resolvers.d.ts.map +1 -1
  332. package/dist/modules/bitshares-native/resolvers.js +18 -4
  333. package/dist/modules/bitshares-native/resolvers.js.map +1 -1
  334. package/dist/modules/bitshares-native/serial/chain_constants.js +1 -1
  335. package/dist/modules/bitshares-native/serial/chain_constants.js.map +1 -1
  336. package/dist/modules/bitshares-native/serial/index.d.ts.map +1 -1
  337. package/dist/modules/bitshares-native/serial/index.js +1 -1
  338. package/dist/modules/bitshares-native/serial/index.js.map +1 -1
  339. package/dist/modules/bitshares-native/serial/operations.js +1 -1
  340. package/dist/modules/bitshares-native/serial/operations.js.map +1 -1
  341. package/dist/modules/bitshares-native/serial/serializer.js +1 -1
  342. package/dist/modules/bitshares-native/serial/serializer.js.map +1 -1
  343. package/dist/modules/bitshares-native/serial/types.js +1 -1
  344. package/dist/modules/bitshares-native/serial/types.js.map +1 -1
  345. package/dist/modules/bitshares-native/signing_client.js +2 -2
  346. package/dist/modules/bitshares-native/signing_client.js.map +1 -1
  347. package/dist/modules/bitshares-native/subscriptions.d.ts.map +1 -1
  348. package/dist/modules/bitshares-native/subscriptions.js +5 -14
  349. package/dist/modules/bitshares-native/subscriptions.js.map +1 -1
  350. package/dist/modules/bitshares-native/transport.js +1 -1
  351. package/dist/modules/bitshares-native/transport.js.map +1 -1
  352. package/dist/modules/bitshares-native/tx/builder.js +1 -1
  353. package/dist/modules/bitshares-native/tx/builder.js.map +1 -1
  354. package/dist/modules/bitshares-native/tx/tx_cache.d.ts +3 -2
  355. package/dist/modules/bitshares-native/tx/tx_cache.d.ts.map +1 -1
  356. package/dist/modules/bitshares-native/tx/tx_cache.js +7 -4
  357. package/dist/modules/bitshares-native/tx/tx_cache.js.map +1 -1
  358. package/dist/modules/bitshares_client.js +10 -10
  359. package/dist/modules/bitshares_client.js.map +1 -1
  360. package/dist/modules/bot_settings.d.ts.map +1 -1
  361. package/dist/modules/bot_settings.js +11 -18
  362. package/dist/modules/bot_settings.js.map +1 -1
  363. package/dist/modules/bots_file_lock.d.ts +1 -1
  364. package/dist/modules/bots_file_lock.js +1 -1
  365. package/dist/modules/broadcast_failure.d.ts +13 -0
  366. package/dist/modules/broadcast_failure.d.ts.map +1 -1
  367. package/dist/modules/broadcast_failure.js +0 -13
  368. package/dist/modules/broadcast_failure.js.map +1 -1
  369. package/dist/modules/chain_orders.d.ts.map +1 -1
  370. package/dist/modules/chain_orders.js +15 -17
  371. package/dist/modules/chain_orders.js.map +1 -1
  372. package/dist/modules/config.js +1 -1
  373. package/dist/modules/config.js.map +1 -1
  374. package/dist/modules/constants.d.ts +21 -20
  375. package/dist/modules/constants.d.ts.map +1 -1
  376. package/dist/modules/constants.js +53 -56
  377. package/dist/modules/constants.js.map +1 -1
  378. package/dist/modules/cr_planner.d.ts +1 -7
  379. package/dist/modules/cr_planner.d.ts.map +1 -1
  380. package/dist/modules/cr_planner.js +3 -77
  381. package/dist/modules/cr_planner.js.map +1 -1
  382. package/dist/modules/credential_policy.d.ts +0 -4
  383. package/dist/modules/credential_policy.d.ts.map +1 -1
  384. package/dist/modules/credential_policy.js +17 -2
  385. package/dist/modules/credential_policy.js.map +1 -1
  386. package/dist/modules/credit_runtime.d.ts +0 -7
  387. package/dist/modules/credit_runtime.d.ts.map +1 -1
  388. package/dist/modules/credit_runtime.js +21 -60
  389. package/dist/modules/credit_runtime.js.map +1 -1
  390. package/dist/modules/crypto/index.d.ts +0 -2
  391. package/dist/modules/crypto/index.d.ts.map +1 -1
  392. package/dist/modules/crypto/index.js +0 -2
  393. package/dist/modules/crypto/index.js.map +1 -1
  394. package/dist/modules/crypto/sync.js.map +1 -1
  395. package/dist/modules/daemon_node_health.js +1 -1
  396. package/dist/modules/daemon_node_health.js.map +1 -1
  397. package/dist/modules/dexbot_class.d.ts +8 -134
  398. package/dist/modules/dexbot_class.d.ts.map +1 -1
  399. package/dist/modules/dexbot_class.js +36 -197
  400. package/dist/modules/dexbot_class.js.map +1 -1
  401. package/dist/modules/dexbot_credential_client.js +1 -1
  402. package/dist/modules/dexbot_credential_client.js.map +1 -1
  403. package/dist/modules/dexbot_fill_runtime.d.ts.map +1 -1
  404. package/dist/modules/dexbot_fill_runtime.js +3 -6
  405. package/dist/modules/dexbot_fill_runtime.js.map +1 -1
  406. package/dist/modules/dexbot_maintenance_runtime.d.ts +6 -34
  407. package/dist/modules/dexbot_maintenance_runtime.d.ts.map +1 -1
  408. package/dist/modules/dexbot_maintenance_runtime.js +27 -19
  409. package/dist/modules/dexbot_maintenance_runtime.js.map +1 -1
  410. package/dist/modules/dexbot_startup_runtime.d.ts.map +1 -1
  411. package/dist/modules/dexbot_startup_runtime.js +31 -15
  412. package/dist/modules/dexbot_startup_runtime.js.map +1 -1
  413. package/dist/modules/dexbot_state_recovery.d.ts +2 -2
  414. package/dist/modules/dexbot_state_recovery.d.ts.map +1 -1
  415. package/dist/modules/dexbot_state_recovery.js +9 -6
  416. package/dist/modules/dexbot_state_recovery.js.map +1 -1
  417. package/dist/modules/fund_registry.d.ts.map +1 -1
  418. package/dist/modules/fund_registry.js +19 -4
  419. package/dist/modules/fund_registry.js.map +1 -1
  420. package/dist/modules/general_settings.d.ts +1 -2
  421. package/dist/modules/general_settings.d.ts.map +1 -1
  422. package/dist/modules/general_settings.js +1 -2
  423. package/dist/modules/general_settings.js.map +1 -1
  424. package/dist/modules/graceful_shutdown.d.ts.map +1 -1
  425. package/dist/modules/graceful_shutdown.js +10 -1
  426. package/dist/modules/graceful_shutdown.js.map +1 -1
  427. package/dist/modules/grid_price_source.d.ts +19 -0
  428. package/dist/modules/grid_price_source.d.ts.map +1 -0
  429. package/dist/modules/grid_price_source.js +23 -0
  430. package/dist/modules/grid_price_source.js.map +1 -0
  431. package/dist/modules/key_store.d.ts +0 -5
  432. package/dist/modules/key_store.d.ts.map +1 -1
  433. package/dist/modules/key_store.js +1 -14
  434. package/dist/modules/key_store.js.map +1 -1
  435. package/dist/modules/launcher/bot_supervisor.d.ts.map +1 -1
  436. package/dist/modules/launcher/bot_supervisor.js +9 -19
  437. package/dist/modules/launcher/bot_supervisor.js.map +1 -1
  438. package/dist/modules/launcher/child_env.d.ts +1 -2
  439. package/dist/modules/launcher/child_env.d.ts.map +1 -1
  440. package/dist/modules/launcher/child_env.js +1 -1
  441. package/dist/modules/launcher/child_env.js.map +1 -1
  442. package/dist/modules/launcher/foreign_cred_daemon.d.ts.map +1 -1
  443. package/dist/modules/launcher/foreign_cred_daemon.js +2 -14
  444. package/dist/modules/launcher/foreign_cred_daemon.js.map +1 -1
  445. package/dist/modules/launcher/market_adapter_runtime.d.ts +1 -1
  446. package/dist/modules/launcher/market_adapter_runtime.d.ts.map +1 -1
  447. package/dist/modules/launcher/market_adapter_runtime.js +3 -14
  448. package/dist/modules/launcher/market_adapter_runtime.js.map +1 -1
  449. package/dist/modules/launcher/market_adapter_watchdog.d.ts.map +1 -1
  450. package/dist/modules/launcher/market_adapter_watchdog.js +3 -2
  451. package/dist/modules/launcher/market_adapter_watchdog.js.map +1 -1
  452. package/dist/modules/launcher/monolithic_runtime.d.ts +0 -1
  453. package/dist/modules/launcher/monolithic_runtime.d.ts.map +1 -1
  454. package/dist/modules/launcher/monolithic_runtime.js +3 -18
  455. package/dist/modules/launcher/monolithic_runtime.js.map +1 -1
  456. package/dist/modules/launcher/runtime_entry.d.ts.map +1 -1
  457. package/dist/modules/launcher/runtime_entry.js +4 -5
  458. package/dist/modules/launcher/runtime_entry.js.map +1 -1
  459. package/dist/modules/launcher/status_reporting.js +1 -1
  460. package/dist/modules/launcher/status_reporting.js.map +1 -1
  461. package/dist/modules/launcher/supervisor_control.js +1 -1
  462. package/dist/modules/launcher/supervisor_control.js.map +1 -1
  463. package/dist/modules/market_adapter_whitelist.d.ts +2 -2
  464. package/dist/modules/market_adapter_whitelist.d.ts.map +1 -1
  465. package/dist/modules/market_adapter_whitelist.js +12 -6
  466. package/dist/modules/market_adapter_whitelist.js.map +1 -1
  467. package/dist/modules/node_failure_ledger.d.ts +23 -0
  468. package/dist/modules/node_failure_ledger.d.ts.map +1 -1
  469. package/dist/modules/node_failure_ledger.js +0 -23
  470. package/dist/modules/node_failure_ledger.js.map +1 -1
  471. package/dist/modules/node_manager.d.ts.map +1 -1
  472. package/dist/modules/node_manager.js +3 -3
  473. package/dist/modules/node_manager.js.map +1 -1
  474. package/dist/modules/order/accounting.js +1 -1
  475. package/dist/modules/order/accounting.js.map +1 -1
  476. package/dist/modules/order/async_lock.d.ts +6 -0
  477. package/dist/modules/order/async_lock.d.ts.map +1 -1
  478. package/dist/modules/order/async_lock.js +11 -0
  479. package/dist/modules/order/async_lock.js.map +1 -1
  480. package/dist/modules/order/export.d.ts +1 -1
  481. package/dist/modules/order/export.js +10 -10
  482. package/dist/modules/order/export.js.map +1 -1
  483. package/dist/modules/order/format.d.ts +1 -0
  484. package/dist/modules/order/format.d.ts.map +1 -1
  485. package/dist/modules/order/format.js +0 -6
  486. package/dist/modules/order/format.js.map +1 -1
  487. package/dist/modules/order/grid.d.ts +2 -12
  488. package/dist/modules/order/grid.d.ts.map +1 -1
  489. package/dist/modules/order/grid.js +23 -24
  490. package/dist/modules/order/grid.js.map +1 -1
  491. package/dist/modules/order/grid_reconcile.d.ts +1 -1
  492. package/dist/modules/order/grid_reconcile.js +1 -1
  493. package/dist/modules/order/grid_reconcile_internal.js +1 -1
  494. package/dist/modules/order/grid_reconcile_internal.js.map +1 -1
  495. package/dist/modules/order/logger.d.ts +3 -0
  496. package/dist/modules/order/logger.d.ts.map +1 -1
  497. package/dist/modules/order/logger.js +22 -13
  498. package/dist/modules/order/logger.js.map +1 -1
  499. package/dist/modules/order/logger_state.d.ts +4 -9
  500. package/dist/modules/order/logger_state.d.ts.map +1 -1
  501. package/dist/modules/order/logger_state.js +5 -14
  502. package/dist/modules/order/logger_state.js.map +1 -1
  503. package/dist/modules/order/manager.d.ts +1 -4
  504. package/dist/modules/order/manager.d.ts.map +1 -1
  505. package/dist/modules/order/manager.js +34 -33
  506. package/dist/modules/order/manager.js.map +1 -1
  507. package/dist/modules/order/processed_fill_store.d.ts.map +1 -1
  508. package/dist/modules/order/processed_fill_store.js +9 -3
  509. package/dist/modules/order/processed_fill_store.js.map +1 -1
  510. package/dist/modules/order/strategy.d.ts +6 -4
  511. package/dist/modules/order/strategy.d.ts.map +1 -1
  512. package/dist/modules/order/strategy.js +6 -4
  513. package/dist/modules/order/strategy.js.map +1 -1
  514. package/dist/modules/order/sync_engine.js +7 -7
  515. package/dist/modules/order/sync_engine.js.map +1 -1
  516. package/dist/modules/order/utils/order.d.ts.map +1 -1
  517. package/dist/modules/order/utils/order.js +1 -2
  518. package/dist/modules/order/utils/order.js.map +1 -1
  519. package/dist/modules/order/utils/system.d.ts +3 -8
  520. package/dist/modules/order/utils/system.d.ts.map +1 -1
  521. package/dist/modules/order/utils/system.js +14 -4
  522. package/dist/modules/order/utils/system.js.map +1 -1
  523. package/dist/modules/order/utils/validate.js +1 -1
  524. package/dist/modules/order/utils/validate.js.map +1 -1
  525. package/dist/modules/path_api.js +1 -1
  526. package/dist/modules/path_api.js.map +1 -1
  527. package/dist/modules/paths.d.ts +1 -7
  528. package/dist/modules/paths.d.ts.map +1 -1
  529. package/dist/modules/paths.js +1 -1
  530. package/dist/modules/paths.js.map +1 -1
  531. package/dist/modules/process_discovery.d.ts +3 -0
  532. package/dist/modules/process_discovery.d.ts.map +1 -1
  533. package/dist/modules/process_discovery.js +15 -1
  534. package/dist/modules/process_discovery.js.map +1 -1
  535. package/dist/modules/runtime_settings.js +1 -1
  536. package/dist/modules/runtime_settings.js.map +1 -1
  537. package/dist/modules/settings_merge.d.ts +5 -1
  538. package/dist/modules/settings_merge.d.ts.map +1 -1
  539. package/dist/modules/settings_merge.js +14 -3
  540. package/dist/modules/settings_merge.js.map +1 -1
  541. package/dist/modules/socket_json_client.d.ts.map +1 -1
  542. package/dist/modules/socket_json_client.js +12 -2
  543. package/dist/modules/socket_json_client.js.map +1 -1
  544. package/dist/modules/storage/browser_adapter.d.ts.map +1 -1
  545. package/dist/modules/storage/browser_adapter.js +5 -3
  546. package/dist/modules/storage/browser_adapter.js.map +1 -1
  547. package/dist/modules/storage/index.d.ts +1 -1
  548. package/dist/modules/storage/index.js +1 -1
  549. package/dist/modules/types.d.ts +1 -1
  550. package/dist/modules/types.d.ts.map +1 -1
  551. package/dist/modules/validate_profiles.d.ts.map +1 -1
  552. package/dist/modules/validate_profiles.js +6 -8
  553. package/dist/modules/validate_profiles.js.map +1 -1
  554. package/dist/pm2.d.ts.map +1 -1
  555. package/dist/pm2.js +2 -3
  556. package/dist/pm2.js.map +1 -1
  557. package/dist/scripts/analyze-git.d.ts +1 -1
  558. package/dist/scripts/analyze-git.js +1 -1
  559. package/dist/scripts/analyze-orders.d.ts.map +1 -1
  560. package/dist/scripts/analyze-orders.js +35 -16
  561. package/dist/scripts/analyze-orders.js.map +1 -1
  562. package/dist/scripts/diagnose-pool-history.js +1 -1
  563. package/dist/scripts/divergence-calc.d.ts +1 -1
  564. package/dist/scripts/divergence-calc.js +3 -3
  565. package/dist/scripts/native_release_gates.js +4 -2
  566. package/dist/scripts/native_release_gates.js.map +1 -1
  567. package/dist/scripts/print_grid.d.ts +1 -1
  568. package/dist/scripts/print_grid.js +1 -1
  569. package/dist/scripts/run-tests.js +38 -19
  570. package/dist/scripts/run-tests.js.map +1 -1
  571. package/dist/scripts/runner.d.ts +3 -5
  572. package/dist/scripts/runner.d.ts.map +1 -1
  573. package/dist/scripts/runner.js +3 -5
  574. package/dist/scripts/runner.js.map +1 -1
  575. package/dist/scripts/sync-version.d.ts +2 -2
  576. package/dist/scripts/sync-version.js +2 -2
  577. package/dist/scripts/update.d.ts +1 -1
  578. package/dist/scripts/update.js +1 -1
  579. package/dist/scripts/validate_bots.d.ts +1 -1
  580. package/dist/scripts/validate_bots.js +1 -1
  581. package/dist/scripts/verify-browser-bundle.d.ts +1 -1
  582. package/dist/scripts/verify-browser-bundle.js +1 -1
  583. package/dist/unlock.js +4 -4
  584. package/dist/unlock.js.map +1 -1
  585. package/docs/COPY_ON_WRITE_MASTER_PLAN.md +9 -9
  586. package/docs/DEXBOT_COMPARISON.md +4 -4
  587. package/docs/EVOLUTION.md +16 -43
  588. package/docs/FUND_MOVEMENT_AND_ACCOUNTING.md +1 -1
  589. package/docs/README.md +1 -1
  590. package/docs/architecture.md +5 -5
  591. package/docs/developer_guide.md +6 -6
  592. package/package.json +22 -14
  593. package/scripts/README.md +33 -7
  594. package/scripts/clean-dist.js +10 -2
  595. package/tests/README.md +4 -3
@@ -1,15 +1,60 @@
1
+ 'use strict';
1
2
  import fs from 'node:fs';
2
3
  import path from 'node:path';
3
- import { calculateAMA } from '../../market_adapter/core/strategies/ama.js';
4
+ import { pathToFileURL } from 'node:url';
5
+ import { calculateAMA, getAmaWarmupBars } from '../../market_adapter/core/strategies/ama.js';
6
+ import { computeAverageAmaSlopePct } from '../../market_adapter/core/strategies/ama_slope_model.js';
4
7
  import { range } from '../math_utils.js';
5
8
  import { parseListOrRange, loadLpData, fmt } from './shared_utils.js';
6
9
  import { getStorage } from '../../modules/storage/index.js';
7
10
  import { PATHS } from '../../modules/paths.js';
11
+ import { GRID_LIMITS, MARKET_ADAPTER } from '../../modules/constants.js';
8
12
  const { ensureDir, readJSON, writeJSON } = getStorage();
9
- 'use strict';
10
- const DEFAULT_ACTIVE_ORDERS = 5;
13
+ // Default mirrors production sizing: createOrderGrid sizes EVERY rail slot in
14
+ // bounds (modules/order/grid.ts), it does not cap per side. Infinity = all
15
+ // slots; --active-orders N restores a bounded run.
16
+ const DEFAULT_ACTIVE_ORDERS = Infinity;
11
17
  const DEFAULT_FEE_ROUNDTRIP_PCT = 0.20;
12
- const DEFAULT_MIN_SPREAD_FACTOR = 2.1;
18
+ // BTS operation fees — same model as backtest_ama_sweep. Every placement
19
+ // (initial grid, reset rebuild, per-cycle slot refill) pays a maker create
20
+ // fee, every cancel pays a cancel fee. Fees are converted into percentage
21
+ // points against --bts-fee-capital so they deduct from net capture in the
22
+ // same units as the rest of the accounting.
23
+ const DEFAULT_BTS_CREATE_FEE = 0.48260;
24
+ const DEFAULT_BTS_CANCEL_FEE = 0.00482;
25
+ const DEFAULT_BTS_MAKER_CREATE_FACTOR = 0.10;
26
+ const DEFAULT_TX_FEE_PRICE = 1.0;
27
+ const DEFAULT_BTS_FEE_CAPITAL = 10000;
28
+ // ── Production grid-reset triggers (MARKET_ADAPTER, modules/constants.ts) ────
29
+ //
30
+ // Trigger A — AMA delta: the live adapter records the AMA center and writes a
31
+ // recalculate.<botKey>.trigger when AMA moves ±AMA_DELTA_THRESHOLD_PERCENT
32
+ // from that recorded center; the center re-records only when a trigger fires
33
+ // (ratchet semantics — see analyze_ama_price_changes.trackRepositions).
34
+ // --reposition-pct overrides the default.
35
+ const DEFAULT_REPOSITION_PCT = MARKET_ADAPTER.AMA_DELTA_THRESHOLD_PERCENT;
36
+ //
37
+ // Trigger B — AMA slope delta, plus the grid price offset, are BOTH gated in
38
+ // production behind the per-bot asymmetricBounds whitelist
39
+ // (market_adapter_service.ts: isGridRangeScalingWhitelisted consumes both
40
+ // shouldTrigger at the slope-reset write and computeGridPriceOffsetPlan via
41
+ // README "asymmetricBounds whitelist also enables gridPriceOffsetPct").
42
+ // The sim therefore exposes one switch, default OFF (typical non-whitelisted
43
+ // bot): --asymmetric-bounds enables slope-delta resets AND slope-ratio offset.
44
+ // Trigger B fires when |slopePct_now − baseline| reaches
45
+ // (AMA_SLOPE_DELTA_THRESHOLD_PERCENT / 100) × DYNAMIC_WEIGHT_AMA_MAX_SLOPE_PCT,
46
+ // where slopePct is the average per-bar AMA change over
47
+ // DYNAMIC_WEIGHT_AMA_LOOKBACK_BARS (computeAverageAmaSlopePct) and the
48
+ // baseline mirrors botState.gridRangeScalingAmaSlope (re-seeded every reset).
49
+ const SLOPE_TRIGGER_FACTOR = MARKET_ADAPTER.AMA_SLOPE_DELTA_THRESHOLD_PERCENT;
50
+ const SLOPE_MAX_PCT = MARKET_ADAPTER.DYNAMIC_WEIGHT_AMA_MAX_SLOPE_PCT;
51
+ const SLOPE_LOOKBACK_BARS = MARKET_ADAPTER.DYNAMIC_WEIGHT_AMA_LOOKBACK_BARS;
52
+ const SLOPE_NEUTRAL_ZONE_PCT = MARKET_ADAPTER.DYNAMIC_WEIGHT_AMA_NEUTRAL_ZONE_PCT;
53
+ // Spread-gap floor knobs (GRID_LIMITS): the effective target spread is
54
+ // clamped up to incrementPercent × MIN_SPREAD_FACTOR and the gap is never
55
+ // narrower than MIN_SPREAD_ORDERS slots — mirrored from calculateGapSlots
56
+ // (modules/order/utils/math.ts).
57
+ const DEFAULT_MIN_SPREAD_FACTOR = GRID_LIMITS.MIN_SPREAD_FACTOR;
13
58
  // Inventory-risk penalty weights (in score points)
14
59
  const RISK_W_DURATION = 1.0; // avg open bars
15
60
  const RISK_W_PEAK_OPEN = 2.0; // peak simultaneous open orders
@@ -29,6 +74,13 @@ function parseArgs() {
29
74
  activeOrders: DEFAULT_ACTIVE_ORDERS,
30
75
  feeRoundtripPct: DEFAULT_FEE_ROUNDTRIP_PCT,
31
76
  minSpreadFactor: DEFAULT_MIN_SPREAD_FACTOR,
77
+ repositionPct: DEFAULT_REPOSITION_PCT,
78
+ asymmetricBounds: false,
79
+ btsCreateFee: DEFAULT_BTS_CREATE_FEE,
80
+ btsCancelFee: DEFAULT_BTS_CANCEL_FEE,
81
+ makerCreateFactor: DEFAULT_BTS_MAKER_CREATE_FACTOR,
82
+ txFeePrice: DEFAULT_TX_FEE_PRICE,
83
+ btsFeeCapital: DEFAULT_BTS_FEE_CAPITAL,
32
84
  riskWDuration: RISK_W_DURATION,
33
85
  riskWPeakOpen: RISK_W_PEAK_OPEN,
34
86
  riskWImbalance: RISK_W_IMBALANCE,
@@ -36,6 +88,12 @@ function parseArgs() {
36
88
  };
37
89
  for (let i = 0; i < args.length; i++) {
38
90
  const arg = args[i];
91
+ // Valueless boolean flag — must be handled before the value lookup
92
+ // below (and before the trailing-arg `if (!val) continue` guard).
93
+ if (arg === '--asymmetric-bounds') {
94
+ out.asymmetricBounds = true;
95
+ continue;
96
+ }
39
97
  const val = args[i + 1];
40
98
  if (!val)
41
99
  continue;
@@ -72,6 +130,30 @@ function parseArgs() {
72
130
  out.minSpreadFactor = Number(val);
73
131
  i++;
74
132
  break;
133
+ case '--reposition-pct':
134
+ out.repositionPct = Number(val);
135
+ i++;
136
+ break;
137
+ case '--bts-create-fee':
138
+ out.btsCreateFee = Number(val);
139
+ i++;
140
+ break;
141
+ case '--bts-cancel-fee':
142
+ out.btsCancelFee = Number(val);
143
+ i++;
144
+ break;
145
+ case '--maker-create-factor':
146
+ out.makerCreateFactor = Number(val);
147
+ i++;
148
+ break;
149
+ case '--tx-fee-price':
150
+ out.txFeePrice = Number(val);
151
+ i++;
152
+ break;
153
+ case '--bts-fee-capital':
154
+ out.btsFeeCapital = Number(val);
155
+ i++;
156
+ break;
75
157
  case '--risk-duration':
76
158
  out.riskWDuration = Number(val);
77
159
  i++;
@@ -156,113 +238,432 @@ function loadAmaStrategies(resultsPath) {
156
238
  }
157
239
  return out;
158
240
  }
159
- function levelGrossSpreadPct(levelRatio) {
160
- return (((1 + levelRatio) / (1 - levelRatio)) - 1) * 100;
241
+ /**
242
+ * Spread-gap width in slots — direct port of calculateGapSlots
243
+ * (modules/order/utils/math.ts:1228). The effective target spread is clamped
244
+ * up to incrementPercent × MIN_SPREAD_FACTOR and the gap never drops below
245
+ * MIN_SPREAD_ORDERS slots. `incrementPercent`/`targetSpreadPercent` in PERCENT
246
+ * units, matching the production signature.
247
+ */
248
+ function computeGapSlots(incrementPercent, targetSpreadPercent) {
249
+ const step = 1 + (incrementPercent / 100);
250
+ const minSpreadPercent = incrementPercent * GRID_LIMITS.MIN_SPREAD_FACTOR;
251
+ const effectiveTargetSpread = Math.max(targetSpreadPercent || 0, minSpreadPercent);
252
+ const requiredSteps = Math.ceil(Math.log(1 + (effectiveTargetSpread / 100)) / Math.log(step));
253
+ return Math.max(GRID_LIMITS.MIN_SPREAD_ORDERS, requiredSteps - 1);
254
+ }
255
+ /**
256
+ * Slope-ratio grid price offset — port of computeGridPriceOffsetPlan
257
+ * (market_adapter/core/market_adapter_service.ts:92-119) combined with the
258
+ * trend/slopeRatio semantics of computeAmaSlopeWeights
259
+ * (market_adapter/core/strategies/ama_slope_model.ts):
260
+ *
261
+ * maxGridPriceOffsetPct = targetSpreadPercent / 2
262
+ * slopeRatio = min(|slopePct| / DYNAMIC_WEIGHT_AMA_MAX_SLOPE_PCT, 1)
263
+ * direction = sign(slopePct) (0 inside the neutral zone)
264
+ * offsetPct = direction × slopeRatio × maxGridPriceOffsetPct
265
+ *
266
+ * Production applies this to startPrice (grid.ts:982: startPrice × (1 +
267
+ * offset/100)) only for asymmetricBounds-whitelisted bots; the sim applies it
268
+ * to the placement center on every grid build when asymmetricBounds is on.
269
+ */
270
+ function computeGridPriceOffsetPct(slopePct, targetSpreadPercent) {
271
+ if (!Number.isFinite(slopePct))
272
+ return 0;
273
+ if (Math.abs(slopePct) <= SLOPE_NEUTRAL_ZONE_PCT)
274
+ return 0;
275
+ const slopeRatio = Math.min(Math.abs(slopePct) / SLOPE_MAX_PCT, 1);
276
+ const maxGridPriceOffsetPct = targetSpreadPercent / 2;
277
+ const direction = slopePct > 0 ? 1 : -1;
278
+ const offsetPct = direction * slopeRatio * maxGridPriceOffsetPct;
279
+ return Math.round(offsetPct * 1e6) / 1e6;
280
+ }
281
+ /**
282
+ * Build a persistent grid with FIXED chain prices from a master rail —
283
+ * port of createOrderGrid (modules/order/grid.ts:374-505):
284
+ *
285
+ * - Master rail: geometric progression starting at √(1±inc) × center and
286
+ * expanding by (1±inc) steps outward, bounded by
287
+ * [center/maxMinRatio, center×maxMinRatio] (grid.ts:428-444).
288
+ * - Spread gap: gapSlots empty slots centered on the center price
289
+ * (calculateIdealBoundary: boundaryIdx = splitIdx − floor(gap/2) − 1;
290
+ * sells start at boundaryIdx + gapSlots + 1).
291
+ * - By default every rail slot in bounds is sized (activeOrders = Infinity,
292
+ * matching production); an explicit cap keeps only the slots nearest the
293
+ * gap on each side.
294
+ *
295
+ * Order prices are placement-time constants — exactly like on-chain orders,
296
+ * they do NOT follow AMA after placement.
297
+ */
298
+ function buildProductionGrid(center, spreadPct, incrementPctFrac, maxMinRatio, activeOrders) {
299
+ const stepUp = 1 + incrementPctFrac;
300
+ const stepDown = 1 - incrementPctFrac;
301
+ const minBound = center / maxMinRatio;
302
+ const maxBound = center * maxMinRatio;
303
+ const rail = [];
304
+ let p = center * Math.sqrt(stepUp);
305
+ while (p <= maxBound) {
306
+ rail.push(p);
307
+ p *= stepUp;
308
+ }
309
+ p = center * Math.sqrt(stepDown);
310
+ while (p >= minBound) {
311
+ rail.push(p);
312
+ p *= stepDown;
313
+ }
314
+ rail.sort((a, b) => a - b);
315
+ if (rail.length === 0)
316
+ return { buys: [], sells: [], rail: [], buySliceStart: 0, sellStartIdx: 0 };
317
+ const gapSlots = computeGapSlots(incrementPctFrac * 100, spreadPct);
318
+ let splitIdx = rail.findIndex((v) => v >= center);
319
+ if (splitIdx === -1)
320
+ splitIdx = rail.length;
321
+ const buySpread = Math.floor(gapSlots / 2);
322
+ const boundaryIdx = Math.max(0, Math.min(rail.length - 1, splitIdx - buySpread - 1));
323
+ const sellStartIdx = boundaryIdx + gapSlots + 1;
324
+ // Buys closest to the gap = highest priced below boundary; sells closest =
325
+ // lowest priced above sellStartIdx. Rail + slice offsets are returned so
326
+ // callers can map each placed slot onto its MASTER-RAIL index (rotation
327
+ // walks adjacent rail nodes, exactly like the live anchor-&-refill hop).
328
+ const buySliceStart = Math.max(0, boundaryIdx - activeOrders + 1);
329
+ const sellsArr = rail.slice(sellStartIdx, sellStartIdx + activeOrders);
330
+ return {
331
+ buys: rail.slice(buySliceStart, boundaryIdx + 1),
332
+ sells: sellsArr,
333
+ rail,
334
+ buySliceStart,
335
+ sellStartIdx,
336
+ };
161
337
  }
338
+ /**
339
+ * Slot-rotation simulation with FIXED chain prices, mirroring production
340
+ * anchor-&-refill (strategy.ts) on top of the createOrderGrid geometry:
341
+ *
342
+ * - Initial grid built once at the post-warmup AMA (createOrderGrid geometry
343
+ * via buildProductionGrid); order prices never follow AMA afterwards. When
344
+ * asymmetricBounds is enabled the placement center is shifted by the
345
+ * slope-ratio offset (#3) exactly like the live startPrice offset.
346
+ * - Rotation economics (#1/#2/#15): a FILLED BUY at rail node k instantly
347
+ * re-offers that base at the ADJACENT MASTER-RAIL NODE k+1; when that
348
+ * refill sells, the rotation books exactly one rail hop minus the
349
+ * round-trip fee, and the freed quote re-bids the node k-1 below. Slots
350
+ * cycle on small oscillations between resets — the earnings model of a
351
+ * refilled live slot, not a cross-gap differential.
352
+ * - Inventory-funded selling: an INITIAL (unlinked) sell can only execute
353
+ * against held inventory — it books its proceeds against the weighted
354
+ * average entry of the position (the live bot funds sells from real
355
+ * balances; unfundable sells stay open and retry, never shorting). Base
356
+ * bought in the SAME bar does not fund unlinked sales until the next bar
357
+ * (live balance updates propagate on the next maintenance tick).
358
+ * - Same-bar guard: newly armed/refill orders carry a one-bar cooldown, so
359
+ * a slot that just cycled cannot fill again inside the completion bar.
360
+ * - Grid reset fires on EITHER production trigger:
361
+ * (A) |AMA − recordedCenter| / recordedCenter ≥ repositionThresholdPct
362
+ * (ratchet: recordedCenter updates only when the trigger fires),
363
+ * (B) slope-delta reset, ONLY when asymmetricBounds (whitelist gate):
364
+ * |slopePct_now − slopeBaseline| ≥ slopeDeltaThresholdPct
365
+ * (= AMA_SLOPE_DELTA_THRESHOLD_PERCENT/100 ×
366
+ * DYNAMIC_WEIGHT_AMA_MAX_SLOPE_PCT), where slopePct is the
367
+ * DYNAMIC_WEIGHT_AMA_LOOKBACK_BARS average-slope series and
368
+ * slopeBaseline mirrors botState.gridRangeScalingAmaSlope — seeded
369
+ * at start and re-seeded on every reset.
370
+ * On reset ALL unfilled orders are canceled (counted); bought-and-held
371
+ * base REMAINS as inventory (live resync never market-sells) and merges
372
+ * into the weighted-average-entry pool; a fresh grid is placed at the
373
+ * new center.
374
+ * - Scoring uses REALIZED rotations and op fees ONLY. The end-of-run
375
+ * inventory position (units × mark-vs-avg-entry) is reported as an
376
+ * informational field — it is real carried risk, but including unrealized
377
+ * bag marks in the ranking objective let trend-following combos dump
378
+ * phantom paper profit into the score.
379
+ * - BTS operation fees (#9): every order placement (initial grid + every
380
+ * armed refill/rebid) pays makerCreateFee × btsCreateFee, every reset
381
+ * cancel pays btsCancelFee; totals are converted to percentage points
382
+ * against the --bts-fee-capital reference and deducted from net capture.
383
+ *
384
+ * Differences from production (by design, documented):
385
+ * #6 bar-granularity triggers and reset-vs-fill ordering (OHLC sim);
386
+ * #7 all-or-nothing fills on raw hi/lo touch (no partial fills/dust/queue);
387
+ * #8 unit sizes / percentage-point accounting instead of capital-weighted
388
+ * dynamic sizing;
389
+ * #10 pool-price fills (no book depth/slippage);
390
+ * #11 no consolidation/dust-cancel/COW/collision mechanics.
391
+ */
162
392
  function simulateForParams(candles, amaValues, params) {
163
- const { spreadPct, incrementPct, maxMinRatio, activeOrders, feeRoundtripPct, risk } = params;
164
- const skip = Math.max(20, Math.floor(candles.length * 0.1));
165
- const levels = Array.from({ length: activeOrders }, (_, i) => incrementPct * (i + 1));
166
- const openBuy = new Map(); // lvl -> openedAtBarIdx
167
- const openSell = new Map(); // lvl -> openedAtBarIdx
393
+ const { spreadPct, incrementPct, maxMinRatio, activeOrders, feeRoundtripPct, repositionThresholdPct, asymmetricBounds, risk, btsCreateFee, btsCancelFee, makerCreateFactor, txFeePrice, btsFeeCapital } = params;
394
+ // Warmup follows production AMA seeding/convergence (getAmaWarmupBars)
395
+ // instead of an arbitrary fraction of the dataset, so simulations never
396
+ // start on SMA-warmup values when the fitted ER period is large.
397
+ const skip = Math.min(params.warmupBars, Math.max(0, candles.length - 2));
398
+ const singleLegFeePct = feeRoundtripPct / 2;
399
+ const slopeDeltaThresholdPct = (SLOPE_TRIGGER_FACTOR / 100) * SLOPE_MAX_PCT;
400
+ const makerCreateFeeBts = btsCreateFee * makerCreateFactor;
401
+ const stepUpFrac = 1 + incrementPct; // one-rail-step rotation distance
402
+ // First tradable bar: need a finite positive AMA to anchor the chain.
403
+ let startIdx = Math.min(skip, candles.length - 1);
404
+ let gridCenter = Number.NaN;
405
+ for (let j = startIdx; j < candles.length; j++) {
406
+ const v = amaValues[j];
407
+ if (Number.isFinite(v) && v > 0) {
408
+ gridCenter = v;
409
+ startIdx = j;
410
+ break;
411
+ }
412
+ }
413
+ // Production AMA slope series (%/bar averaged over the lookback window).
414
+ // Evaluated over full history like the live adapter (only bar-index guards).
415
+ const slopeAt = new Array(candles.length).fill(null);
416
+ for (let j = SLOPE_LOOKBACK_BARS; j < candles.length; j++) {
417
+ const s = computeAverageAmaSlopePct(amaValues[j], amaValues[j - SLOPE_LOOKBACK_BARS], SLOPE_LOOKBACK_BARS);
418
+ if (s != null && Number.isFinite(s))
419
+ slopeAt[j] = s;
420
+ }
421
+ // Open orders keyed by running id: { side, price, linkedBuyPrice,
422
+ // linkedEntryBar, cooldownUntil }. linkedBuyPrice != null marks an armed
423
+ // refill sell created by a specific filled buy (one-increment rotation).
424
+ const orders = new Map();
425
+ let nextOrderId = 0;
426
+ // Bought-and-held base across the whole run (weighted-average entry
427
+ // pool). Never negative — sells without inventory stay pending.
428
+ const inv = { units: 0, cost: 0 };
429
+ let btsFeesBts = 0;
430
+ let offsetAppliedCount = 0;
431
+ // Master rail of the CURRENT epoch — rotation hops read adjacent nodes.
432
+ let activeRail = [];
433
+ const placeInitialGrid = (center, slopePct) => {
434
+ const offsetPct = (asymmetricBounds && slopePct != null)
435
+ ? computeGridPriceOffsetPct(slopePct, spreadPct)
436
+ : 0;
437
+ if (offsetPct !== 0)
438
+ offsetAppliedCount++;
439
+ const effCenter = center * (1 + offsetPct / 100);
440
+ const built = buildProductionGrid(effCenter, spreadPct, incrementPct, maxMinRatio, activeOrders);
441
+ activeRail = built.rail;
442
+ orders.clear();
443
+ // Rail indices matter: rotation re-offers/re-bids walk ADJACENT
444
+ // master-rail nodes (buy at node k arms a sell at node k+1; the freed
445
+ // quote re-bids node k-1), preserving the exact production hop sizes.
446
+ built.buys.forEach((price, i) => orders.set(nextOrderId++, {
447
+ side: 'buy', price, railIdx: built.buySliceStart + i,
448
+ linkedBuyPrice: null, linkedEntryBar: -1, cooldownUntil: -1,
449
+ }));
450
+ built.sells.forEach((price, i) => orders.set(nextOrderId++, {
451
+ side: 'sell', price, railIdx: built.sellStartIdx + i,
452
+ linkedBuyPrice: null, linkedEntryBar: -1, cooldownUntil: -1,
453
+ }));
454
+ btsFeesBts += (built.buys.length + built.sells.length) * makerCreateFeeBts;
455
+ };
168
456
  let touchedOrders = 0;
169
- let matchedPairs = 0;
457
+ let cyclesTotal = 0;
458
+ let rotationCount = 0; // linked ping-pong rotations (buy → refill sell)
459
+ let inventorySaleCount = 0; // unlinked sells executed against held bags
170
460
  let canceledOnReposition = 0;
461
+ let repositionCount = 0;
462
+ let driftTriggerCount = 0;
463
+ let slopeTriggerCount = 0;
171
464
  let totalGrossCapturePct = 0;
172
465
  let totalNetCapturePct = 0;
173
- let activeLevelTouches = 0;
174
466
  let peakOpenOrders = 0;
175
467
  let imbalanceSum = 0;
176
468
  let imbalanceSamples = 0;
177
469
  let matchedOpenDurationBars = 0;
178
- for (let i = skip + 1; i < candles.length; i++) {
470
+ const invAvgEntry = () => (inv.units > 0 ? inv.cost / inv.units : 0);
471
+ if (Number.isFinite(gridCenter))
472
+ placeInitialGrid(gridCenter, slopeAt[startIdx]);
473
+ // Slope-delta baseline: mirrors botState.gridRangeScalingAmaSlope —
474
+ // seeded at bootstrap (first cycle) and re-seeded to the current slope on
475
+ // EVERY grid reset (advanceTriggeredBotState), so trigger B measures how
476
+ // far slope has moved SINCE THE LAST RESET, not bar-over-bar jitter.
477
+ let slopeBaseline = null;
478
+ for (let j = startIdx + 1; j < candles.length; j++) {
479
+ if (slopeAt[j] != null) {
480
+ slopeBaseline = slopeAt[j];
481
+ break;
482
+ }
483
+ }
484
+ for (let i = startIdx + 1; i < candles.length; i++) {
179
485
  const ama = amaValues[i];
180
- const prevAma = amaValues[i - 1];
181
486
  const hi = candles[i].high;
182
487
  const lo = candles[i].low;
183
- if (Math.abs(ama - prevAma) / prevAma > incrementPct) {
184
- canceledOnReposition += openBuy.size + openSell.size;
185
- openBuy.clear();
186
- openSell.clear();
488
+ // ── Grid-reset check: trigger A (AMA delta) always; trigger B
489
+ // (slope delta) only under the asymmetricBounds whitelist gate.
490
+ let shouldReset = false;
491
+ if (Number.isFinite(ama) && ama > 0) {
492
+ const driftPct = (Math.abs(ama - gridCenter) / gridCenter) * 100;
493
+ if (driftPct >= repositionThresholdPct) {
494
+ shouldReset = true;
495
+ driftTriggerCount++;
496
+ }
497
+ }
498
+ if (!shouldReset && asymmetricBounds && slopeBaseline != null && slopeAt[i] != null) {
499
+ const slopeDeltaPct = Math.abs(slopeAt[i] - slopeBaseline);
500
+ if (slopeDeltaPct >= slopeDeltaThresholdPct) {
501
+ shouldReset = true;
502
+ slopeTriggerCount++;
503
+ }
187
504
  }
188
- const currentOpen = openBuy.size + openSell.size;
505
+ if (shouldReset && Number.isFinite(ama) && ama > 0) {
506
+ canceledOnReposition += orders.size;
507
+ btsFeesBts += orders.size * btsCancelFee;
508
+ orders.clear(); // inventory survives — resync never market-sells
509
+ repositionCount++;
510
+ gridCenter = ama; // ratchet the recorded center to the current AMA
511
+ // Re-seed the slope baseline with the current slope (falls back to
512
+ // the previous baseline when slope is not ready — same as
513
+ // advanceTriggeredBotState's `|| previous` chain).
514
+ if (slopeAt[i] != null)
515
+ slopeBaseline = slopeAt[i];
516
+ placeInitialGrid(gridCenter, slopeAt[i]);
517
+ }
518
+ const currentOpen = orders.size;
189
519
  if (currentOpen > peakOpenOrders)
190
520
  peakOpenOrders = currentOpen;
191
- imbalanceSum += Math.abs(openBuy.size - openSell.size);
521
+ let buyCount = 0;
522
+ for (const [, o] of orders) {
523
+ if (o.side === 'buy')
524
+ buyCount++;
525
+ }
526
+ imbalanceSum += Math.abs(buyCount - (orders.size - buyCount));
192
527
  imbalanceSamples++;
193
- const minBound = ama / maxMinRatio;
194
- const maxBound = ama * maxMinRatio;
195
- for (let lvl = 0; lvl < levels.length; lvl++) {
196
- const r = levels[lvl];
197
- if (r >= 0.95)
198
- continue;
199
- const buyPrice = ama * (1 - r);
200
- const sellPrice = ama * (1 + r);
201
- if (buyPrice < minBound || sellPrice > maxBound)
202
- continue;
203
- const grossPct = levelGrossSpreadPct(r);
204
- if (grossPct < spreadPct)
528
+ // ── Fill detection against FIXED chain prices ───────────────────
529
+ const filledBuys = [];
530
+ const filledSells = [];
531
+ for (const [id, o] of orders) {
532
+ if (i < o.cooldownUntil)
205
533
  continue;
206
- const touchBuy = lo <= buyPrice;
207
- const touchSell = hi >= sellPrice;
208
- if (!touchBuy && !touchSell)
209
- continue;
210
- activeLevelTouches++;
211
- if (touchBuy && !openBuy.has(lvl)) {
212
- touchedOrders++;
213
- if (openSell.has(lvl)) {
214
- const openedAt = openSell.get(lvl);
215
- matchedOpenDurationBars += (i - openedAt);
216
- matchedPairs++;
217
- openSell.delete(lvl);
218
- totalGrossCapturePct += grossPct;
219
- }
220
- else {
221
- openBuy.set(lvl, i);
222
- }
534
+ if (o.side === 'buy' && lo <= o.price)
535
+ filledBuys.push({ id, order: o });
536
+ else if (o.side === 'sell' && hi >= o.price)
537
+ filledSells.push({ id, order: o });
538
+ }
539
+ touchedOrders += filledBuys.length + filledSells.length;
540
+ // Base held BEFORE this bar's intakes — an unlinked sell may only
541
+ // dispose against pre-existing funds (live balance updates propagate
542
+ // on the next maintenance tick; same-bar funding is not assumed).
543
+ const invAtBarStart = inv.units;
544
+ // ── Buy intakes first: base enters inventory, refill armed at the
545
+ // ADJACENT MASTER-RAIL NODE above (anchor-&-refill hop; cooldown
546
+ // blocks same-bar recycles).
547
+ for (const f of filledBuys) {
548
+ orders.delete(f.id);
549
+ inv.units += 1;
550
+ inv.cost += f.order.price;
551
+ const upIdx = (f.order.railIdx ?? -1) + 1;
552
+ const refillPrice = activeRail[upIdx] ?? f.order.price * stepUpFrac;
553
+ orders.set(nextOrderId++, {
554
+ side: 'sell',
555
+ price: refillPrice,
556
+ railIdx: upIdx,
557
+ linkedBuyPrice: f.order.price,
558
+ linkedEntryBar: i,
559
+ cooldownUntil: i + 1,
560
+ });
561
+ btsFeesBts += makerCreateFeeBts;
562
+ }
563
+ // ── Sell disposals: linked refills book the one-rail-hop rotation;
564
+ // unlinked (initial-grid) sells need held inventory — no shorting.
565
+ // Linked refills resolve FIRST so same-bar cross-gap inventory
566
+ // sales against a fresh bag cannot happen.
567
+ filledSells.sort((a, b) => ((a.order.linkedBuyPrice != null ? 0 : 1) - (b.order.linkedBuyPrice != null ? 0 : 1)));
568
+ let disposables = invAtBarStart;
569
+ for (const f of filledSells) {
570
+ const o = f.order;
571
+ if (o.linkedBuyPrice != null) {
572
+ const grossPct = (o.price / o.linkedBuyPrice - 1) * 100;
573
+ totalGrossCapturePct += grossPct;
574
+ totalNetCapturePct += grossPct - feeRoundtripPct;
575
+ cyclesTotal++;
576
+ rotationCount++;
577
+ matchedOpenDurationBars += Math.abs(i - o.linkedEntryBar);
578
+ // Dispose the unit its own rotation bought.
579
+ const applied = Math.min(1, inv.units);
580
+ inv.cost -= applied * invAvgEntry();
581
+ inv.units -= applied;
582
+ // Its disposal also drains the pre-bar funding budget —
583
+ // otherwise later unlinked sales could overspend stock.
584
+ disposables -= applied;
585
+ // Freed quote re-bids the ADJACENT RAIL NODE below.
586
+ const downIdx = (o.railIdx ?? 0) - 1;
587
+ const rebidPrice = activeRail[downIdx] ?? o.price / stepUpFrac;
588
+ orders.delete(f.id);
589
+ orders.set(nextOrderId++, {
590
+ side: 'buy',
591
+ price: rebidPrice,
592
+ railIdx: downIdx,
593
+ linkedBuyPrice: null,
594
+ linkedEntryBar: -1,
595
+ cooldownUntil: i + 1,
596
+ });
597
+ btsFeesBts += makerCreateFeeBts;
223
598
  }
224
- if (touchSell && !openSell.has(lvl)) {
225
- touchedOrders++;
226
- if (openBuy.has(lvl)) {
227
- const openedAt = openBuy.get(lvl);
228
- matchedOpenDurationBars += (i - openedAt);
229
- matchedPairs++;
230
- openBuy.delete(lvl);
231
- totalGrossCapturePct += grossPct;
232
- }
233
- else {
234
- openSell.set(lvl, i);
235
- }
599
+ else if (disposables >= 1) {
600
+ const avgEntry = invAvgEntry();
601
+ const grossPct = (o.price / avgEntry - 1) * 100;
602
+ totalGrossCapturePct += grossPct;
603
+ totalNetCapturePct += grossPct - feeRoundtripPct;
604
+ cyclesTotal++;
605
+ inventorySaleCount++;
606
+ inv.cost -= avgEntry; // remove that unit at pool-average cost
607
+ inv.units -= 1;
608
+ disposables -= 1;
609
+ orders.delete(f.id); // sold bag is gone; slot not re-armed
610
+ }
611
+ else {
612
+ // Unfundable (no base to sell): stays open, retries next bar.
613
+ o.cooldownUntil = i + 1;
236
614
  }
237
615
  }
238
616
  }
239
- // Profit model requested: totalProfit = fills * (spread - increment)
240
- // (all values in percentage points)
241
- const incrementPctPoints = incrementPct * 100;
242
- const netPerFillPct = Math.max(0, spreadPct - incrementPctPoints - feeRoundtripPct);
243
- totalNetCapturePct = matchedPairs * netPerFillPct;
244
- const fillEfficiency = touchedOrders > 0 ? (matchedPairs / touchedOrders) * 100 : 0;
245
- const avgNetPerPair = matchedPairs > 0 ? totalNetCapturePct / matchedPairs : 0;
246
- const utilization = (activeLevelTouches / Math.max(1, (candles.length - skip))) * 100;
247
- const baseScore = totalNetCapturePct * (fillEfficiency / 100);
248
- const avgOpenDurationBars = matchedPairs > 0 ? (matchedOpenDurationBars / matchedPairs) : 0;
617
+ // ── End-of-run inventory mark (informational, NOT in score) ────────
618
+ // Bought-and-held base is real carried risk, but unrealized bag marks are
619
+ // excluded from ranking so trend-following combos can't dump phantom
620
+ // paper profit into the objective. Marked once at the final close with a
621
+ // single-leg exit fee per unit.
622
+ const lastClose = candles.length > 0 ? candles[candles.length - 1].close : NaN;
623
+ const inventoryUnits = inv.units;
624
+ const inventoryAvgEntry = invAvgEntry();
625
+ const inventoryNetPts = inventoryUnits > 0 && Number.isFinite(lastClose) && lastClose > 0
626
+ ? (((lastClose / inventoryAvgEntry) - 1) * 100 - singleLegFeePct) * inventoryUnits
627
+ : 0;
628
+ // BTS operation fees → percentage points against the reference capital.
629
+ const btsFeePts = (btsFeesBts * txFeePrice) / Math.max(1, btsFeeCapital) * 100;
630
+ const totalNetCaptureAfterFeesPct = totalNetCapturePct - btsFeePts;
631
+ const fillEfficiency = touchedOrders > 0 ? (cyclesTotal / touchedOrders) * 100 : 0;
632
+ const avgNetPerPair = cyclesTotal > 0 ? totalNetCapturePct / cyclesTotal : 0;
633
+ const utilization = (touchedOrders / Math.max(1, candles.length - skip)) * 100;
634
+ const avgOpenDurationBars = rotationCount > 0 ? (matchedOpenDurationBars / rotationCount) : 0;
249
635
  const avgImbalance = imbalanceSamples > 0 ? (imbalanceSum / imbalanceSamples) : 0;
250
636
  const riskPenalty = (avgOpenDurationBars * risk.duration) +
251
637
  (peakOpenOrders * risk.peakOpen) +
252
638
  (avgImbalance * risk.imbalance) +
253
639
  (canceledOnReposition * risk.cancel);
640
+ const baseScore = totalNetCaptureAfterFeesPct * (fillEfficiency / 100);
254
641
  const score = baseScore - riskPenalty;
255
642
  return {
256
643
  spreadPct,
257
644
  incrementPct,
258
645
  maxMinRatio,
259
646
  touchedOrders,
260
- matchedPairs,
647
+ matchedPairs: cyclesTotal,
648
+ cyclesTotal,
649
+ rotationCount,
650
+ inventorySaleCount,
651
+ avgCyclesPerSlot: cyclesTotal / Math.max(1, peakOpenOrders),
261
652
  fillEfficiency,
262
653
  totalGrossCapturePct,
263
654
  totalNetCapturePct,
655
+ btsFeePts,
656
+ btsFeesBts,
657
+ totalNetCaptureAfterFeesPct,
264
658
  avgNetPerPair,
265
659
  canceledOnReposition,
660
+ repositionCount,
661
+ driftTriggerCount,
662
+ slopeTriggerCount,
663
+ inventoryUnits,
664
+ inventoryAvgEntry,
665
+ inventoryNetPts,
666
+ offsetAppliedCount,
266
667
  avgOpenDurationBars,
267
668
  peakOpenOrders,
268
669
  avgImbalance,
@@ -290,6 +691,9 @@ function run() {
290
691
  const candles = loaded.candles;
291
692
  const closes = candles.map((c) => c.close);
292
693
  const strategies = loadAmaStrategies(cfg.resultsPath);
694
+ if (!Number.isFinite(cfg.repositionPct) || cfg.repositionPct <= 0) {
695
+ throw new Error(`Invalid reposition threshold: ${cfg.repositionPct}`);
696
+ }
293
697
  const totalCombos = cfg.spreadValues.length * cfg.incrementValues.length * cfg.ratioValues.length;
294
698
  console.log('================================================================================');
295
699
  console.log(' BOT FITTING BACKTEST (1h LP candles)');
@@ -299,26 +703,43 @@ function run() {
299
703
  console.log(` Spread grid: ${cfg.spreadValues[0]}..${cfg.spreadValues[cfg.spreadValues.length - 1]}% (${cfg.spreadValues.length})`);
300
704
  console.log(` Increment: ${cfg.incrementValues[0]}..${cfg.incrementValues[cfg.incrementValues.length - 1]}% (${cfg.incrementValues.length})`);
301
705
  console.log(` Max/Min ratio:${cfg.ratioValues[0]}..${cfg.ratioValues[cfg.ratioValues.length - 1]} (${cfg.ratioValues.length})`);
302
- console.log(` Active orders:${cfg.activeOrders} per side`);
706
+ console.log(` Active orders:${Number.isFinite(cfg.activeOrders) ? cfg.activeOrders : 'all'} per side (Infinity = every rail slot, matching production)`);
303
707
  console.log(` Fee RT: ${cfg.feeRoundtripPct}%`);
304
708
  console.log(` Spread floor: spread >= ${cfg.minSpreadFactor} x increment`);
709
+ console.log(` Reset (A): AMA drift >= ${cfg.repositionPct}% from recorded center${cfg.repositionPct === DEFAULT_REPOSITION_PCT ? ' (AMA_DELTA_THRESHOLD_PERCENT)' : ''}`);
710
+ console.log(` Asym. bounds: ${cfg.asymmetricBounds ? 'ON — slope reset (B) + grid price offset enabled (whitelist semantics)' : 'OFF — typical non-whitelisted bot (production default)'}`);
711
+ console.log(` Reset (B): |slope - slope@lastReset| >= ${(SLOPE_TRIGGER_FACTOR / 100) * SLOPE_MAX_PCT}% (${SLOPE_TRIGGER_FACTOR}% x ${SLOPE_MAX_PCT}, lookback ${SLOPE_LOOKBACK_BARS})${cfg.asymmetricBounds ? '' : ' [gated off]'}`);
712
+ console.log(` Tx fees: create=${fmt(cfg.btsCreateFee * cfg.makerCreateFactor, 5)} BTS, cancel=${fmt(cfg.btsCancelFee, 5)} BTS, 1 BTS=${fmt(cfg.txFeePrice, 2)} units, capital=${fmt(cfg.btsFeeCapital, 0)}`);
305
713
  console.log(` Risk W: duration=${cfg.riskWDuration}, peakOpen=${cfg.riskWPeakOpen}, imbalance=${cfg.riskWImbalance}, cancel=${cfg.riskWCancel}`);
306
714
  console.log(` Combos/AMA: ${totalCombos}\n`);
307
715
  const byAma = [];
308
716
  for (const s of strategies) {
309
717
  const amaValues = calculateAMA(closes, { erPeriod: s.er, fastPeriod: s.fast, slowPeriod: s.slow });
718
+ // Production-aligned warmup: ER window + convergence (getAmaWarmupBars).
719
+ const warmupBars = getAmaWarmupBars(s.er, s.slow, 0, s.fast);
310
720
  let best = null;
311
721
  for (const spreadPct of cfg.spreadValues) {
312
722
  for (const incrementPct of cfg.incrementValues) {
723
+ // Dedup guard only: computeGapSlots clamps the effective target
724
+ // spread up to increment × MIN_SPREAD_FACTOR, so combos below the
725
+ // floor would build an identical grid to the floored combo.
726
+ if (spreadPct + Number.EPSILON < (cfg.minSpreadFactor * incrementPct))
727
+ continue;
313
728
  for (const maxMinRatio of cfg.ratioValues) {
314
- if (spreadPct + Number.EPSILON < (cfg.minSpreadFactor * incrementPct))
315
- continue;
316
729
  const sim = simulateForParams(candles, amaValues, {
317
730
  spreadPct,
318
731
  incrementPct: incrementPct / 100,
319
732
  maxMinRatio,
320
733
  activeOrders: cfg.activeOrders,
321
734
  feeRoundtripPct: cfg.feeRoundtripPct,
735
+ repositionThresholdPct: cfg.repositionPct,
736
+ asymmetricBounds: cfg.asymmetricBounds,
737
+ btsCreateFee: cfg.btsCreateFee,
738
+ btsCancelFee: cfg.btsCancelFee,
739
+ makerCreateFactor: cfg.makerCreateFactor,
740
+ txFeePrice: cfg.txFeePrice,
741
+ btsFeeCapital: cfg.btsFeeCapital,
742
+ warmupBars,
322
743
  risk: {
323
744
  duration: cfg.riskWDuration,
324
745
  peakOpen: cfg.riskWPeakOpen,
@@ -335,8 +756,8 @@ function run() {
335
756
  }
336
757
  console.log('BEST PARAMS PER AMA');
337
758
  console.log('--------------------------------------------------------------------------------');
338
- console.log('AMA | spread | incr | ratio | pairs | fill% | net% | risk | score');
339
- console.log('---------------------------------|--------|------|-------|-------|-------|--------|-------|-------');
759
+ console.log('AMA | spread | incr | ratio | cyc | fill% | net% | risk | score | inv-units (info)');
760
+ console.log('---------------------------------|--------|------|-------|-------|-------|--------|-------|-------|-----------------');
340
761
  for (const row of byAma) {
341
762
  const b = row.best;
342
763
  if (!b)
@@ -349,8 +770,10 @@ function run() {
349
770
  `${fmt(b.fillEfficiency, 1).padStart(5)} | ` +
350
771
  `${fmt(b.totalNetCapturePct, 1).padStart(6)} | ` +
351
772
  `${fmt(b.riskPenalty, 1).padStart(5)} | ` +
352
- `${fmt(b.score, 1).padStart(5)}`);
773
+ `${fmt(b.score, 1).padStart(5)} | ` +
774
+ `${fmt(b.inventoryUnits, 0).padStart(8)} (${fmt(b.inventoryNetPts, 1)} pts)`);
353
775
  }
776
+ console.log('(* end-of-run inventory mark: informational only — excluded from scoring)');
354
777
  console.log();
355
778
  const outName = `bot_fitting_results_${path.basename(cfg.dataPath, '.json')}.json`;
356
779
  const outPath = path.join(PATHS.ANALYSIS.RESULTS_DIR, outName);
@@ -361,18 +784,34 @@ function run() {
361
784
  dataPath: path.relative(process.cwd(), cfg.dataPath),
362
785
  resultsPath: path.relative(process.cwd(), cfg.resultsPath),
363
786
  candles: candles.length,
364
- activeOrders: cfg.activeOrders,
787
+ activeOrders: Number.isFinite(cfg.activeOrders) ? cfg.activeOrders : 'all',
365
788
  feeRoundtripPct: cfg.feeRoundtripPct,
789
+ btsCreateFee: cfg.btsCreateFee,
790
+ btsCancelFee: cfg.btsCancelFee,
791
+ makerCreateFactor: cfg.makerCreateFactor,
792
+ txFeePrice: cfg.txFeePrice,
793
+ btsFeeCapital: cfg.btsFeeCapital,
366
794
  search: {
367
795
  spreadValues: cfg.spreadValues,
368
796
  incrementValues: cfg.incrementValues,
369
797
  ratioValues: cfg.ratioValues,
370
798
  minSpreadFactor: cfg.minSpreadFactor,
799
+ repositionPct: cfg.repositionPct,
800
+ asymmetricBounds: cfg.asymmetricBounds,
371
801
  combosPerAma: totalCombos,
372
802
  },
373
803
  scoring: {
374
- baseScore: 'totalNetCapturePct * (fillEfficiency / 100)',
375
- totalNetCapturePct: 'matchedPairs * (spread - increment - fee)',
804
+ baseScore: 'totalNetCaptureAfterFeesPct * (fillEfficiency / 100)',
805
+ gridModel: 'persistent fixed chain prices (createOrderGrid port): master rail at sqrt(1±inc) offsets bounded by [center/ratio, center*ratio], gapSlots spread zone centered on center; prices never follow AMA after placement',
806
+ spreadParam: 'targetSpreadPercent for calculateGapSlots (floored at increment * MIN_SPREAD_FACTOR)',
807
+ resetTriggers: `(A) AMA drift >= ${cfg.repositionPct}% from recorded center (ratchet)${cfg.asymmetricBounds ? ` OR (B) |slope - slopeAtLastReset| >= ${(SLOPE_TRIGGER_FACTOR / 100) * SLOPE_MAX_PCT}% over ${SLOPE_LOOKBACK_BARS}-bar average slope (baseline re-seeded on every reset)` : ' (trigger B gated off — asymmetricBounds whitelist)'}`,
808
+ gridPriceOffset: cfg.asymmetricBounds ? 'slope-ratio offset applied to placement center (direction * min(|slope|/maxSlopePct,1) * targetSpread/2) on every grid build' : 'disabled (asymmetricBounds whitelist)',
809
+ repositionAccounting: 'unfilled orders canceled + counted (incl armed refills/rebids); bought-and-held base carries across resets in a weighted-average-entry inventory pool (resync never market-sells); end-of-run inventory mark is informational and excluded from scoring',
810
+ cycleEconomics: 'slot rotation: filled buy re-offers one rail step up; that refill selling books ~increment% minus round-trip fee and the freed quote re-bids one step down; unlinked initial-grid sells only execute against held inventory at weighted-average entry (no shorting)',
811
+ totalGrossCapturePct: 'sum of realized per-rotation gross from actual fixed prices (linked rotations + inventory sales)',
812
+ totalNetCapturePct: 'realized gross - roundtrip fee per completed disposition; excludes the end-of-run inventory mark',
813
+ btsFees: `every order placement (initial grid + armed refills/rebids) pays maker create (${cfg.btsCreateFee}*${cfg.makerCreateFactor} BTS), every reset cancel pays ${cfg.btsCancelFee} BTS; btsFeePts = total BTS * txFeePrice / btsFeeCapital * 100 deducted from net before scoring`,
814
+ warmup: 'getAmaWarmupBars(er, slow, 0, fast)',
376
815
  riskPenalty: `avgOpenDurationBars*${cfg.riskWDuration} + peakOpenOrders*${cfg.riskWPeakOpen} + avgImbalance*${cfg.riskWImbalance} + canceledOnReposition*${cfg.riskWCancel}`,
377
816
  finalScore: 'baseScore - riskPenalty',
378
817
  },
@@ -381,5 +820,10 @@ function run() {
381
820
  });
382
821
  console.log(`Saved: ${path.relative(process.cwd(), outPath)}`);
383
822
  }
384
- run();
823
+ // Main-thread entry guard: importing this module (e.g. from the logic tests)
824
+ // must not execute the CLI run.
825
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
826
+ run();
827
+ }
828
+ export { computeGapSlots, computeGridPriceOffsetPct, buildProductionGrid, simulateForParams };
385
829
  //# sourceMappingURL=backtest_bot_fitting.js.map