ProBacktest/probacktest · proorder

ROUNDEDDOWN

ROUNDEDDOWN in ProBacktest and ProOrder rounds a value down to the nearest whole number, used to size share quantities from available cash. Syntax and examples.

Syntax

probuilder
ROUNDEDDOWN(expression)

Parameters

NameTypeDefaultDescription
expressionnumbernoneValue to round. Any literal, variable, or arithmetic expression that evaluates to a number.

How it works

ROUNDEDDOWN discards the fractional part of a value and returns the next lower whole number. Dividing available cash by a share price usually produces a fraction, and since most markets only accept whole share quantities, the result must be rounded before it can feed an order instruction. Rounding down is the budget-safe direction: the resulting quantity never costs more than the cash that was available.

The typical pattern is a three-line sizing block, compute the raw quantity as a division, round it down, then pass the result as the quantity of a BUY or SELLSHORT order. Because the function accepts full expressions, the division can happen directly inside the call.

For the opposite direction, rounding a fraction up to the next whole number, use ROUNDEDUP. For rounding to the nearest whole number in either direction, ROUND applies.

Examples

Example 1, Whole shares from a fixed cash budget (ProBacktest)

probuilder
// How many whole shares does 1000 in cash buy at 123.45 per share
cash = 1000
pricePerShare = 123.45
maxShares = ROUNDEDDOWN(cash / pricePerShare)

The raw division gives roughly 8.1, and ROUNDEDDOWN reduces it to 8, the largest whole quantity that fits the budget. This is the example from the official reference.

Example 2, Sizing an order from a fixed allocation (ProOrder)

probuilder
DEFPARAM CumulateOrders = false

// Allocate 5000 in cash per trade, sized at the current close
allocation = 5000
qty = ROUNDEDDOWN(allocation / close)

IF NOT onmarket AND close CROSSES OVER Average[50](close) AND qty >= 1 THEN
  BUY qty SHARES AT MARKET
ENDIF

Each entry converts the same cash allocation into a whole share count at the current price. The qty >= 1 guard prevents zero-quantity orders on expensive instruments.

Example 3, Risk-based contract sizing (ProOrder)

probuilder
DEFPARAM CumulateOrders = false

// Risk at most 200 in account currency per trade
riskBudget = 200
stopPoints = 20
contracts = ROUNDEDDOWN(riskBudget / (stopPoints * PointValue))

IF NOT onmarket AND RSI[14](close) < 30 AND contracts >= 1 THEN
  BUY contracts CONTRACT AT MARKET
  SET STOP PLOSS stopPoints
ENDIF

The position size is derived from the risk budget divided by the cash value of the stop distance, rounded down so the worst-case loss stays at or below the budget.

Common errors and gotchas

  • A result of zero cancels the trade. When the budget is smaller than one share or one contract of risk, ROUNDEDDOWN returns 0 and the order instruction does nothing. Guard entries with a qty >= 1 condition to make the behavior explicit.
  • Not available in indicators. ROUNDEDDOWN belongs to the strategy languages. The same rounding in indicator or screener code is written with FLOOR; using ROUNDEDDOWN there fails to compile.
  • Rounding down is not truncation for negatives. Sizing math should only ever produce positive quantities. Feeding a negative intermediate value into a sizing block yields a negative or zero quantity, which never places an order; validate inputs rather than relying on the rounding.
  • Do not round the price, round the quantity. Applying ROUNDEDDOWN to the share price before dividing distorts the calculation. Round once, at the end, on the quantity itself.
  • ROUNDEDUP, rounds a value up to the next whole number.
  • ROUND, rounds to the nearest whole number.
  • FLOOR, rounds down, available in all sub-languages.
  • CEIL, rounds up, available in all sub-languages.
  • SHARES, quantity unit keyword for stock orders.
  • CASH, cash-based position sizing keyword.
  • BUY, opens a long position with the computed quantity.
  • POINTVALUE, cash value of one point, used in risk sizing.