一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

量化交易回測系列一:技術(shù)信號(hào)回測

 量化貓 2020-12-11

本系列文章將會(huì)介紹如何使用DolphinDB進(jìn)行交易回測。本文以移動(dòng)平均線指標(biāo)為例,介紹如何在DolphinDB中實(shí)現(xiàn)技術(shù)信號(hào)回測。移動(dòng)平均線指標(biāo)(Moving average,簡稱MA)屬于趨勢指標(biāo)。在金融分析領(lǐng)域,移動(dòng)平均線是不可缺少的指標(biāo)工具。除了指示趨勢,均線指標(biāo)還能避免由于股價(jià)下跌錯(cuò)失清倉的機(jī)會(huì),減少收益的損失,及時(shí)止損,也能避免股價(jià)上漲錯(cuò)失買入的時(shí)機(jī),從而獲得更高的收益。

回測過程中,我們考慮兩種情況:不止損回測和止損回測。

數(shù)據(jù)表需要包含以下字段:

股票代碼:sym

日期:date

收盤價(jià)格:close

1. 定義MA信號(hào)

當(dāng)短期均線大于長期均線時(shí),我們認(rèn)為這是一個(gè)MA交易信號(hào)。

def maSignal(x, shortHorizon, longHorizon){
signal = mavg(x, shortHorizon) > mavg(x, longHorizon)
signal[0:min(x.size(), longHorizon - 1)] = NULL
return signal
}

2. 不止損回測

我們定義的交易算法如下:

假設(shè)前一天的MA信號(hào)為prevSignal,當(dāng)天的MA信號(hào)為signal。

(1)如果prevSignal=false,signal=true,那么買入多頭頭寸(long position)。

(2)如果prevSignal=true,signal=false,那么賣出空頭頭寸(short position)。

(3)如果不符合以上兩種情況,則保持與前一天相同的頭寸。

def backtest(t){
t2 = select sym,date,close,prev(close) as prevClose,signal, prev(signal) as prevSignal from t context by sym
update t2 set position=iif(prevSignal==false and signal==true, 1 ,iif(prevSignal==true and signal==false, -1, int())).prev().ffill() context by sym
return select sym,date,close,signal,position,position*(close - prevClose) as pnl from t2 where isValid(position)
}

DolphinDB函數(shù)說明:

iif(condition, trueResult, falseResult):如果滿足條件condition,則返回trueResult,否則返回falseResult。它相當(dāng)于if...else語句,但是語法上更加簡潔。

int():返回int類型的NULL值。

prev(x):把向量中的所有元素向右移動(dòng)一個(gè)位置。

ffill(x):使用NULL值前的非NULL元素填充向量中的NULL值。

isValid():檢查每個(gè)元素是否為NULL。如果為NULL,返回0,否則返回1。

backtest 函數(shù)說明:

回測時(shí)首先整理數(shù)據(jù),使用prev()函數(shù)把前一天的收盤價(jià)格prevClose和前一天的MA信號(hào)prevSignal與當(dāng)天的數(shù)據(jù)對(duì)齊,便于計(jì)算。

接著,按照我們定義的交易算法,計(jì)算每個(gè)股票的頭寸position。position=1表示買入,position=-1表示賣出,position=NULL表示保持不變。

最后,使用position*(close - prevClose)計(jì)算盈虧pnl。

3. 止損回測

3.1 判斷止損點(diǎn)

首先,定義函數(shù)stoploss判斷是否需要止損。該函數(shù)返回布爾類型的向量。

def stoploss(ret, threshold){
cumret = cumprod(1+ret)
drawDown = 1 - cumret / cumret.cummax()
firstCutIndex = at(drawDown >= threshold).first() + 1
indicator = take(false, ret.size())
if(isValid(firstCutIndex) and firstCutIndex < ret.size())
indicator[firstCutIndex:] = true
return indicator
}

DolphinDB內(nèi)置函數(shù)說明:

cumprod:計(jì)算累計(jì)乘積。

cummax:計(jì)算累計(jì)最大值。

at(x):x是布爾表達(dá)式,找出符合條件x的元素的位置。

first:返回第一個(gè)元素。

take(X, k):返回包含k個(gè)x的向量。

stoploss 函數(shù)說明:

