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,431 @@
|
|
|
1
|
+
"""
|
|
2
|
+
因子和信号使用示例
|
|
3
|
+
|
|
4
|
+
展示如何使用factor中的因子和signal中的信号策略
|
|
5
|
+
|
|
6
|
+
使用方法:
|
|
7
|
+
# 方式1: 作为模块运行(推荐)
|
|
8
|
+
python -m cyqnt_trd.trading_signal.example_usage
|
|
9
|
+
|
|
10
|
+
# 方式2: 直接运行脚本
|
|
11
|
+
python example_usage.py
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import sys
|
|
15
|
+
import os
|
|
16
|
+
|
|
17
|
+
# 尝试直接导入(当作为 package 安装时)
|
|
18
|
+
try:
|
|
19
|
+
from cyqnt_trd.backtesting import BacktestFramework
|
|
20
|
+
from cyqnt_trd.trading_signal.factor import ma_factor, ma_cross_factor, rsi_factor
|
|
21
|
+
from cyqnt_trd.trading_signal.signal import (
|
|
22
|
+
ma_signal,
|
|
23
|
+
ma_cross_signal,
|
|
24
|
+
factor_based_signal,
|
|
25
|
+
multi_factor_signal,
|
|
26
|
+
normalized_factor_signal
|
|
27
|
+
)
|
|
28
|
+
from cyqnt_trd.trading_signal.selected_alpha import alpha1_factor, alpha15_factor
|
|
29
|
+
except ImportError:
|
|
30
|
+
# 如果直接导入失败,尝试添加项目根目录到路径(用于开发模式)
|
|
31
|
+
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
32
|
+
# 获取项目根目录(cyqnt_trd 的父目录)
|
|
33
|
+
# example_usage.py 位于: cyqnt_trd/cyqnt_trd/trading_signal/example_usage.py
|
|
34
|
+
# 需要向上2级到达: cyqnt_trd/
|
|
35
|
+
project_root = os.path.dirname(os.path.dirname(current_dir))
|
|
36
|
+
if project_root not in sys.path:
|
|
37
|
+
sys.path.insert(0, project_root)
|
|
38
|
+
|
|
39
|
+
# 再次尝试导入
|
|
40
|
+
try:
|
|
41
|
+
from cyqnt_trd.backtesting import BacktestFramework
|
|
42
|
+
from cyqnt_trd.trading_signal.factor import ma_factor, ma_cross_factor, rsi_factor
|
|
43
|
+
from cyqnt_trd.trading_signal.signal import (
|
|
44
|
+
ma_signal,
|
|
45
|
+
ma_cross_signal,
|
|
46
|
+
factor_based_signal,
|
|
47
|
+
multi_factor_signal,
|
|
48
|
+
normalized_factor_signal
|
|
49
|
+
)
|
|
50
|
+
from cyqnt_trd.trading_signal.selected_alpha import alpha1_factor, alpha15_factor
|
|
51
|
+
except ImportError as e:
|
|
52
|
+
print(f"导入错误: {e}")
|
|
53
|
+
print("\n提示:请使用以下方式之一:")
|
|
54
|
+
print(" 1. 安装 package: pip install -e .")
|
|
55
|
+
print(" 2. 作为模块运行: python -m cyqnt_trd.trading_signal.example_usage")
|
|
56
|
+
print(" 3. 在项目根目录下运行: cd /path/to/cyqnt_trd && python -m cyqnt_trd.trading_signal.example_usage")
|
|
57
|
+
sys.exit(1)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def example_1_use_factor(data_path):
|
|
61
|
+
"""
|
|
62
|
+
示例1: 使用factor中的因子进行因子测试
|
|
63
|
+
"""
|
|
64
|
+
print("=" * 60)
|
|
65
|
+
print("示例1: 使用factor中的因子进行因子测试")
|
|
66
|
+
print("=" * 60)
|
|
67
|
+
|
|
68
|
+
framework = BacktestFramework(data_path=data_path)
|
|
69
|
+
|
|
70
|
+
# 使用factor中的ma_factor进行测试
|
|
71
|
+
# 注意:ma_factor现在接收数据切片,不需要包装函数
|
|
72
|
+
def ma_factor_wrapper(data_slice):
|
|
73
|
+
return ma_factor(data_slice, period=3)
|
|
74
|
+
|
|
75
|
+
factor_results = framework.test_factor(
|
|
76
|
+
factor_func=ma_factor_wrapper,
|
|
77
|
+
forward_periods=5,
|
|
78
|
+
min_periods=10,
|
|
79
|
+
factor_name="MA5因子(来自factor模块)"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
save_dir = '/Users/user/Desktop/repo/cyqnt_trd/result'
|
|
83
|
+
framework.print_factor_results(
|
|
84
|
+
factor_results,
|
|
85
|
+
save_dir=save_dir
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def example_2_use_signal(data_path):
|
|
90
|
+
"""
|
|
91
|
+
示例2: 使用signal中的信号策略进行回测
|
|
92
|
+
"""
|
|
93
|
+
print("\n" + "=" * 60)
|
|
94
|
+
print("示例2: 使用signal中的信号策略进行回测")
|
|
95
|
+
print("=" * 60)
|
|
96
|
+
|
|
97
|
+
framework = BacktestFramework(data_path=data_path)
|
|
98
|
+
|
|
99
|
+
# 使用signal中的ma_signal进行回测
|
|
100
|
+
# 注意:需要创建一个包装函数,因为ma_signal需要period参数
|
|
101
|
+
# 使用闭包来捕获period值
|
|
102
|
+
period = 3
|
|
103
|
+
def ma_signal_wrapper(data_slice, position, entry_price, entry_index, take_profit, stop_loss, check_periods):
|
|
104
|
+
return ma_signal(
|
|
105
|
+
data_slice, position, entry_price, entry_index,
|
|
106
|
+
take_profit, stop_loss, period=period
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
backtest_results = framework.backtest_strategy(
|
|
110
|
+
signal_func=ma_signal_wrapper,
|
|
111
|
+
min_periods=10,
|
|
112
|
+
position_size=0.2,
|
|
113
|
+
initial_capital=10000.0,
|
|
114
|
+
commission_rate=0.00001,
|
|
115
|
+
take_profit=0.03,
|
|
116
|
+
stop_loss=0.1,
|
|
117
|
+
strategy_name="MA3策略(来自signal模块)"
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
framework.print_backtest_results(backtest_results)
|
|
121
|
+
|
|
122
|
+
save_dir = '/Users/user/Desktop/repo/cyqnt_trd/result'
|
|
123
|
+
framework.plot_backtest_results(
|
|
124
|
+
backtest_results,
|
|
125
|
+
save_dir=save_dir
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def example_3_factor_in_signal(data_path):
|
|
130
|
+
"""
|
|
131
|
+
示例3: 在signal中使用factor中的因子
|
|
132
|
+
"""
|
|
133
|
+
print("\n" + "=" * 60)
|
|
134
|
+
print("示例3: 在signal中使用factor中的因子")
|
|
135
|
+
print("=" * 60)
|
|
136
|
+
|
|
137
|
+
framework = BacktestFramework(data_path=data_path)
|
|
138
|
+
|
|
139
|
+
# 使用factor_based_signal,它内部会使用factor中的因子
|
|
140
|
+
# 创建一个包装函数,传入ma_factor作为因子函数
|
|
141
|
+
def factor_signal_wrapper(data_slice, position, entry_price, entry_index, take_profit, stop_loss, check_periods):
|
|
142
|
+
# 使用factor中的ma_factor
|
|
143
|
+
factor_func = lambda d: ma_factor(d, period=5)
|
|
144
|
+
return factor_based_signal(
|
|
145
|
+
data_slice, position, entry_price, entry_index,
|
|
146
|
+
take_profit, stop_loss, check_periods,
|
|
147
|
+
factor_func=factor_func
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
backtest_results = framework.backtest_strategy(
|
|
151
|
+
signal_func=factor_signal_wrapper,
|
|
152
|
+
min_periods=35, # 至少需要35个周期,确保factor_based_signal有足够的数据(30+2+缓冲)
|
|
153
|
+
position_size=0.2,
|
|
154
|
+
initial_capital=10000.0,
|
|
155
|
+
commission_rate=0.00001,
|
|
156
|
+
take_profit=0.1,
|
|
157
|
+
stop_loss=0.5,
|
|
158
|
+
check_periods=1, # 只能为1,因为实际使用时无法看到未来数据
|
|
159
|
+
strategy_name="基于MA因子的策略"
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
framework.print_backtest_results(backtest_results)
|
|
163
|
+
|
|
164
|
+
save_dir = '/Users/user/Desktop/repo/cyqnt_trd/result'
|
|
165
|
+
framework.plot_backtest_results(
|
|
166
|
+
backtest_results,
|
|
167
|
+
save_dir=save_dir
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def example_4_multi_factor(data_path):
|
|
172
|
+
"""
|
|
173
|
+
示例4: 使用多因子组合策略
|
|
174
|
+
"""
|
|
175
|
+
print("\n" + "=" * 60)
|
|
176
|
+
print("示例4: 使用多因子组合策略")
|
|
177
|
+
print("=" * 60)
|
|
178
|
+
|
|
179
|
+
framework = BacktestFramework(data_path=data_path)
|
|
180
|
+
|
|
181
|
+
# 使用multi_factor_signal,组合多个因子
|
|
182
|
+
def multi_factor_signal_wrapper(data_slice, position, entry_price, entry_index, take_profit, stop_loss, check_periods):
|
|
183
|
+
# 组合ma_factor和rsi_factor
|
|
184
|
+
factor_funcs = [
|
|
185
|
+
lambda d: ma_factor(d, period=5),
|
|
186
|
+
lambda d: rsi_factor(d, period=14)
|
|
187
|
+
]
|
|
188
|
+
weights = [0.6, 0.4] # MA因子权重0.6,RSI因子权重0.4
|
|
189
|
+
|
|
190
|
+
return multi_factor_signal(
|
|
191
|
+
data_slice, position, entry_price, entry_index,
|
|
192
|
+
take_profit, stop_loss, check_periods,
|
|
193
|
+
factor_funcs=factor_funcs,
|
|
194
|
+
weights=weights
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
backtest_results = framework.backtest_strategy(
|
|
198
|
+
signal_func=multi_factor_signal_wrapper,
|
|
199
|
+
min_periods=20, # 需要更多周期因为RSI需要14个周期
|
|
200
|
+
position_size=0.2,
|
|
201
|
+
initial_capital=10000.0,
|
|
202
|
+
commission_rate=0.00001,
|
|
203
|
+
take_profit=0.1,
|
|
204
|
+
stop_loss=0.5,
|
|
205
|
+
check_periods=1, # 只能为1,因为实际使用时无法看到未来数据
|
|
206
|
+
strategy_name="多因子组合策略(MA+RSI)"
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
framework.print_backtest_results(backtest_results)
|
|
210
|
+
|
|
211
|
+
save_dir = '/Users/user/Desktop/repo/cyqnt_trd/result'
|
|
212
|
+
framework.plot_backtest_results(
|
|
213
|
+
backtest_results,
|
|
214
|
+
save_dir=save_dir
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def example_5_alpha1_factor(data_path):
|
|
219
|
+
"""
|
|
220
|
+
示例5: 使用Alpha#1因子进行因子测试
|
|
221
|
+
"""
|
|
222
|
+
print("\n" + "=" * 60)
|
|
223
|
+
print("示例5: 使用Alpha#1因子进行因子测试")
|
|
224
|
+
print("=" * 60)
|
|
225
|
+
print("\n因子说明:")
|
|
226
|
+
print(" - 公式: rank(Ts_ArgMax(SignedPower(((returns<0)?stddev(returns,20):close),2.),5))-0.5)")
|
|
227
|
+
print(" - 策略逻辑:对过去5天按照收盘价最高或下行波动率最高进行排名")
|
|
228
|
+
print(" - 下行波动率最高的一天离计算时间越近,越可以投资")
|
|
229
|
+
print(" - 收盘价最高离计算时间越近,越可以投资")
|
|
230
|
+
print(" - 标签:mean-reversion+momentum")
|
|
231
|
+
print()
|
|
232
|
+
|
|
233
|
+
framework = BacktestFramework(data_path=data_path)
|
|
234
|
+
|
|
235
|
+
# 使用Alpha#1因子进行测试
|
|
236
|
+
def alpha1_wrapper(data_slice):
|
|
237
|
+
"""
|
|
238
|
+
Alpha#1 因子包装函数
|
|
239
|
+
|
|
240
|
+
使用默认参数:lookback_days=5, stddev_period=20, power=2.0
|
|
241
|
+
"""
|
|
242
|
+
return alpha1_factor(
|
|
243
|
+
data_slice,
|
|
244
|
+
lookback_days=5,
|
|
245
|
+
stddev_period=20,
|
|
246
|
+
power=2.0
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
# 测试因子
|
|
250
|
+
print("开始测试 Alpha#1 因子...")
|
|
251
|
+
print(f" 回看天数: 5")
|
|
252
|
+
print(f" 标准差周期: 20")
|
|
253
|
+
print(f" 幂次: 2.0")
|
|
254
|
+
print(f" 向前看周期: 7")
|
|
255
|
+
print()
|
|
256
|
+
|
|
257
|
+
factor_results = framework.test_factor(
|
|
258
|
+
factor_func=alpha1_wrapper,
|
|
259
|
+
forward_periods=7, # 未来7个周期
|
|
260
|
+
min_periods=30, # 至少需要30个周期(5+20+一些缓冲)
|
|
261
|
+
factor_name="Alpha#1因子"
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
# 打印结果并保存
|
|
265
|
+
save_dir = '/Users/user/Desktop/repo/cyqnt_trd/result'
|
|
266
|
+
framework.print_factor_results(
|
|
267
|
+
factor_results,
|
|
268
|
+
save_dir=save_dir
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def example_6_alpha1_signal(data_path):
|
|
273
|
+
"""
|
|
274
|
+
示例6: 使用基于Alpha#1因子的信号策略进行回测
|
|
275
|
+
"""
|
|
276
|
+
print("\n" + "=" * 60)
|
|
277
|
+
print("示例6: 使用基于Alpha#1因子的信号策略进行回测")
|
|
278
|
+
print("=" * 60)
|
|
279
|
+
|
|
280
|
+
framework = BacktestFramework(data_path=data_path)
|
|
281
|
+
|
|
282
|
+
# 创建使用 Alpha#1 因子的信号策略
|
|
283
|
+
def alpha1_signal_wrapper(data_slice, position, entry_price, entry_index, take_profit, stop_loss, check_periods):
|
|
284
|
+
"""
|
|
285
|
+
使用 Alpha#1 因子的信号策略
|
|
286
|
+
"""
|
|
287
|
+
# 使用 Alpha#1 因子
|
|
288
|
+
factor_func = lambda d: alpha1_factor(d, lookback_days=5, stddev_period=20, power=2.0)
|
|
289
|
+
return factor_based_signal(
|
|
290
|
+
data_slice, position, entry_price, entry_index,
|
|
291
|
+
take_profit, stop_loss, check_periods,
|
|
292
|
+
factor_func=factor_func
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
# 回测策略
|
|
296
|
+
print("开始回测基于 Alpha#1 因子的策略...")
|
|
297
|
+
backtest_results = framework.backtest_strategy(
|
|
298
|
+
signal_func=alpha1_signal_wrapper,
|
|
299
|
+
min_periods=30, # 至少需要30个周期
|
|
300
|
+
position_size=0.2, # 每次使用20%的资金
|
|
301
|
+
initial_capital=10000.0,
|
|
302
|
+
commission_rate=0.00001, # 0.001%手续费
|
|
303
|
+
take_profit=0.1, # 止盈10%
|
|
304
|
+
stop_loss=0.5, # 止损50%
|
|
305
|
+
check_periods=1, # 只能为1,因为实际使用时无法看到未来数据
|
|
306
|
+
strategy_name="基于Alpha#1因子的策略"
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
# 打印结果
|
|
310
|
+
framework.print_backtest_results(backtest_results)
|
|
311
|
+
|
|
312
|
+
# 绘制结果并保存
|
|
313
|
+
save_dir = '/Users/user/Desktop/repo/cyqnt_trd/result'
|
|
314
|
+
framework.plot_backtest_results(
|
|
315
|
+
backtest_results,
|
|
316
|
+
save_dir=save_dir
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def example_7_normalized_alpha15_signal(data_path):
|
|
321
|
+
"""
|
|
322
|
+
示例7: 使用基于归一化Alpha#15因子的信号策略进行回测
|
|
323
|
+
"""
|
|
324
|
+
print("\n" + "=" * 60)
|
|
325
|
+
print("示例7: 使用基于归一化Alpha#15因子的信号策略进行回测")
|
|
326
|
+
print("=" * 60)
|
|
327
|
+
print("\n策略说明:")
|
|
328
|
+
print(" - 使用 normalized_factor_signal 策略")
|
|
329
|
+
print(" - 因子:Alpha#15")
|
|
330
|
+
print(" - 公式: (-1 * sum(rank(correlation(rank(high), rank(volume), 3)), 3))")
|
|
331
|
+
print(" - 计算当前周期和之前30个周期的因子值,进行归一化后生成交易信号")
|
|
332
|
+
print(" - 当归一化后的因子值从负转正时买入,从正转负时卖出")
|
|
333
|
+
print()
|
|
334
|
+
|
|
335
|
+
framework = BacktestFramework(data_path=data_path)
|
|
336
|
+
|
|
337
|
+
# 创建使用归一化 Alpha#15 因子的信号策略
|
|
338
|
+
# 添加调试计数器
|
|
339
|
+
debug_count = {'total': 0, 'buy': 0, 'sell': 0, 'hold': 0, 'factor_zero': 0}
|
|
340
|
+
|
|
341
|
+
def normalized_alpha15_signal_wrapper(data_slice, position, entry_price, entry_index, take_profit, stop_loss, check_periods):
|
|
342
|
+
"""
|
|
343
|
+
使用归一化 Alpha#15 因子的信号策略
|
|
344
|
+
"""
|
|
345
|
+
debug_count['total'] += 1
|
|
346
|
+
|
|
347
|
+
# 使用 Alpha#15 因子
|
|
348
|
+
factor_func = lambda d: alpha15_factor(d)
|
|
349
|
+
|
|
350
|
+
# 调试:检查前几个因子值
|
|
351
|
+
if debug_count['total'] <= 5:
|
|
352
|
+
try:
|
|
353
|
+
test_factor = factor_func(data_slice.iloc[-30:] if len(data_slice) >= 30 else data_slice)
|
|
354
|
+
print(f" 调试 [{debug_count['total']}]: 数据长度={len(data_slice)}, 测试因子值={test_factor:.6f}")
|
|
355
|
+
except Exception as e:
|
|
356
|
+
print(f" 调试 [{debug_count['total']}]: 计算因子时出错: {e}")
|
|
357
|
+
|
|
358
|
+
signal = normalized_factor_signal(
|
|
359
|
+
data_slice, position, entry_price, entry_index,
|
|
360
|
+
take_profit, stop_loss, check_periods,
|
|
361
|
+
factor_func=factor_func,
|
|
362
|
+
lookback_periods=30 # 回看30个周期进行归一化
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
debug_count[signal] += 1
|
|
366
|
+
if debug_count['total'] % 5000 == 0:
|
|
367
|
+
print(f" 进度: 总调用={debug_count['total']}, buy={debug_count['buy']}, sell={debug_count['sell']}, hold={debug_count['hold']}")
|
|
368
|
+
|
|
369
|
+
return signal
|
|
370
|
+
|
|
371
|
+
# 回测策略
|
|
372
|
+
print("开始回测基于归一化 Alpha#15 因子的策略...")
|
|
373
|
+
print(f" 回看周期数: 30")
|
|
374
|
+
print(f" 止盈比例: 10%")
|
|
375
|
+
print(f" 止损比例: 50%")
|
|
376
|
+
print()
|
|
377
|
+
|
|
378
|
+
backtest_results = framework.backtest_strategy(
|
|
379
|
+
signal_func=normalized_alpha15_signal_wrapper,
|
|
380
|
+
min_periods=65, # 至少需要65个周期(30+30+5缓冲,确保有足够数据计算因子和归一化)
|
|
381
|
+
position_size=0.2, # 每次使用20%的资金
|
|
382
|
+
initial_capital=10000.0,
|
|
383
|
+
commission_rate=0.00001, # 0.001%手续费
|
|
384
|
+
take_profit=0.5, # 止盈10%
|
|
385
|
+
stop_loss=0.2, # 止损50%
|
|
386
|
+
check_periods=1, # 只能为1,因为实际使用时无法看到未来数据
|
|
387
|
+
strategy_name="基于归一化Alpha#15因子的策略"
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
# 打印调试信息
|
|
391
|
+
print(f"\n调试统计:")
|
|
392
|
+
print(f" 总调用次数: {debug_count['total']}")
|
|
393
|
+
print(f" buy信号: {debug_count['buy']}")
|
|
394
|
+
print(f" sell信号: {debug_count['sell']}")
|
|
395
|
+
print(f" hold信号: {debug_count['hold']}")
|
|
396
|
+
print()
|
|
397
|
+
|
|
398
|
+
# 打印结果
|
|
399
|
+
framework.print_backtest_results(backtest_results)
|
|
400
|
+
|
|
401
|
+
# 绘制结果并保存
|
|
402
|
+
save_dir = '/Users/user/Desktop/repo/cyqnt_trd/result'
|
|
403
|
+
framework.plot_backtest_results(
|
|
404
|
+
backtest_results,
|
|
405
|
+
save_dir=save_dir
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
def main():
|
|
410
|
+
"""
|
|
411
|
+
主函数:运行所有示例
|
|
412
|
+
"""
|
|
413
|
+
# 取消注释想要运行的示例
|
|
414
|
+
data_path = "/Users/user/Desktop/repo/data_all/tmp/data/BTCUSDT_current/BTCUSDT_3m_2880_20251215_000000_20251221_000000_20251222_173038.json"
|
|
415
|
+
# example_1_use_factor()
|
|
416
|
+
# example_2_use_signal(data_path)
|
|
417
|
+
# example_4_multi_factor()
|
|
418
|
+
# example_3_factor_in_signal(data_path)
|
|
419
|
+
# example_5_alpha1_factor() # Alpha#1因子测试
|
|
420
|
+
# example_6_alpha1_signal(data_path) # 基于Alpha#1因子的策略回测
|
|
421
|
+
example_7_normalized_alpha15_signal(data_path) # 基于归一化Alpha#15因子的策略回测
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
# print("\n提示:")
|
|
425
|
+
# print(" - 取消注释example_usage.py中的示例函数来运行测试")
|
|
426
|
+
# print(" - 推荐使用模块方式运行: python3 -m cyqnt_trd.trading_signal.example_usage")
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
if __name__ == "__main__":
|
|
430
|
+
main()
|
|
431
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""
|
|
2
|
+
交易因子模块
|
|
3
|
+
|
|
4
|
+
定义各种交易因子,用于预测价格方向
|
|
5
|
+
因子函数签名: factor_func(data: pd.DataFrame, index: int) -> float
|
|
6
|
+
- 正数表示看多,负数表示看空,0表示中性
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
# 导入所有因子
|
|
10
|
+
from .ma_factor import ma_factor, ma_cross_factor
|
|
11
|
+
from .rsi_factor import rsi_factor
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
'ma_factor',
|
|
15
|
+
'ma_cross_factor',
|
|
16
|
+
'rsi_factor',
|
|
17
|
+
]
|
|
18
|
+
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""
|
|
2
|
+
移动平均线因子
|
|
3
|
+
|
|
4
|
+
包含基于移动平均线的各种因子
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import pandas as pd
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def ma_factor(data_slice: 'pd.DataFrame', period: int = 5) -> float:
|
|
12
|
+
"""
|
|
13
|
+
简单移动平均线因子
|
|
14
|
+
|
|
15
|
+
如果当前价格高于过去period期的平均价格,返回1(看多)
|
|
16
|
+
否则返回-1(看空)
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
data_slice: 数据切片,必须包含至少 period+1 行数据
|
|
20
|
+
最后一行是当前数据点,前面 period 行是历史数据
|
|
21
|
+
period: 移动平均周期(默认5)
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
因子值:1.0(看多)、-1.0(看空)或 0(数据不足)
|
|
25
|
+
"""
|
|
26
|
+
if len(data_slice) < period + 1:
|
|
27
|
+
return 0.0
|
|
28
|
+
|
|
29
|
+
# 最后一行是当前数据点
|
|
30
|
+
current_price = data_slice.iloc[-1]['close_price']
|
|
31
|
+
# 前period行是历史数据(不包括最后一行)
|
|
32
|
+
# 使用最后period行数据计算MA
|
|
33
|
+
ma = data_slice.iloc[-period-1:-1]['close_price'].mean()
|
|
34
|
+
|
|
35
|
+
if current_price > ma:
|
|
36
|
+
return 1.0 # 看多
|
|
37
|
+
else:
|
|
38
|
+
return -1.0 # 看空
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def ma_cross_factor(data_slice: 'pd.DataFrame', short_period: int = 5, long_period: int = 20) -> float:
|
|
42
|
+
"""
|
|
43
|
+
移动平均线交叉因子
|
|
44
|
+
|
|
45
|
+
当短期均线上穿长期均线时看多,下穿时看空
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
data_slice: 数据切片,必须包含至少 long_period+2 行数据
|
|
49
|
+
最后一行是当前数据点,前面 long_period+1 行是历史数据
|
|
50
|
+
short_period: 短期均线周期(默认5)
|
|
51
|
+
long_period: 长期均线周期(默认20)
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
因子值:1.0(看多)、-1.0(看空)或 0(数据不足)
|
|
55
|
+
"""
|
|
56
|
+
if len(data_slice) < long_period + 2:
|
|
57
|
+
return 0.0
|
|
58
|
+
|
|
59
|
+
# 计算当前周期的均线(使用最后period行数据,不包括最后一行)
|
|
60
|
+
short_ma_current = data_slice.iloc[-short_period-1:-1]['close_price'].mean()
|
|
61
|
+
long_ma_current = data_slice.iloc[-long_period-1:-1]['close_price'].mean()
|
|
62
|
+
|
|
63
|
+
# 计算上一周期的均线(使用倒数第二行之前的数据)
|
|
64
|
+
short_ma_prev = data_slice.iloc[-short_period-2:-2]['close_price'].mean()
|
|
65
|
+
long_ma_prev = data_slice.iloc[-long_period-2:-2]['close_price'].mean()
|
|
66
|
+
|
|
67
|
+
# 上穿:之前短期均线在长期均线下方,现在在上方
|
|
68
|
+
if short_ma_prev <= long_ma_prev and short_ma_current > long_ma_current:
|
|
69
|
+
return 1.0 # 看多
|
|
70
|
+
# 下穿:之前短期均线在长期均线上方,现在在下方
|
|
71
|
+
elif short_ma_prev >= long_ma_prev and short_ma_current < long_ma_current:
|
|
72
|
+
return -1.0 # 看空
|
|
73
|
+
else:
|
|
74
|
+
return 0.0 # 中性
|
|
75
|
+
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""
|
|
2
|
+
RSI(相对强弱指标)因子
|
|
3
|
+
|
|
4
|
+
基于RSI指标的交易因子
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import pandas as pd
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def rsi_factor(data_slice: 'pd.DataFrame', period: int = 14, oversold: float = 30.0, overbought: float = 70.0) -> float:
|
|
12
|
+
"""
|
|
13
|
+
RSI因子
|
|
14
|
+
|
|
15
|
+
当RSI低于oversold时看多,高于overbought时看空
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
data_slice: 数据切片,必须包含至少 period+1 行数据
|
|
19
|
+
最后一行是当前数据点,前面 period 行是历史数据
|
|
20
|
+
period: RSI计算周期(默认14)
|
|
21
|
+
oversold: 超卖阈值(默认30)
|
|
22
|
+
overbought: 超买阈值(默认70)
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
因子值:1.0(看多)、-1.0(看空)或 0(数据不足或中性)
|
|
26
|
+
"""
|
|
27
|
+
if len(data_slice) < period + 1:
|
|
28
|
+
return 0.0
|
|
29
|
+
|
|
30
|
+
# 计算价格变化(使用最后period+1行数据)
|
|
31
|
+
prices = data_slice.iloc[-period-1:]['close_price'].values
|
|
32
|
+
deltas = np.diff(prices)
|
|
33
|
+
|
|
34
|
+
# 分离上涨和下跌
|
|
35
|
+
gains = np.where(deltas > 0, deltas, 0)
|
|
36
|
+
losses = np.where(deltas < 0, -deltas, 0)
|
|
37
|
+
|
|
38
|
+
# 计算平均收益和平均损失
|
|
39
|
+
avg_gain = np.mean(gains)
|
|
40
|
+
avg_loss = np.mean(losses)
|
|
41
|
+
|
|
42
|
+
# 计算RSI
|
|
43
|
+
if avg_loss == 0:
|
|
44
|
+
rsi = 100.0
|
|
45
|
+
else:
|
|
46
|
+
rs = avg_gain / avg_loss
|
|
47
|
+
rsi = 100.0 - (100.0 / (1.0 + rs))
|
|
48
|
+
|
|
49
|
+
# 根据RSI值返回因子
|
|
50
|
+
if rsi < oversold:
|
|
51
|
+
return 1.0 # 超卖,看多
|
|
52
|
+
elif rsi > overbought:
|
|
53
|
+
return -1.0 # 超买,看空
|
|
54
|
+
else:
|
|
55
|
+
return 0.0 # 中性
|
|
56
|
+
|