Data Handling and Management 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 Signals To Data
Why this lesson matters
In Course Introduction and Setting Up Development Environment, you built a C++ workspace and learned to measure early. In Understanding the Basics of Algorithmic Trading, you saw the trading system loop: market data comes in, logic evaluates it, orders may go out.
Now we focus on the part that feeds everything else: data handling and management.
In an algo trading application, bad data handling can cause:
- delayed decisions,
- incorrect prices,
- memory waste,
- crashes during fast market movement,
- misleading backtest results later.
Today, we will build practical C++ habits for representing, storing, validating, and reading market data efficiently.

Market Data Shapes
What data are we managing?
Before connecting to real financial APIs, we need clean internal models.
Common market data shapes include:
- Tick: one price event at a specific time.
- Quote: best bid and ask prices with quantities.
- Trade: executed price and quantity.
- Candle/OHLC bar: open, high, low, close, volume over an interval.
A useful mental model:
Raw market event
|
v
Typed C++ object
|
v
Validated storage
|
v
Strategy input
The goal is not just to store numbers. The goal is to preserve meaning: timestamp, symbol, price, size, and source.

Choose The Model
You want to represent a one-minute summary containing open, high, low, close, and volume.
Which market data shape is the best fit?
Structs With Meaning
Use types that explain the data
For intermediate C++ developers, struct is a clean way to model market records.
Prefer explicit field names over anonymous arrays like double values[5]. In trading code, readability reduces expensive mistakes.
This example creates a small tick model, stores sample ticks, and calculates the latest price.
```cpp
#include <iostream>
#include <string>
#include <vector>
#include <cstdint>
struct Tick {
std::string symbol;
std::int64_t timestamp_ms;
double price;
int quantity;
};
int main() {
std::vector<Tick> ticks = {
{"INFY", 1710000000001, 1498.25, 100},
{"INFY", 1710000000035, 1498.40, 50},
{"INFY", 1710000000060, 1498.10, 75}
};
const Tick& latest = ticks.back();
std::cout << "Latest tick for " << latest.symbol << "\n";
std::cout << "Time(ms): " << latest.timestamp_ms << "\n";
std::cout << "Price: " << latest.price << "\n";
std::cout << "Qty: " << latest.quantity << "\n";
return 0;
}
```
Validate Before Trust
True or false:
If a market data record is stored in a C++ object, we can assume it is valid and safe to use in trading calculations.
Fast Recent Storage
Keep the recent window close
Many trading calculations need recent data: last 10 ticks, last 100 prices, last N bars.
A simple and efficient structure for this is a ring buffer:
- fixed capacity,
- overwrites oldest values,
- avoids repeated memory growth,
- keeps recent observations available.
This is not the final performance-tuned version yet; that comes later. For now, it teaches a core data-management pattern.
```cpp
#include <iostream>
#include <array>
#include <cstddef>
class PriceRingBuffer {
public:
void push(double price) {
data_[next_] = price;
next_ = (next_ + 1) % data_.size();
if (count_ < data_.size()) {
++count_;
}
}
void printRecent() const {
std::cout << "Recent prices: ";
for (std::size_t i = 0; i < count_; ++i) {
std::size_t index = (next_ + data_.size() - count_ + i) % data_.size();
std::cout << data_[index] << " ";
}
std::cout << "\n";
}
private:
std::array<double, 5> data_{};
std::size_t next_ = 0;
std::size_t count_ = 0;
};
int main() {
PriceRingBuffer prices;
prices.push(100.10);
prices.push(100.25);
prices.push(100.40);
prices.push(100.15);
prices.push(100.30);
prices.push(100.50); // overwrites the oldest value
prices.printRecent();
return 0;
}
```
Name The Buffer
Fill in the blank:
A fixed-size structure that overwrites the oldest value when new data arrives is commonly called a ____ buffer.
Parse Simple CSV
Reading historical data
Even before live API connectivity, you need to load sample or historical data from files.
CSV is common for learning, testing, and early prototypes:
symbol,timestamp_ms,price,quantity
INFY,1710000000001,1498.25,100
For production systems, parsing must be stricter and faster. But this small example shows the basic flow: read line, split fields, convert types, validate, store.
```cpp
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <cstdint>
struct Tick {
std::string symbol;
std::int64_t timestamp_ms;
double price;
int quantity;
};
bool isValid(const Tick& t) {
return !t.symbol.empty() && t.timestamp_ms > 0 && t.price > 0.0 && t.quantity > 0;
}
int main() {
std::string csv =
"symbol,timestamp_ms,price,quantity\n"
"INFY,1710000000001,1498.25,100\n"
"INFY,1710000000035,1498.40,50\n"
"INFY,0,-10.00,25\n";
std::istringstream input(csv);
std::string line;
std::vector<Tick> ticks;
std::getline(input, line); // skip header
while (std::getline(input, line)) {
std::istringstream row(line);
std::string symbol, timestamp, price, quantity;
std::getline(row, symbol, ',');
std::getline(row, timestamp, ',');
std::getline(row, price, ',');
std::getline(row, quantity, ',');
Tick tick{symbol, std::stoll(timestamp), std::stod(price), std::stoi(quantity)};
if (isValid(tick)) {
ticks.push_back(tick);
} else {
std::cout << "Rejected invalid row: " << line << "\n";
}
}
std::cout << "Accepted ticks: " << ticks.size() << "\n";
for (const auto& tick : ticks) {
std::cout << tick.symbol << " " << tick.price << " x " << tick.quantity << "\n";
}
return 0;
}
```
Storage Tradeoffs
You need to keep only the most recent 1,000 prices for a calculation and want to avoid continuous memory growth.
Which approach best matches that need?
Data Quality Rules
Practical validation checklist
Before a strategy consumes data, check the basics:
- Price must be positive.
- Quantity/volume must be positive or at least non-negative, depending on the field.
- Timestamp must exist and usually move forward.
- Symbol must match the instrument being processed.
- Duplicate records should be detected if they can affect calculations.
- Missing fields should be rejected or handled explicitly.
In a fast trading system, validation is not optional. It protects the logic you will build in upcoming lessons.
A clean path looks like this:
Read -> Parse -> Validate -> Store -> Consume

Ready For Connectivity
What you can now handle
You now have the foundation for market data inside a C++ trading application:
- model records with clear structs,
- store streams of values using appropriate containers,
- keep recent data efficiently,
- parse CSV-style historical samples,
- validate records before strategy logic sees them.
This lesson sits between concepts and real-world input. In the next lesson, Connectivity with Financial Market APIs, you will start thinking about how external market data enters your application.
For now, remember the rule: fast code is only useful when the data is correct enough to trust.
