Building a Robust Trading System: From Signal to Execution

A comprehensive guide to designing trading infrastructure that scales from weekly rebalancing to high-frequency market making.


Introduction Link to heading

After years of working with trading systems across different firms and strategies, I’ve come to appreciate that the difference between a fragile system and a robust one isn’t the sophistication of the alpha—it’s the clarity of the architecture.

This post distills the key architectural patterns I’ve learned into a coherent framework. Whether you’re building a simple portfolio rebalancer or a multi-strategy hedge fund platform, these principles apply.

We’ll start with the human side—how trading desks organize roles—then show how good software architecture mirrors these same principles.


Table of Contents Link to heading

Part 1: The Human Side Link to heading

  1. Roles on a Trading Desk
  2. Deep Dive: Portfolio Manager Expertise
  3. Deep Dive: Risk Manager Expertise
  4. Deep Dive: Trader Expertise

Part 2: The Software Architecture Link to heading

  1. The Four Levels of Abstraction
  2. Level 1: Risk Management (Not Allocation!)
  3. Level 2: Signal Generation
  4. Level 3: Order Management
  5. Level 4: Market Access
  6. The OMS and PMS: Bookkeeping Layers

Part 3: Advanced Topics Link to heading

  1. Rule-Based vs Statistical Approaches
  2. Backtesting: Matching Fidelity to Purpose
  3. Continuous Signals and Position Sizing
  4. Adaptive Risk Systems
  5. Putting It All Together

Part 1: The Human Side Link to heading

Roles on a Trading Desk Link to heading

Before diving into code, let’s understand how trading desks organize human roles. Good software architecture mirrors this structure because both solve the same problem: separation of concerns and clear accountability.

┌───────────────────────┬────────────────────────┬─────────────────────────┐
│  SYSTEM LAYER         │  HUMAN ROLE            │  RESPONSIBILITY         │
├───────────────────────┼────────────────────────┼─────────────────────────┤
│  L1: Risk Management  │  Risk Manager          │  "You can't do that"    │
│                       │                        │  Sets limits, no alpha  │
│                       │                        │  views, just safety     │
├───────────────────────┼────────────────────────┼─────────────────────────┤
│  L2: Signal Generation│  Researcher / Analyst  │  "We should do this"    │
│                       │  Portfolio Manager     │  Investment thesis,     │
│                       │                        │  alpha ideas, sizing    │
├───────────────────────┼────────────────────────┼─────────────────────────┤
│  L3: Order Management │  Trader                │  "I'll work the order"  │
│                       │  Execution Desk        │  HOW to execute, algo   │
│                       │                        │  selection, timing      │
├───────────────────────┼────────────────────────┼─────────────────────────┤
│  L4: Market Access    │  Prime Broker / DMA    │  Connectivity to        │
│                       │  Infrastructure        │  exchanges              │
├───────────────────────┼────────────────────────┼─────────────────────────┤
│  OMS / PMS            │  Middle & Back Office  │  Bookkeeping, P&L,      │
│                       │  Operations            │  reconciliation         │
└───────────────────────┴────────────────────────┴─────────────────────────┘

Why This Structure Exists Link to heading

PrincipleHuman OrganizationSoftware Architecture
No conflicts of interestRisk manager doesn’t get paid on P&LL1 has no alpha views
Specialized expertiseTraders know market microstructureL3 handles execution algos
Clear handoffsPM says “buy 10k shares”, trader decides howSignal → Order separation
Audit trailOperations tracks everythingOMS/PMS logging

Real Workflow Example Link to heading

Human version:

  1. Analyst researches and says: “AAPL is undervalued, we should be 5% long”
  2. PM agrees, sizes it: “Let’s do 3% given current exposure”
  3. Risk Manager checks: “That’s within limits, approved”
  4. Trader executes: “I’ll TWAP it over 2 hours to minimize impact”
  5. Operations reconciles: “Filled 100k shares @ $182.34 avg”

System version:

  1. L2 (Alpha) generates signal: {instrument: AAPL, direction: BUY, target: 0.03}
  2. L1 (Risk) checks: projected_position < max_single_position ✓
  3. L3 (Execution) routes: TWAP(duration=2h, slices=24)
  4. L4 (MA) sends orders to exchange
  5. OMS/PMS tracks fills and updates P&L

Why This Matters Link to heading

When roles blur in human organizations—PM overrides risk, trader picks stocks—things go wrong. The same applies to software: when L1 has alpha views or L2 specifies execution details, the system becomes fragile.

The cleanest trading operations have the same separation in both people AND code. This architecture isn’t just software engineering—it’s encoding decades of institutional wisdom about how to run a trading operation without blowing up.


Deep Dive: Portfolio Manager Expertise Link to heading

Since PMs sit at L2 (Signal Generation), their expertise centers on “what should we do” — generating alpha and constructing portfolios.

PM Expertise Domains Link to heading

┌─────────────────────────────────────────────────────────────────────────────┐
│                        PM EXPERTISE DOMAINS                                  │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   CORE (Must Have)              ADJACENT (Should Know)     NOT THEIR JOB    │
│   ─────────────────             ────────────────────────   ──────────────   │
│   • Alpha generation            • Risk metrics             • Algo tuning    │
│   • Investment thesis           • Execution costs          • API specs      │
│   • Position sizing             • Market microstructure    • Infra/DevOps   │
│   • Portfolio construction      • Regulatory constraints   • Reconciliation │
│   • Market knowledge            • Basic coding/quant       • Limit setting  │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

