============================================================================== STEP 1 - LOAD ============================================================================== message file: INTC_2012-06-21_34200000_57600000_message_10.csv (25,663,091 bytes) orderbook file: INTC_2012-06-21_34200000_57600000_orderbook_10.csv (158,466,105 bytes) ============================================================================== ASSERTIONS ============================================================================== [PASS] row counts match: 624,040 == 624,040 [PASS] no NaN values: message=0, orderbook=0 [PASS] all 46 columns numeric (6 message + 40 orderbook) ============================================================================== ROW COUNT ============================================================================== events loaded: 624,040 event_type counts (raw, before any filtering): 1 new visible limit order 304,790 (48.84%) 2 partial cancellation 8,028 ( 1.29%) 3 total deletion 278,739 (44.67%) 4 visible execution 28,924 ( 4.63%) 5 hidden execution 3,559 ( 0.57%) ============================================================================== FIRST 20 ROWS - MESSAGE (left) vs ORDERBOOK LEVEL 1 (right) ============================================================================== Prices are still raw integers (dollars x 10000), Step 2 converts them. time event_type order_id size price direction ask_price_1 ask_size_1 bid_price_1 bid_size_1 0 34200.005743 4 15835012 34 275200 -1 275200 66 275100 400 1 34200.006241 1 16114545 100 275200 -1 275200 166 275100 400 2 34200.006462 1 16114695 100 275500 -1 275200 166 275100 400 3 34200.006484 1 16114707 100 275800 -1 275200 166 275100 400 4 34200.048864 3 16063194 100 275000 1 275200 166 275100 400 5 34200.048883 3 15833239 100 275100 1 275200 166 275100 300 6 34200.048989 1 16127246 100 275000 1 275200 166 275100 300 7 34200.049011 1 16127264 500 274900 1 275200 166 275100 300 8 34200.049078 1 16127293 500 274800 1 275200 166 275100 300 9 34200.049110 1 16127306 500 274700 1 275200 166 275100 300 10 34200.049156 1 16127319 500 274600 1 275200 166 275100 300 11 34200.049231 1 16127343 500 274500 1 275200 166 275100 300 12 34200.049284 1 16127361 500 274400 1 275200 166 275100 300 13 34200.049301 1 16127367 200 275000 1 275200 166 275100 300 14 34200.049338 1 16127378 500 274300 1 275200 166 275100 300 15 34200.049386 1 16127398 500 276100 -1 275200 166 275100 300 16 34200.049521 3 15834355 100 274600 1 275200 166 275100 300 17 34200.049525 2 15834520 1900 274400 1 275200 166 275100 300 18 34200.056549 1 16129989 100 274600 1 275200 166 275100 300 19 34200.211338 4 15835012 66 275200 -1 275200 100 275100 300 ============================================================================== FULL 40-COLUMN ORDERBOOK STRUCTURE - FIRST 3 ROWS ============================================================================== ask_price_1 ask_size_1 bid_price_1 bid_size_1 ask_price_2 ask_size_2 bid_price_2 bid_size_2 ask_price_3 ask_size_3 bid_price_3 bid_size_3 ask_price_4 ask_size_4 bid_price_4 bid_size_4 ask_price_5 ask_size_5 bid_price_5 bid_size_5 ask_price_6 ask_size_6 bid_price_6 bid_size_6 ask_price_7 ask_size_7 bid_price_7 bid_size_7 ask_price_8 ask_size_8 bid_price_8 bid_size_8 ask_price_9 ask_size_9 bid_price_9 bid_size_9 ask_price_10 ask_size_10 bid_price_10 bid_size_10 0 275200 66 275100 400 275300 1000 275000 100 275400 373 274900 200 275600 100 274800 661 275700 100 274700 300 275900 8589 274600 700 276000 959 274500 900 276100 2300 274400 2800 276200 2700 274300 3300 276300 2000 274200 4063 1 275200 166 275100 400 275300 1000 275000 100 275400 373 274900 200 275600 100 274800 661 275700 100 274700 300 275900 8589 274600 700 276000 959 274500 900 276100 2300 274400 2800 276200 2700 274300 3300 276300 2000 274200 4063 2 275200 166 275100 400 275300 1000 275000 100 275400 373 274900 200 275500 100 274800 661 275600 100 274700 300 275700 100 274600 700 275900 8589 274500 900 276000 959 274400 2800 276100 2300 274300 3300 276200 2700 274200 4063 ============================================================================== ALIGNMENT PROOF - is orderbook row k BEFORE or AFTER message k? ============================================================================== checked 1,993 sampled events passed 1,993 failed 0 (100.0000% agreement) [PASS] orderbook row k is the state AFTER message k. ============================================================================== STEP 2 - CONVERT UNITS ============================================================================== Identifying unoccupied level slots two independent ways: volume == 0 rule : 0 cells price == +/-9999999999 rule : 0 cells cells where they disagree : 0 [PASS] the two rules are identical; adopting the volume rule (no magic threshold) 0 of 12,480,800 level slots are padding (0.0000%) - i.e. the 10-level window was never deeper than the real book. price scale applied: raw integer / 10000 -> dollars message price : 26.5200 .. 27.6800 best ask (L1) : 26.6200 .. 27.6000 best bid (L1) : 26.6100 .. 27.5900 clock column added for plotting only: 2012-06-21 09:30:00.005742728 .. 2012-06-21 15:59:59.948441634 [PASS] all level-1 prices lie in $1-$1000 (plausible for INTC in 2012) ============================================================================== STEP 3 - RESTRICT THE SESSION ============================================================================== reason rows flagged % of file -------------------------------------------------- time < 09:30:00 0 0.0000% time > 16:00:00 0 0.0000% event_type 6 or 7 0 0.0000% -------------------------------------------------- total dropped 0 0.0000% kept 624,040 100.0000% [PASS] row counts still match after filtering: 624,040 == 624,040 [PASS] both frames re-indexed identically (alignment preserved) [PASS] no event_type 6 or 7 remain; surviving types: [1, 2, 3, 4, 5] [PASS] time in session: 34200.005743 >= 34200 and 57599.948442 <= 57600 ============================================================================== STEP 4 - BUILD THE TOP OF BOOK ============================================================================== Working frame columns: ['time', 'clock', 'event_type', 'bid', 'ask', 'bid_size', 'ask_size', 'spread', 'mid'] rows: 624,040 time clock event_type bid ask bid_size ask_size spread mid 0 34200.005743 2012-06-21 09:30:00.005742728 4 27.51 27.52 400.0 66.0 0.01 27.515 1 34200.006241 2012-06-21 09:30:00.006241020 1 27.51 27.52 400.0 166.0 0.01 27.515 2 34200.006462 2012-06-21 09:30:00.006461694 1 27.51 27.52 400.0 166.0 0.01 27.515 3 34200.006484 2012-06-21 09:30:00.006484232 1 27.51 27.52 400.0 166.0 0.01 27.515 4 34200.048864 2012-06-21 09:30:00.048863815 3 27.51 27.52 400.0 166.0 0.01 27.515 5 34200.048883 2012-06-21 09:30:00.048883439 3 27.51 27.52 300.0 166.0 0.01 27.515 6 34200.048989 2012-06-21 09:30:00.048989220 1 27.51 27.52 300.0 166.0 0.01 27.515 7 34200.049011 2012-06-21 09:30:00.049010886 1 27.51 27.52 300.0 166.0 0.01 27.515 8 34200.049078 2012-06-21 09:30:00.049078453 1 27.51 27.52 300.0 166.0 0.01 27.515 9 34200.049110 2012-06-21 09:30:00.049110147 1 27.51 27.52 300.0 166.0 0.01 27.515 ============================================================================== STEP 4 - SANITY OF THE TOUCH (counts BEFORE dropping anything) ============================================================================== condition rows % of rows ----------------------------------------------------------------- crossed book (spread < 0) 0 0.00000% locked book (spread == 0) 0 0.00000% empty bid side (bid_size <= 0 or NaN) 0 0.00000% empty ask side (ask_size <= 0 or NaN) 0 0.00000% undefined spread (NaN) 0 0.00000% ----------------------------------------------------------------- union of all failures 0 0.00000% spread summary (cents): min=1.00 median=1.00 max=4.00 dropped 0 unusable rows (0.00000%); 624,040 remain [PASS] every remaining row: spread > 0, bid_size > 0, ask_size > 0 cached working frame -> output\top_of_book.pkl (44.9 MB) ============================================================================== STEP 5 - DIAGNOSTIC PLOTS ============================================================================== rows: 624,040 fraction of rows with a one cent spread : 76.7028% median spread (cents) : 1.00 median bid_size (shares) : 13,391 median ask_size (shares) : 12,291 mid range : 26.615 - 27.595 spread by half hour: mean_spread_cents pct_one_cent rows clock 2012-06-21 09:30:00 1.4003 0.6050 84889 2012-06-21 10:00:00 1.2100 0.7901 52928 2012-06-21 10:30:00 1.1699 0.8301 36576 2012-06-21 11:00:00 1.2191 0.7809 50587 2012-06-21 11:30:00 1.1877 0.8123 41154 2012-06-21 12:00:00 1.2473 0.7527 50080 2012-06-21 12:30:00 1.2677 0.7323 43031 2012-06-21 13:00:00 1.1816 0.8184 33499 2012-06-21 13:30:00 1.2186 0.7814 37974 2012-06-21 14:00:00 1.0812 0.9188 22798 2012-06-21 14:30:00 1.2657 0.7343 39314 2012-06-21 15:00:00 1.2031 0.7969 50219 2012-06-21 15:30:00 1.1843 0.8157 80991 wrote fig05_mid.png, fig05_spread.png, fig05_spread_hist.png ============================================================================== STEP 6 - IMBALANCE ============================================================================== [PASS] imb within [-1, +1] for every row [PASS] no NaN or infinite values mean : +0.06011 std : 0.41576 fraction |imb|>0.8: 6.1002% median |imb| : 0.2964 wrote fig06_imbalance.png and features.pkl ============================================================================== STEP 7 - FORWARD RETURNS ============================================================================== [PASS] fwd_return_10 is NaN for exactly the last 10 rows and no others [PASS] fwd_return_50 is NaN for exactly the last 50 rows and no others [PASS] fwd_return_100 is NaN for exactly the last 100 rows and no others rows where mid is unchanged over 10 events: 95.45% sampling only rows that moved, so the check can actually fail: row mid[t-10] mid[t] mid[t+10] by hand from column match 270,114 27.1250 27.1250 27.1300 1.843e-04 1.843e-04 True 302,308 27.0800 27.0800 27.0750 -1.846e-04 -1.846e-04 True 349,166 26.9400 26.9400 26.9450 1.856e-04 1.856e-04 True 542,406 26.7150 26.7150 26.7200 1.872e-04 1.872e-04 True 575,397 26.6950 26.6950 26.6900 -1.873e-04 -1.873e-04 True [PASS] all five agree to floating point tolerance [PASS] forward differs from backward on the sampled rows, shift reads ahead magnitude check (should be a few basis points, not percent scale): std(fwd_return_10 ) = 4.304e-05 = 0.430 bps std(fwd_return_50 ) = 9.679e-05 = 0.968 bps std(fwd_return_100) = 1.397e-04 = 1.397 bps [PASS] magnitudes are basis point scale ============================================================================== LEAKAGE CONTRAST - forward vs backward correlation with imb ============================================================================== bad_return is the BACKWARD return. It is a description of what already happened, never a prediction. Reported as the contrast case. horizon corr(imb, fwd) corr(imb, backward) -------------------------------------------------- N=10 0.24299 -0.10476 N=50 0.38694 0.01455 N=100 0.43460 0.08536 wrote features.pkl ============================================================================== STEP 8 - BUCKETED RELATIONSHIP ============================================================================== decile edges of imb: 1 (-1.0010, -0.4880] 2 (-0.4880, -0.2950] 3 (-0.2950, -0.1630] 4 (-0.1630, -0.0414] 5 (-0.0414, +0.0771] 6 (+0.0771, +0.1840] 7 (+0.1840, +0.2980] 8 (+0.2980, +0.4190] 9 (+0.4190, +0.5950] 10 (+0.5950, +1.0000] horizon N=10 n mean_bps se_bps lo hi imb_decile 1 62394 -0.2346 0.0029 -0.2402 -0.2289 2 62404 -0.0376 0.0015 -0.0405 -0.0348 3 62405 -0.0250 0.0012 -0.0275 -0.0226 4 62403 -0.0255 0.0012 -0.0278 -0.0232 5 62405 -0.0133 0.0011 -0.0154 -0.0111 6 62405 0.0043 0.0010 0.0024 0.0062 7 62547 0.0194 0.0011 0.0172 0.0216 8 62264 0.0223 0.0013 0.0198 0.0247 9 62399 0.0374 0.0015 0.0344 0.0404 10 62404 0.2054 0.0027 0.2000 0.2108 horizon N=50 n mean_bps se_bps lo hi imb_decile 1 62354 -0.8072 0.0052 -0.8174 -0.7969 2 62404 -0.3056 0.0036 -0.3127 -0.2985 3 62405 -0.1740 0.0030 -0.1799 -0.1681 4 62403 -0.1303 0.0027 -0.1357 -0.1249 5 62405 -0.0543 0.0028 -0.0597 -0.0488 6 62405 0.0354 0.0025 0.0305 0.0403 7 62547 0.1186 0.0027 0.1133 0.1240 8 62264 0.1517 0.0030 0.1458 0.1577 9 62399 0.2761 0.0038 0.2688 0.2835 10 62404 0.6521 0.0052 0.6419 0.6622 horizon N=100 n mean_bps se_bps lo hi imb_decile 1 62308 -1.2586 0.0068 -1.2720 -1.2452 2 62404 -0.5752 0.0052 -0.5853 -0.5651 3 62402 -0.3650 0.0045 -0.3738 -0.3561 4 62402 -0.2673 0.0043 -0.2757 -0.2590 5 62405 -0.1086 0.0042 -0.1168 -0.1003 6 62405 0.0630 0.0041 0.0550 0.0709 7 62547 0.2210 0.0041 0.2129 0.2291 8 62264 0.2811 0.0044 0.2724 0.2898 9 62399 0.5323 0.0053 0.5220 0.5426 10 62404 1.0019 0.0068 0.9886 1.0152 wrote fig08_deciles.png ============================================================================== STEP 9 - REGRESSION fwd_return_N ~ imb ============================================================================== naive OLS errors vs HAC (Newey-West, lags = N) horizon n coef(bps) se_naive t_naive se_HAC t_HAC R2 -------------------------------------------------------------------------------------- N=10 624,030 0.252 0.0013 197.9 0.0052 48.6 0.05905 N=50 623,990 0.901 0.0027 331.5 0.0190 47.3 0.14972 N=100 623,940 1.461 0.0038 381.2 0.0336 43.5 0.18887 t-stat inflation from ignoring overlap: N=10 naive t = 197.9 HAC t = 48.6 overstated by 4.1x N=50 naive t = 331.5 HAC t = 47.3 overstated by 7.0x N=100 naive t = 381.2 HAC t = 43.5 overstated by 8.8x ============================================================================== STEP 10 - IS IT TRADABLE? ============================================================================== median spread : 1.000 cents half spread (cost in) : 0.500 cents predicted move over the next 100 events, by extreme decile: decile rows mean ret (bps) mean price edge (cents) ------------------------------------------------------------------ 10 (top) 62,404 1.0019 27.1208 0.2717 1 (bottom) 62,404 -1.2586 27.0446 -0.3404 ------------------------------------------------------------------ predicted edge, top decile : +0.2717 cents cost of crossing to enter : 0.5000 cents ratio edge / half spread : 0.543 shortfall : 0.2283 cents CONCLUSION: the predicted move is SMALLER than the cost of crossing. The signal is real but not tradable by taking liquidity. Only a participant already resting in the queue, who pays no spread to enter, can act on it, by managing queue position rather than by crossing. ============================================================================== STEP 11 - ROBUSTNESS ============================================================================== ------------------------------------------------------------------------------ 1. TIME OF DAY SPLIT ------------------------------------------------------------------------------ open 0930-1030 (137,817 rows) horizon n coef(bps) se_naive t_naive se_HAC t_HAC R2 -------------------------------------------------------------------------------------- N=10 137,817 0.330 0.0035 95.6 0.0119 27.8 0.06222 N=50 137,817 1.058 0.0075 140.6 0.0450 23.5 0.12551 N=100 137,817 1.621 0.0107 151.0 0.0824 19.7 0.14202 midday 1030-1500 (355,013 rows) horizon n coef(bps) se_naive t_naive se_HAC t_HAC R2 -------------------------------------------------------------------------------------- N=10 355,013 0.233 0.0015 154.8 0.0067 34.8 0.06326 N=50 355,013 0.869 0.0032 271.0 0.0237 36.7 0.17144 N=100 355,013 1.434 0.0045 318.9 0.0408 35.2 0.22264 close 1500-1600 (131,210 rows) horizon n coef(bps) se_naive t_naive se_HAC t_HAC R2 -------------------------------------------------------------------------------------- N=10 131,200 0.206 0.0023 88.4 0.0103 20.1 0.05621 N=50 131,160 0.820 0.0048 171.6 0.0377 21.8 0.18338 N=100 131,110 1.388 0.0066 211.3 0.0640 21.7 0.25407 ------------------------------------------------------------------------------ 2. ONE CENT SPREAD ONLY ------------------------------------------------------------------------------ spread == 1 cent (478,656 rows, 76.7% of sample) horizon n coef(bps) se_naive t_naive se_HAC t_HAC R2 -------------------------------------------------------------------------------------- N=10 478,646 0.266 0.0012 222.4 0.0056 47.2 0.09365 N=50 478,606 0.897 0.0027 331.1 0.0198 45.2 0.18633 N=100 478,556 1.434 0.0041 353.9 0.0348 41.3 0.20744 ------------------------------------------------------------------------------ 3. POST-TRADE EXCLUSION ------------------------------------------------------------------------------ dropping rows within 10 events of an execution (502,683 rows kept, 121,357 dropped) horizon n coef(bps) se_naive t_naive se_HAC t_HAC R2 -------------------------------------------------------------------------------------- N=10 502,683 0.051 0.0010 49.9 0.0030 16.8 0.00492 N=50 502,644 0.508 0.0027 190.3 0.0162 31.4 0.06722 N=100 502,622 1.039 0.0041 253.5 0.0324 32.0 0.11338 ------------------------------------------------------------------------------ 4. SHUFFLE CONTROL ------------------------------------------------------------------------------ imb is randomly permuted, destroying any real link to the future. The coefficient must collapse to zero. If it does not, there is a bug. shuffled imb (placebo) horizon n coef(bps) se_naive t_naive se_HAC t_HAC R2 -------------------------------------------------------------------------------------- N=10 624,030 -0.001 0.0013 -0.6 0.0013 -0.6 0.00000 N=50 623,990 -0.001 0.0029 -0.4 0.0029 -0.4 0.00000 N=100 623,940 0.002 0.0043 0.5 0.0042 0.5 0.00000 N=100 real R2 = 0.18887 shuffled R2 = 0.00000033 ratio = 566,080x N=100 real HAC t = 43.5 shuffled HAC t = 0.46 ############################################################################## # step01_load.py ############################################################################## ############################################################################## # steps_02_04.py ############################################################################## ############################################################################## # step05_plots.py ############################################################################## ############################################################################## # step06_imbalance.py ############################################################################## ############################################################################## # step07_forward.py ############################################################################## ############################################################################## # step08_deciles.py ############################################################################## ############################################################################## # step09_regression.py ############################################################################## ############################################################################## # step10_tradable.py ############################################################################## ############################################################################## # step11_robustness.py ############################################################################## all steps completed