script adapted from demo folder luxor in quantstrat package:
require(quantstrat)
require(foreach)
if (!"doMC" %in% installed.packages()[, 1]) {
#install.packages("doMC")
}
#require(doMC)
#registerDoMC(cores = 2)
options(width = 240)
Sys.setenv(TZ = "UTC")
###
startDate = '2002-10-21'
.from = startDate
.to = '2002-10-31'
###
strategy.st = 'luxor'
portfolio.st = 'forex'
account.st = 'IB'
###
.orderqty = 100000
.threshold = 0.0005
.txnfees = -6 # round-trip fee
### Distributions for paramset analysis
.nsamples = 100
.FastSMA = (1:20)
.SlowSMA = (30:80)
.StopLoss = seq(0.05, 2.4, length.out = 48) / 100
# generate 24x24h ISO8601 timespan vector
# this includes non-ISO8601 elements (e.g. "T01:00/T00:59")
# that are discarded at processing
.timespans.start <- paste(sprintf("T%02d", 0:23), ':00', sep = '')
.timespans.stop <- paste(sprintf("T%02d", 0:23), ':59', sep = '')
.timespans <-
outer(.timespans.start,
.timespans.stop,
FUN = paste,
sep = '/')
# in order to run the full 24x24 hour scan above, comment out the following line:
.timespans <-
c(
'T06:00/T10:00',
'T07:00/T11:00',
'T08:00/T12:00',
'T09:00/T13:00',
'T10:00/T14:00',
'T11:00/T15:00',
'T12:00/T16:00'
)
### Actual arameters
.fast = 1
.slow = 30
#.timespan = 'T09:00/T13:00'
.timespan = 'T00:00/T23:59'
#.timespan = NULL
.stoploss <- 0.40 / 100
### FinancialInstrument
currency(c('GBP', 'USD'))
exchange_rate('GBPUSD', tick_size = 0.0001)
### quantmod
# FinancialInstrument - method for loading data from split files
getSymbols.FI(
Symbols = 'GBPUSD',
dir = system.file('extdata', package = 'quantstrat'),
# dir='~/R/OHLC',
from = .from,
to = .to
,
extension = 'rda'
,
use_identifier = NA
)
### xts
GBPUSD = to.minutes30(GBPUSD)
GBPUSD = align.time(GBPUSD, 1800)
### define strategy
rm.strat(name = "luxor")
rm.strat(name = "forex")
rm.strat(name = "IB")
strategy(strategy.st, store = TRUE)
initPortf(portfolio.st, symbols = 'GBPUSD', currency = 'USD')
addPosLimit(
portfolio = portfolio.st,
symbol = 'GBPUSD',
timestamp = startDate,
maxpos = .orderqty
)
initAcct(account.st, portfolios = portfolio.st, currency = 'USD')
###
initOrders(portfolio.st)
### indicators
add.indicator(
strategy.st,
name = "SMA",
arguments = list(x = quote(Cl(mktdata)[, 1]),
n = .fast),
label = "nFast"
)
add.indicator(
strategy.st,
name = "SMA",
arguments = list(x = quote(Cl(mktdata)[, 1]),
n = .slow),
label = "nSlow"
)
### signals
add.signal(
strategy.st,
name = 'sigCrossover',
arguments = list(
columns = c("nFast", "nSlow"),
relationship = "gte"
),
label = 'long'
)
add.signal(
strategy.st,
name = 'sigCrossover',
arguments = list(
columns = c("nFast", "nSlow"),
relationship = "lt"
),
label = 'short'
)
### rules ############
# normal exit rules
add.rule(
strategy.st,
name = 'ruleSignal',
arguments = list(
sigcol = 'long' ,
sigval = TRUE,
replace = TRUE,
orderside = 'short',
ordertype = 'market',
TxnFees = .txnfees,
orderqty = 'all',
orderset = 'ocoshort'
),
type = 'exit',
timespan = .timespan,
label = 'Exit2LONG'
)
add.rule(
strategy.st,
name = 'ruleSignal',
arguments = list(
sigcol = 'short',
sigval = TRUE,
replace = TRUE,
orderside = 'long' ,
ordertype = 'market',
TxnFees = .txnfees,
orderqty = 'all',
orderset = 'ocolong'
),
type = 'exit',
timespan = .timespan,
label = 'Exit2SHORT'
)
# normal entry rules
add.rule(
strategy.st,
name = 'ruleSignal',
arguments = list(
sigcol = 'long' ,
sigval = TRUE,
replace = FALSE,
orderside = 'long' ,
ordertype = 'stoplimit',
prefer = 'High',
threshold = .threshold,
TxnFees = 0,
orderqty = +.orderqty,
osFUN = osMaxPos,
orderset = 'ocolong'
),
type = 'enter',
timespan = .timespan,
label = 'EnterLONG'
)
add.rule(
strategy.st,
name = 'ruleSignal',
arguments = list(
sigcol = 'short',
sigval = TRUE,
replace = FALSE,
orderside = 'short',
ordertype = 'stoplimit',
prefer = 'Low',
threshold = -.threshold,
TxnFees = 0,
orderqty = -.orderqty,
osFUN = osMaxPos,
orderset = 'ocoshort'
),
type = 'enter',
timespan = .timespan,
label = 'EnterSHORT'
)
### parameter sets
# stop-loss
add.rule(
strategy.st,
name = 'ruleSignal',
arguments = list(
sigcol = 'long' ,
sigval = TRUE,
replace = FALSE,
orderside = 'long',
ordertype = 'stoplimit',
tmult = TRUE,
threshold = quote(.stoploss),
TxnFees = .txnfees,
orderqty = 'all',
orderset = 'ocolong'
),
type = 'chain',
parent = 'EnterLONG',
label = 'StopLossLONG',
timespan = .timespan,
enabled = FALSE
)
add.rule(
strategy.st,
name = 'ruleSignal',
arguments = list(
sigcol = 'short' ,
sigval = TRUE,
replace = FALSE,
orderside = 'short',
ordertype = 'stoplimit',
tmult = TRUE,
threshold = quote(.stoploss),
TxnFees = .txnfees,
orderqty = 'all',
orderset = 'ocoshort'
),
type = 'chain',
parent = 'EnterSHORT',
label = 'StopLossSHORT',
timespan = .timespan,
enabled = FALSE
)
add.distribution(
strategy.st,
paramset.label = 'StopLoss',
component.type = 'chain',
component.label = 'StopLossLONG',
variable = list(threshold = .StopLoss),
label = 'StopLossLONG'
)
add.distribution(
strategy.st,
paramset.label = 'StopLoss',
component.type = 'chain',
component.label = 'StopLossSHORT',
variable = list(threshold = .StopLoss),
label = 'StopLossSHORT'
)
add.distribution.constraint(
strategy.st,
paramset.label = 'StopLoss',
distribution.label.1 = 'StopLossLONG',
distribution.label.2 = 'StopLossSHORT',
operator = '==',
label = 'StopLoss'
)
enable.rule('luxor', 'chain', 'StopLoss')
results <-
apply.paramset(
strategy.st,
paramset.label = 'StopLoss',
portfolio.st = portfolio.st,
account.st = account.st,
nsamples = .nsamples,
verbose = TRUE
)
stats <- results$tradeStats
print(t(stats))
plot(
100 * stats$StopLossLONG,
stats$Net.Trading.PL,
type = 'b',
xlab = 'Stoploss %',
ylab = 'Net.Trading.PL',
main = 'Luxor'
)
results generates error for all samples:
print(results$error) [[1]] <simpleError in variable.name %in% c("timespan"): object 'variable.name' not found>
the same error results if .timespan = NULL in above script is changed to .timespan = 'T00:00/T23:59' and timespan=.timespan is added to entry/exit/stop loss rules in above script
R version 4.2.3 (2023-03-15)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 22.04.2 LTS
Matrix products: default
BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.10.0
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.10.0
locale:
[1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8 LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 LC_PAPER=en_US.UTF-8 LC_NAME=C
[9] LC_ADDRESS=C LC_TELEPHONE=C LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
attached base packages:
[1] parallel stats graphics grDevices utils datasets methods base
other attached packages:
[1] doMC_1.3.8 iterators_1.0.14 quantstrat_0.24 foreach_1.5.2 blotter_0.16.2 PerformanceAnalytics_2.0.4 FinancialInstrument_1.3.1 quantmod_0.4.24
[9] TTR_0.24.3 xts_0.13.1 zoo_1.8-12
loaded via a namespace (and not attached):
[1] quadprog_1.5-8 lattice_0.20-45 codetools_0.2-19 MASS_7.3-58.3 grid_4.2.3 jsonlite_1.8.7 curl_5.0.1 boot_1.3-28 tools_4.2.3 compiler_4.2.3
This was a bug in quantstrat that is now fixed in version 0.25 on GitHub. See the commit for gory details.