[R-SIG-Finance] Wrong execution time
Mike
m|ke9 @end|ng |rom po@teo@n|
Thu Sep 22 21:42:22 CEST 2022
I like to backtest this strategy:
1. If a long signal occurs on day 0 (signal day) then
enter long on day 1 at least until 15:29 if the price exeeds signal
day's high.
2. On execution of the entry order issue 2 exit orders combined by
OCO:
a. Stop loss at x USD of entry price
b. MOC of entry day (last bar at 15:30)
So the strategy holds the stock for one day only.
I got test data with 30 minutes per bar (attached SYM.csv). I already
integrated a long signal into the data for simplicity.
According to the test data I would expect the strategy to close the
position with rule CloseLONG on Close of 2021-01-26 15:30:00 at
60.91.
Why does it close at 2021-01-26 10:00:00 instead although the time
index in the order book seems correct?
Mike
The result:
[1] "2021-01-26 09:30:00 SYM 100 @ 61.2"
[1] "2021-01-26 10:00:00 SYM -100 @ 60.78"
^^^^^^^^
$str1
$str1$SYM
Order.Qty Order.Price Order.Type Order.Side
2021-01-25 15:30:00 "100" "60.58" "stoplimit" "long"
2021-01-26 09:30:00 "all" "60" "stoplimit" "long"
2021-01-26 15:30:00 "all" "61.2" "market" "long"
^^^^^^^^
Order.Threshold Order.Status Order.StatusTime Prefer
2021-01-25 15:30:00 NA "closed" "2021-01-26 09:30:00" "High"
2021-01-26 09:30:00 "-1.2" "replaced" "2021-01-26 09:30:00" "Low"
2021-01-26 15:30:00 NA "closed" "2021-01-26 10:00:00" "Close"
Order.Set Txn.Fees Rule Time.In.Force
2021-01-25 15:30:00 NA "0" "EnterLONG" "2021-01-26 15:29:00"
2021-01-26 09:30:00 "ocolong" "0" "StopLossLONG" ""
2021-01-26 15:30:00 "ocolong" "0" "CloseLONG" ""
The strategy:
library(lubridate)
library(quantstrat)
secTo1530 <- function (ts) {
# Seconds until 15:30 on the same day
dest <- ts
lubridate::hour (dest) <- 15
lubridate::minute (dest) <- 30
lubridate::second (dest) <- 0
as.numeric (as.duration (dest - ts), "seconds")
}
secTo1529 <- function (mktdata, ts) {
# Seconds from timestamp until one minute before last bar on the next day
# (15:29/12:29).
idx <- index (to.daily (mktdata[,1:5], name=NULL))
# Since length of tomorrow's trading session is unknown add 2 days and go
# back one bar.
day_idx_val <- which (idx == lubridate::date (ts))
day_after_tomorrow_idx_val <- day_idx_val + 2
day_after_tomorrow <- idx[day_after_tomorrow_idx_val]
idx_val_day_after_tomorrow <-
which (lubridate::date(index(mktdata)) == day_after_tomorrow)
idx_begin_day_after_tomorrow <- min (idx_val_day_after_tomorrow)
last_idx_tomorrow <- idx_begin_day_after_tomorrow - 1
# Tomorrow/next day 15:30:00 UTC
ymd_hms_begin_last_idx_tomorrow <- index(mktdata)[last_idx_tomorrow]
dest <- ymd_hms_begin_last_idx_tomorrow - lubridate::minutes (1)
as.numeric (as.duration (dest - ts), "seconds")
}
suppressWarnings(rm("account.str1","portfolio.str1",pos=.blotter))
suppressWarnings(rm("order_book.str1",pos=.strategy))
oldtz<-Sys.getenv("TZ")
if(oldtz=="") Sys.setenv(TZ="UTC")
sy <- 'SYM'
symbols = c(sy)
fn <- "SYM.csv"
tmp <- as.xts (read.csv2.zoo (fn, header=T, stringsAsFactors=F,
dec = ".", FUN=as.POSIXct))
assign(sy, tmp)
tradeSize <- 5000
initEq <- 100000
currency("USD")
stock(sy, currency="USD",multiplier=1)
initPortf('str1', symbols=symbols)
initAcct('str1', portfolios='str1', initEq=initEq)
initOrders(portfolio='str1')
strategy.st <- 'str1'
strategy (strategy.st, store=TRUE)
Hi_yesterday <- function (x) {
# Generate row with yesterday's high
agg <- to.daily (x)
H_yesterday <- lag (Hi (agg))
idx_new <- as.POSIXct (x=paste0 (index (H_yesterday), " 09:30:00"), tz="UTC")
yesterday <- H_yesterday
index (yesterday) <- idx_new
result <- base::merge (yesterday, xts (,index (x)), fill = na.locf)
# Already provide this day's high in it's last bar
result <- stats::lag (result, -1)
return (result)
}
add.indicator(strategy.st, name = "Hi_yesterday", arguments = list(
x = quote(mktdata)),
label="HiY")
add.rule(strategy.st, name='ruleSignal', arguments = list(
sigcol = "Long",
sigval = TRUE,
ordertype = 'stoplimit',
prefer = 'High',
orderside = 'long',
tmult = F,
threshold = quote(mktdata$HiY[timestamp]), # > high yesterday
time.in.force = quote(secTo1529 (mktdata, timestamp)),
tradeSize = tradeSize,
maxSize = tradeSize,
orderqty = 100),
type='enter',
label='EnterLONG')
# Exit: Stop Loss
add.rule(strategy.st, name = 'ruleSignal', arguments = list(
sigcol = 'Long',
sigval = TRUE,
orderside = 'long',
ordertype = 'stoplimit',
prefer = 'Low',
tmult = F,
threshold = 1.20,
orderqty = 'all',
orderset = 'ocolong'),
type='chain', parent='EnterLONG',
label='StopLossLONG')
# Exit: Sell at close of the market of entry-day
add.rule(strategy.st, name = 'ruleSignal', arguments = list(
sigcol = 'Long',
sigval = TRUE,
orderside = 'long',
ordertype = 'market',
prefer = 'Close',
delay = quote(secTo1530 (timestamp)),
orderqty = 'all',
orderset = 'ocolong'),
type='chain', parent='EnterLONG',
label='CloseLONG')
out<-try(applyStrategy(strategy='str1' , portfolios='str1'))
print(getOrderBook('str1'))
updatePortf(Portfolio='str1')
updateAcct('str1')
updateEndEq('str1')
Sys.setenv(TZ=oldtz)
SYM.csv:
Index;Open;High;Low;Close;Volume;Long
2021-01-25 09:30:00;60.67;60.77;59.705;59.98;4841167;0
2021-01-25 10:00:00;59.98;60.31;59.955;59.992;2331090;0
2021-01-25 10:30:00;59.99;60.155;59.64;59.69;2011158;0
2021-01-25 11:00:00;59.6771;59.76;59.26;59.38;2717999;0
2021-01-25 11:30:00;59.38;59.79;59.17;59.67;1758438;0
2021-01-25 12:00:00;59.675;59.85;59.4601;59.4601;1536049;0
2021-01-25 12:30:00;59.475;59.93;59.47;59.9;1212432;0
2021-01-25 13:00:00;59.9;60.37;59.875;60.32;1461132;0
2021-01-25 13:30:00;60.32;60.42;60.185;60.23;970523;0
2021-01-25 14:00:00;60.24;60.29;59.94;60;971210;0
2021-01-25 14:30:00;60;60.24;59.88;60.06;1038065;0
2021-01-25 15:00:00;60.055;60.4;60.04;60.345;931919;0
2021-01-25 15:30:00;60.35;60.58;60.3;60.56;2135034;1
2021-01-26 09:30:00;61.2;61.24;60.087;60.335;2512210;0
2021-01-26 10:00:00;60.335;60.9;60.29;60.78;1768021;0
2021-01-26 10:30:00;60.78;60.87;60.408;60.445;1173861;0
2021-01-26 11:00:00;60.45;60.56;60.15;60.52;1085131;0
2021-01-26 11:30:00;60.51;60.53;60.19;60.33;919405;0
2021-01-26 12:00:00;60.33;60.68;60.31;60.65;1130399;0
2021-01-26 12:30:00;60.645;60.95;60.63;60.915;756772;0
2021-01-26 13:00:00;60.92;61.04;60.81;60.875;848270;0
2021-01-26 13:30:00;60.87;60.95;60.73;60.805;822825;0
2021-01-26 14:00:00;60.8;61.15;60.78;60.95;989872;0
2021-01-26 14:30:00;60.95;60.98;60.81;60.9;1001693;0
2021-01-26 15:00:00;60.9;60.93;60.73;60.86;854300;0
2021-01-26 15:30:00;60.85;60.93;60.67;60.91;3214855;0
2021-01-27 09:30:00;59.9;59.99;58.53;58.98;3972687;0
2021-01-27 10:00:00;58.97;59.43;58.74;59.37;2386966;0
2021-01-27 10:30:00;59.375;59.85;59.13;59.81;2147582;0
2021-01-27 11:00:00;59.82;59.86;59.44;59.69;1273143;0
2021-01-27 11:30:00;59.6998;59.76;59.4;59.45;1183463;0
2021-01-27 12:00:00;59.45;60;59.35;59.41;1359946;0
2021-01-27 12:30:00;59.41;59.62;59.31;59.565;570512;0
2021-01-27 13:00:00;59.565;59.868;59.44;59.76;761216;0
2021-01-27 13:30:00;59.76;59.765;59.45;59.58;623576;0
2021-01-27 14:00:00;59.585;59.7;59.37;59.42;897427;0
2021-01-27 14:30:00;59.425;59.625;59.21;59.3283;2123241;0
2021-01-27 15:00:00;59.33;59.83;59.2;59.67;1558001;0
2021-01-27 15:30:00;59.66;59.7;59.17;59.4;3507501;0
More information about the R-SIG-Finance
mailing list