In [1]:
from __future__ import print_function
from __future__ import division

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
sns.set_context(rc={'figure.figsize': (14, 7) } )
figzize_me = figsize =(14, 7)
# import warnings; 
# warnings.filterwarnings('ignore')

import os
import sys
# 使用insert 0即只使用github,避免交叉使用了pip安装的abupy,导致的版本不一致问题
sys.path.insert(0, os.path.abspath('../'))
import abupy
# 使用沙盒数据,目的是和书中一样的数据环境
abupy.env.enable_example_env_ipython()


enable example env will only read RomDataBu/df_kl.h5

第8章 量化系统-开发

abu量化系统github地址 (您的star是我的动力!)

abu量化文档教程ipython notebook

8.1 abu量化系统择时

8.1.1 买入因子的实现


In [2]:
from abupy import AbuFactorBuyBreak
from abupy import AbuBenchmark
# buy_factors 60日向上突破,42日向上突破两个因子
buy_factors = [{'xd': 60, 'class': AbuFactorBuyBreak}, 
               {'xd': 42, 'class': AbuFactorBuyBreak}]
benchmark = AbuBenchmark()

In [3]:
from abupy import AbuPickTimeWorker 
from abupy import AbuCapital
from abupy import AbuKLManager

capital = AbuCapital(1000000, benchmark)
kl_pd_manager = AbuKLManager(benchmark, capital)
# 获取TSLA的交易数据
kl_pd = kl_pd_manager.get_pick_time_kl_pd('usTSLA')
abu_worker = AbuPickTimeWorker(capital, kl_pd, benchmark, buy_factors, None)
%time abu_worker.fit()


CPU times: user 151 ms, sys: 1.57 ms, total: 153 ms
Wall time: 152 ms

In [4]:
from abupy import ABuTradeProxy
orders_pd, action_pd, _ = ABuTradeProxy.trade_summary(abu_worker.orders, kl_pd, draw=True)



In [5]:
from abupy import ABuTradeExecute
ABuTradeExecute.apply_action_to_capital(capital, action_pd, kl_pd_manager)
capital.capital_pd.capital_blance.plot()


Out[5]:
<matplotlib.axes._subplots.AxesSubplot at 0x11ea673c8>

8.1.2 卖出因子的实现


In [6]:
from abupy import AbuFactorSellBreak
# 使用120天向下突破为卖出信号
sell_factor1 = {'xd': 120, 'class': AbuFactorSellBreak}

In [7]:
from abupy import ABuPickTimeExecute
# 只使用120天向下突破为卖出因子
sell_factors = [sell_factor1]
capital = AbuCapital(1000000, benchmark)
orders_pd, action_pd, _ = ABuPickTimeExecute.do_symbols_with_same_factors(
                          ['usTSLA'], benchmark, buy_factors, sell_factors, capital, show=True)


pid:1369 pick times complete:100.0%
pid:1369 done!

In [8]:
from abupy import AbuFactorAtrNStop
# 趋势跟踪策略止盈要大于止损设置值,这里0.5,3.0
sell_factor2 = {'stop_loss_n':0.5, 'stop_win_n':3.0, 'class': AbuFactorAtrNStop}
# 两个卖出因子策略并行同时生效
sell_factors = [sell_factor1, sell_factor2]
capital = AbuCapital(1000000, benchmark)
orders_pd, action_pd, _ = ABuPickTimeExecute.do_symbols_with_same_factors(
                          ['usTSLA'], benchmark, buy_factors, sell_factors, capital, show=True)


pid:1369 pick times complete:100.0%
pid:1369 done!

In [9]:
from abupy import AbuFactorPreAtrNStop
# 暴跌止损卖出因子形成dict
sell_factor3 =  {'class': AbuFactorPreAtrNStop, 'pre_atr_n':1.0}
# 三个卖出因子同时生效,组成sell_factors
sell_factors = [sell_factor1, sell_factor2, sell_factor3]
capital = AbuCapital(1000000, benchmark)
orders_pd, action_pd, _ = ABuPickTimeExecute.do_symbols_with_same_factors(
                          ['usTSLA'], benchmark, buy_factors, sell_factors, capital, show=True)


pid:1369 pick times complete:100.0%
pid:1369 done!

