機器學習多因子策略


機器學習多因子策略

標簽(空格分隔): 量化交易 機器學習


前言

  • 在二級市場的量化策略中,多因子策略稱得上是最早被創造但是同時也是變化最多的投資策略之一,好的因子意味着長期穩定的收入,多因子策略可以通過不同的渠道來實現,從而帶來不同的市場表現
  • 傳統使用的多元線性回歸模型能夠獲得多因子與股價之間的一定的對應關系,但是在有的時候不夠穩定
  • 機器學習在預測和分類中具有良好的表現,傳統的多因子線性回歸模型也證明了多個因子確實和股價有關系,這種關系天然的適合應用機器學習去對股票進行選股和擇時,從而使得獲取超額收益的可能性更高

多因子策略簡介

因子可以分為擇時因子和選股因子以及衍生出來的市值解釋因子,擇時和選股可以說是量化策略中的核心部分,而通過市值解釋因子則可以幫助我們進行擇時選股操作,量化策略的所有工作幾乎都是圍繞着這兩個核心進行的,量化系統的組成可以看下圖:

st=>start: 行情數據,財務數據,自定義數據,投資經驗
op=>operation: 選股,擇時,倉位管理,止盈止損
io=>inputoutput: 買入信號,賣出信號,交易費用,收益
e=>end
st->op->io->e
io->e

最為經典的多因子模型是Fama和French提出的三因子模型,而其基本的 股票的超額收益率可以由市場風險、市值風險、賬面市值三個因素決定,因此我們將股票一個時期內的超額收益率對這三個因素進行回歸,再講回歸得到的參數本時期內的超額收益率進行預測,比較真實值和預測值,如果預測值大於真實值,也就是說理論上的超額收益率應該大於當前的超額收益率,那么根據有效市場假說,未來的超額收益率應該上升,反之亦然

市值解釋因子簡介

2005年,在哈佛大學Matthew Rhodes-Kropf教授以及杜克大學S. Viwanathan和David T. Robinson教授合著的論文《Valuation Waves and Merger Activity: The Empirical Evidence》中,股票市值被分解為如下的三因子模型:
$$m=\alpha_0IND+\alpha_1b+\alpha_3I\ln(NI)^+\alpha_4LEV+\epsilon$$

其中,$IND$為行業虛擬變量矩陣(若該股屬於某行業,則將這一行業虛擬變量的值設為1,其他行業的虛擬變量值設為0),$m$為個股的對數凈資產,$NI$為公司凈利潤,當凈利潤為負的時候$I$的值為1,並且我們取凈利潤絕對值的對數放到回歸運算中;$LEV$為公司的財務杠桿(負債除以資產),當該模型被用於擬合特定美股的時候,此三因子模型平均擬合優度超過80%,這意味着這三因子模型是有效的

2012年,馬里蘭大學的Charles R. Hulten教授及其博士生Janet X. Hao發表的論文《The Role Of Intangible Capital in the Transformation and Growth of the Chinese Economy》中,發現上市公司的市值與其凈資產、開發支出、組織資本以及市盈率密不可分,選取開發支出力度大的公司進行下述回歸,擬合優度可以達到94%:
$$m=\alpha_0+\alpha_1b+\alpha_2RD+\alpha_3O+\alpha_4PE+\epsilon$$

其中$\alpha_0$為年度虛擬變量矩陣,$m$和$b$的含義與上文相同,$RD$為對數開發支出,$O$為對數組織資本,PE為市盈率

上述的多因子模型說明,股票在某個時間點的市值可以被多個因子解釋,而通過市值我們就可以對股票的價格進行預測,從而根據市值的高低來指導我們的擇時策略

模型搭建和因子選擇

  • 基本思路:多因子策略的原理是:股票的市值可以被多個因素解釋,通過對多個因素做回歸計算得到理論股票值,股票的真實市值減去理論市值,得到殘差,殘差越小表明股價越被低估,意味着該股票未來上漲的可能性越大
  • 因子選擇:對數凈資產,對數凈利潤,公司財務杠桿,營業收入增長率,對數開發支出,以及行業虛擬變量

