AlgoDaily

Live Trading and Deployment

Read at your own pace. Code execution, quizzes, progress tracking, and the AI tutor are available in the interactive view with JavaScript enabled.

From Tested To Live

Your final course step

Now that you've completed Introduction to Algorithmic Trading, Data Retrieval and Preprocessing, Building Trading Models, and Backtesting and Performance Evaluation, you have the full offline trading loop:

  • Retrieve and align market data
  • Build multi-timeframe features
  • Generate model decisions
  • Evaluate performance with friction and bias awareness

This lesson moves from research code to a live trading system. The goal is not to make the strategy more clever. It is to make the system safer, observable, and recoverable when real markets, APIs, latency, and failures appear.

Live deployment is where algorithmic trading becomes software engineering under financial risk.

From Tested To Live

Live System Shape

The deployment contract

A live trading system should be split into clear responsibilities. This keeps your C++ code testable and prevents a model bug from becoming an execution disaster.

Market Data API
      |
      v
Preprocessing + Multi-Timeframe Aggregation
      |
      v
Model / Signal Engine
      |
      v
Risk Gate
      |
      v
Execution Adapter ---> Broker / Exchange API
      |
      v
Logs + Metrics + Reconciliation

The important shift: your model no longer directly means “place a trade.”

A model produces an intent. The risk gate and execution layer decide whether, how, and when that intent becomes an order.

Live System Shape

Deployment Boundary

In a live trading system, what is the best role for the model component?

Order State Machine

Orders are not instant

Backtests often treat a trade as one clean event. Live trading does not.

An order may be submitted, partially filled, rejected, canceled, or filled later than expected. So your execution code should track state transitions, not just “buy” or “sell.”

A small state machine gives you a safer foundation for real broker APIs.

```cpp
#include <iostream>
#include <string>

enum class OrderState {
    Created,
    Submitted,
    PartiallyFilled,
    Filled,
    Rejected,
    Cancelled
};

std::string toString(OrderState s) {
    switch (s) {
        case OrderState::Created: return "Created";
        case OrderState::Submitted: return "Submitted";
        case OrderState::PartiallyFilled: return "PartiallyFilled";
        case OrderState::Filled: return "Filled";
        case OrderState::Rejected: return "Rejected";
        case OrderState::Cancelled: return "Cancelled";
    }
    return "Unknown";
}

bool canTransition(OrderState from, OrderState to) {
    if (from == OrderState::Created && to == OrderState::Submitted) return true;
    if (from == OrderState::Submitted && to == OrderState::PartiallyFilled) return true;
    if (from == OrderState::Submitted && to == OrderState::Filled) return true;
    if (from == OrderState::Submitted && to == OrderState::Rejected) return true;
    if (from == OrderState::Submitted && to == OrderState::Cancelled) return true;
    if (from == OrderState::PartiallyFilled && to == OrderState::Filled) return true;
    if (from == OrderState::PartiallyFilled && to == OrderState::Cancelled) return true;
    return false;
}

struct Order {
    int id;
    std::string symbol;
    int quantity;
    OrderState state = OrderState::Created;

    void apply(OrderState next) {
        std::cout << "Order " << id << ": " << toString(state)
                  << " -> " << toString(next);

        if (canTransition(state, next)) {
            state = next;
            std::cout << " accepted\n";
        } else {
            std::cout << " BLOCKED\n";
        }
    }
};

int main() {
    Order order{101, "AAPL", 50};

    order.apply(OrderState::Submitted);
    order.apply(OrderState::PartiallyFilled);
    order.apply(OrderState::Filled);

    // This should be blocked: a filled order cannot be cancelled.
    order.apply(OrderState::Cancelled);

    std::cout << "Final state: " << toString(order.state) << "\n";
    return 0;
}
```

Paper Before Capital

True or false: if a strategy had strong backtest metrics in the previous lesson, it is safe to connect it directly to a live broker with real capital.

Risk Gate Code

The model asks. Risk decides.

In earlier lessons, you built signals from time series and model rules. In live deployment, every signal should pass a risk gate before execution.

Common checks include:

  • Maximum order quantity
  • Maximum notional exposure
  • Daily loss limits
  • Kill switch state
  • Whether the system is already in a conflicting position

A risk gate should be boring, explicit, and easy to audit.

