-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathStrategy.py
265 lines (213 loc) · 11.4 KB
/
Strategy.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
import numpy as np
import pandas as pd
from datetime import datetime, timedelta
from iFinDPy import *
from sklearn.linear_model import LogisticRegression
class Strategy:
def __init__(self):
"""
全部策略的父类 Strategy。后续在编写新的策略时,可以在此基础上添加新的内容,但子类中需要覆写父类中已有的属性和方法。
"""
self.name = None # 策略的名字
self.indicator_require = {} # 策略所需要的技术指标
# 例如:{'ma':[5,10],'TR':[True]},第一个键值对表示需要5日和10日均线,第二个表示需要True Range(极差),因为有些指标不需要参数,所以只需放True即可。
self.time_frequency = 0 # 策略所需要的数据频率
self.need_daily = False # 策略是否需要用到日频数据
def open_criterion(self, data, i, direction=0):
"""
策略的开仓条件
:param data: 包含了K线和技术指标的数据框
:param i: 当前时间步
:param direction: 默认值为0,表示在没有头寸时的开仓条件。如果是1或-1,则表示在持有多头或空头头寸时的加仓条件
:return: 返回0表示不开仓,返回正数或负数表示开多或开空。如果是小数,表示用当前账户余额的比例来交保证金;如果大于1的数,则表示具体开多少手。
"""
return 0
def close_criterion(self, data, i, direction):
"""
策略的平仓条件
:param data: 包含了K线和技术指标的数据框
:param i: 当前时间步
:param direction: 取1或-1,表示在持有多头或空头头寸时的平仓条件
:return: 返回0表示不平仓,返回小数表示平掉当前头寸的比例大小;如果是大于1的数,则表示具体平多少手。
"""
return 0
class momentum_1h_original(Strategy):
"""
结合60小时线和60日线的双均线策略。在这两个均线以上时多开,在这两个均线以下时多平,其余情况不开仓或平仓。
"""
def __init__(self):
super().__init__()
self.name = 'momentum_1h_original'
self.indicator_require = {'ma': [60]}
self.time_frequency = 60
self.need_daily = True
def open_criterion(self, data, i, direction=0):
if direction == 0:
# 当direction是0的时候,此时是新开仓,否则可以加仓
temp_price = data.loc[i, 'close']
temp_ma60 = data.loc[i, 'ma60']
temp_ma60_daily = data.loc[i, 'ma60_daily']
if temp_price > temp_ma60 and temp_price > temp_ma60_daily:
return 0.2
if temp_price < temp_ma60 and temp_price < temp_ma60_daily:
return -0.2
return 0
def close_criterion(self, data, i, direction):
temp_price = self.data.loc[i, 'close']
temp_ma60 = data.loc[i, 'ma60']
temp_ma60_daily = data.loc[i, 'ma60_daily']
if direction == 1:
if temp_price < temp_ma60 or temp_price < temp_ma60_daily:
return 1
if direction == -1:
if temp_price > temp_ma60 or temp_price > temp_ma60_daily:
return 1
return 0
class momentum_1h_updated(Strategy):
"""
60小时线和60日线双均线策略的改进版本,放宽了平仓条件,并加入了时间止损。
"""
def __init__(self):
super().__init__()
self.name = 'momentum_1h_updated'
self.indicator_require = {'ma': [60]}
self.time_frequency = 60
self.stop_loss_point = 0 # 止损点位
self.ready_to_stop = False # 是否准备止损
self.wait_k_line_num = 0 # 等待K线的数量
self.need_daily = True
def open_criterion(self, data, i, direction=0):
if direction == 0:
temp_price = data.loc[i, 'close']
temp_ma60 = data.loc[i, 'ma60']
temp_ma60_daily = data.loc[i, 'ma60_daily']
if temp_price > temp_ma60 and temp_price > temp_ma60_daily:
return 0.2
if temp_price < temp_ma60 and temp_price < temp_ma60_daily:
return -0.2
return 0
def close_criterion(self, data, i, direction):
temp_price = data.loc[i, 'close']
temp_ma60 = data.loc[i, 'ma60']
temp_ma60_daily = data.loc[i, 'ma60_daily']
if direction == 1:
if temp_price < temp_ma60 or temp_price < temp_ma60_daily:
if not self.ready_to_stop:
# 当第一次触发止损条件时 开启止损记录 调整止损点位
self.ready_to_stop = True
self.stop_loss_point = temp_price * 0.99 # 设置止损点
return 0
else:
# 当已经触发了止损时 如果当前价格已经跌破了止损点点位 则平仓 否则 把等待k线数加一 当等了5根k线没修复时 平仓
if temp_price < self.stop_loss_point:
self.ready_to_stop = False
self.wait_k_line_num = 0
return 1
self.wait_k_line_num += 1
if self.wait_k_line_num >= 5 and (
temp_price < temp_ma60 * 0.99 or temp_price < temp_ma60_daily * 0.99):
self.wait_k_line_num = 0
self.ready_to_stop = False
return 1
if direction == -1:
if temp_price > temp_ma60 or temp_price > temp_ma60_daily:
if not self.ready_to_stop:
self.ready_to_stop = True
self.stop_loss_point = temp_price * 1.01 # 设置止损点
return 0
else:
if temp_price > self.stop_loss_point:
self.ready_to_stop = False
self.wait_k_line_num = 0
return 1
self.wait_k_line_num += 1
if self.wait_k_line_num >= 5 and (
temp_price > temp_ma60 * 1.01 or temp_price > temp_ma60_daily * 1.01):
self.wait_k_line_num = 0
self.ready_to_stop = False
return 1
return 0
class momentum_v3(Strategy):
"""
改进的动量策略版本 以小时线的ma15 和 ma60作为判断指标 同时动态维护每一次交易的止盈点位 引入Trailing Stop Loss机制
"""
def __init__(self):
super().__init__()
self.name = 'momentum_v3'
self.indicator_require = {'ma': [15, 60]}
self.time_frequency = 60
self.temp_date = None # 临时日期
self.temp_high = None # 临时最高价
self.temp_low = None # 临时最低价
self.long_target = None # 多头目标
self.short_target = None # 空头目标
self.sl_target = None # 止损目标
self.count = 0 # 计数器
self.temp_ZL = None # 临时证券代码
self.need_daily = False
self.open_price = None # 开仓价
self.sl_price = None # 止损价
self.ready_to_stop = False # 是否准备止损
self.wait_k_line = 0 # 等待K线数量
def open_criterion(self, data, i, direction=0):
if direction == 0:
temp_price = data.loc[i, 'close']
data['date'] = pd.to_datetime(data['date'])
temp_date = data.loc[i, 'date'].date()
temp_ma15 = data.loc[i, 'ma15']
temp_ma60 = data.loc[i, 'ma60']
temp_underlying = data.loc[i, '证券代码']
if self.temp_ZL != temp_underlying:
self.count = 0
self.temp_ZL = temp_underlying
self.count += 1
# 先找出过去30小时(交易时间)的最高和最低
if self.count >= 30:
self.temp_high = data.loc[i - 29:i + 1, 'close'].max()
self.temp_low = data.loc[i - 29:i + 1, 'close'].min()
# 当价格高于ma15高于ma60且价格比过去30小时的最高还要高时 多开
if temp_ma60 < temp_ma15 < temp_price and temp_price >= self.temp_high:
# 把止盈目标设置为接近过去3个月的最高价
hundred_days_ago_string = (temp_date - timedelta(days=100)).strftime("%Y-%m-%d")
temp_date_string = (temp_date - timedelta(days=1)).strftime("%Y-%m-%d")
self.long_target = THS_HQ(temp_underlying, 'close', '', hundred_days_ago_string,
temp_date_string).data['close'].max() * 0.99
# 特殊情况 当现在开仓的价格已经处于过去3个月的高点时 则不设置止盈点
if temp_price >= self.long_target:
self.long_target = float('inf')
self.open_price = temp_price # 记录一下当前交易的开仓价格
self.sl_price = -float('inf') # 初始化一下止损点为负无穷 后续在检查平仓条件时会更新
return 0.3
# 当价格低于ma15低于ma60且价格比过去30小时的最低还要低时 空开
if temp_ma60 > temp_ma15 > temp_price and temp_price <= self.temp_low:
# 把止盈目标设置为接近过去3个月的最低价
hundred_days_ago_string = (temp_date - timedelta(days=100)).strftime("%Y-%m-%d")
temp_date_string = (temp_date - timedelta(days=1)).strftime("%Y-%m-%d")
self.short_target = THS_HQ(temp_underlying, 'close', '', hundred_days_ago_string,
temp_date_string).data['close'].min() * 1.01
# 特殊情况 当现在开仓的价格已经处于过去3个月的低点时 则不设置止盈点
if temp_price <= self.short_target:
self.short_target = -float('inf')
self.open_price = temp_price # 记录一下当前交易的开仓价格
self.sl_price = float('inf') # 初始化一下止损点为正无穷 后续在检查平仓条件时会更新
return -0.3
return 0
return 0
def close_criterion(self, data, i, direction):
# 获取一下当前价格和ma60
temp_price = data.loc[i, 'close']
temp_ma60 = data.loc[i, 'ma60']
# 引入Trailing Stop Loss机制 当当前交易赚了3%时 一定保住20%的利润 通过设定止损点来达到
if direction == 1:
if temp_price >= self.open_price * 1.03:
self.sl_price = (temp_price - self.open_price) * 0.2 + self.open_price
# 如果当前价格比止盈点位高或比ma60低或比止损点低时 平仓
if temp_price >= self.long_target or temp_price <= temp_ma60 or temp_price <= self.sl_price:
return 1
if direction == -1:
if temp_price <= self.open_price * 0.97:
self.sl_price = self.open_price - (self.open_price - temp_price) * 0.2
# 如果当前价格比止盈点位低或比ma60高或比止损点高时 平仓
if temp_price <= self.short_target or temp_price >= temp_ma60 or temp_price >= self.sl_price:
return 1
return 0