dexbot 1.1.10

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 (807) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +287 -0
  3. package/claw/README.md +513 -0
  4. package/claw/scripts/memu_runner.py +385 -0
  5. package/claw/skills/bitshares-guide/SKILL.md +14 -0
  6. package/claw/skills/bitshares-guide/references/example-skill-shells.md +18 -0
  7. package/claw/skills/bitshares-guide/references/presentation-patterns.md +19 -0
  8. package/claw/skills/bitshares-guide/references/scope-guardrails.md +9 -0
  9. package/claw/skills/launcher-ops/SKILL.md +18 -0
  10. package/claw/skills/launcher-ops/references/launcher-workflow.md +23 -0
  11. package/claw/skills/margin-trading/SKILL.md +23 -0
  12. package/claw/skills/margin-trading/references/honest-asset-list.md +74 -0
  13. package/claw/skills/margin-trading/references/honest-assets.md +44 -0
  14. package/claw/skills/margin-trading/references/position-management.md +203 -0
  15. package/claw/skills/margin-trading/references/trading-concepts.md +80 -0
  16. package/claw/skills/memu-memory/SKILL.md +218 -0
  17. package/claw/skills/shared/references/js-automation-overview.md +24 -0
  18. package/claw/skills/shared/references/safety-and-staleness.md +11 -0
  19. package/claw/skills/shared/references/skill-boundaries.md +17 -0
  20. package/claw/skills/trend-detection/SKILL.md +33 -0
  21. package/claw/skills/trend-detection/agents/openai.yaml +3 -0
  22. package/claw/skills/trend-detection/references/service.md +45 -0
  23. package/dist/analysis/ama_fitting/analyze_ama_price_changes.d.ts +3 -0
  24. package/dist/analysis/ama_fitting/analyze_ama_price_changes.d.ts.map +1 -0
  25. package/dist/analysis/ama_fitting/analyze_ama_price_changes.js +149 -0
  26. package/dist/analysis/ama_fitting/analyze_ama_price_changes.js.map +1 -0
  27. package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.d.ts +3 -0
  28. package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.d.ts.map +1 -0
  29. package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.js +387 -0
  30. package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.js.map +1 -0
  31. package/dist/analysis/ama_fitting/calibrate_convergence_er.d.ts +3 -0
  32. package/dist/analysis/ama_fitting/calibrate_convergence_er.d.ts.map +1 -0
  33. package/dist/analysis/ama_fitting/calibrate_convergence_er.js +200 -0
  34. package/dist/analysis/ama_fitting/calibrate_convergence_er.js.map +1 -0
  35. package/dist/analysis/ama_fitting/fetch_lp_candles.d.ts +3 -0
  36. package/dist/analysis/ama_fitting/fetch_lp_candles.d.ts.map +1 -0
  37. package/dist/analysis/ama_fitting/fetch_lp_candles.js +212 -0
  38. package/dist/analysis/ama_fitting/fetch_lp_candles.js.map +1 -0
  39. package/dist/analysis/ama_fitting/generate_unified_comparison_chart.d.ts +31 -0
  40. package/dist/analysis/ama_fitting/generate_unified_comparison_chart.d.ts.map +1 -0
  41. package/dist/analysis/ama_fitting/generate_unified_comparison_chart.js +249 -0
  42. package/dist/analysis/ama_fitting/generate_unified_comparison_chart.js.map +1 -0
  43. package/dist/analysis/ama_fitting/optimizer_high_resolution.d.ts +2 -0
  44. package/dist/analysis/ama_fitting/optimizer_high_resolution.d.ts.map +1 -0
  45. package/dist/analysis/ama_fitting/optimizer_high_resolution.js +782 -0
  46. package/dist/analysis/ama_fitting/optimizer_high_resolution.js.map +1 -0
  47. package/dist/analysis/analyze_derivatives.d.ts +95 -0
  48. package/dist/analysis/analyze_derivatives.d.ts.map +1 -0
  49. package/dist/analysis/analyze_derivatives.js +295 -0
  50. package/dist/analysis/analyze_derivatives.js.map +1 -0
  51. package/dist/analysis/analyze_dynamic_weight.d.ts +14 -0
  52. package/dist/analysis/analyze_dynamic_weight.d.ts.map +1 -0
  53. package/dist/analysis/analyze_dynamic_weight.js +208 -0
  54. package/dist/analysis/analyze_dynamic_weight.js.map +1 -0
  55. package/dist/analysis/analyze_kalman.d.ts +13 -0
  56. package/dist/analysis/analyze_kalman.d.ts.map +1 -0
  57. package/dist/analysis/analyze_kalman.js +123 -0
  58. package/dist/analysis/analyze_kalman.js.map +1 -0
  59. package/dist/analysis/analyze_regime.d.ts +20 -0
  60. package/dist/analysis/analyze_regime.d.ts.map +1 -0
  61. package/dist/analysis/analyze_regime.js +139 -0
  62. package/dist/analysis/analyze_regime.js.map +1 -0
  63. package/dist/analysis/analyze_regime_windows.d.ts +19 -0
  64. package/dist/analysis/analyze_regime_windows.d.ts.map +1 -0
  65. package/dist/analysis/analyze_regime_windows.js +413 -0
  66. package/dist/analysis/analyze_regime_windows.js.map +1 -0
  67. package/dist/analysis/analyze_risk_profile.d.ts +3 -0
  68. package/dist/analysis/analyze_risk_profile.d.ts.map +1 -0
  69. package/dist/analysis/analyze_risk_profile.js +159 -0
  70. package/dist/analysis/analyze_risk_profile.js.map +1 -0
  71. package/dist/analysis/analyze_trade_heatmap.d.ts +3 -0
  72. package/dist/analysis/analyze_trade_heatmap.d.ts.map +1 -0
  73. package/dist/analysis/analyze_trade_heatmap.js +367 -0
  74. package/dist/analysis/analyze_trade_heatmap.js.map +1 -0
  75. package/dist/analysis/analyze_volatility.d.ts +22 -0
  76. package/dist/analysis/analyze_volatility.d.ts.map +1 -0
  77. package/dist/analysis/analyze_volatility.js +172 -0
  78. package/dist/analysis/analyze_volatility.js.map +1 -0
  79. package/dist/analysis/bot_fitting/backtest_ama_sweep.d.ts +99 -0
  80. package/dist/analysis/bot_fitting/backtest_ama_sweep.d.ts.map +1 -0
  81. package/dist/analysis/bot_fitting/backtest_ama_sweep.js +804 -0
  82. package/dist/analysis/bot_fitting/backtest_ama_sweep.js.map +1 -0
  83. package/dist/analysis/bot_fitting/backtest_bot_fitting.d.ts +2 -0
  84. package/dist/analysis/bot_fitting/backtest_bot_fitting.d.ts.map +1 -0
  85. package/dist/analysis/bot_fitting/backtest_bot_fitting.js +347 -0
  86. package/dist/analysis/bot_fitting/backtest_bot_fitting.js.map +1 -0
  87. package/dist/analysis/bot_fitting/shared_utils.d.ts +15 -0
  88. package/dist/analysis/bot_fitting/shared_utils.d.ts.map +1 -0
  89. package/dist/analysis/bot_fitting/shared_utils.js +48 -0
  90. package/dist/analysis/bot_fitting/shared_utils.js.map +1 -0
  91. package/dist/analysis/bot_key_utils.d.ts +16 -0
  92. package/dist/analysis/bot_key_utils.d.ts.map +1 -0
  93. package/dist/analysis/bot_key_utils.js +61 -0
  94. package/dist/analysis/bot_key_utils.js.map +1 -0
  95. package/dist/analysis/bot_usage/discover_bot_accounts.d.ts +3 -0
  96. package/dist/analysis/bot_usage/discover_bot_accounts.d.ts.map +1 -0
  97. package/dist/analysis/bot_usage/discover_bot_accounts.js +498 -0
  98. package/dist/analysis/bot_usage/discover_bot_accounts.js.map +1 -0
  99. package/dist/analysis/bot_usage/kibana_bot_queries.d.ts +546 -0
  100. package/dist/analysis/bot_usage/kibana_bot_queries.d.ts.map +1 -0
  101. package/dist/analysis/bot_usage/kibana_bot_queries.js +427 -0
  102. package/dist/analysis/bot_usage/kibana_bot_queries.js.map +1 -0
  103. package/dist/analysis/chart_utils.d.ts +13 -0
  104. package/dist/analysis/chart_utils.d.ts.map +1 -0
  105. package/dist/analysis/chart_utils.js +142 -0
  106. package/dist/analysis/chart_utils.js.map +1 -0
  107. package/dist/analysis/derivative_chart_generator.d.ts +18 -0
  108. package/dist/analysis/derivative_chart_generator.d.ts.map +1 -0
  109. package/dist/analysis/derivative_chart_generator.js +896 -0
  110. package/dist/analysis/derivative_chart_generator.js.map +1 -0
  111. package/dist/analysis/math_utils.d.ts +35 -0
  112. package/dist/analysis/math_utils.d.ts.map +1 -0
  113. package/dist/analysis/math_utils.js +121 -0
  114. package/dist/analysis/math_utils.js.map +1 -0
  115. package/dist/analysis/price_sources.d.ts +34 -0
  116. package/dist/analysis/price_sources.d.ts.map +1 -0
  117. package/dist/analysis/price_sources.js +103 -0
  118. package/dist/analysis/price_sources.js.map +1 -0
  119. package/dist/analysis/trade_profitability.d.ts +115 -0
  120. package/dist/analysis/trade_profitability.d.ts.map +1 -0
  121. package/dist/analysis/trade_profitability.js +1247 -0
  122. package/dist/analysis/trade_profitability.js.map +1 -0
  123. package/dist/analysis/tradingview/analyze_tradingview.d.ts +38 -0
  124. package/dist/analysis/tradingview/analyze_tradingview.d.ts.map +1 -0
  125. package/dist/analysis/tradingview/analyze_tradingview.js +212 -0
  126. package/dist/analysis/tradingview/analyze_tradingview.js.map +1 -0
  127. package/dist/analysis/tradingview/tradingview_uplot_chart_generator.d.ts +9 -0
  128. package/dist/analysis/tradingview/tradingview_uplot_chart_generator.d.ts.map +1 -0
  129. package/dist/analysis/tradingview/tradingview_uplot_chart_generator.js +1717 -0
  130. package/dist/analysis/tradingview/tradingview_uplot_chart_generator.js.map +1 -0
  131. package/dist/analysis/trend_detection/derivative_analyzer.d.ts +250 -0
  132. package/dist/analysis/trend_detection/derivative_analyzer.d.ts.map +1 -0
  133. package/dist/analysis/trend_detection/derivative_analyzer.js +903 -0
  134. package/dist/analysis/trend_detection/derivative_analyzer.js.map +1 -0
  135. package/dist/analysis/trend_detection/dynamic_weight_chart_generator.d.ts +6 -0
  136. package/dist/analysis/trend_detection/dynamic_weight_chart_generator.d.ts.map +1 -0
  137. package/dist/analysis/trend_detection/dynamic_weight_chart_generator.js +1449 -0
  138. package/dist/analysis/trend_detection/dynamic_weight_chart_generator.js.map +1 -0
  139. package/dist/analysis/trend_detection/hurst_analyzer.d.ts +42 -0
  140. package/dist/analysis/trend_detection/hurst_analyzer.d.ts.map +1 -0
  141. package/dist/analysis/trend_detection/hurst_analyzer.js +159 -0
  142. package/dist/analysis/trend_detection/hurst_analyzer.js.map +1 -0
  143. package/dist/analysis/trend_detection/kalman_chart_generator.d.ts +6 -0
  144. package/dist/analysis/trend_detection/kalman_chart_generator.d.ts.map +1 -0
  145. package/dist/analysis/trend_detection/kalman_chart_generator.js +408 -0
  146. package/dist/analysis/trend_detection/kalman_chart_generator.js.map +1 -0
  147. package/dist/analysis/trend_detection/kalman_trend_analyzer.d.ts +103 -0
  148. package/dist/analysis/trend_detection/kalman_trend_analyzer.d.ts.map +1 -0
  149. package/dist/analysis/trend_detection/kalman_trend_analyzer.js +229 -0
  150. package/dist/analysis/trend_detection/kalman_trend_analyzer.js.map +1 -0
  151. package/dist/analysis/trend_detection/kalman_velocity_smoothing.d.ts +34 -0
  152. package/dist/analysis/trend_detection/kalman_velocity_smoothing.d.ts.map +1 -0
  153. package/dist/analysis/trend_detection/kalman_velocity_smoothing.js +89 -0
  154. package/dist/analysis/trend_detection/kalman_velocity_smoothing.js.map +1 -0
  155. package/dist/analysis/trend_detection/permutation_entropy_analyzer.d.ts +39 -0
  156. package/dist/analysis/trend_detection/permutation_entropy_analyzer.d.ts.map +1 -0
  157. package/dist/analysis/trend_detection/permutation_entropy_analyzer.js +132 -0
  158. package/dist/analysis/trend_detection/permutation_entropy_analyzer.js.map +1 -0
  159. package/dist/analysis/trend_detection/regime_chart_generator.d.ts +6 -0
  160. package/dist/analysis/trend_detection/regime_chart_generator.d.ts.map +1 -0
  161. package/dist/analysis/trend_detection/regime_chart_generator.js +345 -0
  162. package/dist/analysis/trend_detection/regime_chart_generator.js.map +1 -0
  163. package/dist/analysis/trend_detection/tests/test_kalman_trend.d.ts +2 -0
  164. package/dist/analysis/trend_detection/tests/test_kalman_trend.d.ts.map +1 -0
  165. package/dist/analysis/trend_detection/tests/test_kalman_trend.js +130 -0
  166. package/dist/analysis/trend_detection/tests/test_kalman_trend.js.map +1 -0
  167. package/dist/analysis/trend_detection/tests/test_kalman_velocity_smoothing.d.ts +2 -0
  168. package/dist/analysis/trend_detection/tests/test_kalman_velocity_smoothing.d.ts.map +1 -0
  169. package/dist/analysis/trend_detection/tests/test_kalman_velocity_smoothing.js +38 -0
  170. package/dist/analysis/trend_detection/tests/test_kalman_velocity_smoothing.js.map +1 -0
  171. package/dist/analysis/trend_detection/volatility_chart_generator.d.ts +6 -0
  172. package/dist/analysis/trend_detection/volatility_chart_generator.d.ts.map +1 -0
  173. package/dist/analysis/trend_detection/volatility_chart_generator.js +732 -0
  174. package/dist/analysis/trend_detection/volatility_chart_generator.js.map +1 -0
  175. package/dist/bot.d.ts +49 -0
  176. package/dist/bot.d.ts.map +1 -0
  177. package/dist/bot.js +221 -0
  178. package/dist/bot.js.map +1 -0
  179. package/dist/credential-daemon.d.ts +64 -0
  180. package/dist/credential-daemon.d.ts.map +1 -0
  181. package/dist/credential-daemon.js +987 -0
  182. package/dist/credential-daemon.js.map +1 -0
  183. package/dist/dexbot.d.ts +87 -0
  184. package/dist/dexbot.d.ts.map +1 -0
  185. package/dist/dexbot.js +1222 -0
  186. package/dist/dexbot.js.map +1 -0
  187. package/dist/market_adapter/ama_signal_runner.d.ts +3 -0
  188. package/dist/market_adapter/ama_signal_runner.d.ts.map +1 -0
  189. package/dist/market_adapter/ama_signal_runner.js +175 -0
  190. package/dist/market_adapter/ama_signal_runner.js.map +1 -0
  191. package/dist/market_adapter/candle_utils.d.ts +57 -0
  192. package/dist/market_adapter/candle_utils.d.ts.map +1 -0
  193. package/dist/market_adapter/candle_utils.js +252 -0
  194. package/dist/market_adapter/candle_utils.js.map +1 -0
  195. package/dist/market_adapter/core/asymmetric_bounds.d.ts +20 -0
  196. package/dist/market_adapter/core/asymmetric_bounds.d.ts.map +1 -0
  197. package/dist/market_adapter/core/asymmetric_bounds.js +88 -0
  198. package/dist/market_adapter/core/asymmetric_bounds.js.map +1 -0
  199. package/dist/market_adapter/core/config_normalizers.d.ts +10 -0
  200. package/dist/market_adapter/core/config_normalizers.d.ts.map +1 -0
  201. package/dist/market_adapter/core/config_normalizers.js +24 -0
  202. package/dist/market_adapter/core/config_normalizers.js.map +1 -0
  203. package/dist/market_adapter/core/kibana_candles.d.ts +74 -0
  204. package/dist/market_adapter/core/kibana_candles.d.ts.map +1 -0
  205. package/dist/market_adapter/core/kibana_candles.js +249 -0
  206. package/dist/market_adapter/core/kibana_candles.js.map +1 -0
  207. package/dist/market_adapter/core/kibana_client.d.ts +27 -0
  208. package/dist/market_adapter/core/kibana_client.d.ts.map +1 -0
  209. package/dist/market_adapter/core/kibana_client.js +120 -0
  210. package/dist/market_adapter/core/kibana_client.js.map +1 -0
  211. package/dist/market_adapter/core/kibana_market_candles.d.ts +143 -0
  212. package/dist/market_adapter/core/kibana_market_candles.d.ts.map +1 -0
  213. package/dist/market_adapter/core/kibana_market_candles.js +170 -0
  214. package/dist/market_adapter/core/kibana_market_candles.js.map +1 -0
  215. package/dist/market_adapter/core/market_adapter_service.d.ts +210 -0
  216. package/dist/market_adapter/core/market_adapter_service.d.ts.map +1 -0
  217. package/dist/market_adapter/core/market_adapter_service.js +2328 -0
  218. package/dist/market_adapter/core/market_adapter_service.js.map +1 -0
  219. package/dist/market_adapter/core/strategies/ama.d.ts +2 -0
  220. package/dist/market_adapter/core/strategies/ama.d.ts.map +1 -0
  221. package/dist/market_adapter/core/strategies/ama.js +138 -0
  222. package/dist/market_adapter/core/strategies/ama.js.map +1 -0
  223. package/dist/market_adapter/core/strategies/ama_slope_model.d.ts +50 -0
  224. package/dist/market_adapter/core/strategies/ama_slope_model.d.ts.map +1 -0
  225. package/dist/market_adapter/core/strategies/ama_slope_model.js +143 -0
  226. package/dist/market_adapter/core/strategies/ama_slope_model.js.map +1 -0
  227. package/dist/market_adapter/core/strategies/atr/calculator.d.ts +12 -0
  228. package/dist/market_adapter/core/strategies/atr/calculator.d.ts.map +1 -0
  229. package/dist/market_adapter/core/strategies/atr/calculator.js +47 -0
  230. package/dist/market_adapter/core/strategies/atr/calculator.js.map +1 -0
  231. package/dist/market_adapter/core/strategies/collateral_manager.d.ts +32 -0
  232. package/dist/market_adapter/core/strategies/collateral_manager.d.ts.map +1 -0
  233. package/dist/market_adapter/core/strategies/collateral_manager.js +68 -0
  234. package/dist/market_adapter/core/strategies/collateral_manager.js.map +1 -0
  235. package/dist/market_adapter/core/strategies/regime_gate.d.ts +66 -0
  236. package/dist/market_adapter/core/strategies/regime_gate.d.ts.map +1 -0
  237. package/dist/market_adapter/core/strategies/regime_gate.js +189 -0
  238. package/dist/market_adapter/core/strategies/regime_gate.js.map +1 -0
  239. package/dist/market_adapter/index.d.ts +10 -0
  240. package/dist/market_adapter/index.d.ts.map +1 -0
  241. package/dist/market_adapter/index.js +71 -0
  242. package/dist/market_adapter/index.js.map +1 -0
  243. package/dist/market_adapter/inputs/fetch_cex_synthetic_data.d.ts +3 -0
  244. package/dist/market_adapter/inputs/fetch_cex_synthetic_data.d.ts.map +1 -0
  245. package/dist/market_adapter/inputs/fetch_cex_synthetic_data.js +1165 -0
  246. package/dist/market_adapter/inputs/fetch_cex_synthetic_data.js.map +1 -0
  247. package/dist/market_adapter/inputs/fetch_lp_data.d.ts +54 -0
  248. package/dist/market_adapter/inputs/fetch_lp_data.d.ts.map +1 -0
  249. package/dist/market_adapter/inputs/fetch_lp_data.js +743 -0
  250. package/dist/market_adapter/inputs/fetch_lp_data.js.map +1 -0
  251. package/dist/market_adapter/inputs/kibana_source.d.ts +68 -0
  252. package/dist/market_adapter/inputs/kibana_source.d.ts.map +1 -0
  253. package/dist/market_adapter/inputs/kibana_source.js +143 -0
  254. package/dist/market_adapter/inputs/kibana_source.js.map +1 -0
  255. package/dist/market_adapter/interval_utils.d.ts +6 -0
  256. package/dist/market_adapter/interval_utils.d.ts.map +1 -0
  257. package/dist/market_adapter/interval_utils.js +14 -0
  258. package/dist/market_adapter/interval_utils.js.map +1 -0
  259. package/dist/market_adapter/log_format.d.ts +16 -0
  260. package/dist/market_adapter/log_format.d.ts.map +1 -0
  261. package/dist/market_adapter/log_format.js +72 -0
  262. package/dist/market_adapter/log_format.js.map +1 -0
  263. package/dist/market_adapter/lp_chart_core.d.ts +6 -0
  264. package/dist/market_adapter/lp_chart_core.d.ts.map +1 -0
  265. package/dist/market_adapter/lp_chart_core.js +874 -0
  266. package/dist/market_adapter/lp_chart_core.js.map +1 -0
  267. package/dist/market_adapter/lp_chart_runner.d.ts +135 -0
  268. package/dist/market_adapter/lp_chart_runner.d.ts.map +1 -0
  269. package/dist/market_adapter/lp_chart_runner.js +337 -0
  270. package/dist/market_adapter/lp_chart_runner.js.map +1 -0
  271. package/dist/market_adapter/lp_chart_strategy_loader.d.ts +23 -0
  272. package/dist/market_adapter/lp_chart_strategy_loader.d.ts.map +1 -0
  273. package/dist/market_adapter/lp_chart_strategy_loader.js +169 -0
  274. package/dist/market_adapter/lp_chart_strategy_loader.js.map +1 -0
  275. package/dist/market_adapter/market_adapter.d.ts +133 -0
  276. package/dist/market_adapter/market_adapter.d.ts.map +1 -0
  277. package/dist/market_adapter/market_adapter.js +1331 -0
  278. package/dist/market_adapter/market_adapter.js.map +1 -0
  279. package/dist/market_adapter/merge_lp_data.d.ts +3 -0
  280. package/dist/market_adapter/merge_lp_data.d.ts.map +1 -0
  281. package/dist/market_adapter/merge_lp_data.js +125 -0
  282. package/dist/market_adapter/merge_lp_data.js.map +1 -0
  283. package/dist/market_adapter/test_helpers.d.ts +14 -0
  284. package/dist/market_adapter/test_helpers.d.ts.map +1 -0
  285. package/dist/market_adapter/test_helpers.js +22 -0
  286. package/dist/market_adapter/test_helpers.js.map +1 -0
  287. package/dist/market_adapter/utils/adapter_client.d.ts +20 -0
  288. package/dist/market_adapter/utils/adapter_client.d.ts.map +1 -0
  289. package/dist/market_adapter/utils/adapter_client.js +88 -0
  290. package/dist/market_adapter/utils/adapter_client.js.map +1 -0
  291. package/dist/market_adapter/utils/atomic_write.d.ts +9 -0
  292. package/dist/market_adapter/utils/atomic_write.d.ts.map +1 -0
  293. package/dist/market_adapter/utils/atomic_write.js +13 -0
  294. package/dist/market_adapter/utils/atomic_write.js.map +1 -0
  295. package/dist/market_adapter/utils/chain.d.ts +50 -0
  296. package/dist/market_adapter/utils/chain.d.ts.map +1 -0
  297. package/dist/market_adapter/utils/chain.js +196 -0
  298. package/dist/market_adapter/utils/chain.js.map +1 -0
  299. package/dist/market_adapter/utils/data_discovery.d.ts +6 -0
  300. package/dist/market_adapter/utils/data_discovery.d.ts.map +1 -0
  301. package/dist/market_adapter/utils/data_discovery.js +35 -0
  302. package/dist/market_adapter/utils/data_discovery.js.map +1 -0
  303. package/dist/market_adapter/utils/dynamic_grid_snapshot.d.ts +15 -0
  304. package/dist/market_adapter/utils/dynamic_grid_snapshot.d.ts.map +1 -0
  305. package/dist/market_adapter/utils/dynamic_grid_snapshot.js +60 -0
  306. package/dist/market_adapter/utils/dynamic_grid_snapshot.js.map +1 -0
  307. package/dist/market_adapter/utils/file_lock.d.ts +19 -0
  308. package/dist/market_adapter/utils/file_lock.d.ts.map +1 -0
  309. package/dist/market_adapter/utils/file_lock.js +191 -0
  310. package/dist/market_adapter/utils/file_lock.js.map +1 -0
  311. package/dist/market_adapter/utils/native_history.d.ts +19 -0
  312. package/dist/market_adapter/utils/native_history.d.ts.map +1 -0
  313. package/dist/market_adapter/utils/native_history.js +172 -0
  314. package/dist/market_adapter/utils/native_history.js.map +1 -0
  315. package/dist/market_adapter/utils/paths.d.ts +5 -0
  316. package/dist/market_adapter/utils/paths.d.ts.map +1 -0
  317. package/dist/market_adapter/utils/paths.js +7 -0
  318. package/dist/market_adapter/utils/paths.js.map +1 -0
  319. package/dist/modules/account_bots.d.ts +112 -0
  320. package/dist/modules/account_bots.d.ts.map +1 -0
  321. package/dist/modules/account_bots.js +1259 -0
  322. package/dist/modules/account_bots.js.map +1 -0
  323. package/dist/modules/account_orders.d.ts +273 -0
  324. package/dist/modules/account_orders.d.ts.map +1 -0
  325. package/dist/modules/account_orders.js +662 -0
  326. package/dist/modules/account_orders.js.map +1 -0
  327. package/dist/modules/authority_resolver.d.ts +2 -0
  328. package/dist/modules/authority_resolver.d.ts.map +1 -0
  329. package/dist/modules/authority_resolver.js +231 -0
  330. package/dist/modules/authority_resolver.js.map +1 -0
  331. package/dist/modules/bitshares-native/chain_client.d.ts +38 -0
  332. package/dist/modules/bitshares-native/chain_client.d.ts.map +1 -0
  333. package/dist/modules/bitshares-native/chain_client.js +322 -0
  334. package/dist/modules/bitshares-native/chain_client.js.map +1 -0
  335. package/dist/modules/bitshares-native/crypto/ecc.browser.d.ts +59 -0
  336. package/dist/modules/bitshares-native/crypto/ecc.browser.d.ts.map +1 -0
  337. package/dist/modules/bitshares-native/crypto/ecc.browser.js +456 -0
  338. package/dist/modules/bitshares-native/crypto/ecc.browser.js.map +1 -0
  339. package/dist/modules/bitshares-native/crypto/ecc.d.ts +66 -0
  340. package/dist/modules/bitshares-native/crypto/ecc.d.ts.map +1 -0
  341. package/dist/modules/bitshares-native/crypto/ecc.js +557 -0
  342. package/dist/modules/bitshares-native/crypto/ecc.js.map +1 -0
  343. package/dist/modules/bitshares-native/crypto/ecc_selector.d.ts +2 -0
  344. package/dist/modules/bitshares-native/crypto/ecc_selector.d.ts.map +1 -0
  345. package/dist/modules/bitshares-native/crypto/ecc_selector.js +20 -0
  346. package/dist/modules/bitshares-native/crypto/ecc_selector.js.map +1 -0
  347. package/dist/modules/bitshares-native/index.d.ts +3 -0
  348. package/dist/modules/bitshares-native/index.d.ts.map +1 -0
  349. package/dist/modules/bitshares-native/index.js +32 -0
  350. package/dist/modules/bitshares-native/index.js.map +1 -0
  351. package/dist/modules/bitshares-native/resolvers.d.ts +40 -0
  352. package/dist/modules/bitshares-native/resolvers.d.ts.map +1 -0
  353. package/dist/modules/bitshares-native/resolvers.js +161 -0
  354. package/dist/modules/bitshares-native/resolvers.js.map +1 -0
  355. package/dist/modules/bitshares-native/serial/chain_constants.d.ts +56 -0
  356. package/dist/modules/bitshares-native/serial/chain_constants.d.ts.map +1 -0
  357. package/dist/modules/bitshares-native/serial/chain_constants.js +92 -0
  358. package/dist/modules/bitshares-native/serial/chain_constants.js.map +1 -0
  359. package/dist/modules/bitshares-native/serial/index.d.ts +10 -0
  360. package/dist/modules/bitshares-native/serial/index.d.ts.map +1 -0
  361. package/dist/modules/bitshares-native/serial/index.js +14 -0
  362. package/dist/modules/bitshares-native/serial/index.js.map +1 -0
  363. package/dist/modules/bitshares-native/serial/operations.d.ts +102 -0
  364. package/dist/modules/bitshares-native/serial/operations.d.ts.map +1 -0
  365. package/dist/modules/bitshares-native/serial/operations.js +615 -0
  366. package/dist/modules/bitshares-native/serial/operations.js.map +1 -0
  367. package/dist/modules/bitshares-native/serial/serializer.d.ts +64 -0
  368. package/dist/modules/bitshares-native/serial/serializer.d.ts.map +1 -0
  369. package/dist/modules/bitshares-native/serial/serializer.js +252 -0
  370. package/dist/modules/bitshares-native/serial/serializer.js.map +1 -0
  371. package/dist/modules/bitshares-native/serial/types.d.ts +120 -0
  372. package/dist/modules/bitshares-native/serial/types.d.ts.map +1 -0
  373. package/dist/modules/bitshares-native/serial/types.js +837 -0
  374. package/dist/modules/bitshares-native/serial/types.js.map +1 -0
  375. package/dist/modules/bitshares-native/signing_client.d.ts +6 -0
  376. package/dist/modules/bitshares-native/signing_client.d.ts.map +1 -0
  377. package/dist/modules/bitshares-native/signing_client.js +141 -0
  378. package/dist/modules/bitshares-native/signing_client.js.map +1 -0
  379. package/dist/modules/bitshares-native/subscriptions.d.ts +6 -0
  380. package/dist/modules/bitshares-native/subscriptions.d.ts.map +1 -0
  381. package/dist/modules/bitshares-native/subscriptions.js +865 -0
  382. package/dist/modules/bitshares-native/subscriptions.js.map +1 -0
  383. package/dist/modules/bitshares-native/transport.d.ts +51 -0
  384. package/dist/modules/bitshares-native/transport.d.ts.map +1 -0
  385. package/dist/modules/bitshares-native/transport.js +447 -0
  386. package/dist/modules/bitshares-native/transport.js.map +1 -0
  387. package/dist/modules/bitshares-native/tx/builder.d.ts +30 -0
  388. package/dist/modules/bitshares-native/tx/builder.d.ts.map +1 -0
  389. package/dist/modules/bitshares-native/tx/builder.js +262 -0
  390. package/dist/modules/bitshares-native/tx/builder.js.map +1 -0
  391. package/dist/modules/bitshares_client.d.ts +129 -0
  392. package/dist/modules/bitshares_client.d.ts.map +1 -0
  393. package/dist/modules/bitshares_client.js +627 -0
  394. package/dist/modules/bitshares_client.js.map +1 -0
  395. package/dist/modules/bot_settings.d.ts +33 -0
  396. package/dist/modules/bot_settings.d.ts.map +1 -0
  397. package/dist/modules/bot_settings.js +328 -0
  398. package/dist/modules/bot_settings.js.map +1 -0
  399. package/dist/modules/bots_file_lock.d.ts +88 -0
  400. package/dist/modules/bots_file_lock.d.ts.map +1 -0
  401. package/dist/modules/bots_file_lock.js +161 -0
  402. package/dist/modules/bots_file_lock.js.map +1 -0
  403. package/dist/modules/chain_keys.d.ts +302 -0
  404. package/dist/modules/chain_keys.d.ts.map +1 -0
  405. package/dist/modules/chain_keys.js +1095 -0
  406. package/dist/modules/chain_keys.js.map +1 -0
  407. package/dist/modules/chain_orders.d.ts +423 -0
  408. package/dist/modules/chain_orders.d.ts.map +1 -0
  409. package/dist/modules/chain_orders.js +1201 -0
  410. package/dist/modules/chain_orders.js.map +1 -0
  411. package/dist/modules/cli_whitelist_args.d.ts +6 -0
  412. package/dist/modules/cli_whitelist_args.d.ts.map +1 -0
  413. package/dist/modules/cli_whitelist_args.js +13 -0
  414. package/dist/modules/cli_whitelist_args.js.map +1 -0
  415. package/dist/modules/config.d.ts +57 -0
  416. package/dist/modules/config.d.ts.map +1 -0
  417. package/dist/modules/config.js +107 -0
  418. package/dist/modules/config.js.map +1 -0
  419. package/dist/modules/constants.d.ts +635 -0
  420. package/dist/modules/constants.d.ts.map +1 -0
  421. package/dist/modules/constants.js +1464 -0
  422. package/dist/modules/constants.js.map +1 -0
  423. package/dist/modules/cr_planner.d.ts +51 -0
  424. package/dist/modules/cr_planner.d.ts.map +1 -0
  425. package/dist/modules/cr_planner.js +299 -0
  426. package/dist/modules/cr_planner.js.map +1 -0
  427. package/dist/modules/credential_policy.d.ts +188 -0
  428. package/dist/modules/credential_policy.d.ts.map +1 -0
  429. package/dist/modules/credential_policy.js +1452 -0
  430. package/dist/modules/credential_policy.js.map +1 -0
  431. package/dist/modules/credential_runtime.d.ts +42 -0
  432. package/dist/modules/credential_runtime.d.ts.map +1 -0
  433. package/dist/modules/credential_runtime.js +148 -0
  434. package/dist/modules/credential_runtime.js.map +1 -0
  435. package/dist/modules/credential_session_cache.d.ts +36 -0
  436. package/dist/modules/credential_session_cache.d.ts.map +1 -0
  437. package/dist/modules/credential_session_cache.js +106 -0
  438. package/dist/modules/credential_session_cache.js.map +1 -0
  439. package/dist/modules/credit_runtime.d.ts +412 -0
  440. package/dist/modules/credit_runtime.d.ts.map +1 -0
  441. package/dist/modules/credit_runtime.js +2866 -0
  442. package/dist/modules/credit_runtime.js.map +1 -0
  443. package/dist/modules/crypto/browser_provider.d.ts +15 -0
  444. package/dist/modules/crypto/browser_provider.d.ts.map +1 -0
  445. package/dist/modules/crypto/browser_provider.js +113 -0
  446. package/dist/modules/crypto/browser_provider.js.map +1 -0
  447. package/dist/modules/crypto/index.d.ts +9 -0
  448. package/dist/modules/crypto/index.d.ts.map +1 -0
  449. package/dist/modules/crypto/index.js +44 -0
  450. package/dist/modules/crypto/index.js.map +1 -0
  451. package/dist/modules/crypto/node_provider.d.ts +15 -0
  452. package/dist/modules/crypto/node_provider.d.ts.map +1 -0
  453. package/dist/modules/crypto/node_provider.js +74 -0
  454. package/dist/modules/crypto/node_provider.js.map +1 -0
  455. package/dist/modules/crypto/provider.d.ts +34 -0
  456. package/dist/modules/crypto/provider.d.ts.map +1 -0
  457. package/dist/modules/crypto/provider.js +3 -0
  458. package/dist/modules/crypto/provider.js.map +1 -0
  459. package/dist/modules/crypto/pure_ripemd160.d.ts +8 -0
  460. package/dist/modules/crypto/pure_ripemd160.d.ts.map +1 -0
  461. package/dist/modules/crypto/pure_ripemd160.js +142 -0
  462. package/dist/modules/crypto/pure_ripemd160.js.map +1 -0
  463. package/dist/modules/crypto/pure_scrypt.d.ts +23 -0
  464. package/dist/modules/crypto/pure_scrypt.d.ts.map +1 -0
  465. package/dist/modules/crypto/pure_scrypt.js +161 -0
  466. package/dist/modules/crypto/pure_scrypt.js.map +1 -0
  467. package/dist/modules/crypto/pure_secp256k1.d.ts +29 -0
  468. package/dist/modules/crypto/pure_secp256k1.d.ts.map +1 -0
  469. package/dist/modules/crypto/pure_secp256k1.js +195 -0
  470. package/dist/modules/crypto/pure_secp256k1.js.map +1 -0
  471. package/dist/modules/crypto/sync.d.ts +13 -0
  472. package/dist/modules/crypto/sync.d.ts.map +1 -0
  473. package/dist/modules/crypto/sync.js +37 -0
  474. package/dist/modules/crypto/sync.js.map +1 -0
  475. package/dist/modules/dexbot_class.d.ts +1074 -0
  476. package/dist/modules/dexbot_class.d.ts.map +1 -0
  477. package/dist/modules/dexbot_class.js +4613 -0
  478. package/dist/modules/dexbot_class.js.map +1 -0
  479. package/dist/modules/dexbot_credential_client.d.ts +71 -0
  480. package/dist/modules/dexbot_credential_client.d.ts.map +1 -0
  481. package/dist/modules/dexbot_credential_client.js +224 -0
  482. package/dist/modules/dexbot_credential_client.js.map +1 -0
  483. package/dist/modules/dexbot_fill_runtime.d.ts +173 -0
  484. package/dist/modules/dexbot_fill_runtime.d.ts.map +1 -0
  485. package/dist/modules/dexbot_fill_runtime.js +217 -0
  486. package/dist/modules/dexbot_fill_runtime.js.map +1 -0
  487. package/dist/modules/dexbot_maintenance_runtime.d.ts +279 -0
  488. package/dist/modules/dexbot_maintenance_runtime.d.ts.map +1 -0
  489. package/dist/modules/dexbot_maintenance_runtime.js +1613 -0
  490. package/dist/modules/dexbot_maintenance_runtime.js.map +1 -0
  491. package/dist/modules/env.d.ts +12 -0
  492. package/dist/modules/env.d.ts.map +1 -0
  493. package/dist/modules/env.js +57 -0
  494. package/dist/modules/env.js.map +1 -0
  495. package/dist/modules/fund_registry.d.ts +96 -0
  496. package/dist/modules/fund_registry.d.ts.map +1 -0
  497. package/dist/modules/fund_registry.js +261 -0
  498. package/dist/modules/fund_registry.js.map +1 -0
  499. package/dist/modules/general_settings.d.ts +36 -0
  500. package/dist/modules/general_settings.d.ts.map +1 -0
  501. package/dist/modules/general_settings.js +63 -0
  502. package/dist/modules/general_settings.js.map +1 -0
  503. package/dist/modules/graceful_shutdown.d.ts +86 -0
  504. package/dist/modules/graceful_shutdown.d.ts.map +1 -0
  505. package/dist/modules/graceful_shutdown.js +164 -0
  506. package/dist/modules/graceful_shutdown.js.map +1 -0
  507. package/dist/modules/key_store.d.ts +60 -0
  508. package/dist/modules/key_store.d.ts.map +1 -0
  509. package/dist/modules/key_store.js +215 -0
  510. package/dist/modules/key_store.js.map +1 -0
  511. package/dist/modules/launcher/bot_supervisor.d.ts +84 -0
  512. package/dist/modules/launcher/bot_supervisor.d.ts.map +1 -0
  513. package/dist/modules/launcher/bot_supervisor.js +1067 -0
  514. package/dist/modules/launcher/bot_supervisor.js.map +1 -0
  515. package/dist/modules/launcher/child_env.d.ts +9 -0
  516. package/dist/modules/launcher/child_env.d.ts.map +1 -0
  517. package/dist/modules/launcher/child_env.js +78 -0
  518. package/dist/modules/launcher/child_env.js.map +1 -0
  519. package/dist/modules/launcher/credential_bootstrap.d.ts +22 -0
  520. package/dist/modules/launcher/credential_bootstrap.d.ts.map +1 -0
  521. package/dist/modules/launcher/credential_bootstrap.js +303 -0
  522. package/dist/modules/launcher/credential_bootstrap.js.map +1 -0
  523. package/dist/modules/launcher/credential_daemon.d.ts +32 -0
  524. package/dist/modules/launcher/credential_daemon.d.ts.map +1 -0
  525. package/dist/modules/launcher/credential_daemon.js +173 -0
  526. package/dist/modules/launcher/credential_daemon.js.map +1 -0
  527. package/dist/modules/launcher/credential_secret.d.ts +6 -0
  528. package/dist/modules/launcher/credential_secret.d.ts.map +1 -0
  529. package/dist/modules/launcher/credential_secret.js +15 -0
  530. package/dist/modules/launcher/credential_secret.js.map +1 -0
  531. package/dist/modules/launcher/foreign_cred_daemon.d.ts +2 -0
  532. package/dist/modules/launcher/foreign_cred_daemon.d.ts.map +1 -0
  533. package/dist/modules/launcher/foreign_cred_daemon.js +166 -0
  534. package/dist/modules/launcher/foreign_cred_daemon.js.map +1 -0
  535. package/dist/modules/launcher/headless_password.d.ts +8 -0
  536. package/dist/modules/launcher/headless_password.d.ts.map +1 -0
  537. package/dist/modules/launcher/headless_password.js +33 -0
  538. package/dist/modules/launcher/headless_password.js.map +1 -0
  539. package/dist/modules/launcher/launch_modes.d.ts +36 -0
  540. package/dist/modules/launcher/launch_modes.d.ts.map +1 -0
  541. package/dist/modules/launcher/launch_modes.js +129 -0
  542. package/dist/modules/launcher/launch_modes.js.map +1 -0
  543. package/dist/modules/launcher/market_adapter_runtime.d.ts +43 -0
  544. package/dist/modules/launcher/market_adapter_runtime.d.ts.map +1 -0
  545. package/dist/modules/launcher/market_adapter_runtime.js +217 -0
  546. package/dist/modules/launcher/market_adapter_runtime.js.map +1 -0
  547. package/dist/modules/launcher/market_adapter_watchdog.d.ts +26 -0
  548. package/dist/modules/launcher/market_adapter_watchdog.d.ts.map +1 -0
  549. package/dist/modules/launcher/market_adapter_watchdog.js +214 -0
  550. package/dist/modules/launcher/market_adapter_watchdog.js.map +1 -0
  551. package/dist/modules/launcher/monolithic_runtime.d.ts +89 -0
  552. package/dist/modules/launcher/monolithic_runtime.d.ts.map +1 -0
  553. package/dist/modules/launcher/monolithic_runtime.js +425 -0
  554. package/dist/modules/launcher/monolithic_runtime.js.map +1 -0
  555. package/dist/modules/launcher/runtime_entry.d.ts +26 -0
  556. package/dist/modules/launcher/runtime_entry.d.ts.map +1 -0
  557. package/dist/modules/launcher/runtime_entry.js +49 -0
  558. package/dist/modules/launcher/runtime_entry.js.map +1 -0
  559. package/dist/modules/launcher/status_reporting.d.ts +48 -0
  560. package/dist/modules/launcher/status_reporting.d.ts.map +1 -0
  561. package/dist/modules/launcher/status_reporting.js +113 -0
  562. package/dist/modules/launcher/status_reporting.js.map +1 -0
  563. package/dist/modules/launcher/supervisor_control.d.ts +6 -0
  564. package/dist/modules/launcher/supervisor_control.d.ts.map +1 -0
  565. package/dist/modules/launcher/supervisor_control.js +59 -0
  566. package/dist/modules/launcher/supervisor_control.js.map +1 -0
  567. package/dist/modules/logger.d.ts +2 -0
  568. package/dist/modules/logger.d.ts.map +1 -0
  569. package/dist/modules/logger.js +71 -0
  570. package/dist/modules/logger.js.map +1 -0
  571. package/dist/modules/market_adapter_whitelist.d.ts +22 -0
  572. package/dist/modules/market_adapter_whitelist.d.ts.map +1 -0
  573. package/dist/modules/market_adapter_whitelist.js +82 -0
  574. package/dist/modules/market_adapter_whitelist.js.map +1 -0
  575. package/dist/modules/node_health_cache.d.ts +55 -0
  576. package/dist/modules/node_health_cache.d.ts.map +1 -0
  577. package/dist/modules/node_health_cache.js +134 -0
  578. package/dist/modules/node_health_cache.js.map +1 -0
  579. package/dist/modules/node_manager.d.ts +215 -0
  580. package/dist/modules/node_manager.d.ts.map +1 -0
  581. package/dist/modules/node_manager.js +628 -0
  582. package/dist/modules/node_manager.js.map +1 -0
  583. package/dist/modules/order/accounting.d.ts +349 -0
  584. package/dist/modules/order/accounting.d.ts.map +1 -0
  585. package/dist/modules/order/accounting.js +1191 -0
  586. package/dist/modules/order/accounting.js.map +1 -0
  587. package/dist/modules/order/async_lock.d.ts +126 -0
  588. package/dist/modules/order/async_lock.d.ts.map +1 -0
  589. package/dist/modules/order/async_lock.js +195 -0
  590. package/dist/modules/order/async_lock.js.map +1 -0
  591. package/dist/modules/order/export.d.ts +129 -0
  592. package/dist/modules/order/export.d.ts.map +1 -0
  593. package/dist/modules/order/export.js +316 -0
  594. package/dist/modules/order/export.js.map +1 -0
  595. package/dist/modules/order/format.d.ts +158 -0
  596. package/dist/modules/order/format.d.ts.map +1 -0
  597. package/dist/modules/order/format.js +232 -0
  598. package/dist/modules/order/format.js.map +1 -0
  599. package/dist/modules/order/grid.d.ts +549 -0
  600. package/dist/modules/order/grid.d.ts.map +1 -0
  601. package/dist/modules/order/grid.js +1746 -0
  602. package/dist/modules/order/grid.js.map +1 -0
  603. package/dist/modules/order/grid_reconcile.d.ts +154 -0
  604. package/dist/modules/order/grid_reconcile.d.ts.map +1 -0
  605. package/dist/modules/order/grid_reconcile.js +1192 -0
  606. package/dist/modules/order/grid_reconcile.js.map +1 -0
  607. package/dist/modules/order/index.d.ts +55 -0
  608. package/dist/modules/order/index.d.ts.map +1 -0
  609. package/dist/modules/order/index.js +79 -0
  610. package/dist/modules/order/index.js.map +1 -0
  611. package/dist/modules/order/logger.d.ts +136 -0
  612. package/dist/modules/order/logger.d.ts.map +1 -0
  613. package/dist/modules/order/logger.js +614 -0
  614. package/dist/modules/order/logger.js.map +1 -0
  615. package/dist/modules/order/logger_state.d.ts +133 -0
  616. package/dist/modules/order/logger_state.d.ts.map +1 -0
  617. package/dist/modules/order/logger_state.js +170 -0
  618. package/dist/modules/order/logger_state.js.map +1 -0
  619. package/dist/modules/order/manager.d.ts +413 -0
  620. package/dist/modules/order/manager.d.ts.map +1 -0
  621. package/dist/modules/order/manager.js +1605 -0
  622. package/dist/modules/order/manager.js.map +1 -0
  623. package/dist/modules/order/processed_fill_store.d.ts +135 -0
  624. package/dist/modules/order/processed_fill_store.d.ts.map +1 -0
  625. package/dist/modules/order/processed_fill_store.js +288 -0
  626. package/dist/modules/order/processed_fill_store.js.map +1 -0
  627. package/dist/modules/order/runner.d.ts +70 -0
  628. package/dist/modules/order/runner.d.ts.map +1 -0
  629. package/dist/modules/order/runner.js +140 -0
  630. package/dist/modules/order/runner.js.map +1 -0
  631. package/dist/modules/order/strategy.d.ts +196 -0
  632. package/dist/modules/order/strategy.d.ts.map +1 -0
  633. package/dist/modules/order/strategy.js +398 -0
  634. package/dist/modules/order/strategy.js.map +1 -0
  635. package/dist/modules/order/sync_engine.d.ts +386 -0
  636. package/dist/modules/order/sync_engine.d.ts.map +1 -0
  637. package/dist/modules/order/sync_engine.js +1459 -0
  638. package/dist/modules/order/sync_engine.js.map +1 -0
  639. package/dist/modules/order/utils/math.d.ts +677 -0
  640. package/dist/modules/order/utils/math.d.ts.map +1 -0
  641. package/dist/modules/order/utils/math.js +1172 -0
  642. package/dist/modules/order/utils/math.js.map +1 -0
  643. package/dist/modules/order/utils/order.d.ts +572 -0
  644. package/dist/modules/order/utils/order.d.ts.map +1 -0
  645. package/dist/modules/order/utils/order.js +1145 -0
  646. package/dist/modules/order/utils/order.js.map +1 -0
  647. package/dist/modules/order/utils/system.d.ts +268 -0
  648. package/dist/modules/order/utils/system.d.ts.map +1 -0
  649. package/dist/modules/order/utils/system.js +1261 -0
  650. package/dist/modules/order/utils/system.js.map +1 -0
  651. package/dist/modules/order/utils/validate.d.ts +280 -0
  652. package/dist/modules/order/utils/validate.d.ts.map +1 -0
  653. package/dist/modules/order/utils/validate.js +918 -0
  654. package/dist/modules/order/utils/validate.js.map +1 -0
  655. package/dist/modules/order/working_grid.d.ts +212 -0
  656. package/dist/modules/order/working_grid.d.ts.map +1 -0
  657. package/dist/modules/order/working_grid.js +279 -0
  658. package/dist/modules/order/working_grid.js.map +1 -0
  659. package/dist/modules/path_api.d.ts +32 -0
  660. package/dist/modules/path_api.d.ts.map +1 -0
  661. package/dist/modules/path_api.js +148 -0
  662. package/dist/modules/path_api.js.map +1 -0
  663. package/dist/modules/paths.d.ts +58 -0
  664. package/dist/modules/paths.d.ts.map +1 -0
  665. package/dist/modules/paths.js +82 -0
  666. package/dist/modules/paths.js.map +1 -0
  667. package/dist/modules/process_discovery.d.ts +58 -0
  668. package/dist/modules/process_discovery.d.ts.map +1 -0
  669. package/dist/modules/process_discovery.js +265 -0
  670. package/dist/modules/process_discovery.js.map +1 -0
  671. package/dist/modules/runtime.d.ts +34 -0
  672. package/dist/modules/runtime.d.ts.map +1 -0
  673. package/dist/modules/runtime.js +98 -0
  674. package/dist/modules/runtime.js.map +1 -0
  675. package/dist/modules/runtime_settings.d.ts +12 -0
  676. package/dist/modules/runtime_settings.d.ts.map +1 -0
  677. package/dist/modules/runtime_settings.js +122 -0
  678. package/dist/modules/runtime_settings.js.map +1 -0
  679. package/dist/modules/settings_merge.d.ts +38 -0
  680. package/dist/modules/settings_merge.d.ts.map +1 -0
  681. package/dist/modules/settings_merge.js +246 -0
  682. package/dist/modules/settings_merge.js.map +1 -0
  683. package/dist/modules/storage/browser_adapter.d.ts +56 -0
  684. package/dist/modules/storage/browser_adapter.d.ts.map +1 -0
  685. package/dist/modules/storage/browser_adapter.js +231 -0
  686. package/dist/modules/storage/browser_adapter.js.map +1 -0
  687. package/dist/modules/storage/index.d.ts +28 -0
  688. package/dist/modules/storage/index.d.ts.map +1 -0
  689. package/dist/modules/storage/index.js +52 -0
  690. package/dist/modules/storage/index.js.map +1 -0
  691. package/dist/modules/storage/node_adapter.d.ts +49 -0
  692. package/dist/modules/storage/node_adapter.d.ts.map +1 -0
  693. package/dist/modules/storage/node_adapter.js +167 -0
  694. package/dist/modules/storage/node_adapter.js.map +1 -0
  695. package/dist/modules/storage/types.d.ts +92 -0
  696. package/dist/modules/storage/types.d.ts.map +1 -0
  697. package/dist/modules/storage/types.js +3 -0
  698. package/dist/modules/storage/types.js.map +1 -0
  699. package/dist/modules/types.d.ts +1382 -0
  700. package/dist/modules/types.d.ts.map +1 -0
  701. package/dist/modules/types.js +11 -0
  702. package/dist/modules/types.js.map +1 -0
  703. package/dist/modules/utils/base58check.d.ts +12 -0
  704. package/dist/modules/utils/base58check.d.ts.map +1 -0
  705. package/dist/modules/utils/base58check.js +112 -0
  706. package/dist/modules/utils/base58check.js.map +1 -0
  707. package/dist/modules/utils/build_dir.d.ts +7 -0
  708. package/dist/modules/utils/build_dir.d.ts.map +1 -0
  709. package/dist/modules/utils/build_dir.js +8 -0
  710. package/dist/modules/utils/build_dir.js.map +1 -0
  711. package/dist/modules/utils/fs_utils.d.ts +25 -0
  712. package/dist/modules/utils/fs_utils.d.ts.map +1 -0
  713. package/dist/modules/utils/fs_utils.js +27 -0
  714. package/dist/modules/utils/fs_utils.js.map +1 -0
  715. package/dist/modules/utils/math_utils.d.ts +10 -0
  716. package/dist/modules/utils/math_utils.d.ts.map +1 -0
  717. package/dist/modules/utils/math_utils.js +17 -0
  718. package/dist/modules/utils/math_utils.js.map +1 -0
  719. package/dist/modules/validate_profiles.d.ts +37 -0
  720. package/dist/modules/validate_profiles.d.ts.map +1 -0
  721. package/dist/modules/validate_profiles.js +369 -0
  722. package/dist/modules/validate_profiles.js.map +1 -0
  723. package/dist/pm2.d.ts +167 -0
  724. package/dist/pm2.d.ts.map +1 -0
  725. package/dist/pm2.js +998 -0
  726. package/dist/pm2.js.map +1 -0
  727. package/dist/scripts/analyze-git.d.ts +11 -0
  728. package/dist/scripts/analyze-git.d.ts.map +1 -0
  729. package/dist/scripts/analyze-git.js +851 -0
  730. package/dist/scripts/analyze-git.js.map +1 -0
  731. package/dist/scripts/analyze-orders.d.ts +17 -0
  732. package/dist/scripts/analyze-orders.d.ts.map +1 -0
  733. package/dist/scripts/analyze-orders.js +1568 -0
  734. package/dist/scripts/analyze-orders.js.map +1 -0
  735. package/dist/scripts/diagnose-kibana-candles.d.ts +3 -0
  736. package/dist/scripts/diagnose-kibana-candles.d.ts.map +1 -0
  737. package/dist/scripts/diagnose-kibana-candles.js +82 -0
  738. package/dist/scripts/diagnose-kibana-candles.js.map +1 -0
  739. package/dist/scripts/diagnose-pool-history.d.ts +3 -0
  740. package/dist/scripts/diagnose-pool-history.d.ts.map +1 -0
  741. package/dist/scripts/diagnose-pool-history.js +296 -0
  742. package/dist/scripts/diagnose-pool-history.js.map +1 -0
  743. package/dist/scripts/divergence-calc.d.ts +26 -0
  744. package/dist/scripts/divergence-calc.d.ts.map +1 -0
  745. package/dist/scripts/divergence-calc.js +119 -0
  746. package/dist/scripts/divergence-calc.js.map +1 -0
  747. package/dist/scripts/generate_lp_chart.d.ts +31 -0
  748. package/dist/scripts/generate_lp_chart.d.ts.map +1 -0
  749. package/dist/scripts/generate_lp_chart.js +92 -0
  750. package/dist/scripts/generate_lp_chart.js.map +1 -0
  751. package/dist/scripts/generate_mainnet_corpus_report.d.ts +24 -0
  752. package/dist/scripts/generate_mainnet_corpus_report.d.ts.map +1 -0
  753. package/dist/scripts/generate_mainnet_corpus_report.js +237 -0
  754. package/dist/scripts/generate_mainnet_corpus_report.js.map +1 -0
  755. package/dist/scripts/generate_market_adapter_whitelist.d.ts +2 -0
  756. package/dist/scripts/generate_market_adapter_whitelist.d.ts.map +1 -0
  757. package/dist/scripts/generate_market_adapter_whitelist.js +111 -0
  758. package/dist/scripts/generate_market_adapter_whitelist.js.map +1 -0
  759. package/dist/scripts/migrate_bot_keys.d.ts +6 -0
  760. package/dist/scripts/migrate_bot_keys.d.ts.map +1 -0
  761. package/dist/scripts/migrate_bot_keys.js +301 -0
  762. package/dist/scripts/migrate_bot_keys.js.map +1 -0
  763. package/dist/scripts/native_release_gates.d.ts +3 -0
  764. package/dist/scripts/native_release_gates.d.ts.map +1 -0
  765. package/dist/scripts/native_release_gates.js +52 -0
  766. package/dist/scripts/native_release_gates.js.map +1 -0
  767. package/dist/scripts/print_grid.d.ts +16 -0
  768. package/dist/scripts/print_grid.d.ts.map +1 -0
  769. package/dist/scripts/print_grid.js +80 -0
  770. package/dist/scripts/print_grid.js.map +1 -0
  771. package/dist/scripts/run-tests.d.ts +2 -0
  772. package/dist/scripts/run-tests.d.ts.map +1 -0
  773. package/dist/scripts/run-tests.js +49 -0
  774. package/dist/scripts/run-tests.js.map +1 -0
  775. package/dist/scripts/sync-version.d.ts +14 -0
  776. package/dist/scripts/sync-version.d.ts.map +1 -0
  777. package/dist/scripts/sync-version.js +158 -0
  778. package/dist/scripts/sync-version.js.map +1 -0
  779. package/dist/scripts/test-credit-renewal.d.ts +2 -0
  780. package/dist/scripts/test-credit-renewal.d.ts.map +1 -0
  781. package/dist/scripts/test-credit-renewal.js +329 -0
  782. package/dist/scripts/test-credit-renewal.js.map +1 -0
  783. package/dist/scripts/update.d.ts +24 -0
  784. package/dist/scripts/update.d.ts.map +1 -0
  785. package/dist/scripts/update.js +650 -0
  786. package/dist/scripts/update.js.map +1 -0
  787. package/dist/scripts/validate_bots.d.ts +16 -0
  788. package/dist/scripts/validate_bots.d.ts.map +1 -0
  789. package/dist/scripts/validate_bots.js +106 -0
  790. package/dist/scripts/validate_bots.js.map +1 -0
  791. package/dist/scripts/verify-browser-bundle.d.ts +22 -0
  792. package/dist/scripts/verify-browser-bundle.d.ts.map +1 -0
  793. package/dist/scripts/verify-browser-bundle.js +339 -0
  794. package/dist/scripts/verify-browser-bundle.js.map +1 -0
  795. package/dist/unlock.d.ts +48 -0
  796. package/dist/unlock.d.ts.map +1 -0
  797. package/dist/unlock.js +925 -0
  798. package/dist/unlock.js.map +1 -0
  799. package/package.json +112 -0
  800. package/scripts/README.md +356 -0
  801. package/scripts/clear-all.sh +195 -0
  802. package/scripts/clear-logs.sh +95 -0
  803. package/scripts/clear-market-adapter.sh +196 -0
  804. package/scripts/clear-orders.sh +113 -0
  805. package/scripts/create-bot-symlinks.sh +51 -0
  806. package/scripts/postinstall.js +9 -0
  807. package/scripts/reset-settings.sh +118 -0
