@clonegod/ttd-core 3.0.20 → 3.1.1

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.
@@ -1,3 +1,3 @@
1
1
  import { OrderMessageType, PriceMessageType } from "../../types";
2
- export declare const report_trade_analyze_data: (type: string, message: PriceMessageType | OrderMessageType) => void;
2
+ export declare const report_trade_analyze_data: (type: string, message: PriceMessageType | OrderMessageType | any) => void;
3
3
  export declare const get_pool_latest_quote_price: (unique_orderbook_id: string) => Promise<PriceMessageType>;
@@ -15,35 +15,34 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.get_pool_latest_quote_price = exports.report_trade_analyze_data = void 0;
16
16
  const axios_1 = __importDefault(require("axios"));
17
17
  const index_1 = require("../index");
18
- const trade_analyze_url = process.env.TRADE_ANALYZE_URL || `http://localhost:8004/trade/analyze`;
19
- const report_trade_log = process.env.REPORT_TRADE_LOG === 'true';
18
+ const ANALYZE_HOST = process.env.TRADE_ANALYZE_HOST || '';
19
+ const ANALYZE_PORT = process.env.TRADE_ANALYZE_PORT || '8004';
20
+ const ANALYZE_BASE = ANALYZE_HOST ? `http://${ANALYZE_HOST}:${ANALYZE_PORT}/trade/analyze` : '';
20
21
  const headers = { 'Content-Type': 'application/json' };
