AlgoDaily

Lesson 3: Parsing Buy and Sell Signals in C++

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

From Text To Intent

Why this lesson matters

In Lesson 2: Reading Gmail API in C++, you got message IDs and decoded Gmail body text.

Now the job changes:

email body text  ->  trading signal object

A message like:

ALERT: BUY AAPL qty=25

should become something your C++ program can reason about:

  • direction: BUY
  • symbol: AAPL
  • quantity: 25

This is the bridge between mailbox data and the trading pipeline we introduced in Lesson 1: Introduction to API in C++.

From Text To Intent

Define The Signal

Parse into a small contract

Before writing parsing code, decide the shape of the result.

For this lesson, we will use a compact signal model:

Field Example Meaning direction BUY Trading action symbol AAPL Instrument ticker quantity 25 Number of shares/contracts

This keeps your parser honest. It should not return vague text. It should return either:

  • a valid structured signal, or
  • a clear failure.

That mindset matters in algorithmic trading because ambiguous text can become expensive behavior.

Define The Signal

First Regex Parser

Match one known alert format

Start with a narrow format you control:

ALERT: BUY AAPL qty=25

A regular expression is useful here because the signal has repeated structure:

  • fixed prefix: ALERT:
  • direction: BUY or SELL
  • ticker symbol: uppercase letters
  • quantity: digits after qty=

This standalone example parses one email body and prints the structured result.

```cpp
#include <algorithm>
#include <iostream>
#include <regex>
#include <string>

struct Signal {
    std::string direction;
    std::string symbol;
    int quantity;
};

std::string upper(std::string s) {
    std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) {
        return std::toupper(c);
    });
    return s;
}

int main() {
    std::string body = "ALERT: BUY AAPL qty=25";

    std::regex pattern(
        "^\\s*ALERT:\\s*(BUY|SELL)\\s+([A-Z]{1,5})\\s+qty=(\\d+)\\s*$",
        std::regex::icase
    );

    std::smatch match;

    if (std::regex_match(body, match, pattern)) {
        Signal signal{
            upper(match[1].str()),
            upper(match[2].str()),
            std::stoi(match[3].str())
        };

        std::cout << "Parsed signal" << std::endl;
        std::cout << "direction=" << signal.direction << std::endl;
        std::cout << "symbol=" << signal.symbol << std::endl;
        std::cout << "quantity=" << signal.quantity << std::endl;
    } else {
        std::cout << "No valid trading signal found" << std::endl;
    }

    return 0;
}
```

Parser Responsibility

A Gmail message body contains this text:

ALERT: SELL MSFT qty=10

What is the parser's main responsibility in this lesson?

Normalize Then Validate

Two separate checks

A strong parser does not stop at "the regex matched."

Use two phases:

1. Normalize

Make equivalent inputs consistent:

  • buy -> BUY
  • aapl -> AAPL
  • extra leading/trailing spaces -> ignored
2. Validate

Reject values that should not become trading instructions:

  • quantity is 0
  • symbol is empty or too long
  • direction is not BUY or SELL
  • message format is not recognized

In trading systems, this separation is important: normalization makes data consistent; validation keeps bad data out.

Normalize Then Validate

Parsing Guarantees

True or false:

If a message contains the word BUY anywhere in the email body, the program should treat it as a valid buy signal.

Handle Bad Messages

Most messages are not signals

Your Gmail inbox may contain newsletters, confirmations, promotions, and normal emails.

So your parser should expect failures as normal behavior:

promo: buy one get one free       -> reject
ALERT: HOLD AAPL qty=10           -> reject
ALERT: BUY AAPL qty=0             -> reject
ALERT: SELL TSLA qty=5            -> accept

A good rule for this stage:

If the message is unclear, do not trade.

For now, we only parse and log. Later lessons can connect the accepted signal to REST or FIX-style API workflows.

Handle Bad Messages

Regex Direction

Complete the direction group in this regex fragment:

ALERT:\s*(____)\s+([A-Z]{1,5})\s+qty=(\d+)

It should match only the two supported actions.

Batch Parse Emails

Connect to Lesson 2 output

In Lesson 2, your program decoded Gmail body text.

Now imagine you have several decoded bodies in a std::vector<std::string>. The parser can scan them, accept valid signals, and skip everything else.

This standalone example uses std::optional<Signal> so a parse can cleanly mean either:

  • Signal exists, or
  • no valid signal exists.
```cpp
#include <algorithm>
#include <iostream>
#include <optional>
#include <regex>
#include <string>
#include <vector>

struct Signal {
    std::string direction;
    std::string symbol;
    int quantity;
};

std::string upper(std::string s) {
    std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) {
        return std::toupper(c);
    });
    return s;
}

std::optional<Signal> parseSignal(const std::string& body) {
    std::regex pattern(
        "^\\s*(ALERT:\\s*)?(BUY|SELL)\\s+([A-Z]{1,5})\\s+(qty=)?(\\d+)\\s*$",
        std::regex::icase
    );

    std::smatch match;
    if (!std::regex_match(body, match, pattern)) {
        return std::nullopt;
    }

    Signal signal{
        upper(match[2].str()),
        upper(match[3].str()),
        std::stoi(match[5].str())
    };

    if (signal.quantity <= 0) {
        return std::nullopt;
    }

    return signal;
}

int main() {
    std::vector<std::string> decodedBodies = {
        "ALERT: BUY AAPL qty=25",
        "promo: buy shoes today",
        "SELL TSLA qty=0",
        "BUY MSFT 10",
        "ALERT: HOLD NVDA qty=2"
    };

    int accepted = 0;

    for (const auto& body : decodedBodies) {
        std::cout << "Message: " << body << std::endl;

        auto signal = parseSignal(body);
        if (signal) {
            ++accepted;
            std::cout << "  ACCEPTED -> "
                      << signal->direction << " "
                      << signal->symbol << " qty="
                      << signal->quantity << std::endl;
        } else {
            std::cout << "  rejected" << std::endl;
        }
    }

    std::cout << "Accepted signals: " << accepted << std::endl;
    return 0;
}
```

Lesson Wrap

What you can now do

You have moved from decoded Gmail text to structured trading intent.

You practiced how to:

  • define a small Signal model
  • parse BUY and SELL alerts
  • normalize direction and symbol text
  • validate quantity and format
  • reject unclear messages safely
  • batch-process decoded email bodies

The key lesson: parsing is a safety boundary. It protects the rest of your trading pipeline from vague or malformed input.

Next, Lesson 4: Working with REST APIs in C++ will focus on API calls beyond Gmail, but this signal object will remain the kind of clean data you want to pass forward.

Lesson Wrap

Open interactive view →