動量策略是通過利用市場波動從現有趨勢的延續中獲利。簡單來說,高買高賣,反之亦然(「低買高賣」是均值回歸策略思想,與動量策略相反)。價值投資通常基於均值的長期回歸,而動量投資基於均值回歸發生之前的時間間隔。通常而言,基於過去回報(價格動量策略)或收益意外(稱為收益動量策略)的策略是利用市場對不同信息的反應不足。換句話說,收益動量策略是基於對短期收益相關信息的反應不足中獲利,而價格動量策略是基於從市場對更廣泛信息(包括長期盈利能力)的緩慢反應中獲利。動量策略的構建有兩種思路,一種是個股歷史價格動量,即與過去價格相比計算漲跌幅,也叫時間動量;另一種是截面動量,即對當前市場所有個股進行某期間漲跌幅排序,如歐奈爾的RPS指標。下面以簡單的均線為例,構建均線多頭排列的時間動量進行歷史回測。數據獲取、可視化和回測均用到公眾號開發的qstock包(免費),關於qstock的數據、可視化、選股等詳細教程請參閱以下推文:
【qstock開源了】數據篇之行情交易數據
【qstock數據篇】行業概念板塊與資金流
【qstock量化】數據篇之股票基本面數據
【qstock量化】數據篇之宏觀指標和財經新聞文本
【qstock量化】動態交互數據可視化
【qstock量化】技術形態與概念熱點選股池
【手把手教你】使用qstock實現量化策略選股
使用漢明距離(scipy.spatial.distance)度量均線多頭排列的動量趨勢。漢明距離是信息論里的一個概念,它表示兩個(相同長度)字符串對應位置的不同字符的數量。漢明距離對向量按元素進行比較,並對差異的數量進行平均,如果兩個向量相同,得到的距離是0之間,如果兩個向量完全不同,得到的距離是1。
importnumpyasnpimportpandasaspdimportscipy.statsasstatsfromdatetimeimporttimedeltaimportscipy.spatial.distanceasdistanceimportmatplotlib.pyplotaspltimportqstockasqs使用qstock獲取回測用數據,以中國平安為例,基準指數為滬深300指數,回測期間為2010-2022年。#獲取數據#data_feed是qstock回測模塊獲取數據函數,默認基準指數為滬深300#fqt=2表示後復權數據,等於1表示前復權df=qs.data_feed('中國平安',index='hs300',start='20100101',end='202201216',fqt=2)#計算10個均線序列foriinnp.linspace(10,100,10):df[str(i)+'日均線']=df['close'].rolling(window=int(i),center=False).mean()df.dropna(inplace=True)均線數據可視化。
#均線可視化cols=['close']+[str(i)+'日均線'foriinnp.linspace(10,100,10)]qs.line(df['2020':][cols])cols=[str(i)+'日均線'foriinnp.linspace(10,100,10)]
fordateindf.index:#圍繞每一日的均線大小進行排序ranking=stats.rankdata(df.loc[date,cols].values)#計算每一日均線之間的漢明距離(scipy.spatial.distance)df.loc[date,'scores']=distance.hamming(ranking,range(1,11))個股價格與均線漢明距離得分數據可視化。
#價格走勢與均線排列的漢明距離得分可視化df[['close','scores']].plot(figsize=(15,7),secondary_y='scores',alpha=0.6)plt.show()策略思路:當短期均線大於長期均線呈現多條均線的多頭排列時,買入做多,當均線呈現空頭排列時賣出。使用漢明距離可以度量均線的多頭與空頭排列得分,當出現完美的均線多頭時(短期均線依次大於長期均線,如10日MA > 20日MA >… 100日MA),得分為1;當出現完美的空頭時,即短期均線依次小於長期均線,如10日MA < 20日MA <… <100日MA)得為0,其他均線排列得分位於0-1之間。可以根據得分設定一個門檻值,如當scores得分大於0.5,給出買入或持有的信號,否則為賣出或做空信號。
#封裝成函數方便後面進行回測分析defma_momentum(code,benchmark='hs300',start='20100101',end='202201219',ma_list=None,threshold=0.8):df=qs.data_feed(code,index=benchmark,start=start,end=end,fqt=2)ss=np.linspace(10,100,10)ifma_listisNoneelsema_listforiinss:df[str(i)+'日均線']=df['close'].rolling(window=int(i),center=False).mean()df.dropna(inplace=True)cols=[str(i)+'日均線'foriinss]fordateindf.index:ranking=stats.rankdata(df.loc[date,cols].values)df.loc[date,'scores']=distance.hamming(ranking,range(1,len(ss)+1))#當日均線多頭排列scores=1發出買入信號設置為1df.loc[df['scores']>threshold,'signal']=1#當日均線空頭排列scores=0發出買入信號設置為0df.loc[df['scores']<=threshold,'signal']=0df['position']=df['signal'].shift(1)df['position'].fillna(method='ffill',inplace=True)d=df[df['position']==1].index[0]-timedelta(days=1)df1=df.loc[d:].copy()df1['position'][0]=0#當倉位為1時,買入持倉,當倉位為0時,空倉,計算資金淨值df1['capital_ret']=df1.rets.values*df1['position'].values#計算策略累計收益率df1['capital_line']=(df1.capital_ret+1.0).cumprod()returndf1#可以通過ma_list自定義設置ma均線計算周期#如ma_list=[3,5,8,13,21,34,55,89,144,233]#ma_list=None表示默認使用10-100日均線data=ma_momentum('中國平安',ma_list=None,threshold=0.8)回測結果。
qs.start_backtest(data)修改均線參數,同時以貴州茅台個股為例重新進行回測。
fib=[3,5,8,13,21,34,55,89,144,233]data=ma_momentum('貴州茅台',ma_list=fib,threshold=0.5)qs.start_backtest(data)此外,介紹一個非常簡單易上手的回測框架quantstats,下面使用它展示歷史回測結果。注意quantstats要先使用"pip install QuantStats"進行安裝,注意安裝的時候包含大寫字母,導入使用小寫字母。quantstats與pyfolio類似,一行代碼可以實現豐富的回測圖表,下面只展示部分結果。如下面輸入qst.reports.html(data.capital_ret),可以生成本地基於web的html回測結果。關於pyfolio的回測用法可以參照推文:《Pyfolio一行代碼實現專業量化回測圖表》
importquantstatsasqstqst.reports.full(data.capital_ret)本文利用漢明距離計算均線排列的得分來評估股價的動量趨勢,並以此構建擇時交易策略,即當呈現多頭均線排列的趨勢時買入,空頭排列時賣出。以中國平安和貴州茅台個股為例進行了歷史回測,結果顯示該交易策略優於買入持有和基準指數。
對於歷史上證明有效的任何策略,通常有兩種解釋,該策略已經補償了它所承擔的額外風險,或者存在溢價行為因素。那為什麼動量策略有效?動量策略起作用的邏輯在於,投資者表現出一長串行為偏見和情緒錯誤。然而,這說起來容易做起來難,因為趨勢不會永遠持續下去,並且在達到頂峰和結束時可能會迅速逆轉。動量交易比大多數其他策略具有更高程度的波動性,並試圖利用市場波動性。通過使用適當的風險管理技術和止損,正確安排買賣時間以避免損失非常重要。
最後為有意加入知識星球的新用戶送上100張89元的優惠券,新用戶或續費用戶在加入前可先添加星主微信 「sky2blue2」 了解更多優惠信息。


