17 min read

五分钟搞定 SMA 指标的量化策略开发和回测

常有人问我能用几分钟时间写一段代码进行一个简易的量化投资策略的开发和回测吗,答案是当然可以。对于量化投资而言,门槛永远不是编程和代码,而是投资思路和模型解读。下面我们用五分钟左右的时间来开发一个基于 SMA 指标的量化投资策略并进行回测。

引言

本文的代码基于R软件和 Rstuido 软件运行,如果未安装上述软件,请自行安装。

策略开发还需要基于以下 R 包来实现,可以运行如下代码安装并加载相关 R 包。

# 安装依赖包,如果未安装
install.packages(c("quantstrat", "Tushare", "xts", "dplyr", "showtext", "zoo","PerformanceAnalytics","tidyverse"))
# 加载软件包
suppressMessages({
  library(quantmod)
  library(quantstrat)
  library(PerformanceAnalytics)
  library(Tushare)
  library(xts)
  library(dplyr)
  library(zoo)
  library(tidyverse)
})

清理环境

第一步,先清理历史环境,避免历史环境的干扰。

# 清理历史环境
rm(list=ls(.blotter), envir=.blotter)
rm(list=ls(.strategy), envir=.strategy)

策略开发

下面进入正式开发流程。

初始化设置

# 参数设置
initDate <- "2009-12-31"
fromDate <- "2010-01-01"
endDate <- Sys.Date()
symbol <- "600519.SS"
initEq <- 100000
fastMA <- 5
slowMA <- 20

获取数据

使用quantmod获取贵州茅台数据

# 获取数据
getSymbols(symbol, from=fromDate, to=endDate, src="yahoo")
## [1] "600519.SS"
maotai <- `600519.SS`
colnames(maotai) <- c("Open","High","Low","Close","Volume","Adjusted")

初始化策略

currency("RMB")
## [1] "RMB"
stock(symbol, currency="RMB", multiplier=1)
## [1] "X600519.SS"
strategy.st <- "maotai_sma"
portfolio.st <- "maotai_portfolio"
account.st <- "maotai_account"

# 清除旧策略(如果存在)
if(exists("strategy.st", where=.strategy)) {
  rm.strat(strategy.st)
}

# 创建组合/账户/策略
initPortf(portfolio.st, symbols=symbol, initDate=initDate)
## [1] "maotai_portfolio"
initAcct(account.st, portfolios=portfolio.st, initDate=initDate, initEq=initEq)
## [1] "maotai_account"
initOrders(portfolio.st, initDate=initDate)
strategy(strategy.st, store=TRUE)

添加指标

这里添加的简单移动平均线(SMA):

# 添加指标
add.indicator(
  strategy.st,
  name="SMA",
  arguments=list(x=quote(Cl(mktdata)), n=fastMA),
  label="fastMA"
)
## [1] "maotai_sma"
add.indicator(
  strategy.st,
  name="SMA",
  arguments=list(x=quote(Cl(mktdata)), n=slowMA),
  label="slowMA"
)
## [1] "maotai_sma"

添加信号 - 金叉死叉

# 添加信号
add.signal(
  strategy.st,
  name="sigCrossover",
  arguments=list(columns=c("fastMA","slowMA"), relationship="gt"),
  label="fast.gt.slow"
)
## [1] "maotai_sma"
add.signal(
  strategy.st,
  name="sigCrossover",
  arguments=list(columns=c("fastMA","slowMA"), relationship="lt"),
  label="fast.lt.slow"
)
## [1] "maotai_sma"

添加交易规则

add.rule(
  strategy.st,
  name="ruleSignal",
  arguments=list(
    sigcol="fast.gt.slow",
    sigval=TRUE,
    orderqty=100,
    ordertype="market",
    orderside="long",
    replace=FALSE
  ),
  type="enter",
  label="EnterLONG"
)
## [1] "maotai_sma"
add.rule(
  strategy.st,
  name="ruleSignal",
  arguments=list(
    sigcol="fast.lt.slow",
    sigval=TRUE,
    orderqty="all",
    ordertype="market",
    orderside="long",
    replace=FALSE
  ),
  type="exit",
  label="ExitLONG"
)
## [1] "maotai_sma"

策略回测

applyStrategy(strategy.st, 
              portfolios=portfolio.st)