21
22
  const report_trade_analyze_data = (type, message) => {
22
- const body = {
23
- type,
24
- message
25
- };
26
- if (!report_trade_log) {
23
+ if (!ANALYZE_BASE)
27
24
  return;
25
+ try {
26
+ axios_1.default.post(ANALYZE_BASE, { type, message }, { headers, timeout: 3000 })
27
+ .then(() => (0, index_1.log_trace)(`[analyze] report ${type} ok`))
28
+ .catch(err => (0, index_1.log_warn)(`[analyze] report ${type} fail: ${err.message}`));
29
+ }
30
+ catch (err) {
31
+ (0, index_1.log_warn)(`[analyze] report ${type} error: ${err.message}`);
28
32
  }
29
- axios_1.default.post(trade_analyze_url, body, { headers })
30
- .then(res => (0, index_1.log_trace)('report_trade_analzye_data, success, res=', res.data))
31
- .catch(err => (0, index_1.log_warn)(`report_trade_analzye_data, error: ${err.message}`));
32
33
  };
33
34
  exports.report_trade_analyze_data = report_trade_analyze_data;
34
35
  const get_pool_latest_quote_price = (unique_orderbook_id) => __awaiter(void 0, void 0, void 0, function* () {
35
- let price_msg = null;
36
- let url = `${trade_analyze_url}/price_msg?unique_orderbook_id=${unique_orderbook_id}`;
37
- if (!(0, index_1.isEmpty)(unique_orderbook_id)) {
38
- try {
39
- let res = (yield axios_1.default.get(url, { headers })).data;
40
- let { code, msg, data } = res;
41
- price_msg = data;
42
- }
43
- catch (err) {
44
- (0, index_1.log_error)(`get_pool_latest_quote_price error! url=${url}`, new Error(err.message));
45
- }
36
+ if (!ANALYZE_BASE || (0, index_1.isEmpty)(unique_orderbook_id))
37
+ return null;
38
+ try {
39
+ const url = `${ANALYZE_BASE}/price_msg?unique_orderbook_id=${unique_orderbook_id}`;
40
+ const res = (yield axios_1.default.get(url, { headers, timeout: 3000 })).data;
41
+ return res.data;
42
+ }
43
+ catch (err) {
44
+ (0, index_1.log_warn)(`[analyze] get_price fail: ${err.message}`);
45
+ return null;
46
46
  }
47
- return price_msg;
48
47
  });
49
48
  exports.get_pool_latest_quote_price = get_pool_latest_quote_price;
package/dist/index.d.ts CHANGED
@@ -15,7 +15,7 @@ export * from './trade';
15
15
  export * from './chains';
16
16
  export * from './ws';
17
17
  export * from './util';
18
- export type { CommonServiceType, ConfigCenterServiceType, QuoteServiceType, OrderbookServiceType, TradeProxyServiceType, StandardTokenConfigType, StandardTokenInfoType, StandardPoolConfigType, StandardDexPoolConfigType, StandardPoolInfoType, StandardPairType, TradeServiceConfigType, TradeGroupType, TradePairType, TradePairDexPoolsType, TradeSettingsType, RpcInfoType, TradeStrategyType, TradeCommandLineArgs, TradeRuntimeType, TradeProcessInstanceType, TokenPriceWithAmountType, QuoteResultType, PriceMessageType, QuoteSourceType, UniqueOrderbookIdType, PriceType, QuoteTimeInfoType, OrderbookPriceType, Ladder, OrderMessageType, OrderSubmitResultType, OrderSubmitResponseType, StandardSwapDetailType, TokenBalChangeType, TokenBalanceChangeType, TradeResponseType, TradeResultType, TradeResultBalanceChangeType, TradeExecutionInfoType, TradeTimeFlowType, TradeBroadcastType, TradeGasFeeType, ServerInfoType, SendTxLogType, WalletInfoType, WalletTokenBalanceInfoType, RedisConfigChangeEventMessageType, RedisOrderEventMessageType, RedisQuoteEventMessageType, } from '../types';
18
+ export type { CommonServiceType, ConfigCenterServiceType, QuoteServiceType, OrderbookServiceType, TradeProxyServiceType, StandardTokenConfigType, StandardTokenInfoType, StandardPoolConfigType, StandardDexPoolConfigType, StandardPoolInfoType, StandardPairType, TradeServiceConfigType, TradeGroupType, TradePairType, TradePairDexPoolsType, TradeSettingsType, RpcInfoType, TradeStrategyType, TradeCommandLineArgs, TradeRuntimeType, TradeProcessInstanceType, TokenPriceWithAmountType, QuoteResultType, PriceMessageType, QuoteSourceType, UniqueOrderbookIdType, PriceType, QuoteTimeInfoType, OrderbookPriceType, Ladder, OrderMessageType, OrderSubmitResultType, OrderSubmitResponseType, StandardSwapDetailType, TokenBalChangeType, TokenBalanceChangeType, TradeResponseType, TradeResultType, TradeResultBalanceChangeType, TradeExecutionInfoType, TradeTimeFlowType, TradeBroadcastType, TradeGasFeeType, ServerInfoType, SendTxLogType, WalletInfoType, WalletTokenBalanceInfoType, RedisConfigChangeEventMessageType, RedisOrderEventMessageType, RedisQuoteEventMessageType, PreTradeEventType, ProviderComparisonType, ProviderArrivalType, OnTradeType, OnTradePriceType, OnTradeDepthType, OnTradeExecutionType, OnTradeResultType, AnalyzeDepthLevelType, AnalyzeTokenAmountType, PostTradeType, AnalyzeQuoteSnapshotType, AnalyzePoolEventType, AnalyzeEventSummaryType, AnalyzeSameBlockType, } from '../types';
19
19
  export declare const FAILED = "FAILED";
20
20
  export declare const SUCCESS = "SUCCESS";
21
21
  export declare const NOT_FOUND = "NOT_FOUND";
@@ -33,30 +33,5 @@ function log_quote_price(event_source, price_message, tx_hash) {
33
33
  String(ask.price).padEnd(8) + ' - ' +
34
34
  String(bid.price).padEnd(8) + ' - ' +
35
35
  `${times.join(',')} ms`);
36
- const depthLine = formatDepthLine(ask, bid);
37
- if (depthLine) {
38
- console.log(depthLine);
39
- }
40
36
  });
41
37
  }
