Quantstrat, How can I put a stop loss at a specific price?
Good day!
Friends I really need your help!
My question is: How can I put a stop loss at a specific price?
Quantstrat works like this (for a long position): Stop price = initial price - entry price threshold *.
For example, I am trying to run my code. But StopLossLONG doesn't work.
How do I write the code to 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!
source to share
There are some odd settings in your code that I will point out if this is part of your problem:
1) You have set the enabled = FALSE
label to break rule StopLossLONG
, so this rule will not apply regardless.
2) It SPY
never seems to reach 208 during your data period, so you won't receive long input transactions.
You ask if you can set a stop at a specific price. After reading your question carefully, I think you mean that I can stop stopping at some absolute level like 0.005? Instead of some absolute level "initial price - some threshold value". Yes you can if you change ruleSignal
. This is why it name = 'ruleSignal
appears in the function add.rule
... so you can make your own settings for creating orders.
Here's an example where your entry is now at 202, which allows one trade in your example. It sets the stop level at 9.999 (you can set any absolute price level below your entry price). I have added comments to the function ruleSignalAbsoluteStopPrice
that will replace ruleSignal
. You can use any function you want, as long as you have the correct expected arguments (for example for ruleSignal) and you are calling addOrder
(or something like addOrder
if you want to use a modified version of that function ... but you need to understand the source of the quantumstratum before than to do it).
If you want to figure out how to change ruleSignal
in a way that is correct with respect to the rest of the existing quantumstrat code, try placing browser()
Signal inside the rule and step by line to see what you need to change in order for everything to work correctly.
See the comments I added where I changed parts of the existing code ruleSignal
.
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 if you get what you expected (stoplimit at 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 can see that 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 it helps.
source to share