首先計(jì)算累計(jì)回報(bào)率cumret,接著計(jì)算當(dāng)前回報(bào)率和累計(jì)最大回報(bào)率的回撤drawdown,當(dāng)回撤drawdown大于等于預(yù)設(shè)閾值threshold時(shí),則認(rèn)為應(yīng)當(dāng)止損,并記錄止損的起始位置firstCutIndex(由于到股市收盤時(shí)才知道是否需要止損或止盈,所以firstCutIndex要加1)。止損信號(hào)indicator的所有元素一開始設(shè)定為全是false。如果止損的起始位置firstCutIndex不為NULL,且不超過當(dāng)前的數(shù)據(jù)量,則把止損信號(hào)indicator中從firstCutIndex開始到最后的所有元素設(shè)為true,表示從firstCutIndex開始,都應(yīng)當(dāng)止損。

3.2 止損回測

回測時(shí),將止損前后的盈虧進(jìn)行對(duì)比 。

def backtest_stoploss(t, thresholdDrawDown){
t2 = select sym,date,close,prev(close) as prevClose,signal, prev(signal) as prevSignal from t context by sym
update t2 set position=iif(prevSignal==false and signal==true, 1 ,iif(prevSignal==true and signal==false, -1, int())).prev().ffill() context by sym
update t2 set pnl = position*(close - prevClose), ret = (close - prevClose)/prevClose
update t2 set stoplossInd = segmentby(stoploss{,thresholdDrawDown}, ret, position) context by sym
return select sym,date,close,signal,position,stoplossInd,pnl * stoplossInd as pnl, pnl as nostoplossPnl from t2 where isValid(position)
}

DolphinDB函數(shù)說明:

segmentby(func, funcArgs, segment):把funcArgs分成多個(gè)組,并把函數(shù)func應(yīng)用到每個(gè)組中。segment是一個(gè)向量,可以把它看作是分組方案,連續(xù)相同的元素為一組。通過下面的例子我們可以更好地理解segmentby:

x=1 2 3 0 3 2 1 4 5
y=1 1 1 -1 -1 -1 1 1 1
segmentby(cumsum,x,y)

1 3 6 0 3 5 1 5 10

上面的例子中,y定義了3個(gè)分組:1 1 1、-1 -1 -1 和1 1 1,第一個(gè)分組的index是0-2,第二個(gè)分組的index是3-5,第三個(gè)分組的index是6-9。按照這個(gè)規(guī)則把x分成3組:1 2 3、0 3 2、1 4 5,并在每個(gè)分組中計(jì)算累計(jì)和。

stoploss{, thresholdDrawDown}這種表達(dá)方式是定義一個(gè)部分應(yīng)用,用于固定stoploss的第二個(gè)參數(shù)thresholdDrawDown。

backtest_stoploss 函數(shù)說明:

前三行代碼和1.2大致相同,除了計(jì)算盈虧pnl之外,還計(jì)算了回報(bào)率ret,因?yàn)閟toploss函數(shù)需要ret作為輸入。接著把每個(gè)股票的回報(bào)率ret按階段分組(position中的元素連續(xù)多個(gè)1表示持續(xù)買入,連續(xù)多個(gè)-1表示持續(xù)賣出,連續(xù)多個(gè)NULL表示持續(xù)不變),在每個(gè)階段分組中判斷是否需要止損,為每只股票生成止損信號(hào)stoplossInd。最后計(jì)算止損前后的盈虧,止損前的盈虧為nostoplossPnl,止損后的盈虧為pnl。

4. 統(tǒng)計(jì)信息

通常情況下,我們還需要分析盈虧的統(tǒng)計(jì)信息。通過下面的自定義函數(shù)calcPerformance可以計(jì)算盈虧的統(tǒng)計(jì)信息,比如累計(jì)盈虧cumpnl、平均盈虧avgpnl、盈虧天數(shù)days、盈虧的標(biāo)準(zhǔn)差std、最大回撤maxDrawdown等。返回的數(shù)據(jù)類型是字典。