## [1] "2010-05-25 00:00:00 600519.SS 100 @ 98.6100692749023"
## [1] "2010-06-01 00:00:00 600519.SS -100 @ 99.6468811035156"
## [1] "2010-06-03 00:00:00 600519.SS 100 @ 101.450035095215"
## [1] "2010-06-23 00:00:00 600519.SS -100 @ 98.9481582641602"
## [1] "2010-07-15 00:00:00 600519.SS 100 @ 99.0458297729492"
## [1] "2010-10-15 00:00:00 600519.SS -100 @ 120.195343017578"
## [1] "2010-10-25 00:00:00 600519.SS 100 @ 129.977462768555"
## [1] "2010-11-02 00:00:00 600519.SS -100 @ 122.216377258301"
## [1] "2010-11-11 00:00:00 600519.SS 100 @ 132.171295166016"
## [1] "2010-12-23 00:00:00 600519.SS -100 @ 143.283248901367"
## [1] "2011-02-11 00:00:00 600519.SS 100 @ 138.940643310547"
## [1] "2011-03-02 00:00:00 600519.SS -100 @ 133.140487670898"
## [1] "2011-03-16 00:00:00 600519.SS 100 @ 136.619079589844"
## [1] "2011-03-31 00:00:00 600519.SS -100 @ 135.123962402344"
## [1] "2011-04-27 00:00:00 600519.SS 100 @ 136.100677490234"
## [1] "2011-08-25 00:00:00 600519.SS -100 @ 171.421493530273"
## [1] "2011-08-29 00:00:00 600519.SS 100 @ 177.909088134766"
## [1] "2011-09-07 00:00:00 600519.SS -100 @ 171.561981201172"
## [1] "2011-10-20 00:00:00 600519.SS 100 @ 157.933883666992"
## [1] "2011-11-18 00:00:00 600519.SS -100 @ 165.760330200195"
## [1] "2011-11-28 00:00:00 600519.SS 100 @ 176.752059936523"
## [1] "2011-12-09 00:00:00 600519.SS -100 @ 165.140487670898"
## [1] "2012-02-07 00:00:00 600519.SS 100 @ 153.603302001953"
## [1] "2012-04-06 00:00:00 600519.SS -100 @ 171.876037597656"
## [1] "2012-04-10 00:00:00 600519.SS 100 @ 171.991729736328"
## [1] "2012-05-21 00:00:00 600519.SS -100 @ 184.454544067383"
## [1] "2012-06-01 00:00:00 600519.SS 100 @ 198.652893066406"
## [1] "2012-06-29 00:00:00 600519.SS -100 @ 197.644622802734"
## [1] "2012-07-04 00:00:00 600519.SS 100 @ 213.768600463867"
## [1] "2012-07-24 00:00:00 600519.SS -100 @ 206.099166870117"
## [1] "2012-08-10 00:00:00 600519.SS 100 @ 205.132232666016"
## [1] "2012-08-17 00:00:00 600519.SS -100 @ 189.768600463867"
## [1] "2012-09-10 00:00:00 600519.SS 100 @ 199.735534667969"
## [1] "2012-09-26 00:00:00 600519.SS -100 @ 194.933883666992"
## [1] "2012-09-28 00:00:00 600519.SS 100 @ 203.140487670898"
## [1] "2012-10-30 00:00:00 600519.SS -100 @ 202.132232666016"
## [1] "2012-11-05 00:00:00 600519.SS 100 @ 200.760330200195"
## [1] "2012-11-07 00:00:00 600519.SS -100 @ 196.256195068359"
## [1] "2012-12-19 00:00:00 600519.SS 100 @ 181.363632202148"
## [1] "2013-01-17 00:00:00 600519.SS -100 @ 169.528930664062"
## [1] "2013-03-12 00:00:00 600519.SS 100 @ 150.561981201172"
## [1] "2013-03-19 00:00:00 600519.SS -100 @ 136.512390136719"
## [1] "2013-04-16 00:00:00 600519.SS 100 @ 143.107437133789"
## [1] "2013-06-17 00:00:00 600519.SS -100 @ 156.59504699707"
## [1] "2013-07-04 00:00:00 600519.SS 100 @ 162.495864868164"
## [1] "2013-07-16 00:00:00 600519.SS -100 @ 157.809921264648"
## [1] "2013-08-14 00:00:00 600519.SS 100 @ 147.677688598633"
## [1] "2013-08-23 00:00:00 600519.SS -100 @ 142.966949462891"
## [1] "2013-10-18 00:00:00 600519.SS 100 @ 118.16529083252"
## [1] "2013-10-30 00:00:00 600519.SS -100 @ 109.578514099121"
## [1] "2013-11-13 00:00:00 600519.SS 100 @ 119.603302001953"
## [1] "2013-11-28 00:00:00 600519.SS -100 @ 117.214874267578"
## [1] "2013-12-02 00:00:00 600519.SS 100 @ 113.041320800781"
## [1] "2013-12-03 00:00:00 600519.SS -100 @ 113.702476501465"
## [1] "2014-01-23 00:00:00 600519.SS 100 @ 110.818183898926"
## [1] "2014-03-31 00:00:00 600519.SS -100 @ 127.85124206543"
## [1] "2014-04-09 00:00:00 600519.SS 100 @ 135"
## [1] "2014-04-30 00:00:00 600519.SS -100 @ 135.438018798828"
## [1] "2014-06-11 00:00:00 600519.SS 100 @ 127.223136901855"
## [1] "2014-08-14 00:00:00 600519.SS -100 @ 146.781814575195"
## [1] "2014-09-05 00:00:00 600519.SS 100 @ 152.281814575195"
## [1] "2014-09-18 00:00:00 600519.SS -100 @ 144.772720336914"
## [1] "2014-10-08 00:00:00 600519.SS 100 @ 146.118179321289"
## [1] "2014-10-13 00:00:00 600519.SS -100 @ 141.909088134766"
## [1] "2014-11-18 00:00:00 600519.SS 100 @ 141.5"
## [1] "2014-11-25 00:00:00 600519.SS -100 @ 140.581817626953"
## [1] "2014-11-27 00:00:00 600519.SS 100 @ 142.43635559082"
## [1] "2015-01-16 00:00:00 600519.SS -100 @ 169.190902709961"
## [1] "2015-02-12 00:00:00 600519.SS 100 @ 166.881820678711"
## [1] "2015-05-19 00:00:00 600519.SS -100 @ 227.309097290039"
## [1] "2015-05-25 00:00:00 600519.SS 100 @ 260.754547119141"
## [1] "2015-06-09 00:00:00 600519.SS -100 @ 235.481811523438"
## [1] "2015-07-07 00:00:00 600519.SS 100 @ 221.981811523438"
## [1] "2015-07-08 00:00:00 600519.SS -100 @ 215.327270507812"
## [1] "2015-07-14 00:00:00 600519.SS 100 @ 226.409088134766"
## [1] "2015-07-21 00:00:00 600519.SS -100 @ 221.660003662109"
## [1] "2015-09-15 00:00:00 600519.SS 100 @ 202"
## [1] "2015-09-29 00:00:00 600519.SS -100 @ 190.169998168945"
## [1] "2015-10-15 00:00:00 600519.SS 100 @ 199.990005493164"
## [1] "2015-11-20 00:00:00 600519.SS -100 @ 213.720001220703"
## [1] "2015-12-07 00:00:00 600519.SS 100 @ 214.509994506836"
## [1] "2015-12-11 00:00:00 600519.SS -100 @ 211.410003662109"
## [1] "2015-12-21 00:00:00 600519.SS 100 @ 227.029998779297"
## [1] "2016-01-05 00:00:00 600519.SS -100 @ 212.820007324219"
## [1] "2016-02-05 00:00:00 600519.SS 100 @ 203.869995117188"
## [1] "2016-04-18 00:00:00 600519.SS -100 @ 243.679992675781"
## [1] "2016-05-03 00:00:00 600519.SS 100 @ 260"
## [1] "2016-05-20 00:00:00 600519.SS -100 @ 251.259994506836"
## [1] "2016-05-27 00:00:00 600519.SS 100 @ 252.440002441406"
## [1] "2016-08-03 00:00:00 600519.SS -100 @ 306.820007324219"
## [1] "2016-08-12 00:00:00 600519.SS 100 @ 316.970001220703"
## [1] "2016-08-22 00:00:00 600519.SS -100 @ 307.320007324219"
## [1] "2016-10-13 00:00:00 600519.SS 100 @ 303.890014648438"
## [1] "2016-11-18 00:00:00 600519.SS -100 @ 310"
## [1] "2016-11-29 00:00:00 600519.SS 100 @ 323.959991455078"
## [1] "2016-12-26 00:00:00 600519.SS -100 @ 324.480010986328"
## [1] "2017-01-04 00:00:00 600519.SS 100 @ 351.910003662109"
## [1] "2017-02-07 00:00:00 600519.SS -100 @ 343.579986572266"
## [1] "2017-02-16 00:00:00 600519.SS 100 @ 348.089996337891"
## [1] "2017-07-05 00:00:00 600519.SS -100 @ 460.130004882812"
## [1] "2017-07-25 00:00:00 600519.SS 100 @ 477.959991455078"
## [1] "2017-09-07 00:00:00 600519.SS -100 @ 481.269989013672"
## [1] "2017-09-19 00:00:00 600519.SS 100 @ 496.950012207031"
## [1] "2017-11-27 00:00:00 600519.SS -100 @ 621.289978027344"
## [1] "2017-12-15 00:00:00 600519.SS 100 @ 653.789978027344"
## [1] "2018-01-31 00:00:00 600519.SS -100 @ 764.539978027344"
## [1] "2018-02-28 00:00:00 600519.SS 100 @ 725.619995117188"
## [1] "2018-03-14 00:00:00 600519.SS -100 @ 726.880004882812"
## [1] "2018-03-15 00:00:00 600519.SS 100 @ 746.469970703125"
## [1] "2018-03-27 00:00:00 600519.SS -100 @ 714.739990234375"
## [1] "2018-05-10 00:00:00 600519.SS 100 @ 714.190002441406"
## [1] "2018-06-25 00:00:00 600519.SS -100 @ 765.559997558594"
## [1] "2018-07-17 00:00:00 600519.SS 100 @ 742.429992675781"
## [1] "2018-08-02 00:00:00 600519.SS -100 @ 695.840026855469"
## [1] "2018-08-30 00:00:00 600519.SS 100 @ 680.400024414062"
## [1] "2018-09-06 00:00:00 600519.SS -100 @ 644"
## [1] "2018-09-21 00:00:00 600519.SS 100 @ 700.010009765625"
## [1] "2018-10-16 00:00:00 600519.SS -100 @ 667.140014648438"
## [1] "2018-12-04 00:00:00 600519.SS 100 @ 602.22998046875"
## [1] "2018-12-24 00:00:00 600519.SS -100 @ 568"
## [1] "2019-01-07 00:00:00 600519.SS 100 @ 605.489990234375"
## [1] "2019-05-09 00:00:00 600519.SS -100 @ 858.809997558594"
## [1] "2019-06-03 00:00:00 600519.SS 100 @ 892"
## [1] "2019-06-06 00:00:00 600519.SS -100 @ 862.130004882812"
## [1] "2019-06-14 00:00:00 600519.SS 100 @ 913"
## [1] "2019-07-16 00:00:00 600519.SS -100 @ 968"
## [1] "2019-08-01 00:00:00 600519.SS 100 @ 959.299987792969"
## [1] "2019-08-06 00:00:00 600519.SS -100 @ 946.299987792969"
## [1] "2019-08-13 00:00:00 600519.SS 100 @ 1017.95001220703"
## [1] "2019-09-17 00:00:00 600519.SS -100 @ 1094.01000976562"
## [1] "2019-09-23 00:00:00 600519.SS 100 @ 1149"
## [1] "2019-10-25 00:00:00 600519.SS -100 @ 1171.34997558594"
## [1] "2019-10-31 00:00:00 600519.SS 100 @ 1180.01000976562"
## [1] "2019-11-27 00:00:00 600519.SS -100 @ 1189.94995117188"
## [1] "2019-12-20 00:00:00 600519.SS 100 @ 1146.30004882812"
## [1] "2019-12-26 00:00:00 600519.SS -100 @ 1135.09997558594"
## [1] "2019-12-31 00:00:00 600519.SS 100 @ 1183"
## [1] "2020-01-06 00:00:00 600519.SS -100 @ 1077.98999023438"
## [1] "2020-02-14 00:00:00 600519.SS 100 @ 1088"
## [1] "2020-03-02 00:00:00 600519.SS -100 @ 1086.01000976562"
## [1] "2020-03-05 00:00:00 600519.SS 100 @ 1171"
## [1] "2020-03-18 00:00:00 600519.SS -100 @ 1007.98999023438"
## [1] "2020-04-03 00:00:00 600519.SS 100 @ 1139.7900390625"
## [1] "2020-07-29 00:00:00 600519.SS -100 @ 1672"
## [1] "2020-08-19 00:00:00 600519.SS 100 @ 1687"
## [1] "2020-09-11 00:00:00 600519.SS -100 @ 1733"
## [1] "2020-09-17 00:00:00 600519.SS 100 @ 1670.52001953125"
## [1] "2020-09-18 00:00:00 600519.SS -100 @ 1695"
## [1] "2020-10-14 00:00:00 600519.SS 100 @ 1729"
## [1] "2020-10-29 00:00:00 600519.SS -100 @ 1676"
## [1] "2020-11-10 00:00:00 600519.SS 100 @ 1745"
## [1] "2021-03-01 00:00:00 600519.SS -100 @ 2158"
## [1] "2021-04-01 00:00:00 600519.SS 100 @ 2044.5"
## [1] "2021-04-15 00:00:00 600519.SS -100 @ 2015.59997558594"
## [1] "2021-04-20 00:00:00 600519.SS 100 @ 2094.80004882812"
## [1] "2021-05-06 00:00:00 600519.SS -100 @ 1959"
## [1] "2021-05-20 00:00:00 600519.SS 100 @ 2058.8798828125"
## [1] "2021-06-18 00:00:00 600519.SS -100 @ 2090.93994140625"
## [1] "2021-09-08 00:00:00 600519.SS 100 @ 1633.09997558594"
## [1] "2021-11-01 00:00:00 600519.SS -100 @ 1803"
## [1] "2021-11-23 00:00:00 600519.SS 100 @ 1896.43005371094"
## [1] "2022-01-05 00:00:00 600519.SS -100 @ 2024"
## [1] "2022-01-28 00:00:00 600519.SS 100 @ 1887"
## [1] "2022-02-07 00:00:00 600519.SS -100 @ 1867.9599609375"
## [1] "2022-04-07 00:00:00 600519.SS 100 @ 1765"
## [1] "2022-04-28 00:00:00 600519.SS -100 @ 1835"
## [1] "2022-05-05 00:00:00 600519.SS 100 @ 1837"
## [1] "2022-05-13 00:00:00 600519.SS -100 @ 1778.23999023438"
## [1] "2022-06-02 00:00:00 600519.SS 100 @ 1786"
## [1] "2022-07-14 00:00:00 600519.SS -100 @ 1953"
## [1] "2022-08-18 00:00:00 600519.SS 100 @ 1895.5"
## [1] "2022-08-23 00:00:00 600519.SS -100 @ 1870.01000976562"
## [1] "2022-09-20 00:00:00 600519.SS 100 @ 1878"
## [1] "2022-09-23 00:00:00 600519.SS -100 @ 1834.43005371094"
## [1] "2022-09-30 00:00:00 600519.SS 100 @ 1872.5"
## [1] "2022-10-12 00:00:00 600519.SS -100 @ 1760"
## [1] "2022-11-16 00:00:00 600519.SS 100 @ 1585.25"
## [1] "2023-01-03 00:00:00 600519.SS -100 @ 1730.01000976562"
## [1] "2023-01-09 00:00:00 600519.SS 100 @ 1841.19995117188"
## [1] "2023-02-07 00:00:00 600519.SS -100 @ 1797"
## [1] "2023-02-21 00:00:00 600519.SS 100 @ 1867"
## [1] "2023-02-28 00:00:00 600519.SS -100 @ 1813.73999023438"
## [1] "2023-03-30 00:00:00 600519.SS 100 @ 1800"
## [1] "2023-04-13 00:00:00 600519.SS -100 @ 1723"
## [1] "2023-05-08 00:00:00 600519.SS 100 @ 1720.52001953125"
## [1] "2023-05-10 00:00:00 600519.SS -100 @ 1725"
## [1] "2023-06-15 00:00:00 600519.SS 100 @ 1755"
## [1] "2023-07-07 00:00:00 600519.SS -100 @ 1690.03002929688"
## [1] "2023-07-18 00:00:00 600519.SS 100 @ 1722.80004882812"
## [1] "2023-08-17 00:00:00 600519.SS -100 @ 1828.05004882812"
## [1] "2023-09-01 00:00:00 600519.SS 100 @ 1851.05004882812"
## [1] "2023-09-14 00:00:00 600519.SS -100 @ 1818.68994140625"
## [1] "2023-11-03 00:00:00 600519.SS 100 @ 1811.23999023438"
## [1] "2023-11-29 00:00:00 600519.SS -100 @ 1774.7099609375"
## [1] "2024-01-02 00:00:00 600519.SS 100 @ 1685.01000976562"
## [1] "2024-01-09 00:00:00 600519.SS -100 @ 1641"
## [1] "2024-02-08 00:00:00 600519.SS 100 @ 1706"
## [1] "2024-03-11 00:00:00 600519.SS -100 @ 1694.48999023438"
## [1] "2024-03-14 00:00:00 600519.SS 100 @ 1716.63000488281"
## [1] "2024-03-29 00:00:00 600519.SS -100 @ 1702.90002441406"
## [1] "2024-04-02 00:00:00 600519.SS 100 @ 1713.98999023438"
## [1] "2024-04-09 00:00:00 600519.SS -100 @ 1662.21997070312"
## [1] "2024-04-26 00:00:00 600519.SS 100 @ 1709.43005371094"
## [1] "2024-05-20 00:00:00 600519.SS -100 @ 1709"
## [1] "2024-07-18 00:00:00 600519.SS 100 @ 1497.51000976562"
## [1] "2024-07-26 00:00:00 600519.SS -100 @ 1422.18994140625"
## [1] "2024-08-16 00:00:00 600519.SS 100 @ 1431.19995117188"
## [1] "2024-08-28 00:00:00 600519.SS -100 @ 1389"
## [1] "2024-09-30 00:00:00 600519.SS 100 @ 1748"
## [1] "2024-10-29 00:00:00 600519.SS -100 @ 1531.61999511719"
## [1] "2024-11-08 00:00:00 600519.SS 100 @ 1609.96997070312"
## [1] "2024-11-20 00:00:00 600519.SS -100 @ 1544.81005859375"
## [1] "2024-12-13 00:00:00 600519.SS 100 @ 1519"
## [1] "2024-12-27 00:00:00 600519.SS -100 @ 1528.96997070312"
## [1] "2025-02-17 00:00:00 600519.SS 100 @ 1471.61999511719"
## [1] "2025-04-03 00:00:00 600519.SS -100 @ 1568.88000488281"
## [1] "2025-04-22 00:00:00 600519.SS 100 @ 1548.80004882812"
## [1] "2025-04-25 00:00:00 600519.SS -100 @ 1550"
## [1] "2025-05-09 00:00:00 600519.SS 100 @ 1591.18005371094"

