2

I want to set up a trading strategy using quantstrat. It should compare, if the closeprice is higher than the Donchianchannel high. i would like to create a Longsignal if: Closeprice > 0.85 * Donchianchannel high.

library(quantstrat)
Sys.setenv(TZ = "UTC")
currency(USD)

init_date <- "2014-12-31"
start_date <- "2015-01-01"
end_date <- "2017-12-31"
init_equity <- 100000
adjustment <- TRUE
getSymbols(Symbols = "QQQ", 
           src = "yahoo", index.class = "POSIXct",
           from = start_date, 
           to = end_date, 
           adjust = adjustment)

QQQ=na.omit(QQQ)
stock("QQQ",currency="USD",multiplier = 1)

> head(QQQ)
            QQQ.Open  QQQ.High  QQQ.Low QQQ.Close QQQ.Volume QQQ.Adjusted
2015-01-02 100.66108 101.09768 99.39009  99.87520   31148800     99.71343
2015-01-05  99.44830  99.55502 98.12879  98.41016   36521300     98.25075
2015-01-06  98.55569  98.72063 96.65405  97.09065   66205500     96.93339
2015-01-07  97.74070  98.57509 97.49814  98.34224   37577400     98.18295
2015-01-08  99.20574 100.41853 99.06991 100.22448   40212600    100.06215
2015-01-09 100.53496 100.56406 98.98259  99.56473   41401300     99.40346


strategy.st<-"basic_strat"
portfolio.st<-"basic_portfolio"
account.st<-"basic_account"
rm.strat(portfolio.st)
rm.strat(account.st)
initPortf(name = portfolio.st,symbols = "QQQ",initDate = init_date)

initAcct(name = account.st,portfolios = portfolio.st,initDate = init_date,initEq = init_equity)

initOrders(portfolio = portfolio.st,symbols = "QQQ",initDate = init_date)
strategy(strategy.st, store = TRUE)

add.indicator(strategy = strategy.st, 
      name = "Donchianchannel",
              arguments = list(price = quote(Cl(mktdata)), 
                               n = 260),
              label = "DCH")

mktdata_ind <- applyIndicators(strategy=strategy.st,mktdata=NSEI) This step doesnt work:

Error in .xts(e, .index(e2), .indexCLASS = indexClass(e2), .indexFORMAT = indexFormat(e2), : index length must match number of observations )

mktdata_ind[is.na(mktdata_ind)]=0
knitr::kable(tail(mktdata_ind))

Can someone identify the problem and help me?

The signal should look like this in my mind:

add.signal(strategy.st, name = "sigCrossover", arguments = list(columns = c("DHC.high*0.85","Close"),relationship="gt"), label = "Close_gt_DHC.high")

Thank you very much for your help!

FXQuantTrader
  • 6,821
  • 3
  • 36
  • 67
Ramon
  • 71
  • 8

1 Answers1

0

Here is a fully reproducible example, for long trades. Hopefully you can fix this for the short side and whatever adjustments you want.

You had a few errors in your sample code which I've also corrected:

library(quantstrat)
Sys.setenv(TZ = "UTC")
# The currency argument should be a character vector, not an expression without quotes:
currency("USD")

# You you're using Donchian channel with 260 look back period, you need a much larger data period to get meaningful results as you'll lose the first 259 rows of data:
start_date <- "2007-01-01"
end_date <- "2017-12-31"
init_equity <- 100000
adjustment <- TRUE
getSymbols(Symbols = "QQQ",
           src = "yahoo", index.class = "POSIXct",
           from = start_date,
           to = end_date)
#saveRDS(QQQ, "QQQ.rds")
#QQQ <- readRDS("QQQ.rds")

QQQ=na.omit(QQQ)
symbols <- "QQQ"
stock(symbols,currency="USD",multiplier = 1)

strategy.st<-"basic_strat"
portfolio.st<-"basic_portfolio"
account.st<-"basic_account"

LongEnabled <- TRUE
ShortEnabled <- TRUE

