Design Market Data, Order Management, and Trade Signal for an Algorithmic Trading System
Here's a basic Java structure representing Market Data, Order Management, and Trade Signal for an algorithmic trading system. These can be expanded based on complexity like order types, strategy logic, exchange adapters, etc.
1. MarketData.java
— Represents a market data tick
public class MarketData {
private String symbol;
private double bidPrice;
private double askPrice;
private double lastTradedPrice;
private long timestamp;
public MarketData(String symbol, double bidPrice, double askPrice, double lastTradedPrice, long timestamp) {
this.symbol = symbol;
this.bidPrice = bidPrice;
this.askPrice = askPrice;
this.lastTradedPrice = lastTradedPrice;
this.timestamp = timestamp;
}
// Getters and Setters
public String getSymbol() { return symbol; }
public double getBidPrice() { return bidPrice; }
public double getAskPrice() { return askPrice; }
public double getLastTradedPrice() { return lastTradedPrice; }
public long getTimestamp() { return timestamp; }
@Override
public String toString() {
return String.format("MarketData[%s] Bid: %.2f Ask: %.2f LTP: %.2f", symbol, bidPrice, askPrice, lastTradedPrice);
}
}
2. TradeSignal.java
— Represents a trading signal
public class TradeSignal {
public enum SignalType { BUY, SELL, HOLD }
private String symbol;
private SignalType signalType;
private double confidenceScore;
public TradeSignal(String symbol, SignalType signalType, double confidenceScore) {
this.symbol = symbol;
this.signalType = signalType;
this.confidenceScore = confidenceScore;
}
public String getSymbol() { return symbol; }
public SignalType getSignalType() { return signalType; }
public double getConfidenceScore() { return confidenceScore; }
@Override
public String toString() {
return String.format("TradeSignal[%s] %s (Confidence: %.2f)", symbol, signalType, confidenceScore);
}
}
3. Order.java
— Represents an order
public class Order {
public enum OrderType { MARKET, LIMIT }
public enum Side { BUY, SELL }
private String orderId;
private String symbol;
private Side side;
private OrderType type;
private double price;
private int quantity;
private long timestamp;
public Order(String orderId, String symbol, Side side, OrderType type, double price, int quantity) {
this.orderId = orderId;
this.symbol = symbol;
this.side = side;
this.type = type;
this.price = price;
this.quantity = quantity;
this.timestamp = System.currentTimeMillis();
}
public String getOrderId() { return orderId; }
public String getSymbol() { return symbol; }
public Side getSide() { return side; }
public OrderType getType() { return type; }
public double getPrice() { return price; }
public int getQuantity() { return quantity; }
public long getTimestamp() { return timestamp; }
@Override
public String toString() {
return String.format("Order[%s] %s %s %d@%.2f", orderId, side, type, quantity, price);
}
}
4. OrderManager.java
— Handles order placement (mock logic)
import java.util.UUID;
public class OrderManager {
public Order placeOrder(String symbol, Order.Side side, Order.OrderType type, double price, int quantity) {
String orderId = UUID.randomUUID().toString();
Order order = new Order(orderId, symbol, side, type, price, quantity);
// Simulate sending to exchange
System.out.println("Placing order: " + order);
return order;
}
public void cancelOrder(Order order) {
// Simulate cancel logic
System.out.println("Cancelling order: " + order.getOrderId());
}
}
Example Usage:
public class AlgoTradingApp {
public static void main(String[] args) {
MarketData md = new MarketData("AAPL", 172.5, 173.0, 172.8, System.currentTimeMillis());
System.out.println(md);
TradeSignal signal = new TradeSignal("AAPL", TradeSignal.SignalType.BUY, 0.92);
System.out.println(signal);
OrderManager orderManager = new OrderManager();
if (signal.getSignalType() == TradeSignal.SignalType.BUY) {
orderManager.placeOrder("AAPL", Order.Side.BUY, Order.OrderType.MARKET, 0.0, 100);
}
}
}
Let’s build and add strategy logic (e.g., TWAP, momentum-based signals) with FIX engine integration.
1. Strategy Logic
We’ll implement:
TWAP (Time Weighted Average Price) strategy
Momentum-based signal generator
2. Strategy Interface
public interface TradingStrategy {
TradeSignal generateSignal(MarketData marketData);
}
3. TWAP Strategy
This strategy will place trades evenly across a time window.
import java.util.*;
public class TWAPStrategy implements TradingStrategy {
private final int totalQuantity;
private final long startTime;
private final long endTime;
private final int slices;
private int executedSlices = 0;
public TWAPStrategy(int totalQuantity, long startTime, long endTime, int slices) {
this.totalQuantity = totalQuantity;
this.startTime = startTime;
this.endTime = endTime;
this.slices = slices;
}
@Override
public TradeSignal generateSignal(MarketData marketData) {
long now = System.currentTimeMillis();
if (now < startTime || now > endTime || executedSlices >= slices) {
return new TradeSignal(marketData.getSymbol(), TradeSignal.SignalType.HOLD, 0.0);
}
long sliceInterval = (endTime - startTime) / slices;
long expectedTimeForNextSlice = startTime + (executedSlices * sliceInterval);
if (now >= expectedTimeForNextSlice) {
executedSlices++;
return new TradeSignal(marketData.getSymbol(), TradeSignal.SignalType.BUY, 1.0);
}
return new TradeSignal(marketData.getSymbol(), TradeSignal.SignalType.HOLD, 0.0);
}
}
4. Momentum Strategy
import java.util.LinkedList;
import java.util.Queue;
public class MomentumStrategy implements TradingStrategy {
private final Queue<Double> priceWindow = new LinkedList<>();
private final int windowSize;
public MomentumStrategy(int windowSize) {
this.windowSize = windowSize;
}
@Override
public TradeSignal generateSignal(MarketData marketData) {
priceWindow.add(marketData.getLastTradedPrice());
if (priceWindow.size() > windowSize) {
priceWindow.poll();
}
if (priceWindow.size() < windowSize) {
return new TradeSignal(marketData.getSymbol(), TradeSignal.SignalType.HOLD, 0.0);
}
double first = priceWindow.peek();
double last = marketData.getLastTradedPrice();
if (last > first * 1.01) {
return new TradeSignal(marketData.getSymbol(), TradeSignal.SignalType.BUY, 0.8);
} else if (last < first * 0.99) {
return new TradeSignal(marketData.getSymbol(), TradeSignal.SignalType.SELL, 0.8);
} else {
return new TradeSignal(marketData.getSymbol(), TradeSignal.SignalType.HOLD, 0.2);
}
}
}
5. FIX Engine Integration (Mocked for now)
For now, we'll mock a FIX order sender. Later we can plug in QuickFIX/J.
public class FixOrderSender {
public void send(Order order) {
System.out.println("[FIX] Sending order via FIX: " + order);
// Later: actual QuickFIX/J integration
}
}
6. TWAP Strategy
public class StrategyExecutor {
private final TradingStrategy strategy;
private final OrderManager orderManager;
private final FixOrderSender fixSender;
public StrategyExecutor(TradingStrategy strategy, OrderManager orderManager, FixOrderSender fixSender) {
this.strategy = strategy;
this.orderManager = orderManager;
this.fixSender = fixSender;
}
public void onMarketData(MarketData marketData) {
TradeSignal signal = strategy.generateSignal(marketData);
System.out.println("Signal: " + signal);
if (signal.getSignalType() == TradeSignal.SignalType.BUY) {
Order order = orderManager.placeOrder(marketData.getSymbol(), Order.Side.BUY, Order.OrderType.MARKET, 0.0, 100);
fixSender.send(order);
} else if (signal.getSignalType() == TradeSignal.SignalType.SELL) {
Order order = orderManager.placeOrder(marketData.getSymbol(), Order.Side.SELL, Order.OrderType.MARKET, 0.0, 100);
fixSender.send(order);
}
}
}
7. Main App
public class AlgoTradingSystem {
public static void main(String[] args) throws InterruptedException {
OrderManager orderManager = new OrderManager();
FixOrderSender fixSender = new FixOrderSender();
TradingStrategy strategy = new TWAPStrategy(
500,
System.currentTimeMillis(),
System.currentTimeMillis() + 60000,
5
);
// TradingStrategy strategy = new MomentumStrategy(3);
StrategyExecutor executor = new StrategyExecutor(strategy, orderManager, fixSender);
// Simulate incoming market data every 5 seconds
for (int i = 0; i < 10; i++) {
MarketData md = new MarketData("AAPL", 172.0 + i, 172.5 + i, 172.3 + i, System.currentTimeMillis());
executor.onMarketData(md);
Thread.sleep(5000);
}
}
}
8. Backtesting Framework (Lightweight & Pluggable)
This lets you simulate strategy performance on historical market data.
import java.util.List;
public class BacktestEngine {
private final TradingStrategy strategy;
private final OrderManager orderManager;
private final FixOrderSender fixSender;
public BacktestEngine(TradingStrategy strategy) {
this.strategy = strategy;
this.orderManager = new OrderManager(); // Could be mocked
this.fixSender = new FixOrderSender(); // Could log to file
}
public void run(List<MarketData> historicalData) {
StrategyExecutor executor = new StrategyExecutor(strategy, orderManager, fixSender);
for (MarketData marketData : historicalData) {
executor.onMarketData(marketData);
}
System.out.println("Backtest complete.");
}
}
import java.util.*;
public class HistoricalDataLoader {
public static List<MarketData> load() {
List<MarketData> data = new ArrayList<>();
long now = System.currentTimeMillis();
for (int i = 0; i < 20; i++) {
data.add(new MarketData("AAPL", 170 + i, 170.5 + i, 170.2 + i, now + i * 1000));
}
return data;
}
}
public class BacktestApp {
public static void main(String[] args) {
TradingStrategy strategy = new MomentumStrategy(3);
List<MarketData> historicalData = HistoricalDataLoader.load();
BacktestEngine engine = new BacktestEngine(strategy);
engine.run(historicalData);
}
}
9. Real-Time Market Data Adapter
We can simulate this with:
WebSocket Client (for a public API like Binance/Coinbase)
Kafka Consumer (for internal enterprise feeds)
public class KafkaMarketDataConsumer {
private final StrategyExecutor executor;
public KafkaMarketDataConsumer(StrategyExecutor executor) {
this.executor = executor;
}
public void startConsuming() {
// Simulate incoming data (replace with real Kafka logic)
new Thread(() -> {
try {
for (int i = 0; i < 10; i++) {
MarketData md = new MarketData("AAPL", 175 + i, 175.5 + i, 175.2 + i, System.currentTimeMillis());
executor.onMarketData(md);
Thread.sleep(1000); // mimic Kafka stream delay
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
// You'd use libraries like 'java-websocket' or 'OkHttp WebSocket'
public class WebSocketMarketDataAdapter {
private final StrategyExecutor executor;
public WebSocketMarketDataAdapter(StrategyExecutor executor) {
this.executor = executor;
}
public void connectToFeed() {
// Connect to a WebSocket market feed (like Binance, Polygon, etc.)
// On receiving a message, parse it and pass it as MarketData:
// executor.onMarketData(parsedMarketData);
}
}
Let’s begin by converting the core architecture of the Java-based algorithmic trading system into C++, including:
1. Market Data Structure
#pragma once
#include <string>
#include <iostream>
struct MarketData {
std::string symbol;
double bidPrice;
double askPrice;
double lastTradedPrice;
long timestamp;
void print() const {
std::cout << "MarketData[" << symbol << "] Bid: " << bidPrice
<< " Ask: " << askPrice << " LTP: " << lastTradedPrice << "\n";
}
};
2. Trade Signal
#pragma once
#include <string>
#include <iostream>
enum class SignalType { BUY, SELL, HOLD };
struct TradeSignal {
std::string symbol;
SignalType type;
double confidence;
void print() const {
std::string typeStr = (type == SignalType::BUY) ? "BUY" :
(type == SignalType::SELL) ? "SELL" : "HOLD";
std::cout << "TradeSignal[" << symbol << "] " << typeStr
<< " (Confidence: " << confidence << ")\n";
}
};
3. Order Management
#pragma once
#include <string>
#include <iostream>
#include <uuid/uuid.h>
enum class OrderType { MARKET, LIMIT };
enum class Side { BUY, SELL };
struct Order {
std::string orderId;
std::string symbol;
Side side;
OrderType type;
double price;
int quantity;
long timestamp;
void print() const {
std::string sideStr = (side == Side::BUY) ? "BUY" : "SELL";
std::string typeStr = (type == OrderType::MARKET) ? "MARKET" : "LIMIT";
std::cout << "Order[" << orderId << "] " << sideStr << " " << typeStr
<< " " << quantity << "@" << price << "\n";
}
};
class OrderManager {
public:
Order placeOrder(const std::string& symbol, Side side, OrderType type, double price, int quantity) {
Order order;
order.orderId = generateUUID();
order.symbol = symbol;
order.side = side;
order.type = type;
order.price = price;
order.quantity = quantity;
order.timestamp = time(nullptr);
std::cout << "Placing order: ";
order.print();
return order;
}
private:
std::string generateUUID() {
uuid_t uuid;
uuid_generate(uuid);
char uuid_str[37];
uuid_unparse(uuid, uuid_str);
return std::string(uuid_str);
}
};
4. Strategy Interface + TWAP Strategy
#pragma once
#include "MarketData.hpp"
#include "TradeSignal.hpp"
#include <chrono>
class TradingStrategy {
public:
virtual TradeSignal generateSignal(const MarketData& md) = 0;
};
class TWAPStrategy : public TradingStrategy {
int totalQuantity;
long startTime;
long endTime;
int slices;
int executedSlices;
public:
TWAPStrategy(int qty, long start, long end, int s)
: totalQuantity(qty), startTime(start), endTime(end), slices(s), executedSlices(0) {}
TradeSignal generateSignal(const MarketData& md) override {
long now = time(nullptr);
if (now < startTime || now > endTime || executedSlices >= slices)
return {md.symbol, SignalType::HOLD, 0.0};
long sliceInterval = (endTime - startTime) / slices;
long expectedTimeForNextSlice = startTime + (executedSlices * sliceInterval);
if (now >= expectedTimeForNextSlice) {
executedSlices++;
return {md.symbol, SignalType::BUY, 1.0};
}
return {md.symbol, SignalType::HOLD, 0.0};
}
};
5. Strategy Execution Engine
#pragma once
#include "TradingStrategy.hpp"
#include "OrderManager.hpp"
#include "FixOrderSender.hpp"
class StrategyExecutor {
TradingStrategy* strategy;
OrderManager* orderManager;
FixOrderSender* fixSender;
public:
StrategyExecutor(TradingStrategy* s, OrderManager* o, FixOrderSender* f)
: strategy(s), orderManager(o), fixSender(f) {}
void onMarketData(const MarketData& md) {
TradeSignal signal = strategy->generateSignal(md);
signal.print();
if (signal.type == SignalType::BUY) {
Order o = orderManager->placeOrder(md.symbol, Side::BUY, OrderType::MARKET, 0.0, 100);
fixSender->send(o);
} else if (signal.type == SignalType::SELL) {
Order o = orderManager->placeOrder(md.symbol, Side::SELL, OrderType::MARKET, 0.0, 100);
fixSender->send(o);
}
}
};
6. FIX Order Sender (Mock)
#pragma once
#include "OrderManager.hpp"
class FixOrderSender {
public:
void send(const Order& order) {
std::cout << "[FIX] Sending order via FIX: ";
order.print();
}
};
7. Backtest Engine
#pragma once
#include <vector>
#include "StrategyExecutor.hpp"
class BacktestEngine {
StrategyExecutor* executor;
public:
BacktestEngine(StrategyExecutor* exec) : executor(exec) {}
void run(const std::vector<MarketData>& historicalData) {
for (const auto& md : historicalData) {
executor->onMarketData(md);
}
std::cout << "Backtest complete.\n";
}
};
8. Historical Data Simulation
#include <vector>
#include "MarketData.hpp"
std::vector<MarketData> generateHistoricalData() {
std::vector<MarketData> data;
long now = time(nullptr);
for (int i = 0; i < 10; ++i) {
data.push_back({"AAPL", 170.0 + i, 170.5 + i, 170.2 + i, now + i});
}
return data;
}
9. Main Function
#include "TWAPStrategy.hpp"
#include "StrategyExecutor.hpp"
#include "OrderManager.hpp"
#include "FixOrderSender.hpp"
#include "BacktestEngine.hpp"
int main() {
OrderManager orderManager;
FixOrderSender fixSender;
long now = time(nullptr);
TWAPStrategy strategy(500, now, now + 60, 5);
StrategyExecutor executor(&strategy, &orderManager, &fixSender);
BacktestEngine backtest(&executor);
auto data = generateHistoricalData();
backtest.run(data);
return 0;
}
What We Achieved
The code above builds a modular, extensible algorithmic trading framework in C++, mirroring a professional trading system's architecture. Here's a breakdown of what it includes:
Core Components:
Market Data Model – A structure to represent streaming or historical market prices.
Trade Signal Generation – A strategy interface (
TradingStrategy
) and a TWAP implementation to simulate signal generation.Order Management System (OMS) – Allows placing mock orders with basic metadata (side, type, price).
Execution Engine – Executes signals into orders using a strategy-agnostic executor.
FIX Order Sender (Mocked) – Emulates sending orders via the FIX protocol.
Backtest Framework – Allows testing strategies on historical data to simulate trading performance.
Optional & Extendable Modules:
Kafka/WebSocket integration for real-time data feeds
Real FIX engine integration
Performance metrics: PnL, Sharpe ratio, latency, etc.
Advanced strategies: VWAP, Momentum, Mean Reversion, etc.
Goal:
To lay down a C++ foundation for an end-to-end low-latency, high-performance algorithmic trading system that is:
Strategy-pluggable
Execution-layer decoupled
Easily testable with historical or simulated data
Suitable for backtesting, paper trading, or real execution with minor enhancements
Suggested Blog Titles:
Technical / Serious:
"Building a Modular C++ Algorithmic Trading System from Scratch"
"TWAP Strategy, FIX Orders, and Backtesting: A Complete C++ Algo Trading Stack"
"Designing a Low-Latency Trading Architecture in C++"
Catchy / Engaging:
"From Signal to Execution: Crafting Your Own C++ Algo Trading Engine"
"Code Your First Trading Bot in C++ (With Backtesting & TWAP Strategy)"
"C++ for Quants: Building a High-Performance Algo Trading System"