I am trying to write a Pine Script strategy that passes a long order based on a condition and closes the order at the end of the candle, whatever happens unless a stop loss is reached.
For that I use the strategy configuration option "calc_on_order_fills = true" so that the strategy is recalculated when the order is filled (at the beginning of the candle) and so that the close order can be executed at the end of the candle (the close order is delayed by the duration of the candle).
Orders are correctly opened but the logic does not work as intended as close order would only execute at the open 2 candles after the long was executed (instead of at the close of the same candle). I am not sure what I am missing, and here is the code (long execution removed for clarity as they are working as intended):
//@version=5
strategy(title="Keltner Strategy v3", shorttitle="KS3", overlay=true, close_entries_rule="ANY", calc_on_order_fills = true)
// Create inputs that configure the backtest's date range
useDateFilter = input.bool(true, title="Begin Backtest at Start Date",
group="Backtest Time Period")
backtestStartDate = input.time(timestamp("1 Jan 2023"),
title="Start Date", group="Backtest Time Period",
tooltip="This start date is in the time zone of the exchange " +
"where the chart's instrument trades. It doesn't use the time " +
"zone of the chart or of your computer.")
// See if current bar happens on, or later than, the start date
inTradeWindow = not useDateFilter or time >= backtestStartDate
// Converting the time frame in seconds for delaying close orders
timeFrameSeconds = timeframe.in_seconds()
// Condition to check if a candle closes outside the channel and RSI is > 70 or < 30
bearishSignal = src > open and src > 1.0025 * upperBand and rsiVal > 70
bullishSignal = src < open and src < 0.9975 * lowerBand and rsiVal < 30
if (inTradeWindow and bearishSignal and strategy.opentrades == 0)
stopLoss1 = close * 1.011
strategy.entry("sell1", strategy.short, qty = 1)
label.new(bar_index, high, text="EXE")
strategy.exit("Exit sell1", "sell1", stop=stopLoss1)
if (inTradeWindow and bearishSignal and strategy.opentrades >= 1)
stopLoss2 = close * 1.011
strategy.entry("sell2", strategy.short, qty = 1)
label.new(bar_index, high, text="EXE")
strategy.exit("Exit sell2", "sell2", stop=stopLoss2)
for i = 0 to strategy.opentrades-1
if (time - strategy.opentrades.entry_time(i) >= timeFrameSeconds*1000)
entry = strategy.opentrades.entry_id(i)
strategy.close(entry)
I found my own solution to the problem, see code as follow. It basically opens the trade at the close of a candle and closes it at the next candle close. This is possible mostly in crypto as there is no wide gaps between a close and an open.
//@version=5
strategy(title="Keltner Strategy v3", shorttitle="KS3", overlay=true, close_entries_rule="ANY", process_orders_on_close = true)
// Create inputs that configure the backtest's date range
useDateFilter = input.bool(true, title="Begin Backtest at Start Date",
group="Backtest Time Period")
backtestStartDate = input.time(timestamp("1 Jan 2023"),
title="Start Date", group="Backtest Time Period",
tooltip="This start date is in the time zone of the exchange " +
"where the chart's instrument trades. It doesn't use the time " +
"zone of the chart or of your computer.")
// See if current bar happens on, or later than, the start date
inTradeWindow = not useDateFilter or time >= backtestStartDate
//
timeFrameSeconds = timeframe.in_seconds()
// Condition to check if a candle closes outside the channel and RSI is > 70 or < 30
bearishSignal = src > open and src > 1.0025 * upperBand and rsiVal > 70
bullishSignal = src < open and src < 0.9975 * lowerBand and rsiVal < 30
for i = 0 to strategy.opentrades-1
if time - strategy.opentrades.entry_time(i) >= 3590*1000
entry = strategy.opentrades.entry_id(i)
strategy.close(entry)
if (inTradeWindow and bearishSignal and strategy.opentrades == 0)
stopLoss1 = close * 1.011
strategy.entry("sell1", strategy.short, qty = 1)
label.new(bar_index, high, text="SELL_1")
strategy.exit("Exit sell1", "sell1", stop=stopLoss1)
if (inTradeWindow and bearishSignal and strategy.opentrades >= 1)
stopLoss2 = close * 1.011
strategy.entry("sell2", strategy.short, qty = 1)
label.new(bar_index, high, text="SELL_2")
strategy.exit("Exit sell2", "sell2", stop=stopLoss2)