Okay, so my issue is that I'm trying to debunk a trading system I found
online, and it involves using an indicator for a stop-loss and a
take-profit type of order. I based my syntax on the luxor demo, aside from
using an order.price argument, but I'm not sure of how to make the exact
syntax work.

Here's a minimum reproducible example.

**************************************************************************************

hammer <- function(OHLC, profMargin=1.5) {
  dailyMax <- pmax(Op(OHLC), Cl(OHLC))
  dailyMin <- pmin(Op(OHLC), Cl(OHLC))
  upShadow <- Hi(OHLC) - dailyMax
  dnShadow <- dailyMin - Lo(OHLC)
  body <- dailyMax-dailyMin
  hammerDay <- dnShadow/body > 2 & dnShadow/upShadow > 5
  hammers <- OHLC[hammerDay==1,]
  hammers$stopLoss <- 4/3*Lo(hammers)-1/3*Hi(hammers)
  hammers$takeProfit <- Hi(hammers) +
(Hi(hammers)-hammers$stopLoss)*profMargin
  hammers <- cbind(hammerDay, hammers$stopLoss, hammers$takeProfit)
  hammers$stopLoss <- na.locf(hammers$stopLoss)
  hammers$takeProfit <- na.locf(hammers$takeProfit)
  colnames(hammers) <- c("hammer", "SL", "TP")
  return(hammers)
}

sigAND <- function(label, data=mktdata, columns,  cross = FALSE) {
  ret_sig = NULL
  colNums <- rep(0, length(columns))
  for(i in 1:length(columns)) {
    colNums[i] <- match.names(columns[i], colnames(data))
  }
  ret_sig <- data[, colNums[1]]
  for(i in 2:length(colNums)) {
    ret_sig <- ret_sig & data[, colNums[i]]
  }
  ret_sig <- ret_sig*1
  if (isTRUE(cross))
    ret_sig <- diff(ret_sig) == 1
  colnames(ret_sig) <- label
  return(ret_sig)
}

lagATR <- function(HLC, n=14, maType, lag=1, ...) {
  ATR <- ATR(HLC, n=n, maType=maType, ...)
  ATR <- lag(ATR, lag)
  out <- ATR$atr
  colnames(out) <- "atr"
  return(out)
}

