1
+ #include < iostream>
2
+ #include < string>
3
+ #include < sstream>
4
+ #include < vector>
5
+ #include < map>
6
+ #include < cpprest/ws_client.h>
7
+ #include < boost/property_tree/ptree.hpp>
8
+ #include < boost/property_tree/json_parser.hpp>
9
+ #include < thread>
10
+ #include < algorithm>
11
+ #include < chrono>
12
+ #include " matplotlibcpp.h"
13
+ #include < Python.h>
14
+
15
+ using namespace web ;
16
+ using namespace web ::websockets::client;
17
+ using namespace boost ::property_tree;
18
+ namespace plt = matplotlibcpp;
19
+
20
+ class datafeed {
21
+ private:
22
+ ptree JSON (std::string message){
23
+ std::stringstream ss (message);
24
+ ptree result;
25
+ read_json (ss, result);
26
+ return result;
27
+ }
28
+
29
+ void CYCLONE (ptree df, std::map<double , double > & bids, std::map<double , double > & asks){
30
+ bool snapshot = false ;
31
+ bool l2update = false ;
32
+ for (ptree::const_iterator it = df.begin (); it != df.end (); ++it){
33
+ if (l2update == true && it->first == " changes" ){
34
+ for (ptree::const_iterator jt = it->second .begin (); jt != it->second .end (); ++jt){
35
+ std::vector<std::string> hold;
36
+ for (ptree::const_iterator kt = jt->second .begin (); kt != jt->second .end (); ++kt){
37
+ hold.push_back (kt->second .get_value <std::string>().c_str ());
38
+ }
39
+
40
+ double price = atof (hold[1 ].c_str ());
41
+ double volume = atof (hold[2 ].c_str ());
42
+
43
+ if (hold[0 ] == " buy" ){
44
+ if (volume == 0 ){
45
+ bids.erase (price);
46
+ } else {
47
+ bids[price] = volume;
48
+ }
49
+ } else {
50
+ if (volume == 0 ){
51
+ asks.erase (price);
52
+ } else {
53
+ asks[price] = volume;
54
+ }
55
+ }
56
+ }
57
+ }
58
+ if (snapshot == true && it->first == " bids" ){
59
+ for (ptree::const_iterator jt = it->second .begin (); jt != it->second .end (); ++jt){
60
+ std::vector<double > hold;
61
+ for (ptree::const_iterator kt = jt->second .begin (); kt != jt->second .end (); ++kt){
62
+ hold.push_back (atof (kt->second .get_value <std::string>().c_str ()));
63
+ }
64
+ bids[hold[0 ]] = hold[1 ];
65
+ }
66
+ }
67
+ if (snapshot == true && it->first == " asks" ){
68
+ for (ptree::const_iterator jt = it->second .begin (); jt != it->second .end (); ++jt){
69
+ std::vector<double > hold;
70
+ for (ptree::const_iterator kt = jt->second .begin (); kt != jt->second .end (); ++kt){
71
+ hold.push_back (atof (kt->second .get_value <std::string>().c_str ()));
72
+ }
73
+ asks[hold[0 ]] = hold[1 ];
74
+ }
75
+ }
76
+
77
+ if (it->first == " type" ){
78
+ if (it->second .get_value <std::string>() == " l2update" ){
79
+ l2update = true ;
80
+ }
81
+ if (it->second .get_value <std::string>() == " snapshot" ){
82
+ snapshot = true ;
83
+ }
84
+ }
85
+ }
86
+ }
87
+
88
+
89
+
90
+ public:
91
+
92
+ static void Socket (datafeed dx, std::map<double , double > & bids, std::map<double , double > & asks){
93
+ std::string url = " wss://ws-feed.exchange.coinbase.com" ;
94
+ std::string msg = " {\" type\" :\" subscribe\" ,\" product_ids\" :[\" BTC-USD\" ],\" channels\" :[\" level2_batch\" ]}" ;
95
+
96
+ websocket_client client;
97
+ client.connect (url).wait ();
98
+ websocket_outgoing_message outmsg;
99
+ outmsg.set_utf8_message (msg);
100
+ client.send (outmsg);
101
+
102
+ while (true ){
103
+ client.receive ().then ([](websocket_incoming_message inmsg){
104
+ return inmsg.extract_string ();
105
+ }).then ([&](std::string message){
106
+ dx.CYCLONE (dx.JSON (message), std::ref (bids), std::ref (asks));
107
+ }).wait ();
108
+ }
109
+
110
+ client.close ().wait ();
111
+
112
+ }
113
+ };
114
+
115
+ std::map<std::string, std::vector<double >> Extract (std::map<double , double > bids, std::map<double , double > asks)
116
+ {
117
+ int depth = 80 ;
118
+ std::map<std::string, std::vector<double >> result;
119
+
120
+ int count = 0 ;
121
+ double bidvol = 0 ;
122
+ for (auto it = bids.rbegin (); it != bids.rend (); ++it){
123
+ bidvol += it->second ;
124
+ result[" bidPrice" ].push_back (it->first );
125
+ result[" bidSize" ].push_back (bidvol);
126
+ count += 1 ;
127
+ if (count >= depth){
128
+ break ;
129
+ }
130
+ }
131
+
132
+ count = 0 ;
133
+ double askvol = 0 ;
134
+ for (auto it = asks.begin (); it != asks.end (); ++it){
135
+ askvol += it->second ;
136
+ result[" askPrice" ].push_back (it->first );
137
+ result[" askSize" ].push_back (askvol);
138
+ count += 1 ;
139
+ if (count >= depth){
140
+ break ;
141
+ }
142
+ }
143
+
144
+ std::reverse (result[" bidPrice" ].begin (), result[" bidPrice" ].end ());
145
+ std::reverse (result[" bidSize" ].begin (), result[" bidSize" ].end ());
146
+
147
+
148
+ return result;
149
+ }
150
+
151
+ std::vector<double > push_into (double ii, int n){
152
+ std::vector<double > result;
153
+ for (int i = 0 ; i < n; ++i){
154
+ result.push_back (ii);
155
+ }
156
+ return result;
157
+ }
158
+
159
+ int main ()
160
+ {
161
+ PyObject * ax = plt::chart (121 );
162
+ PyObject * ay = plt::chart (122 );
163
+
164
+ std::map<double , double > bids, asks;
165
+ std::map<std::string, std::vector<double >> preprice;
166
+
167
+ datafeed wsfeed;
168
+ std::thread feed (wsfeed.Socket , wsfeed, std::ref (bids), std::ref (asks));
169
+
170
+ std::this_thread::sleep_for (std::chrono::seconds (10 ));
171
+
172
+ std::vector<std::vector<double >> bX, bY, bZ, aX, aY, aZ;
173
+
174
+ int ii = 0 ;
175
+ int jj = 0 ;
176
+ int limit = 80 ;
177
+
178
+ while (true ){
179
+ preprice = Extract (bids, asks);
180
+ bX.clear ();
181
+ bY.clear ();
182
+ bZ.push_back (preprice[" bidSize" ]);
183
+ for (int u = 0 ; u < bZ.size (); ++u){
184
+ bY.push_back (preprice[" bidPrice" ]);
185
+ bX.push_back (push_into (ii, preprice[" bidPrice" ].size ()));
186
+ ii += 1 ;
187
+ }
188
+
189
+ aX.clear ();
190
+ aY.clear ();
191
+ aZ.push_back (preprice[" askSize" ]);
192
+ for (int u = 0 ; u < aZ.size (); ++u){
193
+ aY.push_back (preprice[" askPrice" ]);
194
+ aX.push_back (push_into (jj, preprice[" askPrice" ].size ()));
195
+ jj += 1 ;
196
+ }
197
+
198
+
199
+ if (bZ.size () >= limit){
200
+ bX.erase (bX.begin ());
201
+ bY.erase (bY.begin ());
202
+ bZ.erase (bZ.begin ());
203
+ }
204
+
205
+ if (aZ.size () >= limit){
206
+ aX.erase (aX.begin ());
207
+ aY.erase (aY.begin ());
208
+ aZ.erase (aZ.begin ());
209
+ }
210
+
211
+ plt::Clear3DChart (ax);
212
+ plt::Clear3DChart (ay);
213
+
214
+ plt::surface3D (ax, bX, bY, bZ, " red" , 1.0 );
215
+ plt::surface3D (ay, aX, aY, aZ, " limegreen" , 1.0 );
216
+
217
+ plt::pause (0.1 );
218
+
219
+ // std::cout << bX.size() << " " << bX[0].size() << "\t" << bY.size() << " " << bY[0].size() << "\t" << bZ.size() << " " << bZ[0].size() << std::endl;
220
+ }
221
+
222
+ plt::show ();
223
+ feed.join ();
224
+ return 0 ;
225
+ }
0 commit comments