量能回測實戰

photo by Leio McLaren on Unsplash

本文重點概要

· 文章難度:★★☆☆☆

· 以成交量增長為篩選指標

· 閱讀建議:本文以成交量增長作為買賣指標,以視覺化的方式觀察交易訊號以及買賣點,接著再利用函數計算出報酬率,如果對回測或是技術指標不了解的讀者,歡迎先行閱讀【量化分析(二)】- 技術分析簡介與回測,詳細理解回測的執行流程。

前言

近幾年動能交易很常出現在股票策略的討論當中,我們在股票市場通常很常聽到談論價量關係,價是量的先行指標等等,而本文想進而探討當成交量放大時以做為進場策略之回測效應,本方法並沒有像其他技術指標一樣有一定之準則,於是在設計上比較較為彈性,在程式設計上能使讀者們自行更改,詳細參數設定上會在後面程式碼中提及如何修改。而本文採用以下策略進行回測:

1. 進場成交量是前”4”日平均的2.5倍做為進入準則

2. 出場設在成交量低於”5”日平均的0.75倍

編輯環境及模組需求

本文使用 Window10 並以 Spyder(anaconda31) 作為編輯器

###匯入套件 ##########數據分析三寶 import pandas as pd import matplotlib.pyplot as plt import numpy as np #################TEJ import tejapi tejapi.ApiConfig.api_key = 'Your Key' tejapi.ApiConfig.ignoretz = True

資料庫使用

證券交易資料表:上市(櫃)未調整股價(日),資料代碼為(TWN/EWPRCD)。

資料導入

coid="2618" #### 可自行更換股票代碼 start="2018-01-01" ### 自行更換起始時間 end= "2022-02-17"  ### 自行更換結束時間 opts={'columns': ['coid', 'mdate', 'volume', 'close_adj','close_d','open_d']}  ###本文使用除權息調整收盤價 ############# fly=tejapi.get('TWN/EWPRCD',coid=coid,                  mdate={'gt':start,'lt':end},                 paginate=True,                 chinese_column_name=True,                 opts=opts )

選擇現在最熱門的族群航空,時間範圍選取於2018年1月1日至 2022年2月16日,並把圖繪出來藉以觀察股價情況。

fly.set_index("日期",drop=True,inplace=True) # 設定index plt.figure(facecolor='white',figsize=(12,8)) plt.plot(fly['收盤價'], label='收盤價') plt.title("飛機起飛表",fontsize=25) plt.xticks(rotation=45) plt.xlabel('日期',fontsize=25) plt.ylabel('股價',fontsize=25) plt.grid() plt.show()
飛機起飛表
飛機起飛表

資料處理

step1 計算指標

def voltrade(df,p,q,r):     df =df.copy()     df["當日交易量"]=df["成交量(千股)"].rolling(p).mean()      df["前五日總量"]=df["成交量(千股)"].rolling(q).sum()     df[str(r)+"日均線"]=df["收盤價-除權息"].rolling(r).mean()     ####扣除掉當日之平均     df["前幾日平均"]=(df["前五日總量"]-df["當日交易量"])/(q-p)     return df

此段能得到前4天的平均交易量(扣除當日),以及5MA(皆能自行更改,改動q, r即可)

如q設5,能得到前四日平均交易量,如r設5,得到近5日平均股價

r=5 stock=voltrade(fly, 1, 5, r) # 本文選定策略參數 stock
股票資訊
股票資訊

Step 4. 找出買賣訊號與視覺化買賣點(詳見完整程式碼)

def buysell(company,a,b):     company =company.copy()     buy=[]     sell=[]     hold=0     for i in range(len(company)):         if  company["當日交易量"][i] > company["前幾日平均"][i]*a :             sell.append(np.nan)             if hold !=1:                 buy.append(company["收盤價-除權息"][i])                   hold = 1             else:                  buy.append(np.nan)         elif company["當日交易量"][i]<company["前幾日平均"][i]*b :             buy.append(np.nan)             if hold !=0:                 sell.append(company["收盤價-除權息"][i])                 hold = 0             else:                 sell.append(np.nan)         else:             buy.append(np.nan)             sell.append(np.nan)     a=(buy,sell)     company['Buy_Signal_Price']=a[0]     company['Sell_Signal_Price']=a[1]     company["買賣股數1"]=company['Buy_Signal_Price'].apply(lambda x : 1000 if x >0 else 0)     company["買賣股數2"]=company['Sell_Signal_Price'].apply(lambda x : -1000 if x >0 else 0  )     company["買賣股數"]=company["買賣股數1"]+ company["買賣股數2"]     return company

