AlgoDaily

Implementing Trading Algorithms

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

Strategy Layer Begins

Why this lesson matters

In Course Introduction and Setting Up Development Environment, you built a C++ workspace. In Data Handling and Management in C++, you shaped market data into useful objects. In Connectivity with Financial Market APIs, you learned how the app can receive prices and send requests.

Now we add the brain of the system: the trading algorithm.

A trading algorithm should answer a focused question:

Given the latest market data and current strategy state, what action should we consider next?

For this lesson, we will keep the scope tight:

  • Convert market data into signals
  • Convert signals into order intents
  • Keep simple position state
  • Make the algorithm deterministic and testable

We will not deeply tune speed, backtest years of history, or build full risk controls yet. Those are coming in later lessons.

Strategy Layer Begins

Algorithm Boundaries

Keep the algorithm small and honest

A common mistake is making the strategy function do everything:

  • Parse market data
  • Call APIs
  • Calculate indicators
  • Place orders
  • Log results
  • Manage reconnection

That becomes hard to debug.

Instead, treat the trading algorithm as a clean middle layer:

Market data object  ->  Strategy logic  ->  Order intent

The algorithm should not need to know whether prices came from a CSV, WebSocket, or REST API. You already handled those ideas in earlier lessons.

A useful C++ mental model

Design strategy code so it is close to a pure decision engine:

  • Inputs: recent prices, latest tick/bar, current position
  • Internal state: indicator values, previous signal, last action
  • Output: BUY, SELL, or HOLD intent

This makes your strategy easier to inspect before it ever touches real money.

Algorithm Boundaries

SMA Crossover

First concrete strategy: moving average crossover

A simple algorithmic idea is:

  • Calculate a short moving average
  • Calculate a long moving average
  • If short average rises above long average: bullish signal
  • If short average falls below long average: bearish signal

This is not a recommendation to trade this strategy live. It is a clean learning example because it forces us to implement:

  • Recent price storage
  • Indicator calculation
  • Signal generation
  • Action output

The code below uses fixed sample prices and prints the decision at each step.

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

std::string signalFromSMA(const std::vector<double>& prices, int shortWindow, int longWindow) {
    if (prices.size() < static_cast<size_t>(longWindow)) {
        return "HOLD";
    }

    double shortSum = 0.0;
    for (int i = prices.size() - shortWindow; i < static_cast<int>(prices.size()); ++i) {
        shortSum += prices[i];
    }

    double longSum = 0.0;
    for (int i = prices.size() - longWindow; i < static_cast<int>(prices.size()); ++i) {
        longSum += prices[i];
    }

    double shortAvg = shortSum / shortWindow;
    double longAvg = longSum / longWindow;

    if (shortAvg > longAvg) return "BUY";
    if (shortAvg < longAvg) return "SELL";
    return "HOLD";
}

