1. Work
  2. Algorithmic Trading Bot (Simulated Arena)
  3. Docs

Algorithmic Trading Bot (Simulated Arena)

Python strategy backtester that streams trade signals over TCP to a C++ simulated execution engine.

5 min read

Source on GitHub

A two-language MVP: a Python side that generates synthetic market data, trains a classifier, and backtests a momentum strategy, wired over a local TCP socket to a C++ execution engine that fills simulated orders and logs them with high-resolution timestamps.

Data disclaimer: all OHLCV data is synthetically generated locally (geometric Brownian motion + injected momentum trends). Nothing in this project makes a network call or fetches real market data. Treat it purely as a stand-in for a historical-data-ingestion feed.

What it does

  1. Python (python/trading_bot.py)

    • Generates synthetic daily OHLCV bars for 3 tickers (GBM random walk with a handful of injected drift/momentum windows so trend-following features have real signal to find).
    • Engineers features: SMA(5)/SMA(20) crossover, 10-bar momentum, an RSI-like oscillator, volume change, and daily return.
    • Trains a StandardScaler + LogisticRegression pipeline (scikit-learn) to classify next-bar up/down, on a chronological 70/30 train/test split.
    • Runs a vectorized backtest on the held-out test set: total return, a Sharpe-like ratio, max drawdown, trade count, win rate. Prints a report.
    • --mode live: replays the test-set predictions as BUY/SELL signals, streamed as newline-delimited JSON over a TCP socket to the C++ engine.
  2. C++ (cpp/server.cpp)

    • Plain POSIX socket TCP server (no external networking library).
    • Parses each NDJSON signal line (nlohmann/json, header-only, via Homebrew) and runs it through a simplified matching engine: one resting price level per ticker, incoming market orders cross the spread with a fixed slippage and fill immediately.
    • Logs every fill with a monotonic nanosecond timestamp (std::chrono::steady_clock) plus running position/cash per ticker.
    • Prints a fills/PnL summary when the client sends an {"type":"end"} marker or disconnects.

Architecture