此段設計為當日成交量大於前四日平均2.5倍時進場,在成交量小於前四日平均0.75倍時出場,係數皆能自行調整。

vol=buysell(stock,2.5,0.75) plot(vol)
買賣交易訊號(一)
買賣交易訊號(一)

我們能看到這方法中,股票前三年中皆在盤整進出增加了許多摩擦成本,到2021年開始飆升但此方法因為條件過於簡易而造成了上漲但是提早出場的情形,因此在條件上本文多設了五日均線的設定,成交量大量且突破五日均線下買入,成交量縮小且跌破五日均線時賣出,結果如下圖。

買賣交易訊號(二)
買賣交易訊號(二)

本文使用成交量為進出指標,於是把股價與成交量畫再一起,本文提供一起畫與分開畫的方法,斟酌於自己喜歡哪種~~

pvtwo(volma) #分開繪製 pvsame(volma)#合併繪製
圖(四)
圖(四)
圖(五)
圖(五)

計算報酬

MACD指標回測實戰裡,我們有詳細介紹考慮手續費、現金部位計算報酬率的方式,因為流程固定,本文以下方函數包裝。

def target_return(data, principal):     data=data.copy()     #計算成本     data['手續費'] = data['收盤價-除權息']* abs(data['買賣股數'])*0.001425     data['手續費'] = np.where((data['手續費']>0)&(data['手續費'] <20), 20, data['手續費'])     data['證交稅'] = np.where(data['買賣股數']<0, data['收盤價-除權息']* abs(data['買賣股數'])*0.003, 0)     data['摩擦成本'] = (data['手續費'] + data['證交稅']).apply(np.floor)     #計算資產價值     data['股票價值'] = data['買賣股數'].cumsum() * data['收盤價-除權息']     data['現金價值'] = principal - data['摩擦成本'] + (data['收盤價-除權息']* -data['買賣股數']).cumsum()      data['資產價值'] = data['股票價值'] + data['現金價值']     #計算報酬率     data['當日價值變動(%)'] = (data['資產價值']/data['資產價值'].shift(1) - 1)*100     data['累計報酬(%)'] = (data['資產價值']/principal - 1)*100     return data

本文單純考量一般股票買賣,並無考慮融券融資情形,所以沒有計算保證金的流程,只要將買賣股數的資料整理好,並決定期初的現金部位,即可算出交易成本以及報酬率。本文選擇投入16000元為期初一張股票之價格。

volreturn1 = target_return( volma, principal = 16000)##有加入均線之策略 volreturn2 = target_return( vol, principal = 16000)##並未加入均線策略
圖(五)
圖(五)

加入買入持有策略,與本文策略進行比較。

keep=vol.copy() keep["買賣股數"]=0 keep["買賣股數"][0]=1000 keep["買賣股數"][len(keep)-1]=-1000 volreturn3 = target_return( keep, principal = 16000)

報酬績效比較

Step 1. 累計報酬比較(詳見完整程式碼)

圖(六)
圖(六)

Step 2. 累計報酬比較(詳見完整程式碼)

圖(七)
圖(七)

結論

我們能看到如果只使用成交量做為進出條件,年化報酬率只有8%與持有相當,加入條件MA後年化報酬率來到了在17.31,Sharp ratio 也是裡面最高的,但是缺點也很明顯在於2018~2020年上報酬率為負數,也就是在於盤整的股票上,效果並不是那麼好,甚至有可能會變成負報酬率,或許在進場的條件上能設定的較為嚴格,減少多餘的進出,還有兩個特殊情形要提醒此方法的使用:

  1. 面臨到被處置股票也無法使用此方法,因為處置時成交量勢必下降。

2. 在進行指數調整時,如富時指數,msci等,成交量容易放大導致買賣點判斷錯誤。

來到2021年後,長榮航開始起漲,俗話都說股價是用錢砸出來的,成交量放大才能推升股價,因此此策略能在這段找到不錯的進場點位,而因為短進短出的特性,也能讓資金使用上更具備效率。

再之後也會介紹使用TEJ資料庫尋找成交量放大的股票,藉由程式的篩選,能讓尋找標的時候更便利,也能試試看搭配此方法一起使用喔!所以歡迎對各種交易回測有興趣的讀者,選購TEJ E-Shop的相關方案,用高品質的資料庫,建構出適合自己的交易策略。

完整程式碼

延伸閱讀

相關連結

返回總覽頁
Procesing