dexbot 1.5.2 → 1.6.0

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 (240) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/README.md +4 -3
  3. package/analysis/README.md +1 -2
  4. package/analysis/ama_fitting/fetch_lp_candles.ts +1 -9
  5. package/analysis/ama_fitting/package.json +1 -1
  6. package/analysis/analyze_derivatives.ts +1 -1
  7. package/analysis/bot_usage/discover_bot_accounts.ts +12 -6
  8. package/analysis/resolve_source.ts +11 -1
  9. package/analysis/results/ama_sweep_results_lp_pool_133_1h.json +2455 -0
  10. package/analysis/results/bot_fitting_results_lp_pool_133_1h.json +218 -0
  11. package/analysis/tradingview/README.md +32 -10
  12. package/analysis/tradingview/analyze_tradingview.ts +118 -3
  13. package/analysis/tradingview/h-bts_tradingview.html +1570 -0
  14. package/analysis/tradingview/t-bts_tradingview.html +1570 -0
  15. package/analysis/tradingview/tradingview_uplot_chart_generator.ts +1392 -125
  16. package/analysis/trend_detection/package.json +1 -1
  17. package/claw/docs/DEXBOT2_TUNING_CHEAT_SHEET.md +1 -1
  18. package/claw/modules/dexbot_profiles.ts +22 -2
  19. package/claw/package.json +1 -1
  20. package/claw/runtimes/openclaw-plugin/openclaw.plugin.json +1 -1
  21. package/claw/runtimes/openclaw-plugin/package.json +1 -1
  22. package/claw/skills/launcher-ops/references/launcher-workflow.md +1 -1
  23. package/claw/tests/test_claw_mcp_transport.ts +2 -2
  24. package/claw/tests/test_dexbot_profiles.ts +65 -0
  25. package/dist/analysis/ama_fitting/fetch_lp_candles.js +1 -9
  26. package/dist/analysis/ama_fitting/fetch_lp_candles.js.map +1 -1
  27. package/dist/analysis/analyze_derivatives.js +1 -1
  28. package/dist/analysis/bot_usage/discover_bot_accounts.js +11 -6
  29. package/dist/analysis/bot_usage/discover_bot_accounts.js.map +1 -1
  30. package/dist/analysis/bot_usage/kibana_bot_queries.d.ts +2 -0
  31. package/dist/analysis/bot_usage/kibana_bot_queries.d.ts.map +1 -1
  32. package/dist/analysis/resolve_source.d.ts +1 -0
  33. package/dist/analysis/resolve_source.d.ts.map +1 -1
  34. package/dist/analysis/resolve_source.js +8 -1
  35. package/dist/analysis/resolve_source.js.map +1 -1
  36. package/dist/analysis/tradingview/analyze_tradingview.d.ts +8 -0
  37. package/dist/analysis/tradingview/analyze_tradingview.d.ts.map +1 -1
  38. package/dist/analysis/tradingview/analyze_tradingview.js +137 -3
  39. package/dist/analysis/tradingview/analyze_tradingview.js.map +1 -1
  40. package/dist/analysis/tradingview/tradingview_uplot_chart_generator.d.ts +5 -1
  41. package/dist/analysis/tradingview/tradingview_uplot_chart_generator.d.ts.map +1 -1
  42. package/dist/analysis/tradingview/tradingview_uplot_chart_generator.js +1387 -125
  43. package/dist/analysis/tradingview/tradingview_uplot_chart_generator.js.map +1 -1
  44. package/dist/bot.js +1 -1
  45. package/dist/bot.js.map +1 -1
  46. package/dist/dexbot.js +3 -3
  47. package/dist/dexbot.js.map +1 -1
  48. package/dist/market_adapter/ama_signal_runner.js +2 -2
  49. package/dist/market_adapter/candle_utils.d.ts +6 -0
  50. package/dist/market_adapter/candle_utils.d.ts.map +1 -1
  51. package/dist/market_adapter/candle_utils.js +6 -0
  52. package/dist/market_adapter/candle_utils.js.map +1 -1
  53. package/dist/market_adapter/core/asymmetric_bounds.d.ts +33 -1
  54. package/dist/market_adapter/core/asymmetric_bounds.d.ts.map +1 -1
  55. package/dist/market_adapter/core/asymmetric_bounds.js +38 -1
  56. package/dist/market_adapter/core/asymmetric_bounds.js.map +1 -1
  57. package/dist/market_adapter/core/kibana_candles.d.ts +17 -1
  58. package/dist/market_adapter/core/kibana_candles.d.ts.map +1 -1
  59. package/dist/market_adapter/core/kibana_candles.js +101 -19
  60. package/dist/market_adapter/core/kibana_candles.js.map +1 -1
  61. package/dist/market_adapter/core/kibana_client.d.ts +2 -0
  62. package/dist/market_adapter/core/kibana_client.d.ts.map +1 -1
  63. package/dist/market_adapter/core/kibana_client.js +31 -4
  64. package/dist/market_adapter/core/kibana_client.js.map +1 -1
  65. package/dist/market_adapter/core/market_adapter_service.d.ts.map +1 -1
  66. package/dist/market_adapter/core/market_adapter_service.js +0 -6
  67. package/dist/market_adapter/core/market_adapter_service.js.map +1 -1
  68. package/dist/market_adapter/inputs/fetch_book_data.d.ts +14 -0
  69. package/dist/market_adapter/inputs/fetch_book_data.d.ts.map +1 -0
  70. package/dist/market_adapter/inputs/fetch_book_data.js +138 -0
  71. package/dist/market_adapter/inputs/fetch_book_data.js.map +1 -0
  72. package/dist/market_adapter/inputs/fetch_cex_synthetic_data.js +1 -1
  73. package/dist/market_adapter/inputs/fetch_lp_data.d.ts +16 -2
  74. package/dist/market_adapter/inputs/fetch_lp_data.d.ts.map +1 -1
  75. package/dist/market_adapter/inputs/fetch_lp_data.js +109 -281
  76. package/dist/market_adapter/inputs/fetch_lp_data.js.map +1 -1
  77. package/dist/market_adapter/inputs/kibana_feed_source.d.ts +87 -0
  78. package/dist/market_adapter/inputs/kibana_feed_source.d.ts.map +1 -0
  79. package/dist/market_adapter/inputs/kibana_feed_source.js +570 -0
  80. package/dist/market_adapter/inputs/kibana_feed_source.js.map +1 -0
  81. package/dist/market_adapter/inputs/kibana_source.d.ts.map +1 -1
  82. package/dist/market_adapter/inputs/kibana_source.js +10 -5
  83. package/dist/market_adapter/inputs/kibana_source.js.map +1 -1
  84. package/dist/market_adapter/inputs/window_cache.d.ts +166 -0
  85. package/dist/market_adapter/inputs/window_cache.d.ts.map +1 -0
  86. package/dist/market_adapter/inputs/window_cache.js +500 -0
  87. package/dist/market_adapter/inputs/window_cache.js.map +1 -0
  88. package/dist/market_adapter/interval_utils.d.ts +8 -1
  89. package/dist/market_adapter/interval_utils.d.ts.map +1 -1
  90. package/dist/market_adapter/interval_utils.js +14 -1
  91. package/dist/market_adapter/interval_utils.js.map +1 -1
  92. package/dist/modules/account_bots.d.ts +1 -0
  93. package/dist/modules/account_bots.d.ts.map +1 -1
  94. package/dist/modules/account_bots.js +21 -5
  95. package/dist/modules/account_bots.js.map +1 -1
  96. package/dist/modules/account_orders.d.ts +25 -4
  97. package/dist/modules/account_orders.d.ts.map +1 -1
  98. package/dist/modules/account_orders.js +67 -4
  99. package/dist/modules/account_orders.js.map +1 -1
  100. package/dist/modules/bitshares-native/chain_client.d.ts +2 -0
  101. package/dist/modules/bitshares-native/chain_client.d.ts.map +1 -1
  102. package/dist/modules/bitshares-native/chain_client.js +3 -1
  103. package/dist/modules/bitshares-native/chain_client.js.map +1 -1
  104. package/dist/modules/bitshares-native/subscriptions.d.ts.map +1 -1
  105. package/dist/modules/bitshares-native/subscriptions.js +13 -3
  106. package/dist/modules/bitshares-native/subscriptions.js.map +1 -1
  107. package/dist/modules/bitshares-native/transport.d.ts +2 -0
  108. package/dist/modules/bitshares-native/transport.d.ts.map +1 -1
  109. package/dist/modules/bitshares-native/transport.js +122 -28
  110. package/dist/modules/bitshares-native/transport.js.map +1 -1
  111. package/dist/modules/bitshares_client.d.ts.map +1 -1
  112. package/dist/modules/bitshares_client.js +59 -8
  113. package/dist/modules/bitshares_client.js.map +1 -1
  114. package/dist/modules/bot_settings.d.ts.map +1 -1
  115. package/dist/modules/bot_settings.js +11 -0
  116. package/dist/modules/bot_settings.js.map +1 -1
  117. package/dist/modules/constants.d.ts +13 -0
  118. package/dist/modules/constants.d.ts.map +1 -1
  119. package/dist/modules/constants.js +68 -4
  120. package/dist/modules/constants.js.map +1 -1
  121. package/dist/modules/dexbot_class.d.ts +10 -18
  122. package/dist/modules/dexbot_class.d.ts.map +1 -1
  123. package/dist/modules/dexbot_class.js +57 -2
  124. package/dist/modules/dexbot_class.js.map +1 -1
  125. package/dist/modules/dexbot_cow_runtime.d.ts +62 -37
  126. package/dist/modules/dexbot_cow_runtime.d.ts.map +1 -1
  127. package/dist/modules/dexbot_cow_runtime.js +797 -569
  128. package/dist/modules/dexbot_cow_runtime.js.map +1 -1
  129. package/dist/modules/dexbot_fill_runtime.d.ts +41 -1
  130. package/dist/modules/dexbot_fill_runtime.d.ts.map +1 -1
  131. package/dist/modules/dexbot_fill_runtime.js +135 -5
  132. package/dist/modules/dexbot_fill_runtime.js.map +1 -1
  133. package/dist/modules/dexbot_maintenance_runtime.d.ts +79 -12
  134. package/dist/modules/dexbot_maintenance_runtime.d.ts.map +1 -1
  135. package/dist/modules/dexbot_maintenance_runtime.js +585 -97
  136. package/dist/modules/dexbot_maintenance_runtime.js.map +1 -1
  137. package/dist/modules/dexbot_startup_runtime.d.ts.map +1 -1
  138. package/dist/modules/dexbot_startup_runtime.js +13 -0
  139. package/dist/modules/dexbot_startup_runtime.js.map +1 -1
  140. package/dist/modules/dexbot_state_recovery.d.ts +15 -1
  141. package/dist/modules/dexbot_state_recovery.d.ts.map +1 -1
  142. package/dist/modules/dexbot_state_recovery.js +36 -7
  143. package/dist/modules/dexbot_state_recovery.js.map +1 -1
  144. package/dist/modules/fund_registry.d.ts +1 -1
  145. package/dist/modules/fund_registry.js +1 -1
  146. package/dist/modules/node_connect_policy.d.ts +52 -0
  147. package/dist/modules/node_connect_policy.d.ts.map +1 -0
  148. package/dist/modules/node_connect_policy.js +35 -0
  149. package/dist/modules/node_connect_policy.js.map +1 -0
  150. package/dist/modules/node_manager.d.ts +32 -0
  151. package/dist/modules/node_manager.d.ts.map +1 -1
  152. package/dist/modules/node_manager.js +76 -9
  153. package/dist/modules/node_manager.js.map +1 -1
  154. package/dist/modules/order/accounting.d.ts +30 -0
  155. package/dist/modules/order/accounting.d.ts.map +1 -1
  156. package/dist/modules/order/accounting.js +176 -3
  157. package/dist/modules/order/accounting.js.map +1 -1
  158. package/dist/modules/order/export.d.ts.map +1 -1
  159. package/dist/modules/order/export.js +1 -0
  160. package/dist/modules/order/export.js.map +1 -1
  161. package/dist/modules/order/grid.d.ts.map +1 -1
  162. package/dist/modules/order/grid.js +170 -51
  163. package/dist/modules/order/grid.js.map +1 -1
  164. package/dist/modules/order/grid_reconcile.d.ts.map +1 -1
  165. package/dist/modules/order/grid_reconcile.js +5 -3
  166. package/dist/modules/order/grid_reconcile.js.map +1 -1
  167. package/dist/modules/order/grid_reconcile_internal.d.ts.map +1 -1
  168. package/dist/modules/order/grid_reconcile_internal.js +182 -6
  169. package/dist/modules/order/grid_reconcile_internal.js.map +1 -1
  170. package/dist/modules/order/manager.d.ts +66 -3
  171. package/dist/modules/order/manager.d.ts.map +1 -1
  172. package/dist/modules/order/manager.js +238 -12
  173. package/dist/modules/order/manager.js.map +1 -1
  174. package/dist/modules/order/strategy.d.ts +3 -0
  175. package/dist/modules/order/strategy.d.ts.map +1 -1
  176. package/dist/modules/order/strategy.js +79 -7
  177. package/dist/modules/order/strategy.js.map +1 -1
  178. package/dist/modules/order/sync_engine.d.ts.map +1 -1
  179. package/dist/modules/order/sync_engine.js +90 -1
  180. package/dist/modules/order/sync_engine.js.map +1 -1
  181. package/dist/modules/order/utils/math.d.ts +20 -12
  182. package/dist/modules/order/utils/math.d.ts.map +1 -1
  183. package/dist/modules/order/utils/math.js +33 -12
  184. package/dist/modules/order/utils/math.js.map +1 -1
  185. package/dist/modules/order/utils/order.d.ts +308 -28
  186. package/dist/modules/order/utils/order.d.ts.map +1 -1
  187. package/dist/modules/order/utils/order.js +862 -38
  188. package/dist/modules/order/utils/order.js.map +1 -1
  189. package/dist/modules/order/utils/system.d.ts +37 -30
  190. package/dist/modules/order/utils/system.d.ts.map +1 -1
  191. package/dist/modules/order/utils/system.js +130 -101
  192. package/dist/modules/order/utils/system.js.map +1 -1
  193. package/dist/modules/order/utils/validate.d.ts +3 -2
  194. package/dist/modules/order/utils/validate.d.ts.map +1 -1
  195. package/dist/modules/order/utils/validate.js +11 -3
  196. package/dist/modules/order/utils/validate.js.map +1 -1
  197. package/dist/modules/paths.d.ts +2 -0
  198. package/dist/modules/paths.d.ts.map +1 -1
  199. package/dist/modules/paths.js +1 -0
  200. package/dist/modules/paths.js.map +1 -1
  201. package/dist/modules/runtime_settings.d.ts +13 -0
  202. package/dist/modules/runtime_settings.d.ts.map +1 -1
  203. package/dist/modules/runtime_settings.js +20 -0
  204. package/dist/modules/runtime_settings.js.map +1 -1
  205. package/dist/modules/utils/errors.d.ts +16 -0
  206. package/dist/modules/utils/errors.d.ts.map +1 -1
  207. package/dist/modules/utils/errors.js +31 -0
  208. package/dist/modules/utils/errors.js.map +1 -1
  209. package/dist/pm2.js +7 -7
  210. package/dist/scripts/analyze-credit.d.ts.map +1 -1
  211. package/dist/scripts/analyze-credit.js +13 -3
  212. package/dist/scripts/analyze-credit.js.map +1 -1
  213. package/dist/scripts/analyze-orders.js +2 -2
  214. package/dist/scripts/analyze-orders.js.map +1 -1
  215. package/dist/scripts/diagnose-kibana-candles.d.ts.map +1 -1
  216. package/dist/scripts/diagnose-kibana-candles.js +0 -1
  217. package/dist/scripts/diagnose-kibana-candles.js.map +1 -1
  218. package/dist/scripts/test-credit-renewal.js +1 -1
  219. package/dist/scripts/test-credit-renewal.js.map +1 -1
  220. package/dist/scripts/tv.d.ts +24 -2
  221. package/dist/scripts/tv.d.ts.map +1 -1
  222. package/dist/scripts/tv.js +190 -65
  223. package/dist/scripts/tv.js.map +1 -1
  224. package/docs/BITSHARES_ONBOARDING.md +9 -2
  225. package/docs/COW_INVARIANTS.md +18 -1
  226. package/docs/DEXBOT_COMPARISON.md +3 -3
  227. package/docs/EVOLUTION.md +9 -7
  228. package/docs/FUND_MOVEMENT_AND_ACCOUNTING.md +21 -9
  229. package/docs/GRID_RECALCULATION.md +5 -6
  230. package/docs/GRID_RECONCILE.md +12 -2
  231. package/docs/MPA_CREDIT_USAGE.md +2 -2
  232. package/docs/README.md +5 -6
  233. package/docs/architecture.md +0 -58
  234. package/docs/developer_guide.md +2 -1
  235. package/docs/docker.md +1 -1
  236. package/market_adapter/README.md +4 -0
  237. package/modules/README.md +1 -1
  238. package/package.json +1 -1
  239. package/scripts/README.md +5 -3
  240. package/tests/README.md +2 -2
