Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

quantstrat, How could I put a stop-loss at a specific price?

Tags:

r

quantstrat

Good day!

Friends I really need your help!

My question is: How could I put a stop-loss at a specific price?

Quantstrat works like this (for long position): Stop price = entry price – entry price * threshold.

For example, I try to run my code. But StopLossLONG does not work.

How to write code for stop?

library('TTR')
library('blotter')
library("quantmod")
require(quantstrat)

from <- "2016-04-01"
to <- "2016-07-01"

SPY <- getSymbols.yahoo('SPY',
                        env = .GlobalEnv,
                        return.class = 'xts',
                        index.class = 'Date',
                        from = from,
                        to = to,
                        periodicity = "daily",
                        auto.assign = FALSE)

SPY <- SPY[, c(1, 2, 3, 4, 5)]
names(SPY) <- c('Open','High','Low','Close','Volume')

level <- function(ts, level) {
    ts$level <- level
    res <- ts$level
    names(res) <- c("")
    return(res)
}

rm(list = ls(.blotter), envir = .blotter)
symbols = "SPY"
currency('USD')
initDate = from
from = from
to = to
initEq = 100000
strName = "test"

stock(symbols, currency = "USD", tick_size = 0.001, multiplier = 1)
getInstrument(symbols, type = "instrument")

strategy.st <- strName
portfolio.st <- strName
account.st <- strName
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)

addPosLimit(portfolio.st, symbols, timestamp = initDate, maxpos = 1, minpos = -1)

# indicators

add.indicator(strategy.st, name = "level",
              arguments = list(ts = quote((mktdata)), level = 208.0),
              label = "LEV208")

add.indicator(strategy.st, name = "level",
              arguments = list(ts = quote((mktdata)), level = 212.0),
              label = "LEV212")

add.indicator(strategy.st, name = "level",
              arguments = list(ts = quote((mktdata)), level = 207.0),
              label = "LEV207")

# signals

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

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

# rules

add.rule(strategy.st, name = "ruleSignal",
         arguments = list(sigcol = "OPEN", sigval = TRUE,
                        orderside = "long",
                        ordertype = "market",
                        prefer = "Open",
                        orderqty = 1,
                        replace = FALSE,
                        osFUN = osMaxPos
         ),
         type = "enter",
         label = "LE"
)

add.rule(strategy.st, name = "ruleSignal",
         arguments = list(sigcol = "CLOSE", sigval = TRUE,
                        orderside = "long",
                        ordertype = "market",
                        prefer = "Open",
                        orderqty = "all",
                        replace = FALSE
         ),
         type = "exit",
         label = "LX"
)

add.rule(strategy.st,
         name = "ruleSignal",
         arguments = list(sigcol = "OPEN",
                          sigval = TRUE,
                          replace = FALSE,
                          orderside = "long",
                          ordertype = "stoplimit",
                          threshold = quote(0.005),
                          orderqty = "all",
                          orderset = "ocolong"),
         type = "chain",
         parent = "LE",
         label = "StopLossLONG",
         enabled = FALSE
)


applyStrategy(strategy.st, portfolio.st)
save.strategy(strategy.st)

orderbook <- getOrderBook(portfolio.st)
orderbook

Thank you!

like image 452
Anatolye Avatar asked Oct 23 '25 18:10

Anatolye


1 Answers

Your code has some odd settings which I'll point out in case it is part of your problem:

1) You have set enabled = FALSE for the stop rule with label StopLossLONG, so this rule would not be applied regardless.

2) It seems SPY never reaches 208 in your data period, so you won't get any long entry trades.

You ask if you can set a stop at a specific price. After reading your question carefully I think you mean can I set a stop at some absolute level, like 0.005 here? Rather than some absolute level of "entry price - some threshold amount". Yes, you can, if you modify ruleSignal. This is why name = 'ruleSignal is exposed in the add.rule function ... so you can make your own tweaks to how the orders are generated.

Here is an example, where your entry is now at 202 which permits one trade in your example. It sets a stop level at 9.999 (you could set any absolute price level below your entry price). I've added comments to the function ruleSignalAbsoluteStopPrice, which will replace ruleSignal. You can use any function you want, provided you have the correct expected arguments (like those for ruleSignal), and you call addOrder (or something like addOrder if you want to use a modified version of this function too ... but you need to understand the quantstrat source before doing this).

