Skip to content

Commit f8abb36

Browse files
committed
趋势变化敏感速度数值, 重构所有因子的index方式,简化上层使用
1 parent f528da3 commit f8abb36

40 files changed

Lines changed: 424 additions & 382 deletions

File tree

abupy/AlphaBu/ABuPickTimeWorker.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,11 @@ def _day_task(self, today):
9898
# 注意回测模式下始终非高频,非当日买菜,不区分美股,A股市场,卖出因子要先于买入因子的执行
9999
for sell_factor in self.sell_factors:
100100
# 迭代卖出因子,每个卖出因子针对今日交易数据,已经所以交易单进行择时
101-
sell_factor.fit_day(today, self.orders)
101+
sell_factor.read_fit_day(today, self.orders)
102102
# 买入因子行为要在卖出因子下面,否则为高频日交易模式
103103
for buy_factor in self.buy_factors:
104104
# 迭代买入因子,每个因子都对今天进行择时,如果生成order加入self.orders
105-
order = buy_factor.fit_day(today)
105+
order = buy_factor.read_fit_day(today)
106106
if order and order.order_deal:
107107
self.orders.append(order)
108108

abupy/CoreBu/ABuPdHelper.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
g_pandas_has_resampler = True
2424
except ImportError:
2525
try:
26-
# 整天瞎鸡巴移代码位置,里面一行也没改
2726
# noinspection PyUnresolvedReferences
2827
from pandas.core.resample import DatetimeIndexResampler
2928
g_pandas_has_resampler = True

abupy/FactorBuyBu/ABuFactorBuyBase.py

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ def __init__(self, capital, kl_pd, combine_kl_pd, benchmark, **kwargs):
107107
# 默认的factor_name,子类通过_init_self可覆盖更具体的名字
108108
self.factor_name = '{}'.format(self.__class__.__name__)
109109

110+
# 忽略的交易日数量
111+
self.skip_days = 0
112+
110113
# 子类继续完成自有的构造
111114
self._init_self(**kwargs)
112115

@@ -118,13 +121,15 @@ def __str__(self):
118121

119122
__repr__ = __str__
120123

121-
def make_buy_order(self, day_ind):
124+
def make_buy_order(self, day_ind=-1):
122125
"""
123126
根据交易发生的时间索引,依次进行交易订单生成,交易时间序列特征生成,
124127
决策交易是否拦截,生成特征学习数据,最终返回order,即订单生效
125128
:param day_ind: 交易发生的时间索引,即对应self.kl_pd.key
126-
:return:
127129
"""
130+
if day_ind == -1:
131+
# 默认模式下非高频,信号发出后,明天进行买入操作
132+
day_ind = self.today_ind
128133

129134
order = AbuOrder()
130135
# AbuOrde对象根据交易发生的时间索引生成交易订单
@@ -169,8 +174,43 @@ def _init_self(self, **kwargs):
169174
"""子类因子针对可扩展参数的初始化"""
170175
pass
171176

177+
def read_fit_day(self, today):
178+
"""
179+
在择时worker对象中做日交易的函数,亦可以理解为盘前的一些决策事件处理,
180+
内部会调用子类实现的fit_day函数
181+
:param today: 当前驱动的交易日金融时间序列数据
182+
:return: 生成的交易订单AbuOrder对象
183+
"""
184+
if self.skip_days > 0:
185+
self.skip_days -= 1
186+
return None
187+
188+
# 今天这个交易日在整个金融时间序列的序号
189+
self.today_ind = int(today.key)
190+
# 回测中默认忽略最后一个交易日
191+
if self.today_ind >= self.kl_pd.shape[0] - 1:
192+
return None
193+
194+
return self.fit_day(today)
195+
196+
def buy_tomorrow(self):
197+
"""
198+
明天进行买入操作,比如突破策略使用了今天收盘的价格做为参数,发出了买入信号,
199+
需要进行明天买入操作,不能执行今天买入操作
200+
:return 生成的交易订单AbuOrder对象
201+
"""
202+
return self.make_buy_order(self.today_ind)
203+
204+
def buy_today(self):
205+
"""
206+
今天即进行买入操作,需要不能使用今天的收盘数据等做为fit_day中信号判断,
207+
适合如比特币非明确一天交易日时间或者特殊情况的买入信号
208+
:return 生成的交易订单AbuOrder对象
209+
"""
210+
return self.make_buy_order(self.today_ind - 1)
211+
172212
@abstractmethod
173-
def fit_day(self, *args, **kwargs):
213+
def fit_day(self, today):
174214
"""子类主要需要实现的函数,完成策略因子针对每一个交易日的买入交易策略"""
175215
pass
176216

abupy/FactorBuyBu/ABuFactorBuyBreak.py

Lines changed: 9 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ def _init_self(self, **kwargs):
2121
"""kwargs中必须包含: 突破参数xd 比如20,30,40天...突破"""
2222
# 突破参数 xd, 比如20,30,40天...突破, 不要使用kwargs.pop('xd', 20), 明确需要参数xq
2323
self.xd = kwargs['xd']
24-
# 忽略连续创新高,比如买入后第二天又突破新高,忽略
25-
self.skip_days = 0
2624
# 在输出生成的orders_pd中显示的名字
2725
self.factor_name = '{}:{}'.format(self.__class__.__name__, self.xd)
2826

@@ -32,25 +30,16 @@ def fit_day(self, today):
3230
:param today: 当前驱动的交易日金融时间序列数据
3331
:return:
3432
"""
35-
36-
# key是金融时间序列索引
37-
day_ind = int(today.key)
38-
# 忽略不符合买入的天(统计周期内前xd天及最后一天)
39-
if day_ind < self.xd - 1 or day_ind >= self.kl_pd.shape[0] - 1:
40-
return None
41-
42-
# TODO: 如果子策略中使用skip_days频率高,加个装饰器,子类依据情况选择是否装饰
43-
if self.skip_days > 0:
44-
# 执行买入订单后的忽略,否则如果昨天突破了执行了买入,今天继续又比昨天高,难道继续买入吗
45-
self.skip_days -= 1
33+
# 忽略不符合买入的天(统计周期内前xd天)
34+
if self.today_ind < self.xd - 1:
4635
return None
4736

4837
# 今天的收盘价格达到xd天内最高价格则符合买入条件
49-
if today.close == self.kl_pd.close[day_ind - self.xd + 1:day_ind + 1].max():
38+
if today.close == self.kl_pd.close[self.today_ind - self.xd + 1:self.today_ind + 1].max():
5039
# 把突破新高参数赋值skip_days,这里也可以考虑make_buy_order确定是否买单成立,但是如果停盘太长时间等也不好
5140
self.skip_days = self.xd
52-
# 生成买入订单
53-
return self.make_buy_order(day_ind)
41+
# 生成买入订单, 由于使用了今天的收盘价格做为策略信号判断,所以信号发出后,只能明天买
42+
return self.buy_tomorrow()
5443
return None
5544

5645

@@ -63,7 +52,6 @@ def _init_self(self, **kwargs):
6352

6453
# 突破参数 xd, 比如20,30,40天...突破, 不要使用kwargs.pop('xd', 20), 明确需要参数xq
6554
self.xd = kwargs['xd']
66-
self.skip_days = 0
6755
self.factor_name = '{}:{}'.format(self.__class__.__name__, self.xd)
6856

6957
def fit_day(self, today):
@@ -72,19 +60,13 @@ def fit_day(self, today):
7260
:param today: 当前驱动的交易日金融时间序列数据
7361
:return:
7462
"""
75-
day_ind = int(today.key)
76-
# 忽略不符合买入的天(统计周期内前xd天及最后一天)
77-
if day_ind < self.xd - 1 or day_ind >= self.kl_pd.shape[0] - 1:
63+
# 忽略不符合买入的天(统计周期内前xd天)
64+
if self.today_ind < self.xd - 1:
7865
return None
79-
if self.skip_days > 0:
80-
# 执行买入订单后的忽略
81-
self.skip_days -= 1
82-
return None
83-
8466
"""
8567
与AbuFactorBuyBreak区别就是买向下突破的,即min()
8668
"""
87-
if today.close == self.kl_pd.close[day_ind - self.xd + 1:day_ind + 1].min():
69+
if today.close == self.kl_pd.close[self.today_ind - self.xd + 1:self.today_ind + 1].min():
8870
self.skip_days = self.xd
89-
return self.make_buy_order(day_ind)
71+
return self.buy_tomorrow()
9072
return None

