ProBacktest/probacktest · proorder

TRADEINDEX

TRADEINDEX(N) returns the bar index where a past trade was executed in ProBacktest and ProOrder, letting strategies count bars since the Nth most recent entry.

Syntax

probuilder
TRADEINDEX(N)

Parameters

NameTypeDefaultDescription
Ninteger1Trade number counted backwards in time. 1 is the most recent trade, 2 the one before it, and so on.

How it works

Each executed order is recorded together with the index of the bar it filled on. TRADEINDEX(N) looks that index up for the Nth most recent trade. The value is an absolute bar index, the same numbering that BARINDEX uses for the current bar, not a count of elapsed bars.

The elapsed-time question is therefore answered by a subtraction: BARINDEX - TRADEINDEX(1) is the number of bars since the latest execution. This drives time-based trade management, for example exiting a stalled position after a fixed number of bars, enforcing a cooldown between entries, or allowing pyramiding only after the previous fill has aged.

With DEFPARAM CumulateOrders = true, every partial entry counts as its own trade, so TRADEINDEX(1) refers to the latest addition, not the original entry of the accumulated position. TRADEPRICE(N) follows the same numbering and returns the execution price instead of the bar index, the two are often used together.

Examples

Example 1, Time stop after five bars in the trade (ProOrder)

probuilder
// Close everything once 5 bars have passed since the last execution
IF onmarket AND BARINDEX - TRADEINDEX(1) >= 5 THEN
  SELL AT MARKET
  EXITSHORT AT MARKET
ENDIF

Whatever direction the position has, it is closed once five bars have elapsed since the most recent fill. This is the reference example for the instruction.

Example 2, Pyramiding gated by bar count and price progress (ProBacktest)

probuilder
DEFPARAM CumulateOrders = true
myMACD = MACD[12,26,9](close)
long = myMACD crosses over 0
exit = myMACD crosses under 0

// Initial entry
IF NOT LongOnMarket AND long THEN
  BUY 1 CONTRACTS AT MARKET
ENDIF

IF LongOnMarket AND exit THEN
  SELL AT MARKET
ENDIF

// Add only if 5 bars have passed and price is 10 points beyond the last fill
IF BARINDEX - TRADEINDEX(1) > 5 AND Close - TRADEPRICE(1) > 10 AND LongOnMarket THEN
  BUY 1 CONTRACTS AT MARKET
ENDIF

// One trailing stop protects the whole accumulated position
SET STOP %TRAILING 1.5

Additional contracts are bought only when the last fill is at least five bars old and price has advanced ten points beyond it, a standard pyramiding filter combining TRADEINDEX with TRADEPRICE.

Example 3, Cooldown between consecutive entries (ProOrder)

probuilder
// No new trade within 20 bars of the previous execution
signal = close crosses over average[20](close)
coolingDown = BARINDEX - TRADEINDEX(1) < 20

IF NOT onmarket AND signal AND NOT coolingDown THEN
  BUY 1 CONTRACT AT MARKET
  SET STOP LOSS 25
ENDIF

After any execution, the strategy refuses new entries for 20 bars, which prevents rapid re-entry churn in choppy conditions.

Common errors and gotchas

  • Index, not age. TRADEINDEX(1) returns a bar index, not the number of bars since the trade. Comparing it directly to a small constant is meaningless, always subtract it from BARINDEX.
  • Reverse numbering. N counts backwards, 1 is the latest trade. Assuming 1 means the first trade of the session inverts the logic silently.
  • No trades yet. On the early bars of a backtest, before any execution, the value is not meaningful. Guard time-based conditions with onmarket or a flag that flips after the first entry.
  • CumulateOrders changes the meaning. With accumulated positions every partial fill is a trade, so TRADEINDEX(1) tracks the latest addition rather than the position's original entry. Use a saved variable at first entry if the original bar matters.
  • BarIndex, index of the current bar, the reference for elapsed-bar arithmetic.
  • TRADEPRICE, execution price of the Nth most recent trade.
  • POSITIONPRICE, average price of the open position.
  • ONMARKET, true while any position is open.
  • CumulateOrders, DEFPARAM that makes each partial entry count as a trade.
  • BarsSince, counts bars since a condition was true.
  • COUNTOFPOSITION, size of the position currently open.
  • LONGONMARKET, true while a long position is open.