Skip to content

Commit adc9d91

Browse files
authored
Update book.cpp
1 parent 4121ad0 commit adc9d91

File tree

1 file changed

+31
-3
lines changed

1 file changed

+31
-3
lines changed

BookViz/book.cpp

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,24 @@
1212
#include "matplotlibcpp.h"
1313
#include <Python.h>
1414

15+
// Declare global namespaces to simplify calling objects
1516
using namespace web;
1617
using namespace web::websockets::client;
1718
using namespace boost::property_tree;
1819
namespace plt = matplotlibcpp;
1920

21+
// Coinbase datafeed class
2022
class datafeed {
2123
private:
24+
// Converts a string response to JSON using Boost
2225
ptree JSON(std::string message){
2326
std::stringstream ss(message);
2427
ptree result;
2528
read_json(ss, result);
2629
return result;
2730
}
2831

32+
// Parses the level2 orderbook for Bitcoin and updates each change in order which the book receives
2933
void CYCLONE(ptree df, std::map<double, double> & bids, std::map<double, double> & asks){
3034
bool snapshot = false;
3135
bool l2update = false;
@@ -37,9 +41,11 @@ class datafeed {
3741
hold.push_back(kt->second.get_value<std::string>().c_str());
3842
}
3943

44+
// Extract the latest price and volume
4045
double price = atof(hold[1].c_str());
4146
double volume = atof(hold[2].c_str());
4247

48+
// Erases part of book if the volume equals zero meaning that the order has been filled or cancelled fully
4349
if(hold[0] == "buy"){
4450
if(volume == 0){
4551
bids.erase(price);
@@ -55,6 +61,7 @@ class datafeed {
5561
}
5662
}
5763
}
64+
// Parses the bid book in the initial snapshot
5865
if(snapshot == true && it->first == "bids"){
5966
for(ptree::const_iterator jt = it->second.begin(); jt != it->second.end(); ++jt){
6067
std::vector<double> hold;
@@ -64,6 +71,7 @@ class datafeed {
6471
bids[hold[0]] = hold[1];
6572
}
6673
}
74+
// Parses the ask book in the initial snapshot
6775
if(snapshot == true && it->first == "asks"){
6876
for(ptree::const_iterator jt = it->second.begin(); jt != it->second.end(); ++jt){
6977
std::vector<double> hold;
@@ -74,6 +82,7 @@ class datafeed {
7482
}
7583
}
7684

85+
// Activates whether the message is a snapshot or an update
7786
if(it->first == "type"){
7887
if(it->second.get_value<std::string>() == "l2update"){
7988
l2update = true;
@@ -88,11 +97,13 @@ class datafeed {
8897

8998

9099
public:
91-
100+
101+
// Level2 limit orderbook websocket feed using cpprest
92102
static void Socket(datafeed dx, std::map<double, double> & bids, std::map<double, double> & asks){
93103
std::string url = "wss://ws-feed.exchange.coinbase.com";
94104
std::string msg = "{\"type\":\"subscribe\",\"product_ids\":[\"BTC-USD\"],\"channels\":[\"level2_batch\"]}";
95105

106+
// Connect to client and send the subscription message
96107
websocket_client client;
97108
client.connect(url).wait();
98109
websocket_outgoing_message outmsg;
@@ -103,6 +114,7 @@ class datafeed {
103114
client.receive().then([](websocket_incoming_message inmsg){
104115
return inmsg.extract_string();
105116
}).then([&](std::string message){
117+
// Retreives response from websocket and parses the data as a snapshot of the book, or an update of the book
106118
dx.CYCLONE(dx.JSON(message), std::ref(bids), std::ref(asks));
107119
}).wait();
108120
}
@@ -112,42 +124,50 @@ class datafeed {
112124
}
113125
};
114126

127+
// Sets the examination depth to 80 and pulls the orderbooks price and volume for both bids and asks
115128
std::map<std::string, std::vector<double>> Extract(std::map<double, double> bids, std::map<double, double> asks)
116129
{
130+
// Set depth of book
117131
int depth = 80;
118132
std::map<std::string, std::vector<double>> result;
119133

134+
// Pulls bid orders and takes the cumulative volume summation
120135
int count = 0;
121136
double bidvol = 0;
122137
for(auto it = bids.rbegin(); it != bids.rend(); ++it){
123138
bidvol += it->second;
124139
result["bidPrice"].push_back(it->first);
125140
result["bidSize"].push_back(bidvol);
126141
count += 1;
142+
// Breaks loop once depth limit has been reached
127143
if(count >= depth){
128144
break;
129145
}
130146
}
131147

148+
// Pulls ask orders and takes the cumulative volume summation
132149
count = 0;
133150
double askvol = 0;
134151
for(auto it = asks.begin(); it != asks.end(); ++it){
135152
askvol += it->second;
136153
result["askPrice"].push_back(it->first);
137154
result["askSize"].push_back(askvol);
138155
count += 1;
156+
// Breaks loop once depth limit has been reached
139157
if(count >= depth){
140158
break;
141159
}
142160
}
143161

162+
// Bids must be reveresed in order to be plotted as the lowest bid must be at the beginning of the vector
144163
std::reverse(result["bidPrice"].begin(), result["bidPrice"].end());
145164
std::reverse(result["bidSize"].begin(), result["bidSize"].end());
146165

147166

148167
return result;
149168
}
150169

170+
// Builds a vector with a single value for n elements
151171
std::vector<double> push_into(double ii, int n){
152172
std::vector<double> result;
153173
for(int i = 0; i < n; ++i){
@@ -158,15 +178,18 @@ std::vector<double> push_into(double ii, int n){
158178

159179
int main()
160180
{
181+
// Declare two plots, one for bid and one for ask
161182
PyObject * ax = plt::chart(121);
162183
PyObject * ay = plt::chart(122);
163184

164185
std::map<double, double> bids, asks;
165186
std::map<std::string, std::vector<double>> preprice;
166187

188+
// Open datafeed thread
167189
datafeed wsfeed;
168190
std::thread feed(wsfeed.Socket, wsfeed, std::ref(bids), std::ref(asks));
169191

192+
// Sleep for 10 seconds to allow the orderbook thread to build a dataset
170193
std::this_thread::sleep_for(std::chrono::seconds(10));
171194

172195
std::vector<std::vector<double>> bX, bY, bZ, aX, aY, aZ;
@@ -176,7 +199,10 @@ int main()
176199
int limit = 80;
177200

178201
while(true){
202+
// Extract the depth orderbook data
179203
preprice = Extract(bids, asks);
204+
205+
// Store bid snapshots for 3D plotting
180206
bX.clear();
181207
bY.clear();
182208
bZ.push_back(preprice["bidSize"]);
@@ -186,6 +212,7 @@ int main()
186212
ii += 1;
187213
}
188214

215+
// Store ask snapshots for 3D plotting
189216
aX.clear();
190217
aY.clear();
191218
aZ.push_back(preprice["askSize"]);
@@ -195,7 +222,7 @@ int main()
195222
jj += 1;
196223
}
197224

198-
225+
// Erase data from the beginning of the vectors if limit has been reached
199226
if(bZ.size() >= limit){
200227
bX.erase(bX.begin());
201228
bY.erase(bY.begin());
@@ -208,6 +235,7 @@ int main()
208235
aZ.erase(aZ.begin());
209236
}
210237

238+
// Clear and plot the two orderbooks in their own plots
211239
plt::Clear3DChart(ax);
212240
plt::Clear3DChart(ay);
213241

@@ -222,4 +250,4 @@ int main()
222250
plt::show();
223251
feed.join();
224252
return 0;
225-
}
253+
}

0 commit comments

Comments
 (0)