更新组合和账户

updatePortf(portfolio.st)
## [1] "maotai_portfolio"
updateAcct(account.st)
## [1] "maotai_account"
updateEndEq(account.st)
## [1] "maotai_account"

分析结果

# 获取交易数据
trades <- getTxns(Portfolio = portfolio.st, Symbol = symbol)
print(trades)
##            Txn.Qty  Txn.Price Txn.Fees   Txn.Value Txn.Avg.Cost
## 2009-12-31       0    0.00000        0       0.000      0.00000
## 2010-05-25     100   98.61007        0    9861.007     98.61007
## 2010-06-01    -100   99.64688        0   -9964.688     99.64688
## 2010-06-03     100  101.45004        0   10145.004    101.45004
## 2010-06-23    -100   98.94816        0   -9894.816     98.94816
## 2010-07-15     100   99.04583        0    9904.583     99.04583
## 2010-10-15    -100  120.19534        0  -12019.534    120.19534
## 2010-10-25     100  129.97746        0   12997.746    129.97746
## 2010-11-02    -100  122.21638        0  -12221.638    122.21638
## 2010-11-11     100  132.17130        0   13217.130    132.17130
##        ...                                                     
## 2024-10-29    -100 1531.62000        0 -153162.000   1531.62000
## 2024-11-08     100 1609.96997        0  160996.997   1609.96997
## 2024-11-20    -100 1544.81006        0 -154481.006   1544.81006
## 2024-12-13     100 1519.00000        0  151900.000   1519.00000
## 2024-12-27    -100 1528.96997        0 -152896.997   1528.96997
## 2025-02-17     100 1471.62000        0  147162.000   1471.62000
## 2025-04-03    -100 1568.88000        0 -156888.000   1568.88000
## 2025-04-22     100 1548.80005        0  154880.005   1548.80005
## 2025-04-25    -100 1550.00000        0 -155000.000   1550.00000
## 2025-05-09     100 1591.18005        0  159118.005   1591.18005
##            Net.Txn.Realized.PL
## 2009-12-31              0.0000
## 2010-05-25              0.0000
## 2010-06-01            103.6812
## 2010-06-03              0.0000
## 2010-06-23           -250.1877
## 2010-07-15              0.0000
## 2010-10-15           2114.9513
## 2010-10-25              0.0000
## 2010-11-02           -776.1086
## 2010-11-11              0.0000
##        ...                    
## 2024-10-29         -21638.0005
## 2024-11-08              0.0000
## 2024-11-20          -6515.9912
## 2024-12-13              0.0000
## 2024-12-27            996.9971
## 2025-02-17              0.0000
## 2025-04-03           9726.0010
## 2025-04-22              0.0000
## 2025-04-25            119.9951
## 2025-05-09              0.0000
# 获取交易统计数据
tstats <- tradeStats(portfolio.st)
print(tstats)
##                  Portfolio    Symbol Num.Txns Num.Trades Net.Trading.PL
## 600519.SS maotai_portfolio 600519.SS      219        109         107330
##           Avg.Trade.PL Med.Trade.PL Largest.Winner Largest.Loser Gross.Profits
## 600519.SS     1001.725    -420.9091          53221        -21638      312497.1
##           Gross.Losses Std.Dev.Trade.PL Std.Err.Trade.PL Percent.Positive
## 600519.SS    -203309.1         8949.005         857.1592          41.2844
##           Percent.Negative Profit.Factor Avg.Win.Trade Med.Win.Trade
## 600519.SS          58.7156      1.537054      6944.381      2675.455
##           Avg.Losing.Trade Med.Losing.Trade Avg.Daily.PL Med.Daily.PL
## 600519.SS        -3176.705        -1388.979     1001.725    -420.9091
##           Std.Dev.Daily.PL Std.Err.Daily.PL Ann.Sharpe Max.Drawdown
## 600519.SS         8949.005         857.1592   1.776945    -88252.01
##           Profit.To.Max.Draw Avg.WinLoss.Ratio Med.WinLoss.Ratio Max.Equity
## 600519.SS           1.216176          2.186032          1.926203     185832
##           Min.Equity End.Equity
## 600519.SS  -146.5065     107330
# 查看持仓情况
positions <- getPos(Portfolio = portfolio.st, Symbol = symbol, Date = "2020-12-31")
print(positions)
##            Pos.Qty Pos.Avg.Cost
## 2020-11-10     100         1745
# 获取投资组合的收益率
returns <- PortfReturns(Account = account.st)