```cpp
#include <iostream>
#include <string>
#include <cmath>

struct Signal {
    std::string symbol;
    int targetQuantity;   // positive = long, negative = short
    double referencePrice;
};

struct RiskConfig {
    int maxAbsQuantity = 100;
    double maxNotional = 25000.0;
    double maxDailyLoss = 500.0;
    bool killSwitch = false;
};

struct AccountState {
    double realizedPnlToday = 0.0;
};

class RiskGate {
public:
    explicit RiskGate(RiskConfig config) : config_(config) {}

    bool approve(const Signal& signal, const AccountState& account) const {
        double notional = std::abs(signal.targetQuantity) * signal.referencePrice;

        if (config_.killSwitch) {
            std::cout << "Rejected: kill switch is active\n";
            return false;
        }
        if (std::abs(signal.targetQuantity) > config_.maxAbsQuantity) {
            std::cout << "Rejected: quantity limit exceeded\n";
            return false;
        }
        if (notional > config_.maxNotional) {
            std::cout << "Rejected: notional limit exceeded\n";
            return false;
        }
        if (account.realizedPnlToday < -config_.maxDailyLoss) {
            std::cout << "Rejected: daily loss limit exceeded\n";
            return false;
        }

        std::cout << "Approved: " << signal.symbol
                  << " qty=" << signal.targetQuantity
                  << " notional=$" << notional << "\n";
        return true;
    }

private:
    RiskConfig config_;
};

int main() {
    RiskConfig config;
    AccountState account{-120.0};
    RiskGate gate(config);

    Signal conservative{"MSFT", 40, 310.50};
    Signal tooLarge{"NVDA", 300, 875.00};

    gate.approve(conservative, account);
    gate.approve(tooLarge, account);

    return 0;
}
```

Observe Everything

If you cannot observe it, you cannot operate it

A live strategy needs telemetry. Not just for debugging, but for survival.

Track at least:

  • Market data heartbeat: are candles/ticks still arriving?
  • Signal heartbeat: is the model still producing decisions?
  • Order events: submitted, rejected, filled, canceled
  • Position state: internal position vs broker position
  • Risk state: exposure, drawdown, kill switch status
  • Latency: data arrival to decision to order submission

A practical rule: every important state transition should produce a structured log line.

timestamp | component | symbol | event | details

When something goes wrong at 9:47:03, your logs should tell the story without guessing.

Observe Everything

Safety Trigger

Fill in the blank: a manual or automatic control that immediately prevents new orders from being sent is commonly called a ________.

Reconcile Broker State

Your system can be wrong

In live trading, your internal state is only an estimate until confirmed by the broker or exchange.

Problems happen:

  • A fill message arrives late
  • Your process restarts
  • An order is partially filled before cancellation
  • The API disconnects during a position change

So a deployed system should periodically reconcile internal state against broker-reported state. This prevents your strategy from making decisions based on a position it does not actually have.

```cpp
#include <iostream>
#include <map>
#include <string>

using PositionBook = std::map<std::string, int>;

void printBook(const std::string& label, const PositionBook& book) {
    std::cout << label << "\n";
    for (const auto& [symbol, qty] : book) {
        std::cout << "  " << symbol << ": " << qty << " shares\n";
    }
}

void reconcile(PositionBook& internal, const PositionBook& broker) {
    for (const auto& [symbol, brokerQty] : broker) {
        int internalQty = internal[symbol];
        if (internalQty != brokerQty) {
            std::cout << "Mismatch on " << symbol
                      << ": internal=" << internalQty
                      << ", broker=" << brokerQty
                      << ". Updating internal state.\n";
            internal[symbol] = brokerQty;
        }
    }
}

int main() {
    PositionBook internal{{"AAPL", 100}, {"MSFT", 0}};

    // Broker shows a partial fill the internal engine missed.
    PositionBook broker{{"AAPL", 60}, {"MSFT", 0}};

    printBook("Before reconciliation:", internal);
    reconcile(internal, broker);
    printBook("After reconciliation:", internal);

    return 0;
}
```

Course Wrap

You now have the full loop

Across this course, you moved through the practical lifecycle of an algorithmic trading system:

  1. Introduction to Algorithmic Trading — defined the lifecycle, risk-first mindset, and C++ skeleton.
  2. Data Retrieval and Preprocessing — turned raw financial data into aligned, usable time series.
  3. Building Trading Models — transformed features, rules, curvature ideas, and multi-timeframe logic into model decisions.
  4. Backtesting and Performance Evaluation — tested those decisions with metrics, friction, and bias awareness.
  5. Live Trading and Deployment — added execution boundaries, risk gates, observability, and reconciliation.

The most important professional habit: separate the idea from the system.

An innovative alternative algorithm may generate the signal, but robust deployment determines whether it can survive contact with live markets.

Keep iterating carefully: paper trade, measure, reduce risk, deploy small, observe deeply, and never let automation outrun your controls.

Course Wrap

Open interactive view →