In [10]:
from abupy import AbuFactorCloseAtrNStop
# 保护止盈卖出因子组成dict
sell_factor4 = {'class': AbuFactorCloseAtrNStop, 'close_atr_n':1.5}
# 四个卖出因子同时并行生效
sell_factors = [sell_factor1, sell_factor2, sell_factor3, sell_factor4]
capital = AbuCapital(1000000, benchmark)
orders_pd, action_pd, _ = ABuPickTimeExecute.do_symbols_with_same_factors(
                          ['usTSLA'], benchmark, buy_factors, sell_factors, capital, show=True)


pid:1369 pick times complete:100.0%
pid:1369 done!

8.1.3 滑点买入卖出价格确定及策略实现


In [11]:
from abupy import AbuSlippageBuyBase

# 修改g_open_down_rate的值为0.02
g_open_down_rate = 0.02

class AbuSlippageBuyMean2(AbuSlippageBuyBase):
    def fit_price(self):
        if (self.kl_pd_buy.open / self.kl_pd_buy.pre_close) < (
            1 - g_open_down_rate):
            # 开盘下跌K_OPEN_DOWN_RATE以上,单子失效
            print(self.factor_name + 'open down threshold')
            return np.inf
        # 买入价格为当天均价
        self.buy_price = np.mean(
            [self.kl_pd_buy['high'], self.kl_pd_buy['low']])
        return self.buy_price

In [12]:
# 只针对60使用AbuSlippageBuyMean2
buy_factors2 = [{'slippage': AbuSlippageBuyMean2, 'xd': 60,
                 'class': AbuFactorBuyBreak},
                {'xd': 42, 'class': AbuFactorBuyBreak}]

sell_factors = [sell_factor1, sell_factor2, sell_factor3,
                sell_factor4]
capital = AbuCapital(1000000, benchmark)
orders_pd, action_pd, _ = \
    ABuPickTimeExecute.do_symbols_with_same_factors(['usTSLA'],
                                                    benchmark,
                                                    buy_factors2,
                                                    sell_factors,
                                                    capital,
                                                    show=True)


pid:1369 pick times complete:100.0%
AbuFactorBuyBreak:60open down threshold
AbuFactorBuyBreak:60open down threshold
pid:1369 done!

8.1.4 对多支股票进行择时


In [13]:
# 我们假定choice_symbols是我们选股模块的结果,
choice_symbols = ['usTSLA', 'usNOAH', 'usSFUN', 'usBIDU', 'usAAPL', 'usGOOG', 'usWUBA', 'usVIPS']
capital = AbuCapital(1000000, benchmark)
orders_pd, action_pd, all_fit_symbols_cnt = ABuPickTimeExecute.do_symbols_with_same_factors(choice_symbols, benchmark, buy_factors, sell_factors, capital, show=False)


pid:1369 pick times complete:100.0%
pid:1369 done!

In [14]:
orders_pd[:10].filter(['symbol', 'buy_price', 'buy_cnt', 'buy_factor', 'buy_pos', 
                       'sell_date', 'sell_type_extra', 'sell_type', 'profit'])


Out[14]:
symbol buy_price buy_cnt buy_factor buy_pos sell_date sell_type_extra sell_type profit
2014-10-24 usAAPL 105.010 1904.0 AbuFactorBuyBreak:60 AbuAtrPosition 20141202 AbuFactorPreAtrNStop:pre_atr=1.0 win 17592.96
2014-10-24 usAAPL 105.010 1904.0 AbuFactorBuyBreak:42 AbuAtrPosition 20141202 AbuFactorPreAtrNStop:pre_atr=1.0 win 17592.96
2014-10-29 usBIDU 223.680 781.0 AbuFactorBuyBreak:42 AbuAtrPosition 20141202 AbuFactorPreAtrNStop:pre_atr=1.0 win 9473.53
2014-10-29 usNOAH 16.010 9217.0 AbuFactorBuyBreak:42 AbuAtrPosition 20141208 AbuFactorAtrNStop:stop_win=3.0 win 74104.68
2014-10-29 usVIPS 21.430 6095.0 AbuFactorBuyBreak:42 AbuAtrPosition 20141105 AbuFactorPreAtrNStop:pre_atr=1.0 win 12433.80
2014-10-29 usBIDU 223.680 781.0 AbuFactorBuyBreak:60 AbuAtrPosition 20141202 AbuFactorPreAtrNStop:pre_atr=1.0 win 9473.53
2014-11-03 usVIPS 23.364 5900.0 AbuFactorBuyBreak:60 AbuAtrPosition 20141105 AbuFactorPreAtrNStop:pre_atr=1.0 win 625.40
2014-11-11 usNOAH 16.990 9491.0 AbuFactorBuyBreak:60 AbuAtrPosition 20141211 AbuFactorCloseAtrNStop:close_atr_n=1.5 win 29944.10
2014-11-12 usWUBA 43.250 2945.0 AbuFactorBuyBreak:42 AbuAtrPosition 20141209 AbuFactorPreAtrNStop:pre_atr=1.0 loss -1789.09
2014-11-26 usWUBA 47.100 3262.0 AbuFactorBuyBreak:60 AbuAtrPosition 20141209 AbuFactorAtrNStop:stop_loss=0.5 loss -14540.36

