量化投資:第5節 選股策略的開發

做者: 阿布html

阿布量化版權全部 未經容許 禁止轉載python

abu量化系統github地址(歡迎+star,你的支持是我更新的動力!)git

本節ipython notebookgithub

在第一節即說過:api

  • 在對的時間,碰見對的人(股票),是一種幸福
  • 在對的時間,碰見錯的人(股票),是一種悲傷
  • 在錯的時間,碰見對的人(股票),是一聲嘆息
  • 在錯的時間,碰見錯的人(股票),是一種無奈

以前的節講的都是擇時(何時投資), 本節將講解選股。緩存

1. 選股因子的編寫

與擇時小節相似,實現示例在中abu量化系統實現一個選股策略。微信

以下代碼AbuPickRegressAngMinMax爲選股因子,它的做用是將股票前期走勢進行線性擬合計算一個角度,參數爲選股條件,將選股條件做用於角度後進行股票的篩選。機器學習

from abupy import AbuPickStockBase, ps, ABuRegUtil

class AbuPickRegressAngMinMax(AbuPickStockBase):
    """擬合角度選股因子示例類"""
    def _init_self(self, **kwargs):
        """經過kwargs設置擬合角度邊際條件,配置因子參數"""

        # 暫時與base保持一致不使用kwargs.pop('a', default)方式
        # fit_pick中 ang > threshold_ang_min, 默認負無窮,即默認全部都符合
        self.threshold_ang_min = -np.inf
        if 'threshold_ang_min' in kwargs:
            # 設置最小角度閥值
            self.threshold_ang_min = kwargs['threshold_ang_min']

        # fit_pick中 ang < threshold_ang_max, 默認正無窮,即默認全部都符合
        self.threshold_ang_max = np.inf
        if 'threshold_ang_max' in kwargs:
            # 設置最大角度閥值
            self.threshold_ang_max = kwargs['threshold_ang_max']

    @ps.reversed_result
    def fit_pick(self, kl_pd, target_symbol):
        """開始根據自定義擬合角度邊際參數進行選股"""
        # 計算走勢角度
        ang = ABuRegUtil.calc_regress_deg(kl_pd.close, show=False)
        # 根據參數進行角度條件判斷
        if self.threshold_ang_min < ang < self.threshold_ang_max:
            return True
        return False
    
    def fit_first_choice(self, pick_worker, choice_symbols, *args, **kwargs):
        raise NotImplementedError('AbuPickRegressAng fit_first_choice unsupported now!')

上面編寫的AbuPickRegressAngMinMax即爲一個完整的選股策略:函數

  1. 選股策略必須繼承自AbuPickStockBase
  2. 選股策略必須實現fit_pick,即完成經過選股階段金融時間序列對股票決策是否選中
  3. 選股策略必須實現fit_first_choice, 可是能夠raise NotImplementedError,fit_first_choice後面的章節示例
  4. fit_pick上的裝飾器ps.reversed_result稍後講解

選股模塊主要功能依託AbuPickStockWorker,其相似擇時模塊中的AbuPickTimeWorker,其經過init_stock_pickers()函數將全部選股因子實例化,而後在以後的fit()操做中,遍歷全部選股因子,使用選股因子的fit_pick()函數,保留全部選股因子的fit_pick()都返回True的股票,只要有一個選股因子的fit_pick結果是False就將股票剔除。oop

詳細代碼請查閱 AbuPickStockWorker源代碼。

本節只講簡單講解選股使用示例,好比只想選取符合上升走勢的股票:

from abupy import AbuPickStockWorker
from abupy import AbuBenchmark, AbuCapital, AbuKLManager

# 選股條件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']

benchmark = AbuBenchmark()
capital = AbuCapital(1000000, benchmark)
kl_pd_manger = AbuKLManager(benchmark, capital)
stock_pick = AbuPickStockWorker(capital, benchmark, kl_pd_manger,
                                choice_symbols=choice_symbols,
                                stock_pickers=stock_pickers)
stock_pick.fit()
# 打印最後的選股結果
stock_pick.choice_symbols
['usSFUN', 'usBIDU', 'usTSLA', 'usWUBA', 'usVIPS']

上面的實現方式和第一節中講解擇時回測的使用時同樣經過分解流程方式一步一步實現使用AbuPickStockWorker進行選股,目的是爲了更清晰的說明內部操做流程,編碼過程會顯的有些複雜臃腫。

