Day 57: Market Friction Modeling: Fixed Commissions
Before you read further, be honest with yourself: every backtest you have written until now is probably lying to you. Not because the math is wrong — because you have been treating commission as an afterthought. By the end of today, that changes permanently.
What This Lesson Covers
By the end of Day 57 you will have:
A working mental model of why commission must live before the trade decision, not after it
Three working Python modules —
CommissionModel,ExecutionRecord, andCommissionAwareOrderRouter— that form the cost accounting spine of every strategy you build from here onA CLI dashboard that lets you watch the gate accept and reject trades in real time
22 passing unit tests that prove your numbers are right
The “Subtract At The End” Trap
Every junior quant makes the same mistake. They build a backtest, nail the signal logic, produce a beautiful equity curve, and then — at the very end of the loop — do this:
# The naive approach (DO NOT DO THIS)
total_pnl = sum(trade_returns)
total_commission = num_trades * 0.005 * avg_shares # flat estimate
net_pnl = total_pnl - total_commission
print(f"Net P&L: ${net_pnl:.2f}")
This will get you fired. Here is why.
That single line treats commission as an accounting footnote — something you reconcile after the strategy has already decided to trade. In production, commission is a gate condition, not a line item. The moment you decouple cost from decision, you have built a strategy that will routinely execute trades with negative expected value. At scale, this is not a rounding error — it is systematic alpha destruction.
Funds blow through six-figure paper profits because their backtest used a 0.1% flat commission estimate while their broker charged $0.005/share with a $1.00 minimum. On a 50-share trade at $12/share ($600 notional), that is $1.00 / $600 = 16.7 basis points in commission alone. If your signal’s average edge is 15 bps, every single trade loses money by design.
The Failure Mode: Three Technical Crashes
Understanding how this breaks is as important as knowing that it breaks. There are three distinct failure modes, and you are probably exposed to all three right now.
Crash 1 — The Wrong Commission Model
Brokers do not all charge the same way. Alpaca charges $0.00/trade for equities but may charge on options. Interactive Brokers uses a tiered per-share model with minimums. Your generic commission_rate = 0.001 assumption is a fiction that compounds across thousands of trades.
Crash 2 — Float Accumulation Drift
pnl = 0.0
for trade in trades:
pnl += trade.return_usd - (trade.shares * 0.005) # float arithmetic
# After 10,000 trades: pnl has drifted by $0.02–$0.15 in float errors
In a strategy with tight expected returns, this drift contaminates your Sharpe calculation. Use decimal.Decimal for all monetary values in production execution logs — IEEE 754 floating-point is not an accounting standard.
Crash 3 — No Minimum Viable Edge (MVE) Gate
Without a pre-execution viability check, your order router submits trades where:
expected_return_usd < commission_cost_usd
This is the mathematical definition of negative expectancy. Every such trade is a scheduled loss.
The AutoQuant-Alpha Architecture
We implement a three-layer commission system. Each layer has exactly one responsibility, and they only communicate downward.
┌─────────────────────────────────────────────────────┐
│ Layer 1: CommissionModel │
│ Supports: FLAT | PER_SHARE | PERCENTAGE │
│ Output: cost_usd (Decimal), viable (bool) │
├─────────────────────────────────────────────────────┤
│ Layer 2: ExecutionRecord │
│ Atomic trade log with Decimal P&L accounting │
│ Immutable dataclass — write-once, append-only │
├─────────────────────────────────────────────────────┤
│ Layer 3: CommissionAwareOrderRouter │
│ Pre-flight cost gate before Alpaca API call │
│ Position sizing adjusted to maintain MVE threshold │
└─────────────────────────────────────────────────────┘
The key design principle: commission is computed before any order is constructed. The order router never touches the Alpaca API unless the viability gate passes.



