Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
fenwick_tree_example.cc
Go to the documentation of this file.
1/*
2Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
67# include <cstdio>
68# include <iostream>
69# include <iomanip>
70# include <string>
71
72# include <tpl_fenwick_tree.H>
73
74using namespace std;
75using namespace Aleph;
76
77// =====================================================================
78// Helper: print a horizontal bar of width proportional to value
79// =====================================================================
80static void bar(int val, int scale = 1)
81{
82 int w = val / scale;
83 for (int i = 0; i < w; ++i)
84 cout << '#';
85}
86
87// =====================================================================
88// SCENARIO 1 — Order Book Depth
89// =====================================================================
90//
91// Imagine a simplified stock listed with price ticks 0..19 (each tick
92// represents $100.00 + tick * $0.01, so tick 0 = $100.00, tick 19 =
93// $100.19).
94//
95// The "bid side" of the order book tells us how many shares people are
96// willing to BUY at each tick. When someone sells at market, the
97// exchange fills the order starting at the highest bid, consuming
98// volume downward.
99//
100// But here we model the "ask side" (offers to sell) from the lowest
101// price upward, because that is the natural direction for a buyer
102// placing a market order:
103//
104// tick 0 ($100.00): 120 shares
105// tick 1 ($100.01): 80 shares
106// tick 3 ($100.03): 200 shares
107// ...
108//
109// A market BUY order of 250 shares will sweep:
110// 120 from tick 0 + 80 from tick 1 + 50 from tick 3 = 250
111// The worst price paid is tick 3 ($100.03).
112//
113// find_kth(250) gives us that answer in O(log n).
114//
116{
117 cout << "============================================================\n"
118 << " SCENARIO 1: Order Book Depth (Fenwick_Tree + find_kth)\n"
119 << "============================================================\n\n";
120
121 const size_t TICKS = 20; // price ticks 0..19
123
124 // -- Limit orders arrive on the ask side --
125 cout << "Limit SELL orders arrive:\n";
126
127 struct Order { size_t tick; int shares; const char *label; };
128 Order orders[] = {
129 { 0, 120, "$100.00"},
130 { 1, 80, "$100.01"},
131 { 3, 200, "$100.03"},
132 { 4, 50, "$100.04"},
133 { 7, 300, "$100.07"},
134 {10, 150, "$100.10"},
135 {15, 400, "$100.15"},
136 };
137
138 for (auto & o : orders)
139 {
140 ask_book.update(o.tick, o.shares);
141 cout << " " << setw(7) << o.label
142 << " +" << setw(4) << o.shares << " shares\n";
143 }
144
145 cout << "\nOrder book (ask side):\n\n";
146 cout << " Tick Price Volume Cumulative\n"
147 << " ---- -------- ------ ----------\n";
148
149 for (size_t t = 0; t < TICKS; ++t)
150 {
151 int vol = ask_book.get(t);
152 if (vol == 0)
153 continue;
154 int cum = ask_book.prefix(t);
155 cout << " " << setw(4) << t
156 << " $" << fixed << setprecision(2) << (100.0 + t * 0.01)
157 << " " << setw(6) << vol
158 << " " << setw(10) << cum << " ";
159 bar(vol, 10);
160 cout << "\n";
161 }
162
163 // -- A trader places a market BUY order --
164 int buy_sizes[] = {100, 250, 500, 1000, 1500};
165
166 cout << "\nMarket BUY order fill simulation:\n\n";
167 cout << " Order Size Worst Tick Worst Price\n"
168 << " ---------- ---------- -----------\n";
169
170 for (int sz : buy_sizes)
171 {
172 size_t worst_tick = ask_book.find_kth(sz);
173 if (worst_tick >= TICKS)
174 cout << " " << setw(10) << sz << " INSUFFICIENT LIQUIDITY\n";
175 else
176 cout << " " << setw(10) << sz
177 << " " << setw(10) << worst_tick
178 << " $" << fixed << setprecision(2)
179 << (100.0 + worst_tick * 0.01) << "\n";
180 }
181
182 // -- An order gets cancelled, book updates --
183 cout << "\n>> Cancel 150 shares at tick 3 ($100.03)\n";
184 ask_book.update(3, -150);
185
186 cout << ">> New fill for 250 shares: ";
187 size_t w = ask_book.find_kth(250);
188 cout << "worst price = $" << fixed << setprecision(2)
189 << (100.0 + w * 0.01)
190 << " (tick " << w << ")\n";
191
192 int total_liquidity = ask_book.prefix(TICKS - 1);
193 cout << "\nTotal ask liquidity: " << total_liquidity << " shares\n";
194}
195
196// =====================================================================
197// SCENARIO 2 — Intraday P&L Dashboard
198// =====================================================================
199//
200// A quantitative trading desk executes hundreds of trades per day.
201// Each trade's realized P&L is booked into a minute-bucket (0 = 09:30,
202// 1 = 09:31, ..., 389 = 16:00 — the 390 minutes of a US trading day).
203//
204// The risk dashboard needs instant answers to:
205// "What was the cumulative P&L from market open to now?"
206// "What was the P&L between the Fed announcement (14:00 = min 270)
207// and the close (16:00 = min 389)?"
208//
210{
211 cout << "\n\n============================================================\n"
212 << " SCENARIO 2: Intraday P&L Dashboard (Gen_Fenwick_Tree)\n"
213 << "============================================================\n\n";
214
215 const size_t MINUTES = 390; // 09:30 to 16:00
217
218 // -- Simulated trades throughout the day --
219 struct Trade { size_t minute; double pnl; const char *event; };
220 Trade trades[] = {
221 { 0, 1200.0, "Open: initial scalp profit" },
222 { 5, -300.0, "Stop-loss hit on AAPL" },
223 { 30, 4500.0, "NVDA earnings beat — long pays off" },
224 { 31, 2200.0, "Follow-through momentum" },
225 { 60, -800.0, "Mean reversion loss" },
226 { 120, -1500.0, "Lunch hour chop" },
227 { 180, 3000.0, "Afternoon trend resumes" },
228 { 270, 8000.0, "Fed holds rates — massive rally" },
229 { 271, 5000.0, "Fed follow-through" },
230 { 330, -2000.0, "Profit taking" },
231 { 389, 1500.0, "MOC imbalance capture" },
232 };
233
234 auto min_to_time = [](size_t m) -> string
235 {
236 int h = 9 + (int)(m + 30) / 60;
237 int mm = ((int)m + 30) % 60;
238 char buf[16];
239 snprintf(buf, sizeof(buf), "%02d:%02d", h, mm);
240 return buf;
241 };
242
243 cout << "Trades booked:\n\n";
244 cout << " Time Minute P&L Event\n"
245 << " ----- ------ ---------- ----------------------------\n";
246
247 for (auto & t : trades)
248 {
249 pnl.update(t.minute, t.pnl);
250 cout << " " << min_to_time(t.minute)
251 << " " << setw(6) << t.minute
252 << " " << setw(10) << fixed << setprecision(2) << t.pnl
253 << " " << t.event << "\n";
254 }
255
256 // -- Dashboard queries --
257 cout << "\nDashboard queries:\n\n";
258
259 double open_to_lunch = pnl.prefix(179);
260 double fed_to_close = pnl.query(270, 389);
261 double total_day = pnl.prefix(389);
262 double morning = pnl.query(0, 119); // 09:30 — 11:30
263 double afternoon = pnl.query(120, 389); // 11:30 — 16:00
264
265 cout << " Open to lunch (09:30-12:30): $" << setw(10) << open_to_lunch << "\n"
266 << " Fed to close (14:00-16:00): $" << setw(10) << fed_to_close << "\n"
267 << " Morning session (09:30-11:30): $" << setw(10) << morning << "\n"
268 << " Afternoon (11:30-16:00): $" << setw(10) << afternoon << "\n"
269 << " ----------------------------------------\n"
270 << " Total day P&L: $" << setw(10) << total_day << "\n";
271
272 // -- Late correction: a trade was re-priced --
273 cout << "\n>> Correction: NVDA trade at 10:00 re-priced from "
274 << "$4500 to $4000\n";
275 pnl.update(30, -500.0);
276 cout << " Adjusted total day P&L: $"
277 << fixed << setprecision(2) << pnl.prefix(389) << "\n";
278}
279
280// =====================================================================
281// SCENARIO 3 — Betting Exchange Promotions
282// =====================================================================
283//
284// A sports betting exchange runs daily promotions to attract users.
285// Each promotion adds a fixed bonus (in cents) to every participant
286// on each day the promotion is active. Promotions overlap freely:
287//
288// Promo A: days 0-6 (first week), +50c/day
289// Promo B: days 3-9 (overlap), +30c/day
290// Promo C: days 5-5 (single day), +100c/day
291// Promo D: days 0-13 (full period), +10c/day
292//
293// The accounting team needs:
294// - How much was paid to each user on day d?
295// - Total payout over any date range?
296//
297// This is a textbook range-update / range-query problem.
298//
300{
301 cout << "\n\n============================================================\n"
302 << " SCENARIO 3: Betting Exchange Promotions (Range_Fenwick_Tree)\n"
303 << "============================================================\n\n";
304
305 const size_t DAYS = 14; // two weeks, days 0..13
306 Range_Fenwick_Tree<int> payouts(DAYS); // cents per user per day
307
308 struct Promo { size_t from; size_t to; int bonus; const char *name; };
309 Promo promos[] = {
310 { 0, 6, 50, "Welcome Week" },
311 { 3, 9, 30, "Midweek Boost" },
312 { 5, 5, 100, "Super Saturday" },
313 { 0, 13, 10, "Loyalty Baseline" },
314 };
315
316 cout << "Promotions applied:\n\n";
317 cout << " Promotion Days Bonus/day\n"
318 << " ---------------- --------- ---------\n";
319
320 for (auto & p : promos)
321 {
322 payouts.update(p.from, p.to, p.bonus);
323 cout << " " << setw(16) << left << p.name << right
324 << " " << setw(2) << p.from << " - " << setw(2) << p.to
325 << " " << setw(5) << p.bonus << "c\n";
326 }
327
328 // -- Daily breakdown --
329 const char *day_names[] = {
330 "Mon W1", "Tue W1", "Wed W1", "Thu W1", "Fri W1", "Sat W1", "Sun W1",
331 "Mon W2", "Tue W2", "Wed W2", "Thu W2", "Fri W2", "Sat W2", "Sun W2"
332 };
333
334 cout << "\nDaily payout per user:\n\n"
335 << " Day Name Cents Breakdown\n"
336 << " --- ------- ----- ---------\n";
337
338 for (size_t d = 0; d < DAYS; ++d)
339 {
340 int cents = payouts.get(d);
341 cout << " " << setw(3) << d
342 << " " << day_names[d]
343 << " " << setw(5) << cents << " ";
344 bar(cents, 5);
345 cout << "\n";
346 }
347
348 // -- Accounting queries --
349 cout << "\nAccounting queries:\n\n";
350
351 int week1 = payouts.query(0, 6);
352 int week2 = payouts.query(7, 13);
353 int total = payouts.prefix(13);
354 int peak_weekend = payouts.query(4, 6); // Fri-Sun of week 1
355
356 cout << " Week 1 total (days 0-6): " << setw(5) << week1 << "c\n"
357 << " Week 2 total (days 7-13): " << setw(5) << week2 << "c\n"
358 << " Peak weekend (Fri-Sun W1): " << setw(5) << peak_weekend << "c\n"
359 << " ----------------------------------\n"
360 << " Grand total (14 days): " << setw(5) << total << "c\n";
361
362 // -- New promotion added retroactively --
363 cout << "\n>> Retroactive adjustment: 'Apology Bonus' +20c on days 10-13\n";
364 payouts.update(10, 13, 20);
365
366 cout << " Adjusted week 2 total: " << payouts.query(7, 13) << "c\n"
367 << " Adjusted grand total: " << payouts.prefix(13) << "c\n";
368
369 // -- Per-user cost if exchange has 10,000 users --
370 int users = 10000;
371 cout << "\n>> With " << users << " users:\n"
372 << " Total 14-day cost: $"
373 << fixed << setprecision(2)
374 << (payouts.prefix(13) * users / 100.0) << "\n";
375}
376
377// =====================================================================
378
379int main()
380{
384
385 cout << "\n";
386 return 0;
387}
long double h
Definition btreepic.C:154
long double w
Definition btreepic.C:153
Fenwick tree over an arbitrary abelian group.
Fenwick tree supporting range updates and range queries.
static void scenario_pnl_dashboard()
static void scenario_order_book()
static void bar(int val, int scale=1)
static void scenario_betting_promos()
int main()
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
DynList< T > maps(const C &c, Op op)
Classic map operation.
STL namespace.
Fenwick tree for arithmetic types with find_kth support.
Fenwick tree (Binary Indexed Tree) for prefix queries.