dexbot 1.4.25 → 1.5.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 (182) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +6 -2
  3. package/analysis/README.md +14 -7
  4. package/analysis/ama_fitting/package.json +1 -1
  5. package/analysis/analyze_derivatives.ts +1 -1
  6. package/analysis/bot_key_utils.ts +272 -3
  7. package/analysis/bot_usage/discover_bot_accounts.ts +64 -9
  8. package/analysis/bot_usage/kibana_bot_queries.ts +40 -1
  9. package/analysis/chart_utils.ts +6 -3
  10. package/analysis/grid_correction_check.ts +56 -20
  11. package/analysis/resolve_bot_accounts.ts +199 -0
  12. package/analysis/trade_profitability.ts +36 -8
  13. package/analysis/tradingview/README.md +25 -0
  14. package/analysis/tradingview/analyze_tradingview.ts +2 -2
  15. package/analysis/trend_detection/package.json +1 -1
  16. package/claw/modules/claw_launcher.ts +5 -4
  17. package/claw/modules/credit_runtime_adapter.ts +2 -1
  18. package/claw/modules/dexbot_profiles.ts +4 -3
  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/tests/test_claw_mcp_transport.ts +2 -2
  23. package/dist/analysis/analyze_derivatives.js +1 -1
  24. package/dist/analysis/bot_key_utils.d.ts +28 -1
  25. package/dist/analysis/bot_key_utils.d.ts.map +1 -1
  26. package/dist/analysis/bot_key_utils.js +385 -3
  27. package/dist/analysis/bot_key_utils.js.map +1 -1
  28. package/dist/analysis/bot_usage/discover_bot_accounts.js +60 -10
  29. package/dist/analysis/bot_usage/discover_bot_accounts.js.map +1 -1
  30. package/dist/analysis/bot_usage/kibana_bot_queries.d.ts +45 -1
  31. package/dist/analysis/bot_usage/kibana_bot_queries.d.ts.map +1 -1
  32. package/dist/analysis/bot_usage/kibana_bot_queries.js +39 -1
  33. package/dist/analysis/bot_usage/kibana_bot_queries.js.map +1 -1
  34. package/dist/analysis/chart_utils.d.ts +2 -1
  35. package/dist/analysis/chart_utils.d.ts.map +1 -1
  36. package/dist/analysis/chart_utils.js +4 -1
  37. package/dist/analysis/chart_utils.js.map +1 -1
  38. package/dist/analysis/grid_correction_check.d.ts.map +1 -1
  39. package/dist/analysis/grid_correction_check.js +60 -20
  40. package/dist/analysis/grid_correction_check.js.map +1 -1
  41. package/dist/analysis/resolve_bot_accounts.d.ts +3 -0
  42. package/dist/analysis/resolve_bot_accounts.d.ts.map +1 -0
  43. package/dist/analysis/resolve_bot_accounts.js +216 -0
  44. package/dist/analysis/resolve_bot_accounts.js.map +1 -0
  45. package/dist/analysis/trade_profitability.d.ts.map +1 -1
  46. package/dist/analysis/trade_profitability.js +40 -8
  47. package/dist/analysis/trade_profitability.js.map +1 -1
  48. package/dist/analysis/tradingview/analyze_tradingview.js +2 -2
  49. package/dist/analysis/tradingview/analyze_tradingview.js.map +1 -1
  50. package/dist/bot.d.ts.map +1 -1
  51. package/dist/bot.js +2 -1
  52. package/dist/bot.js.map +1 -1
  53. package/dist/dexbot.d.ts.map +1 -1
  54. package/dist/dexbot.js +73 -17
  55. package/dist/dexbot.js.map +1 -1
  56. package/dist/market_adapter/ama_signal_runner.js +2 -2
  57. package/dist/market_adapter/inputs/fetch_cex_synthetic_data.js +2 -1
  58. package/dist/market_adapter/inputs/fetch_cex_synthetic_data.js.map +1 -1
  59. package/dist/market_adapter/inputs/fetch_lp_data.d.ts +4 -1
  60. package/dist/market_adapter/inputs/fetch_lp_data.d.ts.map +1 -1
  61. package/dist/market_adapter/inputs/fetch_lp_data.js +3 -2
  62. package/dist/market_adapter/inputs/fetch_lp_data.js.map +1 -1
  63. package/dist/modules/account_bots.d.ts +42 -1
  64. package/dist/modules/account_bots.d.ts.map +1 -1
  65. package/dist/modules/account_bots.js +168 -17
  66. package/dist/modules/account_bots.js.map +1 -1
  67. package/dist/modules/bitshares_client.d.ts +4 -1
  68. package/dist/modules/bitshares_client.d.ts.map +1 -1
  69. package/dist/modules/bitshares_client.js +12 -4
  70. package/dist/modules/bitshares_client.js.map +1 -1
  71. package/dist/modules/bot_settings.d.ts.map +1 -1
  72. package/dist/modules/bot_settings.js +2 -1
  73. package/dist/modules/bot_settings.js.map +1 -1
  74. package/dist/modules/cli_colors.d.ts +39 -0
  75. package/dist/modules/cli_colors.d.ts.map +1 -0
  76. package/dist/modules/cli_colors.js +42 -0
  77. package/dist/modules/cli_colors.js.map +1 -0
  78. package/dist/modules/constants.d.ts.map +1 -1
  79. package/dist/modules/constants.js +15 -11
  80. package/dist/modules/constants.js.map +1 -1
  81. package/dist/modules/credit_pricing.d.ts +61 -0
  82. package/dist/modules/credit_pricing.d.ts.map +1 -0
  83. package/dist/modules/credit_pricing.js +237 -0
  84. package/dist/modules/credit_pricing.js.map +1 -0
  85. package/dist/modules/credit_runtime.d.ts +1 -0
  86. package/dist/modules/credit_runtime.d.ts.map +1 -1
  87. package/dist/modules/credit_runtime.js +49 -107
  88. package/dist/modules/credit_runtime.js.map +1 -1
  89. package/dist/modules/dexbot_class.d.ts +2 -1
  90. package/dist/modules/dexbot_class.d.ts.map +1 -1
  91. package/dist/modules/dexbot_class.js +22 -6
  92. package/dist/modules/dexbot_class.js.map +1 -1
  93. package/dist/modules/dexbot_cow_runtime.d.ts +19 -2
  94. package/dist/modules/dexbot_cow_runtime.d.ts.map +1 -1
  95. package/dist/modules/dexbot_cow_runtime.js +249 -26
  96. package/dist/modules/dexbot_cow_runtime.js.map +1 -1
  97. package/dist/modules/dexbot_maintenance_runtime.d.ts +15 -16
  98. package/dist/modules/dexbot_maintenance_runtime.d.ts.map +1 -1
  99. package/dist/modules/dexbot_maintenance_runtime.js +69 -42
  100. package/dist/modules/dexbot_maintenance_runtime.js.map +1 -1
  101. package/dist/modules/fund_registry.d.ts +1 -1
  102. package/dist/modules/fund_registry.js +1 -1
  103. package/dist/modules/launcher/adapter_requirement.d.ts +38 -0
  104. package/dist/modules/launcher/adapter_requirement.d.ts.map +1 -0
  105. package/dist/modules/launcher/adapter_requirement.js +141 -0
  106. package/dist/modules/launcher/adapter_requirement.js.map +1 -0
  107. package/dist/modules/launcher/bot_supervisor.d.ts +2 -2
  108. package/dist/modules/launcher/bot_supervisor.d.ts.map +1 -1
  109. package/dist/modules/launcher/bot_supervisor.js +32 -3
  110. package/dist/modules/launcher/bot_supervisor.js.map +1 -1
  111. package/dist/modules/launcher/launch_modes.d.ts.map +1 -1
  112. package/dist/modules/launcher/launch_modes.js +5 -4
  113. package/dist/modules/launcher/launch_modes.js.map +1 -1
  114. package/dist/modules/launcher/monolithic_runtime.d.ts +1 -1
  115. package/dist/modules/launcher/monolithic_runtime.d.ts.map +1 -1
  116. package/dist/modules/launcher/monolithic_runtime.js +12 -8
  117. package/dist/modules/launcher/monolithic_runtime.js.map +1 -1
  118. package/dist/modules/launcher/status_reporting.d.ts +6 -6
  119. package/dist/modules/launcher/status_reporting.d.ts.map +1 -1
  120. package/dist/modules/launcher/status_reporting.js +9 -6
  121. package/dist/modules/launcher/status_reporting.js.map +1 -1
  122. package/dist/modules/order/export.d.ts +1 -1
  123. package/dist/modules/order/export.js +1 -1
  124. package/dist/modules/order/grid.d.ts.map +1 -1
  125. package/dist/modules/order/grid.js +47 -12
  126. package/dist/modules/order/grid.js.map +1 -1
  127. package/dist/modules/order/logger.d.ts +23 -1
  128. package/dist/modules/order/logger.d.ts.map +1 -1
  129. package/dist/modules/order/logger.js +60 -17
  130. package/dist/modules/order/logger.js.map +1 -1
  131. package/dist/modules/order/manager.d.ts.map +1 -1
  132. package/dist/modules/order/manager.js +43 -3
  133. package/dist/modules/order/manager.js.map +1 -1
  134. package/dist/modules/order/sync_engine.js +1 -1
  135. package/dist/modules/order/utils/system.d.ts +52 -4
  136. package/dist/modules/order/utils/system.d.ts.map +1 -1
  137. package/dist/modules/order/utils/system.js +106 -14
  138. package/dist/modules/order/utils/system.js.map +1 -1
  139. package/dist/modules/order/utils/validate.d.ts +1 -1
  140. package/dist/modules/order/utils/validate.d.ts.map +1 -1
  141. package/dist/modules/order/utils/validate.js +43 -3
  142. package/dist/modules/order/utils/validate.js.map +1 -1
  143. package/dist/modules/utils/chain_logs.d.ts +11 -0
  144. package/dist/modules/utils/chain_logs.d.ts.map +1 -0
  145. package/dist/modules/utils/chain_logs.js +23 -0
  146. package/dist/modules/utils/chain_logs.js.map +1 -0
  147. package/dist/modules/utils/sanitize_key.d.ts +7 -0
  148. package/dist/modules/utils/sanitize_key.d.ts.map +1 -1
  149. package/dist/modules/utils/sanitize_key.js +15 -0
  150. package/dist/modules/utils/sanitize_key.js.map +1 -1
  151. package/dist/pm2.d.ts +11 -1
  152. package/dist/pm2.d.ts.map +1 -1
  153. package/dist/pm2.js +66 -15
  154. package/dist/pm2.js.map +1 -1
  155. package/dist/scripts/analyze-credit.d.ts +4 -0
  156. package/dist/scripts/analyze-credit.d.ts.map +1 -0
  157. package/dist/scripts/analyze-credit.js +760 -0
  158. package/dist/scripts/analyze-credit.js.map +1 -0
  159. package/dist/scripts/analyze-orders.d.ts +1 -10
  160. package/dist/scripts/analyze-orders.d.ts.map +1 -1
  161. package/dist/scripts/analyze-orders.js +11 -34
  162. package/dist/scripts/analyze-orders.js.map +1 -1
  163. package/dist/scripts/test-credit-renewal.d.ts.map +1 -1
  164. package/dist/scripts/test-credit-renewal.js +37 -5
  165. package/dist/scripts/test-credit-renewal.js.map +1 -1
  166. package/dist/scripts/tv.d.ts +11 -0
  167. package/dist/scripts/tv.d.ts.map +1 -0
  168. package/dist/scripts/tv.js +357 -0
  169. package/dist/scripts/tv.js.map +1 -0
  170. package/dist/scripts/update.js +77 -10
  171. package/dist/scripts/update.js.map +1 -1
  172. package/dist/unlock.d.ts.map +1 -1
  173. package/dist/unlock.js +20 -8
  174. package/dist/unlock.js.map +1 -1
  175. package/docs/DEXBOT_COMPARISON.md +3 -3
  176. package/docs/EVOLUTION.md +7 -6
  177. package/docs/FUND_MOVEMENT_AND_ACCOUNTING.md +1 -1
  178. package/docs/MPA_CREDIT_USAGE.md +3 -1
  179. package/docs/README.md +2 -2
  180. package/docs/WORKFLOW.md +3 -1
  181. package/package.json +2 -1
  182. package/scripts/README.md +12 -0
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ declare function parseArgs(argv: string[]): {
3
+ target: string | null;
4
+ months: number;
5
+ chart: string | null;
6
+ priceScale: string;
7
+ help: boolean;
8
+ };
9
+ declare function isPoolIdTarget(target: string): boolean;
10
+ export { parseArgs, isPoolIdTarget };
11
+ //# sourceMappingURL=tv.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tv.d.ts","sourceRoot":"","sources":["../../scripts/tv.ts"],"names":[],"mappings":";AAsDA,iBAAS,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;IAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CA2CrI;AAED,iBAAS,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE/C;AAgPD,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,CAAA"}
@@ -0,0 +1,357 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ /**
4
+ * dexbot tv — TradingView chart shortcut.
5
+ *
6
+ * Usage:
7
+ * dexbot tv <bot|pool-id|AssetA/AssetB> [--month N] [--chart <path>] [--scale log|linear]
8
+ *
9
+ * - 1h candles, N months of history (default 3).
10
+ * - Target resolution:
11
+ * - bot name/key from profiles/bots.json
12
+ * - pool id (e.g. 133 or 1.19.133)
13
+ * - AssetA/AssetB symbols (pool-first, orderbook fill fallback when no pool)
14
+ *
15
+ * This script ONLY pulls fresh candle data and writes it to a temp JSON file.
16
+ * Rendering (chart HTML, AMA overlay like the exporter, auto chart path + print)
17
+ * is delegated to the existing analyzer at analysis/tradingview/analyze_tradingview.js.
18
+ */
19
+ import fs from 'node:fs';
20
+ import os from 'node:os';
21
+ import path from 'node:path';
22
+ import { spawnSync } from 'node:child_process';
23
+ import { fileURLToPath, pathToFileURL } from 'node:url';
24
+ const __filename = fileURLToPath(import.meta.url);
25
+ const __dirname = path.dirname(__filename);
26
+ import { loadBotMeta, resolveAmaConfig, loadBotSettings, computeBotKey } from '../analysis/bot_key_utils.js';
27
+ import { PATHS } from '../modules/paths.js';
28
+ import { normalizePoolId, resolveAsset, findPoolByAssets } from '../market_adapter/utils/chain.js';
29
+ import { fetchCandlesSequentially, outputPath, buildFetchWindowsFromRange } from '../market_adapter/inputs/fetch_lp_data.js';
30
+ import { getMarketCandles } from '../market_adapter/core/kibana_market_candles.js';
31
+ import { mergeCandles } from '../market_adapter/candle_utils.js';
32
+ import { getErrorMessage } from '../modules/utils/errors.js';
33
+ import { muteChainLogs } from '../modules/utils/chain_logs.js';
34
+ import { isSameBotName, sanitizeKey } from '../modules/utils/sanitize_key.js';
35
+ const INTERVAL_SECONDS = 3600;
36
+ const DEFAULT_MONTHS = 3;
37
+ const HOURS_PER_MONTH = 730;
38
+ function printUsage() {
39
+ console.log('Usage: dexbot tv <bot|pool-id|AssetA/AssetB> [--month N] [--chart <path>] [--scale log|linear]');
40
+ console.log('');
41
+ console.log(' <bot> Bot name or key from profiles/bots.json (AMA overlay like the exporter)');
42
+ console.log(' <pool-id> Liquidity pool id, e.g. 133 or 1.19.133');
43
+ console.log(' AssetA/AssetB Pair symbols, e.g. TOKENA/TOKENB (pool-first, orderbook fallback)');
44
+ console.log('');
45
+ console.log('Options:');
46
+ console.log(` --month N Months of 1h history (default ${DEFAULT_MONTHS})`);
47
+ console.log(' --months N Alias for --month');
48
+ console.log(' --chart <path> Override auto output path');
49
+ console.log(' --scale <log|linear> Price axis scale (default log)');
50
+ }
51
+ function parseArgs(argv) {
52
+ let target = null;
53
+ let months = DEFAULT_MONTHS;
54
+ let chart = null;
55
+ let priceScale = 'log';
56
+ let help = false;
57
+ for (let i = 0; i < argv.length; i++) {
58
+ const arg = argv[i];
59
+ if (arg === '-h' || arg === '--help')
60
+ help = true;
61
+ else if (arg === '--month' || arg === '--months') {
62
+ const raw = argv[++i];
63
+ const n = Number(raw);
64
+ if (!Number.isFinite(n) || n <= 0)
65
+ throw new Error(`--month: invalid value "${raw}" (expected positive months, e.g. --month 6)`);
66
+ months = n;
67
+ }
68
+ else if (arg.startsWith('--month=')) {
69
+ const n = Number(arg.split('=')[1]);
70
+ if (!Number.isFinite(n) || n <= 0)
71
+ throw new Error(`--month: invalid value "${arg}" (expected positive months)`);
72
+ months = n;
73
+ }
74
+ else if (arg.startsWith('--months=')) {
75
+ const n = Number(arg.split('=')[1]);
76
+ if (!Number.isFinite(n) || n <= 0)
77
+ throw new Error(`--months: invalid value "${arg}" (expected positive months)`);
78
+ months = n;
79
+ }
80
+ else if (arg === '--chart') {
81
+ chart = String(argv[++i] || '');
82
+ if (!chart)
83
+ throw new Error('--chart: missing path');
84
+ }
85
+ else if (arg.startsWith('--chart=')) {
86
+ chart = arg.split('=').slice(1).join('=');
87
+ if (!chart)
88
+ throw new Error('--chart: missing path');
89
+ }
90
+ else if (arg === '--scale' || arg === '--price-scale') {
91
+ priceScale = String(argv[++i] || 'log').toLowerCase();
92
+ if (priceScale !== 'log' && priceScale !== 'linear')
93
+ throw new Error(`--scale: unsupported value "${priceScale}" (use log|linear)`);
94
+ }
95
+ else if (arg.startsWith('--scale=')) {
96
+ priceScale = arg.split('=')[1]?.toLowerCase() || 'log';
97
+ if (priceScale !== 'log' && priceScale !== 'linear')
98
+ throw new Error(`--scale: unsupported value "${priceScale}" (use log|linear)`);
99
+ }
100
+ else if (arg.startsWith('--')) {
101
+ throw new Error(`Unknown flag "${arg}". Usage: dexbot tv <bot|pool-id|AssetA/AssetB> [--month N]`);
102
+ }
103
+ else if (!target) {
104
+ target = arg;
105
+ }
106
+ else {
107
+ throw new Error(`Unexpected argument "${arg}". Only one target is supported. Usage: dexbot tv <bot|pool-id|AssetA/AssetB> [--month N]`);
108
+ }
109
+ }
110
+ return { target, months, chart, priceScale, help };
111
+ }
112
+ function isPoolIdTarget(target) {
113
+ return /^(1\.19\.\d+|\d+)$/.test(target.trim());
114
+ }
115
+ function findBotByTarget(target) {
116
+ const settings = loadBotSettings();
117
+ const entries = Array.isArray(settings?.bots) ? settings.bots : [];
118
+ for (let i = 0; i < entries.length; i++) {
119
+ const entry = entries[i];
120
+ if (!entry)
121
+ continue;
122
+ if (isSameBotName(entry.name, target))
123
+ return { botKey: computeBotKey(entry, i), meta: entry };
124
+ }
125
+ const meta = loadBotMeta(target);
126
+ if (meta) {
127
+ const idx = entries.indexOf(meta);
128
+ return { botKey: computeBotKey(meta, idx >= 0 ? idx : 0), meta };
129
+ }
130
+ return null;
131
+ }
132
+ function slugPart(value) {
133
+ return String(value || '').trim().toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '') || 'unknown';
134
+ }
135
+ function monthsLabel(months) {
136
+ return Number.isInteger(months) ? `${months}m` : `${String(months).replace('.', 'p')}m`;
137
+ }
138
+ async function resolvePoolAssets(poolId, bitsharesClient) {
139
+ const fullId = normalizePoolId(poolId);
140
+ // Chain pool object via get_objects([poolId]) → asset_a / asset_b.
141
+ const db = bitsharesClient.BitShares?.db;
142
+ if (db && typeof db.get_objects === 'function') {
143
+ try {
144
+ const objs = await db.get_objects([fullId]);
145
+ const pool = Array.isArray(objs) ? objs[0] : null;
146
+ const idA = pool?.asset_a || pool?.asset_ids?.[0];
147
+ const idB = pool?.asset_b || pool?.asset_ids?.[1];
148
+ if (idA && idB) {
149
+ const assets = typeof db.get_assets === 'function' ? await db.get_assets([String(idA), String(idB)]) : null;
150
+ // Tolerate both [..] and [[..]] result shapes.
151
+ const list = Array.isArray(assets) ? assets.flat(Infinity) : [];
152
+ const metaA = list.find((a) => String(a?.id) === String(idA));
153
+ const metaB = list.find((a) => String(a?.id) === String(idB));
154
+ if (metaA && metaB) {
155
+ return {
156
+ assetA: { id: String(metaA.id), precision: Number(metaA.precision), symbol: String(metaA.symbol || idA) },
157
+ assetB: { id: String(metaB.id), precision: Number(metaB.precision), symbol: String(metaB.symbol || idB) },
158
+ };
159
+ }
160
+ }
161
+ }
162
+ catch (_) {
163
+ // Fall through to Kibana discovery below.
164
+ }
165
+ }
166
+ // Fallback: Kibana discovery (what went into the pool) + chain precision lookup.
167
+ const { discoverPoolAssets } = await import('../market_adapter/inputs/kibana_source.js');
168
+ const ids = await discoverPoolAssets(fullId, {});
169
+ if (!Array.isArray(ids) || ids.length !== 2) {
170
+ throw new Error(`Pool ${fullId}: expected exactly 2 assets, discovered [${(ids || []).join(', ')}]. Pass AssetA/AssetB instead.`);
171
+ }
172
+ const [idA, idB] = ids.map(String);
173
+ const assets = await db.get_assets([idA, idB]);
174
+ const metaA = (assets || []).find((a) => String(a?.id) === idA);
175
+ const metaB = (assets || []).find((a) => String(a?.id) === idB);
176
+ if (!metaA || !metaB || !Number.isFinite(Number(metaA.precision)) || !Number.isFinite(Number(metaB.precision))) {
177
+ throw new Error(`Pool ${fullId}: failed to resolve asset metadata for ${idA}/${idB}`);
178
+ }
179
+ return {
180
+ assetA: { id: idA, precision: Number(metaA.precision), symbol: String(metaA.symbol || idA) },
181
+ assetB: { id: idB, precision: Number(metaB.precision), symbol: String(metaB.symbol || idB) },
182
+ };
183
+ }
184
+ async function run() {
185
+ // Mute chain connection chatter first — shared helper, console.error untouched.
186
+ muteChainLogs();
187
+ const { target, months, chart, priceScale, help } = parseArgs(process.argv.slice(2));
188
+ if (help || !target) {
189
+ printUsage();
190
+ if (!target && !help)
191
+ process.exit(1);
192
+ process.exit(0);
193
+ }
194
+ const lookbackHours = Math.max(1, Math.round(months * HOURS_PER_MONTH));
195
+ const bucketMs = INTERVAL_SECONDS * 1000;
196
+ const endMs = Math.floor(Date.now() / bucketMs) * bucketMs;
197
+ const startMs = endMs - lookbackHours * 3600 * 1000;
198
+ const timeRange = { gte: new Date(startMs).toISOString(), lte: new Date(endMs).toISOString() };
199
+ // Classify the target locally first so a typo'd bot / malformed pair
200
+ // fails fast without waiting for a chain connection.
201
+ const botHit = findBotByTarget(target);
202
+ const poolTarget = !botHit && isPoolIdTarget(target);
203
+ const pairTarget = !botHit && !poolTarget && target.includes('/');
204
+ const pairParts = pairTarget ? target.split('/').map((s) => s.trim()).filter(Boolean) : [];
205
+ if (!botHit && !poolTarget && !pairTarget) {
206
+ const settings = loadBotSettings();
207
+ const entries = Array.isArray(settings?.bots) ? settings.bots : [];
208
+ const keys = entries.map((b, i) => computeBotKey(b, i)).filter(Boolean);
209
+ throw new Error(`Unknown target "${target}". Use a bot name/key${keys.length ? ` (${keys.slice(0, 8).join(', ')}${keys.length > 8 ? ', …' : ''})` : ''}, a pool id (e.g. 133), or AssetA/AssetB.`);
210
+ }
211
+ if (pairTarget && pairParts.length !== 2)
212
+ throw new Error(`Invalid pair "${target}". Use AssetA/AssetB, e.g. TOKENA/TOKENB`);
213
+ const bitsharesClient = await import('../modules/bitshares_client.js');
214
+ const { waitForConnected } = bitsharesClient;
215
+ await waitForConnected();
216
+ let tmpFile = null;
217
+ try {
218
+ let assetA;
219
+ let assetB;
220
+ let poolId = null;
221
+ let sourceLabel = '';
222
+ let botKey = null;
223
+ let botMeta = null;
224
+ if (botHit) {
225
+ botKey = botHit.botKey;
226
+ botMeta = botHit.meta;
227
+ const symA = botMeta.assetA;
228
+ const symB = botMeta.assetB;
229
+ if (!symA || !symB)
230
+ throw new Error(`Bot '${target}' has no assetA/assetB pair in profiles/bots.json`);
231
+ const [metaA, metaB] = await Promise.all([resolveAsset(symA, bitsharesClient), resolveAsset(symB, bitsharesClient)]);
232
+ assetA = { id: metaA.id, precision: metaA.precision, symbol: symA };
233
+ assetB = { id: metaB.id, precision: metaB.precision, symbol: symB };
234
+ try {
235
+ poolId = (await findPoolByAssets(assetA.id, assetB.id, { bitsharesClient, sortBy: 'assetABalance' })).id;
236
+ }
237
+ catch (_) {
238
+ poolId = null;
239
+ }
240
+ sourceLabel = poolId ? `pool ${poolId}` : 'orderbook';
241
+ }
242
+ else if (poolTarget) {
243
+ poolId = normalizePoolId(target.trim());
244
+ const resolved = await resolvePoolAssets(poolId, bitsharesClient);
245
+ assetA = resolved.assetA;
246
+ assetB = resolved.assetB;
247
+ sourceLabel = `pool ${poolId}`;
248
+ }
249
+ else {
250
+ const [metaA, metaB] = await Promise.all([resolveAsset(pairParts[0], bitsharesClient), resolveAsset(pairParts[1], bitsharesClient)]);
251
+ assetA = { id: metaA.id, precision: metaA.precision, symbol: pairParts[0] };
252
+ assetB = { id: metaB.id, precision: metaB.precision, symbol: pairParts[1] };
253
+ try {
254
+ poolId = (await findPoolByAssets(assetA.id, assetB.id, { bitsharesClient, sortBy: 'assetABalance' })).id;
255
+ }
256
+ catch (_) {
257
+ poolId = null;
258
+ }
259
+ sourceLabel = poolId ? `pool ${poolId}` : 'orderbook';
260
+ }
261
+ // ── Data pull (the only job of this script) ──────────────────────────
262
+ // Both paths reuse the existing Kibana infrastructure in 1-month
263
+ // windows: LP goes through the fetcher's manifest/resume + per-chunk
264
+ // timeout/retry machinery, book fills use the same windowing with the
265
+ // shared mergeCandles helper. No fetch logic is duplicated here.
266
+ const TV_CHUNK_MONTHS = 1;
267
+ console.log(`[tv] Fetching 1h candles (${months}mo, ${timeRange.gte.slice(0, 10)} → ${timeRange.lte.slice(0, 10)}) from ${sourceLabel} for ${assetA.symbol}/${assetB.symbol}...`);
268
+ let candles;
269
+ if (poolId) {
270
+ candles = await fetchCandlesSequentially(poolId, assetA, assetB, {
271
+ intervalSeconds: INTERVAL_SECONDS,
272
+ timeRange,
273
+ chunkMonths: TV_CHUNK_MONTHS,
274
+ }, outputPath(poolId, INTERVAL_SECONDS, assetA, assetB));
275
+ }
276
+ else {
277
+ const windows = buildFetchWindowsFromRange(timeRange, TV_CHUNK_MONTHS);
278
+ let merged = [];
279
+ for (let w = 0; w < windows.length; w++) {
280
+ console.log(` Window ${w + 1}/${windows.length}: ${windows[w].gte.slice(0, 10)} → ${windows[w].lte.slice(0, 10)}`);
281
+ const part = await getMarketCandles(assetA, assetB, { intervalSeconds: INTERVAL_SECONDS, timeRange: windows[w] });
282
+ console.log(` -> ${part.length} candles`);
283
+ merged = merged.length === 0
284
+ ? part
285
+ : mergeCandles(merged, part, {
286
+ onCollision: (existing, incoming) => incoming[5] > existing[5] ? incoming : existing,
287
+ });
288
+ }
289
+ candles = merged;
290
+ }
291
+ if (!Array.isArray(candles) || candles.length === 0)
292
+ throw new Error('No candles returned for the requested range');
293
+ console.log(`[tv] Fetched ${candles.length} candles`);
294
+ tmpFile = path.join(os.tmpdir(), `dexbot-tv-${sanitizeKey(botKey || assetA.symbol + '-' + assetB.symbol)}-${process.pid}.json`);
295
+ fs.writeFileSync(tmpFile, JSON.stringify({
296
+ meta: {
297
+ fetchedAt: new Date().toISOString(),
298
+ source: `dexbot tv (${sourceLabel})`,
299
+ pool: poolId,
300
+ assetA: { id: assetA.id, precision: assetA.precision, symbol: assetA.symbol },
301
+ assetB: { id: assetB.id, precision: assetB.precision, symbol: assetB.symbol },
302
+ intervalSeconds: INTERVAL_SECONDS,
303
+ lookbackHours,
304
+ format: '[timestamp_ms, open, high, low, close, volume_A]',
305
+ },
306
+ candles,
307
+ }), 'utf8');
308
+ // ── Delegate rendering to the existing TradingView exporter ──────────
309
+ const analyzer = path.join(__dirname, '..', 'analysis', 'tradingview', 'analyze_tradingview.js');
310
+ if (!fs.existsSync(analyzer))
311
+ throw new Error(`TradingView exporter not found at ${analyzer} (run npm run build first)`);
312
+ const baseName = botKey
313
+ ? `tv_${sanitizeKey(botKey)}`
314
+ : poolId
315
+ ? `tv_pool_${String(poolId).replace(/^1\.19\./, '')}`
316
+ : `tv_${slugPart(assetA.symbol)}_${slugPart(assetB.symbol)}`;
317
+ const chartFile = chart
318
+ ? path.resolve(chart)
319
+ : path.join(PATHS.ANALYSIS.CHARTS_DIR, `${baseName}_1h_${monthsLabel(months)}.html`);
320
+ const label = poolId ? `Pool ${String(poolId).replace(/^1\.19\./, '')}` : `${assetA.symbol}/${assetB.symbol}`;
321
+ const title = botKey && botMeta?.name ? `${botMeta.name} · ${label} · 1h · TradingView` : `${label} · 1h · TradingView`;
322
+ const analyzerArgs = ['--file', tmpFile, '--chart', chartFile, '--title', title, '--scale', priceScale];
323
+ if (botKey) {
324
+ // Same AMA overlay the exporter resolves for this bot.
325
+ const ama = resolveAmaConfig(botKey);
326
+ analyzerArgs.push('--bot-key', botKey, '--ama-er-period', String(ama.erPeriod), '--ama-fast-period', String(ama.fastPeriod), '--ama-slow-period', String(ama.slowPeriod));
327
+ }
328
+ const result = spawnSync(process.execPath, [analyzer, ...analyzerArgs], { stdio: 'inherit' });
329
+ if (result.error)
330
+ throw result.error;
331
+ if (result.status !== 0)
332
+ throw new Error(`TradingView exporter exited with status ${result.status}`);
333
+ try {
334
+ fs.unlinkSync(tmpFile);
335
+ }
336
+ catch (_) { /* keep on failure path only */ }
337
+ tmpFile = null;
338
+ }
339
+ finally {
340
+ try {
341
+ const { disconnectClient: dc } = await import('../modules/bitshares_client.js');
342
+ dc();
343
+ }
344
+ catch (_) { /* best-effort */ }
345
+ // The BitShares WS + node monitor keep the event loop alive; exit explicitly.
346
+ setTimeout(() => process.exit(0), 50).unref();
347
+ }
348
+ }
349
+ const invoked = process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href;
350
+ if (invoked) {
351
+ run().catch((err) => {
352
+ console.error(`[tv] Error: ${getErrorMessage(err)}`);
353
+ process.exit(1);
354
+ });
355
+ }
356
+ export { parseArgs, isPoolIdTarget };
357
+ //# sourceMappingURL=tv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tv.js","sourceRoot":"","sources":["../../scripts/tv.ts"],"names":[],"mappings":"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"}
@@ -45,11 +45,12 @@ import { Config } from '../modules/config.js';
45
45
  import { getStorage } from '../modules/storage/index.js';