實際上在編寫完成一個策略後只須要abu.run_loop_back()函數便可以完成回測,在後面的小節中會進行講解。

上面選股的結果將noah剔除,由於它在回測以前的選股週期內趨勢爲降低趨勢,以下圖所示:

# 從kl_pd_manger緩存中獲取選股走勢數據,
# 注意get_pick_stock_kl_pd()爲選股數據,get_pick_time_kl_pd()爲擇時
kl_pd_noah = kl_pd_manger.get_pick_stock_kl_pd('usNOAH')
# 繪製並計算角度
deg = ABuRegUtil.calc_regress_deg(kl_pd_noah.close)
print('noah 選股週期內角度={}'.format(round(deg, 3)))

noah 選股週期內角度=-9.289

注意上面的選股數據要使用擇時回測數據以前的一段時間數據,在AbuPickStockBase中定義了xd,min_xd選股週期獲取參數,
在AbuKLManager中經過get_pick_stock_kl_pd()函數配合xd,min_xd參數獲取選股週期數據

更多詳情請閱讀AbuPickStockBase源代碼與AbuKLManager源代碼

上述選股代碼實如今ABuPickStockExecute.do_pick_stock_work()中進行了封裝,即講AbuPickStockWorker及一些零散操做進行封裝。

更多詳情請閱讀ABuPickStockExecute,使用示例以下所示:

eg:繼續使用AbuPickRegressAngMinMax作爲選股因子,以下定義threshold_ang_min=0.0, threshold_ang_max=10.0,即只選取上升趨勢且上升角度小於10度的股票,下面示例使用ABuPickStockExecute.do_pick_stock_work()函數

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)
['usSFUN', 'usBIDU']

能夠看到結果sfun和baidu都符合,下面代碼驗證一下:

kl_pd_sfun = kl_pd_manger.get_pick_stock_kl_pd('usSFUN')
print('sfun 選股週期內角度={:.3f}'.format(ABuRegUtil.calc_regress_deg(kl_pd_sfun.close)))

sfun 選股週期內角度=8.230
kl_pd_baidu = kl_pd_manger.get_pick_stock_kl_pd('usBIDU')
print('bidu 選股週期內角度={:.3f}'.format(ABuRegUtil.calc_regress_deg(kl_pd_baidu.close)))

bidu 選股週期內角度=9.644

上面結果顯示兩支股票在選股週期中的價格趨勢擬合角度都在0-10之間。

假設修改需求想要選取週期內趨勢角度在0度-10度以外的全部股票,能夠這樣編寫代碼:

# 和上面的代碼惟一的區別就是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)
['usNOAH', 'usTSLA', 'usWUBA', 'usVIPS']

能夠看到結果與以前相反除了baidu和sfun以外全部股票都被選上,因爲在AbuPickStockBase中定義函數reversed_result(),它的做用就是定義結果是否反轉。

具體實現請閱讀AbuPickStockBase中reversed_result裝飾器的實現。

使用實際很簡單,在每一個具體的選股因子上的fit_pick()函數上根據須要選擇是否安上裝飾器,以下編寫價格選股因子所示:

class AbuPickStockPriceMinMax(AbuPickStockBase):
    """價格選股因子示例類"""
    def _init_self(self, **kwargs):
        """經過kwargs設置選股價格邊際條件,配置因子參數"""

        # 暫時與base保持一致不使用kwargs.pop('a', default)方式
        # fit_pick中選擇 > 最小(threshold_price_min), 默認負無窮,即默認全部都符合
        self.threshold_price_min = -np.inf
        if 'threshold_price_min' in kwargs:
            # 最小价格閥值
            self.threshold_price_min = kwargs['threshold_price_min']

        # fit_pick中選擇 < 最大(threshold_price_max), 默認正無窮,即默認全部都符合
        self.threshold_price_max = np.inf
        if 'threshold_price_max' in kwargs:
            # 最大價格閥值
            self.threshold_price_max = kwargs['threshold_price_max']

    @ps.reversed_result
    def fit_pick(self, kl_pd, target_symbol):
        """開始根據自定義價格邊際參數進行選股"""
        if kl_pd.close.max() < self.threshold_price_max and kl_pd.close.min() > self.threshold_price_min:
            # kl_pd.close的最大價格 < 最大價格閥值 且 kl_pd.close的最小价格 > 最小价格閥值
            return True
        return False

    def fit_first_choice(self, pick_worker, choice_symbols, *args, **kwargs):
        raise NotImplementedError('AbuPickStockPriceMinMax fit_first_choice unsupported now!')

