-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path05_websocket_market.cpp
More file actions
148 lines (127 loc) · 5.34 KB
/
Copy path05_websocket_market.cpp
File metadata and controls
148 lines (127 loc) · 5.34 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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Example 05: WebSocket — Sports moneyline live orderbook and odds.
//
// Looks up a sports event by slug, finds the moneyline (winner) market,
// and streams live orderbook updates to stdout.
//
// Key patterns demonstrated:
// - Event discovery by slug via GammaClient
// - Token extraction via ClobClient
// - Orderbook maintained as std::map<price, size> (no manual sorting)
// - price_change deltas applied as simple map inserts/erases
// - initial_dump=true means full book arrives on connect — no REST prefetch needed
//
// Run: ./05_websocket_market <event-slug>
// Example: ./05_websocket_market atp-djokovic-alcaraz-2026-01-01
#include <polymarket/gamma/gamma_client.hpp>
#include <polymarket/clob/clob_client.hpp>
#include <polymarket/ws/ws_client.hpp>
#include <polymarket/types/enums.hpp>
#include <map>
#include <thread>
#include <chrono>
#include <unordered_map>
#include <iostream>
using namespace polymarket;
static double to_double(const std::string& s) {
return s.empty() ? 0 : std::strtod(s.c_str(), nullptr);
}
struct TokenBook {
std::string name;
std::map<double, double> bids; // price → size, rbegin = best bid
std::map<double, double> asks; // price → size, begin = best ask
};
static void print_state(const std::string& reason,
const std::vector<std::string>& order,
const std::unordered_map<std::string, TokenBook>& book) {
std::cout << "── " << reason << " ──\n";
for (auto& tid : order) {
auto& p = book.at(tid);
double best_bid = p.bids.empty() ? 0 : p.bids.rbegin()->first;
double best_ask = p.asks.empty() ? 0 : p.asks.begin()->first;
double kf = best_ask > 0.001 ? 1.0 / best_ask : 0;
std::cout << " " << p.name
<< " kf=" << kf
<< " bid=" << best_bid
<< " ask=" << best_ask << "\n";
int n = 0;
for (auto it = p.bids.rbegin(); it != p.bids.rend() && n < 3; ++it, ++n)
std::cout << " bid kf=" << 1.0 / it->first
<< " $" << (int)(it->first * it->second) << "\n";
n = 0;
for (auto it = p.asks.begin(); it != p.asks.end() && n < 3; ++it, ++n)
std::cout << " ask kf=" << 1.0 / it->first
<< " $" << (int)(it->first * it->second) << "\n";
}
std::cout << std::flush;
}
int main(int argc, char* argv[]) {
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " <event-slug>\n";
return 1;
}
const std::string slug = argv[1];
// 1. Find event and moneyline market
GammaClient gamma;
auto ev = gamma.get_event_by_slug(slug);
if (!ev) { std::cerr << "Event error: " << ev.error().message() << "\n"; return 1; }
const GammaMarket* mainline = nullptr;
for (const auto& m : ev->data.markets) {
if (!mainline) mainline = &m;
std::string smt(m.sports_market_type);
if (smt == "winner" || smt == "moneyline") { mainline = &m; break; }
}
if (!mainline) { std::cerr << "No moneyline market found\n"; return 1; }
std::string cid(mainline->condition_id.c_str());
if (cid.empty()) { std::cerr << "Empty condition_id\n"; return 1; }
// 2. Get tokens from CLOB
ClobClient clob;
auto mkt = clob.get_market(cid);
if (!mkt || !mkt->tokens || mkt->tokens->empty()) {
std::cerr << "CLOB error\n"; return 1;
}
std::cout << "Market: " << mkt->question << "\n";
std::vector<std::string> token_ids;
std::unordered_map<std::string, TokenBook> book;
for (auto& tok : *mkt->tokens) {
token_ids.push_back(tok.token_id);
book[tok.token_id] = {tok.outcome, {}, {}};
std::cout << " " << tok.outcome << " → " << tok.token_id << "\n";
}
// 3. Stream live updates — initial_dump=true sends full book on connect
WsClient::Config cfg; cfg.auto_reconnect = true;
WsClient ws(cfg);
ws.on_book([&](WsBookUpdate b) {
auto it = book.find(b.asset_id);
if (it == book.end()) return;
auto& p = it->second;
p.bids.clear();
for (auto& l : b.bids) p.bids[to_double(l.price)] = to_double(l.size);
p.asks.clear();
for (auto& l : b.asks) p.asks[to_double(l.price)] = to_double(l.size);
print_state("book " + p.name, token_ids, book);
});
ws.on_price([&](WsPriceChange pc) {
bool any = false;
for (auto& ch : pc.price_changes) {
auto it = book.find(ch.asset_id);
if (it == book.end()) continue;
auto& bk = side_from_string(ch.side) == std::optional{Side::Buy}
? it->second.bids : it->second.asks;
double price = to_double(ch.price), size = to_double(ch.size);
if (size > 0) bk[price] = size;
else bk.erase(price);
any = true;
}
if (any) print_state("price_change", token_ids, book);
});
ws.on_trade([&](WsLastTradePrice lt) {
auto it = book.find(lt.asset_id);
if (it == book.end()) return;
std::cout << "── trade " << it->second.name
<< " price=" << lt.price << " ──\n" << std::flush;
});
ws.on_error([](const std::string& e) { std::cerr << "WS: " << e << "\n"; });
ws.subscribe(token_ids);
ws.connect();
while (true) std::this_thread::sleep_for(std::chrono::seconds(60));
}