cyqnt-trd 0.1.2__py3-none-any.whl

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 (147) hide show
  1. cyqnt_trd/__init__.py +26 -0
  2. cyqnt_trd/backtesting/README.md +264 -0
  3. cyqnt_trd/backtesting/__init__.py +12 -0
  4. cyqnt_trd/backtesting/factor_test.py +332 -0
  5. cyqnt_trd/backtesting/framework.py +311 -0
  6. cyqnt_trd/backtesting/strategy_backtest.py +545 -0
  7. cyqnt_trd/diagnose_api.py +28 -0
  8. cyqnt_trd/get_data/__init__.py +15 -0
  9. cyqnt_trd/get_data/get_futures_data.py +472 -0
  10. cyqnt_trd/get_data/get_trending_data.py +771 -0
  11. cyqnt_trd/online_trading/__init__.py +13 -0
  12. cyqnt_trd/online_trading/realtime_price_tracker.py +1001 -0
  13. cyqnt_trd/test.py +119 -0
  14. cyqnt_trd/test_script/README.md +411 -0
  15. cyqnt_trd/test_script/get_network_info.py +192 -0
  16. cyqnt_trd/test_script/get_symbols_by_volume.py +227 -0
  17. cyqnt_trd/test_script/realtime_price_tracker.py +839 -0
  18. cyqnt_trd/test_script/test_alpha.py +261 -0
  19. cyqnt_trd/test_script/test_kline_data.py +479 -0
  20. cyqnt_trd/test_script/test_order.py +1360 -0
  21. cyqnt_trd/trading_signal/README.md +276 -0
  22. cyqnt_trd/trading_signal/__init__.py +17 -0
  23. cyqnt_trd/trading_signal/example_test_alpha.py +430 -0
  24. cyqnt_trd/trading_signal/example_usage.py +431 -0
  25. cyqnt_trd/trading_signal/factor/__init__.py +18 -0
  26. cyqnt_trd/trading_signal/factor/ma_factor.py +75 -0
  27. cyqnt_trd/trading_signal/factor/rsi_factor.py +56 -0
  28. cyqnt_trd/trading_signal/selected_alpha/__init__.py +158 -0
  29. cyqnt_trd/trading_signal/selected_alpha/alpha1.py +87 -0
  30. cyqnt_trd/trading_signal/selected_alpha/alpha10.py +90 -0
  31. cyqnt_trd/trading_signal/selected_alpha/alpha100.py +74 -0
  32. cyqnt_trd/trading_signal/selected_alpha/alpha101.py +86 -0
  33. cyqnt_trd/trading_signal/selected_alpha/alpha11.py +86 -0
  34. cyqnt_trd/trading_signal/selected_alpha/alpha12.py +86 -0
  35. cyqnt_trd/trading_signal/selected_alpha/alpha13.py +86 -0
  36. cyqnt_trd/trading_signal/selected_alpha/alpha14.py +87 -0
  37. cyqnt_trd/trading_signal/selected_alpha/alpha15.py +87 -0
  38. cyqnt_trd/trading_signal/selected_alpha/alpha16.py +86 -0
  39. cyqnt_trd/trading_signal/selected_alpha/alpha17.py +88 -0
  40. cyqnt_trd/trading_signal/selected_alpha/alpha18.py +88 -0
  41. cyqnt_trd/trading_signal/selected_alpha/alpha19.py +87 -0
  42. cyqnt_trd/trading_signal/selected_alpha/alpha2.py +86 -0
  43. cyqnt_trd/trading_signal/selected_alpha/alpha20.py +88 -0
  44. cyqnt_trd/trading_signal/selected_alpha/alpha21.py +89 -0
  45. cyqnt_trd/trading_signal/selected_alpha/alpha22.py +87 -0
  46. cyqnt_trd/trading_signal/selected_alpha/alpha23.py +88 -0
  47. cyqnt_trd/trading_signal/selected_alpha/alpha24.py +88 -0
  48. cyqnt_trd/trading_signal/selected_alpha/alpha25.py +86 -0
  49. cyqnt_trd/trading_signal/selected_alpha/alpha26.py +87 -0
  50. cyqnt_trd/trading_signal/selected_alpha/alpha27.py +88 -0
  51. cyqnt_trd/trading_signal/selected_alpha/alpha28.py +88 -0
  52. cyqnt_trd/trading_signal/selected_alpha/alpha29.py +87 -0
  53. cyqnt_trd/trading_signal/selected_alpha/alpha3.py +86 -0
  54. cyqnt_trd/trading_signal/selected_alpha/alpha30.py +87 -0
  55. cyqnt_trd/trading_signal/selected_alpha/alpha31.py +90 -0
  56. cyqnt_trd/trading_signal/selected_alpha/alpha32.py +86 -0
  57. cyqnt_trd/trading_signal/selected_alpha/alpha33.py +86 -0
  58. cyqnt_trd/trading_signal/selected_alpha/alpha34.py +87 -0
  59. cyqnt_trd/trading_signal/selected_alpha/alpha35.py +88 -0
  60. cyqnt_trd/trading_signal/selected_alpha/alpha36.py +86 -0
  61. cyqnt_trd/trading_signal/selected_alpha/alpha37.py +86 -0
  62. cyqnt_trd/trading_signal/selected_alpha/alpha38.py +87 -0
  63. cyqnt_trd/trading_signal/selected_alpha/alpha39.py +87 -0
  64. cyqnt_trd/trading_signal/selected_alpha/alpha4.py +86 -0
  65. cyqnt_trd/trading_signal/selected_alpha/alpha40.py +86 -0
  66. cyqnt_trd/trading_signal/selected_alpha/alpha41.py +86 -0
  67. cyqnt_trd/trading_signal/selected_alpha/alpha42.py +86 -0
  68. cyqnt_trd/trading_signal/selected_alpha/alpha43.py +86 -0
  69. cyqnt_trd/trading_signal/selected_alpha/alpha44.py +87 -0
  70. cyqnt_trd/trading_signal/selected_alpha/alpha45.py +88 -0
  71. cyqnt_trd/trading_signal/selected_alpha/alpha46.py +89 -0
  72. cyqnt_trd/trading_signal/selected_alpha/alpha47.py +86 -0
  73. cyqnt_trd/trading_signal/selected_alpha/alpha48.py +74 -0
  74. cyqnt_trd/trading_signal/selected_alpha/alpha49.py +88 -0
  75. cyqnt_trd/trading_signal/selected_alpha/alpha5.py +86 -0
  76. cyqnt_trd/trading_signal/selected_alpha/alpha50.py +86 -0
  77. cyqnt_trd/trading_signal/selected_alpha/alpha51.py +88 -0
  78. cyqnt_trd/trading_signal/selected_alpha/alpha52.py +87 -0
  79. cyqnt_trd/trading_signal/selected_alpha/alpha53.py +86 -0
  80. cyqnt_trd/trading_signal/selected_alpha/alpha54.py +86 -0
  81. cyqnt_trd/trading_signal/selected_alpha/alpha55.py +88 -0
  82. cyqnt_trd/trading_signal/selected_alpha/alpha56.py +86 -0
  83. cyqnt_trd/trading_signal/selected_alpha/alpha57.py +86 -0
  84. cyqnt_trd/trading_signal/selected_alpha/alpha58.py +74 -0
  85. cyqnt_trd/trading_signal/selected_alpha/alpha59.py +74 -0
  86. cyqnt_trd/trading_signal/selected_alpha/alpha6.py +86 -0
  87. cyqnt_trd/trading_signal/selected_alpha/alpha60.py +89 -0
  88. cyqnt_trd/trading_signal/selected_alpha/alpha61.py +88 -0
  89. cyqnt_trd/trading_signal/selected_alpha/alpha62.py +86 -0
  90. cyqnt_trd/trading_signal/selected_alpha/alpha63.py +74 -0
  91. cyqnt_trd/trading_signal/selected_alpha/alpha64.py +86 -0
  92. cyqnt_trd/trading_signal/selected_alpha/alpha65.py +86 -0
  93. cyqnt_trd/trading_signal/selected_alpha/alpha66.py +86 -0
  94. cyqnt_trd/trading_signal/selected_alpha/alpha67.py +74 -0
  95. cyqnt_trd/trading_signal/selected_alpha/alpha68.py +86 -0
  96. cyqnt_trd/trading_signal/selected_alpha/alpha69.py +74 -0
  97. cyqnt_trd/trading_signal/selected_alpha/alpha7.py +88 -0
  98. cyqnt_trd/trading_signal/selected_alpha/alpha70.py +74 -0
  99. cyqnt_trd/trading_signal/selected_alpha/alpha71.py +92 -0
  100. cyqnt_trd/trading_signal/selected_alpha/alpha72.py +86 -0
  101. cyqnt_trd/trading_signal/selected_alpha/alpha73.py +91 -0
  102. cyqnt_trd/trading_signal/selected_alpha/alpha74.py +86 -0
  103. cyqnt_trd/trading_signal/selected_alpha/alpha75.py +86 -0
  104. cyqnt_trd/trading_signal/selected_alpha/alpha76.py +74 -0
  105. cyqnt_trd/trading_signal/selected_alpha/alpha77.py +92 -0
  106. cyqnt_trd/trading_signal/selected_alpha/alpha78.py +86 -0
  107. cyqnt_trd/trading_signal/selected_alpha/alpha79.py +74 -0
  108. cyqnt_trd/trading_signal/selected_alpha/alpha8.py +87 -0
  109. cyqnt_trd/trading_signal/selected_alpha/alpha80.py +74 -0
  110. cyqnt_trd/trading_signal/selected_alpha/alpha81.py +86 -0
  111. cyqnt_trd/trading_signal/selected_alpha/alpha82.py +74 -0
  112. cyqnt_trd/trading_signal/selected_alpha/alpha83.py +86 -0
  113. cyqnt_trd/trading_signal/selected_alpha/alpha84.py +86 -0
  114. cyqnt_trd/trading_signal/selected_alpha/alpha85.py +86 -0
  115. cyqnt_trd/trading_signal/selected_alpha/alpha86.py +86 -0
  116. cyqnt_trd/trading_signal/selected_alpha/alpha87.py +74 -0
  117. cyqnt_trd/trading_signal/selected_alpha/alpha88.py +92 -0
  118. cyqnt_trd/trading_signal/selected_alpha/alpha89.py +74 -0
  119. cyqnt_trd/trading_signal/selected_alpha/alpha9.py +90 -0
  120. cyqnt_trd/trading_signal/selected_alpha/alpha90.py +74 -0
  121. cyqnt_trd/trading_signal/selected_alpha/alpha91.py +74 -0
  122. cyqnt_trd/trading_signal/selected_alpha/alpha92.py +92 -0
  123. cyqnt_trd/trading_signal/selected_alpha/alpha93.py +74 -0
  124. cyqnt_trd/trading_signal/selected_alpha/alpha94.py +86 -0
  125. cyqnt_trd/trading_signal/selected_alpha/alpha95.py +86 -0
  126. cyqnt_trd/trading_signal/selected_alpha/alpha96.py +92 -0
  127. cyqnt_trd/trading_signal/selected_alpha/alpha97.py +74 -0
  128. cyqnt_trd/trading_signal/selected_alpha/alpha98.py +87 -0
  129. cyqnt_trd/trading_signal/selected_alpha/alpha99.py +86 -0
  130. cyqnt_trd/trading_signal/selected_alpha/alpha_utils.py +342 -0
  131. cyqnt_trd/trading_signal/selected_alpha/create_all_alphas.py +279 -0
  132. cyqnt_trd/trading_signal/selected_alpha/generate_alphas.py +133 -0
  133. cyqnt_trd/trading_signal/selected_alpha/test_alpha.py +261 -0
  134. cyqnt_trd/trading_signal/signal/__init__.py +20 -0
  135. cyqnt_trd/trading_signal/signal/factor_based_signal.py +387 -0
  136. cyqnt_trd/trading_signal/signal/ma_signal.py +163 -0
  137. cyqnt_trd/utils/__init__.py +3 -0
  138. cyqnt_trd/utils/set_user.py +33 -0
  139. cyqnt_trd-0.1.2.dist-info/METADATA +148 -0
  140. cyqnt_trd-0.1.2.dist-info/RECORD +147 -0
  141. cyqnt_trd-0.1.2.dist-info/WHEEL +5 -0
  142. cyqnt_trd-0.1.2.dist-info/licenses/LICENSE +21 -0
  143. cyqnt_trd-0.1.2.dist-info/top_level.txt +2 -0
  144. test/real_time_trade.py +746 -0
  145. test/test_example_usage.py +381 -0
  146. test/test_get_data.py +310 -0
  147. test/test_realtime_price_tracker.py +546 -0
