Search code examples
pine-scriptdelay

How to implement delayed entry into the strategy by number of bars?


everyone. I'm learning PineScript and have encountered a silly problem. I have a strategy, PineScript 5 version. Now the minimum task for me is to delay entry into any position by 1 bar. Code example:

//Entry conditions
goLong = crossover(src,highband)
goShort = crossunder(src,lowband)
//
//Set the calculation interval
isinrange = (fixedstart?time>=backtest_start:true) and (fixedend?time<=backtest_end:true)
//
//Find out if the position is open and record it
var float position_size = 0.0
if strategy.position_size != 0
    position_size := strategy.position_size
//
//Marker for delayed notification
var nb = 0
//
// Long Entrys
if goLong and isinrange
    if position_size < 0
        strategy.close("Short", comment="Exit S", qty=abs(position_size))//first we close the open short
    nb := 1   
    strategy.entry("Long", true)
//
//Long Alerts delay of one bar
if nb[1] == 1 and labelalert 
    alert(syminfo.tickerid+" Long Signal",alert.freq_once_per_bar_close)
    nb := 0
//
// Short Entrys
if goShort and isinrange
    if position_size > 0
        strategy.close("Long", comment="Exit L", qty=abs(position_size))//first we close the open long
    nb := 2        
    strategy.entry("Short", false)
//
//Short Alerts delay of one bar
if nb[1] == 2 and labelalert
    alert(syminfo.tickerid+" Short Signal",alert.freq_once_per_bar_close)
    nb := 0  
//
// Exit via SL or TP
strategy.exit(id="s/t L", from_entry="Long", stop=issl?stoploss:na, 
              limit=istp?takeprofit:na, alert_message="Close L")
strategy.exit(id="s/t S",from_entry="Short",stop=issl?stoploss:na, 
              limit=istp?takeprofit:na, alert_message="Stop Loss S")
//

Only alerts work with a delay in this form

Problems arise when I try to use conditions to compare by type goLong[1] or read bar_index of goShort/goLong bars. The one bar delay is triggered, but all positions are immediately closed on the opening bar. For example:

var float position_size = 0.0
if strategy.position_size != 0
    position_size := strategy.position_size
    position_size

var nb = 0
brnum = bar_index
var delent = 0
delay = 1
var entered = false

//Entrys

if goLong and isinrange and not entered
    if position_size < 0
        strategy.close('Short', comment='Exit S', qty=math.abs(position_size))
    label.new(bar_index, low, 'I', xloc=xloc.bar_index, yloc=yloc.price, color=color.green, style=label.style_label_up, size=size.small)
    delent := bar_index + delay
    entered := true

if brnum != 0 and delent != 0 and brnum == delent
    alert(syminfo.tickerid + ' Long Signal', alert.freq_once_per_bar_close)
    label.new(bar_index, low, 'L', xloc=xloc.bar_index, yloc=yloc.price, color=color.green, style=label.style_label_up, size=size.small)
    brnum := 0
    delent := 0
    strategy.entry('Long', strategy.long)
    entered := false

if goShort and isinrange and not entered
    if position_size > 0
        strategy.close('Long', comment='Exit L', qty=math.abs(position_size))
    label.new(bar_index, low, 'I', xloc=xloc.bar_index, yloc=yloc.price, color=color.green, style=label.style_label_up, size=size.small)
    delent := bar_index + delay
    entered := true

if brnum != 0 and delent != 0 and brnum == delent
    alert(syminfo.tickerid + ' Short Signal', alert.freq_once_per_bar_close)
    label.new(bar_index, high, 'S', xloc=xloc.bar_index, yloc=yloc.price, color=color.rgb(255, 0, 0), style=label.style_label_down, size=size.small)
    brnum := 0
    delent := 0
    strategy.entry('Short', strategy.short)
    entered := false

// Exit via SL or TP
strategy.exit(id='s/t L', from_entry='Long', stop=issl ? stoploss : na, limit=istp ? takeprofit : na, alert_message='Close L')
strategy.exit(id='s/t S', from_entry='Short', stop=issl ? stoploss : na, limit=istp ? takeprofit : na, alert_message='Stop Loss S')
//

All trades closed instantly after the opening. I'm asking for help.

Upd. Here I have implemented the simplest condition for entering positions on my strategy. And made a delay to the bar with n[1].