In [15]:
action_pd[:10]


Out[15]:
Date Price Cnt symbol Direction Price2 action deal
0 20141024 105.010 1904.0 usAAPL 1.0 114.250 buy True
1 20141024 105.010 1904.0 usAAPL 1.0 114.250 buy True
2 20141029 16.010 9217.0 usNOAH 1.0 24.050 buy True
3 20141029 223.680 781.0 usBIDU 1.0 235.810 buy True
4 20141029 223.680 781.0 usBIDU 1.0 235.810 buy True
5 20141029 21.430 6095.0 usVIPS 1.0 23.470 buy False
6 20141103 23.364 5900.0 usVIPS 1.0 23.470 buy False
7 20141105 23.470 6095.0 usVIPS 1.0 21.430 sell False
8 20141105 23.470 5900.0 usVIPS 1.0 23.364 sell False
9 20141111 16.990 9491.0 usNOAH 1.0 20.145 buy False

In [16]:
from abupy import AbuMetricsBase 
metrics = AbuMetricsBase(orders_pd, action_pd, capital, benchmark)
metrics.fit_metrics()
metrics.plot_returns_cmp(only_show_returns=True)


买入后卖出的交易数量:67
买入后尚未卖出的交易数量:3
胜率:43.2836%
平均获利期望:12.2712%
平均亏损期望:-4.9050%
盈亏比:1.9327
策略收益: 29.4383%
基准收益: 15.0841%
策略年化收益: 14.7192%
基准年化收益: 7.5420%
策略买入成交比例:84.2857%
策略资金利用率比例:22.3612%
策略共执行504个交易日

8.1.5 自定义仓位管理策略的实现


In [17]:
metrics.gains_mean, -metrics.losses_mean


Out[17]:
(0.1227120960681205, 0.049050477073546726)

In [18]:
from abupy import AbuKellyPosition
# 42d使用AbuKellyPosition,60d仍然使用默认仓位管理类
buy_factors2 = [{'xd': 60, 'class': AbuFactorBuyBreak},
                {'xd': 42, 'position': {'class': AbuKellyPosition, 'win_rate': metrics.win_rate, 
                                        'gains_mean': metrics.gains_mean, 'losses_mean': -metrics.losses_mean},
                 'class': AbuFactorBuyBreak}]
capital = AbuCapital(1000000, benchmark)
orders_pd, action_pd, all_fit_symbols_cnt = ABuPickTimeExecute.do_symbols_with_same_factors(choice_symbols, benchmark, buy_factors2, sell_factors, capital, show=False)


pid:1369 pick times complete:100.0%
pid:1369 done!

In [19]:
orders_pd[:10].filter(['symbol', 'buy_cnt', 'buy_factor', 'buy_pos'])


Out[19]:
symbol buy_cnt buy_factor buy_pos
2014-10-24 usAAPL 1904.0 AbuFactorBuyBreak:60 AbuAtrPosition
2014-10-24 usAAPL 1962.0 AbuFactorBuyBreak:42 AbuKellyPosition
2014-10-29 usBIDU 921.0 AbuFactorBuyBreak:42 AbuKellyPosition
2014-10-29 usNOAH 12875.0 AbuFactorBuyBreak:42 AbuKellyPosition
2014-10-29 usVIPS 9618.0 AbuFactorBuyBreak:42 AbuKellyPosition
2014-10-29 usBIDU 781.0 AbuFactorBuyBreak:60 AbuAtrPosition
2014-11-03 usVIPS 5900.0 AbuFactorBuyBreak:60 AbuAtrPosition
2014-11-11 usNOAH 9491.0 AbuFactorBuyBreak:60 AbuAtrPosition
2014-11-12 usWUBA 4765.0 AbuFactorBuyBreak:42 AbuKellyPosition
2014-11-26 usWUBA 3262.0 AbuFactorBuyBreak:60 AbuAtrPosition

8.1.6 多支股票使用不同的因子进行择时


