dexbot 1.6.3 → 1.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (275) hide show
  1. package/CHANGELOG.md +78 -2
  2. package/README.md +23 -19
  3. package/analysis/README.md +26 -13
  4. package/analysis/account_resolver.ts +171 -0
  5. package/analysis/ama_fitting/analyze_lambda_vs_slow.ts +2 -5
  6. package/analysis/ama_fitting/package.json +1 -1
  7. package/analysis/analyze_dynamic_weight.ts +9 -3
  8. package/analysis/bot_usage/discover_bot_accounts.ts +20 -27
  9. package/analysis/chain_pool.ts +47 -0
  10. package/analysis/chart_utils.ts +33 -20
  11. package/analysis/derivative_chart_generator.ts +2 -3
  12. package/analysis/fills_source.ts +234 -0
  13. package/analysis/grid_correction_check.ts +38 -251
  14. package/analysis/trade_profitability.ts +169 -304
  15. package/analysis/tradingview/README.md +2 -2
  16. package/analysis/tradingview/analyze_tradingview.ts +5 -0
  17. package/analysis/tradingview/tradingview_uplot_chart_generator.ts +5 -6
  18. package/analysis/trend_detection/DYNAMIC_WEIGHT_RESEARCH.md +35 -2
  19. package/analysis/trend_detection/dynamic_weight_chart_generator.ts +84 -13
  20. package/analysis/trend_detection/kalman_chart_generator.ts +2 -3
  21. package/analysis/trend_detection/package.json +1 -1
  22. package/analysis/trend_detection/regime_chart_generator.ts +2 -3
  23. package/analysis/trend_detection/volatility_chart_generator.ts +2 -3
  24. package/claw/modules/dexbot_profiles.ts +4 -3
  25. package/claw/package.json +1 -1
  26. package/claw/runtimes/openclaw-plugin/openclaw.plugin.json +1 -1
  27. package/claw/runtimes/openclaw-plugin/package.json +1 -1
  28. package/claw/tests/test_claw_mcp_transport.ts +2 -2
  29. package/claw/tests/test_dexbot_profiles.ts +18 -1
  30. package/dist/analysis/account_resolver.d.ts +43 -0
  31. package/dist/analysis/account_resolver.d.ts.map +1 -0
  32. package/dist/analysis/account_resolver.js +137 -0
  33. package/dist/analysis/account_resolver.js.map +1 -0
  34. package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.d.ts.map +1 -1
  35. package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.js +2 -4
  36. package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.js.map +1 -1
  37. package/dist/analysis/analyze_dynamic_weight.js +9 -3
  38. package/dist/analysis/analyze_dynamic_weight.js.map +1 -1
  39. package/dist/analysis/bot_usage/discover_bot_accounts.js +20 -28
  40. package/dist/analysis/bot_usage/discover_bot_accounts.js.map +1 -1
  41. package/dist/analysis/chain_pool.d.ts +10 -0
  42. package/dist/analysis/chain_pool.d.ts.map +1 -0
  43. package/dist/analysis/chain_pool.js +47 -0
  44. package/dist/analysis/chain_pool.js.map +1 -0
  45. package/dist/analysis/chart_utils.d.ts +14 -1
  46. package/dist/analysis/chart_utils.d.ts.map +1 -1
  47. package/dist/analysis/chart_utils.js +32 -22
  48. package/dist/analysis/chart_utils.js.map +1 -1
  49. package/dist/analysis/derivative_chart_generator.d.ts.map +1 -1
  50. package/dist/analysis/derivative_chart_generator.js +2 -3
  51. package/dist/analysis/derivative_chart_generator.js.map +1 -1
  52. package/dist/analysis/fills_source.d.ts +79 -0
  53. package/dist/analysis/fills_source.d.ts.map +1 -0
  54. package/dist/analysis/fills_source.js +186 -0
  55. package/dist/analysis/fills_source.js.map +1 -0
  56. package/dist/analysis/grid_correction_check.d.ts +1 -21
  57. package/dist/analysis/grid_correction_check.d.ts.map +1 -1
  58. package/dist/analysis/grid_correction_check.js +30 -257
  59. package/dist/analysis/grid_correction_check.js.map +1 -1
  60. package/dist/analysis/trade_profitability.d.ts +18 -19
  61. package/dist/analysis/trade_profitability.d.ts.map +1 -1
  62. package/dist/analysis/trade_profitability.js +136 -280
  63. package/dist/analysis/trade_profitability.js.map +1 -1
  64. package/dist/analysis/tradingview/analyze_tradingview.d.ts.map +1 -1
  65. package/dist/analysis/tradingview/analyze_tradingview.js +5 -0
  66. package/dist/analysis/tradingview/analyze_tradingview.js.map +1 -1
  67. package/dist/analysis/tradingview/tradingview_uplot_chart_generator.d.ts.map +1 -1
  68. package/dist/analysis/tradingview/tradingview_uplot_chart_generator.js +5 -6
  69. package/dist/analysis/tradingview/tradingview_uplot_chart_generator.js.map +1 -1
  70. package/dist/analysis/trend_detection/dynamic_weight_chart_generator.d.ts.map +1 -1
  71. package/dist/analysis/trend_detection/dynamic_weight_chart_generator.js +84 -13
  72. package/dist/analysis/trend_detection/dynamic_weight_chart_generator.js.map +1 -1
  73. package/dist/analysis/trend_detection/kalman_chart_generator.d.ts.map +1 -1
  74. package/dist/analysis/trend_detection/kalman_chart_generator.js +2 -3
  75. package/dist/analysis/trend_detection/kalman_chart_generator.js.map +1 -1
  76. package/dist/analysis/trend_detection/regime_chart_generator.d.ts.map +1 -1
  77. package/dist/analysis/trend_detection/regime_chart_generator.js +2 -3
  78. package/dist/analysis/trend_detection/regime_chart_generator.js.map +1 -1
  79. package/dist/analysis/trend_detection/volatility_chart_generator.d.ts.map +1 -1
  80. package/dist/analysis/trend_detection/volatility_chart_generator.js +2 -3
  81. package/dist/analysis/trend_detection/volatility_chart_generator.js.map +1 -1
  82. package/dist/dexbot.d.ts.map +1 -1
  83. package/dist/dexbot.js +27 -68
  84. package/dist/dexbot.js.map +1 -1
  85. package/dist/market_adapter/core/asymmetric_bounds.d.ts +2 -2
  86. package/dist/market_adapter/core/asymmetric_bounds.d.ts.map +1 -1
  87. package/dist/market_adapter/core/asymmetric_bounds.js +15 -12
  88. package/dist/market_adapter/core/asymmetric_bounds.js.map +1 -1
  89. package/dist/market_adapter/interval_utils.d.ts +1 -1
  90. package/dist/market_adapter/interval_utils.js +1 -1
  91. package/dist/market_adapter/lp_chart_core.d.ts.map +1 -1
  92. package/dist/market_adapter/lp_chart_core.js +2 -3
  93. package/dist/market_adapter/lp_chart_core.js.map +1 -1
  94. package/dist/modules/account_bots.d.ts +51 -18
  95. package/dist/modules/account_bots.d.ts.map +1 -1
  96. package/dist/modules/account_bots.js +258 -117
  97. package/dist/modules/account_bots.js.map +1 -1
  98. package/dist/modules/bitshares-native/serial/operations.d.ts +1 -84
  99. package/dist/modules/bitshares-native/serial/operations.d.ts.map +1 -1
  100. package/dist/modules/bitshares-native/serial/operations.js +1 -38
  101. package/dist/modules/bitshares-native/serial/operations.js.map +1 -1
  102. package/dist/modules/bot_defaults.d.ts +98 -0
  103. package/dist/modules/bot_defaults.d.ts.map +1 -0
  104. package/dist/modules/bot_defaults.js +169 -0
  105. package/dist/modules/bot_defaults.js.map +1 -0
  106. package/dist/modules/bot_settings.d.ts.map +1 -1
  107. package/dist/modules/bot_settings.js +4 -1
  108. package/dist/modules/bot_settings.js.map +1 -1
  109. package/dist/modules/cli_colors.d.ts +0 -1
  110. package/dist/modules/cli_colors.d.ts.map +1 -1
  111. package/dist/modules/config.d.ts +1 -0
  112. package/dist/modules/config.d.ts.map +1 -1
  113. package/dist/modules/config.js +1 -0
  114. package/dist/modules/config.js.map +1 -1
  115. package/dist/modules/constants.d.ts +11 -2
  116. package/dist/modules/constants.d.ts.map +1 -1
  117. package/dist/modules/constants.js +45 -32
  118. package/dist/modules/constants.js.map +1 -1
  119. package/dist/modules/credential_policy.d.ts +1 -25
  120. package/dist/modules/credential_policy.d.ts.map +1 -1
  121. package/dist/modules/credential_policy.js +1 -1
  122. package/dist/modules/credential_policy.js.map +1 -1
  123. package/dist/modules/credential_runtime.d.ts +1 -6
  124. package/dist/modules/credential_runtime.d.ts.map +1 -1
  125. package/dist/modules/credential_runtime.js +1 -1
  126. package/dist/modules/credential_runtime.js.map +1 -1
  127. package/dist/modules/credential_session_cache.d.ts +1 -5
  128. package/dist/modules/credential_session_cache.d.ts.map +1 -1
  129. package/dist/modules/credential_session_cache.js +1 -1
  130. package/dist/modules/credential_session_cache.js.map +1 -1
  131. package/dist/modules/crypto/pure_secp256k1.d.ts +1 -2
  132. package/dist/modules/crypto/pure_secp256k1.d.ts.map +1 -1
  133. package/dist/modules/crypto/pure_secp256k1.js +1 -1
  134. package/dist/modules/crypto/pure_secp256k1.js.map +1 -1
  135. package/dist/modules/dexbot_class.d.ts +8 -7
  136. package/dist/modules/dexbot_class.d.ts.map +1 -1
  137. package/dist/modules/dexbot_class.js +9 -8
  138. package/dist/modules/dexbot_class.js.map +1 -1
  139. package/dist/modules/dexbot_cow_runtime.d.ts +7 -6
  140. package/dist/modules/dexbot_cow_runtime.d.ts.map +1 -1
  141. package/dist/modules/dexbot_cow_runtime.js +8 -7
  142. package/dist/modules/dexbot_cow_runtime.js.map +1 -1
  143. package/dist/modules/dexbot_fill_runtime.d.ts +1 -17
  144. package/dist/modules/dexbot_fill_runtime.d.ts.map +1 -1
  145. package/dist/modules/dexbot_fill_runtime.js +1 -1
  146. package/dist/modules/dexbot_fill_runtime.js.map +1 -1
  147. package/dist/modules/dexbot_maintenance_runtime.d.ts +2 -2
  148. package/dist/modules/dexbot_maintenance_runtime.d.ts.map +1 -1
  149. package/dist/modules/dexbot_maintenance_runtime.js +24 -8
  150. package/dist/modules/dexbot_maintenance_runtime.js.map +1 -1
  151. package/dist/modules/dexbot_state_recovery.d.ts +1 -7
  152. package/dist/modules/dexbot_state_recovery.d.ts.map +1 -1
  153. package/dist/modules/dexbot_state_recovery.js +1 -1
  154. package/dist/modules/dexbot_state_recovery.js.map +1 -1
  155. package/dist/modules/launcher/adapter_requirement.d.ts +1 -5
  156. package/dist/modules/launcher/adapter_requirement.d.ts.map +1 -1
  157. package/dist/modules/launcher/adapter_requirement.js +2 -2
  158. package/dist/modules/launcher/adapter_requirement.js.map +1 -1
  159. package/dist/modules/launcher/bot_supervisor.d.ts +1 -6
  160. package/dist/modules/launcher/bot_supervisor.d.ts.map +1 -1
  161. package/dist/modules/launcher/bot_supervisor.js +1 -1
  162. package/dist/modules/launcher/bot_supervisor.js.map +1 -1
  163. package/dist/modules/launcher/foreign_cred_daemon.d.ts +1 -3
  164. package/dist/modules/launcher/foreign_cred_daemon.d.ts.map +1 -1
  165. package/dist/modules/launcher/foreign_cred_daemon.js +1 -1
  166. package/dist/modules/launcher/foreign_cred_daemon.js.map +1 -1
  167. package/dist/modules/launcher/launch_modes.d.ts +17 -2
  168. package/dist/modules/launcher/launch_modes.d.ts.map +1 -1
  169. package/dist/modules/launcher/launch_modes.js +18 -1
  170. package/dist/modules/launcher/launch_modes.js.map +1 -1
  171. package/dist/modules/launcher/market_adapter_runtime.d.ts +1 -3
  172. package/dist/modules/launcher/market_adapter_runtime.d.ts.map +1 -1
  173. package/dist/modules/launcher/market_adapter_runtime.js +1 -1
  174. package/dist/modules/launcher/market_adapter_runtime.js.map +1 -1
  175. package/dist/modules/launcher/monolithic_runtime.d.ts +1 -5
  176. package/dist/modules/launcher/monolithic_runtime.d.ts.map +1 -1
  177. package/dist/modules/launcher/monolithic_runtime.js +9 -2
  178. package/dist/modules/launcher/monolithic_runtime.js.map +1 -1
  179. package/dist/modules/launcher/status_reporting.d.ts +1 -2
  180. package/dist/modules/launcher/status_reporting.d.ts.map +1 -1
  181. package/dist/modules/launcher/status_reporting.js +1 -1
  182. package/dist/modules/launcher/status_reporting.js.map +1 -1
  183. package/dist/modules/market_adapter_whitelist.d.ts +40 -1
  184. package/dist/modules/market_adapter_whitelist.d.ts.map +1 -1
  185. package/dist/modules/market_adapter_whitelist.js +161 -11
  186. package/dist/modules/market_adapter_whitelist.js.map +1 -1
  187. package/dist/modules/order/export.d.ts +1 -8
  188. package/dist/modules/order/export.d.ts.map +1 -1
  189. package/dist/modules/order/export.js +1 -1
  190. package/dist/modules/order/export.js.map +1 -1
  191. package/dist/modules/order/grid.d.ts +16 -0
  192. package/dist/modules/order/grid.d.ts.map +1 -1
  193. package/dist/modules/order/grid.js +75 -103
  194. package/dist/modules/order/grid.js.map +1 -1
  195. package/dist/modules/order/grid_reconcile_internal.d.ts +1 -10
  196. package/dist/modules/order/grid_reconcile_internal.d.ts.map +1 -1
  197. package/dist/modules/order/grid_reconcile_internal.js +2 -2
  198. package/dist/modules/order/grid_reconcile_internal.js.map +1 -1
  199. package/dist/modules/order/manager.d.ts +10 -2
  200. package/dist/modules/order/manager.d.ts.map +1 -1
  201. package/dist/modules/order/manager.js +20 -8
  202. package/dist/modules/order/manager.js.map +1 -1
  203. package/dist/modules/order/sync_engine.d.ts.map +1 -1
  204. package/dist/modules/order/sync_engine.js +8 -15
  205. package/dist/modules/order/sync_engine.js.map +1 -1
  206. package/dist/modules/order/utils/math.d.ts +1 -10
  207. package/dist/modules/order/utils/math.d.ts.map +1 -1
  208. package/dist/modules/order/utils/math.js +1 -1
  209. package/dist/modules/order/utils/math.js.map +1 -1
  210. package/dist/modules/order/utils/system.d.ts +5 -16
  211. package/dist/modules/order/utils/system.d.ts.map +1 -1
  212. package/dist/modules/order/utils/system.js +7 -4
  213. package/dist/modules/order/utils/system.js.map +1 -1
  214. package/dist/modules/process_discovery.d.ts +0 -3
  215. package/dist/modules/process_discovery.d.ts.map +1 -1
  216. package/dist/modules/process_discovery.js +1 -1
  217. package/dist/modules/process_discovery.js.map +1 -1
  218. package/dist/modules/settings_merge.d.ts +10 -1
  219. package/dist/modules/settings_merge.d.ts.map +1 -1
  220. package/dist/modules/settings_merge.js +27 -17
  221. package/dist/modules/settings_merge.js.map +1 -1
  222. package/dist/modules/utils/chain_logs.d.ts +1 -2
  223. package/dist/modules/utils/chain_logs.d.ts.map +1 -1
  224. package/dist/modules/utils/chain_logs.js +1 -1
  225. package/dist/modules/utils/chain_logs.js.map +1 -1
  226. package/dist/modules/validate_profiles.d.ts.map +1 -1
  227. package/dist/modules/validate_profiles.js +4 -3
  228. package/dist/modules/validate_profiles.js.map +1 -1
  229. package/dist/scripts/analyze-git.js +2 -2
  230. package/dist/scripts/analyze-git.js.map +1 -1
  231. package/dist/scripts/chart_command.d.ts +48 -0
  232. package/dist/scripts/chart_command.d.ts.map +1 -0
  233. package/dist/scripts/chart_command.js +504 -0
  234. package/dist/scripts/chart_command.js.map +1 -0
  235. package/dist/scripts/dw.d.ts +3 -0
  236. package/dist/scripts/dw.d.ts.map +1 -0
  237. package/dist/scripts/dw.js +30 -0
  238. package/dist/scripts/dw.js.map +1 -0
  239. package/dist/scripts/tv.d.ts +1 -31
  240. package/dist/scripts/tv.d.ts.map +1 -1
  241. package/dist/scripts/tv.js +10 -463
  242. package/dist/scripts/tv.js.map +1 -1
  243. package/dist/scripts/update.js +145 -93
  244. package/dist/scripts/update.js.map +1 -1
  245. package/dist/scripts/update_dist_freshness.d.ts +46 -0
  246. package/dist/scripts/update_dist_freshness.d.ts.map +1 -0
  247. package/dist/scripts/update_dist_freshness.js +115 -0
  248. package/dist/scripts/update_dist_freshness.js.map +1 -0
  249. package/dist/unlock.js +1 -1
  250. package/dist/unlock.js.map +1 -1
  251. package/docs/BITSHARES_ONBOARDING.md +117 -44
  252. package/docs/COPY_ON_WRITE_MASTER_PLAN.md +10 -207
  253. package/docs/COW_INVARIANTS.md +16 -10
  254. package/docs/DEXBOT_COMPARISON.md +3 -3
  255. package/docs/EVOLUTION.md +76 -30
  256. package/docs/FUND_MOVEMENT_AND_ACCOUNTING.md +9 -9
  257. package/docs/GRID_RECALCULATION.md +34 -30
  258. package/docs/GRID_RECONCILE.md +30 -27
  259. package/docs/LIFECYCLE.md +12 -11
  260. package/docs/LOGGING.md +1 -0
  261. package/docs/README.md +58 -52
  262. package/docs/WORKFLOW.md +1 -2
  263. package/docs/architecture.md +21 -32
  264. package/docs/developer_guide.md +4 -3
  265. package/market_adapter/README.md +36 -60
  266. package/modules/README.md +2 -1
  267. package/package.json +1 -2
  268. package/scripts/README.md +18 -25
  269. package/scripts/git-viewer.sh +1 -1
  270. package/scripts/reset-settings.sh +1 -1
  271. package/tests/README.md +10 -1
  272. package/dist/scripts/generate_market_adapter_whitelist.d.ts +0 -15
  273. package/dist/scripts/generate_market_adapter_whitelist.d.ts.map +0 -1
  274. package/dist/scripts/generate_market_adapter_whitelist.js +0 -191
  275. package/dist/scripts/generate_market_adapter_whitelist.js.map +0 -1