@@ -0,0 +1,1568 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * DEXBot Order Analysis Script
5
+ *
6
+ * Analyzes all order files in profiles/orders/ sorted by modified date.
7
+ * Provides compact terminal output checking:
8
+ * - Real spread vs. target spread (including double-sided status)
9
+ * - Increment value % geometric consistency between grid slots
10
+ * - Total funds of AssetA and AssetB in the grid
11
+ * - Grid slot distribution (% near center) vs grid composition
12
+ *
13
+ * Usage:
14
+ * tsx scripts/analyze-orders.ts # terminal output
15
+ * tsx scripts/analyze-orders.ts --export # standalone HTML report
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ const fs = require('fs');
19
+ const path = require('path');
20
+ const { formatPrice6 } = require('../modules/order/format');
21
+ const { resolveConfiguredPriceBound } = require('../modules/order/utils/order');
22
+ const { ORDER_TYPES, ORDER_STATES, MARKET_ADAPTER } = require('../modules/constants');
23
+ const { PATHS } = require('../modules/paths');
24
+ const { getWhitelistFlags } = require('../modules/market_adapter_whitelist');
25
+ const { readJSON } = require('../modules/utils/fs_utils');
26
+ const ORDERS_DIR = PATHS.ORDERS_DIR;
27
+ const BOTS_CONFIG = PATHS.PROFILES.BOTS_JSON;
28
+ // Color codes for terminal output
29
+ const colors = {
30
+ reset: '\x1b[0m',
31
+ buy: '\x1b[92m', // green
32
+ sell: '\x1b[91m', // light red
33
+ buyDark: '\x1b[38;5;28m', // even darker green
34
+ sellDark: '\x1b[31m', // dark red
35
+ spread: '\x1b[93m', // yellow
36
+ cyan: '\x1b[38;5;87m', // bright cyan
37
+ gray: '\x1b[38;5;246m' // medium grey (lighter than bright black)
38
+ };
39
+ // Partial block characters for weight visualization (0-8 eighths height)
40
+ const partialBlocks = ['', '▁', 'ā–‚', 'ā–ƒ', 'ā–„', 'ā–…', 'ā–†', 'ā–‡', 'ā–ˆ'];
41
+ // Maximum age (ms) for a dynamic grid snapshot to be considered "recently available".
42
+ // The market adapter writes a fresh snapshot on every cycle; a gap larger than this
43
+ // typically means the adapter is stopped or stuck for that bot. We allow up to two
44
+ // full cycles of drift (one missed cycle + slack for slow processing) before falling
45
+ // back to the static-only display, so the live colors track the actual adapter
46
+ // cadence rather than a hand-tuned timeout.
47
+ const DYNAMIC_GRID_SNAPSHOT_MAX_AGE_MS = 2 * MARKET_ADAPTER.RUNTIME_DEFAULTS.pollSeconds * 1000;
48
+ // Tolerance (absolute weight delta) for treating the two live weights as equal
49
+ // when picking a color. Half a percentage point avoids noisy green/red flicker
50
+ // when the dynamic weight sits exactly on the static baseline.
51
+ const DYNAMIC_WEIGHT_EPSILON = 0.005;
52
+ // Bar width configuration (single source of truth)
53
+ const BAR_WIDTH = 51;
54
+ // Header width: prefix width (11 chars for " Slots: ") + bar width
55
+ const HEADER_WIDTH = 11 + BAR_WIDTH;
56
+ /**
57
+ * Utility Functions
58
+ * Helper functions for file I/O, formatting, and data retrieval
59
+ */
60
+ function sanitizeKey(source) {
61
+ if (!source)
62
+ return 'bot';
63
+ return String(source)
64
+ .trim()
65
+ .toLowerCase()
66
+ .replace(/[^a-z0-9]+/g, '-')
67
+ .replace(/^-+|-+$/g, '') || 'bot';
68
+ }
69
+ function createBotKey(bot, index) {
70
+ if (bot && bot.name) {
71
+ return sanitizeKey(bot.name);
72
+ }
73
+ const identifier = bot && bot.assetA && bot.assetB
74
+ ? `${bot.assetA}/${bot.assetB}`
75
+ : bot && bot.assetAId && bot.assetBId
76
+ ? `${bot.assetAId}/${bot.assetBId}`
77
+ : `bot-${index}`;
78
+ return `${sanitizeKey(identifier)}-${index}`;
79
+ }
80
+ function hasOrderGrid(data) {
81
+ return Boolean(data && typeof data === 'object' && !Array.isArray(data) &&
82
+ data.meta && typeof data.meta === 'object' &&
83
+ Array.isArray(data.grid));
84
+ }
85
+ /**
86
+ * isAmaGridPrice: Detect bots whose grid price follows the AMA (Kaufman) stream.
87
+ *
88
+ * Mirrors the predicate used in market_adapter.ts / unlock.ts / pm2.ts so the
89
+ * analyzer only attempts to load a dynamic grid snapshot for AMA bots. Non-AMA
90
+ * bots never have a meaningful dynamic grid file.
91
+ */
92
+ function isAmaGridPrice(config) {
93
+ return resolveAmaKey(config) !== null;
94
+ }
95
+ // Mirrors MARKET_ADAPTER.DEFAULT_AMA_KEY in modules/constants.ts — keep in sync.
96
+ function resolveAmaKey(config) {
97
+ if (!config || typeof config !== 'object')
98
+ return null;
99
+ const gridPrice = typeof config.gridPrice === 'string' ? config.gridPrice.trim().toLowerCase() : '';
100
+ if (!/^ama(?:[1-4])?$/.test(gridPrice))
101
+ return null;
102
+ if (gridPrice === 'ama')
103
+ return MARKET_ADAPTER.DEFAULT_AMA_KEY;
104
+ return gridPrice.toUpperCase();
105
+ }
106
+ function readDynamicGridSnapshot(botKey) {
107
+ if (!botKey)
108
+ return null;
109
+ try {
110
+ const filePath = path.join(ORDERS_DIR, `${botKey}.dynamicgrid.json`);
111
+ if (!fs.existsSync(filePath))
112
+ return null;
113
+ const data = readJSON(filePath);
114
+ return data && typeof data === 'object' ? data : null;
115
+ }
116
+ catch (e) {
117
+ return null;
118
+ }
119
+ }
120
+ /**
121
+ * computeAsymmetricBoundsPrices: Mirror of applyAsymmetricBounds logic.
122
+ * Computes the resolved min/max prices after grid range scaling adjustment.
123
+ */
124
+ function computeAsymmetricBoundsPrices(centerPrice, minPrice, maxPrice, trend, appliedAsymmetryFactor) {
125
+ if (!Number.isFinite(centerPrice) || centerPrice <= 0
126
+ || !Number.isFinite(minPrice) || minPrice <= 0
127
+ || !Number.isFinite(maxPrice) || maxPrice <= 0
128
+ || !Number.isFinite(appliedAsymmetryFactor)
129
+ || (trend !== 'UP' && trend !== 'DOWN')) {
130
+ return null;
131
+ }
132
+ const baseMinDiv = centerPrice / minPrice;
133
+ const baseMaxMult = maxPrice / centerPrice;
134
+ let resolvedMinPrice, resolvedMaxPrice;
135
+ if (trend === 'DOWN') {
136
+ resolvedMinPrice = centerPrice / (baseMinDiv * (1 + appliedAsymmetryFactor));
137
+ resolvedMaxPrice = centerPrice * (baseMaxMult * (1 - appliedAsymmetryFactor));
138
+ }
139
+ else {
140
+ resolvedMinPrice = centerPrice / (baseMinDiv * (1 - appliedAsymmetryFactor));
141
+ resolvedMaxPrice = centerPrice * (baseMaxMult * (1 + appliedAsymmetryFactor));
142
+ }
143
+ return { resolvedMinPrice, resolvedMaxPrice };
144
+ }
145
+ /**
146
+ * buildDynamicWeightInfo: Extract a display-ready market-adapter payload.
147
+ *
148
+ * Reads the latest AMA dynamic-grid snapshot for AMA-whitelisted bots. Dynamic
149
+ * weight values are attached only when the bot is also dynamic-weight
150
+ * whitelisted and the snapshot contains effective weights. AMA center and
151
+ * freshness status remain available for AMA-only bots.
152
+ */
153
+ function buildDynamicWeightInfo(botKey, config) {
154
+ if (!isAmaGridPrice(config))
155
+ return null;
156
+ const whitelistFlags = getWhitelistFlags(botKey);
157
+ if (whitelistFlags.ama !== true)
158
+ return null;
159
+ const snapshot = readDynamicGridSnapshot(botKey);
160
+ if (!snapshot)
161
+ return null;
162
+ const dw = snapshot.dynamicWeights && typeof snapshot.dynamicWeights === 'object'
163
+ ? snapshot.dynamicWeights
164
+ : null;
165
+ const hasDynamicWeightData = whitelistFlags.dynamicWeight === true
166
+ && dw
167
+ && dw.effectiveWeights
168
+ && typeof dw.effectiveWeights === 'object';
169
+ let live = null;
170
+ let base = null;
171
+ if (hasDynamicWeightData) {
172
+ const effBuy = Number(dw.effectiveWeights.buy);
173
+ const effSell = Number(dw.effectiveWeights.sell);
174
+ if (Number.isFinite(effBuy) && Number.isFinite(effSell)) {
175
+ const baseFromSnapshot = dw.baseWeights && typeof dw.baseWeights === 'object' ? dw.baseWeights : null;
176
+ const baseBuy = baseFromSnapshot && Number.isFinite(Number(baseFromSnapshot.buy))
177
+ ? Number(baseFromSnapshot.buy)
178
+ : (config.weightDistribution && Number.isFinite(Number(config.weightDistribution.buy))
179
+ ? Number(config.weightDistribution.buy)
180
+ : null);
181
+ const baseSell = baseFromSnapshot && Number.isFinite(Number(baseFromSnapshot.sell))
182
+ ? Number(baseFromSnapshot.sell)
183
+ : (config.weightDistribution && Number.isFinite(Number(config.weightDistribution.sell))
184
+ ? Number(config.weightDistribution.sell)
185
+ : null);
186
+ if (Number.isFinite(baseBuy) && Number.isFinite(baseSell)) {
187
+ live = { buy: effBuy, sell: effSell };
188
+ base = { buy: baseBuy, sell: baseSell };
189
+ }
190
+ }
191
+ }
192
+ const updatedAtMs = Date.parse(String(snapshot.updatedAt || ''));
193
+ const isRecent = Number.isFinite(updatedAtMs)
194
+ && (Date.now() - updatedAtMs) <= DYNAMIC_GRID_SNAPSHOT_MAX_AGE_MS;
195
+ // Fallback to root-level asymmetricBounds when dynamicWeights is absent.
196
+ // The market adapter writes this when asymmetricBounds: true, regardless of
197
+ // whether dynamicWeight is enabled for this bot.
198
+ const rootBounds = !dw && snapshot?.asymmetricBounds && typeof snapshot.asymmetricBounds === 'object'
199
+ ? snapshot.asymmetricBounds
200
+ : null;
201
+ const amaCenterPrice = Number.isFinite(Number(snapshot.amaCenterPrice))
202
+ ? Number(snapshot.amaCenterPrice)
203
+ : (Number.isFinite(Number(snapshot.gridCenterPrice)) ? Number(snapshot.gridCenterPrice) : null);
204
+ const rawAsymmetryFactor = dw && Number.isFinite(Number(dw.rawAsymmetryFactor))
205
+ ? Number(dw.rawAsymmetryFactor)
206
+ : (rootBounds && Number.isFinite(Number(rootBounds.rawAsymmetryFactor))
207
+ ? Number(rootBounds.rawAsymmetryFactor)
208
+ : null);
209
+ const appliedAsymmetryFactor = dw && Number.isFinite(Number(dw.appliedAsymmetryFactor))
210
+ ? Number(dw.appliedAsymmetryFactor)
211
+ : (rootBounds && Number.isFinite(Number(rootBounds.appliedAsymmetryFactor))
212
+ ? Number(rootBounds.appliedAsymmetryFactor)
213
+ : null);
214
+ const maxAsymmetryFactor = dw && Number.isFinite(Number(dw.maxAsymmetryFactor))
215
+ ? Number(dw.maxAsymmetryFactor)
216
+ : null;
217
+ return {
218
+ live,
219
+ base,
220
+ dynamicWeightEnabled: whitelistFlags.dynamicWeight === true,
221
+ isReady: dw ? dw.isReady === true : false,
222
+ trend: dw && typeof dw.trend === 'string' ? dw.trend
223
+ : (rootBounds && typeof rootBounds.trend === 'string' ? rootBounds.trend : null),
224
+ finalOffset: dw && Number.isFinite(Number(dw.finalOffset)) ? Number(dw.finalOffset) : null,
225
+ amaCenterPrice,
226
+ centerPrice: Number.isFinite(Number(snapshot.centerPrice)) ? Number(snapshot.centerPrice) : null,
227
+ isRecent,
228
+ updatedAt: Number.isFinite(updatedAtMs) ? new Date(updatedAtMs) : null,
229
+ rawAsymmetryFactor,
230
+ appliedAsymmetryFactor,
231
+ maxAsymmetryFactor,
232
+ };
233
+ }
234
+ function isRealGridOrder(order) {
235
+ if (!order || typeof order !== 'object')
236
+ return false;
237
+ const hasRealState = order.state === ORDER_STATES.ACTIVE || order.state === ORDER_STATES.PARTIAL;
238
+ const hasRealType = order.type === ORDER_TYPES.BUY || order.type === ORDER_TYPES.SELL;
239
+ const hasOrderId = typeof order.orderId === 'string' && order.orderId.trim().length > 0;
240
+ return hasRealState
241
+ && hasRealType
242
+ && hasOrderId
243
+ && Number(order.price) > 0
244
+ && Number(order.size) > 0;
245
+ }
246
+ function getRealGridOrders(botData) {
247
+ return Array.isArray(botData?.grid) ? botData.grid.filter(isRealGridOrder) : [];
248
+ }
249
+ /**
250
+ * getModifiedTime: Get file modification timestamp
251
+ * Used to sort order files by most recently updated
252
+ * @param {string} filePath - Path to file
253
+ * @returns {Date} Modification time
254
+ */
255
+ function getModifiedTime(filePath) {
256
+ return fs.statSync(filePath).mtime;
257
+ }
258
+ /**
259
+ * formatPercent: Convert decimal to percentage string
260
+ * Example: 0.05 -> "5.00%"
261
+ * @param {number} value - Decimal value (0-1)
262
+ * @returns {string} Formatted percentage with 2 decimal places
263
+ */
264
+ function formatPercent(value) {
265
+ return (value * 100).toFixed(2) + '%';
266
+ }
267
+ /**
268
+ * formatCurrency: Format a number to 5 significant digits without K/M abbreviation.
269
+ * Very small values (< 0.01) use 6 decimal places via formatPrice6.
270
+ * @param {number} value - Numeric value to format
271
+ * @returns {string} Formatted currency/quantity string
272
+ */
273
+ function formatCurrency(value) {
274
+ if (value === 0)
275
+ return '0';
276
+ const abs = Math.abs(value);
277
+ if (abs < 0.1) {
278
+ if (abs >= 0.001)
279
+ return formatCurrency(value * 1000) + 'm';
280
+ if (abs >= 0.000001)
281
+ return formatCurrency(value * 1000000) + 'μ';
282
+ if (abs >= 1e-9)
283
+ return formatCurrency(value * 1e9) + 'n';
284
+ if (abs >= 1e-12)
285
+ return formatCurrency(value * 1e12) + 'p';
286
+ if (abs >= 1e-15)
287
+ return formatCurrency(value * 1e15) + 'f';
288
+ if (abs >= 1e-18)
289
+ return formatCurrency(value * 1e18) + 'a';
290
+ return formatPrice6(value);
291
+ }
292
+ let intDigits = Math.floor(Math.log10(abs)) + 1;
293
+ if (abs < 1)
294
+ intDigits = 1;
295
+ const formatted = intDigits >= 5
296
+ ? String(Math.round(value))
297
+ : value.toFixed(5 - intDigits);
298
+ return intDigits >= 4
299
+ ? formatted.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
300
+ : formatted;
301
+ }
302
+ /**
303
+ * formatFundsValue: Format a fund amount with compact notation (K/M for ≄1000)
304
+ * and up to 5 significant figures, trimming uninformative trailing zeros.
305
+ * Examples:
306
+ * 194395 -> "194.4K"
307
+ * 10000 -> "10K"
308
+ * 1000 -> "1K"
309
+ * 332.33 -> "332.33"
310
+ * 10.389 -> "10.389"
311
+ * 1500000 -> "1.5M"
312
+ * @param {number} value
313
+ * @returns {string}
314
+ */
315
+ function formatFundsValue(value) {
316
+ if (value === 0)
317
+ return '0';
318
+ const absValue = Math.abs(value);
319
+ let quotient;
320
+ let suffix = '';
321
+ if (absValue >= 1000000) {
322
+ quotient = value / 1000000;
323
+ suffix = 'M';
324
+ }
325
+ else if (absValue >= 1000) {
326
+ quotient = value / 1000;
327
+ suffix = 'K';
328
+ }
329
+ else {
330
+ quotient = value;
331
+ }
332
+ const absQ = Math.abs(quotient);
333
+ const intDigits = Math.floor(Math.log10(Math.max(absQ, 1e-10))) + 1;
334
+ let formatted;
335
+ if (intDigits >= 5) {
336
+ formatted = String(Math.round(quotient));
337
+ }
338
+ else {
339
+ const decimalPlaces = Math.max(0, 5 - intDigits);
340
+ formatted = quotient.toFixed(decimalPlaces);
341
+ formatted = formatted.replace(/(\.[0-9]*?)0+$/, '$1').replace(/\.$/, '');
342
+ }
343
+ return formatted + suffix;
344
+ }
345
+ /**
346
+ * stripColorCodes: Remove ANSI color codes from a string
347
+ * @param {string} str - String that may contain color codes
348
+ * @returns {string} String without color codes
349
+ */
350
+ function stripColorCodes(str) {
351
+ return str.replace(/\x1b\[[0-9;]*m/g, '');
352
+ }
353
+ /**
354
+ * padStringCentered: Pad a string to a target visual width, accounting for color codes
355
+ * Centers the string within the specified width with padding
356
+ * @param {string} str - String that may contain color codes
357
+ * @param {number} width - Target visual width
358
+ * @returns {string} Padded string with original colors preserved
359
+ */
360
+ function padStringCentered(str, width) {
361
+ const visualLen = stripColorCodes(str).length;
362
+ const totalPad = Math.max(0, width - visualLen);
363
+ const padLeft = Math.ceil(totalPad / 2);
364
+ const padRight = Math.floor(totalPad / 2);
365
+ return ' '.repeat(padLeft) + str + ' '.repeat(padRight);
366
+ }
367
+ // Load bot configurations
368
+ const botsConfig = readJSON(BOTS_CONFIG).bots;
369
+ function getConfiguredBotConfig(botKey, botData) {
370
+ const meta = botData?.meta || {};
371
+ return botsConfig.find((bot, index) => {
372
+ if (!bot)
373
+ return false;
374
+ return createBotKey(bot, index) === botKey || (meta.name && bot.name === meta.name);
375
+ }) || null;
376
+ }
377
+ function getOrderFileCandidate(fileName) {
378
+ const filePath = path.join(ORDERS_DIR, fileName);
379
+ if (!fileName.endsWith('.json')) {
380
+ return { include: false, reason: 'not a JSON file', report: false };
381
+ }
382
+ if (fileName.endsWith('.dynamicgrid.json')) {
383
+ return { include: false, reason: 'dynamic grid snapshot', report: false };
384
+ }
385
+ let data;
386
+ try {
387
+ data = readJSON(filePath);
388
+ }
389
+ catch (error) {
390
+ return { include: false, reason: `invalid JSON: ${error.message}`, report: true, name: fileName };
391
+ }
392
+ if (!hasOrderGrid(data)) {
393
+ return { include: false, reason: 'not a persisted order grid', report: true, name: fileName };
394
+ }
395
+ // Derive botKey from the file name: profiles/orders/<botKey>.json
396
+ const botKey = fileName.replace(/\.json$/, '');
397
+ const botData = data;
398
+ const config = getConfiguredBotConfig(botKey, botData);
399
+ if (!config) {
400
+ return { include: false, reason: 'no matching bot config', report: true, name: fileName };
401
+ }
402
+ const realOrders = getRealGridOrders(botData);
403
+ if (realOrders.length === 0) {
404
+ return { include: false, reason: 'no real on-chain orders', report: true, name: fileName };
405
+ }
406
+ return { include: true, name: fileName, path: filePath, botKey, config };
407
+ }
408
+ // Get all order files sorted by modified date
409
+ function getOrderFiles() {
410
+ const candidates = fs.readdirSync(ORDERS_DIR).map(getOrderFileCandidate);
411
+ const files = candidates
412
+ .filter(candidate => candidate.include)
413
+ .map(f => ({
414
+ ...f,
415
+ mtime: getModifiedTime(f.path)
416
+ }))
417
+ .sort((a, b) => b.mtime - a.mtime);
418
+ return {
419
+ files,
420
+ skippedCandidates: candidates.filter(candidate => !candidate.include && candidate.report)
421
+ };
422
+ }
423
+ /**
424
+ * analyzeOrder: Comprehensive analysis of a single bot's order grid
425
+ *
426
+ * Examines all aspects of grid health:
427
+ * - Spread: Gap between best buy and best sell vs. target
428
+ * - Increment: Consistency of price steps between grid slots
429
+ * - Funds: Total funds allocated to each side
430
+ * - Distribution: Comparison of slot count vs. fund allocation
431
+ * - Double-sided mode: Whether sides are intentionally unbalanced
432
+ *
433
+ * Terminology:
434
+ * - boundaryIdx: Index of best buy slot (highest buy price)
435
+ * - Slots > boundaryIdx are sells
436
+ * - Slots < boundaryIdx are buys at boundary position
437
+ * - Spread slots are outside normal grid (rare)
438
+ *
439
+ * @param {Object} botData - Order data with grid array and metadata
440
+ * @param {Object} config - Bot configuration (optional) for comparison
441
+ * @param {string} [botKey] - Bot key used to locate the dynamic grid snapshot
442
+ * @returns {Object} Analysis result with spread, increment, funds, distribution
443
+ */
444
+ function analyzeOrder(botData, config, botKey) {
445
+ const meta = botData.meta;
446
+ const grid = botData.grid;
447
+ // Extract asset pair: prioritize assets object from order data, fall back to meta
448
+ let assetA = meta.assetA;
449
+ let assetB = meta.assetB;
450
+ // If metadata is null/missing, get from assets object in order file
451
+ if (!assetA && botData.assets && botData.assets.assetA) {
452
+ assetA = botData.assets.assetA.symbol;
453
+ }
454
+ if (!assetB && botData.assets && botData.assets.assetB) {
455
+ assetB = botData.assets.assetB.symbol;
456
+ }
457
+ /**
458
+ * Grid Slot Separation
459
+ * The grid contains buy slots (prices below market), sell slots (above market),
460
+ * and optional spread slots. Separation enables independent analysis.
461
+ */
462
+ const boundaryIdx = botData.boundaryIdx;
463
+ const buySlots = grid.filter((s, i) => i <= boundaryIdx && s.type === ORDER_TYPES.BUY);
464
+ const sellSlots = grid.filter((s, i) => i > boundaryIdx && s.type === ORDER_TYPES.SELL);
465
+ const spreadSlots = grid.filter(s => s.type === ORDER_TYPES.SPREAD);
466
+ const activeBuySlots = buySlots.filter(s => s.state === ORDER_STATES.ACTIVE || s.state === ORDER_STATES.PARTIAL);
467
+ const virtualBuySlots = buySlots.filter(s => s.state === ORDER_STATES.VIRTUAL);
468
+ const activeSellSlots = sellSlots.filter(s => s.state === ORDER_STATES.ACTIVE || s.state === ORDER_STATES.PARTIAL);
469
+ const virtualSellSlots = sellSlots.filter(s => s.state === ORDER_STATES.VIRTUAL);
470
+ /**
471
+ * Best Prices Identification
472
+ * bestBuySlot: Highest buy price (at boundary, closest to market)
473
+ * bestSellSlot: Lowest sell price (first sell after boundary, closest to market)
474
+ * The spread between these is the "real" spread of the grid
475
+ */
476
+ const bestBuySlot = grid[boundaryIdx];
477
+ const bestSellSlot = grid.slice(boundaryIdx + 1).find(s => s.type === ORDER_TYPES.SELL);
478
+ /**
479
+ * Real Spread Calculation
480
+ * Formula: (bestSellPrice - bestBuyPrice) / bestBuyPrice
481
+ * This is the actual gap in the market, measured as percentage from buy price
482
+ * Example: buy=100, sell=105 -> spread = 5%
483
+ */
484
+ const realSpread = bestBuySlot && bestSellSlot
485
+ ? ((bestSellSlot.price - bestBuySlot.price) / bestBuySlot.price)
486
+ : 0;
487
+ let spreadDiff, targetSpread, incrementCheck;
488
+ /**
489
+ * Config-based Comparisons
490
+ * If bot has configuration, compare actual to target values
491
+ * Otherwise, just report actual values
492
+ */
493
+ if (config) {
494
+ // Config exists - calculate variance from target
495
+ targetSpread = config.targetSpreadPercent / 100;
496
+ spreadDiff = realSpread - targetSpread;
497
+ incrementCheck = checkGeometricIncrement(grid, config.incrementPercent / 100);
498
+ }
499
+ else {
500
+ // No config - report actual values only
501
+ targetSpread = null;
502
+ spreadDiff = null;
503
+ incrementCheck = checkGeometricIncrement(grid, null);
504
+ }
505
+ // Calculate total funds committed to buy and sell sides
506
+ const gridFunds = calculateGridFunds(buySlots, sellSlots, bestBuySlot, bestSellSlot);
507
+ const activeGridFunds = calculateGridFunds(activeBuySlots, activeSellSlots, bestBuySlot, bestSellSlot);
508
+ const virtualGridFunds = calculateGridFunds(virtualBuySlots, virtualSellSlots, bestBuySlot, bestSellSlot);
509
+ // Analyze how funds are distributed across slots
510
+ const distribution = analyzeDistribution(buySlots, sellSlots, bestBuySlot, bestSellSlot);
511
+ // Calculate grid extremes and market price
512
+ const gridMinPrice = grid.length > 0 ? Math.min(...grid.map(s => s.price)) : null;
513
+ const gridMaxPrice = grid.length > 0 ? Math.max(...grid.map(s => s.price)) : null;
514
+ const marketPrice = bestBuySlot && bestSellSlot
515
+ ? (bestBuySlot.price + bestSellSlot.price) / 2
516
+ : null;
517
+ /**
518
+ * Return comprehensive analysis object
519
+ * Includes all metrics needed for health check output
520
+ */
521
+ const _dynamicWeight = buildDynamicWeightInfo(botKey, config);
522
+ const _ab = computeGridRangeScalingDisplay(config, _dynamicWeight);
523
+ let gridPriceValue = null;
524
+ let gridPriceLabel = null;
525
+ let gridPriceStale = false;
526
+ const _amaKey = resolveAmaKey(config);
527
+ if (_amaKey && _dynamicWeight?.amaCenterPrice != null) {
528
+ gridPriceLabel = _amaKey;
529
+ gridPriceValue = _dynamicWeight.amaCenterPrice;
530
+ gridPriceStale = _dynamicWeight.isRecent === false;
531
+ }
532
+ else if (typeof config?.gridPrice === 'number' && Number.isFinite(config.gridPrice) && config.gridPrice > 0) {
533
+ gridPriceLabel = 'Grid';
534
+ gridPriceValue = config.gridPrice;
535
+ }
536
+ return {
537
+ pair: `${assetA}/${assetB}`,
538
+ botName: config?.name || botKey,
539
+ lastUpdated: new Date(meta.updatedAt || botData.lastUpdated),
540
+ gridMinPrice: gridMinPrice,
541
+ marketPrice: marketPrice,
542
+ gridMaxPrice: gridMaxPrice,
543
+ hasConfig: !!config,
544
+ // Spread metrics
545
+ spread: {
546
+ real: realSpread,
547
+ target: targetSpread,
548
+ diff: spreadDiff,
549
+ // Pass if within 0.1% of target (or null if no config to compare)
550
+ pass: config ? Math.abs(spreadDiff) < 0.001 : null
551
+ },
552
+ // Increment consistency metrics
553
+ increment: incrementCheck,
554
+ // Fund allocation breakdown
555
+ funds: gridFunds,
556
+ activeFunds: activeGridFunds,
557
+ virtualFunds: virtualGridFunds,
558
+ // Slot vs fund distribution analysis
559
+ distribution: distribution,
560
+ // Slot counts for structure overview
561
+ slots: {
562
+ buy: buySlots.length,
563
+ sell: sellSlots.length,
564
+ spread: spreadSlots.length,
565
+ activeBuy: activeBuySlots.length,
566
+ virtualBuy: virtualBuySlots.length,
567
+ activeSell: activeSellSlots.length,
568
+ virtualSell: virtualSellSlots.length,
569
+ partialBuy: buySlots.filter(s => s.state === ORDER_STATES.PARTIAL).length,
570
+ partialSell: sellSlots.filter(s => s.state === ORDER_STATES.PARTIAL).length
571
+ },
572
+ // Slot data for weight visualization
573
+ slotData: {
574
+ buy: buySlots,
575
+ sell: sellSlots
576
+ },
577
+ // Target active orders from config
578
+ activeOrdersTarget: config ? config.activeOrders : null,
579
+ // Bot fund allocation settings from config
580
+ botFunds: config ? config.botFunds : null,
581
+ // Weight distribution from config
582
+ weightDistribution: config ? config.weightDistribution : null,
583
+ // Resolved grid price label, value, and staleness flag
584
+ // (null label/value when gridPrice is pool/book/null)
585
+ gridPriceLabel,
586
+ gridPriceValue,
587
+ gridPriceStale,
588
+ // Latest dynamic weight payload from the market adapter (AMA bots only).
589
+ // Null when the bot is not AMA, or when no fresh snapshot is available.
590
+ dynamicWeight: _dynamicWeight,
591
+ // Grid range scaling (asymmetric bounds) display data, null if not applicable.
592
+ asymmetricBounds: _ab,
593
+ };
594
+ }
595
+ /**
596
+ * computeGridRangeScalingDisplay: Compute resolved prices from grid range scaling.
597
+ * Returns null when the bot is not whitelisted or data is incomplete.
598
+ */
599
+ function computeGridRangeScalingDisplay(config, dynamicWeight) {
600
+ if (!dynamicWeight || dynamicWeight.amaCenterPrice == null) {
601
+ return null;
602
+ }
603
+ const centerPrice = dynamicWeight.amaCenterPrice;
604
+ let minPrice, maxPrice;
605
+ try {
606
+ minPrice = resolveConfiguredPriceBound(config && config.minPrice, undefined, centerPrice, 'min');
607
+ maxPrice = resolveConfiguredPriceBound(config && config.maxPrice, undefined, centerPrice, 'max');
608
+ }
609
+ catch (_) {
610
+ return null;
611
+ }
612
+ if (!Number.isFinite(minPrice) || !Number.isFinite(maxPrice))
613
+ return null;
614
+ const hasAsym = Number.isFinite(dynamicWeight.appliedAsymmetryFactor)
615
+ && (dynamicWeight.trend === 'UP' || dynamicWeight.trend === 'DOWN');
616
+ let resolvedMinPrice = minPrice;
617
+ let resolvedMaxPrice = maxPrice;
618
+ if (hasAsym) {
619
+ const prices = computeAsymmetricBoundsPrices(centerPrice, minPrice, maxPrice, dynamicWeight.trend, dynamicWeight.appliedAsymmetryFactor);
620
+ if (prices) {
621
+ resolvedMinPrice = prices.resolvedMinPrice;
622
+ resolvedMaxPrice = prices.resolvedMaxPrice;
623
+ }
624
+ }
625
+ const trend = hasAsym ? dynamicWeight.trend : null;
626
+ return {
627
+ resolvedMinPrice,
628
+ resolvedMaxPrice,
629
+ configuredMinPrice: minPrice,
630
+ configuredMaxPrice: maxPrice,
631
+ appliedAsymmetryFactor: hasAsym ? dynamicWeight.appliedAsymmetryFactor : 0,
632
+ rawAsymmetryFactor: hasAsym ? dynamicWeight.rawAsymmetryFactor : 0,
633
+ trend,
634
+ isRecent: dynamicWeight.isRecent,
635
+ };
636
+ }
637
+ /**
638
+ * checkGeometricIncrement: Verify grid uses consistent geometric price progression
639
+ *
640
+ * A proper grid should have constant percentage increments between slots.
641
+ * This function checks if increments are consistent (low standard deviation).
642
+ *
643
+ * Geometric increment formula:
644
+ * increment = (nextPrice - currentPrice) / currentPrice
645
+ * This is a percentage change from one slot to the next.
646
+ *
647
+ * Example with 2% increment:
648
+ * - Slot 1: 100
649
+ * - Slot 2: 102 (increment = 0.02 or 2%)
650
+ * - Slot 3: 104.04 (increment = 0.02 or 2%)
651
+ *
652
+ * Metrics:
653
+ * - avg: Average increment across all slots
654
+ * - stdDev: Standard deviation (should be < 0.1% for good grids)
655
+ * - pass: True if avg matches target and is consistent (for grids with config)
656
+ *
657
+ * @param {Array} grid - All grid slots
658
+ * @param {number} targetIncrement - Target increment ratio (e.g., 0.02 for 2%)
659
+ * @returns {Object} Increment analysis with avg, target, stdDev, consistency
660
+ */
661
+ function checkGeometricIncrement(grid, targetIncrement) {
662
+ // Filter out spread slots (only analyze regular buy/sell slots)
663
+ const slots = grid.filter(s => s.type !== 'spread');
664
+ // Need at least 2 slots to calculate increment
665
+ if (slots.length < 2) {
666
+ return { pass: null, avgIncrement: 0, consistent: true, target: targetIncrement };
667
+ }
668
+ /**
669
+ * Calculate increment for each consecutive pair of slots
670
+ * Increment = percentage change from previous to current price
671
+ */
672
+ const increments = [];
673
+ for (let i = 1; i < slots.length; i++) {
674
+ const prevPrice = slots[i - 1].price;
675
+ const currPrice = slots[i].price;
676
+ // Relative price change as decimal (0.02 = 2%)
677
+ const increment = (currPrice - prevPrice) / prevPrice;
678
+ increments.push(increment);
679
+ }
680
+ /**
681
+ * Statistical Analysis
682
+ * Average: Mean of all increments
683
+ * Standard deviation: Measure of variability (lower = more consistent)
684
+ */
685
+ const avgIncrement = increments.reduce((a, b) => a + b) / increments.length;
686
+ // Calculate standard deviation (measure of consistency)
687
+ const stdDev = Math.sqrt(increments.reduce((sum, inc) => sum + Math.pow(inc - avgIncrement, 2), 0) / increments.length);
688
+ return {
689
+ avg: avgIncrement, // Actual average increment
690
+ target: targetIncrement, // Expected increment from config
691
+ // Difference from target (null if no config)
692
+ diff: targetIncrement ? avgIncrement - targetIncrement : null,
693
+ stdDev: stdDev, // Consistency metric
694
+ // Grid is "consistent" if std dev < 0.1%
695
+ consistent: stdDev < 0.001,
696
+ // Pass if matches target AND is consistent (null if no config)
697
+ pass: targetIncrement ? (Math.abs(avgIncrement - targetIncrement) < 0.0001 && stdDev < 0.001) : null
698
+ };
699
+ }
700
+ /**
701
+ * calculateGridFunds: Calculate total funds in buy and sell sides
702
+ *
703
+ * Currency Note:
704
+ * - Buy slot sizes: Measured in AssetB (quote currency, e.g., BTS)
705
+ * Each buy slot uses quote currency to purchase base currency
706
+ * - Sell slot sizes: Measured in AssetA (base currency, e.g., XRP)
707
+ * Each sell slot holds base currency ready to sell
708
+ *
709
+ * Conversion logic:
710
+ * - BTS fund in buy side represents potential XRP purchase: totalBTS / marketPrice
711
+ * - XRP fund in sell side converts to BTS equivalent: totalXRP * marketPrice
712
+ * - Uses market price (midpoint between best buy and best sell) for accurate valuation
713
+ *
714
+ * @param {Array} buySlots - Buy order slots
715
+ * @param {Array} sellSlots - Sell order slots
716
+ * @param {Object} bestBuySlot - Best (highest) buy price slot
717
+ * @param {Object} bestSellSlot - Best (lowest) sell price slot
718
+ * @returns {Object} Fund breakdown {buy: {bts, xrp}, sell: {xrp, bts}}
719
+ */
720
+ function calculateGridFunds(buySlots, sellSlots, bestBuySlot, bestSellSlot) {
721
+ /**
722
+ * Direct Fund Aggregation
723
+ * Sum all slot sizes on each side
724
+ * Buy slots: Total BTS committed
725
+ * Sell slots: Total XRP (or base currency) available
726
+ */
727
+ const totalBTS = buySlots.reduce((sum, s) => sum + s.size, 0);
728
+ const totalXRP = sellSlots.reduce((sum, s) => sum + s.size, 0);
729
+ /**
730
+ * Market Price Calculation
731
+ * Use the midpoint between best buy and best sell prices
732
+ * This represents the fair market price for fund valuation
733
+ */
734
+ const marketPrice = bestBuySlot && bestSellSlot
735
+ ? (bestBuySlot.price + bestSellSlot.price) / 2
736
+ : 1;
737
+ // How much XRP the buy-side BTS could purchase (at market price)
738
+ const totalXRPFromBuy = totalBTS / marketPrice;
739
+ // How much BTS the sell-side XRP could generate (at market price)
740
+ const totalBTSFromSell = totalXRP * marketPrice;
741
+ return {
742
+ // Buy side: funds dedicated to purchasing base currency
743
+ buy: {
744
+ bts: totalBTS, // Direct BTS allocation
745
+ xrp: totalXRPFromBuy // Equivalent XRP buying power
746
+ },
747
+ // Sell side: funds available to sell base currency
748
+ sell: {
749
+ xrp: totalXRP, // Direct XRP holdings
750
+ bts: totalBTSFromSell // Equivalent BTS revenue potential
751
+ }
752
+ };
753
+ }
754
+ /**
755
+ * getDeltaColor: Return color code based on delta percentage value
756
+ * Under 10%: green, 10-20%: yellow, over 20%: red
757
+ * @param {number} deltaValue - The delta percentage value
758
+ * @returns {string} Color code
759
+ */
760
+ function getDeltaColor(deltaValue) {
761
+ if (deltaValue < 10)
762
+ return colors.buy; // green
763
+ if (deltaValue <= 20)
764
+ return colors.spread; // yellow
765
+ return colors.sell; // red
766
+ }
767
+ /**
768
+ * createDistributionBar: Create a horizontal bar chart showing BUY/SELL/spread distribution
769
+ * Differentiates between active (dark) and virtual (light) slots
770
+ * @param {Object} counts - Object containing activeBuy, virtualBuy, activeSell, virtualSell, spread
771
+ * @returns {{bar: string, buyWidth: number}} Colored bar visualization
772
+ */
773
+ function createDistributionBar(counts) {
774
+ const barWidth = BAR_WIDTH; // total width in characters
775
+ const total = counts.activeBuy + counts.virtualBuy + counts.spread + counts.activeSell + counts.virtualSell;
776
+ if (total === 0)
777
+ return { bar: ' '.repeat(barWidth), buyWidth: 0 };
778
+ // Calculate widths proportionally
779
+ let activeBuyWidth = Math.round((counts.activeBuy / total) * barWidth);
780
+ let virtualBuyWidth = Math.round((counts.virtualBuy / total) * barWidth);
781
+ let spreadWidth = Math.round((counts.spread / total) * barWidth);
782
+ let activeSellWidth = Math.round((counts.activeSell / total) * barWidth);
783
+ let virtualSellWidth = Math.round((counts.virtualSell / total) * barWidth);
784
+ // Ensure spread is visible if it exists
785
+ if (counts.spread > 0 && spreadWidth === 0) {
786
+ spreadWidth = 1;
787
+ // Borrow from largest other section
788
+ const widths = [
789
+ { name: 'activeBuy', val: activeBuyWidth },
790
+ { name: 'virtualBuy', val: virtualBuyWidth },
791
+ { name: 'activeSell', val: activeSellWidth },
792
+ { name: 'virtualSell', val: virtualSellWidth }
793
+ ].sort((a, b) => b.val - a.val);
794
+ if (widths[0].val > 0) {
795
+ if (widths[0].name === 'activeBuy')
796
+ activeBuyWidth--;
797
+ else if (widths[0].name === 'virtualBuy')
798
+ virtualBuyWidth--;
799
+ else if (widths[0].name === 'activeSell')
800
+ activeSellWidth--;
801
+ else if (widths[0].name === 'virtualSell')
802
+ virtualSellWidth--;
803
+ }
804
+ }
805
+ // Adjust to ensure total is exactly barWidth
806
+ const sum = activeBuyWidth + virtualBuyWidth + spreadWidth + activeSellWidth + virtualSellWidth;
807
+ if (sum !== barWidth) {
808
+ let diff = barWidth - sum;
809
+ const sections = [
810
+ { name: 'activeBuyWidth', get: () => activeBuyWidth, set: v => { activeBuyWidth = v; } },
811
+ { name: 'virtualBuyWidth', get: () => virtualBuyWidth, set: v => { virtualBuyWidth = v; } },
812
+ { name: 'spreadWidth', get: () => spreadWidth, set: v => { spreadWidth = v; } },
813
+ { name: 'activeSellWidth', get: () => activeSellWidth, set: v => { activeSellWidth = v; } },
814
+ { name: 'virtualSellWidth', get: () => virtualSellWidth, set: v => { virtualSellWidth = v; } }
815
+ ];
816
+ while (diff > 0) {
817
+ const target = sections
818
+ .slice()
819
+ .sort((a, b) => b.get() - a.get())[0];
820
+ target.set(target.get() + 1);
821
+ diff--;
822
+ }
823
+ while (diff < 0) {
824
+ const target = sections
825
+ .filter(section => section.get() > 0)
826
+ .sort((a, b) => b.get() - a.get())[0];
827
+ if (!target)
828
+ break;
829
+ target.set(target.get() - 1);
830
+ diff++;
831
+ }
832
+ }
833
+ const buyBar = colors.buy + 'ā–ˆ'.repeat(virtualBuyWidth) + colors.buyDark + 'ā–ˆ'.repeat(activeBuyWidth) + colors.reset;
834
+ const spreadBar = '\x1b[97m' + 'ā–ˆ'.repeat(spreadWidth) + colors.reset; // white
835
+ const sellBar = colors.sellDark + 'ā–ˆ'.repeat(activeSellWidth) + colors.sell + 'ā–ˆ'.repeat(virtualSellWidth) + colors.reset;
836
+ return { bar: `${buyBar}${spreadBar}${sellBar}`, buyWidth: activeBuyWidth + virtualBuyWidth };
837
+ }
838
+ /**
839
+ * createWeightFactorBar: Visualize capital distribution using actual order sizes
840
+ *
841
+ * Shows how capital is distributed across BUY and SELL orders using arithmetic averages.
842
+ * Buy funds measured in quote currency, sell funds in base currency - converts to common basis.
843
+ * Each side scales independently: highest order on each side = 100% (ā–ˆ)
844
+ * Character width is proportional to fund amount on each side (not 50/50 split).
845
+ * Full block (ā–ˆ) = maximum average capital on that side
846
+ * Partial blocks (▁-ā–‡) = progressively lower average capital
847
+ *
848
+ * @param {Array} buyOrders - Buy orders with size property (in quote currency)
849
+ * @param {Array} sellOrders - Sell orders with size property (in base currency)
850
+ * @param {number} barWidth - Target width in characters (default: BAR_WIDTH=51)
851
+ * @param {number} marketPrice - Market price for currency conversion (sell to quote basis)
852
+ * @returns {string} Colored weight visualization with independent scaling
853
+ */
854
+ function createWeightFactorBar(buyOrders, sellOrders, barWidth = BAR_WIDTH, marketPrice = 1) {
855
+ if ((!buyOrders || buyOrders.length === 0) && (!sellOrders || sellOrders.length === 0)) {
856
+ return '(no orders)';
857
+ }
858
+ // Calculate total fund weight on each side using arithmetic sum
859
+ const buyTotalSize = (buyOrders || []).reduce((sum, o) => sum + (o.size || 0), 0);
860
+ const sellTotalSize = (sellOrders || []).reduce((sum, o) => sum + (o.size || 0), 0);
861
+ // Convert sell side to quote currency equivalent for accurate ratio calculation
862
+ // Buy side is in quote currency, sell side is in base currency
863
+ // Using market price to convert: sell_base * market_price = sell_quote_equivalent
864
+ const sellTotalInQuote = sellTotalSize * marketPrice;
865
+ const totalFunds = buyTotalSize + sellTotalInQuote;
866
+ // Allocate widths proportionally based on fund ratios (in common currency basis)
867
+ // This ensures character length reflects the actual fund distribution
868
+ let buyWidth, sellWidth;
869
+ if (totalFunds > 0) {
870
+ buyWidth = Math.round((buyTotalSize / totalFunds) * barWidth);
871
+ sellWidth = barWidth - buyWidth;
872
+ }
873
+ else {
874
+ // Fallback to 50/50 if no funds
875
+ buyWidth = Math.floor(barWidth / 2);
876
+ sellWidth = barWidth - buyWidth;
877
+ }
878
+ // Create buy side with independent scaling (max on buy side = 100%)
879
+ const buyBar = createWeightSide(buyOrders, colors.buyDark, colors.buy, buyWidth);
880
+ // Create sell side with independent scaling (max on sell side = 100%)
881
+ const sellBar = createWeightSide(sellOrders, colors.sellDark, colors.sell, sellWidth);
882
+ return `${buyBar}${sellBar}`;
883
+ }
884
+ /**
885
+ * Helper: Create weight visualization for one side with independent scaling
886
+ * Distributes orders evenly across bar width, ensuring all bars are filled
887
+ * @param {Array} orders - Orders on this side
888
+ * @param {string} activeColor - Color for active orders
889
+ * @param {string} virtualColor - Color for virtual orders
890
+ * @param {number} sideWidth - Width allocated to this side
891
+ */
892
+ function createWeightSide(orders, activeColor, virtualColor, sideWidth) {
893
+ if (!orders || orders.length === 0 || sideWidth === 0) {
894
+ return virtualColor + ' '.repeat(sideWidth) + colors.reset;
895
+ }
896
+ // Get sizes and find max for THIS SIDE only (independent scaling)
897
+ const sizes = orders.map(o => o.size || 0);
898
+ const maxSize = Math.max(...sizes);
899
+ if (maxSize === 0) {
900
+ return virtualColor + 'ā–‘'.repeat(sideWidth) + colors.reset;
901
+ }
902
+ const compressedWeights = [];
903
+ // Distribute orders evenly across all bar positions
904
+ // Each bar maps to a position in the orders array
905
+ for (let barIdx = 0; barIdx < sideWidth; barIdx++) {
906
+ // Map bar position to order range
907
+ // This ensures even distribution even if orders < sideWidth
908
+ const startPos = (barIdx * orders.length) / sideWidth;
909
+ const endPos = ((barIdx + 1) * orders.length) / sideWidth;
910
+ // Get all orders that fall within this bar's range
911
+ const startIdx = Math.floor(startPos);
912
+ const endIdx = Math.ceil(endPos);
913
+ const groupOrders = orders.slice(startIdx, endIdx);
914
+ if (groupOrders.length === 0) {
915
+ // Fallback: if no orders in range, find nearest order
916
+ const nearestIdx = Math.round(startPos);
917
+ groupOrders.push(orders[Math.min(nearestIdx, orders.length - 1)]);
918
+ }
919
+ const groupSizes = groupOrders.map(o => o.size || 0);
920
+ // Calculate arithmetic average of sizes in this group
921
+ const avgSize = groupSizes.reduce((a, b) => a + b, 0) / groupSizes.length;
922
+ // Normalize to max on THIS SIDE (1-8, minimum 1 for visibility)
923
+ const ratio = avgSize / maxSize;
924
+ const blockHeight = Math.max(1, Math.round(ratio * 8));
925
+ // ACTIVE and PARTIAL slots are both real on-chain orders in this analysis.
926
+ const hasLiveOrder = groupOrders.some(o => o.state === ORDER_STATES.ACTIVE || o.state === ORDER_STATES.PARTIAL);
927
+ const color = hasLiveOrder ? activeColor : virtualColor;
928
+ compressedWeights.push(color + partialBlocks[blockHeight] + colors.reset);
929
+ }
930
+ return compressedWeights.join('');
931
+ }
932
+ /**
933
+ * analyzeDistribution: Compare slot distribution vs fund distribution
934
+ *
935
+ * Identifies imbalances between:
936
+ * - Slot distribution: How many buy vs sell slots exist
937
+ * - Fund distribution: How much funds are allocated to buy vs sell
938
+ *
939
+ * These should ideally match:
940
+ * - If 50% slots are buy, ~50% of funds should be on buy side
941
+ * - Deviation suggests intentional weighting or uneven fees
942
+ *
943
+ * Example:
944
+ * - 100 total slots: 40 buy + 60 sell = 40% buy slots
945
+ * - Funds: 6000 BTS buy + 4000 BTS sell equivalent = 60% buy funds
946
+ * - Delta buy: |40% - 60%| = 20% (funds weight more toward buy)
947
+ *
948
+ * @param {Array} buySlots - Buy order slots
949
+ * @param {Array} sellSlots - Sell order slots
950
+ * @param {Object} bestBuySlot - Best buy price (used for market price calculation)
951
+ * @param {Object} bestSellSlot - Best sell price (used for market price calculation)
952
+ * @returns {Object} Distribution analysis with slot%, fund%, and deltas
953
+ */
954
+ function analyzeDistribution(buySlots, sellSlots, bestBuySlot, bestSellSlot) {
955
+ /**
956
+ * Slot Distribution
957
+ * Simple count: what percentage of total slots are buy vs sell
958
+ */
959
+ const totalSlots = buySlots.length + sellSlots.length;
960
+ const buySlotPercent = totalSlots > 0 ? (buySlots.length / totalSlots) * 100 : 0;
961
+ const sellSlotPercent = totalSlots > 0 ? (sellSlots.length / totalSlots) * 100 : 0;
962
+ /**
963
+ * Fund Distribution
964
+ * Calculate total funds on each side, convert to common currency basis
965
+ * This shows if sides have equal capital or if one is prioritized
966
+ */
967
+ const totalBuyFunds = buySlots.reduce((sum, s) => sum + s.size, 0);
968
+ const totalSellFunds = sellSlots.reduce((sum, s) => sum + s.size, 0);
969
+ /**
970
+ * Currency Conversion for Comparison
971
+ * Buy side funds: Measured in AssetB (quote)
972
+ * Sell side funds: Measured in AssetA (base)
973
+ * Convert both to common basis using market price (midpoint between best buy/sell)
974
+ */
975
+ const marketPrice = bestBuySlot && bestSellSlot
976
+ ? (bestBuySlot.price + bestSellSlot.price) / 2
977
+ : 1;
978
+ // Convert sell-side funds (XRP) to quote currency equivalent (BTS)
979
+ // This allows apples-to-apples fund comparison using market price
980
+ const sellFundsInBTS = totalSellFunds * marketPrice;
981
+ const totalFunds = totalBuyFunds + sellFundsInBTS;
982
+ /**
983
+ * Fund Percentage
984
+ * What % of total funds are allocated to buy vs sell
985
+ */
986
+ const buyFundPercent = totalFunds > 0 ? (totalBuyFunds / totalFunds) * 100 : 0;
987
+ const sellFundPercent = totalFunds > 0 ? (sellFundsInBTS / totalFunds) * 100 : 0;
988
+ return {
989
+ // Slot-level breakdown
990
+ slots: {
991
+ buy: buySlots.length,
992
+ sell: sellSlots.length,
993
+ buyPercent: buySlotPercent,
994
+ sellPercent: sellSlotPercent
995
+ },
996
+ // Fund-level breakdown (in common currency)
997
+ funds: {
998
+ buyPercent: buyFundPercent,
999
+ sellPercent: sellFundPercent
1000
+ },
1001
+ // Delta: difference between slot% and fund% (shows imbalance)
1002
+ // If match is 0, slots and funds are perfectly balanced
1003
+ // If match is high, one side is over/under-weighted in funds
1004
+ match: {
1005
+ buyDiff: buyFundPercent - buySlotPercent,
1006
+ sellDiff: sellFundPercent - sellSlotPercent
1007
+ }
1008
+ };
1009
+ }
1010
+ /**
1011
+ * getRawWeightValues: Extract raw buy/sell value strings for column alignment,
1012
+ * without any color codes or formatting artifacts.
1013
+ *
1014
+ * Mirrors the display-mode logic of formatWeightLine but returns plain strings.
1015
+ *
1016
+ * @param {Object|null} weightDistribution
1017
+ * @param {Object|null} dynamicWeight
1018
+ * @returns {{ buy: string, sell: string } | null}
1019
+ */
1020
+ function getRawWeightValues(weightDistribution, dynamicWeight) {
1021
+ if (!weightDistribution)
1022
+ return null;
1023
+ const staticBuy = Number(weightDistribution.buy);
1024
+ const staticSell = Number(weightDistribution.sell);
1025
+ if (!Number.isFinite(staticBuy) || !Number.isFinite(staticSell))
1026
+ return null;
1027
+ if (dynamicWeight && dynamicWeight.isRecent === false) {
1028
+ return { buy: staticBuy.toFixed(2), sell: staticSell.toFixed(2) };
1029
+ }
1030
+ const useLive = !!(dynamicWeight
1031
+ && dynamicWeight.isRecent
1032
+ && dynamicWeight.live
1033
+ && Number.isFinite(Number(dynamicWeight.live.buy))
1034
+ && Number.isFinite(Number(dynamicWeight.live.sell)));
1035
+ if (!useLive) {
1036
+ return { buy: staticBuy.toFixed(2), sell: staticSell.toFixed(2) };
1037
+ }
1038
+ const liveBuy = Number(dynamicWeight.live.buy);
1039
+ const liveSell = Number(dynamicWeight.live.sell);
1040
+ return {
1041
+ buy: liveBuy.toFixed(2),
1042
+ sell: liveSell.toFixed(2)
1043
+ };
1044
+ }
1045
+ /**
1046
+ * formatWeightLine: Render the "Weight:" line, optionally with live dynamic values.
1047
+ *
1048
+ * Has three display modes:
1049
+ * 1. No dynamic snapshot at all (static-only) — e.g. legacy bots
1050
+ * 2. Stale snapshot — static values grayed only when dynamic weights are enabled
1051
+ * 3. Live snapshot — live values colored by delta
1052
+ *
1053
+ * When maxBuyWidth/maxSellWidth are provided, the value portion in each column
1054
+ * is right-padded so it aligns with the widest value across the Active/Weight/Funds block.
1055
+ *
1056
+ * @param {Object|null} weightDistribution - Static weight config from bots.json
1057
+ * @param {Object|null} dynamicWeight - Live weight snapshot from dynamic grid
1058
+ * @param {number} [maxBuyWidth] - Target width for buy-side values (for column alignment)
1059
+ * @param {number} [maxSellWidth] - Target width for sell-side values (for column alignment)
1060
+ * @returns {string|null} Formatted weight line or null if no valid data
1061
+ */
1062
+ function formatWeightLine(weightDistribution, dynamicWeight, maxBuyWidth, maxSellWidth) {
1063
+ if (!weightDistribution)
1064
+ return null;
1065
+ const staticBuy = Number(weightDistribution.buy);
1066
+ const staticSell = Number(weightDistribution.sell);
1067
+ if (!Number.isFinite(staticBuy) || !Number.isFinite(staticSell))
1068
+ return null;
1069
+ // Stale snapshot: snapshot file exists but updatedAt is older than the
1070
+ // freshness window. Surface a red "(adapter offline)" alert so the operator
1071
+ // knows the live envelope is being withheld, not just absent.
1072
+ if (dynamicWeight && dynamicWeight.isRecent === false) {
1073
+ const buyVal = staticBuy.toFixed(2);
1074
+ const sellVal = staticSell.toFixed(2);
1075
+ const alertStr = `${colors.sell}(adapter offline)${colors.reset}`;
1076
+ const valueColor = dynamicWeight.dynamicWeightEnabled === true ? colors.gray : '';
1077
+ const valueReset = valueColor ? colors.reset : '';
1078
+ return ` Weight: ${valueColor}${maxBuyWidth ? buyVal.padEnd(maxBuyWidth) : buyVal}${valueReset} ${colors.buy}buy${colors.reset} | ${valueColor}${maxSellWidth ? sellVal.padEnd(maxSellWidth) : sellVal}${valueReset} ${colors.sell}sell${colors.reset} ${alertStr}`;
1079
+ }
1080
+ const useLive = !!(dynamicWeight
1081
+ && dynamicWeight.isRecent
1082
+ && dynamicWeight.live
1083
+ && Number.isFinite(Number(dynamicWeight.live.buy))
1084
+ && Number.isFinite(Number(dynamicWeight.live.sell)));
1085
+ if (!useLive) {
1086
+ const buyVal = staticBuy.toFixed(2);
1087
+ const sellVal = staticSell.toFixed(2);
1088
+ return ` Weight: ${maxBuyWidth ? buyVal.padEnd(maxBuyWidth) : buyVal} ${colors.buy}buy${colors.reset} | ${maxSellWidth ? sellVal.padEnd(maxSellWidth) : sellVal} ${colors.sell}sell${colors.reset}`;
1089
+ }
1090
+ const liveBuy = Number(dynamicWeight.live.buy);
1091
+ const liveSell = Number(dynamicWeight.live.sell);
1092
+ // Compare the two live weights, not their deltas: the side with the larger
1093
+ // live weight is the one the bot is leaning on most heavily (the "losing"
1094
+ // side for that asset). When the two live weights are equal, no side is
1095
+ // being favored, so both fall back to white (default terminal color).
1096
+ const liveDelta = liveBuy - liveSell;
1097
+ let buyColor;
1098
+ let sellColor;
1099
+ if (Math.abs(liveDelta) <= DYNAMIC_WEIGHT_EPSILON) {
1100
+ buyColor = '';
1101
+ sellColor = '';
1102
+ }
1103
+ else if (liveDelta > 0) {
1104
+ // Buy is higher -> losing side (red); sell is lower -> winning side (green)
1105
+ buyColor = colors.sell;
1106
+ sellColor = colors.buy;
1107
+ }
1108
+ else {
1109
+ // Buy is lower -> winning side (green); sell is higher -> losing side (red)
1110
+ buyColor = colors.buy;
1111
+ sellColor = colors.sell;
1112
+ }
1113
+ const liveBuyStr = `${buyColor}${liveBuy.toFixed(2)}${colors.reset}`;
1114
+ const liveSellStr = `${sellColor}${liveSell.toFixed(2)}${colors.reset}`;
1115
+ const buyValVisual = liveBuy.toFixed(2);
1116
+ const sellValVisual = liveSell.toFixed(2);
1117
+ const coloredBuyVal = liveBuyStr;
1118
+ const coloredSellVal = liveSellStr;
1119
+ const paddedBuyVal = maxBuyWidth ? coloredBuyVal + ' '.repeat(Math.max(0, maxBuyWidth - buyValVisual.length)) : coloredBuyVal;
1120
+ const paddedSellVal = maxSellWidth ? coloredSellVal + ' '.repeat(Math.max(0, maxSellWidth - sellValVisual.length)) : coloredSellVal;
1121
+ return ` Weight: ${paddedBuyVal} ${colors.buy}buy${colors.reset} | ${paddedSellVal} ${colors.sell}sell${colors.reset}`;
1122
+ }
1123
+ /**
1124
+ * formatAnalysis: Format analysis results into readable console output
1125
+ *
1126
+ * Creates a compact, emoji-enriched display of all analysis metrics.
1127
+ * Each line is designed to fit in typical terminal width.
1128
+ *
1129
+ * Output layout:
1130
+ * šŸ“Š PAIR
1131
+ * Updated: [timestamp]
1132
+ * [warnings if applicable]
1133
+ * Spread: [status] [real]% (target: [target]%) [direction][delta]
1134
+ * Increment: [status] [avg]% (target: [target]%) [direction][delta] σ=[stddev]
1135
+ * Slots: [buy] buy + [spread] spread + [sell] sell
1136
+ * Grid: BUY [amount] QUOTE ā‰ˆ [amount] BASE
1137
+ * SELL [amount] BASE ā‰ˆ [amount] QUOTE
1138
+ * Dist: BUY slots [%] vs funds [%] (Ī”[diff]%) | SELL slots [%] vs funds [%] (Ī”[diff]%)
1139
+ *
1140
+ * Symbols:
1141
+ * āœ“ = passes threshold
1142
+ * āœ— = exceeds threshold (needs attention)
1143
+ * ↓ = value is lower than target
1144
+ * ↑ = value is higher than target
1145
+ * σ = standard deviation (consistency)
1146
+ * Ī” = delta (difference)
1147
+ *
1148
+ * @param {Object} analysis - Analysis result object from analyzeOrder()
1149
+ * @returns {string} Formatted multi-line output ready for console.log
1150
+ */
1151
+ function formatAnalysis(analysis) {
1152
+ const lines = [];
1153
+ // Header: Trading pair name
1154
+ lines.push(`\n${colors.cyan}šŸ“Š ${analysis.pair}${colors.reset} (${analysis.botName})`);
1155
+ lines.push(` ${colors.gray}Update: ${analysis.lastUpdated.toLocaleString()}${colors.reset}`);
1156
+ lines.push(``);
1157
+ // Warning: No config available for comparison
1158
+ if (!analysis.hasConfig) {
1159
+ lines.push(` ${colors.gray}āš ļø No config found - showing grid data only${colors.reset}`);
1160
+ }
1161
+ /**
1162
+ * Spread Analysis
1163
+ * Shows: actual spread vs target spread
1164
+ * Status: āœ“ if within 0.1% of target, āœ— if not
1165
+ * Direction: ↑ if above target, ↓ if below target
1166
+ */
1167
+ if (analysis.hasConfig) {
1168
+ lines.push(` Spread:${formatPercent(analysis.spread.real).padStart(6)} (${formatPercent(analysis.spread.target)}) | Incr.:${formatPercent(analysis.increment.avg).padStart(6)} (${formatPercent(analysis.increment.target)})`);
1169
+ }
1170
+ else {
1171
+ lines.push(` Spread:${formatPercent(analysis.spread.real).padStart(6)} | Incr.:${formatPercent(analysis.increment.avg).padStart(6)}`);
1172
+ }
1173
+ // Active orders comparison
1174
+ if (analysis.hasConfig && analysis.activeOrdersTarget) {
1175
+ const buyTarget = analysis.activeOrdersTarget.buy;
1176
+ const sellTarget = analysis.activeOrdersTarget.sell;
1177
+ const buyActual = analysis.slots.activeBuy;
1178
+ const sellActual = analysis.slots.activeSell;
1179
+ // Collect raw buy/sell values across Active, Weight, Funds for column alignment
1180
+ const rawWeightVals = getRawWeightValues(analysis.weightDistribution, analysis.dynamicWeight);
1181
+ const buyValues = [`${buyActual}/${buyTarget}`];
1182
+ const sellValues = [`${sellActual}/${sellTarget}`];
1183
+ if (rawWeightVals) {
1184
+ buyValues.push(rawWeightVals.buy);
1185
+ sellValues.push(rawWeightVals.sell);
1186
+ }
1187
+ if (analysis.botFunds) {
1188
+ buyValues.push(analysis.botFunds.buy);
1189
+ sellValues.push(analysis.botFunds.sell);
1190
+ }
1191
+ const maxBuyWidth = Math.max(...buyValues.map(v => stripColorCodes(v).length));
1192
+ const maxSellWidth = Math.max(...sellValues.map(v => stripColorCodes(v).length));
1193
+ lines.push(` Active: ${(buyActual + '/' + buyTarget).padEnd(maxBuyWidth)} ${colors.buy}buy${colors.reset} | ${(sellActual + '/' + sellTarget).padEnd(maxSellWidth)} ${colors.sell}sell${colors.reset}`);
1194
+ lines.push(``);
1195
+ const weightLine = formatWeightLine(analysis.weightDistribution, analysis.dynamicWeight, maxBuyWidth, maxSellWidth);
1196
+ if (weightLine) {
1197
+ lines.push(weightLine);
1198
+ }
1199
+ if (analysis.botFunds) {
1200
+ lines.push(` Funds: ${analysis.botFunds.buy.padEnd(maxBuyWidth)} ${colors.buy}buy${colors.reset} | ${analysis.botFunds.sell.padEnd(maxSellWidth)} ${colors.sell}sell${colors.reset}`);
1201
+ }
1202
+ if (analysis.gridPriceLabel && analysis.gridPriceValue != null) {
1203
+ lines.push(``);
1204
+ const rawPrice = Number(analysis.gridPriceValue);
1205
+ const priceStr = formatCurrency(rawPrice);
1206
+ const priceColor = analysis.gridPriceStale ? colors.gray : '';
1207
+ const priceReset = priceColor ? colors.reset : '';
1208
+ let diffStr = '';
1209
+ if (analysis.marketPrice != null && rawPrice !== 0) {
1210
+ const diff = (analysis.marketPrice - rawPrice) / rawPrice;
1211
+ const diffColor = diff > 0 ? colors.buy : diff < 0 ? colors.sell : '';
1212
+ const sign = diff > 0 ? '+' : '';
1213
+ diffStr = ` ${diffColor}(${sign}${(diff * 100).toFixed(1)}%)${colors.reset}`;
1214
+ }
1215
+ lines.push(` ${analysis.gridPriceLabel}: ${priceColor}${priceStr}${priceReset}${diffStr}`);
1216
+ }
1217
+ if (analysis.asymmetricBounds) {
1218
+ const ab = analysis.asymmetricBounds;
1219
+ const minStr = formatCurrency(ab.resolvedMinPrice);
1220
+ const maxStr = formatCurrency(ab.resolvedMaxPrice);
1221
+ const asymSign = ab.trend === 'DOWN' ? '-' : '+';
1222
+ const pctStr = ab.appliedAsymmetryFactor !== 0
1223
+ ? ` (${asymSign}${(ab.appliedAsymmetryFactor * 100).toFixed(1)}%)`
1224
+ : '';
1225
+ lines.push(` Bounds: ${colors.buy}${minStr}${colors.reset} - ${colors.sell}${maxStr}${colors.reset}${pctStr}`);
1226
+ }
1227
+ lines.push(``);
1228
+ }
1229
+ // Calculate bar positioning based on slot distribution
1230
+ const totalSlots = analysis.slots.buy + analysis.slots.sell + analysis.slots.spread;
1231
+ const buyBarWidth = totalSlots > 0 ? Math.floor((analysis.slots.buy / totalSlots) * BAR_WIDTH) : 0;
1232
+ const spreadBarWidth = analysis.slots.spread > 0 ? Math.max(1, Math.floor((analysis.slots.spread / totalSlots) * BAR_WIDTH)) : 0;
1233
+ const sellBarWidth = BAR_WIDTH - buyBarWidth - spreadBarWidth;
1234
+ // Create formatted labels for three-column layout
1235
+ const buyLabel = `${analysis.slots.buy} buy`;
1236
+ const spreadLabel = `${analysis.slots.spread} spread`;
1237
+ const sellLabel = `${analysis.slots.sell} sell`;
1238
+ // Price Range - formatted with three-column alignment
1239
+ const buyPrice = analysis.gridMinPrice ? `${colors.buy}${formatCurrency(analysis.gridMinPrice)}${colors.reset}` : 'N/A';
1240
+ const midPrice = analysis.marketPrice ? formatCurrency(analysis.marketPrice) : 'N/A';
1241
+ const sellPrice = analysis.gridMaxPrice ? `${colors.sell}${formatCurrency(analysis.gridMaxPrice)}${colors.reset}` : 'N/A';
1242
+ const pricePrefix = ` Price: `;
1243
+ const slotsPrefix = ` Slots: `;
1244
+ // Get visual lengths (without color codes)
1245
+ const buyPriceVisualLen = stripColorCodes(buyPrice).length;
1246
+ const midPriceVisualLen = stripColorCodes(midPrice).length;
1247
+ const sellPriceVisualLen = stripColorCodes(sellPrice).length;
1248
+ const buyLabelVisualLen = buyLabel.length;
1249
+ const spreadLabelVisualLen = spreadLabel.length;
1250
+ const sellLabelVisualLen = sellLabel.length;
1251
+ // Calculate positions where items should end to align with bar sections
1252
+ const barStart = 0;
1253
+ const buySection = barStart + buyBarWidth;
1254
+ const spreadSection = buySection + spreadBarWidth;
1255
+ const barEnd = spreadSection + sellBarWidth;
1256
+ // Position items right-aligned at section boundaries, with minimum 1 space gap
1257
+ // Buy item: right-align to buySection
1258
+ const buyPriceSpacing1 = Math.max(1, buySection - buyPriceVisualLen);
1259
+ // Spread item: positioned to center in spread zone
1260
+ const spreadMid = buySection + spreadBarWidth / 2;
1261
+ const midPriceSpacing1 = Math.max(1, Math.round(spreadMid - midPriceVisualLen / 2) - buyPriceVisualLen);
1262
+ // Sell item: right-align to barEnd
1263
+ const sellPriceSpacing2 = Math.max(1, barEnd - sellPriceVisualLen - buyPriceVisualLen - midPriceVisualLen - midPriceSpacing1);
1264
+ lines.push(`${pricePrefix}${buyPrice}${' '.repeat(midPriceSpacing1)}${midPrice}${' '.repeat(Math.max(1, sellPriceSpacing2))}${sellPrice}`);
1265
+ // Same logic for slots line
1266
+ const buyLabelSpacing1 = Math.max(1, buySection - buyLabelVisualLen);
1267
+ const spreadMidLabel = buySection + spreadBarWidth / 2;
1268
+ const spreadLabelSpacing1 = Math.max(1, Math.round(spreadMidLabel - spreadLabelVisualLen / 2) - buyLabelVisualLen);
1269
+ const sellLabelSpacing2 = Math.max(1, barEnd - sellLabelVisualLen - buyLabelVisualLen - spreadLabelVisualLen - spreadLabelSpacing1);
1270
+ lines.push(`${slotsPrefix}${colors.buy}${buyLabel}${colors.reset}${' '.repeat(spreadLabelSpacing1)}${spreadLabel}${' '.repeat(Math.max(1, sellLabelSpacing2))}${colors.sell}${sellLabel}${colors.reset}`);
1271
+ /**
1272
+ * Fund Allocation Breakdown
1273
+ * Shows funds in each currency (quote for buy, base for sell)
1274
+ * Also shows cross-currency equivalent for comparison
1275
+ * Example: BUY 1000 BTS ā‰ˆ 50 XRP (at avg buy price)
1276
+ */
1277
+ const [assetASymbol, assetBSymbol] = analysis.pair.split('/');
1278
+ // Fallback for null symbols (shouldn't happen after fix, but added for safety)
1279
+ const aSymbol = assetASymbol || 'BASE';
1280
+ const bSymbol = assetBSymbol || 'QUOTE';
1281
+ /**
1282
+ * Distribution Analysis
1283
+ * Compares slot count % with fund allocation %
1284
+ * Shows if one side is over/under-weighted relative to slot count
1285
+ * Ī” (delta) = difference between slot % and fund %
1286
+ * Ī” 0% = perfectly balanced (slots match funds)
1287
+ * Ī” 20% = significant imbalance (e.g., 40% slots but 60% funds)
1288
+ */
1289
+ const buySlotPct = analysis.distribution.slots.buyPercent.toFixed(1);
1290
+ const buyFundPct = analysis.distribution.funds.buyPercent.toFixed(1);
1291
+ const sellSlotPct = analysis.distribution.slots.sellPercent.toFixed(1);
1292
+ const sellFundPct = analysis.distribution.funds.sellPercent.toFixed(1);
1293
+ const buyMatch = analysis.distribution.match.buyDiff.toFixed(1);
1294
+ const sellMatch = analysis.distribution.match.sellDiff.toFixed(1);
1295
+ // Calculate spread slot percentage (totalSlots already calculated above)
1296
+ const spreadSlotPct = totalSlots > 0 ? ((analysis.slots.spread / totalSlots) * 100).toFixed(1) : '0.0';
1297
+ // Recalculate buy/sell percentages to include spread in total
1298
+ const buySlotPctWithSpread = totalSlots > 0 ? ((analysis.slots.buy / totalSlots) * 100).toFixed(1) : '0.0';
1299
+ const sellSlotPctWithSpread = totalSlots > 0 ? ((analysis.slots.sell / totalSlots) * 100).toFixed(1) : '0.0';
1300
+ const { bar: slotDistBar, buyWidth: slotDistBuyWidth } = createDistributionBar({
1301
+ activeBuy: analysis.slots.activeBuy,
1302
+ virtualBuy: analysis.slots.virtualBuy,
1303
+ spread: analysis.slots.spread,
1304
+ activeSell: analysis.slots.activeSell,
1305
+ virtualSell: analysis.slots.virtualSell
1306
+ });
1307
+ // Weight factor visualization (funds distribution across all orders)
1308
+ const weightBar = createWeightFactorBar(analysis.slotData?.buy, analysis.slotData?.sell, BAR_WIDTH, analysis.marketPrice || 1);
1309
+ lines.push(` ${slotDistBar}`);
1310
+ // Position delta indicator directly under the spread slot character
1311
+ const buyDiffVal = analysis.distribution.match.buyDiff;
1312
+ const signedMatch = (buyDiffVal > 0 ? '+' : '') + buyDiffVal.toFixed(1);
1313
+ const deltaStr = `Ī” ${signedMatch}%`;
1314
+ const spreadStart = 11 + slotDistBuyWidth; // Position where spread character starts (11 = prefix length)
1315
+ lines.push(`${' '.repeat(spreadStart)}${deltaStr}`);
1316
+ lines.push(` Funds: ${weightBar}`);
1317
+ // Funds breakdown: BUY on left, SELL on right (right-aligned within its column)
1318
+ const buyValueStr = `${formatFundsValue(analysis.funds.buy.bts)} ${bSymbol}`;
1319
+ const sellValueStr = `${formatFundsValue(analysis.funds.sell.xrp)} ${aSymbol}`;
1320
+ const buyEquivStr = `ā‰ˆ ${formatFundsValue(analysis.funds.buy.xrp)} ${aSymbol}`;
1321
+ const sellEquivStr = `ā‰ˆ ${formatFundsValue(analysis.funds.sell.bts)} ${bSymbol}`;
1322
+ // Right column width is the maximum of sell value or sell equivalent
1323
+ const rightColWidth = Math.max(sellValueStr.length, sellEquivStr.length);
1324
+ // Right-align both sell strings within the right column width
1325
+ const sellValueRight = ' '.repeat(Math.max(0, rightColWidth - sellValueStr.length)) + sellValueStr;
1326
+ const sellEquivRight = ' '.repeat(Math.max(0, rightColWidth - sellEquivStr.length)) + sellEquivStr;
1327
+ // Build prefix strings and calculate their lengths
1328
+ const prefix1 = ` `;
1329
+ const prefix2 = ` `;
1330
+ const prefix1Len = prefix1.length;
1331
+ const prefix2Len = prefix2.length;
1332
+ // Calculate spacing to match the Slots line width (prefix + bar width)
1333
+ // This ensures funds breakdown lines align with the visual bar width
1334
+ const barLinePrefix = ` Funds: `;
1335
+ const targetWidth = barLinePrefix.length + BAR_WIDTH;
1336
+ // Spacing for each line: targetWidth - line prefix - buyValue - sellColumn
1337
+ const spacing1 = Math.max(2, targetWidth - prefix1Len - buyValueStr.length - rightColWidth);
1338
+ const spacing2 = Math.max(2, targetWidth - prefix2Len - buyEquivStr.length - rightColWidth);
1339
+ lines.push(`${prefix1}${colors.buy}${buyValueStr}${colors.reset}${' '.repeat(spacing1)}${colors.sell}${sellValueRight}${colors.reset}`);
1340
+ lines.push(`${prefix2}${buyEquivStr}${' '.repeat(spacing2)}${sellEquivRight}`);
1341
+ // Align pipe separators across all lines so every | sits at the same column
1342
+ let maxPipePos = 0;
1343
+ const pipeLines = [];
1344
+ for (let i = 0; i < lines.length; i++) {
1345
+ const pipeIdx = lines[i].indexOf('|');
1346
+ if (pipeIdx !== -1) {
1347
+ pipeLines.push(i);
1348
+ const visualLen = stripColorCodes(lines[i].substring(0, pipeIdx)).length;
1349
+ if (visualLen > maxPipePos)
1350
+ maxPipePos = visualLen;
1351
+ }
1352
+ }
1353
+ for (const idx of pipeLines) {
1354
+ const pipeIdx = lines[idx].indexOf('|');
1355
+ const visualLen = stripColorCodes(lines[idx].substring(0, pipeIdx)).length;
1356
+ if (visualLen < maxPipePos) {
1357
+ lines[idx] = lines[idx].substring(0, pipeIdx) + ' '.repeat(maxPipePos - visualLen) + lines[idx].substring(pipeIdx);
1358
+ }
1359
+ }
1360
+ return lines.join('\n');
1361
+ }
1362
+ /**
1363
+ * main: Entry point - analyze all order files and display results
1364
+ *
1365
+ * Flow:
1366
+ * 1. Get all order files from profiles/orders/ (sorted by modified date)
1367
+ * 2. For each file:
1368
+ * - Parse order data JSON
1369
+ * - Look up bot configuration from profiles/bots.json
1370
+ * - Perform comprehensive analysis
1371
+ * - Format and display results
1372
+ * 3. Handle errors gracefully (skip bad files, continue)
1373
+ * 4. Print summary statistics
1374
+ *
1375
+ * Error handling:
1376
+ * - Invalid JSON: Catch and skip file with error message
1377
+ * - Missing config: Display grid data only (no target comparisons)
1378
+ * - Empty orders directory: Display message and exit
1379
+ *
1380
+ * Output order: Files sorted by modification time (most recent first)
1381
+ * makes it easy to see which bots were most recently updated
1382
+ */
1383
+ /**
1384
+ * generateHtmlReport: Export all analyses as a standalone HTML report.
1385
+ *
1386
+ * Produces a self-contained HTML file with visually styled cards, colored
1387
+ * distribution bars, and aligned metrics — matching the terminal output's
1388
+ * information density in a browser-friendly format.
1389
+ *
1390
+ * @param {Array<Object>} analyses - Array of analysis results from analyzeOrder()
1391
+ */
1392
+ function generateHtmlReport(analyses) {
1393
+ const cssColors = {
1394
+ buy: '#00ff00',
1395
+ buyDark: '#007700',
1396
+ sell: '#ff0000',
1397
+ sellDark: '#990000',
1398
+ spread: '#ffff00',
1399
+ cyan: '#5fffff',
1400
+ gray: '#949494'
1401
+ };
1402
+ const htmlColorMap = {
1403
+ [colors.buy]: `<span style="color:${cssColors.buy}">`,
1404
+ [colors.sell]: `<span style="color:${cssColors.sell}">`,
1405
+ [colors.buyDark]: `<span style="color:${cssColors.buyDark}">`,
1406
+ [colors.sellDark]: `<span style="color:${cssColors.sellDark}">`,
1407
+ [colors.spread]: `<span style="color:${cssColors.spread}">`,
1408
+ [colors.cyan]: `<span style="color:${cssColors.cyan}">`,
1409
+ [colors.gray]: `<span style="color:${cssColors.gray}">`,
1410
+ '\x1b[97m': '<span style="color:#ffffff">' // white for spread bar
1411
+ };
1412
+ function ansiToHtml(str) {
1413
+ let escaped = String(str)
1414
+ .replace(/&/g, '&amp;')
1415
+ .replace(/</g, '&lt;')
1416
+ .replace(/>/g, '&gt;')
1417
+ .replace(/"/g, '&quot;');
1418
+ let colorOpen = false;
1419
+ return escaped.replace(/\x1b\[[0-9;]*m/g, code => {
1420
+ let close = '';
1421
+ if (colorOpen) {
1422
+ colorOpen = false;
1423
+ close = '</span>';
1424
+ }
1425
+ if (code === colors.reset)
1426
+ return close;
1427
+ const html = htmlColorMap[code];
1428
+ if (!html)
1429
+ return close;
1430
+ colorOpen = true;
1431
+ return close + html;
1432
+ }) + (colorOpen ? '</span>' : '');
1433
+ }
1434
+ const reports = analyses.map(a => ansiToHtml(formatAnalysis(a))).join('\n');
1435
+ const html = `<!DOCTYPE html>
1436
+ <html lang="en">
1437
+ <head>
1438
+ <meta charset="UTF-8">
1439
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
1440
+ <meta name="darkreader-lock">
1441
+ <title>Order Analysis Report</title>
1442
+ <style>
1443
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
1444
+ body { background: #0d1117; color: #c9d1d9; font-family: -apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif; padding: 24px; }
1445
+ h1 { color: ${cssColors.cyan}; font-size: 20px; margin-bottom: 8px; }
1446
+ .subtitle { color: ${cssColors.gray}; font-size: 13px; margin-bottom: 24px; }
1447
+ .summary { margin-top: 16px; color: ${cssColors.cyan}; font-size: 13px; }
1448
+ pre {
1449
+ font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
1450
+ font-size: 14px;
1451
+ line-height: 1.5;
1452
+ background: #000;
1453
+ padding: 16px;
1454
+ border-radius: 8px;
1455
+ border: 1px solid #30363d;
1456
+ overflow-x: auto;
1457
+ }
1458
+ </style>
1459
+ </head>
1460
+ <body>
1461
+ <h1>šŸ” Order Analysis</h1>
1462
+ <div class="subtitle">${analyses.length} bot${analyses.length !== 1 ? 's' : ''} analyzed — ${new Date().toLocaleString()}</div>
1463
+ <pre>${reports}</pre>
1464
+ <div class="summary">Total: ${analyses.length} analyzed</div>
1465
+ </body>
1466
+ </html>`;
1467
+ const outPath = path.resolve('order-analysis.html');
1468
+ fs.writeFileSync(outPath, html, 'utf-8');
1469
+ console.log(`\nšŸ“„ Order Analysis: ${'./' + path.relative(process.cwd(), outPath)}`);
1470
+ }
1471
+ function main() {
1472
+ const exportHtml = process.argv.includes('--export');
1473
+ if (!exportHtml) {
1474
+ console.log(`\n${colors.cyan}šŸ” Order Analysis${colors.reset}`);
1475
+ console.log(`${colors.cyan}${'='.repeat(HEADER_WIDTH)}${colors.reset}`);
1476
+ }
1477
+ // Get all order files sorted by modification time (newest first)
1478
+ const { files, skippedCandidates } = getOrderFiles();
1479
+ // Handle fully empty directory case. If files were skipped, report why below.
1480
+ if (files.length === 0 && skippedCandidates.length === 0) {
1481
+ if (!exportHtml) {
1482
+ console.log('No order files found in profiles/orders/');
1483
+ }
1484
+ process.exit(0);
1485
+ }
1486
+ // Counters for summary statistics
1487
+ let analyzed = 0;
1488
+ let skipped = 0;
1489
+ const analyses = [];
1490
+ /**
1491
+ * Process each order file
1492
+ * Try-catch ensures one bad file doesn't stop analysis of others
1493
+ */
1494
+ files.forEach((file, index) => {
1495
+ try {
1496
+ // Parse order file JSON
1497
+ const orderData = readJSON(file.path);
1498
+ // Per-bot file: data is the bot's entry directly (no bots wrapper)
1499
+ if (!orderData || !orderData.meta || !Array.isArray(orderData.grid)) {
1500
+ throw new Error('Not a persisted order grid');
1501
+ }
1502
+ const botKey = file.botKey;
1503
+ const botData = orderData;
1504
+ // Candidate validation already required a configured bot entry.
1505
+ const config = file.config || getConfiguredBotConfig(botKey, botData);
1506
+ if (!config) {
1507
+ throw new Error(`Missing configured bot entry for ${botKey}`);
1508
+ }
1509
+ // Analyze the order grid (botKey is used to load the dynamic grid snapshot)
1510
+ const analysis = analyzeOrder(botData, config, botKey);
1511
+ analyses.push(analysis);
1512
+ if (!exportHtml) {
1513
+ // Display formatted results
1514
+ let output = formatAnalysis(analysis);
1515
+ // Remove leading newline from first pair to avoid blank line after header
1516
+ if (index === 0) {
1517
+ output = output.replace(/^\n/, '');
1518
+ console.log(output);
1519
+ console.log(''); // Extra blank line after first batch
1520
+ }
1521
+ else {
1522
+ console.log(output);
1523
+ }
1524
+ }
1525
+ analyzed++;
1526
+ }
1527
+ catch (error) {
1528
+ // Log error but continue processing other files
1529
+ console.error(`\nāŒ Error processing ${file.name}: ${error.message}`);
1530
+ skipped++;
1531
+ }
1532
+ });
1533
+ if (exportHtml) {
1534
+ generateHtmlReport(analyses);
1535
+ return;
1536
+ }
1537
+ if (skippedCandidates.length > 0) {
1538
+ console.log('');
1539
+ console.log(`${colors.cyan}${'='.repeat(HEADER_WIDTH)}${colors.reset}`);
1540
+ skippedCandidates.forEach(candidate => {
1541
+ console.log(`${colors.gray}Skipped ${candidate.name}: ${candidate.reason}${colors.reset}`);
1542
+ skipped++;
1543
+ });
1544
+ }
1545
+ // Summary line
1546
+ console.log(`${colors.cyan}${'='.repeat(HEADER_WIDTH)}${colors.reset}`);
1547
+ console.log(`${colors.cyan}Summary: ${analyzed} analyzed, ${skipped} skipped${colors.reset}\n`);
1548
+ }
1549
+ // Execute analysis only when invoked as a script. When required from a test we
1550
+ // expose the helpers below without triggering the analyzer side effects.
1551
+ if (require.main === module) {
1552
+ main();
1553
+ }
1554
+ module.exports = {
1555
+ resolveAmaKey,
1556
+ isAmaGridPrice,
1557
+ readDynamicGridSnapshot,
1558
+ buildDynamicWeightInfo,
1559
+ formatWeightLine,
1560
+ getRawWeightValues,
1561
+ analyzeOrder,
1562
+ formatAnalysis,
1563
+ generateHtmlReport,
1564
+ colors,
1565
+ DYNAMIC_GRID_SNAPSHOT_MAX_AGE_MS,
1566
+ DYNAMIC_WEIGHT_EPSILON,
1567
+ };
1568
+ //# sourceMappingURL=analyze-orders.js.map