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:
- Load all the historical data from my CSV file.
- Initialize my strategy (with 10-day and 20-day moving averages).
- Set up my initial portfolio with starting cash.
- 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 thePortfolio
. - 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.
- For each day, the
- 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!