In [20]:
# 选定noah和sfun
target_symbols = ['usSFUN', 'usNOAH']
# 针对sfun只使用42d向上突破作为买入因子
buy_factors_sfun = [{'xd': 42, 'class': AbuFactorBuyBreak}]
# 针对sfun只使用60d向下突破作为卖出因子
sell_factors_sfun = [{'xd': 60, 'class': AbuFactorSellBreak}]

# 针对noah只使用21d向上突破作为买入因子
buy_factors_noah = [{'xd': 21, 'class': AbuFactorBuyBreak}]
# 针对noah只使用42d向下突破作为卖出因子
sell_factors_noah = [{'xd': 42, 'class': AbuFactorSellBreak}]

factor_dict = dict()
# 构建SFUN独立的buy_factors,sell_factors的dict
factor_dict['usSFUN'] = {'buy_factors':buy_factors_sfun, 'sell_factors':sell_factors_sfun}
# 构建NOAH独立的buy_factors,sell_factors的dict
factor_dict['usNOAH'] = {'buy_factors':buy_factors_noah, 'sell_factors':sell_factors_noah}
# 初始化资金
capital = AbuCapital(1000000, benchmark)
# 使用do_symbols_with_diff_factors执行
orders_pd, action_pd, all_fit_symbols = ABuPickTimeExecute.do_symbols_with_diff_factors(
                                        target_symbols, benchmark, factor_dict, capital)


pid:1369 pick times complete:100.0%
pid:1369 done!

In [21]:
pd.crosstab(orders_pd.buy_factor, orders_pd.symbol)


Out[21]:
symbol usNOAH usSFUN
buy_factor
AbuFactorBuyBreak:21 9 0
AbuFactorBuyBreak:42 0 4

8.1.7 使用并行来提升择时运行效率


In [22]:
# 要关闭沙盒数据环境,因为沙盒里就那几个股票的历史数据, 下面要随机做300个股票
abupy.env.disable_example_env_ipython()

# 关闭沙盒后,首先基准要从非沙盒环境换取,否则数据对不齐,无法正常运行
benchmark = AbuBenchmark()
capital = AbuCapital(1000000, benchmark)


disable example env

In [23]:
from abupy import ABuMarket
# 当传入choice_symbols为None时代表对整个市场的所有股票进行回测
choice_symbols = None
# 顺序获取市场后50支股票
choice_symbols = ABuMarket.all_symbol()[-50:]
# 随机获取50支股票
choice_symbols = ABuMarket.choice_symbols(50)

In [26]:
from abupy import AbuPickTimeMaster
capital = AbuCapital(1000000, benchmark)
orders_pd, action_pd, _ = AbuPickTimeMaster.do_symbols_with_same_factors_process(
                          choice_symbols, benchmark, buy_factors, sell_factors, 
                          capital)


pid:1398 pick times complete:100.0%
pid:1398 done!

In [27]:
metrics = AbuMetricsBase(orders_pd, action_pd, capital, benchmark)
metrics.fit_metrics()
metrics.plot_returns_cmp(only_show_returns=True)


买入后卖出的交易数量:259
买入后尚未卖出的交易数量:9
胜率:33.5907%
平均获利期望:9.9141%
平均亏损期望:-4.8258%
盈亏比:0.8863
策略收益: -10.9886%
基准收益: 32.5155%
策略年化收益: -5.5162%
基准年化收益: 16.3225%
策略买入成交比例:58.9552%
策略资金利用率比例:57.6239%
策略共执行502个交易日

8.2 abu量化系统选股

8.2.1 选股因子的实现


In [28]:
# 继续使用沙盒数据环境
abupy.env.enable_example_env_ipython()

# 开启沙盒后,基准也要从沙盒环境取,否则数据对不齐,无法正常运行
benchmark = AbuBenchmark()
capital = AbuCapital(1000000, benchmark)
kl_pd_manager = AbuKLManager(benchmark, capital)


enable example env will only read RomDataBu/df_kl.h5

In [29]:
from abupy import AbuPickRegressAngMinMax
from abupy import AbuPickStockWorker
# 选股条件threshold_ang_min=0.0, 即要求股票走势为向上上升趋势
stock_pickers = [{'class': AbuPickRegressAngMinMax, 
                'threshold_ang_min':0.0, 'reversed':False}]

# 从这几个股票里进行选股,只是为了演示方便,一般的选股都会是数量比较多的情况比如全市场股票
choice_symbols = ['usNOAH', 'usSFUN', 'usBIDU', 'usAAPL', 'usGOOG', 'usTSLA', 'usWUBA', 'usVIPS']