@@ -22,7 +22,7 @@ import { calculateAMA } from '../market_adapter/core/strategies/ama.js';
22
22
  import { computeAmaSlopeWeights, createAmaSlopeClipTracker } from '../market_adapter/core/strategies/ama_slope_model.js';
23
23
  import { MARKET_ADAPTER } from '../modules/constants.js';
24
24
  import { PATHS } from '../modules/paths.js';
25
- import { writeChartFile } from './chart_utils.js';
25
+ import { writeChartFile, toFileUrl } from './chart_utils.js';
26
26
  import { getCandleClose } from './math_utils.js';
27
27
  import { resolveSource, listAvailableBots, type SourceConfig } from './resolve_source.js';
28
28
 
@@ -56,6 +56,7 @@ function parseArgs() {
56
56
  const config: {
57
57
  source: { type: string; config: SourceConfig };
58
58
  chartFile: string;
59
+ title: string | null;
59
60
  alpha: any;
60
61
  gain: any;
61
62
  dispWeight: any;
@@ -64,9 +65,11 @@ function parseArgs() {
64
65
  listBots: boolean;
65
66
  lookbackBars?: number;
66
67
  dispScaleMinPct?: number;
68
+ amaEmaSpan?: number;
67
69
  } = {
68
70
  source: { type: 'market_adapter', config: { botKey: '' } },
69
71
  chartFile: path.join(PATHS.ANALYSIS.CHARTS_DIR, 'dynamic_weight_chart.html'),
72
+ title: null,
70
73
  alpha: MARKET_ADAPTER.DYNAMIC_WEIGHT_ALPHA,
71
74
  gain: MARKET_ADAPTER.DYNAMIC_WEIGHT_GAIN,
72
75
  dispWeight: MARKET_ADAPTER.DYNAMIC_WEIGHT_DW,
@@ -84,10 +87,12 @@ function parseArgs() {
84
87
  config.source.type = 'json';
85
88
  }
86
89
  else if (arg === '--chart') config.chartFile = args[++i];
90
+ else if (arg === '--title') config.title = args[++i] ?? null;
87
91
  else if (arg === '--alpha') config.alpha = parseFloat(args[++i]);
88
92
  else if (arg === '--gain') config.gain = parseFloat(args[++i]);
89
93
  else if (arg === '--dw') config.dispWeight = parseFloat(args[++i]);
90
94
  else if (arg === '--lb') config.lookbackBars = parseInt(args[++i], 10);
95
+ else if (arg === '--ema') config.amaEmaSpan = parseInt(args[++i], 10);
91
96
  else if (arg === '--clip') config.clipPct = parseFloat(args[++i]);
92
97
  else if (arg === '--list-bots') config.listBots = true;
93
98
  else if (arg === '--quiet') config.quiet = true;
@@ -201,6 +206,7 @@ async function main() {
201
206
  ...AMA_WEIGHT_CONFIG,
202
207
  lookbackBars: config.lookbackBars ?? AMA_WEIGHT_CONFIG.lookbackBars,
203
208
  },
209
+ amaEmaSpan: config.amaEmaSpan,
204
210
  alpha: config.alpha,
205
211
  gain: config.gain,
206
212
  dispWeight: config.dispWeight,
@@ -223,11 +229,11 @@ async function main() {
223
229
  amaNeutralZonePct: MARKET_ADAPTER.DYNAMIC_WEIGHT_AMA_NEUTRAL_ZONE_PCT,
224
230
  dispScaleMinPct: MARKET_ADAPTER.DYNAMIC_WEIGHT_DISP_SCALE_MIN_PCT,
225
231
  },
226
- }, 'Dynamic Weight Research Tool');
232
+ }, config.title || 'Dynamic Weight Research Tool');
227
233
 