//@version=5
strategy('Moving Regression Band Breakout strategy', shorttitle='MRBS', overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=3)

issl = input.bool(title='SL', inline='linesl1', group='Stop Loss / Take Profit:', defval=true)
slpercent = input.float(title=', %', inline='linesl1', group='Stop Loss / Take Profit:', defval=5, minval=0.0)
istrailing = input.bool(title='Trailing', inline='linesl1', group='Stop Loss / Take Profit:', defval=false)
istp = input.bool(title='TP', inline='linetp1', group='Stop Loss / Take Profit:', defval=true)
tppercent = input.float(title=', %', inline='linetp1', group='Stop Loss / Take Profit:', defval=2)
//
fastLength = input.int(title='Fast Length', defval=12)
slowLength = input.int(title='Slow Length', defval=26)
signalLength = input.int(title='Signal Length', defval=9)
[macdLine, signalLine, _] = ta.macd(close, fastLength, slowLength, signalLength)

longCondition = ta.crossover(macdLine, signalLine)
shortCondition = ta.crossunder(macdLine, signalLine)

// D-RSI signals
goLong = longCondition
goShort = shortCondition

// Entry price / Take profit / Stop Loss
startprice = ta.valuewhen(condition=goLong or goShort, source=close, occurrence=0)
pm3 = goLong ? 1 : goShort ? -1 : 1 / math.sign(strategy.position_size)
takeprofit = startprice * (1 + pm3 * tppercent * 0.01)
// fixed stop loss
stoploss = startprice * (1 - pm3 * slpercent * 0.01)

var float position_size = 0.0
if strategy.position_size != 0
    position_size := strategy.position_size
    position_size

var nb = 0

//Entrys

if goLong
    if position_size < 0
        strategy.close('Short', comment='Exit S', qty=math.abs(position_size))
    nb := 1
    label.new(bar_index, low, 'C', xloc=xloc.bar_index, yloc=yloc.price, color=color.rgb(200, 250, 64), style=label.style_label_up, size=size.small)

if nb[1] == 1
    nb := 0
    alert(syminfo.tickerid + ' Long Signal', alert.freq_once_per_bar_close)
    label.new(bar_index, low, 'L', xloc=xloc.bar_index, yloc=yloc.price, color=color.green, style=label.style_label_up, size=size.small)
    strategy.entry('Long', strategy.long)

if goShort
    if position_size > 0
        strategy.close('Long', comment='Exit L', qty=math.abs(position_size))
    nb := 2
    label.new(bar_index, low, 'C', xloc=xloc.bar_index, yloc=yloc.price, color=color.rgb(209, 255, 3), style=label.style_label_up, size=size.small)
  
if nb[1] == 2
    nb := 0
    alert(syminfo.tickerid + ' Short Signal', alert.freq_once_per_bar_close)
    label.new(bar_index, high, 'S', xloc=xloc.bar_index, yloc=yloc.price, color=color.rgb(255, 0, 0), style=label.style_label_down, size=size.small)
    strategy.entry('Short', strategy.short)

// Exit via SL or TP
strategy.exit(id='s/t L', from_entry='Long', stop=issl ? stoploss : na, limit=istp ? takeprofit : na, alert_message='Close L')
strategy.exit(id='s/t S', from_entry='Short', stop=issl ? stoploss : na, limit=istp ? takeprofit : na, alert_message='Stop Loss S')

Yellow label - true condition, green/red entrance to the strategy. But now the position is immediately closed after opening. If remove [1], everything works, but without delay.Perhaps I didn’t formulate my problem correctly, I learned how to make delays, but positions are constantly closed after opening.


Solution

  • If you want to delay by one bar, you can use the history referencing operator for a quick hack.

    If goLong is the condition that triggers your long entry, you can use goLong[1] to get your delay. You should do this for all the conditions that triggers your entry.

    Edit:

    Check whether you are in a long/short position before calling strategy.exit().

    if (strategy.position_size > 0)
        strategy.exit(id='s/t L', from_entry='Long', stop=issl ? stoploss : na, limit=istp ? takeprofit : na, alert_message='Close L')
    
    if (strategy.position_size < 0)
        strategy.exit(id='s/t S', from_entry='Short', stop=issl ? stoploss : na, limit=istp ? takeprofit : na, alert_message='Stop Loss S')