Portfolio Engine¶
The portfolio engine converts signals into sized orders and manages portfolio-level exposure.
Components¶
Portfolio Allocator¶
Converts signals into orders using target weight sizing:
Sizing formula:
target_weight: Fraction of NAV per position (default 2%)confidence: Signal confidence (0.0-1.0) scales position down- Minimum notional of 100.0 to avoid dust orders
- Direction:
signal.direction >= 0maps to BUY, else SELL
Exposure Manager¶
Validates portfolio-level exposure limits:
- Max position weight — Single position cannot exceed X% of NAV
- Max gross exposure — Sum of all position absolute values cannot exceed X% of NAV
Shared Memory¶
Maintains live portfolio state for the coordinator:
| Field | Description |
|---|---|
latest_snapshot |
Current PortfolioSnapshot |
latest_pnl |
Daily P&L fraction |
rolling_drawdown |
Peak-to-trough drawdown |
current_leverage |
Gross exposure / NAV |
peak_nav |
Highest NAV observed |
update_snapshot(snapshot) automatically derives drawdown and leverage.
Data Flow¶
graph LR
S[Signal] --> A[Portfolio Allocator]
A --> O[Order - PENDING]
O --> R[Risk Engine]
R --> EM[Exposure Manager]
R --> DG[Drawdown Guard]
R --> LG[Leverage Guard]
R --> LQ[Liquidity Guard]
EM --> D{Decision}
DG --> D
LG --> D
LQ --> D
D -->|Pass| APP[Order - APPROVED]
D -->|Fail| REJ[RiskEvent]
Portfolio Types¶
Position(
symbol: str,
quantity: float,
avg_price: float,
market_price: float,
strategy: str,
)
# Computed: market_value = quantity * market_price
PortfolioSnapshot(
timestamp: datetime,
nav: float,
cash: float,
gross_exposure: float,
net_exposure: float,
positions: list[Position],
)
State Persistence¶
Portfolio checkpoints are saved to the EventStore for recovery after restart: