Skip to content

Commit

Permalink
趋势变化敏感速度数值, 重构所有因子的index方式,简化上层使用
Browse files Browse the repository at this point in the history
  • Loading branch information
bbfamily committed Sep 1, 2017
1 parent f528da3 commit f8abb36
Show file tree
Hide file tree
Showing 40 changed files with 424 additions and 382 deletions.
4 changes: 2 additions & 2 deletions abupy/AlphaBu/ABuPickTimeWorker.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,11 @@ def _day_task(self, today):
# 注意回测模式下始终非高频,非当日买菜,不区分美股,A股市场,卖出因子要先于买入因子的执行
for sell_factor in self.sell_factors:
# 迭代卖出因子,每个卖出因子针对今日交易数据,已经所以交易单进行择时
sell_factor.fit_day(today, self.orders)
sell_factor.read_fit_day(today, self.orders)
# 买入因子行为要在卖出因子下面,否则为高频日交易模式
for buy_factor in self.buy_factors:
# 迭代买入因子,每个因子都对今天进行择时,如果生成order加入self.orders
order = buy_factor.fit_day(today)
order = buy_factor.read_fit_day(today)
if order and order.order_deal:
self.orders.append(order)

Expand Down
1 change: 0 additions & 1 deletion abupy/CoreBu/ABuPdHelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
g_pandas_has_resampler = True
except ImportError:
try:
# 整天瞎鸡巴移代码位置,里面一行也没改
# noinspection PyUnresolvedReferences
from pandas.core.resample import DatetimeIndexResampler
g_pandas_has_resampler = True
Expand Down
46 changes: 43 additions & 3 deletions abupy/FactorBuyBu/ABuFactorBuyBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ def __init__(self, capital, kl_pd, combine_kl_pd, benchmark, **kwargs):
# 默认的factor_name,子类通过_init_self可覆盖更具体的名字
self.factor_name = '{}'.format(self.__class__.__name__)

# 忽略的交易日数量
self.skip_days = 0

# 子类继续完成自有的构造
self._init_self(**kwargs)

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

__repr__ = __str__

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

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

def read_fit_day(self, today):
"""
在择时worker对象中做日交易的函数,亦可以理解为盘前的一些决策事件处理,
内部会调用子类实现的fit_day函数
:param today: 当前驱动的交易日金融时间序列数据
:return: 生成的交易订单AbuOrder对象
"""
if self.skip_days > 0:
self.skip_days -= 1
return None

# 今天这个交易日在整个金融时间序列的序号
self.today_ind = int(today.key)
# 回测中默认忽略最后一个交易日
if self.today_ind >= self.kl_pd.shape[0] - 1:
return None

return self.fit_day(today)

def buy_tomorrow(self):
"""
明天进行买入操作,比如突破策略使用了今天收盘的价格做为参数,发出了买入信号,
需要进行明天买入操作,不能执行今天买入操作
:return 生成的交易订单AbuOrder对象
"""
return self.make_buy_order(self.today_ind)

def buy_today(self):
"""
今天即进行买入操作,需要不能使用今天的收盘数据等做为fit_day中信号判断,
适合如比特币非明确一天交易日时间或者特殊情况的买入信号
:return 生成的交易订单AbuOrder对象
"""
return self.make_buy_order(self.today_ind - 1)

@abstractmethod
def fit_day(self, *args, **kwargs):
def fit_day(self, today):
"""子类主要需要实现的函数,完成策略因子针对每一个交易日的买入交易策略"""
pass

Expand Down
36 changes: 9 additions & 27 deletions abupy/FactorBuyBu/ABuFactorBuyBreak.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ def _init_self(self, **kwargs):
"""kwargs中必须包含: 突破参数xd 比如20,30,40天...突破"""
# 突破参数 xd, 比如20,30,40天...突破, 不要使用kwargs.pop('xd', 20), 明确需要参数xq
self.xd = kwargs['xd']
# 忽略连续创新高,比如买入后第二天又突破新高,忽略
self.skip_days = 0
# 在输出生成的orders_pd中显示的名字
self.factor_name = '{}:{}'.format(self.__class__.__name__, self.xd)

Expand All @@ -32,25 +30,16 @@ def fit_day(self, today):
:param today: 当前驱动的交易日金融时间序列数据
:return:
"""

# key是金融时间序列索引
day_ind = int(today.key)
# 忽略不符合买入的天(统计周期内前xd天及最后一天)
if day_ind < self.xd - 1 or day_ind >= self.kl_pd.shape[0] - 1:
return None

# TODO: 如果子策略中使用skip_days频率高,加个装饰器,子类依据情况选择是否装饰
if self.skip_days > 0:
# 执行买入订单后的忽略,否则如果昨天突破了执行了买入,今天继续又比昨天高,难道继续买入吗
self.skip_days -= 1
# 忽略不符合买入的天(统计周期内前xd天)
if self.today_ind < self.xd - 1:
return None

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


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

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

def fit_day(self, today):
Expand All @@ -72,19 +60,13 @@ def fit_day(self, today):
:param today: 当前驱动的交易日金融时间序列数据
:return:
"""
day_ind = int(today.key)
# 忽略不符合买入的天(统计周期内前xd天及最后一天)
if day_ind < self.xd - 1 or day_ind >= self.kl_pd.shape[0] - 1:
# 忽略不符合买入的天(统计周期内前xd天)
if self.today_ind < self.xd - 1:
return None
if self.skip_days > 0:
# 执行买入订单后的忽略
self.skip_days -= 1
return None

"""
与AbuFactorBuyBreak区别就是买向下突破的,即min()
"""
if today.close == self.kl_pd.close[day_ind - self.xd + 1:day_ind + 1].min():
if today.close == self.kl_pd.close[self.today_ind - self.xd + 1:self.today_ind + 1].min():
self.skip_days = self.xd
return self.make_buy_order(day_ind)
return self.buy_tomorrow()
return None
42 changes: 17 additions & 25 deletions abupy/FactorBuyBu/ABuFactorBuyDemo.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ def _init_self(self, **kwargs):

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

def fit_month(self, today):
Expand All @@ -46,7 +45,7 @@ def fit_month(self, today):
end_key = int(benchmark_today.ix[0].key)
start_key = end_key - 20
if start_key < 0:
return 0
return False

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

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


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

# 今天的涨幅
td_change = today.p_change
# 昨天的涨幅
yd_change = self.kl_pd.ix[day_ind - 1].p_change
yd_change = self.kl_pd.ix[self.today_ind - 1].p_change

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


Expand Down Expand Up @@ -178,11 +174,8 @@ def _init_self(self, **kwargs):
"""
# 突破参数 xd, 比如20,30,40天...突破, 不要使用kwargs.pop('xd', 20), 明确需要参数xq
self.xd = kwargs['xd']
# 忽略连续创新高,比如买入后第二天又突破新高,忽略
self.skip_days = 0
# 在输出生成的orders_pd中显示的名字
self.factor_name = '{}:{}'.format(self.__class__.__name__, self.xd)

# 添加了通过AbuFactorBuyBreakUmpDemo记录训练好的决策器
self.hit_ml = kwargs['hit_ml']

Expand Down Expand Up @@ -248,14 +241,12 @@ def fit_day(self, today):
"""
self.pg.show()

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

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

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

# noinspection PyUnresolvedReferences
def make_btc_today(self, sib_btc):
Expand Down
20 changes: 5 additions & 15 deletions abupy/FactorBuyBu/ABuFactorBuyGolden.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,8 @@ def _init_self(self, **kwargs):
self.ma_day = kwargs.pop('ma_day', 5)
# 短暂停留阀值stay_day(int),默认进入1天即算
self.stay_day = kwargs.pop('stay_day', 1)

self.skip_days = 0
# 交易目标短暂停留的标志
self.below_stay_days = 0

# 在输出生成的orders_pd中显示的名字
self.factor_name = '{}:{}'.format(self.__class__.__name__, self.xd)

Expand All @@ -46,19 +43,12 @@ def fit_day(self, today):
:param today: 当前驱动的交易日金融时间序列数据
:return:
"""
# key是金融时间序列索引
day_ind = int(today.key)
# 忽略不符合买入的天(统计周期内前xd天及最后一天)
if day_ind < self.xd - 1 or day_ind >= self.kl_pd.shape[0] - 1:
return None

if self.skip_days > 0:
# 执行买入订单后的忽略
self.skip_days -= 1
# 忽略不符合买入的天(统计周期内前xd天)
if self.today_ind < self.xd - 1:
return None

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

Expand Down Expand Up @@ -99,6 +89,6 @@ def ma_break_func():
self.below_stay_days = 0
# 放弃一段时间的买入观察, 放弃周期=self.xd/2
self.skip_days = self.xd / 2
# 生成买单
return self.make_buy_order(day_ind)
# 生成买单, 由于使用了今天的收盘价格做为策略信号判断,所以信号发出后,只能明天买
return self.buy_tomorrow()
return None
11 changes: 6 additions & 5 deletions abupy/FactorSellBu/ABuFactorAtrNStop.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from __future__ import print_function
from __future__ import division

from .ABuFactorSellBase import AbuFactorSellBase, filter_sell_order, skip_last_day, ESupportDirection
from .ABuFactorSellBase import AbuFactorSellBase, ESupportDirection

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

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

if hasattr(self, 'stop_loss_n') and profit < 0 and profit < -self.stop_loss_n * stop_base:
# 满足止损条件卖出股票, 即收益(profit) < -n倍atr
self.sell_type_extra = self.sell_type_extra_loss
order.fit_sell_order(int(today.key), self)
order.fit_sell_order(self.today_ind, self)
# 由于使用了当天的close价格,所以明天才能卖出
self.sell_tomorrow(order)
11 changes: 4 additions & 7 deletions abupy/FactorSellBu/ABuFactorCloseAtrNStop.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from __future__ import print_function
from __future__ import division

from .ABuFactorSellBase import AbuFactorSellBase, filter_sell_order, skip_last_day, ESupportDirection
from .ABuFactorSellBase import AbuFactorSellBase, ESupportDirection

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

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

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

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

0 comments on commit f8abb36

Please sign in to comment.