@@ -0,0 +1,218 @@
1
+ {
2
+ "meta": {
3
+ "generatedAt": "2026-08-26T15:40:53.423Z",
4
+ "dataPath": "market_adapter/data/lp/1_3_5537_1_3_0/lp_pool_133_1h.json",
5
+ "resultsPath": "analysis/ama_fitting/optimization_results_lp_pool_133_1h.json",
6
+ "candles": 26281,
7
+ "activeOrders": "all",
8
+ "feeRoundtripPct": 0.2,
9
+ "btsCreateFee": 0.4826,
10
+ "btsCancelFee": 0.00482,
11
+ "makerCreateFactor": 0.1,
12
+ "txFeePrice": 1,
13
+ "btsFeeCapital": 10000,
14
+ "search": {
15
+ "spreadValues": [
16
+ 2,
17
+ 4
18
+ ],
19
+ "incrementValues": [
20
+ 0.5,
21
+ 1
22
+ ],
23
+ "ratioValues": [
24
+ 2,
25
+ 3
26
+ ],
27
+ "minSpreadFactor": 2.1,
28
+ "repositionPct": 1,
29
+ "asymmetricBounds": false,
30
+ "combosPerAma": 8
31
+ },
32
+ "scoring": {
33
+ "baseScore": "totalNetCaptureAfterFeesPct * (fillEfficiency / 100)",
34
+ "gridModel": "persistent fixed chain prices (createOrderGrid port): master rail at sqrt(1±inc) offsets bounded by [center/ratio, center*ratio], gapSlots spread zone centered on center; prices never follow AMA after placement",
35
+ "spreadParam": "targetSpreadPercent for calculateGapSlots (floored at increment * MIN_SPREAD_FACTOR)",
36
+ "resetTriggers": "(A) AMA drift >= 1% from recorded center (ratchet) (trigger B gated off — asymmetricBounds whitelist)",
37
+ "gridPriceOffset": "disabled (asymmetricBounds whitelist)",
38
+ "repositionAccounting": "unfilled orders canceled + counted (incl armed refills/rebids); bought-and-held base carries across resets in a weighted-average-entry inventory pool (resync never market-sells); end-of-run inventory mark is informational and excluded from scoring",
39
+ "cycleEconomics": "slot rotation: filled buy re-offers one rail step up; that refill selling books ~increment% minus round-trip fee and the freed quote re-bids one step down; unlinked initial-grid sells only execute against held inventory at weighted-average entry (no shorting)",
40
+ "totalGrossCapturePct": "sum of realized per-rotation gross from actual fixed prices (linked rotations + inventory sales)",
41
+ "totalNetCapturePct": "realized gross - roundtrip fee per completed disposition; excludes the end-of-run inventory mark",
42
+ "btsFees": "every order placement (initial grid + armed refills/rebids) pays maker create (0.4826*0.1 BTS), every reset cancel pays 0.00482 BTS; btsFeePts = total BTS * txFeePrice / btsFeeCapital * 100 deducted from net before scoring",
43
+ "warmup": "getAmaWarmupBars(er, slow, 0, fast)",
44
+ "riskPenalty": "avgOpenDurationBars*1 + peakOpenOrders*2 + avgImbalance*1.2 + canceledOnReposition*0.15",
45
+ "finalScore": "baseScore - riskPenalty"
46
+ }
47
+ },
48
+ "results": [
49
+ {
50
+ "strategy": {
51
+ "id": "AMA1",
52
+ "name": "AMA1",
53
+ "er": 500,
54
+ "fast": 2,
55
+ "slow": 50
56
+ },
57
+ "best": {
58
+ "spreadPct": 4,
59
+ "incrementPct": 0.01,
60
+ "maxMinRatio": 2,
61
+ "touchedOrders": 17118,
62
+ "matchedPairs": 4463,
63
+ "cyclesTotal": 4463,
64
+ "rotationCount": 1911,
65
+ "inventorySaleCount": 2552,
66
+ "avgCyclesPerSlot": 32.81617647058823,
67
+ "fillEfficiency": 26.071971024652413,
68
+ "totalGrossCapturePct": 74380.64032509834,
69
+ "totalNetCapturePct": 73488.04032508115,
70
+ "btsFeePts": 73.45986739997919,
71
+ "btsFeesBts": 7345.986739997918,
72
+ "totalNetCaptureAfterFeesPct": 73414.58045768116,
73
+ "avgNetPerPair": 16.46606325903678,
74
+ "canceledOnReposition": 129640,
75
+ "repositionCount": 972,
76
+ "driftTriggerCount": 972,
77
+ "slopeTriggerCount": 0,
78
+ "inventoryUnits": 567,
79
+ "inventoryAvgEntry": 1480.717680275907,
80
+ "inventoryNetPts": -8250.559317877065,
81
+ "offsetAppliedCount": 0,
82
+ "avgOpenDurationBars": 7.108843537414966,
83
+ "peakOpenOrders": 136,
84
+ "avgImbalance": 4.6666405484818805,
85
+ "riskPenalty": 19730.708812195593,
86
+ "baseScore": 19140.628144796767,
87
+ "utilization": 67.06103580662854,
88
+ "score": -590.0806673988263
89
+ }
90
+ },
91
+ {
92
+ "strategy": {
93
+ "id": "AMA2",
94
+ "name": "AMA2",
95
+ "er": 500,
96
+ "fast": 2,
97
+ "slow": 50
98
+ },
99
+ "best": {
100
+ "spreadPct": 4,
101
+ "incrementPct": 0.01,
102
+ "maxMinRatio": 2,
103
+ "touchedOrders": 17118,
104
+ "matchedPairs": 4463,
105
+ "cyclesTotal": 4463,
106
+ "rotationCount": 1911,
107
+ "inventorySaleCount": 2552,
108
+ "avgCyclesPerSlot": 32.81617647058823,
109
+ "fillEfficiency": 26.071971024652413,
110
+ "totalGrossCapturePct": 74380.64032509834,
111
+ "totalNetCapturePct": 73488.04032508115,
112
+ "btsFeePts": 73.45986739997919,
113
+ "btsFeesBts": 7345.986739997918,
114
+ "totalNetCaptureAfterFeesPct": 73414.58045768116,
115
+ "avgNetPerPair": 16.46606325903678,
116
+ "canceledOnReposition": 129640,
117
+ "repositionCount": 972,
118
+ "driftTriggerCount": 972,
119
+ "slopeTriggerCount": 0,
120
+ "inventoryUnits": 567,
121
+ "inventoryAvgEntry": 1480.717680275907,
122
+ "inventoryNetPts": -8250.559317877065,
123
+ "offsetAppliedCount": 0,
124
+ "avgOpenDurationBars": 7.108843537414966,
125
+ "peakOpenOrders": 136,
126
+ "avgImbalance": 4.6666405484818805,
127
+ "riskPenalty": 19730.708812195593,
128
+ "baseScore": 19140.628144796767,
129
+ "utilization": 67.06103580662854,
130
+ "score": -590.0806673988263
131
+ }
132
+ },
133
+ {
134
+ "strategy": {
135
+ "id": "AMA3",
136
+ "name": "AMA3",
137
+ "er": 500,
138
+ "fast": 2,
139
+ "slow": 50
140
+ },
141
+ "best": {
142
+ "spreadPct": 4,
143
+ "incrementPct": 0.01,
144
+ "maxMinRatio": 2,
145
+ "touchedOrders": 17118,
146
+ "matchedPairs": 4463,
147
+ "cyclesTotal": 4463,
148
+ "rotationCount": 1911,
149
+ "inventorySaleCount": 2552,
150
+ "avgCyclesPerSlot": 32.81617647058823,
151
+ "fillEfficiency": 26.071971024652413,
152
+ "totalGrossCapturePct": 74380.64032509834,
153
+ "totalNetCapturePct": 73488.04032508115,
154
+ "btsFeePts": 73.45986739997919,
155
+ "btsFeesBts": 7345.986739997918,
156
+ "totalNetCaptureAfterFeesPct": 73414.58045768116,
157
+ "avgNetPerPair": 16.46606325903678,
158
+ "canceledOnReposition": 129640,
159
+ "repositionCount": 972,
160
+ "driftTriggerCount": 972,
161
+ "slopeTriggerCount": 0,
162
+ "inventoryUnits": 567,
163
+ "inventoryAvgEntry": 1480.717680275907,
164
+ "inventoryNetPts": -8250.559317877065,
165
+ "offsetAppliedCount": 0,
166
+ "avgOpenDurationBars": 7.108843537414966,
167
+ "peakOpenOrders": 136,
168
+ "avgImbalance": 4.6666405484818805,
169
+ "riskPenalty": 19730.708812195593,
170
+ "baseScore": 19140.628144796767,
171
+ "utilization": 67.06103580662854,
172
+ "score": -590.0806673988263
173
+ }
174
+ },
175
+ {
176
+ "strategy": {
177
+ "id": "AMA4",
178
+ "name": "AMA4",
179
+ "er": 500,
180
+ "fast": 2,
181
+ "slow": 50
182
+ },
183
+ "best": {
184
+ "spreadPct": 4,
185
+ "incrementPct": 0.01,
186
+ "maxMinRatio": 2,
187
+ "touchedOrders": 17118,
188
+ "matchedPairs": 4463,
189
+ "cyclesTotal": 4463,
190
+ "rotationCount": 1911,
191
+ "inventorySaleCount": 2552,
192
+ "avgCyclesPerSlot": 32.81617647058823,
193
+ "fillEfficiency": 26.071971024652413,
194
+ "totalGrossCapturePct": 74380.64032509834,
195
+ "totalNetCapturePct": 73488.04032508115,
196
+ "btsFeePts": 73.45986739997919,
197
+ "btsFeesBts": 7345.986739997918,
198
+ "totalNetCaptureAfterFeesPct": 73414.58045768116,
199
+ "avgNetPerPair": 16.46606325903678,
200
+ "canceledOnReposition": 129640,
201
+ "repositionCount": 972,
202
+ "driftTriggerCount": 972,
203
+ "slopeTriggerCount": 0,
204
+ "inventoryUnits": 567,
205
+ "inventoryAvgEntry": 1480.717680275907,
206
+ "inventoryNetPts": -8250.559317877065,
207
+ "offsetAppliedCount": 0,
208
+ "avgOpenDurationBars": 7.108843537414966,
209
+ "peakOpenOrders": 136,
210
+ "avgImbalance": 4.6666405484818805,
211
+ "riskPenalty": 19730.708812195593,
212
+ "baseScore": 19140.628144796767,
213
+ "utilization": 67.06103580662854,
214
+ "score": -590.0806673988263
215
+ }
216
+ }
217
+ ]
218
+ }
@@ -4,7 +4,7 @@ This exporter generates a standalone HTML chart in the `analysis/charts/` folder
4
4
 
