一廊镜、R代碼實(shí)現(xiàn)鞠鲜。
用google在網(wǎng)上搜索到的回測(cè)語(yǔ)句都大同小異户辫,下面給出一個(gè)示例,改編自:量化策略回測(cè):
# 以S&P500為例箍镜,其雅虎代碼為^GSPC源祈;我們要計(jì)算5日均線指標(biāo)的函數(shù)就是SMA(),
# 先載入需要的擴(kuò)展包
> library(quantmod)
> library(PerformanceAnalytics)
# 先獲取S&P500的交易數(shù)據(jù)色迂,然后根據(jù)其收盤價(jià)(由函數(shù)Cl()抽认闳薄)計(jì)算其5日均線值:
> getSymbols('^GSPC') #S&P500 OHLC data
> close <- Cl(GSPC)
> mv5 <- SMA(close, 5)
# 策略是當(dāng)收盤價(jià)大于5日均線,代表可以入市歇僧,取1图张,否則代表清倉(cāng),取0诈悍。(-1是代表賣空祸轮,不適用。)
> sig <- ifelse(close < mv5, 1, 0)
# 使用Lag()將信號(hào)序列向“過(guò)去”推遲一天侥钳,代表將昨天的信號(hào)适袜,應(yīng)用到今天。
> sig <- Lag(sig) #將該序列向“過(guò)去”延遲一天
# 計(jì)算收益序列
# discrete代表用離散方式計(jì)算當(dāng)天收益率舷夺,即(Close-Close(-1))/Close(-1)
# continous代表用連續(xù)方式計(jì)算當(dāng)天收益率苦酱,即ln(Close/Close(-1))
> roc <- ROC(type='discrete',close)
> ret <- roc * sig
# 畫出策略收益圖
> charts.PerformanceSummary(ret)
# 最上面的板塊是積累收益,相當(dāng)于對(duì)cumprod(1+ret)的繪圖给猾;
# 第二個(gè)是日收益疫萤,相當(dāng)于對(duì)ret原始收益數(shù)據(jù)的繪圖;
# 最下面的是下跌圖(又稱“水下圖”)敢伸,將下跌成分獨(dú)立繪出扯饶,有助于我們分析虧損狀況和研究彌補(bǔ)措施。
以上需要注意的地方是制定策略的語(yǔ)句
> sig <- ifelse(close < mv5, 1, 0)
# 當(dāng)收盤價(jià)大于5日均線時(shí),sig取1帝际,否則取0。
在網(wǎng)上公布的代碼當(dāng)中饶辙,有的是取-1蹲诀,這里-1代表賣空,不是清倉(cāng)弃揽,得到的結(jié)果是不對(duì)的脯爪。
二、excel模擬矿微。
當(dāng)初得到這個(gè)結(jié)果的時(shí)候我很懷疑痕慢,用幾條R語(yǔ)句就把量化策略及結(jié)果模擬出來(lái)了?看上去這么神奇涌矢,結(jié)果對(duì)不對(duì)呢掖举?我在excel里對(duì)該策略進(jìn)行模擬:
以上面的策略為基礎(chǔ),細(xì)化得到的交易方案是這樣的:
- 當(dāng)股票收盤價(jià)格高于五日均線娜庇,且無(wú)持倉(cāng)塔次,那么第二天滿倉(cāng)入市。
- 當(dāng)股票收盤價(jià)格高于五日均線名秀,且滿倉(cāng)励负,那么第二天繼續(xù)持倉(cāng)。
- 當(dāng)股票收盤價(jià)格低于五日均線匕得,且無(wú)持倉(cāng)继榆,那么第二天繼續(xù)空倉(cāng)。
- 當(dāng)股票收盤價(jià)格低于五日均線汁掠,且滿倉(cāng)略吨,那么第二天全部平倉(cāng)。
為了簡(jiǎn)化計(jì)算考阱,假設(shè)以前一天的收盤價(jià)作為成交價(jià):即以前一天的收盤價(jià)滿倉(cāng)入市晋南,或以前一天的收盤價(jià)全部平倉(cāng)。當(dāng)然這可以在進(jìn)一步的研究中細(xì)化羔砾,但這里我們只是為了演示负间,就不過(guò)于復(fù)雜了。
excel表格里得到的結(jié)果如下:
CLOSE | SMA | sig | ROC | ROC*sig | 股票 | 現(xiàn)金 | 總收益 | |
---|---|---|---|---|---|---|---|---|
1994-1-3 | 5.6 | 0 | 1 | 1 | ||||
1994-1-4 | 5.55 | 0 | 1 | 1 | ||||
1994-1-5 | 5.65 | 0 | 1 | 1 | ||||
1994-1-6 | 6.1 | 0 | 1 | 1 | ||||
1994-1-7 | 6.25 | 5.83 | 0 | 1 | 1 | |||
1994-1-10 | 6.45 | 6 | 1 | 0.032 | 0.032 | 1.032 | 0 | 1.032 |
1994-1-11 | 6.15 | 6.12 | 1 | -0.047 | -0.047 | 0.984 | 0 | 0.984 |
1994-1-12 | 6.15 | 6.22 | 1 | 0 | 0 | 0.984 | 0 | 0.984 |
1994-1-13 | 6.25 | 6.25 | 0 | 0.016 | 0 | 0 | 0.984 | 0.984 |
1994-1-14 | 6.1 | 6.22 | 0 | -0.024 | 0 | 0 | 0.984 | 0.984 |
1994-1-17 | 6 | 6.13 | 0 | -0.016 | 0 | 0 | 0.984 | 0.984 |
1994-1-18 | 6.2 | 6.14 | 0 | 0.033 | 0 | 0 | 0.984 | 0.984 |
1994-1-19 | 6 | 6.11 | 1 | -0.032 | -0.032 | 0.952 | 0 | 0.952 |
1994-1-20 | 6 | 6.06 | 0 | 0 | 0 | 0 | 0.952 | 0.952 |
由于是取5日平均姜凄,所以5日平均值SMA從第5個(gè)交易日開始出現(xiàn)政溃。這幾天的資產(chǎn)都是現(xiàn)金,總收益為1态秧。
從第6個(gè)交易日開始董虱,通過(guò)判斷收盤價(jià)與5日均線之間的大小,得到交易信號(hào)sig,注意愤诱,這里的sig是滯后一日的云头,代表前一天的收盤價(jià)與5日均線之間的相對(duì)大小。
1994-1-10 close>SMA淫半,sig=1溃槐,以前一天的收盤價(jià)6.25滿倉(cāng)入市,當(dāng)天收盤價(jià)為6.45科吭,日內(nèi)收益率為0.032昏滴,股票價(jià)值1.032,現(xiàn)金為0对人,總資產(chǎn)價(jià)值為1.032谣殊。
1994-1-11 close>SMA,sig=1牺弄,鑒于前一天已入市姻几,繼續(xù)持倉(cāng),當(dāng)天收盤價(jià)為6.15势告,日內(nèi)收益率為-0.047鲜棠,股票價(jià)值0.984,現(xiàn)金為0培慌,總資產(chǎn)價(jià)值為0.984豁陆。
1994-1-12 close>SMA,sig=1吵护,繼續(xù)持倉(cāng)盒音,當(dāng)天收盤價(jià)為6.15,日內(nèi)收益率為0馅而,股票價(jià)值0.984祥诽,現(xiàn)金為0,總資產(chǎn)價(jià)值為0.984瓮恭。
1994-1-13 close<SMA雄坪,sig=0,以前一天的收盤價(jià)6.15全部清倉(cāng)屯蹦,股票價(jià)值為0维哈,現(xiàn)金為前一天的股票價(jià)值0.984,總資產(chǎn)價(jià)值為0.984登澜。
此時(shí)阔挠,經(jīng)歷了一次持倉(cāng)以及清倉(cāng)之后,投資者手里只擁有現(xiàn)金資產(chǎn)脑蠕,總資產(chǎn)價(jià)值為0.984购撼,虧損0.016跪削。
通過(guò)對(duì)比excel計(jì)算的ret(ROC*sig)與R代碼計(jì)算的ret,兩者的結(jié)果完全一致迂求。
通過(guò)用excel對(duì)以上回測(cè)策略的模擬碾盐,可以發(fā)現(xiàn)以上回測(cè)策略的隱含前提:
(1) 入市價(jià)格和清倉(cāng)價(jià)格均為前一天的收盤價(jià)。
(2) 入市則全部滿倉(cāng)揩局,離市則全部清倉(cāng)毫玖。
三、神秘的charts.PerformanceSummary()函數(shù)谐腰。
在R代碼中孕豹,一條charts.PerformanceSummary()語(yǔ)句涩盾,畫出在該策略下十气,對(duì)應(yīng)股票的總資產(chǎn)收益,日收益和下跌圖春霍。它就像一個(gè)神奇的黑箱砸西,給我們以策略是否有效以最直觀的圖形表示。但光有圖形還不夠址儒,這三條曲線分別對(duì)應(yīng)哪些數(shù)據(jù)芹枷,能不能分別導(dǎo)出方便進(jìn)一步研究呢?
-
總資產(chǎn)收益莲趣。
對(duì)應(yīng)的是excle表格當(dāng)中的總收益鸳慈,直觀表示了應(yīng)用該策略,投資者總資產(chǎn)在回測(cè)時(shí)間內(nèi)的增減情況喧伞。雖然在excel模擬中用股票走芋、現(xiàn)金、總資產(chǎn)三個(gè)條目來(lái)代表潘鲫,但其實(shí)用一條R代碼就可以實(shí)現(xiàn)了:
cumprod(1+ret)
也就是對(duì)(1+ret)的連乘翁逞。很容易理解:假設(shè)到了第n天,那么這一天的總收益Rn應(yīng)該等于前一天的總收益R(n-1)乘以當(dāng)天的收益率溉仑,不是ret挖函,而應(yīng)當(dāng)是(1+ret)。
R代碼得到的結(jié)果與excel是一致的浊竟。
-
日收益怨喘。
就是R代碼當(dāng)中的ret和excel表格中的ROC*sig。
-
下跌圖(這部分參考了R包計(jì)算回撤)振定。
這里只是將下跌成分獨(dú)立繪出哲思,對(duì)應(yīng)的excel數(shù)據(jù)也是ROC*sig,但這里的下跌圖經(jīng)過(guò)了整理吩案。對(duì)應(yīng)的R函數(shù)有:
a)chart.Drawdown:下跌圖棚赔,也就是charts.PerformanceSummary()的第三張圖。
data(edhec) chart.Drawdown(edhec[,c(1,2)], main="Drawdown from Peak Equity Attained", legend.loc="bottomleft")
b)findDrawdowns:返回回撤的起始時(shí)間,時(shí)間間隔靠益,回撤數(shù)值丧肴,常與sortDrawdowns連用找最大回撤。
data(edhec) findDrawdowns(edhec[,"Funds of Funds", drop=FALSE]) sortDrawdowns(findDrawdowns(edhec[,"Funds of Funds", drop=FALSE]))
c)maxDrawdown:返回收益時(shí)間序列的最大回撤胧后。
data(edhec) t(round(maxDrawdown(edhec[,"Funds of Funds"]),4))
d)table.Drawdowns:返回最差回撤的統(tǒng)計(jì)量表格芋浮。
data(edhec) table.Drawdowns(edhec[,1,drop=FALSE])