int main() {
    std::vector<double> stream = {100, 101, 102, 103, 102, 104, 106, 105, 107, 109};
    std::vector<double> seen;

    const int shortWindow = 3;
    const int longWindow = 5;

    for (double price : stream) {
        seen.push_back(price);
        std::string signal = signalFromSMA(seen, shortWindow, longWindow);

        std::cout << "Latest price: " << std::setw(6) << price
                  << " | Decision: " << signal << '\n';
    }

    return 0;
}
```

Signal Question

In a clean algo trading design, what should the strategy layer usually output?

Avoid Signal Spam

Signals are not automatically orders

Suppose your SMA logic says BUY for 20 ticks in a row. Should your system send 20 buy orders?

Usually, no.

The strategy needs state so it knows what it already did. A basic stateful strategy tracks:

  • Current position: flat, long, or short
  • Previous signal
  • Whether a new action is actually needed

This separates a market opinion from a trade action.

Bullish signal + already long  -> HOLD
Bullish signal + currently flat -> BUY
Bearish signal + currently long -> SELL

That distinction is one of the biggest steps from “indicator code” to “trading algorithm code.”

Avoid Signal Spam

Stateful Strategy

Add position-aware decisions

Now let’s upgrade from raw signal output to an order-intent engine.

The strategy below:

  • Reads a sequence of prices
  • Calculates short/long SMA signals
  • Tracks whether we are Flat or Long
  • Sends BUY only when moving from flat to long
  • Sends SELL only when exiting a long position

This is still intentionally simple, but it demonstrates the core pattern used in larger trading systems.

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

using std::string;

enum class Position { Flat, Long };
enum class Intent { Hold, Buy, Sell };

string toString(Intent intent) {
    switch (intent) {
        case Intent::Buy: return "BUY";
        case Intent::Sell: return "SELL";
        default: return "HOLD";
    }
}

double averageLast(const std::vector<double>& prices, int window) {
    double sum = 0.0;
    for (int i = prices.size() - window; i < static_cast<int>(prices.size()); ++i) {
        sum += prices[i];
    }
    return sum / window;
}

Intent decide(const std::vector<double>& prices, Position& position) {
    const int shortWindow = 3;
    const int longWindow = 5;

    if (prices.size() < static_cast<size_t>(longWindow)) {
        return Intent::Hold;
    }

    double shortAvg = averageLast(prices, shortWindow);
    double longAvg = averageLast(prices, longWindow);

    bool bullish = shortAvg > longAvg;
    bool bearish = shortAvg < longAvg;

    if (bullish && position == Position::Flat) {
        position = Position::Long;
        return Intent::Buy;
    }

    if (bearish && position == Position::Long) {
        position = Position::Flat;
        return Intent::Sell;
    }

    return Intent::Hold;
}

int main() {
    std::vector<double> stream = {100, 101, 102, 103, 104, 103, 102, 101, 100, 99, 101, 103};
    std::vector<double> prices;
    Position position = Position::Flat;

    for (double price : stream) {
        prices.push_back(price);
        Intent intent = decide(prices, position);

        std::cout << "Price " << price << " -> Intent: " << toString(intent) << '\n';
    }

    return 0;
}
```

State Matters

True or false: If a strategy already holds a long position, a repeated bullish signal should always create another buy order.

Strategy Interface

Make algorithms swappable

As your application grows, you may want to try different strategies:

  • Moving average crossover
  • Breakout logic
  • Mean reversion logic
  • News or event-driven logic

Instead of hardcoding one strategy everywhere, define a small interface. The rest of the application can call onPrice(...) without caring which strategy is underneath.

This is useful C++ design: keep the calling code stable while the algorithm changes.

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

enum class Intent { Hold, Buy, Sell };

std::string toString(Intent intent) {
    if (intent == Intent::Buy) return "BUY";
    if (intent == Intent::Sell) return "SELL";
    return "HOLD";
}

class Strategy {
public:
    virtual ~Strategy() = default;
    virtual Intent onPrice(double price) = 0;
};

class ThresholdStrategy : public Strategy {
private:
    double buyAbove;
    double sellBelow;
    bool longPosition = false;

public:
    ThresholdStrategy(double buyAbove, double sellBelow)
        : buyAbove(buyAbove), sellBelow(sellBelow) {}

    Intent onPrice(double price) override {
        if (!longPosition && price > buyAbove) {
            longPosition = true;
            return Intent::Buy;
        }

        if (longPosition && price < sellBelow) {
            longPosition = false;
            return Intent::Sell;
        }

        return Intent::Hold;
    }
};

int main() {
    std::unique_ptr<Strategy> strategy = std::make_unique<ThresholdStrategy>(105.0, 101.0);
    std::vector<double> prices = {100, 102, 106, 108, 104, 100, 103, 107};

    for (double price : prices) {
        Intent intent = strategy->onPrice(price);
        std::cout << "Price: " << price << " | Intent: " << toString(intent) << '\n';
    }

    return 0;
}
```

Intent Blank

Fill in the blank: A strategy should usually create an order ______ before the execution layer sends anything to a broker.

Algorithm Checklist

What you can now build

You now have the core structure of an implementable trading algorithm in C++:

  • Market data enters as clean objects
  • Indicators summarize recent behavior
  • Strategy state prevents repeated accidental actions
  • The algorithm outputs BUY, SELL, or HOLD intent
  • The rest of the app can call a stable strategy interface
Before moving on, check your algorithm

Ask these questions:

  1. Does it make the same decision for the same input sequence?
  2. Does it separate signal generation from API execution?
  3. Does it track position state?
  4. Does it print/log decisions clearly enough for inspection?
  5. Can the strategy be swapped without rewriting the whole app?

In the next lesson, Optimization and Performance Tuning, we’ll focus on making these components faster and more efficient without changing their meaning.

Algorithm Checklist

Open interactive view →