2

I am trying to implement a 2 period RSI based strategy backtest in Pine Script. The idea is simple

Objective

  • 2 Period RSI crosses under 10, when 200 EMA is below the recent close, I go long on the next candle with a market order set to limit 2% less than previous candles close.
  • 2 Period RSI crosses over 90, or its been 10 bars since entry (whichever condition occurs first) I exit the trade.

The problem

So apparently pine script defaults to taking a long/short position on open of the next candle. But despite placing a market order by specifying the limit attribute the long position is entered at opening price of the next candle.

A few more details

Timeframe - 1Day

Ticker link - https://in.tradingview.com/chart/GDSsFCKq/# (Ticker - SBILIFE (NSE INDIA))

I am not sure what I am doing wrong here. Please help.

Code

//@version=4
strategy("2RSI Strategy by Larry Connor", overlay=true)
rsi_length = input(title="RSI Length", defval=2) 
buying_rsi_value = input(title="Buy at RSI Value", defval=5)
selling_rsi_value = input(title="Sell at RSI Value", defval= 40)
price = close
rsi = rsi(price, rsi_length)
buy = crossunder(rsi, buying_rsi_value)
sell = crossover(rsi, selling_rsi_value)

date = tostring(dayofmonth) + '-' + tostring(month) + '-' + tostring(year)
disable_date_ranges = input(title="Disable Date Ranges", defval=true)

start_date = input(title="Start Date", type=input.time, defval=timestamp("19 Oct 2020 
00:00 +0530"))
end_date = input(title="End Date", type=input.time, defval=timestamp("18 Oct 2021 
00:00 +0530"))
in_date_range = time >= start_date and time < end_date
    
ema_len = input(200, minval=1, title="EMA Length")
ema_src = input(close, title="EMA Source")
ema_200 = ema(ema_src, ema_len)

entry_condition= buy and ema_200 < price 

exit_condition = sell or entry_condition[10]

previous_day_close = close[1]
two_percent_of_prev_day_close = previous_day_close * 0.02
entry_price = previous_day_close - two_percent_of_prev_day_close

// plotchar(entry_condition, "debug", "", location.bottom)

capital_invested = input(title="Invested capital", defval=100000)
initial_capital = strategy.initial_capital
capital_to_be_invested = capital_invested
if(na(capital_invested) or capital_invested == 0)
    capital_to_be_invested = initial_capital

if (not na(rsi) and (in_date_range or disable_date_ranges))
    strategy.entry("buy", when=entry_condition and low < entry_price, limit= 
entry_price, long= true, qty = capital_to_be_invested/entry_price, comment="Long")
        
if (exit_condition)
    strategy.close("buy", true)
Abhishek
  • 1,101
  • 8
  • 8

2 Answers2

4

To confront this issue is to understand the processing of historical data, which is used in back testing. Historical data is 4 data points per candle (OHLC). Calculations for indicators are made using closing price typically, as well as we don’t have enough information about intra-bar price travel to make assumptions where or when an alert took place. Thus, we must rely on the closing condition for a given candle to establish variable states on the historical bar. In real time, we are confronted with similar issues only that we must wait for close to confirm a signal, or we suffer the affects of repainting. As such, the 2 data types (historical and real time) become aligned as one procedure - a candle close is a confirmed and actionable signal. To establish a closing price a candle would exhaust its last tick for the period. This means that our next actionable sale is the next sale available, which occurs in the first ticks of the bar following. This is why open prices are used in backtesting following a state change of a given variable. If a candle is closed how would we execute an order? As mentioned above, we could forgo this in real time, but to do so is to separate 2 differentiated behaviours of a strategy, which effectively makes the strategy unique, and not one we tested on historical data. Just a few of many caveats of strategy building :)

Cheers!

Bjorgum
  • 2,054
  • 2
  • 4
  • 11
  • Thank you Bjorgum for the answer. This kinda of relieves my anxiety. I've already spent days wondering if my code is buggy. Turns out I simply overlooked the fact that the prospects of limit order execution at an exact given price point in historical back testing are quite iffy unless the candle opens exactly at the limit price. Please do correct me if I've interpreted your answer incorrectly. – Abhishek Oct 22 '21 at 08:52
  • Yes a limit may not execute on a gap up, but either a limit order or a market order is still only actionable on the the bar following a signal as the candle has already closed. – Bjorgum Oct 22 '21 at 13:18
0

While I agree with the answer about only the high, low, open and close prices being used, and not the rest of the intraday movement, there is a way to get around that.

If you use the 'security' function you can load in data from different charts. This can be used for different stocks, but also for different timeframes.

So if you are trading on a day chart, you can use something like:

15minClose = security(systeminfo.tickerid, "15", close)

In this case you get the close data for the current symbol, for the 15 min candles, in the 1 day chart.

So if you want to enter trades in the middle of the day you can for example check against the 15m close prices while the other requirements are met?

For more info, you can look up the security function in the pine reference. https://www.tradingview.com/pine-script-reference/v4/#fun_security

Corove
  • 1
  • 2