abupy/FactorBuyBu/ABuFactorBuyDemo.py

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ def _init_self(self, **kwargs):
3131

3232
# 下面的代码和AbuFactorBuyBase的实现一摸一样
3333
self.xd = kwargs['xd']
34-
self.skip_days = 0
3534
self.factor_name = '{}:{}'.format(self.__class__.__name__, self.xd)
3635

3736
def fit_month(self, today):
@@ -46,7 +45,7 @@ def fit_month(self, today):
4645
end_key = int(benchmark_today.ix[0].key)
4746
start_key = end_key - 20
4847
if start_key < 0:
49-
return 0
48+
return False
5049

5150
# 使用切片切出从今天开始向前20天的数据
5251
benchmark_month = benchmark_df[start_key:end_key + 1]
@@ -68,15 +67,14 @@ def fit_day(self, today):
6867
return None
6968

7069
# 下面的代码和AbuFactorBuyBase的实现一摸一样
71-
day_ind = int(today.key)
72-
if day_ind < self.xd - 1 or day_ind >= self.kl_pd.shape[0] - 1:
73-
return None
74-
if self.skip_days > 0:
75-
self.skip_days -= 1
70+
if self.today_ind < self.xd - 1:
7671
return None
77-
if today.close == self.kl_pd.close[day_ind - self.xd + 1:day_ind + 1].max():
72+
# 今天的收盘价格达到xd天内最高价格则符合买入条件
73+
if today.close == self.kl_pd.close[self.today_ind - self.xd + 1:self.today_ind + 1].max():
74+
# 把突破新高参数赋值skip_days,这里也可以考虑make_buy_order确定是否买单成立,但是如果停盘太长时间等也不好
7875
self.skip_days = self.xd
79-
return self.make_buy_order(day_ind)
76+
# 生成买入订单, 由于使用了今天的收盘价格做为策略信号判断,所以信号发出后,只能明天买
77+
return self.buy_tomorrow()
8078
return None
8179

8280

@@ -94,20 +92,18 @@ def fit_day(self, today):
9492
:param today: 当前驱动的交易日金融时间序列数据
9593
:return:
9694
"""
97-
# key是金融时间序列索引
98-
day_ind = int(today.key)
99-
# 忽略不符合买入的天(统计周期内前第1天及最后一天)
100-
if day_ind == 0 or day_ind >= self.kl_pd.shape[0] - 1:
95+
# 忽略不符合买入的天(统计周期内前第1天, 因为要用到昨天的交易数据)
96+
if self.today_ind == 0:
10197
return None
10298

10399
# 今天的涨幅
104100
td_change = today.p_change
105101
# 昨天的涨幅
106-
yd_change = self.kl_pd.ix[day_ind - 1].p_change
102+
yd_change = self.kl_pd.ix[self.today_ind - 1].p_change
107103

108104
if td_change > 0 and 0 < yd_change < td_change:
109-
# 连续涨两天, 且今天的涨幅比昨天还高 ->买入
110-
return self.make_buy_order(day_ind)
105+
# 连续涨两天, 且今天的涨幅比昨天还高 ->买入, 用到了今天的涨幅,只能明天买
106+
return self.buy_tomorrow()
111107
return None
112108

113109

@@ -178,11 +174,8 @@ def _init_self(self, **kwargs):
178174
"""
179175
# 突破参数 xd, 比如20,30,40天...突破, 不要使用kwargs.pop('xd', 20), 明确需要参数xq
180176
self.xd = kwargs['xd']
181-
# 忽略连续创新高,比如买入后第二天又突破新高,忽略
182-
self.skip_days = 0
183177
# 在输出生成的orders_pd中显示的名字
184178
self.factor_name = '{}:{}'.format(self.__class__.__name__, self.xd)
185-
186179
# 添加了通过AbuFactorBuyBreakUmpDemo记录训练好的决策器
187180
self.hit_ml = kwargs['hit_ml']
188181

