動量策略是最流行的量化策略之一。商品期貨的CTA策略,絕大多數都是基於動量策略。在股票市場,動量策略也是經常使用的量化因子之一。通俗地講,動量策略就是「追漲殺跌」。下面咱們將介紹如何在DolphinDB中測試動量交易策略,並計算動量交易策略的累積回報。數據庫
DolphinDB database 是一款高性能分佈式時序數據庫。與其它一般的數據庫不一樣,DolphinDB不只能夠存儲和檢索數據,並且具有強大的編程和分析功能,能夠直接在數據庫內完成策略回測等複雜的工做,便捷且高效。編程
最經常使用的股票動量因素是基於過去一年中扣除最近一個月的收益率。動量策略一般是一個月調整一次而且持有期也是一個月。本文的例子中,天天調整1/21的投資組合,並持有新的投資組合21天。爲了簡化起見,本文的回測沒有考慮交易成本。分佈式
假設原始數據是一個CSV文件。它包含如下列:性能
PERMNO:股票代碼測試
date:日期url
PRC:每股價格spa
SHROUT:流通股數.net
RET:股票日收益線程
VOL:每日交易量設計
步驟1. 加載股票交易數據,對數據進行清洗和過濾,而後爲每隻股票構建過去一年扣除最近一個月收益率的動量信號。
US = loadText("C:/DolphinDB/Data/US.csv") def loadPriceData(inData){ USstocks = select PERMNO, date, abs(PRC) as PRC, VOL, RET, SHROUT*abs(PRC) as MV from inData where weekday(date) between 1:5, isValid(PRC), isValid(VOL) order by PERMNO, date USstocks = select PERMNO, date, PRC, VOL, RET, MV, cumprod(1+RET) as cumretIndex from USstocks context by PERMNO return select PERMNO, date, PRC, VOL, RET, MV, move(cumretIndex,21)\move(cumretIndex,252)-1 as signal from USstocks context by PERMNO } priceData = loadPriceData(US)
步驟2. 爲動量策略生成投資組合
首先,選擇知足如下條件的流通股:動量信號值完好失、當天的交易量爲正、市值超過1億美圓以及每股價格超過5美圓。
def genTradables(indata){ return select date, PERMNO, MV, signal from indata where PRC>5, MV>100000, VOL>0, isValid(signal) order by date } tradables = genTradables(priceData)
而後根據天天的動量信號,產生10組流通股票。只保留2個最極端的羣體(贏家和輸家)。假設在21天內,天天老是多頭1美圓和空頭1美圓,因此咱們天天在贏家組多頭1/21,在輸家組天天空頭1/21,在輸家組每天空頭1/21。在每組中,咱們可使用等權重或市值權重, 來計算投資組合造成日期上每一個股票的權重。
//WtScheme=1表示等權重;WtScheme=2表示值權重 def formPortfolio(startDate, endDate, tradables, holdingDays, groups, WtScheme){ ports = select date, PERMNO, MV, rank(signal,,groups) as rank, count(PERMNO) as symCount, 0.0 as wt from tradables where date between startDate:endDate context by date having count(PERMNO)>=100 if (WtScheme==1){ update ports set wt = -1.0\count(PERMNO)\holdingDays where rank=0 context by date update ports set wt = 1.0\count(PERMNO)\holdingDays where rank=groups-1 context by date } else if (WtScheme==2){ update ports set wt = -MV\sum(MV)\holdingDays where rank=0 context by date update ports set wt = MV\sum(MV)\holdingDays where rank=groups-1 context by date } return select PERMNO, date as tranche, wt from ports where wt != 0 order by PERMNO, date } startDate=1996.01.01 endDate=2017.01.01 holdingDays=21 groups=10 ports = formPortfolio(startDate, endDate, tradables, holdingDays, groups, 2) dailyRtn = select date, PERMNO, RET as dailyRet from priceData where date between startDate:endDate
步驟3. 計算投資組合中每隻股票接下來21天的利潤或損失。在投資組合造成後的21天關停投資組合。
def calcStockPnL(ports, dailyRtn, holdingDays, endDate, lastDays){ ages = table(1..holdingDays as age) dates = sort distinct ports.tranche dictDateIndex = dict(dates, 1..dates.size()) dictIndexDate = dict(1..dates.size(), dates) pos = select dictIndexDate[dictDateIndex[tranche]+age] as date, PERMNO, tranche, age, take(0.0,size age) as ret, wt as expr, take(0.0,size age) as pnl from cj(ports,ages) where isValid(dictIndexDate[dictDateIndex[tranche]+age]), dictIndexDate[dictDateIndex[tranche]+age]<=min(lastDays[PERMNO], endDate) update pos set ret = dailyRet from ej(pos, dailyRtn,`date`PERMNO) update pos set expr = expr*cumprod(1+ret) from pos context by PERMNO, tranche update pos set pnl = expr*ret/(1+ret) return pos } lastDaysTable = select max(date) as date from priceData group by PERMNO lastDays = dict(lastDaysTable.PERMNO, lastDaysTable.date) undef(`priceData, VAR) stockPnL = calcStockPnL(ports, dailyRtn, holdingDays, endDate, lastDays)
步驟4. 計算投資組合的利潤或損失,並繪製隨時間推移的動量策略累積回報。
portPnL = select sum(pnl) as pnl from stockPnL group by date portPnL = select * from portPnL order by date; plot(cumsum(portPnL.pnl) as cumulativeReturn,portPnL.date, "Cumulative Returns of the Momentum Strategy")
如下是美國股票市場1996年到2016年,20年回測的結果。回測時,天天產生一個新的tranche,包含大約1500只股票(平均天天約7500只股票,取20%),持有21天。如此龐大的數據量和計算量,使用單線程計算,DolphinDB耗時僅3分鐘。
動量交易策略實施起來須要理解得到超額回報的原理和必定的交易技能,以及可能帶來的投資風險。感興趣的朋友能夠到官網下載 DolphinDB database,設計本身的動量交易策略。