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,546 @@
1
+ """
2
+ 模拟实盘测试脚本
3
+
4
+ 参考 cyqnt_trd.online_trading.realtime_price_tracker 中的 RealtimePriceTracker 类,
5
+ 创建模拟实盘交易测试环境。
6
+
7
+ 使用方法:
8
+ python test_realtime_price_tracker.py
9
+ """
10
+
11
+ import os
12
+ import sys
13
+ import asyncio
14
+ import logging
15
+ from pathlib import Path
16
+ from datetime import datetime
17
+ from typing import Optional, Dict, Any
18
+
19
+ # 添加项目根目录到路径
20
+ project_root = Path(__file__).parent.parent
21
+ if str(project_root) not in sys.path:
22
+ sys.path.insert(0, str(project_root))
23
+
24
+ # 导入 cyqnt_trd 包
25
+ try:
26
+ from cyqnt_trd.online_trading.realtime_price_tracker import RealtimePriceTracker
27
+ from cyqnt_trd.trading_signal.signal.ma_signal import ma_signal, ma_cross_signal
28
+ from cyqnt_trd.trading_signal.signal.factor_based_signal import factor_based_signal
29
+ from cyqnt_trd.trading_signal.factor.ma_factor import ma_factor
30
+ from cyqnt_trd.trading_signal.factor.rsi_factor import rsi_factor
31
+ from cyqnt_trd.trading_signal.selected_alpha.alpha1 import alpha1_factor
32
+ except ImportError as e:
33
+ print(f"导入错误: {e}")
34
+ print("\n提示:请确保已安装 cyqnt_trd package: pip install -e /path/to/crypto_trading")
35
+ sys.exit(1)
36
+
37
+ # 配置日志
38
+ logging.basicConfig(
39
+ level=logging.INFO,
40
+ format='%(asctime)s - %(levelname)s - %(message)s'
41
+ )
42
+
43
+
44
+ class SimulatedTradingBot:
45
+ """
46
+ 模拟交易机器人
47
+
48
+ 使用 RealtimePriceTracker 获取实时数据,并根据交易信号执行模拟交易
49
+ """
50
+
51
+ def __init__(
52
+ self,
53
+ symbol: str,
54
+ interval: str = "3m",
55
+ lookback_periods: int = 100,
56
+ initial_capital: float = 10000.0,
57
+ position_size: float = 0.01, # 每次使用90%的资金
58
+ take_profit: float = 0.1, # 止盈10%
59
+ stop_loss: float = 0.05, # 止损5%
60
+ commission_rate: float = 0.0001, # 手续费0.01%
61
+ strategy: str = "ma5", # 策略类型: ma5, ma_cross, ma_factor, rsi_factor, alpha1
62
+ ssl_verify: bool = False
63
+ ):
64
+ """
65
+ 初始化模拟交易机器人
66
+
67
+ Args:
68
+ symbol: 交易对符号
69
+ interval: 时间间隔
70
+ lookback_periods: 历史数据周期数
71
+ initial_capital: 初始资金
72
+ position_size: 每次交易使用的资金比例(0-1)
73
+ take_profit: 止盈比例(0-1)
74
+ stop_loss: 止损比例(0-1)
75
+ commission_rate: 手续费率(0-1)
76
+ strategy: 策略类型
77
+ ssl_verify: SSL证书验证
78
+ """
79
+ self.symbol = symbol
80
+ self.interval = interval
81
+ self.initial_capital = initial_capital
82
+ self.position_size = position_size
83
+ self.take_profit = take_profit
84
+ self.stop_loss = stop_loss
85
+ self.commission_rate = commission_rate
86
+ self.strategy = strategy
87
+
88
+ # 创建价格跟踪器
89
+ self.tracker = RealtimePriceTracker(
90
+ symbol=symbol,
91
+ interval=interval,
92
+ lookback_periods=lookback_periods,
93
+ ssl_verify=ssl_verify
94
+ )
95
+
96
+ # 交易状态
97
+ self.position = 0.0 # 当前持仓数量
98
+ self.entry_price = 0.0 # 入场价格
99
+ self.entry_index = -1 # 入场索引
100
+ self.entry_time = None # 入场时间
101
+
102
+ # 账户状态
103
+ self.current_capital = initial_capital # 当前可用资金
104
+ self.total_assets = initial_capital # 总资产(包括持仓价值)
105
+
106
+ # 交易记录
107
+ self.completed_trades = [] # 已完成的交易
108
+ self.total_trades = 0
109
+ self.win_trades = 0
110
+ self.loss_trades = 0
111
+ self.total_profit = 0.0
112
+ self.max_drawdown = 0.0
113
+ self.peak_assets = initial_capital # 资产峰值
114
+
115
+ # 统计信息
116
+ self.start_time = datetime.now()
117
+ self.last_update_time = None
118
+
119
+ # 注册回调
120
+ self.tracker.register_on_new_kline(self._on_new_kline)
121
+
122
+ def _calculate_signal(self, data_df) -> Optional[str]:
123
+ """
124
+ 根据策略计算交易信号
125
+
126
+ Args:
127
+ data_df: 历史数据DataFrame
128
+
129
+ Returns:
130
+ 交易信号: 'buy', 'sell', 'hold' 或 None
131
+ """
132
+ if len(data_df) < 10:
133
+ return None
134
+
135
+ # 使用足够的数据切片
136
+ data_slice = data_df.iloc[-30:].copy() if len(data_df) >= 30 else data_df.copy()
137
+
138
+ try:
139
+ if self.strategy == "ma5":
140
+ if len(data_slice) >= 6:
141
+ return ma_signal(
142
+ data_slice=data_slice,
143
+ position=self.position,
144
+ entry_price=self.entry_price,
145
+ entry_index=self.entry_index,
146
+ take_profit=self.take_profit,
147
+ stop_loss=self.stop_loss,
148
+ period=5
149
+ )
150
+
151
+ elif self.strategy == "ma_cross":
152
+ if len(data_slice) >= 22:
153
+ return ma_cross_signal(
154
+ data_slice=data_slice,
155
+ position=self.position,
156
+ entry_price=self.entry_price,
157
+ entry_index=self.entry_index,
158
+ take_profit=self.take_profit,
159
+ stop_loss=self.stop_loss,
160
+ check_periods=1,
161
+ short_period=5,
162
+ long_period=20
163
+ )
164
+
165
+ elif self.strategy == "ma_factor":
166
+ if len(data_slice) >= 6:
167
+ return factor_based_signal(
168
+ data_slice=data_slice,
169
+ position=self.position,
170
+ entry_price=self.entry_price,
171
+ entry_index=self.entry_index,
172
+ take_profit=self.take_profit,
173
+ stop_loss=self.stop_loss,
174
+ check_periods=1,
175
+ factor_func=lambda d: ma_factor(d, period=5),
176
+ factor_period=5
177
+ )
178
+
179
+ elif self.strategy == "rsi_factor":
180
+ if len(data_slice) >= 16:
181
+ return factor_based_signal(
182
+ data_slice=data_slice,
183
+ position=self.position,
184
+ entry_price=self.entry_price,
185
+ entry_index=self.entry_index,
186
+ take_profit=self.take_profit,
187
+ stop_loss=self.stop_loss,
188
+ check_periods=1,
189
+ factor_func=lambda d: rsi_factor(d, period=14),
190
+ factor_period=14
191
+ )
192
+
193
+ elif self.strategy == "alpha1":
194
+ if len(data_slice) >= 26:
195
+ return factor_based_signal(
196
+ data_slice=data_slice,
197
+ position=self.position,
198
+ entry_price=self.entry_price,
199
+ entry_index=self.entry_index,
200
+ take_profit=self.take_profit,
201
+ stop_loss=self.stop_loss,
202
+ check_periods=1,
203
+ factor_func=lambda d: alpha1_factor(d, lookback_days=5, stddev_period=20, power=2.0),
204
+ factor_period=25
205
+ )
206
+ except Exception as e:
207
+ logging.debug(f"计算信号时出错: {e}")
208
+ return None
209
+
210
+ return None
211
+
212
+ def _on_new_kline(self, kline_dict: Dict[str, Any], data_df):
213
+ """
214
+ 新K线数据回调函数
215
+
216
+ Args:
217
+ kline_dict: 新K线数据字典
218
+ data_df: 历史数据DataFrame
219
+ """
220
+ current_price = kline_dict['close_price']
221
+ current_time = kline_dict['open_time_str']
222
+
223
+ # 更新总资产
224
+ if self.position > 0:
225
+ position_value = self.position * current_price
226
+ self.total_assets = self.current_capital + position_value
227
+ floating_profit_pct = (current_price - self.entry_price) / self.entry_price * 100
228
+ else:
229
+ self.total_assets = self.current_capital
230
+ floating_profit_pct = 0.0
231
+
232
+ # 更新最大回撤
233
+ if self.total_assets > self.peak_assets:
234
+ self.peak_assets = self.total_assets
235
+ drawdown = (self.peak_assets - self.total_assets) / self.peak_assets
236
+ if drawdown > self.max_drawdown:
237
+ self.max_drawdown = drawdown
238
+
239
+ # 计算交易信号
240
+ signal = self._calculate_signal(data_df)
241
+
242
+ # 显示状态
243
+ self._display_status(current_time, current_price, signal, floating_profit_pct)
244
+
245
+ # 执行交易
246
+ if signal == 'buy' and self.position == 0:
247
+ self._execute_buy(current_price, current_time, len(data_df) - 1)
248
+ elif signal == 'sell' and self.position > 0:
249
+ self._execute_sell(current_price, current_time)
250
+
251
+ self.last_update_time = datetime.now()
252
+
253
+ def _execute_buy(self, price: float, time_str: str, index: int):
254
+ """
255
+ 执行买入操作
256
+
257
+ Args:
258
+ price: 买入价格
259
+ time_str: 时间字符串
260
+ index: 数据索引
261
+ """
262
+ # 计算买入金额(扣除手续费)
263
+ buy_amount = self.current_capital * self.position_size
264
+ commission = buy_amount * self.commission_rate
265
+ net_buy_amount = buy_amount - commission
266
+
267
+ # 计算买入数量
268
+ self.position = net_buy_amount / price
269
+ self.entry_price = price
270
+ self.entry_index = index
271
+ self.entry_time = time_str
272
+
273
+ # 更新资金
274
+ self.current_capital -= buy_amount
275
+
276
+ print(f"\n{'='*80}")
277
+ print(f"✅ 执行买入")
278
+ print(f" 时间: {time_str}")
279
+ print(f" 价格: {price:.2f}")
280
+ print(f" 数量: {self.position:.6f}")
281
+ print(f" 金额: {buy_amount:.2f}")
282
+ print(f" 手续费: {commission:.2f}")
283
+ print(f" 剩余资金: {self.current_capital:.2f}")
284
+ print(f"{'='*80}\n")
285
+
286
+ def _execute_sell(self, price: float, time_str: str):
287
+ """
288
+ 执行卖出操作
289
+
290
+ Args:
291
+ price: 卖出价格
292
+ time_str: 时间字符串
293
+ """
294
+ # 计算卖出金额
295
+ sell_amount = self.position * price
296
+ commission = sell_amount * self.commission_rate
297
+ net_sell_amount = sell_amount - commission
298
+
299
+ # 计算盈亏
300
+ cost_basis = self.position * self.entry_price
301
+ profit_amount = net_sell_amount - cost_basis
302
+ profit_pct = (price - self.entry_price) / self.entry_price * 100
303
+
304
+ # 更新资金
305
+ self.current_capital += net_sell_amount
306
+
307
+ # 记录交易
308
+ trade_record = {
309
+ 'entry_time': self.entry_time,
310
+ 'exit_time': time_str,
311
+ 'entry_price': self.entry_price,
312
+ 'exit_price': price,
313
+ 'quantity': self.position,
314
+ 'profit_amount': profit_amount,
315
+ 'profit_pct': profit_pct,
316
+ 'commission': commission * 2 # 买入和卖出手续费
317
+ }
318
+ self.completed_trades.append(trade_record)
319
+
320
+ # 更新统计
321
+ self.total_trades += 1
322
+ self.total_profit += profit_amount
323
+ if profit_amount > 0:
324
+ self.win_trades += 1
325
+ else:
326
+ self.loss_trades += 1
327
+
328
+ print(f"\n{'='*80}")
329
+ print(f"✅ 执行卖出")
330
+ print(f" 时间: {time_str}")
331
+ print(f" 价格: {price:.2f}")
332
+ print(f" 入场价: {self.entry_price:.2f}")
333
+ print(f" 数量: {self.position:.6f}")
334
+ print(f" 盈亏金额: {profit_amount:+.2f}")
335
+ print(f" 盈亏比例: {profit_pct:+.2f}%")
336
+ print(f" 手续费: {commission:.2f}")
337
+ print(f" 当前资金: {self.current_capital:.2f}")
338
+ print(f"{'='*80}\n")
339
+
340
+ # 重置持仓
341
+ self.position = 0.0
342
+ self.entry_price = 0.0
343
+ self.entry_index = -1
344
+ self.entry_time = None
345
+
346
+ def _display_status(self, time_str: str, price: float, signal: Optional[str], floating_profit_pct: float):
347
+ """
348
+ 显示当前状态
349
+
350
+ Args:
351
+ time_str: 时间字符串
352
+ price: 当前价格
353
+ signal: 交易信号
354
+ floating_profit_pct: 浮动盈亏百分比
355
+ """
356
+ # 计算统计信息
357
+ total_return_pct = (self.total_assets - self.initial_capital) / self.initial_capital * 100
358
+ runtime = datetime.now() - self.start_time
359
+ runtime_str = f"{runtime.days}天 {runtime.seconds // 3600}小时 {(runtime.seconds % 3600) // 60}分钟"
360
+ win_rate = (self.win_trades / self.total_trades * 100) if self.total_trades > 0 else 0.0
361
+
362
+ # 信号显示
363
+ if signal:
364
+ signal_emoji = "🟢" if signal == 'buy' else "🔴" if signal == 'sell' else "⚪"
365
+ signal_text = f"{signal_emoji} {signal.upper()}"
366
+ else:
367
+ signal_text = "⚪ HOLD"
368
+
369
+ print(f"\n{'='*80}")
370
+ print(f"📊 实时状态更新")
371
+ print(f"{'='*80}")
372
+ print(f"时间: {time_str}")
373
+ print(f"价格: {price:.2f}")
374
+ print(f"信号: {signal_text}")
375
+ if self.position > 0:
376
+ print(f"持仓: {self.position:.6f} | 入场价: {self.entry_price:.2f} | 浮动盈亏: {floating_profit_pct:+.2f}%")
377
+ else:
378
+ print(f"持仓: 无")
379
+ print(f"{'='*80}")
380
+ print(f"💰 账户统计:")
381
+ print(f" 初始资金: {self.initial_capital:.2f}")
382
+ print(f" 当前资金: {self.current_capital:.2f}")
383
+ if self.position > 0:
384
+ print(f" 持仓价值: {self.position * price:.2f}")
385
+ print(f" 总资产: {self.total_assets:.2f}")
386
+ print(f" 累计盈亏: {self.total_profit:+.2f} ({total_return_pct:+.2f}%)")
387
+ print(f" 最大回撤: {self.max_drawdown * 100:.2f}%")
388
+ print(f" 运行时间: {runtime_str}")
389
+ print(f" 总交易次数: {self.total_trades} | 盈利: {self.win_trades} | 亏损: {self.loss_trades} | 胜率: {win_rate:.2f}%")
390
+ print(f"{'='*80}\n")
391
+
392
+ def get_statistics(self) -> Dict[str, Any]:
393
+ """
394
+ 获取交易统计信息
395
+
396
+ Returns:
397
+ 统计信息字典
398
+ """
399
+ total_return_pct = (self.total_assets - self.initial_capital) / self.initial_capital * 100
400
+ runtime = datetime.now() - self.start_time
401
+ win_rate = (self.win_trades / self.total_trades * 100) if self.total_trades > 0 else 0.0
402
+
403
+ # 计算平均盈亏
404
+ avg_profit = self.total_profit / self.total_trades if self.total_trades > 0 else 0.0
405
+
406
+ # 计算夏普比率(简化版)
407
+ if len(self.completed_trades) > 0:
408
+ returns = [t['profit_pct'] / 100 for t in self.completed_trades]
409
+ import numpy as np
410
+ if len(returns) > 1:
411
+ sharpe_ratio = np.mean(returns) / np.std(returns) * np.sqrt(252) if np.std(returns) > 0 else 0.0
412
+ else:
413
+ sharpe_ratio = 0.0
414
+ else:
415
+ sharpe_ratio = 0.0
416
+
417
+ return {
418
+ 'initial_capital': self.initial_capital,
419
+ 'final_capital': self.total_assets,
420
+ 'total_return': self.total_profit,
421
+ 'total_return_pct': total_return_pct,
422
+ 'total_trades': self.total_trades,
423
+ 'win_trades': self.win_trades,
424
+ 'loss_trades': self.loss_trades,
425
+ 'win_rate': win_rate,
426
+ 'max_drawdown': self.max_drawdown * 100,
427
+ 'avg_profit': avg_profit,
428
+ 'sharpe_ratio': sharpe_ratio,
429
+ 'runtime': str(runtime),
430
+ 'completed_trades': self.completed_trades
431
+ }
432
+
433
+ async def start(self):
434
+ """
435
+ 启动模拟交易
436
+ """
437
+ print("="*80)
438
+ print("🚀 模拟实盘交易测试启动")
439
+ print("="*80)
440
+ print(f"交易对: {self.symbol}")
441
+ print(f"时间间隔: {self.interval}")
442
+ print(f"策略: {self.strategy}")
443
+ print(f"初始资金: {self.initial_capital:.2f}")
444
+ print(f"仓位大小: {self.position_size * 100:.0f}%")
445
+ print(f"止盈: {self.take_profit * 100:.0f}%")
446
+ print(f"止损: {self.stop_loss * 100:.0f}%")
447
+ print(f"手续费率: {self.commission_rate * 100:.4f}%")
448
+ print("="*80)
449
+ print("\n等待实时数据...\n")
450
+
451
+ await self.tracker.run_forever()
452
+
453
+ def print_final_report(self):
454
+ """
455
+ 打印最终报告
456
+ """
457
+ stats = self.get_statistics()
458
+
459
+ print("\n" + "="*80)
460
+ print("📊 最终交易报告")
461
+ print("="*80)
462
+ print(f"交易对: {self.symbol}")
463
+ print(f"策略: {self.strategy}")
464
+ print(f"运行时间: {stats['runtime']}")
465
+ print(f"\n💰 资金统计:")
466
+ print(f" 初始资金: {stats['initial_capital']:.2f}")
467
+ print(f" 最终资产: {stats['final_capital']:.2f}")
468
+ print(f" 总盈亏: {stats['total_return']:+.2f}")
469
+ print(f" 总收益率: {stats['total_return_pct']:+.2f}%")
470
+ print(f"\n📈 交易统计:")
471
+ print(f" 总交易次数: {stats['total_trades']}")
472
+ print(f" 盈利次数: {stats['win_trades']}")
473
+ print(f" 亏损次数: {stats['loss_trades']}")
474
+ print(f" 胜率: {stats['win_rate']:.2f}%")
475
+ print(f" 平均盈亏: {stats['avg_profit']:.2f}")
476
+ print(f"\n📉 风险指标:")
477
+ print(f" 最大回撤: {stats['max_drawdown']:.2f}%")
478
+ print(f" 夏普比率: {stats['sharpe_ratio']:.2f}")
479
+ print("="*80)
480
+
481
+ # 显示最近10笔交易
482
+ if len(self.completed_trades) > 0:
483
+ print(f"\n最近10笔交易记录:")
484
+ print("-"*80)
485
+ for i, trade in enumerate(self.completed_trades[-10:], 1):
486
+ print(f"{i}. {trade['entry_time']} -> {trade['exit_time']}")
487
+ print(f" 入场: {trade['entry_price']:.2f} | 出场: {trade['exit_price']:.2f}")
488
+ print(f" 盈亏: {trade['profit_amount']:+.2f} ({trade['profit_pct']:+.2f}%)")
489
+ print("="*80)
490
+
491
+
492
+ async def test_simulated_trading():
493
+ """
494
+ 测试模拟交易
495
+ """
496
+ # 创建模拟交易机器人
497
+ bot = SimulatedTradingBot(
498
+ symbol="BTCUSDT",
499
+ interval="1m",
500
+ lookback_periods=100,
501
+ initial_capital=10000.0,
502
+ position_size=0.01,
503
+ take_profit=0.1,
504
+ stop_loss=0.05,
505
+ commission_rate=0.0001,
506
+ strategy="ma5", # 可选: ma5, ma_cross, ma_factor, rsi_factor, alpha1
507
+ ssl_verify=False
508
+ )
509
+
510
+ try:
511
+ # 启动交易
512
+ await bot.start()
513
+ except KeyboardInterrupt:
514
+ print("\n\n收到中断信号,正在停止...")
515
+ finally:
516
+ # 打印最终报告
517
+ bot.print_final_report()
518
+
519
+
520
+ def main():
521
+ """
522
+ 主函数
523
+ """
524
+ print("="*80)
525
+ print("模拟实盘交易测试脚本")
526
+ print("="*80)
527
+ print("\n注意:")
528
+ print(" 1. 确保已安装 cyqnt_trd package")
529
+ print(" 2. 需要网络连接访问 Binance WebSocket")
530
+ print(" 3. 按 Ctrl+C 停止测试")
531
+ print(" 4. 测试结果将显示在控制台")
532
+ print()
533
+
534
+ try:
535
+ asyncio.run(test_simulated_trading())
536
+ except KeyboardInterrupt:
537
+ print("\n测试已停止")
538
+ except Exception as e:
539
+ print(f"\n测试过程中出现错误: {e}")
540
+ import traceback
541
+ traceback.print_exc()
542
+
543
+
544
+ if __name__ == "__main__":
545
+ main()
546
+