If you want to understand how to modify ruleSignal in a way that is correct in relation to the rest of the existing quantstrat code, try placing browser() inside ruleSignal and step line by line to see what you need to change to make things work correctly.

See the comments I've added, where I've tweaked parts of the existing ruleSignal code.

library('TTR')
library('blotter')
library("quantmod")
require(quantstrat)

# Define new function to replace 'ruleSignal' for long stoplimit orders:

ruleSignalAbsoluteStopPrice <- function (mktdata = mktdata, timestamp, sigcol, sigval, orderqty = 0,
                                         ordertype, orderside = NULL, orderset = NULL, threshold = NULL,
                                         tmult = FALSE, replace = TRUE, delay = 1e-04, osFUN = "osNoOp",
                                         pricemethod = c("market", "opside", "active"), portfolio,
                                         symbol, ..., ruletype, TxnFees = 0, prefer = NULL, sethold = FALSE,
                                         label = "", order.price = NULL, chain.price = NULL, time.in.force = "",
                                         absoluteStopPrice = 9.999)
{

    if (!is.function(osFUN))
        osFUN <- match.fun(osFUN)
    if (hasArg(curIndex))
        curIndex <- eval(match.call(expand.dots = TRUE)$curIndex,
                         parent.frame())
    else curIndex <- mktdata[timestamp, which.i = TRUE]
    # Just for long orderside and stoplimit order types.
    if (curIndex > 0 && curIndex <= nrow(mktdata) && ordertype == "stoplimit" && orderside == "long" && (ruletype ==
                                                                                                         "chain" )) {
        pricemethod <- pricemethod[1]
        if (hasArg(prefer))
            prefer = match.call(expand.dots = TRUE)$prefer
        else prefer = NULL

        # chain.price is the transaction price of the long trade.
        # Handle the case where the price may be less than your absolute stop level (here we skip entering a long position):
        if (chain.price <= absoluteStopPrice)
            return()

        threshold <- chain.price - absoluteStopPrice
        # Ensure that tmult = FALSE when using this approach.

        if (is.null(orderside) & !isTRUE(orderqty == 0)) {
            curqty <- getPosQty(Portfolio = portfolio, Symbol = symbol,
                                Date = timestamp)
            if (curqty > 0) {
                orderside <- "long"
            }
            else if (curqty < 0) {
                orderside <- "short"
            }
            else {
                if (orderqty > 0)
                    orderside <- "long"
                else orderside <- "short"
            }
        }
        if (orderqty == "all") {
            if (orderside == "long") {
                tmpqty <- 1
            }
            else {
                tmpqty <- -1
            }
        }
        else {
            tmpqty <- orderqty
        }
        if (!is.null(order.price)) {
            orderprice <- order.price
        }
        else if (!is.null(chain.price)) {
            orderprice <- chain.price
        }
        else {

        }
        if (is.null(orderset))
            orderset = NA
        if (orderqty != "all") {
            orderqty <- osFUN(strategy = strategy, data = mktdata,
                              timestamp = timestamp, orderqty = orderqty, ordertype = ordertype,
                              orderside = orderside, portfolio = portfolio,
                              symbol = symbol, ... = ..., ruletype = ruletype,
                              orderprice = as.numeric(orderprice))
        }
        if (!is.null(orderqty) && orderqty != 0 && length(orderprice)) {

            # All the arguments passed to `addOrder` are reasonable, and similar to what ruleSignal expects
            addOrder(portfolio = portfolio, symbol = symbol,
                     timestamp = timestamp, qty = orderqty, price = as.numeric(orderprice),
                     ordertype = ordertype, side = orderside, orderset = orderset,
                     threshold = threshold, status = "open", replace = replace,
                     delay = delay, tmult = tmult, ... = ..., prefer = prefer,
                     TxnFees = TxnFees, label = label, time.in.force = time.in.force)
        }
    }
    if (sethold)
        hold <<- TRUE
}



from <- "2016-04-01"
to <- "2016-07-01"