# 计算夏普比率,假设无风险利率为0.02
sharpe_ratio <- SharpeRatio(returns, Rf = 0.02)

# 计算最大回撤
max_drawdown <- maxDrawdown(returns)

print(paste0("夏普比率: ", sharpe_ratio))
## [1] "夏普比率: -1.36579368456422" "夏普比率: -1.44224144013023"
## [3] "夏普比率: -1.44224144013023" "夏普比率: -1.40746513390874"
print(paste0("最大回撤: ", max_drawdown))
## [1] "最大回撤: 0.66676665654044"
# 获取策略对象
strategyObj <- getStrategy(strategy.st)

str(strategyObj)
## List of 10
##  $ name       : chr "maotai_sma"
##  $ assets     : NULL
##  $ indicators :List of 2
##   ..$ fastMA:List of 5
##   .. ..$ name     : chr "SMA"
##   .. ..$ label    : chr "fastMA"
##   .. ..$ enabled  : logi TRUE
##   .. ..$ arguments:List of 2
##   .. .. ..$ x: language Cl(mktdata)
##   .. .. ..$ n: num 5
##   .. ..$ call     : language add.indicator(strategy = strategy.st, name = "SMA", arguments = list(x = quote(Cl(mktdata)),      n = fastMA), label = "fastMA")
##   .. ..- attr(*, "class")= chr "strat_indicator"
##   ..$ slowMA:List of 5
##   .. ..$ name     : chr "SMA"
##   .. ..$ label    : chr "slowMA"
##   .. ..$ enabled  : logi TRUE
##   .. ..$ arguments:List of 2
##   .. .. ..$ x: language Cl(mktdata)
##   .. .. ..$ n: num 20
##   .. ..$ call     : language add.indicator(strategy = strategy.st, name = "SMA", arguments = list(x = quote(Cl(mktdata)),      n = slowMA), label = "slowMA")
##   .. ..- attr(*, "class")= chr "strat_indicator"
##  $ signals    :List of 2
##   ..$ :List of 5
##   .. ..$ name     : chr "sigCrossover"
##   .. ..$ label    : chr "fast.gt.slow"
##   .. ..$ enabled  : logi TRUE
##   .. ..$ arguments:List of 3
##   .. .. ..$ columns     : chr [1:2] "fastMA" "slowMA"
##   .. .. ..$ relationship: chr "gt"
##   .. .. ..$ label       : chr "fast.gt.slow"
##   .. ..$ call     : language add.signal(strategy = strategy.st, name = "sigCrossover", arguments = list(columns = c("fastMA",      "slowMA"), | __truncated__
##   .. ..- attr(*, "class")= chr "strat_signal"
##   ..$ :List of 5
##   .. ..$ name     : chr "sigCrossover"
##   .. ..$ label    : chr "fast.lt.slow"
##   .. ..$ enabled  : logi TRUE
##   .. ..$ arguments:List of 3
##   .. .. ..$ columns     : chr [1:2] "fastMA" "slowMA"
##   .. .. ..$ relationship: chr "lt"
##   .. .. ..$ label       : chr "fast.lt.slow"
##   .. ..$ call     : language add.signal(strategy = strategy.st, name = "sigCrossover", arguments = list(columns = c("fastMA",      "slowMA"), | __truncated__
##   .. ..- attr(*, "class")= chr "strat_signal"
##  $ rules      :List of 3
##   ..$ order: list()
##   ..$ enter:List of 1
##   .. ..$ :List of 7
##   .. .. ..$ name     :function (mktdata = mktdata, timestamp, sigcol, sigval, orderqty = 0, ordertype, 
##     orderside = NULL, orderset = NULL, threshold = NULL, tmult = FALSE, 
##     replace = TRUE, delay = 1e-04, osFUN = "osNoOp", pricemethod = c("market", 
##         "opside", "active"), portfolio, symbol, ..., ruletype, TxnFees = 0, 
##     prefer = NULL, sethold = FALSE, label = "", order.price = NULL, chain.price = NULL, 
##     time.in.force = "")  
##   .. .. ..$ type     : chr "enter"
##   .. .. ..$ enabled  : logi TRUE
##   .. .. ..$ label    : chr "EnterLONG"
##   .. .. ..$ arguments:List of 6
##   .. .. .. ..$ sigcol   : chr "fast.gt.slow"
##   .. .. .. ..$ sigval   : logi TRUE
##   .. .. .. ..$ orderqty : num 100
##   .. .. .. ..$ ordertype: chr "market"
##   .. .. .. ..$ orderside: chr "long"
##   .. .. .. ..$ replace  : logi FALSE
##   .. .. ..$ path.dep : logi TRUE
##   .. .. ..$ call     : language add.rule(strategy = strategy.st, name = "ruleSignal", arguments = list(sigcol = "fast.gt.slow",      sigval = TRU| __truncated__ ...
##   .. .. ..- attr(*, "class")= chr "trade_rule"
##   ..$ exit :List of 1
##   .. ..$ :List of 7
##   .. .. ..$ name     :function (mktdata = mktdata, timestamp, sigcol, sigval, orderqty = 0, ordertype, 
##     orderside = NULL, orderset = NULL, threshold = NULL, tmult = FALSE, 
##     replace = TRUE, delay = 1e-04, osFUN = "osNoOp", pricemethod = c("market", 
##         "opside", "active"), portfolio, symbol, ..., ruletype, TxnFees = 0, 
##     prefer = NULL, sethold = FALSE, label = "", order.price = NULL, chain.price = NULL, 
##     time.in.force = "")  
##   .. .. ..$ type     : chr "exit"
##   .. .. ..$ enabled  : logi TRUE
##   .. .. ..$ label    : chr "ExitLONG"
##   .. .. ..$ arguments:List of 6
##   .. .. .. ..$ sigcol   : chr "fast.lt.slow"
##   .. .. .. ..$ sigval   : logi TRUE
##   .. .. .. ..$ orderqty : chr "all"
##   .. .. .. ..$ ordertype: chr "market"
##   .. .. .. ..$ orderside: chr "long"
##   .. .. .. ..$ replace  : logi FALSE
##   .. .. ..$ path.dep : logi TRUE
##   .. .. ..$ call     : language add.rule(strategy = strategy.st, name = "ruleSignal", arguments = list(sigcol = "fast.lt.slow",      sigval = TRU| __truncated__ ...
##   .. .. ..- attr(*, "class")= chr "trade_rule"
##  $ constraints: NULL
##  $ init       : list()
##  $ wrapup     : list()
##  $ trials     : num 6
##  $ call       : language strategy(name = strategy.st, store = TRUE)
##  - attr(*, "class")= chr "strategy"
# 查看指标数据
indicator_data <- strategyObj$indicators
print(indicator_data)
## $fastMA
## $name
## [1] "SMA"
## 
## $label
## [1] "fastMA"
## 
## $enabled
## [1] TRUE
## 
## $arguments
## $arguments$x
## Cl(mktdata)
## 
## $arguments$n
## [1] 5
## 
## 
## $call
## add.indicator(strategy = strategy.st, name = "SMA", arguments = list(x = quote(Cl(mktdata)), 
##     n = fastMA), label = "fastMA")
## 
## attr(,"class")
## [1] "strat_indicator"
## 
## $slowMA
## $name
## [1] "SMA"
## 
## $label
## [1] "slowMA"
## 
## $enabled
## [1] TRUE
## 
## $arguments
## $arguments$x
## Cl(mktdata)
## 
## $arguments$n
## [1] 20
## 
## 
## $call
## add.indicator(strategy = strategy.st, name = "SMA", arguments = list(x = quote(Cl(mktdata)), 
##     n = slowMA), label = "slowMA")
## 
## attr(,"class")
## [1] "strat_indicator"
# 查看信号数据
signal_data <- strategyObj$signals
print(signal_data)
## [[1]]
## $name
## [1] "sigCrossover"
## 
## $label
## [1] "fast.gt.slow"
## 
## $enabled
## [1] TRUE
## 
## $arguments
## $arguments$columns
## [1] "fastMA" "slowMA"
## 
## $arguments$relationship
## [1] "gt"
## 
## $arguments$label
## [1] "fast.gt.slow"
## 
## 
## $call
## add.signal(strategy = strategy.st, name = "sigCrossover", arguments = list(columns = c("fastMA", 
##     "slowMA"), relationship = "gt"), label = "fast.gt.slow")
## 
## attr(,"class")
## [1] "strat_signal"
## 
## [[2]]
## $name
## [1] "sigCrossover"
## 
## $label
## [1] "fast.lt.slow"
## 
## $enabled
## [1] TRUE
## 
## $arguments
## $arguments$columns
## [1] "fastMA" "slowMA"
## 
## $arguments$relationship
## [1] "lt"
## 
## $arguments$label
## [1] "fast.lt.slow"
## 
## 
## $call
## add.signal(strategy = strategy.st, name = "sigCrossover", arguments = list(columns = c("fastMA", 
##     "slowMA"), relationship = "lt"), label = "fast.lt.slow")
## 
## attr(,"class")
## [1] "strat_signal"
# 绘制权益曲线
equity <- getAccount(account.st)$summary$End.Eq
plot(equity, main="Strategy Equity Curve")

# 绘制持仓和交易图表
chart.Posn(portfolio.st, Symbol=symbol, TA="add_SMA(n=fastMA,col='blue');add_SMA(n=slowMA,col='red')")

结语

基于 R 软件进行量化回测一件极度舒适的事情。但由于本文未对回测指标(即 SMA )的参数做优化,因此,本文仅供技术探讨,不构成策略或投资建议。