rm.strat(strategy.st)
rm.strat(portfolio.st)
rm.strat(account.st)
initPortf(name = portfolio.st,symbols = "QQQ")
# You don't need to set init date, it will be figured out automatically.
initAcct(name = account.st,portfolios = portfolio.st, initEq = init_equity)

initOrders(portfolio = portfolio.st,symbols = "QQQ")
strategy(strategy.st, store = TRUE)

txfeeFUN <- function(TxnQty, TxnPrice, Symbol, fee.rate = 0.005) {
  fees <- -abs(TxnQty) * fee.rate * TxnPrice
  if (fees > 0)
    stop("Fees must be a negative number.")
  fees
}


# restrict to 1 entry per side.
tradeSize <- 100
for (sym in symbols) {
  addPosLimit(portfolio.st, sym, start(get(sym)), tradeSize)
}


add.indicator(strategy = strategy.st, 
              # correct name of function:
              name = "DonchianChannel",
              arguments = list(HL = quote(HLC(mktdata)[, 1:2]), 
                               # you will lose 260 rows of data in setting up the donchian channel with just 
                               #        n = 260),
                               n = 100),
              label = "DCH")

ratioPriceSeries <- function(x, 
                             multiplier = 0.85,
                             col = "high.DCH") {
  x$ratioLvl <- multiplier * x[, col]
  x[, "ratioLvl"]
}


add.indicator(strategy = strategy.st, 
              # correct name of function:
              name = "ratioPriceSeries",
              arguments = list(x = quote(mktdata), 
                               multiplier = 0.85,
                               col = "high.DCH"),
              label = "Lratio")





res <- applyIndicators(strategy.st, mktdata = QQQ)

add.signal(strategy.st, name = "sigCrossover",
           arguments = list(
             label = "co",
             data = quote(mktdata),
             columns = c("Close", "Lratio"),
             relation = "gt"
           ),
           label = "enterL")

add.signal(strategy.st, name = "sigCrossover",
           arguments = list(
             label = "co",
             data = quote(mktdata),
             columns = c("Close", "Lratio"),
             relation = "lt"
           ),
           label = "exitL")

res <- applySignals(strategy.st, res)

# debug, check signal counts:
#sum(res[, "enterL"] == 1,na.rm = TRUE)
#sum(res[, "exitL"] == 1,na.rm = TRUE)


add.rule(strategy.st,name='ruleSignal2',
         arguments = list(sigcol="enterL",
                          sigval=TRUE,
                          orderqty=100,
                          ordertype='market',
                          orderside='long',
                          osFUN=osMaxPos,
                          threshold=NULL,
                          TxnFees = "txfeeFUN",
                          # change this to prefer = "Open" if you wish:
                          prefer = "Close"),
         type='enter',
         label='enterLong',
         storefun=FALSE,
         enabled = LongEnabled
)

add.rule(strategy.st,name='ruleSignal',
         arguments = list(sigcol="exitL",
                          sigval=TRUE,
                          orderqty='all',
                          ordertype='market',
                          orderside='long',
                          orderset='DC.set',
                          TxnFees = "txfeeFUN",
                          prefer = "Close"),
         type='exit',
         label='exitLong',
         enabled = LongEnabled
)


applyStrategy(strategy.st, portfolio= portfolio.st)
updatePortf(Portfolio = portfolio.st)

ob <- getOrderBook(portfolio.st)