228
234
  writeChartFile(config.chartFile, html);
229
235
 
230
- if (!config.quiet) console.log(`[DynamicWeight] ✓ Chart saved to ${config.chartFile}`);
236
+ if (!config.quiet) console.log(`\n[DynamicWeight] ✓ Chart saved. Open chart: (${toFileUrl(config.chartFile)})`);
231
237
  } catch (err: unknown) {
232
238
  console.error(`[DynamicWeight] Error: ${(err as any)?.message ?? err}`);
233
239
  process.exit(1);
@@ -1,10 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
- import { createRequire } from 'node:module';
4
- const require = createRequire(import.meta.url);
5
-
6
-
7
3
  import { getStorage } from '../../modules/storage/index.js';
4
+ import { withReadOnlyClient } from '../chain_pool.js';
8
5
  const { writeJSON } = getStorage();
9
6
 
10
7
  /**
@@ -58,7 +55,6 @@ import {
58
55
  buildTopUpdaterAccountsQuery,
59
56
  DEFAULT_CONFIG,
60
57
  } from './kibana_bot_queries.js';
61
- import { NODE_MANAGEMENT } from '../../modules/constants.js';
62
58
 
63
59
  // ─── Types ────────────────────────────────────────────────────────────────────
64
60
 
@@ -283,33 +279,30 @@ function dexScore(creates: number, fills: number, _cancels: number, gridScore: n
283
279
  // ─── Account resolution ───────────────────────────────────────────────────────
284
280
 
285
281
  async function resolveNames(ids: string[]): Promise<Record<string, string>> {
286
- const { createReadOnlyClient } = require('../../modules/bitshares-native');
287
- const client = createReadOnlyClient({ nodes: NODE_MANAGEMENT.DEFAULT_NODES });
288
-
289
282
  const map: Record<string, any> = {};
290
283
  try {
291
- await client.connect();
292
- // BitShares db.get_objects accepts an array of IDs
293
- const objects = await client.db('get_objects', [ids]);
294
- for (const obj of (objects ?? [])) {
295
- if (obj?.id && obj?.name) map[obj.id] = obj.name;
296
- }
284
+ // Ephemeral read-only client over the built-in node pool (shared helper).
285
+ await withReadOnlyClient(async (client) => {
286
+ // BitShares db.get_objects accepts an array of IDs
287
+ const objects = await client.db('get_objects', [ids]);
288
+ for (const obj of (objects ?? [])) {
289
+ if (obj?.id && obj?.name) map[obj.id] = obj.name;
290
+ }
297
291
 
298
- // Resolve extra asset precisions while connected
299
- const toCheck = ['IOB.XRP', 'HONEST.MONEY', 'XBTSX.XRP', 'XBTSX.USDT', 'USD', 'CNY'];
300
- for (const sym of toCheck) {
301
- try {
302
- const assets = await client.db('lookup_asset_symbols', [[sym]]);
303
- const a = Array.isArray(assets) ? assets[0] : null;
304
- if (a?.id && !(a.id in ASSET_PRECISION)) {
305
- (ASSET_PRECISION as Record<string, any>)[a.id] = a.precision;
306
- }
307
- } catch (_) {}
308
- }
292
+ // Resolve extra asset precisions while connected
293
+ const toCheck = ['IOB.XRP', 'HONEST.MONEY', 'XBTSX.XRP', 'XBTSX.USDT', 'USD', 'CNY'];
294
+ for (const sym of toCheck) {
295
+ try {
296
+ const assets = await client.db('lookup_asset_symbols', [[sym]]);
297
+ const a = Array.isArray(assets) ? assets[0] : null;
298
+ if (a?.id && !(a.id in ASSET_PRECISION)) {
299
+ (ASSET_PRECISION as Record<string, any>)[a.id] = a.precision;
300
+ }
301
+ } catch (_) {}
302
+ }
303
+ });
309
304
  } catch (e: any) {
310
305
  console.warn(` [warn] Name resolution failed: ${e.message}`);
311
- } finally {
312
- try { client.disconnect(); } catch (_) {}
313
306
  }
314
307
  return map;
315
308
  }
@@ -0,0 +1,47 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * SHARED CHAIN POOL (analysis)
5
+ *
6
+ * Single source of truth for the node list and the ephemeral read-only
7
+ * connection used by analysis tools for small on-chain lookups (account name
8
+ * resolution, asset precision resolution).
9
+ *
10
+ * Analysis tools deliberately do NOT use the production singleton client
11
+ * (modules/bitshares_client.ts): they are short-lived processes and must never
12
+ * disturb a running bot's connection state. Instead each lookup opens a fresh
13
+ * read-only client over the built-in node pool, which the native transport
14
+ * races in parallel and then retries sequentially — so one dead node is not
15
+ * fatal.
16
+ */
17
+
18
+ import * as C from '../modules/constants.js';
19
+
20
+ /** Nodes for ephemeral read-only analysis connections (node management pool). */
21
+ function defaultNodePool(): string[] {
22
+ return [...C.NODE_MANAGEMENT.DEFAULT_NODES];
23
+ }
24
+
25
+ /**
26
+ * Run `fn` against a fresh read-only client connected over the built-in pool.
27
+ * Transport INFO logging is silenced for the duration of the short-lived
28
+ * connection and the client is always disconnected afterwards.
29
+ */
30
+ async function withReadOnlyClient<T>(fn: (client: any) => Promise<T>): Promise<T> {
31
+ const { createReadOnlyClient } = await import('../modules/bitshares-native/index.js');
32
+ const client = createReadOnlyClient({ nodes: defaultNodePool() });
33
+ // Suppress transport INFO logs during ephemeral connection:
34
+ // bitshares-native transport logger (new Logger('Transport')) writes
35
+ // "[timestamp] [INFO] [Transport] ..." — silence by raising log level.
36
+ const prevLevel = process.env.LOG_LEVEL;
37
+ process.env.LOG_LEVEL = 'warn';
38
+ try {
39
+ await client.connect();
40
+ return await fn(client);
41
+ } finally {
42
+ try { client.disconnect(); } catch (_) { /* best-effort cleanup */ }
43
+ process.env.LOG_LEVEL = prevLevel;
44
+ }
45
+ }
46
+
47
+ export { defaultNodePool, withReadOnlyClient };
@@ -10,26 +10,39 @@ const { ensureDir } = getStorage();
10
10
  * Chart utilities for analysis HTML generators.
11
11
  */
12
12
 
13
- // Runtime assets every generated chart references as ../uplot/* relative to
14
- // its own directory (charts live in <root>/charts, assets in <root>/uplot).
15
- const UPLOT_RUNTIME_FILES = ['uPlot.iife.min.js', 'uPlot.min.css'];
13
+ // Vendored uPlot runtime assets are inlined directly into every generated chart
14
+ // (see uplotInlineTags below), so each chart is a single self-contained file
15
+ // that renders anywhere: no DEXBot2 install, no sibling uplot/ dir, no CDN, no
16
+ // network. The vendored originals always live with the code under the analysis
17
+ // assets dir.
18
+ let _uplotRuntime: { css: string; js: string } | null = null;
19
+
20
+ function getUplotRuntime() {
21
+ if (!_uplotRuntime) {
22
+ const dir = PATHS.ANALYSIS.ASSETS_DIR;
23
+ _uplotRuntime = {
24
+ css: fs.readFileSync(path.join(dir, 'uPlot.min.css'), 'utf8'),
25
+ js: fs.readFileSync(path.join(dir, 'uPlot.iife.min.js'), 'utf8'),
26
+ };
27
+ }
28
+ return _uplotRuntime;
29
+ }
16
30
 
17
31
  /**
18
- * Generated HTML loads uPlot from a sibling `uplot/` dir next to the charts
19
- * dir. In a source checkout that dir is the vendored original; anywhere else
20
- * (relocated analysis root under npm/home profiles, or a custom --chart path)
21
- * materialize a copy so the relative refs keep resolving.
32
+ * Inline <style>/<script> tags carrying the vendored uPlot runtime. Embedding
33
+ * the source (not a relative <script src>) makes a chart portable: it keeps
34
+ * rendering after being copied, mailed, or reopened on a machine without a
35
+ * DEXBot2 installation. The inline script must be the first script that runs,
36
+ * placed before any chart-initialization code, since uPlot must exist first.
37
+ * Both the minified JS (no `</script>`) and CSS (no `</style>`) are safe to
38
+ * embed verbatim.
22
39
  */
23
- function ensureSiblingUplotAssets(chartDir: any) {
24
- const targetDir = path.join(path.dirname(path.resolve(chartDir)), 'uplot');
25
- const sourceDir = PATHS.ANALYSIS.ASSETS_DIR;
26
- if (targetDir === path.resolve(sourceDir)) return;
27
- if (UPLOT_RUNTIME_FILES.every((f) => fs.existsSync(path.join(targetDir, f)))) return;
28
- if (!fs.existsSync(sourceDir)) return;
29
- fs.mkdirSync(targetDir, { recursive: true });
30
- for (const f of UPLOT_RUNTIME_FILES) {
31
- fs.copyFileSync(path.join(sourceDir, f), path.join(targetDir, f));
32
- }
40
+ function uplotInlineTags({ css = true, js = true } = {}) {
41
+ const { css: cssCode, js: jsCode } = getUplotRuntime();
42
+ const parts: string[] = [];
43
+ if (css && cssCode) parts.push(`<style>\n${cssCode}\n</style>`);
44
+ if (js && jsCode) parts.push(`<script>\n${jsCode}\n</script>`);
45
+ return parts.join('\n ');
33
46
  }
34
47
 
35
48
 
@@ -58,9 +71,9 @@ function toFileUrl(filePath: any): string {
58
71
  return `file://${path.resolve(String(filePath))}`;
59
72
  }
60
73
 
61
- function writeChartFile(filePath: any, html: any) { const chartDir = path.dirname(filePath);
74
+ function writeChartFile(filePath: any, html: any) {
75
+ const chartDir = path.dirname(filePath);
62
76
  if (!fs.existsSync(chartDir)) ensureDir(chartDir);
63
- ensureSiblingUplotAssets(chartDir);
64
77
  // Atomic write (tmp + rename, matching the production storage adapter
65
78
  // pattern) so a crash mid-write can never leave a truncated chart file.
66
79
  const tmpPath = `${filePath}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 10)}.tmp`;
@@ -193,5 +206,5 @@ function bindPan(chart) {
193
206
  }
194
207
  `;
195
208
 
196
- export { escapeHtml, serializeJsonForScript, toEpochSeconds, writeChartFile, toFileUrl, embedFunctionSources, UPLOT_SHARED_SCRIPT }
209
+ export { escapeHtml, serializeJsonForScript, toEpochSeconds, writeChartFile, toFileUrl, embedFunctionSources, UPLOT_SHARED_SCRIPT, uplotInlineTags }
197
210
 
@@ -4,7 +4,7 @@
4
4
  import fs from 'node:fs';
5
5
  import path from 'node:path';
6
6
  import { pathToFileURL } from 'node:url';
7
- import { escapeHtml, serializeJsonForScript, toEpochSeconds, UPLOT_SHARED_SCRIPT } from './chart_utils.js';
7
+ import { escapeHtml, serializeJsonForScript, toEpochSeconds, UPLOT_SHARED_SCRIPT, uplotInlineTags } from './chart_utils.js';
8
8
  import { getStorage } from '../modules/storage/index.js';
9
9
  const { ensureDir, readJSON } = getStorage();
10
10
  import { fixedTo } from '../modules/order/utils/math.js';
@@ -225,8 +225,7 @@ function generateHTML(data: any, title: string) {
225
225
  <meta name="darkreader-lock">
226
226
  <meta name="color-scheme" content="dark">
227
227
  <title>${escapeHtml(title)}</title>
228
- <link rel="stylesheet" href="../uplot/uPlot.min.css">
229
- <script src="../uplot/uPlot.iife.min.js"></script>
228
+ ${uplotInlineTags()}
230
229
  <style>
231
230
  :root { color-scheme: dark; }
232
231
  * { box-sizing: border-box; margin: 0; padding: 0; }
@@ -0,0 +1,234 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * SHARED FILLS SOURCE (analysis)
5
+ *
6
+ * Single implementation of the Kibana `fill_order` pipeline and the asset
7
+ * precision table/cache used by the fill-based analysis tools. Both
8
+ * trade_profitability.ts and grid_correction_check.ts carried verbatim copies
9
+ * of this (43-entry ASSETS table, toReal/assetPrec helpers, on-chain precision
10
+ * resolution, query builder and paginated fetch); all of it lives here now.
11
+ */
12
+
13
+ import * as KC from '../market_adapter/core/kibana_client.js';
14
+ import { withReadOnlyClient } from './chain_pool.js';
15
+
16
+ const { kibanaSearch, DEFAULT_CONFIG: BASE_CONFIG } = KC;
17
+
18
+ /** operation_type of a fill_order operation in the chain history index. */
19
+ const OP_FILL_ORDER = 4;
20
+ const BTS_ID = '1.3.0';
21
+
22
+ interface AssetInfo {
23
+ symbol: string;
24
+ precision: number;
25
+ }
26
+
27
+ interface AssetAmount {
28
+ amount: number;
29
+ asset_id: string;
30
+ }
31
+
32
+ interface FillRecord {
33
+ time: string;
34
+ blockNum: number;
35
+ opNum: number;
36
+ orderId: string;
37
+ accountId: string;
38
+ pays: AssetAmount;
39
+ receives: AssetAmount;
40
+ fee: AssetAmount;
41
+ isMaker: boolean;
42
+ sort: any[];
43
+ }
44
+
45
+ const ASSETS: Record<string, AssetInfo> = {
46
+ '1.3.0': { symbol: 'BTS', precision: 5 },
47
+ '1.3.118': { symbol: 'GBP', precision: 4 },
48
+ '1.3.119': { symbol: 'JPY', precision: 2 },
49
+ '1.3.120': { symbol: 'EUR', precision: 4 },
50
+ '1.3.1325': { symbol: 'RUBLE', precision: 5 },
51
+ '1.3.2512': { symbol: 'EVRAZ', precision: 4 },
52
+ '1.3.3291': { symbol: 'TWENTIX', precision: 5 },
53
+ '1.3.4099': { symbol: 'XBTSX.STH', precision: 6 },
54
+ '1.3.4156': { symbol: 'XBTSX.DOGE', precision: 5 },
55
+ '1.3.4157': { symbol: 'XBTSX.BTC', precision: 8 },
56
+ '1.3.4159': { symbol: 'XBTSX.LTC', precision: 8 },
57
+ '1.3.4176': { symbol: 'XBTSX.DASH', precision: 8 },
58
+ '1.3.4274': { symbol: 'XBTSX.BCH', precision: 8 },
59
+ '1.3.4760': { symbol: 'XBTSX.ETH', precision: 7 },
60
+ '1.3.5537': { symbol: 'IOB.XRP', precision: 4 },
61
+ '1.3.5541': { symbol: 'XBTSX.BNB', precision: 7 },
62
+ '1.3.5589': { symbol: 'XBTSX.USDT', precision: 6 },
63
+ '1.3.5641': { symbol: 'HONEST.CNY', precision: 4 },
64
+ '1.3.5649': { symbol: 'HONEST.USD', precision: 4 },
65
+ '1.3.5650': { symbol: 'HONEST.BTC', precision: 8 },
66
+ '1.3.5659': { symbol: 'HONEST.ETH', precision: 6 },
67
+ '1.3.5870': { symbol: 'XBTSX.FIL', precision: 6 },
68
+ '1.3.5887': { symbol: 'XBTSX.RUB', precision: 4 },
69
+ '1.3.5902': { symbol: 'XBTSX.USDC', precision: 6 },
70
+ '1.3.6013': { symbol: 'XBTSX.HIVE', precision: 6 },
71
+ '1.3.6124': { symbol: 'XBTSX.AVAX', precision: 6 },
72
+ '1.3.6139': { symbol: 'XBTSX.XAUT', precision: 6 },
73
+ '1.3.6166': { symbol: 'XBTSX.MATIC', precision: 5 },
74
+ '1.3.6241': { symbol: 'XBTSX.ETC', precision: 7 },
75
+ '1.3.6268': { symbol: 'BTWTY.EOS', precision: 4 },
76
+ '1.3.6301': { symbol: 'HONEST.MONEY', precision: 8 },
77
+ '1.3.6304': { symbol: 'HONEST.ADA', precision: 8 },
78
+ '1.3.6305': { symbol: 'HONEST.DOT', precision: 8 },
79
+ '1.3.6309': { symbol: 'HONEST.ATOM', precision: 8 },
80
+ '1.3.6311': { symbol: 'HONEST.ALGO', precision: 8 },
81
+ '1.3.6312': { symbol: 'HONEST.FIL', precision: 8 },
82
+ '1.3.6313': { symbol: 'HONEST.EOS', precision: 8 },
83
+ '1.3.6315': { symbol: 'HONEST.EUR', precision: 4 },
84
+ '1.3.6316': { symbol: 'HONEST.GBP', precision: 4 },
85
+ '1.3.6317': { symbol: 'HONEST.JPY', precision: 4 },
86
+ '1.3.6444': { symbol: 'IOB.XLM', precision: 4 },
87
+ '1.3.6573': { symbol: 'XBTSX.DAI', precision: 6 },
88
+ '1.3.6620': { symbol: 'XBTSX.A', precision: 6 },
89
+ '1.3.6627': { symbol: 'XBTSX.LINK', precision: 6 },
90
+ };
91
+
92
+ /** Precisions learned on-chain this run (populated by resolveAssetPrecisions). */
93
+ const resolvedPrecisions: Record<string, number> = {};
94
+
95
+ function assetSymbol(id: string): string {
96
+ return ASSETS[id]?.symbol ?? id;
97
+ }
98
+
99
+ function assetPrec(id: string): number | undefined {
100
+ return ASSETS[id]?.precision ?? resolvedPrecisions[id];
101
+ }
102
+
103
+ function toReal(amount: number, assetId: string): number {
104
+ const p = assetPrec(assetId);
105
+ if (p === undefined) return NaN;
106
+ return amount / Math.pow(10, p);
107
+ }
108
+
109
+ /**
110
+ * Collect all unique non-BTS asset IDs from fills, resolve unknown precisions
111
+ * from the blockchain, and populate the runtime cache.
112
+ */
113
+ async function resolveAssetPrecisions(fills: FillRecord[]): Promise<void> {
114
+ const unknownIds = new Set<string>();
115
+ for (const f of fills) {
116
+ for (const id of [f.pays.asset_id, f.receives.asset_id, f.fee.asset_id]) {
117
+ if (id !== BTS_ID && !(id in ASSETS) && !(id in resolvedPrecisions)) {
118
+ unknownIds.add(id);
119
+ }
120
+ }
121
+ }
122
+ if (unknownIds.size === 0) return;
123
+
124
+ const ids = [...unknownIds];
125
+ console.log(` Resolving ${ids.length} unknown asset(s) from blockchain...`);
126
+ try {
127
+ await withReadOnlyClient(async (client) => {
128
+ const assets = await client.db('get_assets', [ids]);
129
+ if (Array.isArray(assets)) {
130
+ for (const asset of assets) {
131
+ if (asset?.id && asset.precision != null) {
132
+ resolvedPrecisions[asset.id] = asset.precision;
133
+ console.log(` ${asset.id} → ${asset.symbol || '?'} (precision ${asset.precision})`);
134
+ }
135
+ }
136
+ }
137
+ const missing = ids.filter(id => !(id in resolvedPrecisions));
138
+ if (missing.length > 0) {
139
+ console.warn(` [warn] ${missing.length} asset(s) not found on chain: ${missing.join(', ')}. Fills referencing them will be skipped.`);
140
+ }
141
+ });
142
+ } catch (e: any) {
143
+ console.warn(` [warn] Asset resolution failed: ${e.message}. Fills with unknown assets will be skipped.`);
144
+ }
145
+ }
146
+
147
+ function buildFillQuery(accountId: string, gte: string, lte: string, size: number) {
148
+ return {
149
+ size,
150
+ track_total_hits: false,
151
+ _source: [
152
+ 'block_data.block_time',
153
+ 'block_data.block_num',
154
+ 'operation_id_num',
155
+ 'operation_history.op_object.pays',
156
+ 'operation_history.op_object.receives',
157
+ 'operation_history.op_object.fee',
158
+ 'operation_history.op_object.order_id',
159
+ 'operation_history.op_object.account_id',
160
+ 'operation_history.op_object.is_maker',
161
+ ],
162
+ query: {
163
+ bool: {
164
+ filter: [
165
+ { term: { operation_type: OP_FILL_ORDER } },
166
+ { term: { 'operation_history.op_object.account_id.keyword': accountId } },
167
+ { range: { 'block_data.block_time': { gte, lte } } },
168
+ ],
169
+ },
170
+ },
171
+ sort: [
172
+ { 'block_data.block_time': { order: 'asc' } },
173
+ { operation_id_num: { order: 'asc' } },
174
+ ],
175
+ };
176
+ }
177
+
178
+ /** Fetch every fill_order for an account in [gte, lte], paginated via search_after. */
179
+ async function fetchAllFills(config: any, accountId: string, gte: string, lte: string): Promise<FillRecord[]> {
180
+ const pageSize = 10000;
181
+ const fills: FillRecord[] = [];
182
+ let searchAfter: any[] | null = null;
183
+ const cfg = { ...BASE_CONFIG, timeout: 60000, ...config };
184
+
185
+ while (true) {
186
+ const query = buildFillQuery(accountId, gte, lte, pageSize);
187
+ if (searchAfter) (query as any).search_after = searchAfter;
188
+
189
+ const result: any = await kibanaSearch(cfg, query);
190
+ const hits = result?.hits?.hits ?? [];
191
+ if (!hits.length) break;
192
+
193
+ for (const hit of hits) {
194
+ const src = hit?._source;
195
+ const op = src?.operation_history?.op_object;
196
+ if (!op || !op.pays || !op.receives) continue;
197
+
198
+ fills.push({
199
+ time: src.block_data?.block_time ?? '',
200
+ blockNum: src.block_data?.block_num ?? 0,
201
+ opNum: Number(src.operation_id_num ?? 0),
202
+ orderId: op.order_id ?? '',
203
+ accountId: op.account_id ?? '',
204
+ pays: { amount: Number(op.pays.amount ?? 0), asset_id: op.pays.asset_id ?? '' },
205
+ receives: { amount: Number(op.receives.amount ?? 0), asset_id: op.receives.asset_id ?? '' },
206
+ fee: { amount: Number(op.fee?.amount ?? 0), asset_id: op.fee?.asset_id ?? '' },
207
+ isMaker: op.is_maker ?? false,
208
+ sort: hit.sort,
209
+ });
210
+ }
211
+
212
+ if (hits.length < pageSize) break;
213
+ searchAfter = hits[hits.length - 1].sort;
214
+ if (!Array.isArray(searchAfter)) break;
215
+ }
216
+
217
+ return fills;
218
+ }
219
+
220
+ export {
221
+ BTS_ID,
222
+ OP_FILL_ORDER,
223
+ ASSETS,
224
+ resolvedPrecisions,
225
+ assetSymbol,
226
+ assetPrec,
227
+ toReal,
228
+ resolveAssetPrecisions,
229
+ buildFillQuery,
230
+ fetchAllFills,
231
+ AssetInfo,
232
+ AssetAmount,
233
+ FillRecord,
234
+ };