这是我正在使用 quantstrat 开发的一个多时间框架策略示例。这是正确的多时间框架策略实现方式吗?我在 quantstrat 演示中没有找到任何其他多时间框架示例,也没有通过谷歌搜索找到。为了保持策略简单(这不是一个人们会交易的策略),并保持对多时间框架方面的关注,我将演示一个简单的策略,该策略使用 Tick 数据和 5 分钟 OHLC 数据。策略逻辑是在 Tick 数据穿过 5 分钟数据的 30 周期 SMA 时买入,并在 Tick 数据再次穿过同一 SMA 时平仓。
例如:如果策略处于空头状态,时间是 13:02,先前观察到的 5 分钟数据的 30 周期 SMA 是 90.55(12:55-13:00 的周期),并且 Tick 数据从 90.55 下方穿过到上方(90.56)则进行买入,当 Tick 数据再次下穿时退出仓位。
为了实现这一点,我需要将 Tick 数据和 5 分钟、30 周期 SMA 合并到同一个对象中,以便 quantstrat 进行处理。我获取 5 分钟的 OHLC xts 并计算其 30 周期 SMA。然后将其合并到 Tick 数据 xts 对象中,这将给我一个包含所有 Tick 数据的对象,然后每 5 分钟我将获得最后观察到的 5 分钟、30 周期 SMA 的行。
如果在 13:00 有一个 30 周期 SMA 值,则为 5 分钟 12:55-13:00。由于 SMA 的下一个更新时间是 5 分钟后,因此需要向下填充行,直到观察到下一个值(在 13:05)等等。
以下是 Tick 数据的头部(我拥有的 Tick 数据不包括毫秒,但我已使用 make.index.unique(clemtick) 使行唯一):
你会注意到第一个OHLC是09:04:00,这是因为
将5分钟数据的30 SMA加入到tick数据中。
现在,如果我再次查询该对象,
所以总结一下,这是实施多时间框架策略的最佳方式吗?
例如:如果策略处于空头状态,时间是 13:02,先前观察到的 5 分钟数据的 30 周期 SMA 是 90.55(12:55-13:00 的周期),并且 Tick 数据从 90.55 下方穿过到上方(90.56)则进行买入,当 Tick 数据再次下穿时退出仓位。
为了实现这一点,我需要将 Tick 数据和 5 分钟、30 周期 SMA 合并到同一个对象中,以便 quantstrat 进行处理。我获取 5 分钟的 OHLC xts 并计算其 30 周期 SMA。然后将其合并到 Tick 数据 xts 对象中,这将给我一个包含所有 Tick 数据的对象,然后每 5 分钟我将获得最后观察到的 5 分钟、30 周期 SMA 的行。
如果在 13:00 有一个 30 周期 SMA 值,则为 5 分钟 12:55-13:00。由于 SMA 的下一个更新时间是 5 分钟后,因此需要向下填充行,直到观察到下一个值(在 13:05)等等。
以下是 Tick 数据的头部(我拥有的 Tick 数据不包括毫秒,但我已使用 make.index.unique(clemtick) 使行唯一):
head(clemtick)
Price Volume
2013-01-15 09:00:00 93.90 1
2013-01-15 09:00:00 93.89 1
2013-01-15 09:00:00 93.89 1
2013-01-15 09:00:00 93.88 2
2013-01-15 09:00:00 93.89 1
2013-01-15 09:00:00 93.89 2
以下是1分钟数据的“头部”(每分钟代表前一分钟的数据,例如时间戳09:01:00 == 从09:00:00到09:01:00的数据):
head(clemin)
Open High Low Close Volume
2013-01-15 09:01:00 93.90 94.04 93.87 93.97 1631
2013-01-15 09:02:00 93.97 93.98 93.90 93.91 522
2013-01-15 09:03:00 93.91 93.97 93.90 93.96 248
2013-01-15 09:04:00 93.95 93.98 93.93 93.95 138
2013-01-15 09:05:00 93.95 93.96 93.91 93.92 143
2013-01-15 09:06:00 93.93 93.97 93.91 93.91 729
将1分钟的数据转换为5分钟的数据:
cle5min <- to.minutes5(clemin)
clemin.Open clemin.High clemin.Low clemin.Close clemin.Volume
2013-01-15 09:04:00 93.90 94.04 93.87 93.95 2539
2013-01-15 09:09:00 93.95 93.97 93.81 93.89 2356
2013-01-15 09:14:00 93.90 94.05 93.86 93.89 4050
2013-01-15 09:19:00 93.90 94.03 93.84 94.00 2351
2013-01-15 09:24:00 93.99 94.21 93.97 94.18 3261
2013-01-15 09:29:00 94.18 94.26 94.18 94.19 1361
你会注意到第一个OHLC是09:04:00,这是因为
to.minutes5
函数的工作方式,这在这个线程中讨论过。基本上,第一个时间戳09:04:00 == OHLC 4分钟的数据从09:00:00 - 09:04:00。09:09:00时间戳是从09:04:00 - 09:09:00的下一个完整的5分钟。理想情况下,我希望每个时间戳都是5、10、15等,但我还没有找出如何做到这一点。将5分钟数据的30 SMA加入到tick数据中。
clemtick$sma30 <- SMA(cle5min$clemin.Close, 30)
这将创建一个带有SMA的新列。SMA需要30个周期来计算第一个值,而且SMA仅会出现在每5分钟的时间戳(11:29:00、11:34:00、11:39等)中。它看起来像:
clemtick["2013-01-15 11:28:59::2013-01-15 11:29:00"]
Price Volume SMA30
2013-01-15 11:28:59 93.87 1 NA
2013-01-15 11:28:59 93.87 1 NA
2013-01-15 11:28:59 93.88 1 NA
2013-01-15 11:29:00 93.87 1 93.92633
2013-01-15 11:29:00 93.87 1 NA
2013-01-15 11:29:00 93.88 1 NA
2013-01-15 11:29:00 93.88 1 NA
现在我需要用重复值填充SMA30
列。11:29:00时的SMA30
值是从11:24:00到11:29:00的OHLC。下一次更新此值将在11:34:00之后,因此我需要向下填充行,直到下一个值,因为这是策略在逐行处理时将引用的内容。
clemtick <- na.locf(clemtick)
现在,如果我再次查询该对象,
clemtick["2013-01-15 11:33:58::2013-01-15 11:34:01"]
Price Volume SMA30
2013-01-15 11:33:58 93.84 1 93.92633
2013-01-15 11:34:00 93.84 1 93.92267
2013-01-15 11:34:00 93.85 1 93.92267
2013-01-15 11:34:01 93.84 1 93.92267
现在我们有了最终的对象,接下来运行策略:
require(quantstrat)
options("getSymbols.warning4.0"=FALSE)
rm(list=ls(.blotter), envir=.blotter)
Sys.setenv(TZ="UTC")
symbols <- "clemtick"
currency('USD')
stock(symbols, currency="USD", multiplier=1)
account.st <- 0
strategy.st <- portfolio.st <- account.st <- "multi"
rm.strat(portfolio.st)
rm.strat(strategy.st)
initDate <- "1980-01-01"
tradeSize <- 1000
initEq <- tradeSize*length(symbols)
initPortf(portfolio.st, symbols=symbols, initDate=initDate, currency='USD')
initAcct(account.st, portfolios=portfolio.st,
initDate=initDate, currency='USD', initEq=initEq)
initOrders(portfolio.st, initDate=initDate)
strategy(strategy.st, store=TRUE)
add.signal(strategy.st, name="sigCrossover",
arguments=list(columns=c("Price", "sma30"), relationship="gt"),
label="golong")
add.signal(strategy.st, name="sigCrossover",
arguments=list(columns=c("Price", "sma30"), relationship="lt"),
label="exitlong")
#enter rule
add.rule(strategy.st, name="ruleSignal",
arguments=list(sigcol="golong",
sigval=TRUE,
ordertype="market",
orderside="long",
replace=TRUE,
prefer="Price",
orderqty=1),
type="enter", path.dep=TRUE, label="long")
#exit rule
add.rule(strategy.st, name = "ruleSignal",
arguments=list(sigcol="exitlong",
sigval=TRUE,
ordertype="market",
orderside="long",
replace=TRUE,
prefer="Price",
orderqty=-1),
type="exit", path.dep=TRUE, label="exitlong")
#apply strategy
t1 <- Sys.time()
out2 <- applyStrategy(strategy=strategy.st, portfolios=portfolio.st, debug=TRUE)
t2 <- Sys.time()
print(t2-t1)
head(mktdata)
nrow(mktdata)
所以总结一下,这是实施多时间框架策略的最佳方式吗?