@@ -248,14 +241,12 @@ def fit_day(self, today):
248241
"""
249242
self.pg.show()
250243

251-
# key是金融时间序列索引
252-
day_ind = int(today.key)
253-
# 忽略不符合买入的天(统计周期内前两天及最后一天),因为btc的机器学习特证需要三天交易数据
254-
if day_ind < 2 or day_ind >= self.kl_pd.shape[0] - 1:
244+
# 忽略不符合买入的天(统计周期内前两天, 因为btc的机器学习特证需要三天交易数据)
245+
if self.today_ind < 2:
255246
return None
256247

257248
# 今天,昨天,前天三天的交易数据进行特证转换
258-
btc = self.kl_pd[day_ind - 2:day_ind + 1]
249+
btc = self.kl_pd[self.today_ind - 2:self.today_ind + 1]
259250
# 三天的交易数据进行转换后得到btc_today_x
260251
btc_today_x = self.make_btc_today(btc)
261252

@@ -265,7 +256,8 @@ def fit_day(self, today):
265256
# 买入条件1: 当日这100个股票60%以上都是上涨的
266257
vote_val = self.similar_predict(today.date)
267258
if vote_val > self.btc_vote_val:
268-
return self.make_buy_order(day_ind - 1)
259+
# 没有使用当天交易日的close等数据,且btc_ml判断的大波动是当日,所以当日买入
260+
return self.buy_today()
269261

270262
# noinspection PyUnresolvedReferences
271263
def make_btc_today(self, sib_btc):

abupy/FactorBuyBu/ABuFactorBuyGolden.py

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,8 @@ def _init_self(self, **kwargs):
3232
self.ma_day = kwargs.pop('ma_day', 5)
3333
# 短暂停留阀值stay_day(int),默认进入1天即算
3434
self.stay_day = kwargs.pop('stay_day', 1)
35-
36-
self.skip_days = 0
3735
# 交易目标短暂停留的标志
3836
self.below_stay_days = 0
39-
4037
# 在输出生成的orders_pd中显示的名字
4138
self.factor_name = '{}:{}'.format(self.__class__.__name__, self.xd)
4239

@@ -46,19 +43,12 @@ def fit_day(self, today):
4643
:param today: 当前驱动的交易日金融时间序列数据
4744
:return:
4845
"""
49-
# key是金融时间序列索引
50-
day_ind = int(today.key)
51-
# 忽略不符合买入的天(统计周期内前xd天及最后一天)
52-
if day_ind < self.xd - 1 or day_ind >= self.kl_pd.shape[0] - 1:
53-
return None
54-
55-
if self.skip_days > 0:
56-
# 执行买入订单后的忽略
57-
self.skip_days -= 1
46+
# 忽略不符合买入的天(统计周期内前xd天)
47+
if self.today_ind < self.xd - 1:
5848
return None
5949

6050
# 切片从前xd开始直到当前交易日为止的金融序列数据
61-
window_pd = self.kl_pd[day_ind - self.xd + 1: day_ind + 1]
51+
window_pd = self.kl_pd[self.today_ind - self.xd + 1: self.today_ind + 1]
6252
# 在切片的金融序列数据上计算黄金分割档位值,具体阅读ABuTLGolden.calc_golden
6353
golden = ABuTLGolden.calc_golden(window_pd, show=False)
6454

@@ -99,6 +89,6 @@ def ma_break_func():
9989
self.below_stay_days = 0
10090
# 放弃一段时间的买入观察, 放弃周期=self.xd/2
10191
self.skip_days = self.xd / 2
102-
# 生成买单
103-
return self.make_buy_order(day_ind)
92+
# 生成买单, 由于使用了今天的收盘价格做为策略信号判断,所以信号发出后,只能明天买
93+
return self.buy_tomorrow()
10494
return None