備註:本節所編寫的選股示例代碼之內置在abupy項目代碼中可經過以下方式直接導入:

from abupy import AbuPickStockPriceMinMax
from abupy import AbuPickRegressAngMinMax

2. 多個選股因子並行執行

  1. ABuPickRegressAngMinMax: threshold_ang_min=0.0, 即要求股票走勢爲向上,上升趨勢
  2. ABuPickStockPriceMinMax threshold_price_min=50.0, 即要求股票在選股週期內股價最小值要大於50.0

繼續使用ABuPickStockExecute,使上面兩個選股因子同時生效,結果符合的只有BIDU及TSLA,代碼以下所示:

from abupy import AbuPickStockPriceMinMax


# 選股list使用兩個不一樣的選股因子組合,並行同時生效
stock_pickers = [{'class': AbuPickRegressAngMinMax,
                  'threshold_ang_min': 0.0, 'reversed': False},
                 {'class': AbuPickStockPriceMinMax,
                  'threshold_price_min': 50.0,
                  'reversed': False}]

%time ABuPickStockExecute.do_pick_stock_work(choice_symbols, benchmark, capital, stock_pickers)
['usBIDU', 'usTSLA']

3. 使用並行來提高選股運行效率

與並行擇時實現方式相似,選股使用AbuPickStockMaster並行執行多個進程來提高選股效率。

具體代碼請查詢AbuPickStockMaster,下面爲使用示例, 使用do_pick_stock_with_process()函數執行默認n_process_pick_stock=8,即默認同時運行8個進程。

# 選股list使用兩個不一樣的選股因子組合,並行同時生效
stock_pickers = [{'class': AbuPickRegressAngMinMax,
                  'threshold_ang_min': 0.0, 'reversed': False},
                 {'class': AbuPickStockPriceMinMax,
                  'threshold_price_min': 50.0,
                  'reversed': False}]

cs = AbuPickStockMaster.do_pick_stock_with_process(capital, benchmark, stock_pickers, choice_symbols)
pid:6614 pick stocks complete:100.0%
pid:6615 pick stocks complete:100.0%
pid:6616 pick stocks complete:100.0%
pid:6617 pick stocks complete:100.0%
pid:6618 pick stocks complete:100.0%
pid:6619 pick stocks complete:100.0%
pid:6620 pick stocks complete:100.0%
pid:6621 pick stocks complete:100.0%
pid:6617 done!
pid:6618 done!
pid:6615 done!
pid:6614 done!
pid:6616 done!
pid:6620 done!
pid:6619 done!
pid:6621 done!

從上面輸出能夠看到選股階段啓動了8個進程,由於股票數量太少,進程啓動銷燬也須要必定時間,因此上例總體效率並無提升。

更多示例請閱讀《量化交易之路》書中的示例以及對應的ipython代碼或者python代碼

abu量化文檔目錄章節

  1. 擇時策略的開發
  2. 擇時策略的優化
  3. 滑點策略與交易手續費
  4. 多支股票擇時回測與倉位管理
  5. 選股策略的開發
  6. 回測結果的度量
  7. 尋找策略最優參數和評分
  8. A股市場的回測
  9. 港股市場的回測
  10. 比特幣,萊特幣的回測
  11. 期貨市場的回測
  12. 機器學習與比特幣示例
  13. 量化技術分析應用
  14. 量化相關性分析應用
  15. 量化交易和搜索引擎
  16. UMP主裁交易決策
  17. UMP邊裁交易決策
  18. 自定義裁判決策交易
  19. 數據源
  20. A股全市場回測
  21. A股UMP決策
  22. 美股全市場回測
  23. 美股UMP決策

abu量化系統文檔教程持續更新中,請關注公衆號中的更新提醒。

更多阿布量化量化技術文章

更多關於量化交易相關請閱讀《量化交易之路》

更多關於量化交易與機器學習相關請閱讀《機器學習之路》

更多關於abu量化系統請關注微信公衆號: abu_quant

相關文章
相關標籤/搜索