dexbot 1.6.3 → 1.6.4
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.
- package/CHANGELOG.md +38 -2
- package/README.md +11 -7
- package/analysis/README.md +18 -12
- package/analysis/account_resolver.ts +171 -0
- package/analysis/ama_fitting/analyze_lambda_vs_slow.ts +2 -5
- package/analysis/ama_fitting/package.json +1 -1
- package/analysis/bot_usage/discover_bot_accounts.ts +20 -27
- package/analysis/chain_pool.ts +47 -0
- package/analysis/chart_utils.ts +33 -20
- package/analysis/derivative_chart_generator.ts +2 -3
- package/analysis/fills_source.ts +234 -0
- package/analysis/grid_correction_check.ts +38 -251
- package/analysis/trade_profitability.ts +169 -304
- package/analysis/tradingview/README.md +2 -2
- package/analysis/tradingview/tradingview_uplot_chart_generator.ts +3 -4
- package/analysis/trend_detection/dynamic_weight_chart_generator.ts +2 -3
- package/analysis/trend_detection/kalman_chart_generator.ts +2 -3
- package/analysis/trend_detection/package.json +1 -1
- package/analysis/trend_detection/regime_chart_generator.ts +2 -3
- package/analysis/trend_detection/volatility_chart_generator.ts +2 -3
- package/claw/package.json +1 -1
- package/claw/runtimes/openclaw-plugin/openclaw.plugin.json +1 -1
- package/claw/runtimes/openclaw-plugin/package.json +1 -1
- package/claw/tests/test_claw_mcp_transport.ts +2 -2
- package/dist/analysis/account_resolver.d.ts +43 -0
- package/dist/analysis/account_resolver.d.ts.map +1 -0
- package/dist/analysis/account_resolver.js +137 -0
- package/dist/analysis/account_resolver.js.map +1 -0
- package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.d.ts.map +1 -1
- package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.js +2 -4
- package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.js.map +1 -1
- package/dist/analysis/bot_usage/discover_bot_accounts.js +20 -28
- package/dist/analysis/bot_usage/discover_bot_accounts.js.map +1 -1
- package/dist/analysis/chain_pool.d.ts +10 -0
- package/dist/analysis/chain_pool.d.ts.map +1 -0
- package/dist/analysis/chain_pool.js +47 -0
- package/dist/analysis/chain_pool.js.map +1 -0
- package/dist/analysis/chart_utils.d.ts +14 -1
- package/dist/analysis/chart_utils.d.ts.map +1 -1
- package/dist/analysis/chart_utils.js +32 -22
- package/dist/analysis/chart_utils.js.map +1 -1
- package/dist/analysis/derivative_chart_generator.d.ts.map +1 -1
- package/dist/analysis/derivative_chart_generator.js +2 -3
- package/dist/analysis/derivative_chart_generator.js.map +1 -1
- package/dist/analysis/fills_source.d.ts +79 -0
- package/dist/analysis/fills_source.d.ts.map +1 -0
- package/dist/analysis/fills_source.js +186 -0
- package/dist/analysis/fills_source.js.map +1 -0
- package/dist/analysis/grid_correction_check.d.ts +1 -21
- package/dist/analysis/grid_correction_check.d.ts.map +1 -1
- package/dist/analysis/grid_correction_check.js +30 -257
- package/dist/analysis/grid_correction_check.js.map +1 -1
- package/dist/analysis/trade_profitability.d.ts +18 -19
- package/dist/analysis/trade_profitability.d.ts.map +1 -1
- package/dist/analysis/trade_profitability.js +136 -280
- package/dist/analysis/trade_profitability.js.map +1 -1
- package/dist/analysis/tradingview/tradingview_uplot_chart_generator.d.ts.map +1 -1
- package/dist/analysis/tradingview/tradingview_uplot_chart_generator.js +3 -4
- package/dist/analysis/tradingview/tradingview_uplot_chart_generator.js.map +1 -1
- package/dist/analysis/trend_detection/dynamic_weight_chart_generator.d.ts.map +1 -1
- package/dist/analysis/trend_detection/dynamic_weight_chart_generator.js +2 -3
- package/dist/analysis/trend_detection/dynamic_weight_chart_generator.js.map +1 -1
- package/dist/analysis/trend_detection/kalman_chart_generator.d.ts.map +1 -1
- package/dist/analysis/trend_detection/kalman_chart_generator.js +2 -3
- package/dist/analysis/trend_detection/kalman_chart_generator.js.map +1 -1
- package/dist/analysis/trend_detection/regime_chart_generator.d.ts.map +1 -1
- package/dist/analysis/trend_detection/regime_chart_generator.js +2 -3
- package/dist/analysis/trend_detection/regime_chart_generator.js.map +1 -1
- package/dist/analysis/trend_detection/volatility_chart_generator.d.ts.map +1 -1
- package/dist/analysis/trend_detection/volatility_chart_generator.js +2 -3
- package/dist/analysis/trend_detection/volatility_chart_generator.js.map +1 -1
- package/dist/market_adapter/lp_chart_core.d.ts.map +1 -1
- package/dist/market_adapter/lp_chart_core.js +2 -3
- package/dist/market_adapter/lp_chart_core.js.map +1 -1
- package/dist/modules/account_bots.d.ts +1 -18
- package/dist/modules/account_bots.d.ts.map +1 -1
- package/dist/modules/account_bots.js +1 -1
- package/dist/modules/account_bots.js.map +1 -1
- package/dist/modules/bitshares-native/serial/operations.d.ts +1 -84
- package/dist/modules/bitshares-native/serial/operations.d.ts.map +1 -1
- package/dist/modules/bitshares-native/serial/operations.js +1 -38
- package/dist/modules/bitshares-native/serial/operations.js.map +1 -1
- package/dist/modules/cli_colors.d.ts +0 -1
- package/dist/modules/cli_colors.d.ts.map +1 -1
- package/dist/modules/constants.js +5 -5
- package/dist/modules/constants.js.map +1 -1
- package/dist/modules/credential_policy.d.ts +1 -25
- package/dist/modules/credential_policy.d.ts.map +1 -1
- package/dist/modules/credential_policy.js +1 -1
- package/dist/modules/credential_policy.js.map +1 -1
- package/dist/modules/credential_runtime.d.ts +1 -6
- package/dist/modules/credential_runtime.d.ts.map +1 -1
- package/dist/modules/credential_runtime.js +1 -1
- package/dist/modules/credential_runtime.js.map +1 -1
- package/dist/modules/credential_session_cache.d.ts +1 -5
- package/dist/modules/credential_session_cache.d.ts.map +1 -1
- package/dist/modules/credential_session_cache.js +1 -1
- package/dist/modules/credential_session_cache.js.map +1 -1
- package/dist/modules/crypto/pure_secp256k1.d.ts +1 -2
- package/dist/modules/crypto/pure_secp256k1.d.ts.map +1 -1
- package/dist/modules/crypto/pure_secp256k1.js +1 -1
- package/dist/modules/crypto/pure_secp256k1.js.map +1 -1
- package/dist/modules/dexbot_class.d.ts +8 -7
- package/dist/modules/dexbot_class.d.ts.map +1 -1
- package/dist/modules/dexbot_class.js +9 -8
- package/dist/modules/dexbot_class.js.map +1 -1
- package/dist/modules/dexbot_cow_runtime.d.ts +7 -6
- package/dist/modules/dexbot_cow_runtime.d.ts.map +1 -1
- package/dist/modules/dexbot_cow_runtime.js +8 -7
- package/dist/modules/dexbot_cow_runtime.js.map +1 -1
- package/dist/modules/dexbot_fill_runtime.d.ts +1 -17
- package/dist/modules/dexbot_fill_runtime.d.ts.map +1 -1
- package/dist/modules/dexbot_fill_runtime.js +1 -1
- package/dist/modules/dexbot_fill_runtime.js.map +1 -1
- package/dist/modules/dexbot_maintenance_runtime.d.ts +1 -1
- package/dist/modules/dexbot_maintenance_runtime.d.ts.map +1 -1
- package/dist/modules/dexbot_maintenance_runtime.js +15 -4
- package/dist/modules/dexbot_maintenance_runtime.js.map +1 -1
- package/dist/modules/dexbot_state_recovery.d.ts +1 -7
- package/dist/modules/dexbot_state_recovery.d.ts.map +1 -1
- package/dist/modules/dexbot_state_recovery.js +1 -1
- package/dist/modules/dexbot_state_recovery.js.map +1 -1
- package/dist/modules/launcher/adapter_requirement.d.ts +1 -5
- package/dist/modules/launcher/adapter_requirement.d.ts.map +1 -1
- package/dist/modules/launcher/adapter_requirement.js +1 -1
- package/dist/modules/launcher/adapter_requirement.js.map +1 -1
- package/dist/modules/launcher/bot_supervisor.d.ts +1 -6
- package/dist/modules/launcher/bot_supervisor.d.ts.map +1 -1
- package/dist/modules/launcher/bot_supervisor.js +1 -1
- package/dist/modules/launcher/bot_supervisor.js.map +1 -1
- package/dist/modules/launcher/foreign_cred_daemon.d.ts +1 -3
- package/dist/modules/launcher/foreign_cred_daemon.d.ts.map +1 -1
- package/dist/modules/launcher/foreign_cred_daemon.js +1 -1
- package/dist/modules/launcher/foreign_cred_daemon.js.map +1 -1
- package/dist/modules/launcher/launch_modes.d.ts +1 -2
- package/dist/modules/launcher/launch_modes.d.ts.map +1 -1
- package/dist/modules/launcher/launch_modes.js +1 -1
- package/dist/modules/launcher/launch_modes.js.map +1 -1
- package/dist/modules/launcher/market_adapter_runtime.d.ts +1 -3
- package/dist/modules/launcher/market_adapter_runtime.d.ts.map +1 -1
- package/dist/modules/launcher/market_adapter_runtime.js +1 -1
- package/dist/modules/launcher/market_adapter_runtime.js.map +1 -1
- package/dist/modules/launcher/monolithic_runtime.d.ts +1 -5
- package/dist/modules/launcher/monolithic_runtime.d.ts.map +1 -1
- package/dist/modules/launcher/monolithic_runtime.js +1 -1
- package/dist/modules/launcher/monolithic_runtime.js.map +1 -1
- package/dist/modules/launcher/status_reporting.d.ts +1 -2
- package/dist/modules/launcher/status_reporting.d.ts.map +1 -1
- package/dist/modules/launcher/status_reporting.js +1 -1
- package/dist/modules/launcher/status_reporting.js.map +1 -1
- package/dist/modules/order/export.d.ts +1 -8
- package/dist/modules/order/export.d.ts.map +1 -1
- package/dist/modules/order/export.js +1 -1
- package/dist/modules/order/export.js.map +1 -1
- package/dist/modules/order/grid.d.ts +7 -0
- package/dist/modules/order/grid.d.ts.map +1 -1
- package/dist/modules/order/grid.js +52 -98
- package/dist/modules/order/grid.js.map +1 -1
- package/dist/modules/order/grid_reconcile_internal.d.ts +1 -10
- package/dist/modules/order/grid_reconcile_internal.d.ts.map +1 -1
- package/dist/modules/order/grid_reconcile_internal.js +2 -2
- package/dist/modules/order/grid_reconcile_internal.js.map +1 -1
- package/dist/modules/order/manager.d.ts +10 -2
- package/dist/modules/order/manager.d.ts.map +1 -1
- package/dist/modules/order/manager.js +17 -6
- package/dist/modules/order/manager.js.map +1 -1
- package/dist/modules/order/sync_engine.d.ts.map +1 -1
- package/dist/modules/order/sync_engine.js +8 -15
- package/dist/modules/order/sync_engine.js.map +1 -1
- package/dist/modules/order/utils/math.d.ts +1 -10
- package/dist/modules/order/utils/math.d.ts.map +1 -1
- package/dist/modules/order/utils/math.js +1 -1
- package/dist/modules/order/utils/math.js.map +1 -1
- package/dist/modules/order/utils/system.d.ts +0 -15
- package/dist/modules/order/utils/system.d.ts.map +1 -1
- package/dist/modules/order/utils/system.js +2 -2
- package/dist/modules/order/utils/system.js.map +1 -1
- package/dist/modules/process_discovery.d.ts +0 -3
- package/dist/modules/process_discovery.d.ts.map +1 -1
- package/dist/modules/process_discovery.js +1 -1
- package/dist/modules/process_discovery.js.map +1 -1
- package/dist/modules/utils/chain_logs.d.ts +1 -2
- package/dist/modules/utils/chain_logs.d.ts.map +1 -1
- package/dist/modules/utils/chain_logs.js +1 -1
- package/dist/modules/utils/chain_logs.js.map +1 -1
- package/dist/scripts/analyze-git.js +2 -2
- package/dist/scripts/analyze-git.js.map +1 -1
- package/dist/scripts/update.js +46 -31
- package/dist/scripts/update.js.map +1 -1
- package/docs/BITSHARES_ONBOARDING.md +110 -40
- package/docs/COPY_ON_WRITE_MASTER_PLAN.md +10 -207
- package/docs/COW_INVARIANTS.md +16 -10
- package/docs/DEXBOT_COMPARISON.md +3 -3
- package/docs/EVOLUTION.md +75 -30
- package/docs/FUND_MOVEMENT_AND_ACCOUNTING.md +6 -6
- package/docs/GRID_RECALCULATION.md +14 -6
- package/docs/GRID_RECONCILE.md +28 -25
- package/docs/LIFECYCLE.md +12 -11
- package/docs/README.md +48 -42
- package/docs/architecture.md +19 -30
- package/docs/developer_guide.md +3 -3
- package/package.json +1 -1
- package/scripts/git-viewer.sh +1 -1
- package/tests/README.md +10 -1
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/**
|
|
3
|
+
* SHARED FILLS SOURCE (analysis)
|
|
4
|
+
*
|
|
5
|
+
* Single implementation of the Kibana `fill_order` pipeline and the asset
|
|
6
|
+
* precision table/cache used by the fill-based analysis tools. Both
|
|
7
|
+
* trade_profitability.ts and grid_correction_check.ts carried verbatim copies
|
|
8
|
+
* of this (43-entry ASSETS table, toReal/assetPrec helpers, on-chain precision
|
|
9
|
+
* resolution, query builder and paginated fetch); all of it lives here now.
|
|
10
|
+
*/
|
|
11
|
+
import * as KC from '../market_adapter/core/kibana_client.js';
|
|
12
|
+
import { withReadOnlyClient } from './chain_pool.js';
|
|
13
|
+
const { kibanaSearch, DEFAULT_CONFIG: BASE_CONFIG } = KC;
|
|
14
|
+
/** operation_type of a fill_order operation in the chain history index. */
|
|
15
|
+
const OP_FILL_ORDER = 4;
|
|
16
|
+
const BTS_ID = '1.3.0';
|
|
17
|
+
const ASSETS = {
|
|
18
|
+
'1.3.0': { symbol: 'BTS', precision: 5 },
|
|
19
|
+
'1.3.118': { symbol: 'GBP', precision: 4 },
|
|
20
|
+
'1.3.119': { symbol: 'JPY', precision: 2 },
|
|
21
|
+
'1.3.120': { symbol: 'EUR', precision: 4 },
|
|
22
|
+
'1.3.1325': { symbol: 'RUBLE', precision: 5 },
|
|
23
|
+
'1.3.2512': { symbol: 'EVRAZ', precision: 4 },
|
|
24
|
+
'1.3.3291': { symbol: 'TWENTIX', precision: 5 },
|
|
25
|
+
'1.3.4099': { symbol: 'XBTSX.STH', precision: 6 },
|
|
26
|
+
'1.3.4156': { symbol: 'XBTSX.DOGE', precision: 5 },
|
|
27
|
+
'1.3.4157': { symbol: 'XBTSX.BTC', precision: 8 },
|
|
28
|
+
'1.3.4159': { symbol: 'XBTSX.LTC', precision: 8 },
|
|
29
|
+
'1.3.4176': { symbol: 'XBTSX.DASH', precision: 8 },
|
|
30
|
+
'1.3.4274': { symbol: 'XBTSX.BCH', precision: 8 },
|
|
31
|
+
'1.3.4760': { symbol: 'XBTSX.ETH', precision: 7 },
|
|
32
|
+
'1.3.5537': { symbol: 'IOB.XRP', precision: 4 },
|
|
33
|
+
'1.3.5541': { symbol: 'XBTSX.BNB', precision: 7 },
|
|
34
|
+
'1.3.5589': { symbol: 'XBTSX.USDT', precision: 6 },
|
|
35
|
+
'1.3.5641': { symbol: 'HONEST.CNY', precision: 4 },
|
|
36
|
+
'1.3.5649': { symbol: 'HONEST.USD', precision: 4 },
|
|
37
|
+
'1.3.5650': { symbol: 'HONEST.BTC', precision: 8 },
|
|
38
|
+
'1.3.5659': { symbol: 'HONEST.ETH', precision: 6 },
|
|
39
|
+
'1.3.5870': { symbol: 'XBTSX.FIL', precision: 6 },
|
|
40
|
+
'1.3.5887': { symbol: 'XBTSX.RUB', precision: 4 },
|
|
41
|
+
'1.3.5902': { symbol: 'XBTSX.USDC', precision: 6 },
|
|
42
|
+
'1.3.6013': { symbol: 'XBTSX.HIVE', precision: 6 },
|
|
43
|
+
'1.3.6124': { symbol: 'XBTSX.AVAX', precision: 6 },
|
|
44
|
+
'1.3.6139': { symbol: 'XBTSX.XAUT', precision: 6 },
|
|
45
|
+
'1.3.6166': { symbol: 'XBTSX.MATIC', precision: 5 },
|
|
46
|
+
'1.3.6241': { symbol: 'XBTSX.ETC', precision: 7 },
|
|
47
|
+
'1.3.6268': { symbol: 'BTWTY.EOS', precision: 4 },
|
|
48
|
+
'1.3.6301': { symbol: 'HONEST.MONEY', precision: 8 },
|
|
49
|
+
'1.3.6304': { symbol: 'HONEST.ADA', precision: 8 },
|
|
50
|
+
'1.3.6305': { symbol: 'HONEST.DOT', precision: 8 },
|
|
51
|
+
'1.3.6309': { symbol: 'HONEST.ATOM', precision: 8 },
|
|
52
|
+
'1.3.6311': { symbol: 'HONEST.ALGO', precision: 8 },
|
|
53
|
+
'1.3.6312': { symbol: 'HONEST.FIL', precision: 8 },
|
|
54
|
+
'1.3.6313': { symbol: 'HONEST.EOS', precision: 8 },
|
|
55
|
+
'1.3.6315': { symbol: 'HONEST.EUR', precision: 4 },
|
|
56
|
+
'1.3.6316': { symbol: 'HONEST.GBP', precision: 4 },
|
|
57
|
+
'1.3.6317': { symbol: 'HONEST.JPY', precision: 4 },
|
|
58
|
+
'1.3.6444': { symbol: 'IOB.XLM', precision: 4 },
|
|
59
|
+
'1.3.6573': { symbol: 'XBTSX.DAI', precision: 6 },
|
|
60
|
+
'1.3.6620': { symbol: 'XBTSX.A', precision: 6 },
|
|
61
|
+
'1.3.6627': { symbol: 'XBTSX.LINK', precision: 6 },
|
|
62
|
+
};
|
|
63
|
+
/** Precisions learned on-chain this run (populated by resolveAssetPrecisions). */
|
|
64
|
+
const resolvedPrecisions = {};
|
|
65
|
+
function assetSymbol(id) {
|
|
66
|
+
return ASSETS[id]?.symbol ?? id;
|
|
67
|
+
}
|
|
68
|
+
function assetPrec(id) {
|
|
69
|
+
return ASSETS[id]?.precision ?? resolvedPrecisions[id];
|
|
70
|
+
}
|
|
71
|
+
function toReal(amount, assetId) {
|
|
72
|
+
const p = assetPrec(assetId);
|
|
73
|
+
if (p === undefined)
|
|
74
|
+
return NaN;
|
|
75
|
+
return amount / Math.pow(10, p);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Collect all unique non-BTS asset IDs from fills, resolve unknown precisions
|
|
79
|
+
* from the blockchain, and populate the runtime cache.
|
|
80
|
+
*/
|
|
81
|
+
async function resolveAssetPrecisions(fills) {
|
|
82
|
+
const unknownIds = new Set();
|
|
83
|
+
for (const f of fills) {
|
|
84
|
+
for (const id of [f.pays.asset_id, f.receives.asset_id, f.fee.asset_id]) {
|
|
85
|
+
if (id !== BTS_ID && !(id in ASSETS) && !(id in resolvedPrecisions)) {
|
|
86
|
+
unknownIds.add(id);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (unknownIds.size === 0)
|
|
91
|
+
return;
|
|
92
|
+
const ids = [...unknownIds];
|
|
93
|
+
console.log(` Resolving ${ids.length} unknown asset(s) from blockchain...`);
|
|
94
|
+
try {
|
|
95
|
+
await withReadOnlyClient(async (client) => {
|
|
96
|
+
const assets = await client.db('get_assets', [ids]);
|
|
97
|
+
if (Array.isArray(assets)) {
|
|
98
|
+
for (const asset of assets) {
|
|
99
|
+
if (asset?.id && asset.precision != null) {
|
|
100
|
+
resolvedPrecisions[asset.id] = asset.precision;
|
|
101
|
+
console.log(` ${asset.id} → ${asset.symbol || '?'} (precision ${asset.precision})`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const missing = ids.filter(id => !(id in resolvedPrecisions));
|
|
106
|
+
if (missing.length > 0) {
|
|
107
|
+
console.warn(` [warn] ${missing.length} asset(s) not found on chain: ${missing.join(', ')}. Fills referencing them will be skipped.`);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
catch (e) {
|
|
112
|
+
console.warn(` [warn] Asset resolution failed: ${e.message}. Fills with unknown assets will be skipped.`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function buildFillQuery(accountId, gte, lte, size) {
|
|
116
|
+
return {
|
|
117
|
+
size,
|
|
118
|
+
track_total_hits: false,
|
|
119
|
+
_source: [
|
|
120
|
+
'block_data.block_time',
|
|
121
|
+
'block_data.block_num',
|
|
122
|
+
'operation_id_num',
|
|
123
|
+
'operation_history.op_object.pays',
|
|
124
|
+
'operation_history.op_object.receives',
|
|
125
|
+
'operation_history.op_object.fee',
|
|
126
|
+
'operation_history.op_object.order_id',
|
|
127
|
+
'operation_history.op_object.account_id',
|
|
128
|
+
'operation_history.op_object.is_maker',
|
|
129
|
+
],
|
|
130
|
+
query: {
|
|
131
|
+
bool: {
|
|
132
|
+
filter: [
|
|
133
|
+
{ term: { operation_type: OP_FILL_ORDER } },
|
|
134
|
+
{ term: { 'operation_history.op_object.account_id.keyword': accountId } },
|
|
135
|
+
{ range: { 'block_data.block_time': { gte, lte } } },
|
|
136
|
+
],
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
sort: [
|
|
140
|
+
{ 'block_data.block_time': { order: 'asc' } },
|
|
141
|
+
{ operation_id_num: { order: 'asc' } },
|
|
142
|
+
],
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/** Fetch every fill_order for an account in [gte, lte], paginated via search_after. */
|
|
146
|
+
async function fetchAllFills(config, accountId, gte, lte) {
|
|
147
|
+
const pageSize = 10000;
|
|
148
|
+
const fills = [];
|
|
149
|
+
let searchAfter = null;
|
|
150
|
+
const cfg = { ...BASE_CONFIG, timeout: 60000, ...config };
|
|
151
|
+
while (true) {
|
|
152
|
+
const query = buildFillQuery(accountId, gte, lte, pageSize);
|
|
153
|
+
if (searchAfter)
|
|
154
|
+
query.search_after = searchAfter;
|
|
155
|
+
const result = await kibanaSearch(cfg, query);
|
|
156
|
+
const hits = result?.hits?.hits ?? [];
|
|
157
|
+
if (!hits.length)
|
|
158
|
+
break;
|
|
159
|
+
for (const hit of hits) {
|
|
160
|
+
const src = hit?._source;
|
|
161
|
+
const op = src?.operation_history?.op_object;
|
|
162
|
+
if (!op || !op.pays || !op.receives)
|
|
163
|
+
continue;
|
|
164
|
+
fills.push({
|
|
165
|
+
time: src.block_data?.block_time ?? '',
|
|
166
|
+
blockNum: src.block_data?.block_num ?? 0,
|
|
167
|
+
opNum: Number(src.operation_id_num ?? 0),
|
|
168
|
+
orderId: op.order_id ?? '',
|
|
169
|
+
accountId: op.account_id ?? '',
|
|
170
|
+
pays: { amount: Number(op.pays.amount ?? 0), asset_id: op.pays.asset_id ?? '' },
|
|
171
|
+
receives: { amount: Number(op.receives.amount ?? 0), asset_id: op.receives.asset_id ?? '' },
|
|
172
|
+
fee: { amount: Number(op.fee?.amount ?? 0), asset_id: op.fee?.asset_id ?? '' },
|
|
173
|
+
isMaker: op.is_maker ?? false,
|
|
174
|
+
sort: hit.sort,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
if (hits.length < pageSize)
|
|
178
|
+
break;
|
|
179
|
+
searchAfter = hits[hits.length - 1].sort;
|
|
180
|
+
if (!Array.isArray(searchAfter))
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
return fills;
|
|
184
|
+
}
|
|
185
|
+
export { BTS_ID, OP_FILL_ORDER, ASSETS, resolvedPrecisions, assetSymbol, assetPrec, toReal, resolveAssetPrecisions, buildFillQuery, fetchAllFills, };
|
|
186
|
+
//# sourceMappingURL=fills_source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fills_source.js","sourceRoot":"","sources":["../../analysis/fills_source.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,25 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
time: string;
|
|
4
|
-
blockNum: number;
|
|
5
|
-
opNum: number;
|
|
6
|
-
orderId: string;
|
|
7
|
-
accountId: string;
|
|
8
|
-
pays: {
|
|
9
|
-
amount: number;
|
|
10
|
-
asset_id: string;
|
|
11
|
-
};
|
|
12
|
-
receives: {
|
|
13
|
-
amount: number;
|
|
14
|
-
asset_id: string;
|
|
15
|
-
};
|
|
16
|
-
fee: {
|
|
17
|
-
amount: number;
|
|
18
|
-
asset_id: string;
|
|
19
|
-
};
|
|
20
|
-
isMaker: boolean;
|
|
21
|
-
sort: any[];
|
|
22
|
-
}
|
|
2
|
+
import { FillRecord } from './fills_source.js';
|
|
23
3
|
interface OrderUpdate {
|
|
24
4
|
orderId: string;
|
|
25
5
|
sequence: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grid_correction_check.d.ts","sourceRoot":"","sources":["../../analysis/grid_correction_check.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"grid_correction_check.d.ts","sourceRoot":"","sources":["../../analysis/grid_correction_check.ts"],"names":[],"mappings":";AAyCA,OAAO,EAEH,UAAU,EAMb,MAAM,mBAAmB,CAAC;AAO3B,UAAU,WAAW;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CACpB;AACD,UAAU,SAAS;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,KAAK,GAAG,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CACpB;AACD,UAAU,SAAS;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,KAAK,GAAG,MAAM,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,SAAS,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACrB;AACD,UAAU,eAAe;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,KAAK,GAAG,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;CACpB;AAID;;;;;;;;;;;GAWG;AACH,iBAAS,sBAAsB,CAC3B,KAAK,EAAE,GAAG,EACV,IAAI,EAAE,GAAG,EACT,SAAS,EAAE,GAAG,EACd,QAAQ,EAAE,GAAG,EACb,gBAAgB,EAAE,GAAG,GACtB;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAiBzF;AAsND,iBAAS,aAAa,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG;IAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAuDpF;AAKD,iBAAS,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,OAAO,GAAE,WAAW,EAAO,GAAG,eAAe,EAAE,CAyD7F;AAGD,iBAAS,gBAAgB,CACrB,KAAK,EAAE,CAAC,SAAS,GAAG,eAAe,CAAC,EAAE,EACtC,gBAAgB,EAAE,OAAO,EACzB,gBAAgB,EAAE,MAAM,GACzB;IAAE,UAAU,EAAE,SAAS,EAAE,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,kBAAkB,EAAE,MAAM,CAAA;CAAE,CAyD/E;AA4PD,OAAO,EAAE,sBAAsB,EAAE,aAAa,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC"}
|
|
@@ -35,66 +35,11 @@ import fs from 'node:fs';
|
|
|
35
35
|
import { pathToFileURL } from 'node:url';
|
|
36
36
|
import * as KC from '../market_adapter/core/kibana_client.js';
|
|
37
37
|
import * as C from '../modules/constants.js';
|
|
38
|
-
import {
|
|
38
|
+
import { loadBotSettings, computeBotKey } from './bot_key_utils.js';
|
|
39
|
+
import { resolveBotAccount } from './account_resolver.js';
|
|
40
|
+
import { BTS_ID, assetPrec, assetSymbol, fetchAllFills, resolveAssetPrecisions, toReal, } from './fills_source.js';
|
|
39
41
|
const { kibanaSearch, DEFAULT_CONFIG: BASE_CONFIG } = KC;
|
|
40
|
-
const OP_FILL_ORDER = 4;
|
|
41
42
|
const OP_LIMIT_ORDER_UPDATE = 77;
|
|
42
|
-
const BTS_ID = '1.3.0';
|
|
43
|
-
const ASSETS = {
|
|
44
|
-
'1.3.0': { symbol: 'BTS', precision: 5 },
|
|
45
|
-
'1.3.118': { symbol: 'GBP', precision: 4 },
|
|
46
|
-
'1.3.119': { symbol: 'JPY', precision: 2 },
|
|
47
|
-
'1.3.120': { symbol: 'EUR', precision: 4 },
|
|
48
|
-
'1.3.1325': { symbol: 'RUBLE', precision: 5 },
|
|
49
|
-
'1.3.2512': { symbol: 'EVRAZ', precision: 4 },
|
|
50
|
-
'1.3.3291': { symbol: 'TWENTIX', precision: 5 },
|
|
51
|
-
'1.3.4099': { symbol: 'XBTSX.STH', precision: 6 },
|
|
52
|
-
'1.3.4156': { symbol: 'XBTSX.DOGE', precision: 5 },
|
|
53
|
-
'1.3.4157': { symbol: 'XBTSX.BTC', precision: 8 },
|
|
54
|
-
'1.3.4159': { symbol: 'XBTSX.LTC', precision: 8 },
|
|
55
|
-
'1.3.4176': { symbol: 'XBTSX.DASH', precision: 8 },
|
|
56
|
-
'1.3.4274': { symbol: 'XBTSX.BCH', precision: 8 },
|
|
57
|
-
'1.3.4760': { symbol: 'XBTSX.ETH', precision: 7 },
|
|
58
|
-
'1.3.5537': { symbol: 'IOB.XRP', precision: 4 },
|
|
59
|
-
'1.3.5541': { symbol: 'XBTSX.BNB', precision: 7 },
|
|
60
|
-
'1.3.5589': { symbol: 'XBTSX.USDT', precision: 6 },
|
|
61
|
-
'1.3.5641': { symbol: 'HONEST.CNY', precision: 4 },
|
|
62
|
-
'1.3.5649': { symbol: 'HONEST.USD', precision: 4 },
|
|
63
|
-
'1.3.5650': { symbol: 'HONEST.BTC', precision: 8 },
|
|
64
|
-
'1.3.5659': { symbol: 'HONEST.ETH', precision: 6 },
|
|
65
|
-
'1.3.5870': { symbol: 'XBTSX.FIL', precision: 6 },
|
|
66
|
-
'1.3.5887': { symbol: 'XBTSX.RUB', precision: 4 },
|
|
67
|
-
'1.3.5902': { symbol: 'XBTSX.USDC', precision: 6 },
|
|
68
|
-
'1.3.6013': { symbol: 'XBTSX.HIVE', precision: 6 },
|
|
69
|
-
'1.3.6124': { symbol: 'XBTSX.AVAX', precision: 6 },
|
|
70
|
-
'1.3.6139': { symbol: 'XBTSX.XAUT', precision: 6 },
|
|
71
|
-
'1.3.6166': { symbol: 'XBTSX.MATIC', precision: 5 },
|
|
72
|
-
'1.3.6241': { symbol: 'XBTSX.ETC', precision: 7 },
|
|
73
|
-
'1.3.6268': { symbol: 'BTWTY.EOS', precision: 4 },
|
|
74
|
-
'1.3.6301': { symbol: 'HONEST.MONEY', precision: 8 },
|
|
75
|
-
'1.3.6304': { symbol: 'HONEST.ADA', precision: 8 },
|
|
76
|
-
'1.3.6305': { symbol: 'HONEST.DOT', precision: 8 },
|
|
77
|
-
'1.3.6309': { symbol: 'HONEST.ATOM', precision: 8 },
|
|
78
|
-
'1.3.6311': { symbol: 'HONEST.ALGO', precision: 8 },
|
|
79
|
-
'1.3.6312': { symbol: 'HONEST.FIL', precision: 8 },
|
|
80
|
-
'1.3.6313': { symbol: 'HONEST.EOS', precision: 8 },
|
|
81
|
-
'1.3.6315': { symbol: 'HONEST.EUR', precision: 4 },
|
|
82
|
-
'1.3.6316': { symbol: 'HONEST.GBP', precision: 4 },
|
|
83
|
-
'1.3.6317': { symbol: 'HONEST.JPY', precision: 4 },
|
|
84
|
-
'1.3.6444': { symbol: 'IOB.XLM', precision: 4 },
|
|
85
|
-
'1.3.6573': { symbol: 'XBTSX.DAI', precision: 6 },
|
|
86
|
-
'1.3.6620': { symbol: 'XBTSX.A', precision: 6 },
|
|
87
|
-
'1.3.6627': { symbol: 'XBTSX.LINK', precision: 6 },
|
|
88
|
-
};
|
|
89
|
-
const resolvedPrecisions = {};
|
|
90
|
-
function assetSymbol(id) { return ASSETS[id]?.symbol ?? id; }
|
|
91
|
-
function assetPrec(id) { return ASSETS[id]?.precision ?? resolvedPrecisions[id]; }
|
|
92
|
-
function toReal(amount, assetId) {
|
|
93
|
-
const p = assetPrec(assetId);
|
|
94
|
-
if (p === undefined)
|
|
95
|
-
return NaN;
|
|
96
|
-
return amount / Math.pow(10, p);
|
|
97
|
-
}
|
|
98
43
|
// ─── LAST-FILL-GUARD helper (1:1 with dexbot_cow_runtime.ts) ─────────────────
|
|
99
44
|
/**
|
|
100
45
|
* LAST-FILL-GUARD helper — pivot ± halfIncrement (replaces price-tolerance).
|
|
@@ -167,7 +112,6 @@ Options:
|
|
|
167
112
|
--refresh-account Force re-resolution of preferredAccount and update the
|
|
168
113
|
stored accountId when it changed (default: reuse the
|
|
169
114
|
stored accountId with no chain lookup)
|
|
170
|
-
--node <url> BitShares node URL for account / precision resolution
|
|
171
115
|
--increment <pct> Grid increment percent (default: from bot config or ${Number(C?.DEFAULT_CONFIG?.incrementPercent ?? 0.5)})
|
|
172
116
|
--tolerance <pct> Deprecated alias for --increment (kept for compat, prefer --increment)
|
|
173
117
|
--per-fill Check at fill granularity (default: per-order aggregated)
|
|
@@ -212,7 +156,6 @@ function parseArgs() {
|
|
|
212
156
|
account: null,
|
|
213
157
|
lookup: false,
|
|
214
158
|
refreshAccount: false,
|
|
215
|
-
node: C.NODE_MANAGEMENT.DEFAULT_NODES[0],
|
|
216
159
|
perFill: false,
|
|
217
160
|
includeCrossPair: false,
|
|
218
161
|
incrementPercent: null,
|
|
@@ -243,9 +186,6 @@ function parseArgs() {
|
|
|
243
186
|
case '--refresh-account':
|
|
244
187
|
opts.refreshAccount = true;
|
|
245
188
|
break;
|
|
246
|
-
case '--node':
|
|
247
|
-
opts.node = args[++i];
|
|
248
|
-
break;
|
|
249
189
|
case '--per-fill':
|
|
250
190
|
opts.perFill = true;
|
|
251
191
|
break;
|
|
@@ -321,162 +261,25 @@ function resolveTimeRange(opts) {
|
|
|
321
261
|
const label = `${gte} → ${lte}`;
|
|
322
262
|
return { gte, lte, label };
|
|
323
263
|
}
|
|
324
|
-
// ─── Account resolution
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
}
|
|
341
|
-
finally {
|
|
342
|
-
try {
|
|
343
|
-
client.disconnect();
|
|
344
|
-
}
|
|
345
|
-
catch (_) { }
|
|
346
|
-
process.env.LOG_LEVEL = prevLevel;
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
async function resolveAccountForBot(botKey, overrideAccount, nodeUrl, doRefresh) {
|
|
350
|
-
const botMeta = loadBotMeta(botKey);
|
|
351
|
-
if (!botMeta && !overrideAccount) {
|
|
352
|
-
console.error(`Error: bot key '${botKey}' not found in profiles/bots.json and no --account provided.`);
|
|
353
|
-
console.error(`Use --list-bots to see available keys, or pass --account <1.2.x> explicitly.`);
|
|
354
|
-
process.exit(1);
|
|
355
|
-
}
|
|
356
|
-
// An explicit --account always wins and is never persisted.
|
|
357
|
-
if (overrideAccount) {
|
|
358
|
-
if (/^1\.2\.\d+$/.test(String(overrideAccount))) {
|
|
359
|
-
return { accountId: String(overrideAccount), botMeta };
|
|
360
|
-
}
|
|
361
|
-
console.log(` Resolving account name '${overrideAccount}'...`);
|
|
362
|
-
const resolvedOverride = await resolveAccountId(String(overrideAccount), nodeUrl);
|
|
363
|
-
if (!resolvedOverride) {
|
|
364
|
-
console.error(`Error: failed to resolve --account '${overrideAccount}' to 1.2.x`);
|
|
365
|
-
process.exit(1);
|
|
366
|
-
}
|
|
367
|
-
console.log(` → ${resolvedOverride}`);
|
|
368
|
-
return { accountId: String(resolvedOverride), botMeta };
|
|
369
|
-
}
|
|
370
|
-
const prefRaw = botMeta?.preferredAccount != null ? String(botMeta.preferredAccount) : null;
|
|
371
|
-
const prefIsId = !!prefRaw && /^1\.2\.\d+$/.test(prefRaw);
|
|
372
|
-
const storedId = /^1\.2\.\d+$/.test(String(botMeta?.accountId ?? '')) ? String(botMeta.accountId) : null;
|
|
373
|
-
// An explicit 1.2.x preferredAccount is authoritative: the stored accountId
|
|
374
|
-
// is a derived cache and must never override it. Self-heal the cache.
|
|
375
|
-
if (prefIsId) {
|
|
376
|
-
if (storedId && storedId !== prefRaw && persistBotAccountId(botKey, prefRaw)) {
|
|
377
|
-
console.log(` Updated stale stored accountId ${storedId} → ${prefRaw} from preferredAccount`);
|
|
378
|
-
}
|
|
379
|
-
return { accountId: prefRaw, botMeta };
|
|
380
|
-
}
|
|
381
|
-
if (!prefRaw) {
|
|
382
|
-
console.error(`Error: bot '${botKey}' has no preferredAccount and no --account provided.`);
|
|
383
|
-
process.exit(1);
|
|
384
|
-
}
|
|
385
|
-
// Name + fresh-enough cache + no refresh requested: offline-friendly fast path.
|
|
386
|
-
if (storedId && !doRefresh) {
|
|
387
|
-
console.log(` Using stored accountId ${storedId} from profiles/bots.json (no lookup needed; pass --refresh-account to re-verify)`);
|
|
388
|
-
return { accountId: storedId, botMeta };
|
|
389
|
-
}
|
|
390
|
-
// No cache, or --refresh-account: resolve the name on-chain.
|
|
391
|
-
console.log(` Resolving account name '${prefRaw}'...`);
|
|
392
|
-
const resolved = await resolveAccountId(prefRaw, nodeUrl);
|
|
393
|
-
if (!resolved) {
|
|
394
|
-
console.error(`Error: failed to resolve account name '${prefRaw}' to 1.2.x`);
|
|
395
|
-
process.exit(1);
|
|
396
|
-
}
|
|
397
|
-
console.log(` → ${resolved}`);
|
|
398
|
-
if (!storedId && persistBotAccountId(botKey, resolved)) {
|
|
399
|
-
console.log(` Stored accountId ${resolved} in profiles/bots.json for '${botKey}'`);
|
|
400
|
-
}
|
|
401
|
-
else if (storedId && storedId !== resolved && persistBotAccountId(botKey, resolved)) {
|
|
402
|
-
console.log(` Updated stored accountId ${storedId} → ${resolved} in profiles/bots.json for '${botKey}'`);
|
|
403
|
-
}
|
|
404
|
-
else if (storedId === resolved) {
|
|
405
|
-
console.log(` Stored accountId ${resolved} confirmed up to date`);
|
|
406
|
-
}
|
|
407
|
-
return { accountId: String(resolved), botMeta };
|
|
408
|
-
}
|
|
409
|
-
// ─── Asset precision resolution ───────────────────────────────────────────────
|
|
410
|
-
async function resolveAssetPrecisions(fills, nodeUrl) {
|
|
411
|
-
const unknownIds = new Set();
|
|
412
|
-
for (const f of fills) {
|
|
413
|
-
for (const id of [f.pays.asset_id, f.receives.asset_id, f.fee.asset_id]) {
|
|
414
|
-
if (id !== BTS_ID && !(id in ASSETS) && !(id in resolvedPrecisions))
|
|
415
|
-
unknownIds.add(id);
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
if (unknownIds.size === 0 || !nodeUrl)
|
|
419
|
-
return;
|
|
420
|
-
const ids = [...unknownIds];
|
|
421
|
-
console.log(` Resolving ${ids.length} unknown asset(s) from blockchain...`);
|
|
422
|
-
const { createReadOnlyClient } = await import('../modules/bitshares-native/index.js');
|
|
423
|
-
const client = createReadOnlyClient({ nodes: [nodeUrl] });
|
|
424
|
-
try {
|
|
425
|
-
await client.connect();
|
|
426
|
-
const assets = await client.db('get_assets', [ids]);
|
|
427
|
-
if (Array.isArray(assets)) {
|
|
428
|
-
for (const asset of assets) {
|
|
429
|
-
if (asset?.id && asset.precision != null) {
|
|
430
|
-
resolvedPrecisions[asset.id] = asset.precision;
|
|
431
|
-
console.log(` ${asset.id} → ${asset.symbol || '?'} (precision ${asset.precision})`);
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
const missing = ids.filter(id => !(id in resolvedPrecisions));
|
|
436
|
-
if (missing.length > 0)
|
|
437
|
-
console.warn(` [warn] ${missing.length} asset(s) not found on chain: ${missing.join(', ')}`);
|
|
438
|
-
}
|
|
439
|
-
catch (e) {
|
|
440
|
-
console.warn(` [warn] Asset resolution failed: ${e.message}`);
|
|
441
|
-
}
|
|
442
|
-
finally {
|
|
443
|
-
try {
|
|
444
|
-
client.disconnect();
|
|
445
|
-
}
|
|
446
|
-
catch (_) { }
|
|
264
|
+
// ─── Account resolution errors ────────────────────────────────────────────────
|
|
265
|
+
/** Map a shared account-resolver failure onto this tool's operator-facing hint. */
|
|
266
|
+
function reportAccountFailure(resolved, opts) {
|
|
267
|
+
switch (resolved.reason) {
|
|
268
|
+
case 'bot-not-found':
|
|
269
|
+
console.error(`Error: bot key '${opts.botKey}' not found in profiles/bots.json and no --account provided.`);
|
|
270
|
+
console.error('Use --list-bots to see available keys, or pass --account <1.2.x> explicitly.');
|
|
271
|
+
break;
|
|
272
|
+
case 'override-unresolved':
|
|
273
|
+
console.error(`Error: failed to resolve --account '${opts.account}' to 1.2.x`);
|
|
274
|
+
break;
|
|
275
|
+
case 'no-preferred-account':
|
|
276
|
+
console.error(`Error: bot '${opts.botKey}' has no preferredAccount and no --account provided.`);
|
|
277
|
+
break;
|
|
278
|
+
default:
|
|
279
|
+
console.error(`Error: failed to resolve account name '${resolved?.botMeta?.preferredAccount ?? opts.botKey}' to 1.2.x`);
|
|
447
280
|
}
|
|
448
281
|
}
|
|
449
282
|
// ─── Kibana fetch ─────────────────────────────────────────────────────────────
|
|
450
|
-
function buildFillQuery(accountId, gte, lte, size) {
|
|
451
|
-
return {
|
|
452
|
-
size,
|
|
453
|
-
track_total_hits: false,
|
|
454
|
-
_source: [
|
|
455
|
-
'block_data.block_time',
|
|
456
|
-
'block_data.block_num',
|
|
457
|
-
'operation_id_num',
|
|
458
|
-
'operation_history.op_object.pays',
|
|
459
|
-
'operation_history.op_object.receives',
|
|
460
|
-
'operation_history.op_object.fee',
|
|
461
|
-
'operation_history.op_object.order_id',
|
|
462
|
-
'operation_history.op_object.account_id',
|
|
463
|
-
'operation_history.op_object.is_maker',
|
|
464
|
-
],
|
|
465
|
-
query: {
|
|
466
|
-
bool: {
|
|
467
|
-
filter: [
|
|
468
|
-
{ term: { operation_type: OP_FILL_ORDER } },
|
|
469
|
-
{ term: { 'operation_history.op_object.account_id.keyword': accountId } },
|
|
470
|
-
{ range: { 'block_data.block_time': { gte, lte } } },
|
|
471
|
-
],
|
|
472
|
-
},
|
|
473
|
-
},
|
|
474
|
-
sort: [
|
|
475
|
-
{ 'block_data.block_time': { order: 'asc' } },
|
|
476
|
-
{ operation_id_num: { order: 'asc' } },
|
|
477
|
-
],
|
|
478
|
-
};
|
|
479
|
-
}
|
|
480
283
|
async function fetchAllOrderUpdates(config, accountId, gte, lte) {
|
|
481
284
|
const pageSize = 10000;
|
|
482
285
|
const updates = [];
|
|
@@ -524,45 +327,6 @@ async function fetchAllOrderUpdates(config, accountId, gte, lte) {
|
|
|
524
327
|
}
|
|
525
328
|
return updates;
|
|
526
329
|
}
|
|
527
|
-
async function fetchAllFills(config, accountId, gte, lte) {
|
|
528
|
-
const pageSize = 10000;
|
|
529
|
-
const fills = [];
|
|
530
|
-
let searchAfter = null;
|
|
531
|
-
const cfg = { ...BASE_CONFIG, timeout: 60000, ...config };
|
|
532
|
-
while (true) {
|
|
533
|
-
const query = buildFillQuery(accountId, gte, lte, pageSize);
|
|
534
|
-
if (searchAfter)
|
|
535
|
-
query.search_after = searchAfter;
|
|
536
|
-
const result = await kibanaSearch(cfg, query);
|
|
537
|
-
const hits = result?.hits?.hits ?? [];
|
|
538
|
-
if (!hits.length)
|
|
539
|
-
break;
|
|
540
|
-
for (const hit of hits) {
|
|
541
|
-
const src = hit?._source;
|
|
542
|
-
const op = src?.operation_history?.op_object;
|
|
543
|
-
if (!op || !op.pays || !op.receives)
|
|
544
|
-
continue;
|
|
545
|
-
fills.push({
|
|
546
|
-
time: src.block_data?.block_time ?? '',
|
|
547
|
-
blockNum: src.block_data?.block_num ?? 0,
|
|
548
|
-
opNum: Number(src.operation_id_num ?? 0),
|
|
549
|
-
orderId: op.order_id ?? '',
|
|
550
|
-
accountId: op.account_id ?? '',
|
|
551
|
-
pays: { amount: Number(op.pays.amount ?? 0), asset_id: op.pays.asset_id ?? '' },
|
|
552
|
-
receives: { amount: Number(op.receives.amount ?? 0), asset_id: op.receives.asset_id ?? '' },
|
|
553
|
-
fee: { amount: Number(op.fee?.amount ?? 0), asset_id: op.fee?.asset_id ?? '' },
|
|
554
|
-
isMaker: op.is_maker ?? false,
|
|
555
|
-
sort: hit.sort,
|
|
556
|
-
});
|
|
557
|
-
}
|
|
558
|
-
if (hits.length < pageSize)
|
|
559
|
-
break;
|
|
560
|
-
searchAfter = hits[hits.length - 1].sort;
|
|
561
|
-
if (!Array.isArray(searchAfter))
|
|
562
|
-
break;
|
|
563
|
-
}
|
|
564
|
-
return fills;
|
|
565
|
-
}
|
|
566
330
|
// ─── Fill classification ─────────────────────────────────────────────────────
|
|
567
331
|
function classifyFills(fills) {
|
|
568
332
|
const trades = [];
|
|
@@ -912,7 +676,16 @@ async function main() {
|
|
|
912
676
|
const { gte, lte, label } = resolveTimeRange(opts);
|
|
913
677
|
console.log(`\nGrid correction check — bot-key: ${opts.botKey}`);
|
|
914
678
|
console.log(`Range: ${label}`);
|
|
915
|
-
const
|
|
679
|
+
const resolvedAccount = await resolveBotAccount(opts.botKey, {
|
|
680
|
+
overrideAccount: opts.account,
|
|
681
|
+
refresh: opts.refreshAccount,
|
|
682
|
+
});
|
|
683
|
+
if (!resolvedAccount.accountId) {
|
|
684
|
+
reportAccountFailure(resolvedAccount, opts);
|
|
685
|
+
process.exit(1);
|
|
686
|
+
}
|
|
687
|
+
const accountId = resolvedAccount.accountId;
|
|
688
|
+
const botMeta = resolvedAccount.botMeta;
|
|
916
689
|
console.log(`Account: ${accountId}${botMeta ? ` (${botMeta.assetA}/${botMeta.assetB})` : ''}`);
|
|
917
690
|
const incrementPercent = resolveIncrementPercent(botMeta, opts.incrementPercent);
|
|
918
691
|
console.log(`Increment: ${incrementPercent}% (halfInc ${incrementPercent / 2}%)${opts.incrementPercent == null && botMeta?.incrementPercent != null ? ' — from bot config' : opts.incrementPercent != null ? ' — from --increment' : ' — default'}`);
|
|
@@ -927,7 +700,7 @@ async function main() {
|
|
|
927
700
|
console.log('\nNo fills in range — nothing to check.');
|
|
928
701
|
process.exit(0);
|
|
929
702
|
}
|
|
930
|
-
await resolveAssetPrecisions(fills
|
|
703
|
+
await resolveAssetPrecisions(fills);
|
|
931
704
|
const { trades, skipped } = classifyFills(fills);
|
|
932
705
|
console.log(` Classified ${trades.length} trade(s)${skipped > 0 ? `, ${skipped} skipped (unknown precision)` : ''}`);
|
|
933
706
|
if (trades.length < 2) {
|