1. Alpha Generation (The Core Job) Link to heading

SkillWhat It MeansExample
Idea generationFinding profitable opportunities“China’s reopening will boost copper demand”
Research methodologySystematic approach to validating ideasFundamental analysis, factor models, data analysis
Information synthesisCombining multiple signalsMacro + technicals + sentiment → conviction
Differentiated viewKnowing WHY you have edge“Market underestimates duration of cycle”

2. Position Sizing & Portfolio Construction Link to heading

# PM thinks in these terms:
class PMDecisionFramework:

    def size_position(self, idea):
        """How much to bet given conviction and risk budget"""

        # Conviction: How confident am I?
        conviction = self.assess_conviction(idea)  # 0-1

        # Capacity: How much can I trade without moving market?
        capacity = self.estimate_capacity(idea.instrument)

        # Risk budget: How much risk can this idea consume?
        risk_budget = self.portfolio.available_risk * conviction

        # Correlation: Does this diversify or concentrate?
        marginal_risk = self.portfolio.marginal_var(idea)

        return min(
            conviction * self.max_position,
            capacity,
            risk_budget / marginal_risk
        )

    def construct_portfolio(self, ideas):
        """Combine ideas into coherent portfolio"""

        # Not just picking winners - managing interactions
        return optimize(
            ideas,
            constraints=[
                sector_limits,
                factor_exposures,
                liquidity_requirements,
                correlation_bounds
            ]
        )

3. Market Knowledge (Domain Expertise) Link to heading

Depends on strategy type:

StrategyPM Expertise Focus
MacroCentral bank policy, FX dynamics, rates, global flows
Equity L/SSector dynamics, company fundamentals, earnings
QuantFactor research, statistical methods, data sources
CreditDefault risk, spreads, covenant analysis
CryptoProtocol economics, on-chain data, DeFi mechanics

4. Risk Understanding (Not Risk Management!) Link to heading

┌─────────────────────────────────────────────────────────────────┐
│  PM's Risk Role vs Risk Manager's Role                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  PM UNDERSTANDS:                    RISK MANAGER SETS:          │
│  ───────────────                    ────────────────            │
│  • How my positions contribute      • What the limits ARE       │
│    to portfolio risk                                            │
│  • Factor exposures I'm taking      • When to force liquidation │
│  • Tail risks of my thesis          • Firm-wide constraints     │
│  • Correlation assumptions          • Regulatory requirements   │
│                                                                 │
│  PM asks: "Is this risk worth it?"  RM asks: "Is this allowed?" │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

5. The Investment Memo Link to heading

A good PM can clearly articulate:

┌─────────────────────────────────────────────────────────────────┐
│  THE INVESTMENT MEMO (What a PM should articulate)              │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. THESIS: What is the trade and why?                          │
│     "Long copper: supply constrained, China demand recovering"  │
│                                                                 │
│  2. EDGE: Why will we be right when others are wrong?           │
│     "Market pricing 2% demand growth, we model 5%"              │
│                                                                 │
│  3. SIZING: Why this size?                                      │
│     "2% of NAV, 0.3 Sharpe contribution, uncorrelated to book"  │
│                                                                 │
│  4. CATALYST: What will make it work and when?                  │
│     "Q2 China PMI data, 3-6 month horizon"                      │
│                                                                 │
│  5. RISK: What could go wrong?                                  │
│     "Global recession kills demand, stop out at -50bps"         │
│                                                                 │
│  6. EXECUTION: Any special requirements?                        │
│     "Spread over 3 days, use LME not COMEX"                     │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

6. Adjacent Skills (Should Know, Not Master) Link to heading

SkillWhy It MattersDepth Needed
Execution costsAffects net returnsKnow impact, not algo details
Basic codingData analysis, backtestingPython/R proficiency, not production code
Risk metricsCommunicate with risk teamVaR, Sharpe, drawdown concepts
Market microstructureKnow when urgency mattersLiquidity patterns, not order book mechanics

What a PM Does NOT Need Link to heading

  • ❌ Deep execution expertise → That’s the Trader (L3)
  • ❌ Exchange API knowledge → That’s Market Access (L4)
  • ❌ Setting risk limits → That’s Risk Manager (L1)
  • ❌ Reconciliation/Operations → That’s Middle Office (OMS/PMS)

PM Archetypes by Strategy Link to heading

TypePrimary SkillSecondary SkillTools
Discretionary MacroMarket intuition, thesisCommunicationBloomberg, research
Fundamental EquityCompany analysisValuation modelingExcel, FactSet
Systematic QuantResearch methodologyCoding, statisticsPython, backtester
Multi-AssetPortfolio constructionCross-asset knowledgeOptimizer, risk system

The PM’s unique value: PMs are paid for judgment — knowing when the model is wrong, when to override signals, when conviction should increase despite drawdown. Technical skills are table stakes; differentiated insight is the edge.


Deep Dive: Risk Manager Expertise Link to heading

Since Risk Managers sit at L1 (Risk Management), their expertise centers on “what can’t we do” — protecting the firm from blowups without opining on alpha.

