-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path01_foundations.cpp
More file actions
133 lines (119 loc) · 6.74 KB
/
Copy path01_foundations.cpp
File metadata and controls
133 lines (119 loc) · 6.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// ============================================================================
// LESSON 01 — Foundations: how C++ actually works, through trading eyes
// ============================================================================
// Build & run:
// clang++ -std=c++20 -Wall -Wextra -O2 01_foundations.cpp -o bin/01_foundations
// ./bin/01_foundations
// (or just `make 01`)
//
// THE COMPILATION MODEL — what happens when you hit enter:
// 1. Preprocessor: #include literally pastes header text into this file.
// 2. Compiler: translates C++ into machine code (an "object file").
// 3. Linker: stitches object files + libraries into one executable.
// Unlike Python there is no interpreter at runtime — the binary IS machine
// code. That's where the speed comes from, and why you must recompile after
// every change.
// ============================================================================
#include <cstdint> // fixed-width integers: int64_t, uint32_t...
#include <iostream> // std::cout — console output
#include <string>
#include <vector>
// ----------------------------------------------------------------------------
// RULE #1 OF TRADING SYSTEMS: PRICES ARE INTEGERS, NEVER DOUBLES.
// ----------------------------------------------------------------------------
// `double` is binary floating point: it cannot represent 0.1 exactly, and
// tiny errors compound across millions of trades into real money (and into
// orders being rejected by the exchange for being off-tick).
// Instead we store prices as an integer count of the smallest increment.
// Here: 1 unit = $0.0001 (a hundredth of a cent), so $101.2500 = 1'012'500.
using Price = std::int64_t; // `using` creates a type alias — self-documenting
using Qty = std::int64_t;
constexpr Price PRICE_SCALE = 10'000; // constexpr = compile-time constant
// (digit separators ' are free to use)
double to_dollars(Price p) { return static_cast<double>(p) / PRICE_SCALE; }
// static_cast is C++'s explicit conversion. C++ will happily convert numbers
// implicitly and silently lose data — always cast explicitly, on purpose.
// ----------------------------------------------------------------------------
// VALUE SEMANTICS — the biggest mental shift from Python/Java
// ----------------------------------------------------------------------------
// In Python, variables are references to objects. In C++, variables ARE the
// object. Assignment COPIES. This function receives a copy; mutating it does
// nothing to the caller's vector:
void broken_add_fill(std::vector<Qty> fills, Qty q) { fills.push_back(q); }
// To let a function see/modify the caller's object, pass a REFERENCE (&).
// A reference is an alias for an existing object — no copy is made.
void add_fill(std::vector<Qty>& fills, Qty q) { fills.push_back(q); }
// If a function only needs to READ a big object, pass by const reference:
// no copy (fast), and the compiler enforces that you can't modify it.
Qty total_quantity(const std::vector<Qty>& fills) {
Qty total = 0;
for (Qty q : fills) total += q; // range-for: iterates every element
return total;
}
// Rule of thumb used at every firm:
// small things (int, Price, double) -> pass by value
// everything else, read-only -> pass by const T&
// everything else, needs modification -> pass by T&
// ----------------------------------------------------------------------------
// RAII — Resource Acquisition Is Initialisation (C++'s superpower)
// ----------------------------------------------------------------------------
// There is no garbage collector. Instead: an object's DESTRUCTOR runs
// automatically and deterministically when it goes out of scope. Wrap every
// resource (memory, file, socket, lock, exchange session...) in an object,
// and cleanup becomes impossible to forget. std::vector and std::string are
// RAII objects — they free their memory themselves. You will almost never
// write `new`/`delete` in modern C++.
class ExchangeSession {
public:
// Constructor: runs at creation. `explicit` prevents accidental implicit
// conversions from string to ExchangeSession.
explicit ExchangeSession(std::string venue) : venue_(std::move(venue)) {
// std::move: transfer the string's guts instead of copying them.
std::cout << " [session] connected to " << venue_ << "\n";
}
// Destructor: runs automatically at scope exit — even on early return
// or exception. This is how real systems guarantee orders get cancelled
// and sockets get closed.
~ExchangeSession() {
std::cout << " [session] disconnected from " << venue_ << " (destructor)\n";
}
const std::string& venue() const { return venue_; }
// trailing `const` = this method promises not to modify the object.
private:
std::string venue_; // trailing underscore: common convention for members
};
// ----------------------------------------------------------------------------
int main() {
std::cout << "=== 01 Foundations ===\n";
// --- integer prices ---
const Price bid = 1'012'500; // $101.2500
const Price ask = bid + 25; // one tick ($0.0025) higher
std::cout << "bid $" << to_dollars(bid)
<< " ask $" << to_dollars(ask)
<< " spread(ticks-units) " << (ask - bid) << "\n";
// `const` = this variable never changes. Default to const; it turns a
// whole class of bugs into compile errors.
// --- value vs reference semantics, live ---
std::vector<Qty> fills; // empty vector of quantities
broken_add_fill(fills, 100); // mutates a COPY — lost
add_fill(fills, 100); // mutates OUR vector
add_fill(fills, 250);
std::cout << "fills recorded: " << fills.size()
<< ", total qty: " << total_quantity(fills) << "\n";
// --- RAII, live ---
{ // an artificial inner scope
ExchangeSession sess{"ASX"};
std::cout << " trading on " << sess.venue() << "...\n";
} // <- sess dies HERE; destructor prints the disconnect line
std::cout << "back in main after session scope\n";
return 0; // 0 = success, by Unix convention
}
// ----------------------------------------------------------------------------
// EXERCISES
// 1. Change `add_fill` to take `const std::vector<Qty>&` and rebuild.
// Read the compiler error — learning to read errors IS learning C++.
// 2. Add a `mid_price(Price bid, Price ask)` function returning the midpoint.
// Careful: what does integer division do to an odd spread?
// 3. Give ExchangeSession a `send_order(Price, Qty)` method that just prints.
// Make it refuse (print an error) if qty <= 0.
// ----------------------------------------------------------------------------