46
46
  const { readJSON } = getStorage();
47
47
  import { getErrorMessage } from '../modules/utils/errors.js';
48
+ import { CLI_COLORS } from '../modules/cli_colors.js';
48
49
  const UPDATE_COLORS = {
49
- reset: '\x1b[0m',
50
- ok: '\x1b[1;92m',
51
- warn: '\x1b[1;33m',
52
- error: '\x1b[1;31m',
50
+ reset: CLI_COLORS.reset,
51
+ ok: CLI_COLORS.brightGreen,
52
+ warn: CLI_COLORS.yellowBold,
53
+ error: CLI_COLORS.boldRed,
53
54
  };
54
55
  function colorUpdateOutput(text, color, stream = process.stdout) {
55
56
  return stream.isTTY && !Config.NO_COLOR
@@ -339,6 +340,51 @@ function resolveStashRef(message) {
339
340
  }
340
341
  return 'stash@{0}';
341
342
  }
343
+ /**
344
+ * needsDepsInstall: post-pull check whether `npm install` is required.
345
+ *
346
+ * Only pre-state is the starting commit SHA (captured before
347
+ * checkout/pull, passed in); the decision itself happens after the pull:
348
+ * - `node_modules` missing or without npm's hidden lockfile (broken tree)
349
+ * -> install.
350
+ * - `package.json`/`package-lock.json` changed since the pre-update
351
+ * commit (covers branch switch + pull) -> install.
352
+ * - those files dirty in the worktree (e.g. stash-restored local edits)
353
+ * -> install (fail-open).
354
+ * Fail-open (true) on any git error so a broken check never skips a
355
+ * needed install.
356
+ */
357
+ function needsDepsInstall(preUpdateHead) {
358
+ if (!fs.existsSync(path.join(PATHS.PROJECT_ROOT, 'node_modules'))
359
+ || !fs.existsSync(path.join(PATHS.PROJECT_ROOT, 'node_modules', '.package-lock.json'))) {
360
+ log('node_modules missing or incomplete — dependencies need install.');
361
+ return true;
362
+ }
363
+ // Diff since the pre-update commit: covers branch switch + pull.
364
+ // Falls back to HEAD@{1} when the SHA capture failed.
365
+ const baseRef = preUpdateHead || 'HEAD@{1}';
366
+ try {
367
+ const pulled = execSync(`git diff --name-only ${baseRef} HEAD -- package.json package-lock.json 2>/dev/null`, { stdio: 'pipe', cwd: PATHS.PROJECT_ROOT }).toString().trim();
368
+ if (pulled) {
369
+ log(`Dependency manifests changed in pull: ${pulled.split('\n').join(', ')}`);
370
+ return true;
371
+ }
372
+ }
373
+ catch (_) {
374
+ return true;
375
+ }
376
+ try {
377
+ const dirty = execSync('git status --porcelain -- package.json package-lock.json 2>/dev/null', { stdio: 'pipe', cwd: PATHS.PROJECT_ROOT }).toString().trim();
378
+ if (dirty) {
379
+ log('Dependency manifests have local modifications — dependencies need install.');
380
+ return true;
381
+ }
382
+ }
383
+ catch (_) {
384
+ return true;
385
+ }
386
+ return false;
387
+ }
342
388
  async function detectIsolatedSupervisor() {
343
389
  try {
344
390
  const resp = await sendControlCommand({ cmd: 'status' });
@@ -748,6 +794,13 @@ async function runNpmUpdateFlow() {
748
794
  const snapshot = snapshotMonolithicState();
749
795
  const monolithicWasRunning = snapshot.monolithicWasRunning;
750
796
  const hadMonolithicFiles = snapshot.hadMonolithicFiles;
797
+ // Starting commit for the post-pull dep check (covers both branch
798
+ // switch and pull — the decision itself still happens after).
799
+ let preUpdateHead = '';
800
+ try {
801
+ preUpdateHead = execSync('git rev-parse HEAD', { stdio: 'pipe', cwd: PATHS.PROJECT_ROOT }).toString().trim();
802
+ }
803
+ catch (_) { }
751
804
  /**
752
805
  * STEP 6b: Prepare Working Directory
753
806
  * Stashes local changes to ensure a clean pull.
@@ -791,6 +844,7 @@ async function runNpmUpdateFlow() {
791
844
  * remote content) and `--theirs` is the stashed content (the user's
792
845
  * local edits). Local changes take precedence over incoming remote.
793
846
  */
847
+ let lockRegenerated = false;
794
848
  if (stashed) {
795
849
  const stashRef = resolveStashRef(STASH_MESSAGE);
796
850
  log('Restoring stashed changes...');
@@ -824,28 +878,41 @@ async function runNpmUpdateFlow() {
824
878
  if (unmerged.includes('package-lock.json')) {
825
879
  log('package-lock.json was conflicted — regenerating...');
826
880
  execSync('npm install --prefer-offline --ignore-scripts 2>&1', { stdio: 'pipe', cwd: PATHS.PROJECT_ROOT });
881
+ lockRegenerated = true;
827
882
  }
828
883
  }
829
884
  }
830
885
  catch (_) { }
831
886
  }
832
887
  /**
833
- * STEP 8: Reinstall Dependencies
834
- * Updates npm packages to versions specified in package-lock.json.
888
+ * STEP 8: Reinstall Dependencies (only when needed)
889
+ * Runs `npm install` when the pull touched package.json/package-lock.json,
890
+ * when those files are dirty (stash-restored local edits), or when
891
+ * node_modules is missing/incomplete. Otherwise skips — the build below
892
+ * is what picks up pure .ts changes.
835
893
  * --ignore-scripts prevents npm from running the package `prepare` hook,
836
894
  * which would build once here before the explicit build step below.
837
895
  * --prefer-offline: Uses cached packages when possible
838
896
  */
839
- log('Updating dependencies...');
840
- run('npm install --prefer-offline --ignore-scripts');
897
+ if (lockRegenerated) {
898
+ log('Dependencies already regenerated after lockfile conflict — skipping npm install.');
899
+ }
900
+ else if (needsDepsInstall(preUpdateHead)) {
901
+ log('Updating dependencies...');
902
+ run('npm install --prefer-offline --ignore-scripts');
903
+ }
904
+ else {
905
+ log('Dependencies unchanged — skipping npm install.');
906
+ }
841
907
  /**
842
908
  * STEP 8b: Build TypeScript sources
843
909
  *
844
910
  * Do NOT rely on the npm `prepare` hook. The `prepare` script only re-fires
845
911
  * when package.json itself changes, not when only .ts source files are
846
912
  * updated. After a `git pull` that touches only .ts files, `npm install`
847
- * is a no-op, `tsc` never runs, and the running bot process keeps loading
848
- * the stale dist/ bundle — with no error surfaced to the operator.
913
+ * is skipped as a no-op (see STEP 8), so `tsc` would never run and the
914
+ * running bot process would keep loading the stale dist/ bundle — with
915
+ * no error surfaced to the operator.
849
916
  *
850
917
  * Always run the explicit build here so the next PM2 restart picks up
851
918
  * the new code. The staleness check at the end of this step is defense