Risk Manager Expertise Domains Link to heading

┌─────────────────────────────────────────────────────────────────────────────┐
│                     RISK MANAGER EXPERTISE DOMAINS                           │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   CORE (Must Have)              ADJACENT (Should Know)     NOT THEIR JOB    │
│   ─────────────────             ────────────────────────   ──────────────   │
│   • Risk measurement            • Strategy mechanics       • Alpha views    │
│   • Limit framework design      • Market microstructure    • Trade ideas    │
│   • Tail risk / stress testing  • Regulatory landscape     • Execution      │
│   • Correlation / factor models • Basic trading P&L        • Stock picking  │
│   • Liquidity risk              • Technology basics        • Sizing advice  │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

1. Risk Measurement (The Core Job) Link to heading

SkillWhat It MeansExample
VaR / Expected ShortfallQuantify potential loss“95% 1-day VaR is $2.3M”
Factor decompositionUnderstand risk sources“72% of risk is from equity beta”
Correlation modelingHow positions interact“These two trades are 0.8 correlated under stress”
Stress testingWhat happens in extremes“In 2008-style event, we lose 23%”

2. Limit Framework Design Link to heading

class RiskLimitFramework:
    """
    Risk Manager designs the constraint structure.
    NOT the alpha - just the guardrails.
    """

    # Position limits
    limits = {
        "single_name": 0.10,          # No single stock > 10% NAV
        "sector": 0.30,                # No sector > 30%
        "gross_exposure": 2.0,         # Total |long| + |short| < 200%
        "net_exposure": 0.50,          # |long - short| < 50%
    }

    # Drawdown limits
    drawdown_limits = {
        "daily": -0.03,                # Stop trading if down 3% in a day
        "weekly": -0.05,               # Reduce risk if down 5% in week
        "monthly": -0.10,              # Hard stop if down 10% in month
    }

    # Dynamic limits (tighten in stress)
    def adjust_for_regime(self, current_vol):
        """Limits tighten when vol spikes"""
        vol_ratio = current_vol / self.baseline_vol
        return {k: v / vol_ratio for k, v in self.limits.items()}

    def escalation_matrix(self, breach_type, severity):
        """Who gets called when limits breach"""
        return {
            ("position", "soft"): "alert_pm",
            ("position", "hard"): "force_reduce",
            ("drawdown", "soft"): "alert_cio",
            ("drawdown", "hard"): "halt_trading",
        }[(breach_type, severity)]

3. The Risk Manager’s Questions Link to heading

┌─────────────────────────────────────────────────────────────────┐
│  WHAT A RISK MANAGER ASKS (vs PM)                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  PM asks:                          RISK MANAGER asks:           │
│  ─────────                         ─────────────────            │
│  "Will this trade make money?"     "Can this trade blow us up?" │
│  "What's the expected return?"     "What's the maximum loss?"   │
│  "Why is this undervalued?"        "What if we're wrong?"       │
│  "When will catalyst happen?"      "How fast can we exit?"      │
│                                                                 │
│  PM thinks in: E[return]           RM thinks in: P[ruin]        │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

4. Stress Testing & Scenario Analysis Link to heading

Scenario TypeWhat It TestsExample
HistoricalReplay past crisis“What if 2020 COVID crash repeats?”
HypotheticalImagine new scenario“What if China invades Taiwan?”
SensitivityMove one factor“What if rates up 100bps?”
ReverseWhat kills us?“What scenario causes -20% drawdown?”

5. Independence & Incentives Link to heading

┌─────────────────────────────────────────────────────────────────┐
│  WHY RISK MANAGER MUST BE INDEPENDENT                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  WRONG STRUCTURE:                  RIGHT STRUCTURE:             │
│  ───────────────                   ────────────────             │
│  Risk reports to PM                Risk reports to CEO/Board    │
│  Risk paid on fund P&L             Risk paid on risk metrics    │
│  Risk "advises"                    Risk has veto power          │
│                                                                 │
│  If Risk is paid on P&L, they'll approve risky trades.          │
│  The whole point is to be the person who says "no."             │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

6. What a Risk Manager Does NOT Do Link to heading

  • ❌ Have alpha views → “I think this trade is bad” (opinion on return)
  • ❌ Size positions → “You should do 2% not 3%” (that’s PM’s job)
  • ❌ Pick execution algo → That’s Trader (L3)
  • ❌ Override PM on alpha → Only on RISK, not on whether trade is “good”

Risk Manager Archetypes Link to heading

TypeFocusTools
Market RiskVaR, Greeks, factor exposureRisk systems, Bloomberg
Credit RiskCounterparty, default probabilityCredit models, ratings
Operational RiskProcess failures, fraudAudit logs, controls
Liquidity RiskCan we exit positions?Volume analysis, stress tests

The Risk Manager’s unique value: Being the person who survives career pressure to say “no” when everyone else is euphoric. Good risk managers are pessimists by design — they imagine everything that could go wrong.


Deep Dive: Trader Expertise Link to heading

Since Traders sit at L3 (Order Management), their expertise centers on “how should we do it” — executing orders efficiently without moving markets.

Trader Expertise Domains Link to heading