def calcPerformance(pnl){
result = dict(STRING, DOUBLE)
result[`cumpnl]= pnl.sum()
result[`avgpnl]= pnl.avg()
result[`days] = pnl.size()
result[`std]= pnl.std()
result[`maxDrawdown] = (pnl.cumsum().cummax() - pnl.cumsum()).max()
return result
}

5. 運(yùn)行實(shí)例

我們使用美國股市從1998年到2016年股票的每日交易信息作為數(shù)據(jù)集來進(jìn)行測試。數(shù)據(jù)集共包含3474萬條記錄。

//數(shù)據(jù)導(dǎo)入和數(shù)據(jù)處理,產(chǎn)生stock數(shù)據(jù)表,包含sym, date, close三個(gè)字段
...

//計(jì)算每個(gè)股票每天的MA信號(hào)
t = select sym,date,close,maSignal(close, 50, 100) as signal from stock context by sym

情況一:不止損回測

//不止損回測
positions = backtest(t)

//計(jì)算盈虧并繪制盈虧走勢圖
dailyPnl = select sum(pnl) as pnl from positions group by date order by date
calcPerformance(dailyPnl.pnl)
plot(dailyPnl.pnl.cumsum() as cumulativePnl, dailyPnl.date, 'Cumulative Pnl of All Stocks without Stop Loss Control')

//分析每只股票的盈虧信息
select calcPerformance(pnl) as `cumpnl`avgpnl`days`std`maxDrawdown from result group by sym

symcumpnlavgpnldaysstdmaxDrawdown
A48.750.01084,513.1.5895106.55
AA7.96250.00174,624.1.131119.75
...
不止損回測所有股票的盈虧走勢圖

情況二:止損回測。我們把預(yù)設(shè)閾值設(shè)為2.5%。

//止損回測
positions = backtst_stoploss(t,0.025)

//計(jì)算盈虧并繪制盈虧走勢圖
dailyPnl = select sum(pnl) as pnl from positions group by date order by date
calcPerformance(dailyPnl.pnl)
plot(dailyPnl.pnl.cumsum() as cumulativePnl, dailyPnl.date, 'Cumulative Pnl of All Stocks with Stop Loss Control')

//分析每只股票的盈虧信息
select calcPerformance(pnl) as `cumpnl`avgpnl`days`std`maxDrawdown from result group by sym

symcumpnlavgpnldaysstdmaxDrawdown
A58.27750.01294,513.1.5731102.125
AA20.470.00444,624.1.1126110.8125
...
止損回測所有股票的盈虧走勢圖

DolphinDB database 雖然是一個(gè)通用的分布式時(shí)序數(shù)據(jù)庫,但因?yàn)閮?nèi)置極其高效的多范式編程語言,開發(fā)效率非常高。如果回測不用考慮止損,僅用了3行代碼計(jì)算MA信號(hào),3行代碼進(jìn)行回測。DolphinDB的運(yùn)行效率更是驚人,對(duì)美國股市18年的全部股票按日進(jìn)行回測,不止損回測執(zhí)行耗時(shí)僅4秒多,止損回測僅7秒多。

本文的目的是從技術(shù)上幫助金融工程師使用DolphinDB快速實(shí)現(xiàn)交易回測。文中采用的各種參數(shù),譬如長短線時(shí)間,止損閾值,數(shù)據(jù)過濾的方法等等,只是起到演示的作用,并非實(shí)踐中的最佳參數(shù)。

歡迎訪問官網(wǎng)下載DolphinDB試用版

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    国产专区亚洲专区久久| 欧美精品日韩精品一区| 国产在线一区二区免费| 一区二区在线激情视频| 国产精品亚洲综合色区韩国| 国内午夜精品视频在线观看| 麻豆蜜桃星空传媒在线观看| 欧美日韩少妇精品专区性色| 欧美黑人在线精品极品| 国产一区二区三区精品免费| 亚洲视频在线观看你懂的| 国产精品成人一区二区三区夜夜夜 | 久久99一本色道亚洲精品| 中文字幕高清不卡一区| 福利在线午夜绝顶三级| 好吊妞视频这里有精品| 国产精品一区二区视频| 男女激情视频在线免费观看| 福利视频一区二区三区| 九九九热视频免费观看| 日本本亚洲三级在线播放| 色婷婷丁香激情五月天| 一区二区三区国产日韩| 好吊日视频这里都是精品| 精品熟女少妇av免费久久野外| 亚洲中文字幕在线乱码av| 中文字幕日产乱码一区二区| 在线观看免费无遮挡大尺度视频| 国产精品夜色一区二区三区不卡| 成人免费在线视频大香蕉| 五月婷婷六月丁香狠狠| 又大又长又粗又黄国产| 中国一区二区三区人妻| 精品国产av一区二区三区不卡蜜 | 精品熟女少妇一区二区三区| 欧美国产日本免费不卡| 五月婷婷缴情七月丁香| 国产午夜精品美女露脸视频| 大香蕉久草网一区二区三区| 欧美三级大黄片免费看| 国产精品不卡一区二区三区四区 |