getTxns(portfolio.st, "QQQ")
# Txn.Qty Txn.Price Txn.Fees Txn.Value Txn.Avg.Cost Net.Txn.Realized.PL
# 1950-01-01       0      0.00    0.000         0         0.00              0.0000
# 2008-04-04     100     45.86  -22.930      4586        45.86            -22.9300
# 2008-04-10    -100     45.54  -22.770     -4554        45.54            -54.7700
# 2008-04-11     100     44.28  -22.140      4428        44.28            -22.1400
# 2008-04-14    -100     44.08  -22.040     -4408        44.08            -42.0397
# 2008-04-17     100     45.27  -22.635      4527        45.27            -22.6350
# 2008-09-10    -100     42.80  -21.400     -4280        42.80           -268.4001
# 2008-09-12     100     43.43  -21.715      4343        43.43            -21.7150
# 2008-09-16    -100     42.41  -21.205     -4241        42.41           -123.2050
# 2009-03-18     100     29.70  -14.850      2970        29.70            -14.8500
# 2010-07-01    -100     42.59  -21.295     -4259        42.59           1267.7049
# 2010-07-08     100     44.20  -22.100      4420        44.20            -22.1000
# 2011-08-09    -100     53.03  -26.515     -5303        53.03            856.4848
# 2011-08-10     100     50.86  -25.430      5086        50.86            -25.4300
# 2011-08-22    -100     50.21  -25.105     -5021        50.21            -90.1052
# 2011-08-24     100     52.69  -26.345      5269        52.69            -26.3450
# 2016-02-08    -100     96.62  -48.310     -9662        96.62           4344.6904
# 2016-02-17     100    102.50  -51.250     10250       102.50            -51.2500

tradeStats(portfolio.st, Symbols = "QQQ")
# Portfolio Symbol Num.Txns Num.Trades Net.Trading.PL Avg.Trade.PL Med.Trade.PL Largest.Winner Largest.Loser Gross.Profits Gross.Losses Std.Dev.Trade.PL
# QQQ basic_portfolio    QQQ       17          8       10986.96      736.295    -48.40485        4344.69     -268.4001       6468.88      -578.52         1557.472
# Std.Err.Trade.PL Percent.Positive Percent.Negative Profit.Factor Avg.Win.Trade Med.Win.Trade Avg.Losing.Trade Med.Losing.Trade Avg.Daily.PL Med.Daily.PL
# QQQ         550.6496             37.5             62.5      11.18177      2156.293      1267.705         -115.704         -90.1052      736.295    -48.40485
# Std.Dev.Daily.PL Std.Err.Daily.PL Ann.Sharpe Max.Drawdown Profit.To.Max.Draw Avg.WinLoss.Ratio Med.WinLoss.Ratio Max.Equity Min.Equity End.Equity
# QQQ         1557.472         550.6496   7.504674     -2070.56           5.306277          18.63629          14.06916   11274.96  -644.6849   10986.96