┌─────────────────────────────────────────────────────────────────────────────┐
│                        TRADER EXPERTISE DOMAINS                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   CORE (Must Have)              ADJACENT (Should Know)     NOT THEIR JOB    │
│   ─────────────────             ────────────────────────   ──────────────   │
│   • Market microstructure       • Strategy intent          • Alpha views    │
│   • Execution algorithms        • Risk constraints         • Position sizing│
│   • Liquidity assessment        • Regulatory rules         • Trade ideas    │
│   • Order book dynamics         • Technology basics        • Limit setting  │
│   • Venue selection             • Settlement/clearing      • P&L targets    │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

1. Market Microstructure (The Core Expertise) Link to heading

ConceptWhat It MeansWhy It Matters
Bid-ask spreadCost of immediacyCrossing spread = guaranteed loss
Market depthSize at each priceDetermines slippage on large orders
Order book dynamicsHow book reactsAnticipate price impact
Toxic flowInformed vs noise tradersAvoid being picked off
Venue fragmentationMultiple exchangesRoute to best liquidity

2. Execution Algorithm Selection Link to heading

class ExecutionRouter:
    """
    Trader decides HOW to execute, not WHAT to execute.
    """

    def select_algo(self, order, market_conditions):
        """Match algo to order characteristics"""

        # Urgency vs cost tradeoff
        if order.urgency == "immediate":
            return MarketOrder()  # Pay the spread, get it done

        # Large orders need slicing
        if order.size > market_conditions.avg_daily_volume * 0.05:
            if order.urgency == "low":
                return VWAP(duration="1day", participation=0.10)
            else:
                return TWAP(duration="2hours")

        # Small, patient orders
        if order.urgency == "low":
            return PassiveLimit(chase_interval="30s")

        # Default
        return AdaptiveAlgo(aggression=self.calc_aggression(order))

    def calc_aggression(self, order):
        """Balance urgency against market impact"""
        base_aggression = {"immediate": 1.0, "high": 0.7, "medium": 0.4, "low": 0.1}
        return base_aggression[order.urgency]

3. The Trader’s Mental Model Link to heading

┌─────────────────────────────────────────────────────────────────┐
│  TRADER'S CORE TRADEOFF                                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│                    URGENCY                                      │
│                       ▲                                         │
│                       │                                         │
│   Cross spread        │        Miss the move                    │
│   High impact    ◄────┼────►   Low impact                       │
│   Certain fill        │        May not fill                     │
│                       │                                         │
│                       ▼                                         │
│                   PATIENCE                                      │
│                                                                 │
│   Trader's job: Find the right point on this spectrum           │
│   for each order given PM's intent and market conditions.       │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

4. Liquidity Assessment Link to heading

QuestionHow Trader AnswersImplication
“How much can I trade?”Look at ADV, book depthSize algo participation rate
“When is liquidity best?”Analyze intraday patternsTime the execution
“Which venue is best?”Compare spreads, depthRoute orders smartly
“Is flow toxic?”Monitor fill rates, adverse selectionAdjust aggression

5. Information the Trader Needs from PM Link to heading

┌─────────────────────────────────────────────────────────────────┐
│  WHAT TRADER NEEDS TO KNOW (Communication Interface)            │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  FROM PM:                          TRADER DOESN'T NEED:         │
│  ────────                          ────────────────────         │
│  • Direction (buy/sell)            • Full investment thesis     │
│  • Size                            • Why PM likes the trade     │
│  • Urgency level                   • Expected return            │
│  • Time horizon for completion     • Other portfolio positions  │
│  • Any price limits                • PM's conviction level      │
│  • Special instructions            • Macro views                │
│                                                                 │
│  "Buy 50k AAPL, medium urgency, complete by EOD, limit $185"   │
│  That's all the trader needs.                                   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

6. Execution Quality Metrics Link to heading

MetricDefinitionTarget
Implementation shortfallActual vs decision priceMinimize
VWAP slippageActual vs VWAPBeat VWAP
Market impactPrice move caused by our orderMinimize
Fill rate% of order filledBalance with cost
Timing costCost of delayed executionDepends on urgency

7. What a Trader Does NOT Do Link to heading

  • ❌ Have alpha views → “I think AAPL is overvalued” (not their call)
  • ❌ Size the position → PM says 50k shares, trader executes 50k
  • ❌ Change direction → If PM says buy, don’t sell because you disagree
  • ❌ Set risk limits → That’s Risk Manager (L1)
  • ❌ Question the trade → Execute first, ask PM later if confused

Trader Archetypes Link to heading

TypeFocusTools
Cash EquitySingle stocks, ETFsAlgo wheel, DMA, broker algos
DerivativesOptions, futuresGreeks, vol surface
FXCurrency pairsECNs, bank relationships
Fixed IncomeBonds, ratesDealer network, RFQ platforms
CryptoDigital assetsCEX/DEX routing, MEV protection

The Trader-PM Relationship Link to heading

┌─────────────────────────────────────────────────────────────────┐
│  HEALTHY vs UNHEALTHY DYNAMICS                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  HEALTHY:                          UNHEALTHY:                   │
│  ────────                          ──────────                   │
│  PM: "Buy 50k AAPL, medium"        PM: "Buy AAPL, whatever you  │
│  Trader: "Will TWAP over 2hr"          think is right"         │
│  PM: "Sounds good"                 (PM abdicating sizing)       │
│                                                                 │
│  Trader: "Market thin today,       Trader: "I don't like this   │
│           suggest slower pace"          trade, doing half"     │
│  PM: "Ok, extend to 4hr"           (Trader overriding alpha)    │
│                                                                 │
│  Trader gives execution feedback.  Trader makes alpha decisions.│
│  PM adjusts if needed.             PM loses control.            │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

