Trading bot order precision: tick size, quantity steps and minimums
A strategy may request 0.0817 units at 123.47, but the venue trades a discrete grid of valid prices and sizes. Converting a risk-sized intent to that grid is not cosmetic formatting. The rounding direction can change exposure, invalidate minimum notional, move a passive order across the spread, or cause an API rejection.
Precision is more than decimal places
Fetch current instrument metadata from the venue rather than maintaining a list by hand. Common constraints include:
| Rule | Meaning | Typical failure |
|---|---|---|
| Price tick | Allowed price increment | Limit or stop price falls between ticks |
| Quantity step | Allowed size increment | Amount has an invalid remainder |
| Minimum quantity | Smallest base amount or contracts | Risk-based size is too small |
| Minimum notional | Smallest price × quantity value | Rounded order value falls below minimum |
| Maximum quantity/notional | Per-order venue cap | Large rebalance is rejected |
| Contract multiplier | Underlying exposure per derivative contract | Units confused with contracts |
| Price band | Distance allowed from reference price | Protective or passive limit is out of range |
Spot base quantity, quote-cost orders, futures contracts, and options contracts may use different units. Name them explicitly in code—base_qty, quote_notional, and contracts—instead of passing an ambiguous variable called amount.
Use Decimal or integer grid arithmetic
Binary floating point cannot represent many decimal fractions exactly. A calculation that visually looks like 0.081 can serialize with a tiny extra remainder and fail a step-size test. Avoid fixing this with a generic number of decimal places: a tick such as 0.05 has two decimal places, but not every two-decimal price is a multiple of 0.05.
grid conversionprice_ticks = floor(raw_price / tick_size)
valid_price = price_ticks * tick_size
quantity_steps = floor(raw_quantity / quantity_step)
valid_quantity = quantity_steps * quantity_step
notional = valid_price * valid_quantity
Implement that logic with a decimal type or scaled integers, and parse venue metadata from strings where possible. Keep the decimal value through risk, fee, and balance checks; converting back to a binary float just before submission can reintroduce the error.
Rounding direction is a risk decision
There is no single “round to nearest” rule. The policy depends on intent:
- Quantity: rounding down commonly prevents exceeding target exposure or available balance. If that misses the minimum, do not silently round up without re-running the risk gate.
- Passive limit price: a buy is often floored and a sell often ceiled to avoid crossing, but the current book and post-only behavior must be checked.
- Marketable price cap: rounding must preserve the maximum acceptable execution price, not accidentally loosen it.
- Stop trigger: rounding changes when protection activates. Choose a documented conservative rule for the position side and venue trigger semantics.
- Take-profit: rounding may change both reward-to-risk and fill likelihood; recalculate both.
The safe pipeline is risk-sized intent → venue-grid conversion → complete notional and balance validation → final risk check. Rounding is a transformation of the trade, so the transformed order must pass the same controls as the original.
Use the position sizing calculator for the continuous target, but treat the venue-grid step as a separate execution concern.
A minimum-notional trap
Consider a hypothetical instrument with a price tick of 0.05, quantity step of 0.001, and minimum notional of $10. A strategy requests a passive buy at 123.47 for 0.0817 units.
| Stage | Value | Check |
|---|---|---|
| Raw price | 123.47 | Not on the 0.05 grid |
| Floored passive buy | 123.45 | Valid price tick |
| Raw quantity | 0.0817 | Not on the 0.001 grid |
| Floored quantity | 0.081 | Valid quantity step |
| Rounded notional | $9.99945 | Below $10 minimum |
Rounding the quantity up to 0.082 would produce $10.12290 of notional, but it also raises exposure above the floored risk target. The correct action depends on the prewritten risk policy: approve the higher grid size if still within limits, choose a different price if the strategy permits, aggregate the intent, or skip it. The bot must not improvise.
Minimum notional can also change between sizing and send as price moves. Apply a small policy-approved buffer only if it remains inside risk and balance limits, and validate again as close to submission as practical.
Preflight every order and refresh metadata
- Load instrument status, tick, step, minimums, maximums, and contract multiplier.
- Confirm the market is enabled for the intended order type and side.
- Convert price and quantity using explicit decimal rounding rules.
- Check quantity, notional, balance, leverage, price bands, and risk limits.
- Serialize without scientific notation unless the API explicitly accepts it.
- Store both raw intent and formatted order with the metadata version used.
- After a precision rejection, pause the symbol, refresh metadata, and diagnose—do not loop the same invalid order.
Test boundary values: exactly one step below and above each minimum, unusually small and large prices, zero, negative input, scientific notation, changed tick sizes, contract multipliers, and fees deducted from the received asset. In a multi-venue bot, do not assume one exchange's precision applies to another just because the symbol text matches.
Libraries can help format values, but the bot still owns unit correctness and risk. If you use ccxt, pair its market metadata and precision helpers with the workflow in the ccxt guide, then verify the venue's current official rules.
Frequently asked questions
What are tick size and step size in a trading bot?
Tick size is the allowed price increment and quantity step is the allowed order-size increment. A venue may also enforce minimum and maximum quantity, minimum notional, contract size, and price bands. The bot must validate the complete current rule set before submission.
Should a trading bot use floating-point numbers for orders?
Binary floating point can create values just above or below an allowed increment. Use decimal or integer tick-and-step arithmetic for prices, quantities, fees, and notional checks, then serialize exactly as the venue expects.
Should order quantity be rounded up or down?
There is no universal direction for every intent. Rounding down often avoids exceeding a risk or balance cap, while rounding up may be required to satisfy a minimum notional but increases exposure. Apply explicit side- and order-aware rules, re-run risk checks after rounding, and skip the trade if no valid size satisfies both venue and risk constraints.
How often should a bot refresh exchange symbol rules?
Load them at startup, refresh on a documented schedule, and invalidate the cache after a precision-related rejection or venue notice. Rules can change. Version the metadata used for each order so a later rejection can be reproduced and audited.