42
- function formatDepthLine(ask, bid) {
43
- const bpsSet = new Set();
44
- for (const key of Object.keys(ask)) {
45
- const match = key.match(/^depth_(\d+)$/);
46
- if (match)
47
- bpsSet.add(Number(match[1]));
48
- }
49
- if (bpsSet.size === 0)
50
- return null;
51
- const parts = [];
52
- for (const bps of [...bpsSet].sort((a, b) => a - b)) {
53
- const askAmt = ask[`depth_${bps}`];
54
- const askUsd = ask[`depth_${bps}_usd`];
55
- const askTick = ask[`depth_${bps}_tick`] || '';
56
- const bidAmt = bid[`depth_${bps}`];
57
- const bidUsd = bid[`depth_${bps}_usd`];
58
- const bidTick = bid[`depth_${bps}_tick`] || '';
59
- parts.push(`${bps}bps: ask=${askAmt}($${askUsd}) bid=${bidAmt}($${bidUsd})${askTick ? ` tick:${askTick}|${bidTick}` : ''}`);
60
- }
61
- return ` ↳ [Depth] ${parts.join(' | ')}`;
62
- }
@@ -26,5 +26,16 @@ function on_quote_respose(appConfig, pool_info, quote_amount_usd, execution_pric
26
26
  }
27
27
  (0, log_quote_price_1.log_quote_price)(slot_info, price_msg, txid);
28
28
  (0, analyze_1.report_trade_analyze_data)('PriceMessageType', Object.assign(Object.assign({}, price_msg), { quote_source: { slot: slot_info, block: null, txid } }));
29
+ if (depth) {
30
+ (0, analyze_1.report_trade_analyze_data)('DepthLevels', {
31
+ price_id: price_msg.price_id,
32
+ unique_orderbook_id: price_msg.unique_orderbook_id,
33
+ pair: price_msg.pair,
34
+ depth
35
+ });
36
+ }
37
+ })
38
+ .catch(err => {
39
+ console.error(`[on_quote_response] error: ${(err === null || err === void 0 ? void 0 : err.message) || err}`);
29
40
  });
30
41
  }