The Trader’s unique value: Understanding market microstructure deeply enough to minimize execution cost. A good trader can save 10-50bps per trade, which compounds to significant alpha over time. They’re specialists in the “last mile” of turning investment ideas into actual positions.


Part 2: The Software Architecture Link to heading

Now that we understand how humans organize trading operations, let’s see how software should mirror these same principles.

The Four Levels of Abstraction Link to heading

Every trading system, regardless of complexity, can be understood through four levels of abstraction:

┌─────────────────────────────────────────────────────────────────┐
│  LEVEL 1: RISK MANAGEMENT                                       │
│  "What can't I do?" — Hard limits, constraints, don't blow up   │
├─────────────────────────────────────────────────────────────────┤
│  LEVEL 2: SIGNAL GENERATION                                     │
│  "What should I do?" — Alpha logic, buy/sell decisions          │
├─────────────────────────────────────────────────────────────────┤
│  LEVEL 3: ORDER MANAGEMENT                                      │
│  "How should I do it?" — TWAP, VWAP, execution algorithms       │
├─────────────────────────────────────────────────────────────────┤
│  LEVEL 4: MARKET ACCESS                                         │
│  "Send the order" — Exchange APIs, connectivity                 │
└─────────────────────────────────────────────────────────────────┘

The key insight: Each layer has a single responsibility and communicates through well-defined interfaces. This separation allows you to:

  • Swap execution algorithms without touching alpha logic
  • Add new alpha strategies without changing risk infrastructure
  • Test signals without real money
  • Scale each layer independently

Level 1: Risk Management (Not Allocation!) Link to heading

Here’s a common mistake I see: conflating portfolio allocation with risk management.

The Wrong Way Link to heading

# L1 as "Portfolio Allocation" — PROBLEMATIC
class Level1:
    target_weights = {"QQQ": 0.70, "XAU": 0.30}  # This is an alpha view!

This creates problems:

  • The “30% QQQ target” is actually a bet that QQQ exposure is desirable
  • L1 ends up blocking L2 signals that disagree
  • You can’t tell if returns came from allocation alpha or trading alpha

The Right Way Link to heading

# L1 as "Pure Risk Management" — CLEAN
class Level1:
    """
    L1 = ONLY risk constraints. No alpha views.
    Just: "Don't do anything that could blow up the portfolio."
    """

    # Position limits
    max_single_position = 0.40      # No single position > 40%
    max_gross_exposure = 1.50       # Total |long| + |short| < 150%
    max_net_exposure = 1.00         # Net exposure < 100%

    # Drawdown limits
    max_drawdown = -0.15            # Stop if down 15%

    # Leverage limits
    max_leverage = 2.0

    # Liquidity
    min_cash_buffer = 0.05          # Always keep 5% cash

    def check(self, signal, portfolio):
        """
        Pure risk check. No opinion on whether trade is "good".
        Just: "Is this safe?"
        """
        projected = portfolio.project_state(signal)

        if projected.single_position > self.max_single_position:
            return Reject("position_limit")
        if projected.gross_exposure > self.max_gross_exposure:
            return Reject("gross_exposure")
        if portfolio.drawdown < self.max_drawdown:
            return Reject("drawdown_limit")

        return Approve()

The principle: L1 should have NO OPINION on whether a trade is profitable. It only ensures the trade is safe.

Portfolio allocation (like “30% QQQ”) should be a Level 2 alpha signal that competes with other alpha signals on equal footing.


Level 2: Signal Generation Link to heading

Level 2 is where all alpha views live—including strategic allocation.

Multiple Time Horizons, One Framework Link to heading

class MultiAlphaL2:
    """
    All alpha sources compete on equal footing.
    Different time horizons, same interface.
    """

    alphas = {
        # Slow: Strategic allocation (monthly/quarterly)
        "strategic": StrategicAllocationAlpha(
            target_weights={"QQQ": 0.30, "XAU": 0.20, "CASH": 0.50},
            rebalance_freq="monthly",
            conviction=0.8
        ),

        # Medium: Tactical allocation (weekly)
        "tactical": TacticalRegimeAlpha(
            signals=["momentum", "value", "volatility"],
            rebalance_freq="weekly",
            conviction=0.5
        ),

        # Fast: Trading alpha (daily)
        "sma_cross": SMACrossoverAlpha(
            fast_period=10,
            slow_period=50,
            conviction=0.3
        ),
    }

    def generate_signals(self, market_data):
        """Aggregate all alpha signals by conviction weight"""

        all_signals = defaultdict(list)

        for name, alpha in self.alphas.items():
            for signal in alpha.generate(market_data):
                all_signals[signal.instrument].append({
                    "source": name,
                    "direction": signal.direction,
                    "conviction": signal.conviction * alpha.conviction
                })

        # Combine signals per instrument
        return self._aggregate(all_signals)

The Signal Interface Link to heading