多元線性回歸模型:
$$m=\alpha_0IND+\alpha_1b+\alpha_3I\ln(NI)^+\alpha_4LEV+\alpha_5g+alpha_6RD+\epsilon$$

支持向量機回歸

import pandas as pd
import numpy as np
import math
from sklearn.svm import SVR
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import learning_curve
import jqdata

def initialize(context):
    set_params()
    set_backtest()
    run_daily(trade,'every_bar')

def set_params():
    g.days = 0
    g.refresh_rate = 10
    g.stocknum = 10

def set_backtest():
    set_benchmark('000985.XSHG')
    set_option('use_real_price',True)
    log.set_level('order','error')

def trade(context):
    if g.days%10 == 0:
        sample = get_index_stock('000985.XSHG',date=None)
        q = query(valuation.code, valuation.market_cap, balance.total_assets - balance.total_liability,
                  balance.total_assets / balance.total_liability, income.net_profit, income.net_profit + 1, 
                  indicator.inc_revenue_year_on_year, balance.development_expenditure).filter(valuation.code.in_(sample))
        df = get_fundamentals(q,date=None)
        df.columns = ['code', 'log_mcap', 'log_NC', 'LEV', 'NI_p', 'NI_n', 'g', 'log_RD']
        df['log_mcap'] = np.log(df['log_mcap'])
        df['log_NC'] = np.log(df['log_NC'])
        df['NI_p'] = np.log(np.abs(df['NI_p']))
        df['NI_n'] = np.log(np.abs(df['NI_n'][df['NI_n']<0]))
        df['log_RD'] = np.log(df['log_RD'])
        df.index = df.code.values
        del df['code']
        df = df.fillna(0)
        df[df>10000] = 10000
        df[df<-10000] = -10000
        industry_set = ['801010', '801020', '801030', '801040', '801050', '801080', '801110', '801120', '801130', 
                  '801140', '801150', '801160', '801170', '801180', '801200', '801210', '801230', '801710',
                  '801720', '801730', '801740', '801750', '801760', '801770', '801780', '801790', '801880','801890']
        for i in range(len(industry_set)):
            industry = get_industry_stocks(industry_set[i], date = None)
            s = pd.Series([0]*len(df), index=df.index)
            s[set(industry) & set(df.index)]=1
            df[industry_set[i]] = s
            
        X = df[['log_NC', 'LEV', 'NI_p', 'NI_n', 'g', 'log_RD','801010', '801020', '801030', '801040', '801050', 
                '801080', '801110', '801120', '801130', '801140', '801150', '801160', '801170', '801180', '801200', 
                '801210', '801230', '801710', '801720', '801730', '801740', '801750', '801760', '801770', '801780', 
                '801790', '801880', '801890']]
        Y = df[['log_mcap']]
        X = X.fillna(0)
        Y = Y.fillna(0)
        
        svr = SVR(kernel='rbf', gamma=0.1) 
        model = svr.fit(X, Y)
        factor = Y - pd.DataFrame(svr.predict(X), index = Y.index, columns = ['log_mcap'])
        factor = factor.sort_index(by = 'log_mcap')
        stockset = list(factor.index[:10])
        sell_list = list(context.portfolio.positions.keys())
        for stock in sell_list:
            if stock not in stockset[:g.stocknum]:
                stock_sell = stock
                order_target_value(stock_sell, 0)
            
        if len(context.portfolio.positions) < g.stocknum:
            num = g.stocknum - len(context.portfolio.positions)
            cash = context.portfolio.cash/num
        else:
            cash = 0
            num = 0
        for stock in stockset[:g.stocknum]:
            if stock in sell_list:
                pass
            else:
                stock_buy = stock
                order_target_value(stock_buy, cash)
                num = num - 1
                if num == 0:
                    break
        g.days += 1
    else:
        g.days = g.days + 1


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM