Maybe you can save a local state for the current updates so that you don’t have to sort a table with other data.
msg.l2update:{
/* handle level2 update messages */
x:“SSZ*”$x; //cast dictionary to relevant types
s:.Q.id x`product_id; //extract sym, remove bad chars
c:“SFF”$/:x`changes; //extract and cast changes
{.[`.gdax.askst`.gdax.bidst y[0]=`buy;(x;y 1);:;y 2]}[s]'[c]; //update state dict(s)
sort.state[s]; //sort state dicts
rec.book[x`time;s]; //record current state of book
}
sort.state:{[s]
/* sort state dictionaries & drop empty levels */
@[;s;{(where 0=x)_x}]'[.gdax.bidst
.gdax.askst]; //drop all zeros
@[`.gdax.askst;s;{stdepth sublist asc[key x]#x}]; //sort asks ascending
@[`.gdax.bidst;s;{stdepth sublist desc[key x]#x}]; //sort bids descending
}
depth:5 //depth to maintain in book table
stdepth:100*depth //depth to maintain in state dicts
exchange: “Gdax”
bidst:(u#enlist
)!enlist(float$())!
float$() //bid state dict
askst:(u#enlist
)!enlist(float$())!
float$() //ask state dict
lb:(u#enlist
)!enlist(bids
bsizesasks
asizes!()) //last book state
/* Redefine publish function to pass to TP for real FH */
publish:upsert //define publish function to upsert for example FH
rec.book:{[t;s]
/* determine if book record needs published & publish if so */
bk: bids
bsizes!depth sublist’(key;value)@:bidst[s]; //get current bid book up to depth
bk,:asks
asizes!depth sublist’(key;value)@:askst[s]; //get current ask book up to depth
if[not bk~lb[s]; //compare to last book
publish[`book;@[bk;`ex`sym`time;:;(`Gdax;s;“p”$t)]]; //publish record if changed
lb[s]:bk; //record state of last book
];
}