A signal should express intent, not execution details:

@dataclass
class Signal:
    instrument: str          # What to trade
    direction: str           # "BUY" or "SELL"
    size: float              # How much (in units or notional)

    # Execution hints (not full specs)
    urgency: str             # "immediate" | "high" | "medium" | "low"
    horizon: str             # How long can execution take?

    # Metadata
    source: str              # Which alpha generated this
    conviction: float        # How confident (0-1)
    expected_return: float   # For logging/analysis

The key: Signals say WHAT to do and roughly HOW URGENTLY. They don’t specify TWAP vs VWAP—that’s Level 3’s job.


Level 3: Order Management Link to heading

Level 3 translates intent into execution. The signal’s urgency naturally maps to execution strategy:

class ExecutionRouter:
    """
    Maps signal urgency to execution algorithm
    """

    URGENCY_TO_ALGO = {
        "immediate": ("MARKET", {"timeout": "1s"}),
        "high":      ("TWAP", {"duration": "2min"}),
        "medium":    ("TWAP", {"duration": "10min"}),
        "low":       ("PASSIVE", {"duration": "1hour"})
    }

    def execute(self, signal):
        algo, params = self.URGENCY_TO_ALGO[signal.urgency]

        # Adjust for size (larger orders need more time)
        if signal.size > self.large_order_threshold:
            params["duration"] *= 2

        return self.algo_router.run(algo, signal, params)

Order Types Spectrum Link to heading

From simple to complex:

TypeUse CaseExample
MarketImmediate fill, any priceEmergency exit
LimitSpecific price, may not fillPatient entry
TWAPTime-slice large orderBuy 100 BTC over 1 hour
VWAPVolume-weighted executionMatch market volume profile
IcebergHide order sizeLarge institutional order
AdaptiveAdjust based on market conditionsSmart order routing

Level 4: Market Access Link to heading

The final layer translates internal order representation to exchange-specific API calls:

class MarketAccess:
    """
    Exchange connectivity layer
    """

    def submit_order(self, order):
        exchange = self.get_exchange(order.instrument)

        # Translate to exchange format
        exchange_order = {
            "symbol": self.translate_symbol(order.instrument),
            "side": order.direction.upper(),
            "type": self.translate_order_type(order.type),
            "quantity": str(order.size),
            "price": str(order.price) if order.price else None,
        }

        response = exchange.api.place_order(**exchange_order)
        return self.parse_response(response)

MA should be thin: It handles connectivity, rate limits, and API translation—nothing more.


The OMS and PMS: Bookkeeping Layers Link to heading

Two critical systems that don’t fit neatly into the four levels: Order Management System (OMS) and Portfolio Management System (PMS).

OMS: The Transaction Ledger Link to heading

OMS tracks every order from birth to death:

┌─────────────────────────────────────────────────────────────────┐
│  ORDER LIFECYCLE IN OMS                                         │
│                                                                 │
│  NEW → PENDING → PARTIAL_FILL → FILLED                         │
│           │                        │                            │
│           └──→ CANCELLED ←─────────┘                            │
│           └──→ REJECTED                                         │
│           └──→ EXPIRED                                          │
└─────────────────────────────────────────────────────────────────┘

OMS Tracks:
- Order ID, status, timestamps
- Original vs filled quantity
- Average fill price
- Commission, fees
- Parent-child relationships (for algo orders)

Virtual balances: OMS maintains its own view of balances, updated immediately when orders are placed/filled. This is faster than querying the exchange.

PMS: The Control Room Link to heading

PMS monitors portfolio state and risk:

class PMS:
    """
    Portfolio Management System

    NOT in the order path! Runs in parallel.
    Observes, calculates, signals.
    """

    def run_monitoring_loop(self):
        while True:
            # 1. Observe: Get latest positions from OMS
            positions = self.sync_from_oms()

            # 2. Calculate: Risk metrics
            pnl = self.calculate_pnl(positions)
            exposure = self.calculate_exposure(positions)
            drawdown = self.calculate_drawdown(positions)

            # 3. Signal: Set flags if limits breached
            if pnl < self.pnl_limit:
                self.set_flag("pnl_breach", True)
            if exposure > self.exposure_limit:
                self.set_flag("exposure_breach", True)

            time.sleep(self.check_interval)

Critical insight: PMS does NOT reject orders directly. It sets flags that execution loops check:

┌─────────────────────────────────────────────────────────────────┐
│  PMS IS NOT A GATE — IT'S A CONTROL ROOM                        │
│                                                                 │
│  Orders flow:  Strategy → OMS → Exchange                        │
│                              ↑                                  │
│                              │ Check flags                      │
│  PMS monitors: ────────→ Redis Flags ←──── Set flags           │
│                                                                 │
│  Execution loops check flags BEFORE placing orders.             │
│  PMS doesn't block; it turns on warning lights.                 │
└─────────────────────────────────────────────────────────────────┘

Part 3: Advanced Topics Link to heading

Rule-Based vs Statistical Approaches Link to heading

Two paradigms for signal generation:

Rule-Based (Traditional Quant) Link to heading

class RuleBasedSignal:
    """
    IF indicator crosses threshold THEN trade
    """

    def generate(self, prices):
        sma_fast = prices[-10:].mean()
        sma_slow = prices[-50:].mean()

        if sma_fast > sma_slow:
            return Signal(direction="BUY")  # Discrete output
        return None

