Here is a reproducible example that I think does what you seek?
The strategy simply enters a long position if the RSI of the SPY
falls below 60, and exits the entire long position if the RSI crosses above 70. The max number of units that the long position can be is 1000 units.
Your code in osInvestAll
has some incorrect/redundant code, which I've omitted. This is a clean minimal order sizing function that(I think) does what you want.
Also, just a tip: you don't need to call updateAcct
and updateEndEq
on each long entry, in order to trade the current equity for the symbol in question, as this will add unnecessary extra computational time in bigger simulations.
osInvestAll <- function (data, timestamp, orderqty, ordertype, orderside, equity, portfolio, symbol, ruletype, ..., initEq) {
datePos <- format(timestamp,"%Y-%m-%d")
updatePortf(Portfolio=portfolio,Symbol=symbol,Dates=paste0(start(data), "/", datePos))
# After updating portfolio profit, we can extract the Net.Trading.PL earned up to datePos.
trading_pl <- sum(.getPortfolio(portfolio)$summary$Net.Trading.PL)
# The total equity in the strategy for this symbol (and this symbol only in isolation always, as this is how quantstrat by default works with applyStrategy)
equity <- initEq + trading_pl
ClosePrice <- getPrice(data, prefer = "Close")[datePos]
UnitSize <- as.numeric(trunc(0.25 * equity / ClosePrice))
UnitSize <- osMaxPos(data, timestamp, UnitSize, ordertype, orderside, portfolio, symbol, ruletype, digits=0)
UnitSize
}
library(quantstrat)
suppressWarnings(rm("order_book.RSI",pos=.strategy))
suppressWarnings(rm("account.RSI","portfolio.RSI",pos=.blotter))
suppressWarnings(rm("account.st","portfolio.st","stock.str","stratRSI","startDate","initEq",'start_t','end_t'))
strategy.st <- "RSI"
stratRSI <- strategy(strategy.st, store = TRUE)
add.indicator(strategy = strategy.st, name = "RSI", arguments = list(price = quote(getPrice(mktdata))), label="RSI")
add.signal(strategy = strategy.st, name="sigThreshold",arguments = list(threshold=70, column="RSI",relationship="gt", cross=TRUE),label="RSI.gt.70")
add.signal(strategy = strategy.st, name="sigThreshold",arguments = list(threshold=60, column="RSI",relationship="lt",cross=TRUE),label="RSI.lt.60")
add.rule(strategy = strategy.st, name='ruleSignal', arguments = list(sigcol="RSI.lt.60", sigval=TRUE, orderqty= 100, TxnFees=0, ordertype='market', orderside='long', pricemethod='market', replace=FALSE, osFUN=osInvestAll), type='enter', path.dep=TRUE)
add.rule(strategy = strategy.st, name='ruleSignal', arguments = list(sigcol="RSI.gt.70", sigval=TRUE, orderqty='all', TxnFees=0, ordertype='market', orderside='long', pricemethod='market', replace=FALSE), type='exit', path.dep=TRUE)
currency("USD")
symbols = c("SPY")
stock.str = symbols
startDate <- "1987-01-01"
getSymbols(stock.str,from=startDate, to= Sys.Date())
#getSymbols(stock.str,from=startDate, to= Sys.Date())
for(symbol in symbols){
stock(symbol, currency="USD",multiplier=1)
}
SPY <- SPY["2015/"]
startDate='1999-12-31'
initEq=100000
port.st<-'RSI'
initPortf(port.st, symbols=symbols)
initAcct(port.st, portfolios=port.st, initEq=initEq)
initOrders(portfolio=port.st)
# Must add maxpos:
for(symbol in symbols){ addPosLimit(port.st, symbol, timestamp = startDate, maxpos = 1000) }
applyStrategy(strategy=strategy.st, portfolios=port.st, initEq = initEq)
# > applyStrategy(strategy=strategy.st, portfolios=port.st, initEq = initEq)
# [1] "2015-03-01 19:00:00 SPY 118 @ 211.990005"
# [1] "2015-03-03 19:00:00 SPY 118 @ 210.229996"
# [1] "2015-05-25 20:00:00 SPY 117 @ 210.699997"
# [1] "2015-10-21 20:00:00 SPY 119 @ 205.210007"
# [1] "2015-11-09 19:00:00 SPY 119 @ 208.559998"
# [1] "2015-12-02 19:00:00 SPY 119 @ 205.610001"
# [1] "2016-03-08 19:00:00 SPY 116 @ 199.380005"
# [1] "2016-04-05 20:00:00 SPY 119 @ 206.419998"
# [1] "2016-04-07 20:00:00 SPY 55 @ 204.5"
# [1] "2016-11-27 19:00:00 SPY -1000 @ 220.479996"
# [1] "2016-12-01 19:00:00 SPY 129 @ 219.679993"
# [1] "2016-12-07 19:00:00 SPY -129 @ 225.149994"
# [1] "2016-12-28 19:00:00 SPY 127 @ 224.350006"
# [1] "2017-01-09 19:00:00 SPY 126 @ 226.460007"
# [1] "2017-01-12 19:00:00 SPY 126 @ 227.050003"
# [1] "2017-01-17 19:00:00 SPY 126 @ 226.75"
# [1] "2017-01-30 19:00:00 SPY 126 @ 227.529999"
# [1] "2017-02-13 19:00:00 SPY -631 @ 233.699997"
# [1] "2017-03-14 20:00:00 SPY 125 @ 238.949997"
# [1] "2017-03-19 20:00:00 SPY 124 @ 236.770004"
# [1] "2017-04-30 20:00:00 SPY 124 @ 238.679993"
# [1] "2017-05-14 20:00:00 SPY 124 @ 240.300003"
# [1] "2017-05-17 20:00:00 SPY 124 @ 236.770004"
# [1] "2017-06-04 20:00:00 SPY -621 @ 243.990005"
# [1] "2017-06-18 20:00:00 SPY 125 @ 244.660004"
# [1] "2017-06-20 20:00:00 SPY 125 @ 242.949997"
# [1] "2017-08-10 20:00:00 SPY 125 @ 244.119995"
# [1] "2017-09-05 20:00:00 SPY 124 @ 246.899994"
# [1] "2017-09-21 20:00:00 SPY 124 @ 249.440002"
updatePortf(Portfolio=port.st,Dates=paste('::',as.Date(Sys.time()),sep=''))
tradeStats(port.st, "SPY")
# Portfolio Symbol Num.Txns Num.Trades Net.Trading.PL Avg.Trade.PL Med.Trade.PL Largest.Winner Largest.Loser Gross.Profits Gross.Losses Std.Dev.Trade.PL Std.Err.Trade.PL Percent.Positive Percent.Negative Profit.Factor
# SPY RSI SPY 29 4 24581.97 5548.314 4063.635 13360.36 0 22193.25 0 5460.273 2730.136 100 0 NA
# Avg.Win.Trade Med.Win.Trade Avg.Losing.Trade Med.Losing.Trade Avg.Daily.PL Med.Daily.PL Std.Dev.Daily.PL Std.Err.Daily.PL Ann.Sharpe Max.Drawdown Profit.To.Max.Draw Avg.WinLoss.Ratio Med.WinLoss.Ratio Max.Equity Min.Equity
# SPY 5548.314 4063.635 NaN NA 5548.314 4063.635 5460.273 2730.136 16.13047 -19148.87 1.28373 NA NA 24946.23 -18349.48
# End.Equity
# SPY 24581.97
You can see in the output that at most 1000 units (long) ever exist in the strategy. And each trade is 25% of the current equity, when a long signal is fired.