5
5
  ## Recommended: `dexbot tv` (One Step)
6
6
 
7
- `dexbot tv` fetches the candles itself (chunked Kibana scans for pools, order-book fallback for pairs) and then renders through this exporter — no manual fetch/export steps needed:
7
+ `dexbot tv` fetches the candles itself (chunked Kibana scans: pools with order-book fallback for pairs) and then renders through this exporter — no manual fetch/export steps needed:
8
8
 
9
9
  ```bash
10
10
  # Bot chart with AMA overlay (bot key from profiles/bots.json, default: 3 months)
@@ -17,10 +17,14 @@ dexbot tv 1.19.133
17
17
  # Any pair (pool-first, order-book fallback)
18
18
  dexbot tv TOKENA/TOKENB
19
19
 
20
+ # MPA price-feed history instead of market candles (opt-in; MPA/MPA pairs
21
+ # cross both feeds into one quote, e.g. HONEST.USD/HONEST.EUR)
22
+ dexbot tv BTS/HONEST.USD --feed
23
+
20
24
  # Options
21
25
  dexbot tv <bot> --month 6 # months of 1h candles (default: 3)
22
26
  dexbot tv <bot> --chart analysis/charts/custom.html
23
- dexbot tv <bot> --scale linear # log (default) or linear
27
+ dexbot tv BTS/HONEST.USD --book # override: order-book fills instead of the pool
24
28
  ```