@@ -32,6 +32,7 @@ const get_quote_token_decimals = (pool_info) => {
32
32
  exports.get_quote_token_decimals = get_quote_token_decimals;
33
33
  function to_price_message(appConfig_1, quote_amount_usd_1, tx_price_1, quote_ask_price_1, quote_bid_price_1, pool_info_1, time_1, slot_1) {
34
34
  return __awaiter(this, arguments, void 0, function* (appConfig, quote_amount_usd, tx_price, quote_ask_price, quote_bid_price, pool_info, time, slot, source = "", depth) {
35
+ var _a, _b;
35
36
  let { pool_address, tokenA, tokenB } = pool_info;
36
37
  let { dex_id, pool_name, fee_rate, is_reverse_token } = yield appConfig.arb_cache.get_one_pool_info(pool_address);
37
38
  let _dex_id = dex_id;
@@ -50,20 +51,15 @@ function to_price_message(appConfig_1, quote_amount_usd_1, tx_price_1, quote_ask
50
51
  price: bid_price,
51
52
  quantity: quote_amount_usd
52
53
  };
53
- if (depth) {
54
- for (const [bps, data] of Object.entries(depth.ask)) {
55
- askData[`depth_${bps}`] = data.amount.toFixed(6);
56
- askData[`depth_${bps}_usd`] = data.amountUsd.toFixed(2);
57
- if (data.tickMove)
58
- askData[`depth_${bps}_tick`] = data.tickMove;
59
- }
60
- for (const [bps, data] of Object.entries(depth.bid)) {
61
- bidData[`depth_${bps}`] = data.amount.toFixed(6);
62
- bidData[`depth_${bps}_usd`] = data.amountUsd.toFixed(2);
63
- if (data.tickMove)
64
- bidData[`depth_${bps}_tick`] = data.tickMove;
65
- }
66
- }
54
+ const cexBps = parseInt(process.env.DEPTH_CEX_BPS || '20');
55
+ const askDepth = (_a = depth === null || depth === void 0 ? void 0 : depth.ask) === null || _a === void 0 ? void 0 : _a[cexBps];
56
+ const bidDepth = (_b = depth === null || depth === void 0 ? void 0 : depth.bid) === null || _b === void 0 ? void 0 : _b[cexBps];
57
+ askData.depth_bps = cexBps;
58
+ askData.depth_amount = askDepth ? askDepth.amount.toFixed(6) : '0';
59
+ askData.depth_usd = askDepth ? askDepth.amountUsd.toFixed(2) : '0';
60
+ bidData.depth_bps = cexBps;
61
+ bidData.depth_amount = bidDepth ? bidDepth.amount.toFixed(6) : '0';
62
+ bidData.depth_usd = bidDepth ? bidDepth.amountUsd.toFixed(2) : '0';
67
63
  let price_message = {
68
64
  chain_id,
69
65
  dex_id,
@@ -11,6 +11,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.AbstractTransactionResultCheck = void 0;
13
13
  const __1 = require("..");
14
+ const analyze_1 = require("../analyze");
14
15
  class AbstractTransactionResultCheck {
15
16
  constructor(env_args, event_emitter) {
16
17
  this.env_args = env_args;
@@ -49,6 +50,7 @@ class AbstractTransactionResultCheck {
49
50
  });
50
51
  }
51
52
  map_swap_result_to_tx_result(swap_result) {
53
+ var _a;
52
54
  let { success, error_code, wallet, block_number, block_time: order_block_time, txid, tx_price, tokenA, tokenB, gas_fee } = swap_result;
53
55
  if (this.context.ui_tip_amount) {
54
56
  gas_fee.priority_fee = this.context.ui_tip_amount;
@@ -78,6 +80,15 @@ class AbstractTransactionResultCheck {
78
80
  order_end_time,
79
81
  total_order_time,
80
82
  };
83
+ time.order_block_number = block_number || 0;
84
+ const _marks = (_a = this.context) === null || _a === void 0 ? void 0 : _a._execution_marks;
85
+ if (_marks) {
86
+ ;
87
+ time.caller_ready_time = _marks['caller'] || 0;
88
+ time.encode_done_time = _marks['encode'] || 0;
89
+ time.sign_done_time = _marks['sign'] || 0;
90
+ time.tx_send_time = _marks['sent'] || 0;
91
+ }
81
92
  let broadcast = [];
82
93
  broadcast.push({
83
94
  rpc: {
@@ -137,6 +148,7 @@ class AbstractTransactionResultCheck {
137
148
  execution: trade_extra_info,
138
149
  c_id
139
150
  };
151
+ (0, analyze_1.report_trade_analyze_data)('TradeResultType', trade_result);
140
152
  return trade_result;
141
153
  }
142
154
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clonegod/ttd-core",
3
- "version": "3.0.20",
3
+ "version": "3.1.1",
4
4
  "description": "Common types and utilities for trading systems - use `npm run push` to publish",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/types/index.d.ts CHANGED
@@ -511,6 +511,13 @@ export interface TradeTimeFlowType extends QuoteTimeInfoType {
511
511
  order_end_time: number // dex 解析得到交易结果的时间
512
512
  order_block_time: number // dex 交易所在区块的出块时间
513
513
  total_order_time: number // dex 交易耗时: order_end_time - order_recv_time
514
+ // trade-analyze 扩展
515
+ order_block_number?: number // 交易所在区块号
516
+ order_tx_index?: number // 交易在区块内的位置
517
+ caller_ready_time?: number // 获取到 Caller Wallet 的时间
518
+ encode_done_time?: number // 交易编码完成时间
519
+ sign_done_time?: number // 交易签名完成时间
520
+ tx_send_time?: number // 交易发送到 RPC 的时间
514
521
  }
515
522
 
516
523
  // TRANSACTION BROADCASTING
@@ -784,3 +791,212 @@ export declare class RedisCommand {
784
791
  }
785
792
 
786
793
 
794
+ /*********************************************************************
795
+ * TRADE ANALYZE TYPES *
796
+ *********************************************************************/
797
+
798
+ // ═══ PreTrade: 事前 - 事件感知延迟 + Provider 对比 ═══
799
+
800
+ export interface PreTradeEventType {
801
+ pool_address: string
802
+ pair: string
803
+ dex_id: string
804
+ event_type: string // Sync | Swap | Mint | Burn | ModifyLiquidity
805
+ source_txid: string
806
+ log_index: number
807
+ tx_index: number // 交易在区块内的位置
808
+
809
+ // 时间线
810
+ block_time: number // 链上出块时间 (ms),analyze 端通过 PriceMessage 缓存补充
811
+ block_number: number
812
+ stream_recv_time: number // RPC/WS 推送到达本地
813
+
814
+ // Provider
815
+ provider_id: string
816
+ subscribe_mode: string // SINGLE | MULTI
817
+
818
+ // 事件内容(stream-quote 已解析好的数据,标准化上报)
819
+ // AMM (Sync)
820
+ reserve0?: string
821
+ reserve1?: string
822
+ // CLMM (Swap)
823
+ amount0?: string
824
+ amount1?: string
825
+ sqrtPriceX96?: string
826
+ tick?: number
827
+ liquidity?: string
828
+ // Liquidity (Mint/Burn/ModifyLiquidity)
829
+ tickLower?: number
830
+ tickUpper?: number
831
+ }
832
+
833
+ export interface ProviderComparisonType {
834
+ event_key: string // blockNumber_txHash_logIndex
835
+ pool_address: string
836
+ event_type: string
837
+ providers: ProviderArrivalType[]
838
+ fastest_provider: string
839
+ max_gap_ms: number
840
+ }
841
+
842
+ export interface ProviderArrivalType {
843
+ provider_id: string
844
+ stream_recv_time: number
845
+ delta_vs_fastest_ms: number
846
+ }
847
+
848
+ // ═══ OnTrade: 事中 - 价格偏差 / 深度验证 / 执行时间线 ═══
849
+
850
+ export interface OnTradeType {
851
+ id: string // unique_order_msg_id
852
+ txid: string
853
+ price_id: string // 关联键:串联 PriceMessage ↔ Order ↔ TradeResult
854
+ unique_orderbook_id: string // 关联键:定位 Pool 的所有报价
855
+ pool_address: string
856
+ pair: string
857
+ dex_id: string
858
+ group_id: string
859
+ chain_id: string
860
+ direction: 'BUY' | 'SELL'
861
+
862
+ price: OnTradePriceType
863
+ depth: OnTradeDepthType
864
+ execution: OnTradeExecutionType
865
+ result: OnTradeResultType
866
+ }
867
+
868
+ export interface OnTradePriceType {
869
+ quote_ask: string
870
+ quote_bid: string
871
+ cex_price: string
872
+ exec_price: string
873
+ /** 报价 vs 成交偏差 (bps), 正=成交比报价差 */
874
+ quote_exec_deviation_bps: number
875
+ /** CEX vs DEX 价差 (bps) */
876
+ cex_dex_spread_bps: number
877
+ }
878
+
879
+ export interface OnTradeDepthType {
880
+ levels: Record<number, AnalyzeDepthLevelType>
881
+ trade_size_usd: number
882
+ /** 交易量消耗了多少可用深度 (%) */
883
+ depth_utilization_pct: number
884
+ estimated_slippage_bps: number
885
+ actual_slippage_bps: number
886
+ /** 滑点偏差 = actual - estimated (bps) */
887
+ slippage_deviation_bps: number
888
+ }
889
+
890
+ export interface AnalyzeDepthLevelType {
891
+ amount: number
892
+ amount_usd: number
893
+ amount_in: number
894
+ amount_in_usd: number
895
+ }
896
+
897
+ export interface OnTradeExecutionType {
898
+ order_send_time: number // CEX 发出
899
+ order_recv_time: number // DEX 收到
900
+ caller_ready_time: number // Caller 就绪
901
+ encode_done_time: number // 编码完成
902
+ sign_done_time: number // 签名完成
903
+ tx_send_time: number // 发送上链
904
+ tx_block_time: number // 交易被打包的区块时间
905
+ tx_block_number: number
906
+ tx_index: number // 区块内位置
907
+ tx_confirmed_time: number // 监控到结果
908
+ }
909
+
910
+ export interface OnTradeResultType {
911
+ success: boolean
912
+ error_code?: string
913
+ token_in: AnalyzeTokenAmountType
914
+ token_out: AnalyzeTokenAmountType
915
+ gas_used: number
916
+ gas_price_gwei: number
917
+ gas_cost_usd: number
918
+ }
919
+
920
+ export interface AnalyzeTokenAmountType {
921
+ symbol: string
922
+ amount: number
923
+ value_usd: number
924
+ }
925
+
926
+ // ═══ PostTrade: 事后 - 交易回溯 ═══
927
+
928
+ export interface PostTradeType {
929
+ txid: string
930
+ pair: string
931
+ pool_address: string
932
+ dex_id: string
933
+ direction: 'BUY' | 'SELL'
934
+
935
+ /** 时间窗口: 报价生成 → 交易上链 */
936
+ window_start: number
937
+ window_end: number
938
+ window_duration_ms: number
939
+
940
+ /** 触发下单的那次报价 */
941
+ trigger_quote: AnalyzeQuoteSnapshotType
942
+ /** 窗口内该 Pool 的所有报价 */
943
+ quote_sequence: AnalyzeQuoteSnapshotType[]
944
+ /** 第一条 vs 最后一条报价的价格变化 (bps) */
945
+ price_drift_bps: number
946
+
947
+ /** 窗口内该 Pool 上发生的链上事件 */
948
+ intervening_events: AnalyzePoolEventType[]
949
+ event_summary: AnalyzeEventSummaryType
950
+
951
+ /** 同区块分析 (MEV) */
952
+ same_block: AnalyzeSameBlockType
953
+ }
954
+
955
+ export interface AnalyzeQuoteSnapshotType {
956
+ price_id: string
957
+ ask: string
958
+ bid: string
959
+ block_number: number
960
+ source_txid: string
961
+ stream_recv_time: number
962
+ price_ready_time: number
963
+ }
964
+
965
+ export interface AnalyzePoolEventType {
966
+ txid: string
967
+ block_number: number
968
+ tx_index: number
969
+ event_type: 'SWAP' | 'MINT' | 'BURN' | 'MODIFY_LIQUIDITY'
970
+ timestamp: number
971
+ swap?: {
972
+ direction: 'BUY' | 'SELL'
973
+ amount_in: string
974
+ amount_out: string
975
+ price: string
976
+ }
977
+ liquidity?: {
978
+ tick_lower?: number
979
+ tick_upper?: number
980
+ amount0: string
981
+ amount1: string
982
+ }
983
+ /** 该事件对价格的影响 (bps) */
984
+ price_impact_bps: number
985
+ }
986
+
987
+ export interface AnalyzeEventSummaryType {
988
+ swap_count: number
989
+ mint_count: number
990
+ burn_count: number
991
+ total_count: number
992
+ cumulative_price_impact_bps: number
993
+ }
994
+
995
+ export interface AnalyzeSameBlockType {
996
+ my_tx_index: number
997
+ before_me: AnalyzePoolEventType[]
998
+ after_me: AnalyzePoolEventType[]
999
+ sandwich_detected: boolean
1000
+ }
1001
+
1002
+