一、均值回歸理論
均值回歸:股票價格無論高於或低於價值中樞(或均值)都會以很高的概率向價值中樞回歸的趨勢。何時會發生均值回歸,屬於“隨機漫步”范疇。
均值回歸的理論基於以下觀測:價格的波動一般會以它的均線為中心。即當標的價格由於波動而偏離移動的均線時,它將調整並重新歸於均線。
偏離程度:(MA-P)/MA
1、均值回歸原理
均值回歸法則:萬物最終都將回歸於其長期的均值。
根據這個理論,一種上漲或者下跌的趨勢不管其延續的時間多長都不能永遠持續下去,最終均值回歸的規律一定會出現:漲得太多了,就會向平均值移動下跌;跌得太多了,就會向平均值移動上升。
與趨勢跟蹤賭趨勢的繼續不同,均值回歸則是賭趨勢的反轉。巴菲特的逆向投資策略,索羅斯的反身理論,其本質都是均值回歸理論的應用,所不同的是前者是價值低估的投資,后者則是泡沫破滅的投機。
均值回歸理論在一定程度上或一定范圍內對股票價格進行預測,對於長線投資者具有重要指導意義。
到目前為止,均值回歸理論仍不能解決的或者說不能預測的是回歸的時間間隔,即回歸的周期呈 " 隨機漫步 "。不同的股票市場,回歸的周期會不一樣,就是對同一個股票市場來說,每次回歸的周期也不一樣。
2、均值回歸策略(選股)
每個調倉日進行。
- 計算股票池中所有股票的N日均線;
- 計算股票池中所有股票和均線的偏離度;
- 選取偏離度最高的M只股票並調倉。
二、均值回歸實現
# 初始化函數,設定基准等等 def initialize(context): # 設定滬深300作為基准 set_benchmark('000300.XSHG') # 開啟動態復權模式(真實價格) set_option('use_real_price', True) # 輸出內容到日志 log.info() log.info('初始函數開始運行且全局只運行一次') # 股票類每筆交易時的手續費是:買入時佣金萬分之三,賣出時佣金萬分之三加千分之一印花稅, 每筆交易佣金最低扣5塊錢 set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock') # 獲取指數成份股 g.security = get_index_stocks('000300.XSHG') # print(g.security) # ['000001.XSHE', '000002.XSHE', '000063.XSHE'...'603986.XSHG', '603993.XSHG'] g.ma_days = 30 # 30天均值 g.stock_num = 10 # 持倉10只股票 run_monthly(handle, 1) # 第一個參數是對應的函數,第二個參數指第幾個交易日 def handle(context): # pandas的Series對象:能夠保存任何類型的數據(整數,字符串,浮點數,Python對象等)的一維標記數組 # Series參數——index索引:索引值必須是唯一的和散列的,與數據的長度相同 sr = pd.Series(index=g.security) # 索引設置為滬深300股票代碼 # 遍歷股票代碼 for stock in sr.index: # attribute_history獲取歷史數據:參數設置股票代碼、單位時間長度 ma = attribute_history(stock, g.ma_days)['close'].mean() # 選取close這一列求平均,獲取30日均值 # 這只股票今天開盤價 # get_current_data: 獲取當前時間數據 p = get_current_data()[stock].day_open # 股票到均線的偏離程度 ratio = (ma - p) / ma sr[stock] = ratio # 選出偏離程度最大的十個 # pandas.DataFrame.nlargest:返回按列降序排列的前n行 to_hold = sr.nlargest(g.stock_num).index.values # print(to_hold) for stock in context.portfolio.positions: if stock not in to_hold: # 目標股數下單,賣出非標的的股票 order_target(stock, 0) # 期待持有且還未持倉的股票 to_buy = [stock for stock in to_hold if stock not in context.portfolio.positions] if len(to_buy) > 0: # 需要調倉 # 每只股票預計投入的資金 cash_per_stock = context.portfolio.available_cash / len(to_buy) for stock in to_buy: # 按價值下單,買入需買入的股票 order_value(stock, cash_per_stock)
執行顯示效果:
1、計算出均線、股價、偏離度
def handle(context): # pandas的Series對象:能夠保存任何類型的數據(整數,字符串,浮點數,Python對象等)的一維標記數組 # Series參數——index索引:索引值必須是唯一的和散列的,與數據的長度相同 sr = pd.Series(index=g.security) # 索引設置為滬深300股票代碼 # 遍歷股票代碼 for stock in sr.index: # attribute_history獲取歷史數據:參數設置股票代碼、單位時間長度 ma = attribute_history(stock, g.ma_days)['close'].mean() # 選取close這一列求平均,獲取30日均值 # 這只股票今天開盤價 # get_current_data: 獲取當前時間數據 p = get_current_data()[stock].day_open # 股票到均線的偏離程度 ratio = (ma - p) / ma sr[stock] = ratio
偏離程度計算:(MA-P)/MA
2、找到偏離度最高的股票
DataFrame.nlargest(self,n,columns,keep ='first' )
pandas.DataFrame.nlargest():返回按列降序排列的前n行。以降序返回column中具有最大值的前n行。未指定的列也將返回,但不用於排序。
此方法等效於 如下方法,但性能更高:
df.sort_values(columns, ascending=False).head(n)
選出偏離度最大的十只股票:
def handle(context): # pandas的Series對象:能夠保存任何類型的數據(整數,字符串,浮點數,Python對象等)的一維標記數組 # Series參數——index索引:索引值必須是唯一的和散列的,與數據的長度相同 sr = pd.Series(index=g.security) # 索引設置為滬深300股票代碼 # 遍歷股票代碼 for stock in sr.index: # attribute_history獲取歷史數據:參數設置股票代碼、單位時間長度 ma = attribute_history(stock, g.ma_days)['close'].mean() # 選取close這一列求平均,獲取30日均值 # 這只股票今天開盤價 # get_current_data: 獲取當前時間數據 p = get_current_data()[stock].day_open # 股票到均線的偏離程度 ratio = (ma - p) / ma sr[stock] = ratio # 選出偏離程度最大的十個 # pandas.DataFrame.nlargest:返回按列降序排列的前n行 to_hold = sr.nlargest(g.stock_num).index print(to_hold)
執行顯示效果:
2019-01-02 09:30:00 - INFO - Index(['002252.XSHE', '600518.XSHG', '300003.XSHE', '600703.XSHG', '002450.XSHE', '002555.XSHE', '002310.XSHE', '600157.XSHG', '603986.XSHG', '002456.XSHE'], dtype='object') 2019-02-01 09:30:00 - INFO - Index(['002450.XSHE', '600518.XSHG', '300072.XSHE', '002252.XSHE', '300296.XSHE', '600100.XSHG', '600867.XSHG', '002310.XSHE', '600703.XSHG', '002460.XSHE'], dtype='object')
可以看到返回的是一個Index對象。
3、將得到的對象轉為數組
pandas.Index.values返回Index對象中數據的數組。
def handle(context): # pandas的Series對象:能夠保存任何類型的數據(整數,字符串,浮點數,Python對象等)的一維標記數組 # Series參數——index索引:索引值必須是唯一的和散列的,與數據的長度相同 sr = pd.Series(index=g.security) # 索引設置為滬深300股票代碼 # 遍歷股票代碼 for stock in sr.index: # attribute_history獲取歷史數據:參數設置股票代碼、單位時間長度 ma = attribute_history(stock, g.ma_days)['close'].mean() # 選取close這一列求平均,獲取30日均值 # 這只股票今天開盤價 # get_current_data: 獲取當前時間數據 p = get_current_data()[stock].day_open # 股票到均線的偏離程度 ratio = (ma - p) / ma sr[stock] = ratio # 選出偏離程度最大的十個 # pandas.DataFrame.nlargest:返回按列降序排列的前n行 to_hold = sr.nlargest(g.stock_num).index.values print(to_hold)
執行顯示:
2019-01-02 09:30:00 - INFO - [002252.XSHE 600518.XSHG 300003.XSHE 600703.XSHG 002450.XSHE 002555.XSHE 002310.XSHE 600157.XSHG 603986.XSHG 002456.XSHE] 2019-02-01 09:30:00 - INFO - [002450.XSHE 600518.XSHG 300072.XSHE 002252.XSHE 300296.XSHE 600100.XSHG 600867.XSHG 002310.XSHE 600703.XSHG 002460.XSHE]
均值回歸也可以作為一個因子加入多因子選股策略!