I am working on a basic RSI trading signal. Buy 100 shares when stock goes below 20 RSI and close position when stock goes above 80 RSI.
What's happening is, once the stock goes below 20 I buy 100 shares, if the stock crosses below 20 again without first going to 80 RSI, I end up buying another 100 shares (total 200).
Once I have a position on, I do not want to add to it. Thank you.
rm.strat(portfolio.st)
rm.strat(strategy.st)
rm.strat(account.st)
#setup
Sys.setenv(TZ = "UTC")
stock.str = "AAPL"
currency('USD')
stock("AAPL", currency= "USD", multiplier = 1)
initDate = "2010-01-01"
startDate = "2011-01-01"
to = Sys.Date()
initEq = 100000
portfolio.st = account.st = strategy.st = 'rsi'
getSymbols("AAPL", from = initDate)
initPortf(portfolio.st, symbols = stock.str,
initDate = initDate)
initAcct(account.st,
portfolio.st,
initDate = initDate, initEq = initEq)
initOrders(portfolio.st, initDate = initDate)
strategy(strategy.st, store = T)
add.indicator(strategy.st,
name = "RSI",
arguments = list(
price = quote(Cl(mktdata)),
n = 14,
maType = "EMA"
),
label = "rsi14")
add.signal(strategy.st,
name = "sigThreshold",
arguments = list(
column = "rsi14",
threshold = 20,
cross = T,
relationship = "lt"
),
label = "crossBelow")
add.signal(strategy.st,
name = "sigThreshold",
arguments = list(
column = "rsi14",
threshold = 80,
cross = T,
relationship = "gt"
),
label = "crossAbove")
add.rule(strategy.st,
name = "ruleSignal",
arguments = list(
sigcol = "crossBelow",
sigval = T,
orderqty = 100,
ordertype = "market",
orderside = "long"
),
type = "enter",
label = "enter")
add.rule(strategy.st,
name = "ruleSignal",
arguments = list(
sigcol = "crossAbove",
sigval = T,
orderqty = "all",
ordertype = "market",
orderside = "long"),
type = "exit",
label = "exit"
)
out = applyStrategy(strategy.st,
portfolio.st)
One thing you could do is consider writing your own order sizing function. This gets passed to quanstrat in add.rule
as a parameter - osFUN
.
Something like this:
my_sizing_fun <- function(data, timestamp, symbol, portfolio, ...) {
equity <- getEndEq(strategy.st, Date = timestamp)
# Get current Position and return 0 if we already have a position
pos <- getPosQty(portfolio, symbol, timestamp)
if(pos != 0) {
return(0)
} else {
return(100)
}
This will return 0 if you already have a position, or 100 otherwise. You can do some pretty complicated stuff inside the order sizing functions to help enhance your strategy.
Now just add osFUN=my_sizing_fun
as an argument inside add.rule
and remove orderqty
and you should be all set.
When you start to want to play around with going short or dealing with your current equity values the following is a helpful example:
### Order Size Function ###
## Calculates Order Size as a percent risk of account equity - currently does not account for multiple symbols or a max trade size like we may implement in real life
## Takes in arguments passed from 'RuleSignal'
## riskPct is the percentage of account equity to risk per trade
## Returns the order quantity as a numeric value
## to do - round order qty to lot sizes
osATR <- function(data, orderside, timestamp, symbol, portfolio, riskPct, ...) {
# Update Accounts and get the Ending Equity
updatePortf(strategy.st)
updateAcct(strategy.st)
updateEndEq(strategy.st)
equity <- getEndEq(strategy.st, Date = timestamp)
# Get current Position and return 0 if we already have a position
pos <- getPosQty(portfolio, symbol, timestamp)
if(pos != 0) {
return(0)
}
# Calculate Order Quantity
qty <- # Add your logic here
qty <- as.numeric(trunc(qty)) # return a numeric and round the qty
# Long / Short Check & Set
if(orderside == "short") {
qty <- -qty
}
# Make sure not to end up with net positions on the wrong side
if (orderside == 'long' && qty < 0 | orderside == 'short' && qty > 0) {
stop("orderqty is of the wrong sign")
}
return(qty)
}