I am exploring the possibility of creating a backtesting based on a DCA (Dollar Cost Average) model in Pine Script V5. I have been trying for days to find a solution to this seemingly easy problem.
In this test strategy, 5 safety orders + 1 base order (main order) are used. The entry condition is CLOSE > EMA (200). The orders are placed on the market, the average entry price is calculated and the stop loss is calculate on the average entry price. What happens is really strange. The algorithm executes the orders and closes them correctly, the problem arises after the orders are closed. In fact, having closed the positions the algorithm should return to a new entry condition and restart from the Base Order. What happens instead is that if, for example, 3 orders or 4 orders are closed, the algorithm continues to open new safety orders even after closing (when instead it should stop and wait for a new entry condition, restarting from the BASE order).
Does anyone know of a solution? Thanks community.
//@version=5
strategy("StackOverflow Issue",
overlay = true,
default_qty_type = strategy.percent_of_equity,
default_qty_value = 100,
currency = currency.EUR,
initial_capital = 1000,
pyramiding = 5,
commission_type = strategy.commission.percent,
commission_value = 0.07,
process_orders_on_close = true
)
ema = ta.ema(close, 200)
condition_open_long = close > ema
SAFETYORDERS = 5
drop = 1
SL = 1.00
TP = 5.00
LONG_CONDITION = condition_open_long==true and strategy.opentrades==0
var float mainorder = 0
var float dca1 = 0
var float dca2 = 0
var float dca3 = 0
var float dca4 = 0
var float dca5 = 0
var float pe = 0
var float dcasl = 0
var float baseorder = 0
var float safetyorder = 0
var float averageprice = 0
if (LONG_CONDITION==true and SAFETYORDERS == 5)
// BASE LONG ORDER
mainorder := close
lot_base = strategy.equity/mainorder
strategy.order(id = "BASE-ORDER", direction = strategy.long, qty = lot_base, limit = mainorder)
// DCA 1 ORDER
dca1 := mainorder - (mainorder * drop / 100)
lot_dca = strategy.equity / dca1
strategy.order(id="L1", direction = strategy.long, qty = lot_dca, limit = dca1)
// DCA 2 ORDER
dca2 := dca1 - (dca1 * drop / 100)
lot_dca2 = strategy.equity / dca2
strategy.order(id="L2", direction = strategy.long, qty = lot_dca2, limit = dca2)
// DCA 3 ORDER
dca3 := dca2 - (dca2 * drop / 100)
lot_dca3 = strategy.equity / dca3
strategy.order(id="L3", direction = strategy.long, qty = lot_dca3, limit = dca3)
// DCA 4 ORDER
dca4 := dca3 - (dca3 * drop / 100)
lot_dca4 = strategy.equity / dca4
strategy.order(id="L4", direction = strategy.long, qty = lot_dca4, limit = dca4)
// DCA 5 ORDER
dca5 := dca4 - (dca4 * drop / 100)
lot_dca5 = strategy.equity / dca5
strategy.order(id="L5", direction = strategy.long, qty = lot_dca5, limit = dca5)
averageprice := (mainorder + dca1 + dca2 + dca3 + dca4 + dca5) / 6
dcasl := averageprice - (averageprice * SL / 100)
if (dcasl)
strategy.exit(id="CL1", from_entry = "BASE-ORDER", stop = dcasl)
strategy.exit(id="CL2", from_entry = "L1", stop = dcasl)
strategy.exit(id="CL3", from_entry = "L2", stop = dcasl)
strategy.exit(id="CL4", from_entry = "L3", stop = dcasl)
strategy.exit(id="CL5", from_entry = "L4", stop = dcasl)
strategy.exit(id="CL6", from_entry = "L5", stop = dcasl)
When you execute limit order commands, they remain on the chart until they are filled or you explicitly cancel them with the strategy.cancel(id required)
/ strategy.cancel_all()
commands. In your screenshot, you can see that the strategy has placed 5 safety orders on the first bar (marked with a green arrow), but the price has reached the limit levels and 2 of them were executed only 2 bars later (red arrow).
What's your intention here? If you would like to cancel pending safety orders that were placed on the chart on previous candles, use:
if myCancelCondition // Cancel only limit entries, so limit exits remain
strategy.cancel("L1")
strategy.cancel("L2")
strategy.cancel("L3")
strategy.cancel("L4")
strategy.cancel("L5")
Also, with the default close_entries_rule=
parameter, your exit commands will not match the given entry, but will close the earliest open order. In case qty=
entry and exit do not match, you may see multiple exits of the same entry order or one exit closing multiple entry orders. To close orders in any order and match the id, use the close_entries_rule = "ANY"
parameter of the strategy()
function:
strategy(..., close_entries_rule = "ANY")