@@ -0,0 +1,192 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ 获取本机IP地址和网关IP地址
4
+ """
5
+
6
+ import socket
7
+ import subprocess
8
+ import platform
9
+ import re
10
+
11
+
12
+ def get_local_ip():
13
+ """
14
+ 获取本机IP地址(IPv4)
15
+
16
+ Returns:
17
+ str: 本机IP地址,如果获取失败返回None
18
+ """
19
+ try:
20
+ # 方法1: 通过连接外部地址获取本机IP
21
+ # 不实际发送数据,只是获取本机地址
22
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
23
+ try:
24
+ # 连接到外部地址(不需要实际连接成功)
25
+ s.connect(('8.8.8.8', 80))
26
+ ip = s.getsockname()[0]
27
+ except Exception:
28
+ # 如果连接失败,尝试获取主机名对应的IP
29
+ hostname = socket.gethostname()
30
+ ip = socket.gethostbyname(hostname)
31
+ finally:
32
+ s.close()
33
+ return ip
34
+ except Exception as e:
35
+ print(f"获取本机IP失败: {e}")
36
+ return None
37
+
38
+
39
+ def get_all_local_ips():
40
+ """
41
+ 获取所有本机IP地址(包括所有网络接口)
42
+
43
+ Returns:
44
+ list: IP地址列表
45
+ """
46
+ ips = []
47
+ try:
48
+ hostname = socket.gethostname()
49
+ # 获取所有IP地址
50
+ addrinfo = socket.getaddrinfo(hostname, None)
51
+ for item in addrinfo:
52
+ ip = item[4][0]
53
+ if ip not in ips and not ip.startswith('127.'):
54
+ ips.append(ip)
55
+ except Exception as e:
56
+ print(f"获取所有IP地址失败: {e}")
57
+
58
+ return ips
59
+
60
+
61
+ def get_gateway_ip():
62
+ """
63
+ 获取网关IP地址
64
+
65
+ Returns:
66
+ str: 网关IP地址,如果获取失败返回None
67
+ """
68
+ system = platform.system()
69
+
70
+ try:
71
+ if system == 'Darwin': # macOS
72
+ # 使用 netstat 命令获取默认网关
73
+ result = subprocess.run(
74
+ ['netstat', '-rn'],
75
+ capture_output=True,
76
+ text=True,
77
+ check=True
78
+ )
79
+
80
+ # 查找默认路由(Destination为default或0.0.0.0)
81
+ lines = result.stdout.split('\n')
82
+ for line in lines:
83
+ if 'default' in line or line.startswith('0.0.0.0'):
84
+ parts = line.split()
85
+ if len(parts) >= 2:
86
+ # Gateway通常在第二列
87
+ gateway = parts[1]
88
+ # 验证是否为有效的IP地址
89
+ if re.match(r'^\d+\.\d+\.\d+\.\d+$', gateway):
90
+ return gateway
91
+
92
+ # 如果netstat方法失败,尝试使用route命令
93
+ result = subprocess.run(
94
+ ['route', '-n', 'get', 'default'],
95
+ capture_output=True,
96
+ text=True,
97
+ check=True
98
+ )
99
+
100
+ for line in result.stdout.split('\n'):
101
+ if 'gateway:' in line.lower():
102
+ gateway = line.split(':')[-1].strip()
103
+ if re.match(r'^\d+\.\d+\.\d+\.\d+$', gateway):
104
+ return gateway
105
+
106
+ elif system == 'Linux':
107
+ # Linux系统
108
+ result = subprocess.run(
109
+ ['ip', 'route', 'show', 'default'],
110
+ capture_output=True,
111
+ text=True,
112
+ check=True
113
+ )
114
+
115
+ # 查找via后面的IP地址
116
+ match = re.search(r'via\s+(\d+\.\d+\.\d+\.\d+)', result.stdout)
117
+ if match:
118
+ return match.group(1)
119
+
120
+ # 如果ip命令失败,尝试route命令
121
+ result = subprocess.run(
122
+ ['route', '-n'],
123
+ capture_output=True,
124
+ text=True,
125
+ check=True
126
+ )
127
+
128
+ for line in result.stdout.split('\n'):
129
+ if line.startswith('0.0.0.0'):
130
+ parts = line.split()
131
+ if len(parts) >= 2:
132
+ gateway = parts[1]
133
+ if re.match(r'^\d+\.\d+\.\d+\.\d+$', gateway):
134
+ return gateway
135
+
136
+ elif system == 'Windows':
137
+ # Windows系统
138
+ result = subprocess.run(
139
+ ['ipconfig'],
140
+ capture_output=True,
141
+ text=True,
142
+ check=True
143
+ )
144
+
145
+ # 查找默认网关
146
+ for line in result.stdout.split('\n'):
147
+ if '默认网关' in line or 'Default Gateway' in line:
148
+ match = re.search(r'(\d+\.\d+\.\d+\.\d+)', line)
149
+ if match:
150
+ return match.group(1)
151
+
152
+ except subprocess.CalledProcessError as e:
153
+ print(f"执行系统命令失败: {e}")
154
+ except Exception as e:
155
+ print(f"获取网关IP失败: {e}")
156
+
157
+ return None
158
+
159
+
160
+ def main():
161
+ """主函数"""
162
+ print("=" * 50)
163
+ print("网络信息查询")
164
+ print("=" * 50)
165
+
166
+ # 获取本机IP
167
+ print("\n【本机IP地址】")
168
+ local_ip = get_local_ip()
169
+ if local_ip:
170
+ print(f"主要IP地址: {local_ip}")
171
+ else:
172
+ print("无法获取主要IP地址")
173
+
174
+ # 获取所有IP地址
175
+ all_ips = get_all_local_ips()
176
+ if all_ips:
177
+ print(f"所有IP地址: {', '.join(all_ips)}")
178
+
179
+ # 获取网关IP
180
+ print("\n【网关IP地址】")
181
+ gateway_ip = get_gateway_ip()
182
+ if gateway_ip:
183
+ print(f"默认网关: {gateway_ip}")
184
+ else:
185
+ print("无法获取网关IP地址")
186
+
187
+ print("\n" + "=" * 50)
188
+
189
+
190
+ if __name__ == '__main__':
191
+ main()
192
+
@@ -0,0 +1,227 @@
1
+ import os
2
+ import logging
3
+ from typing import List, Dict
4
+
5
+ from binance_sdk_spot.spot import Spot, ConfigurationRestAPI, SPOT_REST_API_PROD_URL
6
+ from binance_sdk_derivatives_trading_usds_futures.derivatives_trading_usds_futures import (
7
+ DerivativesTradingUsdsFutures,
8
+ ConfigurationRestAPI as FuturesConfigurationRestAPI,
9
+ DERIVATIVES_TRADING_USDS_FUTURES_REST_API_PROD_URL,
10
+ )
11
+
12
+ # Configure logging
13
+ logging.basicConfig(
14
+ level=logging.INFO,
15
+ format='%(asctime)s - %(levelname)s - %(message)s'
16
+ )
17
+
18
+
19
+ def get_spot_symbols_by_volume() -> List[Dict]:
20
+ """
21
+ 获取所有现货交易对列表,并按24小时交易量排序
22
+
23
+ Returns:
24
+ 按交易量降序排列的交易对列表,每个元素包含 symbol 和 volume
25
+ """
26
+ try:
27
+ # 创建现货客户端配置
28
+ spot_config = ConfigurationRestAPI(
29
+ api_key=os.getenv("API_KEY", "yNCZdF58V32y7oL2EATCIUKlmn8wkQ8ywoQukGIR7w4nkXBLldUFgld68I2xN0fj"),
30
+ api_secret=os.getenv("API_SECRET", "xktvKv6fcTxcgGeLrAmC3MMpX5qcDntzvBByVTPTyHEsNThg7rHoRW48qQhUpP0k"),
31
+ base_path=os.getenv("BASE_PATH", SPOT_REST_API_PROD_URL),
32
+ )
33
+
34
+ # 初始化现货客户端
35
+ spot_client = Spot(config_rest_api=spot_config)
36
+
37
+ # 获取所有交易对的24小时交易量统计
38
+ logging.info("正在获取现货交易对24小时交易量数据...")
39
+ ticker_response = spot_client.rest_api.ticker24hr()
40
+ ticker_data = ticker_response.data()
41
+
42
+ # 处理响应数据:可能是列表或单个对象,可能是 Pydantic 模型或字典
43
+ if not isinstance(ticker_data, list):
44
+ ticker_data = [ticker_data]
45
+
46
+ # 提取交易对和交易量信息
47
+ symbols_with_volume = []
48
+ for ticker in ticker_data:
49
+ # 如果是 Pydantic 模型,转换为字典
50
+ if hasattr(ticker, 'model_dump'):
51
+ ticker_dict = ticker.model_dump(by_alias=True)
52
+ elif hasattr(ticker, 'dict'):
53
+ ticker_dict = ticker.dict(by_alias=True)
54
+ elif isinstance(ticker, dict):
55
+ ticker_dict = ticker
56
+ else:
57
+ # 尝试直接访问属性
58
+ ticker_dict = {
59
+ 'symbol': getattr(ticker, 'symbol', getattr(ticker, 'Symbol', '')),
60
+ 'quoteVolume': getattr(ticker, 'quote_volume', getattr(ticker, 'quoteVolume', '0'))
61
+ }
62
+
63
+ symbol = ticker_dict.get('symbol', '')
64
+ # 使用 quoteVolume (以报价货币计的交易量) 作为排序依据
65
+ quote_volume = ticker_dict.get('quoteVolume', ticker_dict.get('quote_volume', '0'))
66
+ volume = float(quote_volume) if quote_volume else 0.0
67
+ symbols_with_volume.append({
68
+ 'symbol': symbol,
69
+ 'volume': volume,
70
+ 'volume_str': f"{volume:,.2f}"
71
+ })
72
+
73
+ # 按交易量降序排序
74
+ symbols_with_volume.sort(key=lambda x: x['volume'], reverse=True)
75
+
76
+ logging.info(f"成功获取 {len(symbols_with_volume)} 个现货交易对")
77
+ return symbols_with_volume
78
+
79
+ except Exception as e:
80
+ logging.error(f"获取现货交易对列表时出错: {e}")
81
+ import traceback
82
+ logging.error(traceback.format_exc())
83
+ return []
84
+
85
+
86
+ def get_futures_symbols_by_volume() -> List[Dict]:
87
+ """
88
+ 获取所有合约交易对列表,并按24小时交易量排序
89
+
90
+ Returns:
91
+ 按交易量降序排列的交易对列表,每个元素包含 symbol 和 volume
92
+ """
93
+ try:
94
+ # 创建合约客户端配置
95
+ futures_config = FuturesConfigurationRestAPI(
96
+ api_key=os.getenv("API_KEY", ""),
97
+ api_secret=os.getenv("API_SECRET", ""),
98
+ base_path=os.getenv(
99
+ "BASE_PATH", DERIVATIVES_TRADING_USDS_FUTURES_REST_API_PROD_URL
100
+ ),
101
+ )
102
+
103
+ # 初始化合约客户端
104
+ futures_client = DerivativesTradingUsdsFutures(config_rest_api=futures_config)
105
+
106
+ # 获取所有交易对的24小时交易量统计
107
+ logging.info("正在获取合约交易对24小时交易量数据...")
108
+ ticker_response = futures_client.rest_api.ticker24hr_price_change_statistics()
109
+ ticker_data = ticker_response.data()
110
+
111
+ # 处理响应数据:可能是列表或单个对象,可能是 Pydantic 模型或字典
112
+ if not isinstance(ticker_data, list):
113
+ ticker_data = [ticker_data]
114
+
115
+ # 提取交易对和交易量信息
116
+ symbols_with_volume = []
117
+ for ticker in ticker_data:
118
+ # 如果是 Pydantic 模型,转换为字典
119
+ if hasattr(ticker, 'model_dump'):
120
+ ticker_dict = ticker.model_dump(by_alias=True)
121
+ elif hasattr(ticker, 'dict'):
122
+ ticker_dict = ticker.dict(by_alias=True)
123
+ elif isinstance(ticker, dict):
124
+ ticker_dict = ticker
125
+ else:
126
+ # 尝试直接访问属性
127
+ ticker_dict = {
128
+ 'symbol': getattr(ticker, 'symbol', getattr(ticker, 'Symbol', '')),
129
+ 'quoteVolume': getattr(ticker, 'quote_volume', getattr(ticker, 'quoteVolume', '0'))
130
+ }
131
+
132
+ symbol = ticker_dict.get('symbol', '')
133
+ # 使用 quoteVolume (以报价货币计的交易量) 作为排序依据
134
+ quote_volume = ticker_dict.get('quoteVolume', ticker_dict.get('quote_volume', '0'))
135
+ volume = float(quote_volume) if quote_volume else 0.0
136
+ symbols_with_volume.append({
137
+ 'symbol': symbol,
138
+ 'volume': volume,
139
+ 'volume_str': f"{volume:,.2f}"
140
+ })
141
+
142
+ # 按交易量降序排序
143
+ symbols_with_volume.sort(key=lambda x: x['volume'], reverse=True)
144
+
145
+ logging.info(f"成功获取 {len(symbols_with_volume)} 个合约交易对")
146
+ return symbols_with_volume
147
+
148
+ except Exception as e:
149
+ logging.error(f"获取合约交易对列表时出错: {e}")
150
+ import traceback
151
+ logging.error(traceback.format_exc())
152
+ return []
153
+
154
+
155
+ def print_symbols_list(symbols: List[Dict], title: str, top_n: int = 20):
156
+ """
157
+ 打印交易对列表
158
+
159
+ Args:
160
+ symbols: 交易对列表
161
+ title: 标题
162
+ top_n: 显示前N个
163
+ """
164
+ print(f"\n{'='*80}")
165
+ print(f"{title}")
166
+ print(f"{'='*80}")
167
+ print(f"总共 {len(symbols)} 个交易对,显示前 {min(top_n, len(symbols))} 个:")
168
+ print(f"{'排名':<6} {'交易对':<20} {'24h交易量 (USDT)':>25}")
169
+ print(f"{'-'*80}")
170
+
171
+ for idx, item in enumerate(symbols[:top_n], 1):
172
+ print(f"{idx:<6} {item['symbol']:<20} {item['volume_str']:>25}")
173
+
174
+ if len(symbols) > top_n:
175
+ print(f"\n... 还有 {len(symbols) - top_n} 个交易对未显示")
176
+
177
+
178
+ def main():
179
+ """主函数"""
180
+ print("\n" + "="*80)
181
+ print("获取 Binance 交易对列表并按交易量排序")
182
+ print("="*80)
183
+
184
+ # 获取现货交易对列表
185
+ spot_symbols = get_spot_symbols_by_volume()
186
+ if spot_symbols:
187
+ print_symbols_list(spot_symbols, "现货交易对列表(按24小时交易量排序)", top_n=50)
188
+
189
+ # 获取合约交易对列表
190
+ futures_symbols = get_futures_symbols_by_volume()
191
+ if futures_symbols:
192
+ print_symbols_list(futures_symbols, "合约交易对列表(按24小时交易量排序)", top_n=50)
193
+
194
+ # 返回结果供其他脚本使用
195
+ return {
196
+ 'spot': spot_symbols,
197
+ 'futures': futures_symbols
198
+ }
199
+
200
+
201
+ if __name__ == "__main__":
202
+ result = main()
203
+
204
+ # 可选:保存到文件
205
+ import json
206
+ from datetime import datetime
207
+
208
+ output_dir = "/Users/user/Desktop/repo/cyqnt_trd/tmp"
209
+ if not os.path.exists(output_dir):
210
+ os.makedirs(output_dir)
211
+
212
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
213
+
214
+ # 保存现货列表
215
+ if result['spot']:
216
+ spot_file = os.path.join(output_dir, f"spot_symbols_by_volume_{timestamp}.json")
217
+ with open(spot_file, 'w', encoding='utf-8') as f:
218
+ json.dump(result['spot'], f, indent=2, ensure_ascii=False)
219
+ print(f"\n现货交易对列表已保存到: {spot_file}")
220
+
221
+ # 保存合约列表
222
+ if result['futures']:
223
+ futures_file = os.path.join(output_dir, f"futures_symbols_by_volume_{timestamp}.json")
224
+ with open(futures_file, 'w', encoding='utf-8') as f:
225
+ json.dump(result['futures'], f, indent=2, ensure_ascii=False)
226
+ print(f"合约交易对列表已保存到: {futures_file}")
227
+