osDollarATR <- function(orderside, tradeSize, pctATR, maxPctATR=pctATR,
data, timestamp, symbol,
         prefer="Open", portfolio, integerQty=TRUE, atrMod="", rebal=FALSE,
...) {
  if(tradeSize > 0 & orderside == "short"){
    tradeSize <- tradeSize*-1
  }
  pos <- getPosQty(portfolio, symbol, timestamp)
  atrString <- paste0("atr",atrMod)
  atrCol <- grep(atrString, colnames(mktdata))
  if(length(atrCol)==0) {
    stop(paste("Term", atrString, "not found in mktdata column names."))
  }
  atrTimeStamp <- mktdata[timestamp, atrCol]
  if(is.na(atrTimeStamp) | atrTimeStamp==0) {
    stop(paste("ATR corresponding to",atrString,"is invalid at this point
in time.
               Add a logical operator to account for this."))
  }
  dollarATR <- pos*atrTimeStamp
  desiredDollarATR <- pctATR*tradeSize
  remainingRiskCapacity <- tradeSize*maxPctATR-dollarATR

  if(orderside == "long"){
    qty <- min(tradeSize*pctATR/atrTimeStamp,
remainingRiskCapacity/atrTimeStamp)
  } else {
    qty <- max(tradeSize*pctATR/atrTimeStamp,
remainingRiskCapacity/atrTimeStamp)
  }

  if(integerQty) {
    qty <- trunc(qty)
  }
  if(!rebal) {
    if(orderside == "long" & qty < 0) {
      qty <- 0
    }
    if(orderside == "short" & qty > 0) {
      qty <- 0
    }
  }
  if(rebal) {
    if(pos == 0) {
      qty <- 0
    }
  }
  return(qty)
}

require(quantstrat)
require(PerformanceAnalytics)

initDate="1990-01-01"
from="2003-01-01"
to=as.character(Sys.Date())
options(width=70)
verbose=TRUE

options("getSymbols.warning4.0"=FALSE)
rm(list=ls(.blotter), envir=.blotter)

currency('USD')
Sys.setenv(TZ="UTC")
symbols <- c("XLB")
suppressMessages(getSymbols(symbols, from=from, to=to, src="yahoo",
adjust=TRUE))
stock(symbols, currency="USD", multiplier=1)

#trade sizing and initial equity settings
tradeSize <- 100000
initEq <- tradeSize*length(symbols)

strategy.st <- portfolio.st <- account.st <- "Hammer_4TP"
rm.strat(portfolio.st)
rm.strat(strategy.st)
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)

#parameters
nSMA1=10
nSMA2=30
nSMA3=5
profMargin=1.8

period=10
pctATR=.1


#indicators
add.indicator(strategy.st, name="lagATR",
              arguments=list(HLC=quote(HLC(mktdata)), n=period),
              label="atrX")

add.indicator(strategy.st, name="hammer",
              arguments=list(OHLC=quote(OHLC(mktdata)),
profMargin=profMargin),
              label="hammer")

add.indicator(strategy.st, name="SMA",
              arguments=list(x=quote(Cl(mktdata)), n=nSMA1),
              label="sma1")

add.indicator(strategy.st, name="SMA",
              arguments=list(x=quote(Cl(mktdata)), n=nSMA2),
              label="sma2")

add.indicator(strategy.st, name="SMA",
              arguments=list(x=quote(Cl(mktdata)), n=nSMA3),
              label="sma3")
#signals
add.signal(strategy.st, name="sigComparison",
           arguments=list(columns=c("SMA.sma1", "SMA.sma2"),
relationship="gt"),
           label="upTrend")

add.signal(strategy.st, name="sigComparison",
           arguments=list(columns=c("SMA.sma3", "SMA.sma1"),
relationship="lt"),
           label="pullback")

add.signal(strategy.st, name="sigThreshold",
           arguments=list(column="hammer.hammer", threshold=.5,
                          relationship="gt", cross=TRUE),
           label="hammerDay")

add.signal(strategy.st, name="sigAND",
           arguments=list(columns=c("upTrend", "pullback", "hammerDay"),
                          cross=TRUE),
           label="longEntry")

add.signal(strategy.st, name="sigCrossover",
           arguments=list(columns=c("Close", "SL.hammer"),
relationship="lt"),
           label="stopExit")

add.signal(strategy.st, name="sigCrossover",
           arguments=list(columns=c("Close", "TP.hammer"),
relationship="gt"),
           label="profitExit")

add.signal(strategy.st, name="sigCrossover",
           arguments=list(columns=c("SMA.sma1", "SMA.sma2"),
relationship="lt"),
           label="SMAexit")
#rules
add.rule(strategy.st, name="ruleSignal",
         arguments=list(sigcol="longEntry",
                        sigval=TRUE,
                        ordertype="stoplimit",
                        orderside="long",
                        replace=FALSE,
                        osFUN=osDollarATR,
                        tradeSize=tradeSize,
                        prefer="High",
                        pctATR=pctATR,
                        atrMod="X",
                        orderset="orders"),
         type="enter", path.dep=TRUE)

add.rule(strategy.st, name="ruleSignal",
         arguments=list(sigcol="longEntry",
                        sigval=TRUE,
                        ordertype="stoplimit",
                        orderside="long",
                        replace=FALSE,
                        pctATR=pctATR,
                        orderqty='all',
                        order.price=quote(mktdata$SL.hammer[timestamp])
                        orderset="orders"),
         type="chain",
         parent="longEntry",
         label="stopLossLong",
         path.dep=TRUE)

add.rule(strategy.st, name="ruleSignal",
         arguments=list(sigcol="longEntry",
                        sigval=TRUE,
                        ordertype="stoplimit",
                        orderside="long",
                        replace=FALSE,
                        pctATR=pctATR,
                        orderqty='all',
                        order.price=quote(mktdata$TP.hammer[timestamp]),
                        orderset="orders"),
         type="chain",
         parent="longEntry",
         label="takeProfitLong",
         path.dep=TRUE)

# add.rule(strategy.st, name="ruleSignal",
#          arguments=list(sigcol="stopExit", sigval=TRUE, orderqty="all",
ordertype="market",
#                         orderside="long", replace=FALSE, prefer="Open",
orderset="orders"),
#          type="exit", path.dep=TRUE)
#
# add.rule(strategy.st, name="ruleSignal",
#          arguments=list(sigcol="profitExit", sigval=TRUE, orderqty="all",
ordertype="market",
#                         orderside="long", replace=FALSE, prefer="Open",
orderset="orders"),
#          type="exit", path.dep=TRUE)
#
# add.rule(strategy.st, name="ruleSignal",
#          arguments=list(sigcol="SMAexit", sigval=TRUE, orderqty="all",
ordertype="market",
#                         orderside="long", replace=FALSE, prefer="Open",
orderset="orders"),
#          type="exit", path.dep=TRUE)

#apply strategy
t1 <- Sys.time()
out <- applyStrategy(strategy=strategy.st,portfolios=portfolio.st)
t2 <- Sys.time()
print(t2-t1)

#set up analytics
updatePortf(portfolio.st)
dateRange <- time(getPortfolio(portfolio.st)$summary)[-1]
updateAcct(portfolio.st,dateRange)
updateEndEq(account.st)

chart.Posn(portfolio.st, "XLB")
add_TA(SMA(Cl(XLB), n=nSMA1), on=1, lwd=1.5, col="blue")
add_TA(SMA(Cl(XLB), n=nSMA2), on=1, lwd=1.5, col="purple")
add_TA(SMA(Cl(XLB), n=nSMA3), on=1, lwd=1.5, col="orange")
tmp <- hammer(OHLC=OHLC(XLB), profMargin=profMargin)
add_TA(tmp$hammer)
add_TA(tmp$SL, on=1, col="red", lwd=1.5)
add_TA(tmp$TP, on=1, col="green", lwd=1.5)

***************************************************************************************************

Right now, my exit rules aren't working. Commented out are a couple of
market orders that wait for the exit day to actually pass, and are
therefore delayed a day in terms of stopping out or taking a profit.

My question is what is the correct syntax to get my formal chain orders to
work properly and use the actual market data columns for their stopping
values?

Thanks.

	[[alternative HTML version deleted]]

