braverock / quantstrat

289 stars 114 forks source link

problems in buying stocks below high/ open using ordertype="limit" #114

Closed kvekka closed 4 years ago

kvekka commented 4 years ago

Was trying to buy stocks at a certain price offset to the open price in a long position. A simple moving average rule - buy at price lower than the price at open when nFast is gte nSlow; sell when nSlow is gt nFast, taking cues from https://r.789695.n4.nabble.com/Quantstrat-Entering-a-limit-order-below-the-open-price-td4717350.html

Problem that is occurring is as follows: Order.Status on "2018-02-16" is "closed" but it should not be because, the Order.Price = "265.24377134782" which is not within the OHLC for the day after it. It is executed 2 days after, on 21st. SPY data SPY.Open SPY.High SPY.Low SPY.Close SPY.Volume SPY.Adjusted 2018-02-16 267.2438 270.1878 267.1947 268.0190 160420100 264.3314 2018-02-20 266.9592 268.5686 265.4577 266.3409 86369700 262.6763 2018-02-21 266.8316 269.5990 264.9081 265.0161 98883700 261.3698

mktdata is as follows: mktdata["2018-02-16::2018-02-21"] SPY.Open SPY.High SPY.Low SPY.Close SPY.Volume SPY.Adjusted SMA.nFast SMA.nSlow long short 2018-02-16 267.2438 270.1878 267.1947 268.0190 160420100 264.3314 264.3919 262.6681 1 NA 2018-02-20 266.9592 268.5686 265.4577 266.3409 86369700 262.6763 265.5813 262.8714 NA NA 2018-02-21 266.8316 269.5990 264.9081 265.0161 98883700 261.3698 266.3762 263.0450 NA NA

rules used to buy includes - ordertype ="limit", with threshold = 2

Code used is detailed below: library(dplyr) library(quantstrat)

init_date <- "2017-01-01" start_date <- "2017-01-01" end_date <- "2018-12-31" init_equity <- 1e6 # $10,000 .orderqty <- 100 Sys.setenv(TZ = "UTC") fast <- 5 slow <- 73 currency("USD") symbols <- symbol <- "SPY" stock(symbols, currency = "USD", multiplier = 1) for(symbol in symbols){getSymbols(Symbols = symbol, src = "yahoo",auto.assign=T,index.class = "POSIXct",from = start_date,to = end_date,adjust = T)} symbols %>% get() %>% chart_Series()

portfolio.st <- "Port.Luxor" account.st <- "Acct.Luxor" strategy.st <- "Strat.Luxor"

rm.strat(strategy.st) rm.strat(portfolio.st) rm.strat(account.st)

initPortf(name = portfolio.st, symbols = symbols, initDate = init_date)

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

initOrders(portfolio = portfolio.st, symbols = symbols, initDate = init_date)

strategy(strategy.st, store = TRUE)

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

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

add.signal(strategy = strategy.st, name="sigCrossover", arguments = list(columns = c("nFast", "nSlow"), relationship = "gte"), label = "long")

add.signal(strategy = strategy.st, name="sigCrossover", arguments = list(columns = c("nFast", "nSlow"), relationship = "lt"), label = "short")

add.rule(strategy.st, name = "ruleSignal", arguments = list(sigcol = "short", sigval = TRUE, orderside = "long", ordertype = "market", prefer = "Open", orderqty = "all", TxnFees = -10, replace = T), type = "exit", label = "Exit2SHORT")

add.rule(strategy = strategy.st, name = "ruleSignal", arguments = list(sigcol = "long", sigval = TRUE, orderqty = .orderqty, ordertype = "limit", orderside = "long", threshold = 2, prefer = "Open",

threshold = 0.01, #used to buy at 1% below open

                      # tmult = T, #used to buy at % below open 
                      TxnFees = -10,
                      replace = F),
     type = "enter",
     label = "EnterLONG")

applyStrategy(strategy = strategy.st, portfolios = portfolio.st) updatePortf(portfolio.st) daterange <- time(getPortfolio(portfolio.st)$summary)[-1] updateAcct(account.st, daterange) updateEndEq(account.st) tstats <- tradeStats(Portfolios = portfolio.st) tstats %>% t() chart.Posn(Portfolio = portfolio.st, Symbol = symbols, TA= c("add_SMA(n=fast, col='blue')", "add_SMA(n=slow, col='red')")) getOrderBook(portfolio.st)$Port.Luxor$SPY SPY[getOrderBook(portfolio.st)$Port.Luxor$SPY %>% index() %>% as.character()]

jaymon0703 commented 4 years ago

Hi @kvekka looks fine to me. Singal fires on 2018-02-16 and the order price (265.2438, or Open on 2018-02-16 minus order threshold of 2) is inside the OHLC on the day of the entry transaction, 2018-02-21.

image

jaymon0703 commented 4 years ago

The order status is "retrospectively" updated to "closed" on 2018-02-16, when the order is filled on 2018-02-21.

jaymon0703 commented 4 years ago

Hi @kvekka can we close this issue?

kvekka commented 4 years ago

Yes, sure, the issue can be closed. I was thinking that the limit order is either implemented on the next day (when the condition are satisfied) or cancelled (if the conditions are not satisfied). It seems that the order is carried over even further till the conditions are met or is replaced. Again, thank you for your valuable time.

jaymon0703 commented 4 years ago

No problem, thanks for confirming

braverock commented 4 years ago

Limit orders are GTC (good till canceled), not GTD (good today). You need to cancel an order if you don't want it in the market.

jaymon0703 commented 4 years ago

Good point thanks @braverock. FYI @kvekka the time in force (TIF) is documented in the help file for ?addOrder. You may find the other documentation rather insightful.

kvekka commented 4 years ago

Thank you @braverock and @jaymon0703 Your suggestions and guidances are really helpful.