Characteristics:

  • Discrete output: BUY/SELL/HOLD
  • No probability attached
  • Hand-crafted rules
  • Easy to understand and debug

Statistical Expected Value Link to heading

class StatisticalEVSignal:
    """
    Predict E[return] for each decision, trade if EV > threshold
    """

    def generate(self, features):
        # ML model predicts expected return
        ev_buy = self.model.predict(features)["ev_buy"]
        ev_sell = self.model.predict(features)["ev_sell"]

        # The "rule" is just: EV > threshold
        net_ev = ev_buy - self.fee_rate

        if net_ev > self.min_edge:
            return Signal(
                direction="BUY",
                expected_return=net_ev,
                confidence=self.model.confidence
            )
        return None

Characteristics:

  • Continuous output: expected return
  • Probability/confidence attached
  • ML model (trainable)
  • Harder to interpret

They Can Coexist Link to heading

# Wrap statistical model in rule interface
class StatModelWrapper:
    def generate(self, market_data):
        ev = self.model.predict(market_data)

        # Statistical output → Rule-based interface
        if ev - self.fee > self.threshold:
            return Signal(direction="BUY")
        return None

The framework doesn’t care what’s inside the signal generator. It just needs a Signal out.


Backtesting: Matching Fidelity to Purpose Link to heading

Different questions require different backtest fidelity:

Level 1: Signal-Only (Fast Iteration) Link to heading

def backtest_l1(signals, prices):
    """
    Assumption: Fill at signal price + flat haircut
    """
    pnl = 0
    slippage = 0.001  # 10 bps

    for signal in signals:
        entry = prices[signal.entry_time] * (1 + slippage)
        exit = prices[signal.exit_time] * (1 - slippage)
        pnl += (exit - entry) * signal.size

    return pnl

Use for: Idea screening, early research Ignores: Order book, partial fills, market impact

Level 2: Execution-Aware (Development) Link to heading

def backtest_l2(signals, prices, volumes):
    """
    Model execution costs based on size and urgency
    """
    pnl = 0

    for signal in signals:
        # Size-dependent slippage (square root model)
        size_fraction = signal.size / volumes[signal.time]
        impact = 0.1 * sqrt(size_fraction)

        # Urgency multiplier
        urgency_cost = {"immediate": 3, "high": 2, "medium": 1, "low": 0.5}

        total_cost = (0.0001 + impact) * urgency_cost[signal.urgency]

        entry = prices[signal.entry_time] * (1 + total_cost)
        # ...

Use for: Strategy development, parameter tuning Models: Size impact, urgency costs Ignores: Order book dynamics, queue position

Level 3: Full Simulation (Pre-Production) Link to heading

def backtest_l3(signals, order_book_history, trades_history):
    """
    Simulate actual order book interaction
    """
    for signal in signals:
        fills = simulate_twap(
            signal,
            order_book_history,
            trades_history,
            duration="10min",
            slices=20
        )
        # Models: Queue position, partial fills, actual algo behavior

Use for: Pre-production validation, HFT Models: Everything Cost: Slow, requires tick data

When to Use What Link to heading

Strategy TypeHold TimeRecommended Backtest
Weekly rebalanceWeeksLevel 1
Swing tradingDaysLevel 1-2
Intraday momentumHoursLevel 2
Stat arbMinutesLevel 2-3
Market makingSecondsLevel 3

Continuous Signals and Position Sizing Link to heading

A common question: When SMA says “bullish,” do I keep buying every day?

No. A continuous signal represents a TARGET POSITION, not repeated trades.

Event vs State Link to heading

# EVENT-BASED: Trade on state changes
def generate_signal_event(self, prices):
    current_state = "BULLISH" if sma_fast > sma_slow else "BEARISH"

    if current_state != self.previous_state:
        self.previous_state = current_state
        return Signal(direction="BUY" if current_state == "BULLISH" else "SELL")

    return None  # No signal while state unchanged

# STATE-BASED: Signal = target position
def generate_signal_state(self, prices, current_position):
    if sma_fast > sma_slow:
        target = 0.30  # Want to be 30% long while bullish
    else:
        target = 0.00  # Want to be flat while bearish

    delta = target - current_position

    if abs(delta) > 0.01:
        return Signal(direction="BUY" if delta > 0 else "SELL", size=abs(delta))

    return None

Sizing Methods Link to heading

1. Fixed Size

target = 0.30  # Always 30% when bullish

2. Conviction-Based

spread = (sma_fast - sma_slow) / sma_slow
conviction = min(abs(spread) / 0.05, 1.0)
target = max_position * conviction

3. Risk-Budget-Based

risk_budget = 0.05  # 5% vol contribution
asset_vol = get_volatility(instrument)
target = risk_budget / asset_vol  # Inverse vol scaling

Adaptive Risk Systems Link to heading

Different strategies need different risk check intensities. Match the risk infrastructure to the strategy speed.

The Spectrum Link to heading

StrategyPosition Δ/hrRisk CheckImplementation
HFT/MM1000sEvery tickSync, pre-order
Stat arb100sEvery 100msAsync, fast cache
Intraday10sEvery 10sFlag-based
Swing1-2Every minutePeriodic batch
Long-term<1Every 5minDashboard