SPY <- getSymbols.yahoo('SPY',
                        env = .GlobalEnv,
                        return.class = 'xts',
                        index.class = 'Date',
                        from = from,
                        to = to,
                        periodicity = "daily",
                        auto.assign = FALSE)

SPY <- SPY[, c(1, 2, 3, 4, 5)]
names(SPY) <- c('Open','High','Low','Close','Volume')

level <- function(ts, level) {
    ts$level <- level
    res <- ts$level
    names(res) <- c("")
    return(res)
}

rm(list = ls(.blotter), envir = .blotter)
symbols = "SPY"
currency('USD')
initDate = from
from = from
to = to
initEq = 100000
strName = "test"

stock(symbols, currency = "USD", tick_size = 0.001, multiplier = 1)
getInstrument(symbols, type = "instrument")

strategy.st <- strName
portfolio.st <- strName
account.st <- strName
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)

addPosLimit(portfolio.st, symbols, timestamp = initDate, maxpos = 1, minpos = -1)

# indicators

# Set the level to 202 to allow one entry trade at least:

add.indicator(strategy.st, name = "level",
              arguments = list(ts = quote((mktdata)), level = 202.0),
              label = "LEV202")

add.indicator(strategy.st, name = "level",
              arguments = list(ts = quote((mktdata)), level = 212.0),
              label = "LEV212")

add.indicator(strategy.st, name = "level",
              arguments = list(ts = quote((mktdata)), level = 207.0),
              label = "LEV207")

# signals

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

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

# rules

add.rule(strategy.st, name = "ruleSignal",
         arguments = list(sigcol = "OPEN", sigval = TRUE,
                          orderside = "long",
                          ordertype = "market",
                          prefer = "Open",
                          orderqty = 1,
                          replace = FALSE,
                          osFUN = osMaxPos
         ),
         type = "enter",
         label = "LE"
)

add.rule(strategy.st, name = "ruleSignal",
         arguments = list(sigcol = "CLOSE", sigval = TRUE,
                          orderside = "long",
                          ordertype = "market",
                          prefer = "Open",
                          orderqty = "all",
                          replace = FALSE
         ),
         type = "exit",
         label = "LX"
)

add.rule(strategy.st,
         name = "ruleSignalAbsoluteStopPrice",
         arguments = list(sigcol = "OPEN",
                          sigval = TRUE,
                          replace = FALSE,
                          orderside = "long",
                          ordertype = "stoplimit",
                          #threshold = quote(0.005),  don't bother setting threshold argument as ruleSignalAbsoluteStopPrice won't used the passed in argument 'threshold'.
                          absoluteStopPrice = 9.999, # Demonstrat that we can use new arguments related to the `ruleSignalAbsoluteStopPrice`` function
                          tmult = FALSE, # tmult is potentially used in `addOrder`
                          orderqty = "all",
                          orderset = "ocolong"),
         type = "chain",
         parent = "LE",
         label = "StopLossLONG",
         enabled = TRUE # Enable this rule
)


applyStrategy(strategy.st, portfolio.st)
save.strategy(strategy.st)

orderbook <- getOrderBook(portfolio.st)
orderbook

Now check you get what you expected (a stoplimit at the price 9.999):

> orderbook
$test
$test$SPY
           Order.Qty Order.Price Order.Type  Order.Side Order.Threshold Order.Status Order.StatusTime      Prefer Order.Set Txn.Fees Rule           Time.In.Force
2016-04-13 "1"       "201.827"   "market"    "long"     NA              "closed"     "2016-04-14 00:00:00" "Open" NA        "0"      "LE"           ""           
2016-04-14 "all"     "9.999"     "stoplimit" "long"     "-192.812707"   "open"       NA                    ""     "ocolong" "0"      "StopLossLONG" ""  

And we see the trade is still open:

> getTxns(portfolio.st, "SPY")
                    Txn.Qty Txn.Price Txn.Fees Txn.Value Txn.Avg.Cost Net.Txn.Realized.PL
2016-04-01 00:00:00       0      0.00        0      0.00         0.00                   0
2016-04-13 20:00:00       1    202.87        0    202.87       202.87                   0

Hope this helps.

like image 140
FXQuantTrader Avatar answered Oct 26 '25 07:10

FXQuantTrader



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!