Module 16: Accounting & RiskUnderstand account models, margin logic, and fees so your strategy math matches reality
1. Why the Accounting System is Critical
❌ Common Misconception: “I only need to know my PnL; the exchange handles accounting.”
✅ The reality: if your backtest uses margin logic that does not match the venue, your results can be badly misleading. A strategy that looks great at 10x leverage in simulation may be impossible to run in production. The NautilusTrader accounting/ layer is there to keep simulated account behavior aligned with live behavior.
2. CashAccount vs MarginAccount
| Feature | CashAccount (Spot) | MarginAccount (Leveraged) |
|---|---|---|
| Leverage | 1x (None) | Up to 125x (Venue dependent) |
| Pre-trade Check | Cash Balance ≥ Order Cost | Free Margin ≥ Initial Margin |
| Short Selling | ❌ Prohibited | ✅ Supported |
| Liquidation | ❌ Impossible | ✅ Triggered if Margin < Maintenance |
| Use Cases | Equities Spot, Crypto Spot | Futures, Perps, Forex |
| Class Mapping | CashAccount | MarginAccount |
Account Balance Structure
# CashAccount Balance Primitive
account.balance_total(Currency.from_str("USDT")) # Absolute Gross Balance
account.balance_free(Currency.from_str("USDT")) # Liquidable Capital
account.balance_locked(Currency.from_str("USDT")) # Frozen by working orders
# MarginAccount Supplemental Primitives
margin_account.initial_margins() # Initial lockup per instrument
margin_account.maintenance_margins() # Critical thresholds per instrument
# ❗ Core Mathematical Concept
# Available Free Margin = Total Balance - Locked - Initial Margin
# If Total Balance < Maintenance Margin → LIQUIDATION INITIATED!3. The MarginModel State Machine
flowchart LR
order["📝 Execution Request"]
calc["💰 Calculate Initial Margin"]
check["✅ Margin Ceiling Check"]
submit["➡️ Submit to Venue"]
reject["❌ Reject Locally"]
order --> calc
calc --> check
check -->|Sufficient| submit
check -->|Insufficient| reject
style order fill:#0f1419,stroke:#4fc3f7,stroke-width:2px
style reject fill:#0f1419,stroke:#f44336,stroke-width:2px
style submit fill:#0f1419,stroke:#4caf50,stroke-width:2px
# Orchestrating Margin in Backtest
from nautilus_trader.backtest.engine import BacktestEngine
from nautilus_trader.model.enums import AccountType
engine = BacktestEngine()
engine.add_venue(
venue=Venue("BINANCE"),
oms_type=OmsType.NETTING, # Net Position Logic
account_type=AccountType.MARGIN, # Leveraged Account
starting_balances=[
Money(100_000, Currency.from_str("USDT")),
],
leverages={ # Leverage Orchestration
InstrumentId.from_str("BTCUSDT-PERP.BINANCE"): Decimal("10"),
InstrumentId.from_str("ETHUSDT-PERP.BINANCE"): Decimal("20"),
},
default_leverage=Decimal("1"),
)HEDGING: Concurrent Long and Short positions are allowed for a single instrument
(e.g., Forex MT4). Each entry is an independent pod.
NETTING: A single net position exists per instrument (e.g., Binance Perps).
Buying 1 unit followed by selling 1 unit results in zero exposure.
Using the wrong OMS mode will cause critical discrepancies between Research and Production.
4. FeeModel — Calculating Transaction Friction
from nautilus_trader.backtest.models import FeeModel, MakerTakerFeeModel
# Scenario: Professional-tier Maker/Taker logic
fee_model = MakerTakerFeeModel(
maker_fee=Decimal("0.0002"), # Maker: 0.02%
taker_fee=Decimal("0.0005"), # Taker: 0.05%
)
# Injection into Backtest
engine.add_venue(
venue=Venue("BINANCE"),
fee_model=fee_model,
)Maker (Providing Liquidity): Placing non-marketable limit orders that rest on
the book. Lower fees (sometimes rebates).
Taker (Consuming Liquidity): Placing market orders or limit orders that cross
the spread. Higher fees.
❌ Research Pitfall: Utilizing a flat Taker rate while the strategy primarily
uses passive Limit orders results in overestimating friction — potentially discarding a
profitable alpha vector.
5. Multi-Currency Portfolio Primitives
# NautilusTrader natively manages heterogeneous currency pools
engine.add_venue(
venue=Venue("BINANCE"),
starting_balances=[
Money(50_000, Currency.from_str("USDT")),
Money(2, Currency.from_str("BTC")),
Money(30, Currency.from_str("ETH")),
],
)
# Querying Balances within the Strategy Node
class MultiCurrencyAlpha(Strategy):
def on_start(self):
account = self.portfolio.account(self.instrument_id.venue)
usdt = account.balance_total(Currency.from_str("USDT"))
btc = account.balance_total(Currency.from_str("BTC"))
eth = account.balance_total(Currency.from_str("ETH"))
self.log.info(f"Capital Check: USDT={usdt}, BTC={btc}, ETH={eth}")
# Real-time Unrealized PnL (Calculated in Base Currency)
unrealized = self.portfolio.unrealized_pnl(self.instrument_id)
self.log.info(f"Live PnL Anchor: {unrealized}")
6. Advanced RiskEngine Configuration
Deepening the Risk parameters introduced in Module 09:
6.1 Component-Level Risk Constraints
from nautilus_trader.risk.engine import RiskEngine
risk_config = LiveRiskEngineConfig(
bypass=False,
# Execution Frequency Throttling
max_order_submit_rate="100/00:00:01", # Ceiling: 100 sub/sec
max_order_modify_rate="100/00:00:01", # Ceiling: 100 mod/sec
# Exposure Ceilings (Instrument-specific)
max_notional_per_order={
"BTCUSDT-PERP.BINANCE": 100_000, # Ceiling: 100k USDT Notional
},
)6.2 Custom Localized Risk Rules
class InstitutionalRiskStrategy(Strategy):
"""Enforcing localized risk buffers within the Alpha logic"""
def _check_localized_risk(self) -> bool:
"""Determines if new execution is permitted"""
# 1. Daily Drawdown Circuit Breaker
account = self.portfolio.account(self.instrument_id.venue)
if self._daily_pnl < Money(-5000, USD):
self.log.error("DAILY DRAWDOWN BREACHED: -$5000 floor reached.")
return False
# 2. Strategy Pod Density Check
positions = self.cache.positions(venue=self.instrument_id.venue)
if len(positions) >= 5:
self.log.warning("CONCENTRATION RISK: Max active instrument count (5) reached.")
return False
# 3. Directional Exposure Floor
long_count = sum(1 for p in positions if p.is_long)
if long_count >= 3:
self.log.warning("DIRECTIONAL BIAS: Max long density reached.")
return False
return True
def on_bar(self, bar):
if not self._check_localized_risk():
return
# Proceed with entry signal evaluation...
7. Interactive System Probing
Designate the optimal Account and OMS type for the following venues:
- Binance BTCUSDT Spot Liquidity.
- Binance BTCUSDT Perpetual Swaps.
- Interactive Brokers US Equities.
- Binance Spot:
- Schema:
CashAccount(1x leverage only). - OMS:
NETTING(Exchange-side net settlement).
- Schema:
- Binance Perps:
- Schema:
MarginAccount(Leveraged). - OMS:
NETTING(Aggregate position mode). - Leverage: Explicitly defined (1x-125x).
- Schema:
- IB Equities:
- Schema:
MarginAccount(IB permits leveraged Reg-T borrowing). - OMS:
NETTING(Settles to a net shares outstanding).
- Schema:
Variables: Maker=0.02%, Taker=0.05%. You buy 1 BTC @ $60,000 via passive Limit, and sell via Market later.
- Entry Fee (USDT)?
- Exit Fee (USDT)?
- If BTC rises to $60,100, what is the Net Realized Profit after all friction?
- Entry (Limit = Maker):
$60,000 × 0.0002 = $12 USDT. - Exit (Market = Taker):
$60,100 × 0.0005 = $30.05 USDT. - Net Realized Profit:
- Gross PnL: $60,100 – $60,000 = $100.
- Total Friction: $12 + $30.05 = $42.05.
- Net Alpha: $100 – $42.05 = $57.95 USDT.
Ignoring fees results in a deceptive $100 gain. Friction consumed 42% of the alpha — this highlights why High-Fidelity FeeModels are mandatory.
Propose a “Conservative Guardian” risk profile for a $100,000 capitalized node.
Baseline risk parameters ($100k AUM):
- Daily Drawdown Ceiling: $2,000 (2%)
Logic: Tail-risk mitigation during systemic market shocks. Cessation of all new activity when a breach occurs. - Max Notional per Order: $10,000 (10%)
Logic: Ensuring no single position dominates the concentration profile. - Max Concurrent Instruments: 5
Logic: Diversification without compromising monitoring bandwidth. - Order Rate Limit: 10/sec
Logic: Most strategies do not require high-frequency bursts. Protects against “runaway logic” bugs. - Aggregate Leverage Ceiling: 3x
Logic: A 33% counter-move results in total equity wipeout; 3x provides a significant buffer.
8. Synthesis of the Accounting & Risk Architecture
- High-Fidelity Schemas: Matching the exact account behaviors of the exchange is the baseline for credible research.
- Leverage & Margin: Understanding the hierarchy (Initial > Maintenance) prevents unintended liquidations.
- OMS Determinism: Netting vs Hedging determines how positions are aggregated.
- Friction Realism: Accurate Maker/Taker models distinguish between alpha and luck.
- Tiered Defense: Utilizing the global RiskEngine alongside localized Strategy rules creates a defense-in-depth posture.
- Portfolio Versatility: NautilusTrader natively handles complex multi-currency exposure.