Pluggable Risk Tiers Link to heading

class AdaptiveRiskRouter:
    """
    Route signals to appropriate risk checker based on urgency
    """

    def __init__(self):
        self.checkers = {
            "realtime": RealtimeRiskChecker(),  # HFT-grade
            "fast": FastRiskChecker(),          # 100ms cache
            "standard": StandardRiskChecker(),  # Flag-based
            "relaxed": RelaxedRiskChecker(),    # Batch
        }

        self.urgency_to_tier = {
            "immediate": "realtime",
            "high": "fast",
            "medium": "standard",
            "low": "relaxed"
        }

    def check(self, signal):
        tier = self.urgency_to_tier[signal.urgency]
        return self.checkers[tier].check(signal)

Start Simple, Scale Up Link to heading

class RealtimeRiskChecker:
    """
    STUB: Reserved for future HFT implementation
    Falls back to fast tier until needed
    """

    def __init__(self):
        self.enabled = config.get("realtime_enabled", False)
        if not self.enabled:
            self.fallback = FastRiskChecker()

    def check(self, signal):
        if not self.enabled:
            return self.fallback.check(signal)
        # Future: implement microsecond checks

This lets you build infrastructure incrementally—start with flag-based checks, add HFT-grade when needed.


Putting It All Together Link to heading

Here’s how all the pieces fit:

┌─────────────────────────────────────────────────────────────────────────────┐
│                         COMPLETE TRADING SYSTEM                              │
│                                                                              │
│   MARKET DATA                                                                │
│        │                                                                     │
│        ▼                                                                     │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │  LEVEL 2: SIGNAL GENERATION (All Alpha)                             │   │
│   │                                                                      │   │
│   │  ┌──────────────┐ ┌──────────────┐ ┌──────────────┐                │   │
│   │  │  Strategic   │ │   Tactical   │ │   Trading    │                │   │
│   │  │  Allocation  │ │    Alpha     │ │    Alpha     │                │   │
│   │  │  (monthly)   │ │   (weekly)   │ │   (daily)    │                │   │
│   │  └──────────────┘ └──────────────┘ └──────────────┘                │   │
│   │           │               │               │                         │   │
│   │           └───────────────┼───────────────┘                         │   │
│   │                           │                                          │   │
│   │                    SIGNAL AGGREGATOR                                 │   │
│   │                  (conviction-weighted)                               │   │
│   └───────────────────────────┬─────────────────────────────────────────┘   │
│                               │                                              │
│                               ▼                                              │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │  LEVEL 1: RISK CHECK (Pure Safety)                                  │   │
│   │                                                                      │   │
│   │  Position limits? ✓   Leverage? ✓   Drawdown? ✓   Cash buffer? ✓   │   │
│   │                                                                      │   │
│   │  [Adaptive: tier selected by signal.urgency]                        │   │
│   └───────────────────────────┬─────────────────────────────────────────┘   │
│                               │                                              │
│                               ▼                                              │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │  LEVEL 3: ORDER MANAGEMENT                                          │   │
│   │                                                                      │   │
│   │  Urgency → Algo Selection → Order Slicing → Child Orders            │   │
│   │                                                                      │   │
│   │  OMS tracks: status, fills, virtual balances                        │   │
│   └───────────────────────────┬─────────────────────────────────────────┘   │
│                               │                                              │
│                               ▼                                              │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │  LEVEL 4: MARKET ACCESS                                             │   │
│   │                                                                      │   │
│   │  Internal format → Exchange API → Submit                            │   │
│   └───────────────────────────┬─────────────────────────────────────────┘   │
│                               │                                              │
│                               ▼                                              │
│                          EXCHANGES                                           │
│                               │                                              │
│                               │ Fills                                        │
│                               ▼                                              │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │  PMS (Parallel Monitoring)                                          │   │
│   │                                                                      │   │
│   │  Observe positions → Calculate risk → Set flags if breach           │   │
│   │                                                                      │   │
│   │  [Feeds back to L1 risk checks]                                     │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘

Key Takeaways Link to heading

  1. Separate concerns clearly. L1 = safety, L2 = alpha, L3 = execution, L4 = connectivity.

  2. Portfolio allocation is alpha. Put it in L2, not L1. L1 should only contain hard risk limits.

  3. Signals express intent, not execution. Use urgency hints; let L3 choose the algo.

  4. Match infrastructure to strategy speed. Don’t build HFT plumbing for a weekly rebalancer.

  5. PMS monitors, OMS tracks. Neither should be in the critical order path.

  6. Continuous signals = target positions. Trade the delta, not a new order every tick.

  7. Backtest at the right fidelity. Level 1 for screening, Level 2 for development, Level 3 for validation.

  8. Build incrementally. Stub the HFT risk tier; implement when needed.


Final Thoughts Link to heading

The best trading systems I’ve seen share a common trait: they’re boring. The architecture is clean, the responsibilities are clear, and there are no clever hacks.

When you’re tempted to add complexity, ask: “Does this belong in L1, L2, L3, or L4?” If the answer isn’t immediately obvious, you’re probably mixing concerns.

Build the simple version first. Make it work. Then scale.


If you found this useful, feel free to share. Questions and feedback welcome.