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.
- cyqnt_trd/__init__.py +26 -0
- cyqnt_trd/backtesting/README.md +264 -0
- cyqnt_trd/backtesting/__init__.py +12 -0
- cyqnt_trd/backtesting/factor_test.py +332 -0
- cyqnt_trd/backtesting/framework.py +311 -0
- cyqnt_trd/backtesting/strategy_backtest.py +545 -0
- cyqnt_trd/diagnose_api.py +28 -0
- cyqnt_trd/get_data/__init__.py +15 -0
- cyqnt_trd/get_data/get_futures_data.py +472 -0
- cyqnt_trd/get_data/get_trending_data.py +771 -0
- cyqnt_trd/online_trading/__init__.py +13 -0
- cyqnt_trd/online_trading/realtime_price_tracker.py +1001 -0
- cyqnt_trd/test.py +119 -0
- cyqnt_trd/test_script/README.md +411 -0
- cyqnt_trd/test_script/get_network_info.py +192 -0
- cyqnt_trd/test_script/get_symbols_by_volume.py +227 -0
- cyqnt_trd/test_script/realtime_price_tracker.py +839 -0
- cyqnt_trd/test_script/test_alpha.py +261 -0
- cyqnt_trd/test_script/test_kline_data.py +479 -0
- cyqnt_trd/test_script/test_order.py +1360 -0
- cyqnt_trd/trading_signal/README.md +276 -0
- cyqnt_trd/trading_signal/__init__.py +17 -0
- cyqnt_trd/trading_signal/example_test_alpha.py +430 -0
- cyqnt_trd/trading_signal/example_usage.py +431 -0
- cyqnt_trd/trading_signal/factor/__init__.py +18 -0
- cyqnt_trd/trading_signal/factor/ma_factor.py +75 -0
- cyqnt_trd/trading_signal/factor/rsi_factor.py +56 -0
- cyqnt_trd/trading_signal/selected_alpha/__init__.py +158 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha1.py +87 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha10.py +90 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha100.py +74 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha101.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha11.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha12.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha13.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha14.py +87 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha15.py +87 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha16.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha17.py +88 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha18.py +88 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha19.py +87 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha2.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha20.py +88 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha21.py +89 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha22.py +87 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha23.py +88 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha24.py +88 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha25.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha26.py +87 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha27.py +88 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha28.py +88 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha29.py +87 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha3.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha30.py +87 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha31.py +90 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha32.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha33.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha34.py +87 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha35.py +88 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha36.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha37.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha38.py +87 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha39.py +87 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha4.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha40.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha41.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha42.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha43.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha44.py +87 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha45.py +88 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha46.py +89 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha47.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha48.py +74 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha49.py +88 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha5.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha50.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha51.py +88 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha52.py +87 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha53.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha54.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha55.py +88 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha56.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha57.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha58.py +74 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha59.py +74 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha6.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha60.py +89 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha61.py +88 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha62.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha63.py +74 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha64.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha65.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha66.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha67.py +74 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha68.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha69.py +74 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha7.py +88 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha70.py +74 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha71.py +92 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha72.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha73.py +91 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha74.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha75.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha76.py +74 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha77.py +92 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha78.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha79.py +74 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha8.py +87 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha80.py +74 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha81.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha82.py +74 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha83.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha84.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha85.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha86.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha87.py +74 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha88.py +92 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha89.py +74 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha9.py +90 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha90.py +74 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha91.py +74 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha92.py +92 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha93.py +74 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha94.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha95.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha96.py +92 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha97.py +74 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha98.py +87 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha99.py +86 -0
- cyqnt_trd/trading_signal/selected_alpha/alpha_utils.py +342 -0
- cyqnt_trd/trading_signal/selected_alpha/create_all_alphas.py +279 -0
- cyqnt_trd/trading_signal/selected_alpha/generate_alphas.py +133 -0
- cyqnt_trd/trading_signal/selected_alpha/test_alpha.py +261 -0
- cyqnt_trd/trading_signal/signal/__init__.py +20 -0
- cyqnt_trd/trading_signal/signal/factor_based_signal.py +387 -0
- cyqnt_trd/trading_signal/signal/ma_signal.py +163 -0
- cyqnt_trd/utils/__init__.py +3 -0
- cyqnt_trd/utils/set_user.py +33 -0
- cyqnt_trd-0.1.2.dist-info/METADATA +148 -0
- cyqnt_trd-0.1.2.dist-info/RECORD +147 -0
- cyqnt_trd-0.1.2.dist-info/WHEEL +5 -0
- cyqnt_trd-0.1.2.dist-info/licenses/LICENSE +21 -0
- cyqnt_trd-0.1.2.dist-info/top_level.txt +2 -0
- test/real_time_trade.py +746 -0
- test/test_example_usage.py +381 -0
- test/test_get_data.py +310 -0
- 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
|
+
|