mktdata["2008-04"]
# QQQ.Open QQQ.High QQQ.Low QQQ.Close QQQ.Volume QQQ.Adjusted high.DCH mid.DCH low.DCH ratioLvl.Lratio enterL exitL
# 2008-04-01    44.42    45.61   44.41     45.59  137494400     41.33453    54.69  47.870   41.05         46.4865     NA    NA
# 2008-04-02    45.70    46.02   45.17     45.49  132486800     41.24388    54.58  47.815   41.05         46.3930     NA    NA
# 2008-04-03    45.29    45.91   45.14     45.59  140033800     41.33453    53.33  47.190   41.05         45.3305      1    NA
# 2008-04-04    45.77    46.35   45.40     45.86  139261000     41.57934    52.84  46.945   41.05         44.9140     NA    NA
# 2008-04-07    46.14    46.41   45.65     45.76  102297100     41.48867    52.84  46.945   41.05         44.9140     NA    NA
# 2008-04-08    45.41    45.72   45.18     45.41   97435200     41.17133    52.84  46.945   41.05         44.9140     NA    NA
# 2008-04-09    45.47    45.49   44.63     44.90  127182300     40.70894    52.84  46.945   41.05         44.9140     NA     1
# 2008-04-10    44.93    45.84   44.93     45.54  112773800     41.28919    52.84  46.945   41.05         44.9140      1    NA
# 2008-04-11    45.02    45.10   44.12     44.28  120135400     40.14681    52.84  46.945   41.05         44.9140     NA     1
# 2008-04-14    44.21    44.48   43.95     44.08   89274600     39.96547    52.84  46.945   41.05         44.9140     NA    NA
# 2008-04-15    44.24    44.35   43.68     44.14  124232300     40.01989    52.84  46.945   41.05         44.9140     NA    NA
# 2008-04-16    44.69    45.48   44.65     45.37  134027900     41.13506    52.84  46.945   41.05         44.9140      1    NA
# 2008-04-17    45.42    45.47   44.98     45.27  124953100     41.04440    52.84  46.945   41.05         44.9140     NA    NA
# 2008-04-18    46.47    46.93   46.22     46.71  133022500     42.34999    52.84  46.945   41.05         44.9140     NA    NA
# 2008-04-21    46.62    47.08   46.49     47.04   83303200     42.64919    52.84  46.945   41.05         44.9140     NA    NA
# 2008-04-22    46.75    46.77   45.93     46.34  104689600     42.01453    52.84  46.945   41.05         44.9140     NA    NA
# 2008-04-23    46.68    47.06   46.27     46.85  131086200     42.47692    52.84  46.945   41.05         44.9140     NA    NA
# 2008-04-24    46.87    47.79   46.39     47.27  166509000     42.85772    52.84  46.945   41.05         44.9140     NA    NA
# 2008-04-25    47.32    47.35   46.57     47.15  121945400     42.74891    52.84  46.945   41.05         44.9140     NA    NA
# 2008-04-28    47.26    47.62   47.13     47.24   71244000     42.83052    52.84  46.945   41.05         44.9140     NA    NA
# 2008-04-29    47.15    47.76   47.06     47.60   91270600     43.15691    52.84  46.945   41.05         44.9140     NA    NA
# 2008-04-30    47.70    48.06   47.03     47.21  132152700     42.80332    52.84  46.945   41.05         44.9140     NA    NA
FXQuantTrader
  • 6,821
  • 3
  • 36
  • 67
  • thank you very much for your answer! I have a few more questions getting your advice now. Till the step add.indicator ist clear to me. Now i have a question to the add.signal part. I want to set up the long signal like you showed to me. the long position should be hold until the Close Price crosses the 0.85 * high.DCH from above. in my mind it should work with sigCrossover for the long signal entry and exit. How can i set these two Signals. Thank you for your time and advice??? – Ramon May 18 '18 at 14:02
  • Elaborate. Do you mean you enter as soon as the long signal is flagged (which this example does) and then exits when the long signal is no longer true? i.e. enter and stay long while close > 0.85 * high.DCH and then exit as soon as close < 0.85 * high.DCH? If so, this example already gets you most of the way, just a few minor tweaks... – FXQuantTrader May 18 '18 at 14:11
  • Yes exactly. i made it like this: `add.signal(strategy.st, name = "long_DC_signal", arguments = list( mktdata = quote(mktdata), ratio = 0.85), label = "channelUp")` `add.signal(strategy.st, name = "sigCross0ver", arguments = list( data = quote(mktdata), columns = "close", "DC.long.channelUp", relationship = "gt", cross = TRUE ), label = "long.sig") ` The error i get is # Error in sigComparison(label = label, data = data, columns = columns[c(i, : comparison of more than two columns not supported, see sigFormula – Ramon May 18 '18 at 14:26
  • @RamonHörler I've edited the strategy. I believe this strategy code now answers your original question fully? Your error comes partially because you're not using `c("close", "DC.long.channelUp")` as the `columns` argument. My code above gives an example of how to use crossover correctly. – FXQuantTrader May 24 '18 at 12:37
  • Thank you very much, now it works more or less. I have another question. Is it possible to get the signal from the quotes of the QQQ but when a Signal is generated, the rule should not buy the QQQ but buy the TQQQ which is leveraged. How can i set up a strategy like this? – Ramon May 25 '18 at 13:22
  • Try the edited code. it didn't like having an indicator column with "price" in it. Note now that the price entries do occur on the close. You can use the `prefer = "Open" argument in the `add.rule` argument list to make this change if you wish. – FXQuantTrader May 25 '18 at 13:35