python/trading_bot.py                    cpp/server.cpp
┌─────────────────────────┐              ┌──────────────────────────┐
│ generate synthetic OHLCV│              │ POSIX TCP server          │
│ engineer features        │              │ 127.0.0.1:9009            │
│ train LogisticRegression │              │                            │
│ vectorized backtest      │   NDJSON     │ per-ticker order book:     │
│ print backtest report    │  over TCP    │  single price level,       │
│                          │ ───────────> │  slippage fill model       │
│ --mode live: replay      │ {"type":     │                            │
│ predictions as BUY/SELL  │  "signal",...│ logs [FILL] w/ steady_clock│
│ signals, one JSON        │              │ nanosecond timestamps      │
│ object per line          │  {"type":    │                            │
│                          │   "end"}     │ prints fills/PnL summary   │
└─────────────────────────┘              └──────────────────────────┘

Build & run

Run these in order. The C++ server must be listening before the Python client connects.

# 1. Build the C++ execution engine (nlohmann-json is header-only, via Homebrew)
brew install nlohmann-json   # skip if already installed
cd cpp
g++ -std=c++17 -O2 -Wall -I/opt/homebrew/opt/nlohmann-json/include -o server server.cpp
cd ..

# 2. Start the execution engine (foreground terminal A, or background with &)
./cpp/server 9009

# 3. In a second terminal, run the Python side in live mode against it
#    (uses the shared repo-root venv, not a new one)
../.venv10projects/bin/python python/trading_bot.py --mode live --host 127.0.0.1 --port 9009

Backtest only, no C++ server needed:

../.venv10projects/bin/python python/trading_bot.py --mode backtest

CLI flags: --mode {backtest,live}, --host, --port, --delay (seconds between streamed signals, default 0.02), --seed.

Captured output from a full run

Python side (backtest report + live streaming)

Generating synthetic OHLCV data for 3 tickers (500 bars each)...
Engineering features, training logistic regression, running vectorized backtest...
==================================================================
BACKTEST REPORT  (synthetic data - not real market data)
==================================================================
Ticker      TotalRet   Sharpe*     MaxDD   Trades   WinRate
SYN0          -3.51%     -0.18   -18.35%      144     54.9%
SYN1          -8.21%     -0.58   -22.72%      144     49.3%
SYN2          25.09%      2.04    -6.30%      144     52.8%
------------------------------------------------------------------
Portfolio avg total return: 4.46%   avg Sharpe*: 0.43
* Sharpe-like ratio = mean(strategy_ret)/std(strategy_ret) * sqrt(252); not a real Sharpe ratio.
==================================================================

Connecting to execution engine at 127.0.0.1:9009 ...
Connected. Streaming 432 live signals...

  -> sent BUY  SYN0   qty=10   price=114.26 ts=2025-12-26T00:00:00
  -> sent BUY  SYN1   qty=10   price=117.68 ts=2025-12-26T00:00:00
  -> sent SELL SYN2   qty=10   price=137.28 ts=2025-12-26T00:00:00
  ... (432 signals total) ...
  -> sent BUY  SYN2   qty=10   price=148.45 ts=2026-07-15T00:00:00

All signals sent. Sent END marker, closing connection.

C++ side (fills logged in real time + closing summary)

Execution engine listening on 127.0.0.1:9009 ...
Client connected. Awaiting signals...

[FILL] t+00000000068708ns  ticker=SYN0   side=BUY  qty=10     fill_price=114.3159  pos=10.0000  cash=-1143.1593   src_ts=2025-12-26T00:00:00
[FILL] t+38643330000000ns  ticker=SYN1   side=BUY  qty=10     fill_price=117.7424  pos=10.0000  cash=-1177.4244   src_ts=2025-12-26T00:00:00
[FILL] t+76912910000000ns  ticker=SYN2   side=SELL qty=10     fill_price=137.2090  pos=-10.0000 cash=1372.0896    src_ts=2025-12-26T00:00:00
[FILL] t+10872083000000ns  ticker=SYN0   side=BUY  qty=10     fill_price=114.7042  pos=20.0000  cash=-2290.2015   src_ts=2025-12-29T00:00:00
  ... (432 fills total) ...
[FILL] t+16240167910000ns  ticker=SYN2   side=BUY  qty=10     fill_price=148.5241  pos=1100.0000 cash=-162288.8108 src_ts=2026-07-15T00:00:00

Received END marker from client.

==================================================================
EXECUTION ENGINE SUMMARY
==================================================================
Ticker     Fills  Position          Cash    MarkToMarket
SYN0         144   1140.00    -129762.13         -913.40
SYN1         144   1140.00    -132477.87        10012.56
SYN2         144   1100.00    -162288.81         1006.08
------------------------------------------------------------------
Total fills: 432   Total simulated PnL: 10105.24
==================================================================

The t+...ns field is nanoseconds since the server started (monotonic steady_clock), demonstrating high-resolution fill timestamping.

Simplified vs full spec

  • Synthetic data, not real market feeds. OHLCV bars come from a local GBM + injected-trend generator, not a live exchange or historical data vendor. Add when: swap generate_synthetic_ohlcv() for a real data connector (e.g. a broker API or a vendor CSV/parquet feed) behind the same DataFrame interface.
  • Simplified single-price-level matching, not a real order book. Each ticker has one resting price with fixed slippage, not multi-level bid/ask depth or price-time priority. Add when: replace TickerBook with a std::map<double, Level> per side and implement proper price-time matching.
  • No true low-latency/co-located networking. This is a single blocking TCP connection on localhost with a Python-side artificial delay between sends, not microsecond-scale kernel-bypass networking. Add when: move to a UDP multicast or kernel-bypass (DPDK/io_uring) transport and pin the engine to an isolated CPU core.

Files

03-algo-trading-bot/
├── README.md
├── python/
│   └── trading_bot.py   # data gen, features, model, backtest, live streaming
└── cpp/
    ├── server.cpp        # TCP server + matching engine + fill logging
    └── server            # compiled binary (build artifact)

Support

Submit issues, questions, or bug reports to the GitHub issue tracker: https://github.com/ADM1SH/algo-trading-bot/issues

Roadmap

  • Done: Core architecture and baseline implementation.
  • Done: Functional verification and test coverage.
  • To do: Implement FIX 4.4 protocol gateway
  • To do: Add VWAP and TWAP algorithmic order execution slices

Contributing

Contributions are welcome.

  1. Fork the repository.
  2. Create a feature branch: git checkout -b feature/improvement.
  3. Commit your changes: git commit -m "feat: enhance functionality".
  4. Push to the branch: git push origin feature/improvement.
  5. Open a Pull Request.

Authors and Acknowledgment

  • Adam Anwar (ADM1SH) - Lead architect and developer.
  • Engineered by Adam Anwar for high-performance order routing research.

License

Licensed under the MIT License. See LICENSE for details.

Project Status

Simulation arena MVP. Operational TCP order router and strategy backtester.

Back to top