ProBacktest/probacktest · proorder

COUNTOFPOSITION

COUNTOFPOSITION returns the signed size of the open position in ProBacktest and ProOrder, positive for long and negative for short. Syntax and examples.

Syntax

probuilder
COUNTOFPOSITION

The keyword takes no parameters and is used like a read-only variable inside expressions.

How it works

On every bar, COUNTOFPOSITION reflects the quantity currently held by the strategy. The sign encodes direction: a strategy long 3 contracts reads 3, a strategy short 3 contracts reads -3, and a flat strategy reads 0. The value updates as orders fill, so after a partial exit it shows the remaining quantity, not the original entry size.

The signed convention makes the keyword useful in two situations. First, direction checks: COUNTOFPOSITION > 0 is equivalent to LONGONMARKET, and COUNTOFPOSITION < 0 to SHORTONMARKET. Second, exposure caps: ABS(COUNTOFPOSITION) gives total size independent of direction, which is the usual way to limit pyramiding when DEFPARAM CumulateOrders = true allows repeated entries in the same direction.

Only filled quantity is counted. Pending limit or stop orders that have not executed do not change the value. For unsigned per-direction counts, COUNTOFLONGSHARES and COUNTOFSHORTSHARES report the long and short quantities separately.

Examples

Example 1, Capping a pyramided short position (ProBacktest)

probuilder
myMACD = MACD[12,26,9](close)
short = myMACD crosses under 0

// First short entry when flat on the short side
IF NOT ShortOnMarket AND short THEN
  SELLSHORT 1 CONTRACTS AT MARKET
ENDIF

// Allow re-entries only while total size stays at or below 10 contracts
MAXSHARES = abs(COUNTOFPOSITION) <= 10
IF TRADEINDEX(1) > 5 AND TRADEPRICE(1) - Close > 10 * pointsize AND ShortOnMarket AND MAXSHARES THEN
  SELLSHORT 1 CONTRACTS AT MARKET
ENDIF
SET STOP TRAILING 50

The strategy scales into a short as price falls. Because COUNTOFPOSITION is negative while short, ABS() converts it to a total size before comparing against the cap of 10.

Example 2, Direction check without ONMARKET keywords (ProOrder)

probuilder
DEFPARAM CumulateOrders = false

fastMA = Average[20](close)
slowMA = Average[50](close)

// Enter long on a bullish crossover when flat
IF COUNTOFPOSITION = 0 AND fastMA crosses over slowMA THEN
  BUY 2 CONTRACTS AT MARKET
ENDIF

// Close the long on a bearish crossover
IF COUNTOFPOSITION > 0 AND fastMA crosses under slowMA THEN
  SELL AT MARKET
ENDIF

COUNTOFPOSITION = 0 detects a flat strategy and COUNTOFPOSITION > 0 detects an open long, mirroring ONMARKET and LONGONMARKET with a single keyword.

Example 3, Sizing a partial exit from the live position (ProOrder)

probuilder
DEFPARAM CumulateOrders = true

// Scale into a long, then bank half once the trade is 20 points onside
IF LongOnMarket AND close - TRADEPRICE >= 20 * pointsize AND COUNTOFPOSITION >= 4 THEN
  // Exit half of whatever is currently held
  SELL COUNTOFPOSITION / 2 CONTRACTS AT MARKET
ENDIF

Reading the live size lets the exit adapt to however many entries actually filled, instead of hard-coding a quantity.

Common errors and gotchas

  • Forgetting the sign on shorts. While short, COUNTOFPOSITION is negative, so a guard like COUNTOFPOSITION <= 10 is always true and never limits anything. Compare ABS(COUNTOFPOSITION) when the intent is total size.
  • Expecting pending orders to count. The value only reflects filled quantity. A resting limit order that has not executed leaves COUNTOFPOSITION unchanged, so exposure caps based on it do not account for orders waiting at the broker.
  • No accumulation without CumulateOrders. With the default DEFPARAM CumulateOrders = false, additional orders in the same direction do not stack, so COUNTOFPOSITION never grows past the first entry and pyramiding logic silently does nothing.
  • Using it outside strategies. The keyword does not exist in ProBuilder indicators or ProScreener. Position-aware logic has to live in the ProBacktest or ProOrder code itself.