25
29
 
26
30
  Output: `analysis/charts/tv_<bot|pool_<id>|<a>_<b>>_1h_<N>m.html`, with a clickable `file://` link printed on completion. Unknown targets fail fast with the list of known bot keys.
@@ -33,9 +37,15 @@ The sections below cover manual usage (explicit candle files, direct runner flag
33
37
  - Candle timeframe buttons: `1h`, `4h`, `1d`, `1w`
34
38
  - Pair-orientation switcher for `A/B` and `B/A`
35
39
  - SMA overlay
36
- - AMA overlay with explicit `erPeriod`, `fastPeriod`, and `slowPeriod` inputs
40
+ - AMA preset buttons `1–4` (one-click AMA1–4, active preset highlighted); numeric inputs kept
41
+ - Bot-grid range highlight, off by default (the bot's min/max around AMA with live asymmetric tilt; red above AMA, green below)
42
+ - Range-scale switch: fit the price axis to the range band
37
43
  - VWMA overlay
38
- - Bottom volume panel
44
+ - Order overlay for bot charts (active grid buys/sells as dashed levels, reserve line at the lowest grid buy, ceiling line at the highest grid sell, spread label; pair-aware, toggle in-chart)
45
+ - Market panel (top-right): `SELL` / `Market` / `BUY` rows with distance-to-market %
46
+ - Range panel (bottom-right, smaller type): visible-window candle High/Low (red/green, mirroring the SELL/BUY badge)
47
+ - Volume badge (bottom-right of the volume chart, same small type): visible-window max volume, always with the currency suffix (`1.2M BTS`); click the badge, the legend `Vol` value, or the toolbar unit button to switch base/quote units (quote ≈ base × close, persisted per chart like the AMA settings; feed charts show publish counts and disable the switch)
48
+ - Bottom volume panel with `Volume` toggle and per-bar hover tooltip
39
49
  - Crosshair legend with current candle values
40
50
 
41
51
  ## Quick Start
@@ -153,7 +163,7 @@ market_adapter/data/lp/<pair>/lp_pool_<id>_<interval>.json
153
163
 
154
164
  | Flag | Description |
155
165
  |------|-------------|
156
- | `--bot <name>` | Bot name from `profiles/bots.json` (auto-resolves pool) |
166
+ | `--bot <bot>` | Bot name from `profiles/bots.json` (auto-resolves pool) |
157
167
  | `--pool <id>` | Manual mode, no blockchain needed (requires `--precA/--precB`) |
158
168
  | `--interval <1m\|5m\|15m\|30m\|1h\|2h\|4h\|6h\|12h\|1d\|1w>` | Candle bucket size (bare numbers = seconds, e.g. `1800` = 30m) |
159
169
  | `--lookback <N>h` | Hours back from now |
@@ -171,16 +181,24 @@ market_adapter/data/lp/<pair>/lp_pool_<id>_<interval>.json
171
181
  | `--bot-key <key>` | Bot key for `market_adapter` source | — |
172
182
  | `--chart <path>` | Output HTML file | `analysis/charts/tradingview_chart.html` |
173
183
  | `--title <text>` | Chart title | auto-generated from meta |
184
+ | `--price-scale <log\|linear>` | Price-axis scale | `log` |
174
185
  | `--sma-period <n>` | SMA period | `500` |
175
186
  | `--ama-er-period <n>` | AMA ER period | `781` |
176
187
  | `--ama-fast-period <n>` | AMA fast period | `5.2` |
177
188
  | `--ama-slow-period <n>` | AMA slow period | `83.6` |
178
- | `--price-scale <log\|linear>` | Price axis scale | `log` |
179
- | `--scale <log\|linear>` | Alias for `--price-scale` | `log` |
180
189
  | `--vwap-bars <n>` | Rolling VWMA window | `500` |
181
190
  | `--no-sma` | Disable SMA | — |
182
191
  | `--no-ama` | Disable AMA | — |
183
192
  | `--no-vwap` | Disable VWMA | — |
193
+ | `--range` | Enable range highlight (off by default; toggle in-chart) | off |
194
+ | `--no-range` | Disable range highlight | — |
195
+ | `--range-scale` | Range Scaling: size the band by AMA slope like the grid build + fit price axis to it | — |
196
+ | `--range-span <mult>` | x-range around AMA, 1.2–2 (default: bot grid setting) | bot grid |
197
+ | `--orders-file <path>` | Order-grid JSON override for the overlay (default: `profiles/orders/<botKey>.json`) | bot orders |
198
+ | `--no-orders` | Disable the order overlay (levels, reserve/ceiling lines, spread label) | — |
199
+ | `--update-marker-ts <sec>` | Draw an "updated from here" line at the given unix timestamp | — |
200
+ | `--update-marker-bars <n>` | Bar count shown in the update-marker tag (e.g. `(+12)`) | — |
201
+ | `--no-update-marker` | Suppress the update marker even when the candle file has stamped meta | — |
184
202
  | `--quiet` | Suppress progress logs | — |
185
203
 
186
204
  ## Notes
@@ -192,9 +210,13 @@ market_adapter/data/lp/<pair>/lp_pool_<id>_<interval>.json
192
210
  - VWMA is disabled by default.
193
211
  - AMA is auto-enabled when the bot has `gridPrice: "ama"` (or ama1-4), otherwise disabled by default.
194
212
  - The AMA controls start with the bot-specific AMA, then pair-specific entry from `profiles/market_profiles.json` when available, falling back to AMA3 values from `modules/constants.ts`.
195
- - The AMA `Reset` button restores the HTML defaults, not the browser-stored overrides.
196
- - The pair switcher inverts the candles client-side, so you can inspect both `A/B` and `B/A` views from one export.
197
- - Indicator, timeframe, and scale changes are persisted in browser `localStorage` for the generated HTML.
213
+ - The AMA preset buttons `1–4` select the AMA1–4 defaults (active preset highlighted); numeric inputs remain for fine-tuning.
214
+ - The pair switcher inverts the candles client-side, so you can inspect both `A/B` and `B/A` views from one export. The order overlay inverts with it (same levels in display units, side colors preserved).
215
+ - The order overlay resolves from `profiles/orders/<botKey>.json` (same files `scripts/analyze-orders.ts` reads): active/partial grid orders only. Pool/pair charts without a bot key render without it, silently. `--no-orders` removes the whole overlay (levels, reserve/ceiling lines, spread label); the in-chart `Orders` checkbox does the same when orders are present. Grid bounds span the full grid, never calculated: the reserve line sits on the lowest grid buy, the ceiling line on the highest grid sell — live (active/partial) and planned (virtual) slots alike; a missing side hides its line instead of drawing an invented level. Bounds render even when no live levels exist yet (levels, spread, and panel BUY/SELL rows need live orders).
216
+ - The update marker falls back to `prevUpdateLastCandleSec` / `prevUpdateNewBars` stamped in the candle-file `meta` when the flags are absent; those fields are written by external incremental-fetch tooling, not by anything in this repo.
217
+ - `Ctrl+0` (or `Cmd+0`) resets the time-axis zoom to the full dataset.
218
+ - Mouse: drag the candles to pan time + price (price drag sets a manual range); wheel zooms time, except over the price axis where it zooms price. Shift+wheel zooms price anywhere over the price pane (cursor-anchored). Dragging the price-axis gutter scales price, dragging the time-axis gutter scales the timeframe; double-click the price axis to return to autofit. While the price range is manual, timeframe moves no longer refit it.
219
+ - Indicator, timeframe, scale, and overlay-visibility changes are persisted in browser `localStorage` per pool/pair chart (`dexbot2-tradingview-uplot-v3:<pool>:<A>_<B>:<baseSecs|base>`); cursor sync between the price/volume panes uses a separate constant key.
198
220
  - The price axis defaults to log base `10`, with a toolbar switch for `Log` / `Linear`.
199
221
  - If you regenerate the HTML and then open it later, no CDN access is needed — `uPlot` is loaded from the vendored local copy at `analysis/uplot/`.
200
222
 
@@ -35,6 +35,14 @@ function parseArgs() {
35
35
  amaEnabled: boolean;
36
36
  vwapEnabled: boolean;
37
37
  vwapBars: number;
38
+ rangeEnabled: boolean;
39
+ rangeScaleEnabled: boolean;
40
+ rangeSpan: number | undefined;
41
+ ordersFile: string | null;
42
+ noOrders: boolean;
43
+ noUpdateMarker: boolean;
44
+ updateMarkerTsSec: number | null;
45
+ updateMarkerNewBars: number | null;
38
46
  quiet: boolean;
39
47
  listBots: boolean;
40
48
  } = {
@@ -50,6 +58,14 @@ function parseArgs() {
50
58
  amaEnabled: true,
51
59
  vwapEnabled: false,
52
60
  vwapBars: 500,
61
+ rangeEnabled: false,
62
+ rangeScaleEnabled: false,
63
+ rangeSpan: undefined,
64
+ ordersFile: null,
65
+ noOrders: false,
66
+ noUpdateMarker: false,
67
+ updateMarkerTsSec: null,
68
+ updateMarkerNewBars: null,
53
69
  quiet: false,
54
70
  listBots: false,
55
71
  };
@@ -72,7 +88,16 @@ function parseArgs() {
72
88
  else if (arg === '--no-sma') config.smaEnabled = false;
73
89
  else if (arg === '--no-ama') config.amaEnabled = false;
74
90
  else if (arg === '--no-vwap') config.vwapEnabled = false;
75
- else if (arg === '--vwap-bars') config.vwapBars = Math.max(24, parseInt(args[++i], 10) || 500);
91
+ else if (arg === '--vwap-bars') config.vwapBars = Math.max(5, parseInt(args[++i], 10) || 500);
92
+ else if (arg === '--range') config.rangeEnabled = true;
93
+ else if (arg === '--no-range') config.rangeEnabled = false;
94
+ else if (arg === '--range-scale') config.rangeScaleEnabled = true;
95
+ else if (arg === '--range-span') config.rangeSpan = parseFloat(args[++i]);
96
+ else if (arg === '--orders-file') config.ordersFile = String(args[++i] || '');
97
+ else if (arg === '--no-orders') config.noOrders = true;
98
+ else if (arg === '--no-update-marker') config.noUpdateMarker = true;
99
+ else if (arg === '--update-marker-ts') config.updateMarkerTsSec = Math.max(0, parseInt(args[++i], 10) || 0) || null;
100
+ else if (arg === '--update-marker-bars') config.updateMarkerNewBars = Math.max(0, parseInt(args[++i], 10) || 0) || null;
76
101
  else if (arg === '--list-bots') config.listBots = true;
77
102
  else if (arg === '--quiet') config.quiet = true;
78
103
  }
@@ -85,6 +110,61 @@ function loadJsonMeta(filePath: any) {
85
110
  return loadCandleFile(filePath);
86
111
  }
87
112
 
113
+ // ── Order overlay: live grid levels (buys/sells) + full-grid bounds ──
114
+ // Canonical source is profiles/orders/<botKey>.json (same files
115
+ // scripts/analyze-orders.ts reads); --orders-file overrides, --no-orders
116
+ // disables. Pool/pair charts without a bot key render without overlay,
117
+ // silently — no hardcoded personal paths.
118
+ function resolveOrdersFile(botKey: string | null | undefined, explicit: string | null | undefined, disabled: boolean): string | null {
119
+ if (disabled) return null;
120
+ if (explicit) {
121
+ try { if (fs.existsSync(explicit)) return explicit; } catch { /* fall through to warning */ }
122
+ console.warn(`[TradingView] --orders-file not found: ${explicit} (rendering without order overlay)`);
123
+ return null;
124
+ }
125
+ if (!botKey) return null;
126
+ try {
127
+ const ordersDir = (PATHS as any).ORDERS_DIR || path.join(path.dirname(PATHS.PROFILES.BOTS_JSON), 'orders');
128
+ const direct = path.join(ordersDir, `${botKey}.json`);
129
+ if (fs.existsSync(direct)) return direct;
130
+ } catch { /* silent when absent */ }
131
+ return null;
132
+ }
133
+
134
+ // Single-pass read of the order grid, like the runtime sees it: live
135
+ // (active/partial) levels for the overlay plus full-grid bounds (live +
136
+ // planned/virtual slots). Virtual slots carry the same slot geometry
137
+ // without an on-chain order, so excluding them would shrink the shown
138
+ // grid to the live extremes. Spread-type slots are neither buys nor
139
+ // sells and stay out of both.
140
+ function loadOrdersData(filePath: string | null): { buys: number[]; sells: number[]; low: number | null; high: number | null } {
141
+ if (!filePath) return { buys: [], sells: [], low: null, high: null };
142
+ try {
143
+ const od = JSON.parse(fs.readFileSync(filePath, 'utf8'));
144
+ const grid = Array.isArray(od?.grid) ? od.grid : (Array.isArray(od?.orders) ? od.orders : []);
145
+ const buys: number[] = [];
146
+ const sells: number[] = [];
147
+ let low: number | null = null;
148
+ let high: number | null = null;
149
+ for (const s of grid) {
150
+ const price = Number((s as any)?.price);
151
+ if (!Number.isFinite(price) || price <= 0) continue;
152
+ const st = (s as any)?.state;
153
+ if (st !== 'active' && st !== 'partial' && st !== 'virtual') continue;
154
+ if ((s as any)?.type === 'buy') {
155
+ if (low == null || price < low) low = price;
156
+ if (st !== 'virtual') buys.push(price);
157
+ } else if ((s as any)?.type === 'sell') {
158
+ if (high == null || price > high) high = price;
159
+ if (st !== 'virtual') sells.push(price);
160
+ }
161
+ }
162
+ buys.sort((a, b) => a - b);
163
+ sells.sort((a, b) => a - b);
164
+ return { buys, sells, low, high };
165
+ } catch { return { buys: [], sells: [], low: null, high: null }; }
166
+ }
167
+
88
168
  function inferTitle(meta: any, fallback: string) {
89
169
  const pool = meta?.pool ? `Pool ${String(meta.pool).replace(/^1\.19\./, '')}` : null;
90
170
  const a = meta?.assetA?.symbol || meta?.assetA?.id || null;
@@ -104,7 +184,7 @@ async function main() {
104
184
  return;
105
185
  }
106
186
 
107
- const { source, botKey, amaConfig } = resolveSource({ ...config.source.config, type: config.source.type }, { quiet: config.quiet });
187
+ const { source, botKey, amaConfig, meta: sourceMeta } = resolveSource({ ...config.source.config, type: config.source.type }, { quiet: config.quiet });
108
188
  if (!config.quiet) console.log(`[TradingView] Loading candles from ${source.name}...`);
109
189
 
110
190
  const candles = await source.fetchCandles();
@@ -116,7 +196,9 @@ async function main() {
116
196
  const filePath = config.source.config.filePath;
117
197
  const rawJson = isJsonSource ? loadJsonMeta(filePath) : { meta: null, candles: null };
118
198
  const botMeta = botKey ? loadBotMeta(botKey) : null;
119
- const jsonMeta = rawJson.meta || (botMeta ? {
199
+ // Prefer meta from the actual candle file (has pool + asset ids) over
200
+ // the bots.json fallback, which only knows the asset symbols.
201
+ const jsonMeta = rawJson.meta || sourceMeta || (botMeta ? {
120
202
  assetA: { symbol: botMeta.assetA },
121
203
  assetB: { symbol: botMeta.assetB },
122
204
  intervalSeconds: 3600,
@@ -125,6 +207,27 @@ async function main() {
125
207
  const hasAmaGridPrice = AMA_KEYWORDS.has(String(botMeta?.gridPrice || '').trim().toLowerCase());
126
208
  const amaEnabled = hasAmaGridPrice ? config.amaEnabled : false;
127
209
 
210
+ // Bot grid bounds for the range highlight: mirrors the runtime grid
211
+ // (center = AMA, min "Nx" = center/N, max "Nx" = center*N) with the
212
+ // live asymmetric tilt. Null when no bot key (width% fallback in-page).
213
+ const grid = botMeta?.minPrice != null && botMeta?.maxPrice != null ? {
214
+ minPrice: botMeta.minPrice,
215
+ maxPrice: botMeta.maxPrice,
216
+ incrementPercent: Number(botMeta.incrementPercent) > 0 ? Number(botMeta.incrementPercent) : null,
217
+ maxAsymmetryFactor: Number.isFinite(Number(botMeta?.asymmetricBounds?.maxAsymmetryFactor))
218
+ ? Number(botMeta.asymmetricBounds.maxAsymmetryFactor)
219
+ : null,
220
+ minScaleSlots: Number.isFinite(Number(botMeta?.asymmetricBounds?.minScaleSlots))
221
+ ? Number(botMeta.asymmetricBounds.minScaleSlots)
222
+ : null,
223
+ } : null;
224
+ // Order overlay (canonical profiles/orders/<botKey>.json; silent when absent)
225
+ const ordersFile = resolveOrdersFile(botKey, config.ordersFile, config.noOrders);
226
+ const ordersData = loadOrdersData(ordersFile);
227
+ const orderBuys = ordersData.buys;
228
+ const orderSells = ordersData.sells;
229
+ const gridBounds = { low: ordersData.low, high: ordersData.high };
230
+ if (!config.quiet && ordersFile) console.log(`[TradingView] Order overlay: ${orderBuys.length} buys + ${orderSells.length} sells from ${ordersFile}`);
128
231
  const html = generateHTML({
129
232
  candles,
130
233
  meta: jsonMeta || {
@@ -141,9 +244,21 @@ async function main() {
141
244
  amaEnabled,
142
245
  vwapEnabled: config.vwapEnabled,
143
246
  vwapBars: config.vwapBars,
247
+ rangeEnabled: config.rangeEnabled,
248
+ rangeScaleEnabled: config.rangeScaleEnabled,
249
+ rangeSpan: config.rangeSpan,
250
+ grid,
144
251
  priceScale: config.priceScale === 'linear' ? 'linear' : 'log',
145
252
  defaultTimeframe: '1h',
146
253
  marketAdapter: MARKET_ADAPTER,
254
+ orders: { buys: orderBuys, sells: orderSells },
255
+ gridBounds,
256
+ // Update marker ("updated from here" line): explicit CLI flags win,
257
+ // otherwise fall back to stamped data-file meta when present.
258
+ updateMarkerTsSec: config.noUpdateMarker ? null : (config.updateMarkerTsSec
259
+ ?? (Number((jsonMeta as any)?.prevUpdateLastCandleSec) > 0 ? Number((jsonMeta as any).prevUpdateLastCandleSec) : null)),
260
+ updateMarkerNewBars: config.noUpdateMarker ? null : (config.updateMarkerNewBars
261
+ ?? (Number((jsonMeta as any)?.prevUpdateNewBars) || null)),
147
262
  }, title);
148
263
 
149
264
  writeChartFile(config.chartFile, html);