forked from ajtulloch/quantcup-orderbook
-
Notifications
You must be signed in to change notification settings - Fork 0
/
test.cpp
237 lines (213 loc) · 8.14 KB
/
test.cpp
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
#include <stdio.h>
#include "limits.h"
#include "types.h"
#include "constants.h"
#include "engine.h"
/* Besides crashing, the only way to sense
what is happening internally via the
required API functions is to submit
combinations of orders that trigger
execution notifications. Normally the
tests would scale up more smoothly
but because of the api's opacity,
the tests require implementation of
multiple bits of base functionality
in limit, cancel, and execution to even
get to the most basic nontrivial tests. */
int test_cancel(t_order orders1[], unsigned orders1_len, t_orderid cancels[],
unsigned cancels_len, t_order orders2[], unsigned orders2_len,
t_execution execs[], unsigned execs_len);
int test(t_order orders[], unsigned orders_len, t_execution execs[],
unsigned execs_len);
#define TEST(num, orders, execs) \
t_order o##num[] = orders; \
t_execution x##num[] = execs; \
correct += test(o##num, sizeof(o##num) / sizeof(t_order), x##num, \
sizeof(x##num) / sizeof(t_execution));
#define TEST_CANCEL(num, orders1, cancels, orders2, execs) \
t_order o1st##num[] = orders1; \
t_orderid c##num[] = cancels; \
t_order o2nd##num[] = orders2; \
t_execution x##num[] = execs; \
correct += test_cancel(o1st##num, sizeof(o1st##num) / sizeof(t_order), \
c##num, sizeof(c##num) / sizeof(t_orderid), \
o2nd##num, sizeof(o2nd##num) / sizeof(t_order), \
x##num, sizeof(x##num) / sizeof(t_execution));
#define X ,
#define MAX_EXECS 100
unsigned correct = 0;
t_orderid orderid;
unsigned totaltests = 0;
t_execution execs_out[MAX_EXECS];
t_execution* execs_out_iter;
unsigned execs_out_len;
int exec_overflow;
t_order oa101x100 = {"JPM", "MAX", 1, 101, 100};
t_order ob101x100 = {"JPM", "MAX", 0, 101, 100};
t_order oa101x50 = {"JPM", "MAX", 1, 101, 50};
t_order ob101x50 = {"JPM", "MAX", 0, 101, 50};
t_order oa101x25 = {"JPM", "MAX", 1, 101, 25};
t_order ob101x25 = {"JPM", "MAX", 0, 101, 25};
t_order ob101x25x = {"JPM", "XAM", 0, 101, 25};
t_execution xa101x100 = {"JPM", "MAX", 1, 101, 100};
t_execution xb101x100 = {"JPM", "MAX", 0, 101, 100};
t_execution xa101x50 = {"JPM", "MAX", 1, 101, 50};
t_execution xb101x50 = {"JPM", "MAX", 0, 101, 50};
t_execution xa101x25 = {"JPM", "MAX", 1, 101, 25};
t_execution xb101x25 = {"JPM", "MAX", 0, 101, 25};
t_execution xb101x25x = {"JPM", "XAM", 0, 101, 25};
int main() {
printf(
"ECN Matching Engine Autotester Running\n"
"--------------------------------------\n");
// ask
TEST(1, {oa101x100}, {});
// bid
TEST(2, {ob101x100}, {});
// execution
TEST(3, {oa101x100 X ob101x100}, {xa101x100 X xb101x100});
// reordering
TEST(4, {oa101x100 X ob101x100}, {xb101x100 X xa101x100});
TEST(5, {ob101x100 X oa101x100}, {xa101x100 X xb101x100});
TEST(6, {ob101x100 X oa101x100}, {xb101x100 X xa101x100});
// partial fill
TEST(7, {oa101x100 X ob101x50}, {xa101x50 X xb101x50});
TEST(8, {oa101x50 X ob101x100}, {xa101x50 X xb101x50});
// incremental over fill
TEST(9, {oa101x100 X ob101x25 X ob101x25 X ob101x25 X ob101x25 X ob101x25},
{xa101x25 X xb101x25 X xa101x25 X xb101x25 X xa101x25 X xb101x25 X
xa101x25 X xb101x25});
TEST(10, {ob101x100 X oa101x25 X oa101x25 X oa101x25 X oa101x25 X oa101x25},
{xa101x25 X xb101x25 X xa101x25 X xb101x25 X xa101x25 X xb101x25 X
xa101x25 X xb101x25});
// queue position
TEST(11, {ob101x25x X ob101x25 X oa101x25}, {xa101x25 X xb101x25x});
// cancel so no execution
TEST_CANCEL(12, {ob101x25}, {1}, {oa101x25}, {});
// cancel from front of queue
TEST_CANCEL(13, {ob101x25x X ob101x25}, {1}, {oa101x25},
{xa101x25 X xb101x25});
// cancel front, back, out of order then partial execution
TEST_CANCEL(14, {ob101x100 X ob101x25x X ob101x25x X ob101x50}, {1 X 4 X 3},
{oa101x50}, {xb101x25x X xa101x25});
printf("--------------------------------------\n");
printf("You got %i/%i tests correct.\n", correct, totaltests);
}
void execution(t_execution exec) {
execs_out_len++;
if (exec_overflow || (execs_out_iter == &execs_out[MAX_EXECS])) {
exec_overflow = 1;
}
*execs_out_iter = exec;
execs_out_iter++;
}
void set_globals() {
orderid = 0;
totaltests++;
exec_overflow = 0;
execs_out_iter = execs_out;
execs_out_len = 0;
}
int feed_orders(t_order orders[], unsigned orders_len) {
int id;
unsigned i;
for (i = 0; i < orders_len; i++) {
id = limit(orders[i]);
orderid++;
if (static_cast<t_orderid>(id) != orderid) {
printf("orderid returned was %u, should have been %u.\n", id, i + 1);
return 0;
}
}
return 1;
}
int feed_cancels(t_orderid cancels[], unsigned cancels_len) {
unsigned i;
for (i = 0; i < cancels_len; i++) {
cancel(cancels[i]);
}
return 1;
}
int assert_exec_count(unsigned num_execs_expected) {
if (exec_overflow) {
printf("too many executions, test array overflow");
return 0;
}
int correct = execs_out_len == num_execs_expected;
if (!correct) {
printf("execution called %u times, should have been %u.\n", execs_out_len,
num_execs_expected);
}
return correct;
}
int exec_eq(t_execution* e1, t_execution* e2) {
int eq = 1;
int i;
for (i = 0; i < OB::kFieldLength; i++) {
if (e1->symbol[i] == '\0' && e2->symbol[i] == '\0') break;
eq = eq && e1->symbol[i] == e2->symbol[i] && e1->trader[i] == e2->trader[i];
}
eq = eq && e1->side == e2->side && e1->price == e2->price &&
e1->size == e2->size;
return eq;
}
int assert_execs(t_execution execs[], unsigned execs_len) {
unsigned i;
for (i = 0; i < execs_len; i += 2) {
if (!((exec_eq(&execs[i], &execs_out[i]) &&
exec_eq(&execs[i + 1], &execs_out[i + 1])) ||
(exec_eq(&execs[i], &execs_out[i + 1]) &&
exec_eq(&execs[i + 1], &execs_out[i])))) {
printf(
"executions #%u and #%u,\n"
"{symbol=%s, trader=%s, side=%i, price=%u, size=%u},\n"
"{symbol=%s, trader=%s, side=%i, price=%u, size=%u}\n"
"should have been\n"
"{symbol=%s, trader=%s, side=%i, price=%u, size=%u},\n"
"{symbol=%s, trader=%s, side=%i, price=%u, size=%u}.\n"
"Stopped there.\n",
i, i + 1, execs_out[i].symbol.data(), execs_out[i].trader.data(),
execs_out[i].side, execs_out[i].price, (unsigned)execs_out[i].size,
execs_out[i + 1].symbol.data(), execs_out[i + 1].trader.data(),
execs_out[i + 1].side, execs_out[i + 1].price,
(unsigned)execs_out[i + 1].size, execs[i].symbol.data(),
execs[i].trader.data(), execs[i].side, execs[i].price,
(unsigned)execs[i].size, execs[i + 1].symbol.data(),
execs[i + 1].trader.data(), execs[i + 1].side, execs[i + 1].price,
(unsigned)execs[i + 1].size);
return 0;
}
}
return 1;
}
/* IN: orders: sequence of orders
OUT: points received on test */
int test(t_order orders[], unsigned orders_len, t_execution execs[],
unsigned execs_len) {
int ok = 1;
set_globals();
init();
ok = ok && feed_orders(orders, orders_len);
ok = ok && assert_exec_count(execs_len);
ok = ok && assert_execs(execs, execs_len);
destroy();
if (!ok) printf("test %i failed.\n\n", totaltests);
return ok;
}
/* IN: orders: sequence of orders
OUT: points received on test */
int test_cancel(t_order orders1[], unsigned orders1_len, t_orderid cancels[],
unsigned cancels_len, t_order orders2[], unsigned orders2_len,
t_execution execs[], unsigned execs_len) {
int ok = 1;
set_globals();
init();
ok = ok && feed_orders(orders1, orders1_len);
feed_cancels(cancels, cancels_len);
ok = ok && feed_orders(orders2, orders2_len);
ok = ok && assert_exec_count(execs_len);
ok = ok && assert_execs(execs, execs_len);
destroy();
if (!ok) printf("test %i failed.\n\n", totaltests);
return ok;
}