Building an Algorithmic Trading Engine at 18

I’m Johannes, 18, and I’m pushing hard toward a career in Quantitative Finance. To stay accountable (and share some cool insights), I’m documenting my learning journey every day.

After diving into calculus, probability, and the theoretical side of things, I decided to put some of that knowledge to work. I built a functional algorithmic trading engine from scratch!

Now, this isn’t some high-frequency trading engine ready to take on Jane Street. This is a backtesting engine, meaning it uses historical data to simulate how a trading strategy would have performed in the past. It’s the absolute foundational step for any quant aspiring to build automated trading systems.

The Core Components

An algorithmic trading engine needs a few key pieces to operate:

The Market Data Loader

You can’t trade without data. My MarketDataLoader is a C++ class designed to read historical stock prices (like Apple’s, from a CSV file). It takes in all those numbers, date, open, high, low, close, volume, and turns them into structured data my program can understand. Making sure it could handle the raw CSV data without crashing if something was a bit off required careful parsing.

The Strategy Engine

This is where the algorithmic part truly shines. My Strategy class houses the brain of the operation. For this first version, I used a classic: the Simple Moving Average (SMA) Crossover.

Here’s the basics:

  • I track two moving averages: a short-term one (like the average price over the last 10 days) and a long-term one (say, over 20 days).
  • If the short-term average crosses above the long-term average, it’s generally seen as a buy signal (momentum is picking up).
  • If the short-term average crosses below the long-term average, it’s a sell signal (momentum is slowing down).

The core logic for a moving average calculation involves summing prices over a period and dividing by the number of periods. For instance, a 10-day SMA for a given day is:

\( SMA_{10} = \frac{P_1 + P_2 + \dots + P_{10}}{10} \)

where \( P_i \) is the closing price on day \( i \).

The crucial part I refined was making sure the strategy knew what cash I had and how many shares I already owned. No point in trying to buy if I’m broke, or sell if I own nothing. This made the strategy much more robust and stopped those “Trade failed” messages.

The Portfolio Manager

This class, Portfolio, is my virtual bank account and stock ledger. It starts with an initial amount of cash (I gave myself a small $100,000 to start). When the Strategy sends a buy or sell signal, the Portfolio executes the “order.”

It:

  • Deducts cash and adds shares for buys.
  • Adds cash and deducts shares for sells.
  • Keeps track of all successful trades.
  • Updates the market value of my holdings daily based on the latest prices.

My total equity, for example, is calculated as:

\( \text{Total Equity} = \text{Cash} + (\text{Shares Owned} \times \text{Current Stock Price}) \)

The Daily Workflow

Here’s how it all comes together in the main function:

  1. Load all the historical data from my CSV file.
  2. Initialize my strategy (with 10-day and 20-day moving averages).
  3. Set up my initial portfolio with starting cash.
  4. Then, I loop through each day’s price data, one by one:
    • For each day, the Strategy looks at the new price and my current cash/shares to decide if I should BUY, SELL, or HOLD.
    • If there’s a BUY or SELL signal, an Order is created and sent to the Portfolio.
    • The Portfolio tries to execute the order. If it has enough cash/shares, the trade goes through. If not, it skips it.
    • Finally, the Portfolio updates its market value for the day.
  5. After processing all the historical data, the Portfolio prints out a summary of my cash, shares, market value, total equity, and the number of successful trades.

Profit

After coding, compiling, and debugging, the engine ran. It showed a profit of over $5,000 on my initial $100,000. This confirmed that the basic logic was sound and the components were interacting correctly.

Of course, this is just the beginning. This backtesting engine doesn’t account for things like:

  • Brokerage fees (these eat into profits)
  • Slippage (when your order fills at a slightly different price than expected)
  • Market microstructure (the detailed interactions of orders in a market)

Building a functional (for backtesting) algorithmic trading engine feels like a massive win. It’s awesome to see theoretical concepts turn into working code.

You can view the full codebase here: https://github.com/JohannesMeyerYC/AlgorithmicTradingEngine

Stay Calculated!