生命不息,学习不止~
尊重原创,原帖地址(豆瓣-数据铺子):
感谢 数据铺子 的“构建基于R的交易系统”系列帖子。
--- faruto按
(2)基于quantstrat包的回测:单资产情况
现在可以结合quantstrat包和blotter包给出一个更好的量化策略回测。 首先做初始化,这里包括blotter包里边对金融工具和账户和组合的初始化,也包括quantstrat包对策略和指令的初始化。
下面以上一篇用过的faber策略为例。
library(quantstrat)
#
金融产品初始化
currency("RMB")
## [1]
"RMB"
stock("ZSYH", currency = "RMB", multiplier = 1)
## [1]
"ZSYH"
#
设定时区
Sys.setenv(TZ = "UTC")
#
读取金融交易数据并转化为月数据
ZSYH
getSymbols("600036.ss", from = "2008-01-01", to = Sys.Date(), src =
"yahoo",
auto.assign = FALSE)
## As of
0.4-0, 'getSymbols' uses env=parent.frame() and auto.assign=TRUE
by
##
default.
##
## This
behavior will be phased out in 0.5-0 when the call will default
to
## use
auto.assign=FALSE. getOption("getSymbols.env") and
##
getOptions("getSymbols.auto.assign") are now checked for
alternate
##
defaults
##
## This
message is shown once per session and may be disabled by
setting
##
options("getSymbols.warning4.0"=FALSE). See ?getSymbol for more
details
ZSYH
to.monthly(ZSYH, indexAt = "endof")
ZSYH$SMA10m
head(ZSYH$SMA10m)
##
SMA10m
##
2008-01-31 NA
##
2008-02-29 NA
##
2008-03-31 NA
##
2008-04-30 NA
##
2008-05-30 NA
##
2008-06-30 NA
#
初始化组合和账户
q.strategy
initPortf(q.strategy, "ZSYH", initDate =
"2007-12-31")
## [1]
"qFaber"
initAcct(q.strategy, portfolios = q.strategy, initDate =
"2007-12-31", initEq = 1e+06)
## [1]
"qFaber"
#
初始化指定和策略
initOrders(portfolio = q.strategy, initDate =
"2007-12-31")
strategy(q.strategy, store = TRUE)
ls(all =
T) #quantstrat创建了.strategy环境
## [1]
".blotter" ".strategy" "q.strategy" "ZSYH"
#
策略是什么呢?看一下
strategy
summary(strategy)
## Length
Class Mode
## name 1
-none- character
## assets
0 -none- NULL
##
indicators 0 -none- list
## signals
0 -none- list
## rules 1
-none- list
##
constraints 0 -none- NULL
## init 0
-none- list
## wrapup
0 -none- list
## call 3
-none- call
下面是quantstrat包的关键:加入指标、信号和规则。
#
加入一个指标,10月均线
add.indicator(strategy = q.strategy, name = "SMA",
arguments = list(x = quote(Cl(mktdata)),
n =
10), label = "SMA10")
## [1]
"qFaber"
#
加入信号,向上交叉10月线,向下交叉10月线
add.signal(q.strategy, name = "sigCrossover", arguments =
list(columns = c("Close",
"SMA10"), relationship = "gt"), label = "Cl.gt.SMA")
## [1]
"qFaber"
add.signal(q.strategy, name = "sigCrossover", arguments =
list(columns = c("Close",
"SMA10"), relationship = "lt"), label = "Cl.lt.SMA")
## [1]
"qFaber"
#
加入规则,买入规则和卖出规则
add.rule(q.strategy, name = "ruleSignal", arguments =
list(sigcol = "Cl.gt.SMA",
sigval = TRUE, orderqty = 900, ordertype = "market", orderside =
"long",
pricemethod = "market"), type = "enter", path.dep = TRUE) #
买入数量为900股
## [1]
"qFaber"
add.rule(q.strategy, name = "ruleSignal", arguments =
list(sigcol = "Cl.lt.SMA",
sigval = TRUE, orderqty = "all", ordertype = "market", orderside =
"long",
pricemethod = "market"), type = "exit", path.dep = TRUE)
## [1]
"qFaber"
#
此时的策略对象
summary(getStrategy(q.strategy))
## Length
Class Mode
## name 1
-none- character
## assets
0 -none- NULL
##
indicators 1 -none- list
## signals
2 -none- list
## rules 3
-none- list
##
constraints 0 -none- NULL
## init 0
-none- list
## wrapup
0 -none- list
## call 3
-none- call
现在的策略strategy中有1个指标,2种信号和相应的两个规则(买入、卖出)。
下面可以使用这个策略了。
out
applyStrategy(strategy = q.strategy, portfolios =
q.strategy)
## [1]
"2009-05-29 00:00:00 ZSYH 900 @ 12.97"
## [1]
"2010-01-29 00:00:00 ZSYH -900 @ 15.17"
## [1]
"2010-10-29 00:00:00 ZSYH 900 @ 14.57"
## [1]
"2010-11-30 00:00:00 ZSYH -900 @ 13.05"
## [1]
"2011-03-31 00:00:00 ZSYH 900 @ 14.09"
## [1]
"2011-06-30 00:00:00 ZSYH -900 @ 13.02"
## [1]
"2012-01-31 00:00:00 ZSYH 900 @ 12.65"
## [1]
"2012-03-30 00:00:00 ZSYH -900 @ 11.9"
## [1]
"2012-04-30 00:00:00 ZSYH 900 @ 12.2"
## [1]
"2012-05-31 00:00:00 ZSYH -900 @ 11.66"
## [1]
"2012-12-31 00:00:00 ZSYH 900 @ 13.75"
## [1]
"2013-06-28 00:00:00 ZSYH -900 @ 11.6"
summary(out)
## Length
Class Mode
## qFaber
1 -none- list
mktdata["2013"]
##
ZSYH.Open ZSYH.High ZSYH.Low ZSYH.Close ZSYH.Volume
##
2013-01-31 13.75 14.80 13.16 14.30 2.467e+09
##
2013-02-28 14.20 15.01 12.58 13.30 1.906e+09
##
2013-03-29 13.30 13.60 11.70 12.63 1.979e+09
##
2013-04-30 12.49 12.98 12.01 12.15 9.797e+08
##
2013-05-31 12.15 14.10 11.95 13.58 1.909e+09
##
2013-06-28 13.58 13.89 10.00 11.60 1.253e+09
##
2013-07-31 11.50 12.43 10.40 10.60 1.322e+09
##
2013-08-30 10.69 12.14 10.35 10.66 1.257e+09
##
2013-09-30 10.66 12.19 10.61 10.92 1.659e+09
##
2013-10-31 10.92 11.10 10.55 10.74 1.061e+09
##
2013-11-01 10.87 10.95 10.79 10.91 6.854e+07
##
ZSYH.Adjusted ZSYH.Close.SMA.10.SMA10 Cl.gt.SMA
Cl.lt.SMA
##
2013-01-31 13.68 11.31 NA NA
##
2013-02-28 12.73 11.42 NA NA
##
2013-03-29 12.09 11.52 NA NA
##
2013-04-30 11.63 11.64 NA NA
##
2013-05-31 13.00 12.00 NA NA
##
2013-06-28 11.60 12.16 NA 1
##
2013-07-31 10.60 12.20 NA NA
##
2013-08-30 10.66 12.26 NA NA
##
2013-09-30 10.92 12.35 NA NA
##
2013-10-31 10.74 12.05 NA NA
##
2013-11-01 10.91 11.71 NA NA
mktdata是在执行策略过程中创建的一个特殊的变量,包含了原交易数据的时间序列以及指标和信号。在我们上面的ZSYH里,在2013年6月出现一次卖出的信号。
接下来对相关对象(组合、账户和权益价值)进行更新。
updatePortf(q.strategy)
##
Warning: instrument USD not found, please create it first.
Warning:
##
CurrencyUSD not found, using currency multiplier of 1
## [1]
"qFaber"
updateAcct(q.strategy)
## [1]
"qFaber"
updateEndEq(q.strategy)
## [1]
"qFaber"
最后按照现在的组合和账户情况给出策略表现
myTheme
myTheme$col$dn.col
myTheme$col$up.col
myTheme$col$dn.border
myTheme$col$up.border
#
策略表现可视化
chart.Posn(q.strategy, Symbol = "ZSYH", Dates = "2008::",
theme = myTheme)
# 交易统计
(tstats
"ZSYH"))
##
Portfolio Symbol Num.Txns Num.Trades Net.Trading.PL
Avg.Trade.PL
## ZSYH
qFaber ZSYH 12 6 -3447 -574.5
##
Med.Trade.PL Largest.Winner Largest.Loser Gross.Profits
Gross.Losses
## ZSYH
-819 1980 -1935 1980 -5427
##
Std.Dev.Trade.PL Percent.Positive Percent.Negative
Profit.Factor
## ZSYH
1355 16.67 83.33 0.3648
##
Avg.Win.Trade Med.Win.Trade Avg.Losing.Trade
Med.Losing.Trade
## ZSYH
1980 1980 -1085 -963
##
Avg.Daily.PL Med.Daily.PL Std.Dev.Daily.PL Max.Drawdown
## ZSYH
-574.5 -819 1355 -9450
##
Profit.To.Max.Draw Avg.WinLoss.Ratio Med.WinLoss.Ratio
Max.Equity
## ZSYH
-0.3648 1.824 2.056 6003
##
Min.Equity End.Equity
## ZSYH
-3447 -3447
#
指令簿(order
book)
ob
getOrderBook(q.strategy)
head(ob$qFaber$ZSYH)
##
Order.Qty Order.Price Order.Type Order.Side
Order.Threshold
##
2009-05-29 "900" "12.97" "market" "long" NA
##
2010-01-29 "all" "15.17" "market" "long" NA
##
2010-10-29 "900" "14.57" "market" "long" NA
##
2010-11-30 "all" "13.05" "market" "long" NA
##
2011-03-31 "900" "14.09" "market" "long" NA
##
2011-06-30 "all" "13.02" "market" "long" NA
##
Order.Status Order.StatusTime Prefer Order.Set Txn.Fees
##
2009-05-29 "closed" "2009-06-30 00:00:00" "" NA "0"
##
2010-01-29 "closed" "2010-02-26 00:00:00" "" NA "0"
##
2010-10-29 "closed" "2010-11-30 00:00:00" "" NA "0"
##
2010-11-30 "closed" "2010-12-31 00:00:00" "" NA "0"
##
2011-03-31 "closed" "2011-04-29 00:00:00" "" NA "0"
##
2011-06-30 "closed" "2011-07-29 00:00:00" "" NA "0"
##
Rule
##
2009-05-29 "ruleSignal.rule"
##
2010-01-29 "ruleSignal.rule"
##
2010-10-29 "ruleSignal.rule"
##
2010-11-30 "ruleSignal.rule"
##
2011-03-31 "ruleSignal.rule"
##
2011-06-30 "ruleSignal.rule"
quantstrat包给出了MAE(maximum adverse
excursion)和MFE(maximum favorable
excursion)的图形
chart.ME(Portfolio = q.strategy, Symbol = "ZSYH", type =
"MAE", scale = "percent")
chart.ME(Portfolio = q.strategy, Symbol = "ZSYH", type =
"MFE", scale = "percent")
和上一篇blooter里同一个策略的回测过程作比较,quantstrat包的特点是在很大程度上标准化了交易的策略实现,把策略分解为指标、信号和规则这三个部分。对于基于技术交易指标构造的量化策略来说,这种标准化当然是很方便的。特别是需要自己构造复杂的交易策略的时候。只要把注意力集中于策略本身就可以了。
当然,blotter包和quantstrat依然有很多使用上的不方便(我这里把运行时的各种警告都忽略了,呵呵)的地方。所以我想了解或者学习这些工具更重要的意义在于:他山之石,可以攻玉。借鉴别人的工作,丰富自己的工作。
下一篇继续写quantstrat,多资产的回测。