abupy/FactorSellBu/ABuFactorAtrNStop.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from __future__ import print_function
88
from __future__ import division
99

10-
from .ABuFactorSellBase import AbuFactorSellBase, filter_sell_order, skip_last_day, ESupportDirection
10+
from .ABuFactorSellBase import AbuFactorSellBase, ESupportDirection
1111

1212
__author__ = '阿布'
1313
__weixin__ = 'abu_quant'
@@ -38,8 +38,6 @@ def support_direction(self):
3838
"""n倍atr(止盈止损)因子支持两个方向"""
3939
return [ESupportDirection.DIRECTION_CAll.value, ESupportDirection.DIRECTION_PUT.value]
4040

41-
@skip_last_day
42-
@filter_sell_order
4341
def fit_day(self, today, orders):
4442
"""
4543
止盈event:截止今天相比买入时的收益 * 买入时的期望方向 > n倍atr
@@ -60,9 +58,12 @@ def fit_day(self, today, orders):
6058
if hasattr(self, 'stop_win_n') and profit > 0 and profit > self.stop_win_n * stop_base:
6159
# 满足止盈条件卖出股票, 即收益(profit) > n倍atr
6260
self.sell_type_extra = self.sell_type_extra_win
63-
order.fit_sell_order(int(today.key), self)
61+
# 由于使用了当天的close价格,所以明天才能卖出
62+
self.sell_tomorrow(order)
6463

6564
if hasattr(self, 'stop_loss_n') and profit < 0 and profit < -self.stop_loss_n * stop_base:
6665
# 满足止损条件卖出股票, 即收益(profit) < -n倍atr
6766
self.sell_type_extra = self.sell_type_extra_loss
68-
order.fit_sell_order(int(today.key), self)
67+
order.fit_sell_order(self.today_ind, self)
68+
# 由于使用了当天的close价格,所以明天才能卖出
69+
self.sell_tomorrow(order)

abupy/FactorSellBu/ABuFactorCloseAtrNStop.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from __future__ import print_function
99
from __future__ import division
1010

11-
from .ABuFactorSellBase import AbuFactorSellBase, filter_sell_order, skip_last_day, ESupportDirection
11+
from .ABuFactorSellBase import AbuFactorSellBase, ESupportDirection
1212

1313
__author__ = '阿布'
1414
__weixin__ = 'abu_quant'
@@ -34,8 +34,6 @@ def support_direction(self):
3434
"""单日最大跌幅n倍atr(止损)因子支持两个方向"""
3535
return [ESupportDirection.DIRECTION_CAll.value, ESupportDirection.DIRECTION_PUT.value]
3636

37-
@skip_last_day
38-
@filter_sell_order
3937
def fit_day(self, today, orders):
4038
"""
4139
止盈event: 较小利润值 < 买入后最大收益价格 - 今日价格 < 较大利润值
@@ -44,13 +42,11 @@ def fit_day(self, today, orders):
4442
:return:
4543
"""
4644

47-
# 今天即当前交易日在金融时间序列中的index
48-
day_ind = int(today.key)
4945
for order in orders:
5046
# 通过order中的买入日期计算金融时间序列kl_pd中的index
5147
mask_date = self.kl_pd['date'] == order.buy_date
5248
start_ind = int(self.kl_pd[mask_date]['key'].values)
53-
end_ind = day_ind + 1
49+
end_ind = self.today_ind + 1
5450

5551
"""
5652
从买入日子开始计算到今天得到买入后最大收盘价格作为max_close,
@@ -65,4 +61,5 @@ def fit_day(self, today, orders):
6561
"""
6662
if (max_close - order.buy_price) * order.expect_direction > today['atr21'] \
6763
and (max_close - today.close) * order.expect_direction > today['atr21'] * self.close_atr_n:
68-
order.fit_sell_order(day_ind, self)
64+
# 由于使用了当天的close价格,所以明天才能卖出
65+
self.sell_tomorrow(order)

0 commit comments

Comments
 (0)