quantstrat in R: Setting a date based exit signal
Asked Answered
A

1

9

Much of quantstrat and the accompanying examples seem to be set around entering and exiting trades by crossing some kind of technical indicator.

However, let's say you have an arbitrary indicator which you're using to trigger an entry to the trade, but then you want to just unwind the trade on the next day's open or close. How would you best implement this example?

Let's take the following example:

  • Two instruments: XYZ and ABC
  • Entry Signal: Can be anything - we just want to enter the trade any time our "signal" evaluates to true. For this example, let's say any time the ratio of XYZ/ABC changes by more than 1% in either direction from Open to Close on T+0
  • Exit Signal: A market event such as an Open or Close. Let's say, in this example, we want to unwind the trade we set above at the next day's open.

For instance, writing something like this using blotter would be relatively easy:

Assume xts object called ratio with columns for:

  1. ABC OHLC,
  2. XYZ OHLC,
  3. the ratio of ABC/XYZ expressed as an OHLC
  4. currency OHLC "CCY" (this is a cross currency pair)
  5. our indicator (the OpCl(ABC/XYZ)),
  6. "signal up?" which will evaluate to 1 if the indicator is > 1%, else 0 if not
  7. "signal dn?" which will evaluate to 1 if the indicator is < -1%, else 0 if not

Our code would then be:

for( i in 1:nrow(ratio) ) {

  ## Define the dates:

  CurrentDate <- index(ratio[i,])

  NextDate <- index(ratio[i+1,])

  ## Define the prices:

  XYZClosePrice <- as.numeric(ratio$XYZ.Close[i,])
  ABCClosePrice <- as.numeric(ratio$ABC.Close[i,])

  XYZOpenPrice <- as.numeric(ratio$XYZ.Open[i+1,])
  ABCOpenPrice <- as.numeric(ratio$ABC.Open[i+1,])

  CCYClosePrice <- as.numeric(ratio$CCY.Close[i,])
  CCYOpenPrice <- as.numeric(ratio$CCY.Open[i+1,])


  ## Define the spread:      

  SpreadOp <- ABCOpenPrice/XYZOpenPrice
  SpreadCl <- ABCClosePrice/XYZClosePrice

  ## Define the hedge ratio (let's say XYZ has a multiplier of 25 and ABC of 50)

  HedgeOp <- 25 * ((CCYOpenPrice/50)/SpreadOp)
  HedgeCl <- 25 * ((CCYClosePrice/50)/SpreadCl)

  # We want to trade 20 lots of XYZ each time with the corresponding hedge amount of   ABC
  Posn <- round(20 * HedgeCl,0)

  ## Add the trading rules (if move > 1% / else move <-1%):     

  # >= +1 % move

  if(ratio[i,'signal up?']==1){


    ## enter position on today's close

    addTxn(strat.name, Symbol='XYZ', TxnDate=CurrentDate,
           TxnPrice=XYZClosePrice, TxnQty = 20 , TxnFees=0)
    addTxn(strat.name, Symbol='ABC', TxnDate=CurrentDate,
           TxnPrice=ABCClosePrice, TxnQty = - Posn , TxnFees=0)

    ## exit position tomorrow's open

    addTxn(strat.name, Symbol='XYZ', TxnDate=NextDate,
           TxnPrice=XYZOpenPrice, TxnQty = - 20, TxnFeABC=0)
    addTxn(strat.name, Symbol='ABC', TxnDate=NextDate,
           TxnPrice=ABCOpenPrice, TxnQty = Posn , TxnFeABC=0)}

  else {

    # <= -1% move
    if(ratio[i,'signal dn?']==1){

      ## enter position on today's close

      addTxn(strat.name, Symbol='XYZ', TxnDate=CurrentDate,
             TxnPrice=XYZClosePrice, TxnQty = -20 , TxnFees=0)
      addTxn(strat.name, Symbol='ABC', TxnDate=CurrentDate,
             TxnPrice=ABCClosePrice, TxnQty =  Posn , TxnFees=0)

      # exit position on tomorrow's open

      addTxn(strat.name, Symbol='XYZ', TxnDate=NextDate,
             TxnPrice=XYZOpenPrice, TxnQty =  20, TxnFees=0)
      addTxn(strat.name, Symbol='ABC', TxnDate=NextDate,
             TxnPrice=ABCOpenPrice, TxnQty =  - Posn , TxnFees=0)}

  }

This works just fine.

But let's say we want to implement this in quantstrat -- it gets a bit trickier. Assuming all portfolios, accounts, indicators and signals etc are set up correctly, i would then add these trading rules to enter the trade:

> strat <- add.rule(strat, name='ruleSignal',
+                   arguments = list(sigcol="Cl.gt.1pct", sigval=TRUE, orderqty=20,
+                                    ordertype='market', orderside='long', pricemethod='market'),
+                   type='enter', path.dep=TRUE,symbol='XYZ')


> strat <- add.rule(strat, name='ruleSignal',
+                   arguments = list(sigcol="Cl.lt.1pct", sigval=TRUE, orderqty=Posn,
+                                    ordertype='market', orderside='short', pricemethod='market'),
+                   type='enter', path.dep=TRUE,symbol='ABC')

My question is: How do I enter the next two ruleSignal 's to simply unwind the pair on the next day's open?

I know it probably has something to do with the timestamp argument in ruleSignal but I can't figure out how I'd implement it.

There may be a very simple solution here, but I've caught myself in a bit of a loop trying to solve this one.

As ever, any help very much appreciated.

Aftertime answered 4/5, 2012 at 1:41 Comment(2)
Note - I'm also trying to work on a sigComparison based solution to evaluate date comparisons (ie if today's date is yesterday's date plus one workday and there is an existing position, exit the trade"Aftertime
You may get better luck at quant.stackexchange.com though there is a healthy R contingency of finance folks here too.Pargeting
U
6

quantstrat, as described in the manual, is a signals-based framework. It is not designed for filters based trades really.

You could do what you want by using the delay argument to your exit rule. Set the delay to be one day, and the prefer argument to prefer a different price column.

I'm not going to write it for you, but that is enough information to solve your problem.

Unfailing answered 4/5, 2012 at 13:15 Comment(5)
Thanks, Brian. Appreciate the hint. I think the ability to combine signals along with a filter is a great dev direction. Would love to be able to contribute. Is there any chance you guys will move the development from r-forge to somewhere like github?Aftertime
@n.e.w: That's a high fixed cost, so chances are slim.Spheroidal
@JoshuaUlrich in terms of dollar cost or just the time and hassle of shifting the codebase / adapting your workflows etc?Aftertime
@JoshuaUlrich understandable. thanks to all of you for your great work on the various packages you've produced. top notch stuff.Aftertime
@Brian G. Peterson, unfortunately I found that this solution does not work in general. To give a simple example, suppose we have daily data. We enter a position on day 1 and then use delay = 2 to exit on day 3. quantstrat will then add both of these transactions. But now suppose a new entry is triggered on day 2. Then when quantstrat calls addTxn it will give the error: Transactions must be added in order. So is there another way to make a date based exit rule?Watercolor

© 2022 - 2024 — McMap. All rights reserved.