Day 31 · Core Order Architecture · Python 3.11+ · Alpaca Paper Trading
The “Round to Two Decimals” Trap
Every junior quant makes this mistake exactly once.
They build a momentum signal. It fires. They compute a limit price from the mid-quote, call
round(signal_price, 2), and submit. Backtests are clean. Paper trading looks fine. Then they hit a biotech name trading at $0.47 with a tick size of $0.0001, or an ETF in a crossed-market condition at 9:30:01 AM. The order rejects. Or worse — it fills instantly at a price 4 bps worse than intended, because their “limit” order was actually crossing the spread.
Here is what that looks like in code:
# JUNIOR TRAP: Do not ship this
def submit_entry(symbol: str, signal_price: float, qty: int):
limit = round(signal_price, 2) # ← float rounding, no tick awareness
if limit < get_current_price(symbol): # ← synchronous price fetch in hot path
client.submit_order( # ← no spread check, no filter validation
symbol=symbol,
qty=qty,
side='buy',
type='limit',
limit_price=limit,
time_in_force='day'
)
Three failure vectors in twelve lines of code. Let’s take them apart.
The Three Failure Modes
Failure 1: Floating-Point Tick Quantization
round(price, 2) is not tick quantization. It is decimal truncation. When tick_size=0.01:
>>> 0.07 / 0.01
6.999999999999999 # Python float, not 7
>>> round(0.07, 2)
0.07 # Looks right, but...
>>> 0.07 == 7 * 0.01
False # IEEE 754 drift
Alpaca and most exchanges validate price modulo
tick_size. A price of$142.135againsttick_size=0.01yields142.135 % 0.01 ≈ 4.97e-15in float arithmetic — which looks non-zero to the exchange’s integer comparator and triggers a422 Unprocessable Entity. You need Decimal arithmetic with an explicit rounding mode.
In plain English: IEEE 754 is the standard for how computers store decimal numbers in binary. The number 0.07 cannot be stored exactly in binary — just like 1/3 has no exact decimal form. That tiny error (6.999... instead of 7.0) is enough to fail an exchange’s price filter.
Failure 2: Spread Crossing — The Accidental Market Order
If your buy limit price is greater than or equal to the current ask, your order fills immediately at the ask (or sweeps levels above it). You have submitted a limit order with a price ceiling that is already satisfied. This is:
Fine if intentional (an IOC aggressive fill)
A latent slippage bomb if your signal_price logic is computing above the ask systematically
The exchange will not reject it. You will see it in your fills, not your logs. That is what makes it dangerous.
Failure 3: Price Filter Blindness
Alpaca enforces per-symbol price filters. Submitting a price outside [min_price, max_price] or with the wrong tick_size returns a 422 that your try/except swallows, leaving your position unhedged while you think you are filled. In a volatility event, you will do this 40 times before the rate limiter kicks you off.