capital = AbuCapital(1000000, benchmark)
kl_pd_manager = AbuKLManager(benchmark, capital)
stock_pick = AbuPickStockWorker(capital, benchmark, kl_pd_manager, choice_symbols=choice_symbols, stock_pickers=stock_pickers)
stock_pick.fit()
stock_pick.choice_symbols


pid:1369 pick stocks complete:100.0%
pid:1369 done!
Out[29]:
['usSFUN', 'usBIDU', 'usTSLA', 'usWUBA', 'usVIPS']

注意选股结果会与书中的结果不一致,因为要控制沙盒数据体积小于50mb, 所以沙盒数据有些symbol只有两年多一点,与原始环境不一致。


In [30]:
from abupy import ABuRegUtil
# 从kl_pd_manager缓存中获取选股走势数据,注意get_pick_stock_kl_pd为选股数据,get_pick_time_kl_pd为择时
kl_pd_noah = kl_pd_manager.get_pick_stock_kl_pd('usNOAH')
# 绘制并计算角度
deg = ABuRegUtil.calc_regress_deg(kl_pd_noah.close)
print('noah 选股周期内角度={}'.format(round(deg, 3)))


noah 选股周期内角度=-9.289

ABuPickStockExecute


In [31]:
from abupy import ABuPickStockExecute
stock_pickers = [{'class': AbuPickRegressAngMinMax, 
                 'threshold_ang_min':0.0, 'threshold_ang_max':10.0, 'reversed':False}]

ABuPickStockExecute.do_pick_stock_work(choice_symbols, benchmark, capital, stock_pickers)


pid:1369 pick stocks complete:100.0%
pid:1369 done!
Out[31]:
['usSFUN', 'usBIDU']

In [32]:
kl_pd_sfun = kl_pd_manager.get_pick_stock_kl_pd('usSFUN')
print('sfun 选股周期内角度={}'.format(round(ABuRegUtil.calc_regress_deg(kl_pd_sfun.close), 3)))


sfun 选股周期内角度=8.23

reversed


In [33]:
# 和上面的代码唯一的区别就是reversed=True
stock_pickers = [{'class': AbuPickRegressAngMinMax, 
                 'threshold_ang_min':0.0, 'threshold_ang_max':10.0, 'reversed':True}]
ABuPickStockExecute.do_pick_stock_work(choice_symbols, benchmark, capital, stock_pickers)


pid:1369 pick stocks complete:100.0%
pid:1369 done!
Out[33]:
['usNOAH', 'usTSLA', 'usWUBA', 'usVIPS']

8.2.2 多个选股因子并行执行


In [34]:
from abupy import AbuPickStockPriceMinMax

stock_pickers = [{'class': AbuPickRegressAngMinMax, 
                 'threshold_ang_min':0.0, 'reversed':False}, 
                 {'class': AbuPickStockPriceMinMax, 'threshold_price_min':50.0,
                 'reversed':False}]
ABuPickStockExecute.do_pick_stock_work(choice_symbols, benchmark, capital, stock_pickers)


pid:1369 pick stocks complete:100.0%
pid:1369 done!
Out[34]:
['usBIDU', 'usTSLA']

8.2.3 使用并行来提升回测运行效率


In [36]:
# 继续关闭沙盒环境,因为下面要choice_symbols
abupy.env.disable_example_env_ipython()

# 关闭沙盒后,首先基准要从非沙盒环境换取,否则数据对不齐,无法正常运行
benchmark = AbuBenchmark()
capital = AbuCapital(1000000, benchmark)
kl_pd_manager = AbuKLManager(benchmark, capital)

from abupy import ABuMarket, AbuPickStockMaster
# 首先随抽取50支股票
choice_symbols = ABuMarket.choice_symbols(50)


disable example env

In [37]:
# 股价在15-50之间
stock_pickers = [{'class': AbuPickStockPriceMinMax, 'threshold_price_min':15.0,
                'threshold_price_max':50.0, 'reversed':False}]
%time cs = AbuPickStockMaster.do_pick_stock_with_process(capital, benchmark, stock_pickers, choice_symbols)


pid:1369 pick stocks complete:100.0%
pid:1369 done!
CPU times: user 4.17 s, sys: 237 ms, total: 4.41 s
Wall time: 36.8 s

In [38]:
cs


Out[38]:
['usB', 'usLYV', 'usBECN', 'usSJW', 'usERJ', 'usFTD', 'usFITBI', 'usMGM']

In [ ]: