Handle too-fast-edits with `defaultdict[str, bidict[str, tuple]]`
Not entirely sure why this all of a sudden became a problem but it seems price changes on order edits were sometimes resulting in key errors when modifying paper book entries quickly. This changes the implementation to not care about matching the last price when keying/popping old orders and use `bidict`s to more easily pop cleared orders in the paper loop.size_in_shm_token
parent
9200e8da57
commit
fe3d0c6fdd
|
@ -18,6 +18,7 @@
|
||||||
Fake trading for forward testing.
|
Fake trading for forward testing.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
from collections import defaultdict
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
|
@ -72,8 +73,8 @@ class PaperBoi(Struct):
|
||||||
|
|
||||||
# map of paper "live" orders which be used
|
# map of paper "live" orders which be used
|
||||||
# to simulate fills based on paper engine settings
|
# to simulate fills based on paper engine settings
|
||||||
_buys: dict
|
_buys: defaultdict[str, bidict]
|
||||||
_sells: dict
|
_sells: defaultdict[str, bidict]
|
||||||
_reqids: bidict
|
_reqids: bidict
|
||||||
_positions: dict[str, Position]
|
_positions: dict[str, Position]
|
||||||
_trade_ledger: dict[str, Any]
|
_trade_ledger: dict[str, Any]
|
||||||
|
@ -166,10 +167,10 @@ class PaperBoi(Struct):
|
||||||
|
|
||||||
if is_modify:
|
if is_modify:
|
||||||
# remove any existing order for the old price
|
# remove any existing order for the old price
|
||||||
orders[symbol].pop((oid, old_price))
|
orders[symbol].pop(oid)
|
||||||
|
|
||||||
# buys/sells: (symbol -> (price -> order))
|
# buys/sells: {symbol -> bidict[oid, (<price data>)]}
|
||||||
orders.setdefault(symbol, {})[(oid, price)] = (size, reqid, action)
|
orders[symbol][oid] = (price, size, reqid, action)
|
||||||
|
|
||||||
return reqid
|
return reqid
|
||||||
|
|
||||||
|
@ -191,7 +192,6 @@ class PaperBoi(Struct):
|
||||||
|
|
||||||
msg = BrokerdStatus(
|
msg = BrokerdStatus(
|
||||||
status='canceled',
|
status='canceled',
|
||||||
# account=f'paper_{self.broker}',
|
|
||||||
account='paper',
|
account='paper',
|
||||||
reqid=reqid,
|
reqid=reqid,
|
||||||
time_ns=time.time_ns(),
|
time_ns=time.time_ns(),
|
||||||
|
@ -335,9 +335,10 @@ async def simulate_fills(
|
||||||
tick.get('size', client.last_ask[1]),
|
tick.get('size', client.last_ask[1]),
|
||||||
)
|
)
|
||||||
|
|
||||||
orders = client._buys.get(sym, {})
|
# orders = client._buys.get(sym, {})
|
||||||
|
orders = client._buys[sym]
|
||||||
book_sequence = reversed(
|
book_sequence = reversed(
|
||||||
sorted(orders.keys(), key=itemgetter(1)))
|
sorted(orders.values(), key=itemgetter(0)))
|
||||||
|
|
||||||
def pred(our_price):
|
def pred(our_price):
|
||||||
return tick_price <= our_price
|
return tick_price <= our_price
|
||||||
|
@ -351,10 +352,11 @@ async def simulate_fills(
|
||||||
tick_price,
|
tick_price,
|
||||||
tick.get('size', client.last_bid[1]),
|
tick.get('size', client.last_bid[1]),
|
||||||
)
|
)
|
||||||
orders = client._sells.get(sym, {})
|
# orders = client._sells.get(sym, {})
|
||||||
|
orders = client._sells[sym]
|
||||||
book_sequence = sorted(
|
book_sequence = sorted(
|
||||||
orders.keys(),
|
orders.values(),
|
||||||
key=itemgetter(1)
|
key=itemgetter(0)
|
||||||
)
|
)
|
||||||
|
|
||||||
def pred(our_price):
|
def pred(our_price):
|
||||||
|
@ -370,13 +372,20 @@ async def simulate_fills(
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# iterate book prices descending
|
# iterate book prices descending
|
||||||
for oid, our_price in book_sequence:
|
# for oid, our_price in book_sequence:
|
||||||
# print(tick)
|
# print(tick)
|
||||||
# print((sym, list(book_sequence), client._buys, client._sells))
|
# print((
|
||||||
|
# sym,
|
||||||
|
# list(book_sequence),
|
||||||
|
# client._buys,
|
||||||
|
# client._sells,
|
||||||
|
# ))
|
||||||
|
for order_info in book_sequence:
|
||||||
|
(our_price, size, reqid, action) = order_info
|
||||||
clearable = pred(our_price)
|
clearable = pred(our_price)
|
||||||
if clearable:
|
if clearable:
|
||||||
# retreive order info
|
# retreive order info
|
||||||
(size, reqid, action) = orders.pop((oid, our_price))
|
oid = orders.inverse.pop(order_info)
|
||||||
|
|
||||||
# clearing price would have filled entirely
|
# clearing price would have filled entirely
|
||||||
await client.fake_fill(
|
await client.fake_fill(
|
||||||
|
@ -454,20 +463,20 @@ async def handle_order_requests(
|
||||||
|
|
||||||
|
|
||||||
_reqids: bidict[str, tuple] = {}
|
_reqids: bidict[str, tuple] = {}
|
||||||
_buys: dict[
|
_buys: defaultdict[
|
||||||
str,
|
str, # symbol
|
||||||
dict[
|
bidict[
|
||||||
tuple[str, float],
|
str, # oid
|
||||||
tuple[float, str, str],
|
tuple[float, float, str, str], # order info
|
||||||
]
|
]
|
||||||
] = {}
|
] = defaultdict(bidict)
|
||||||
_sells: dict[
|
_sells: defaultdict[
|
||||||
str,
|
str, # symbol
|
||||||
dict[
|
bidict[
|
||||||
tuple[str, float],
|
str, # oid
|
||||||
tuple[float, str, str],
|
tuple[float, float, str, str], # order info
|
||||||
]
|
]
|
||||||
] = {}
|
] = defaultdict(bidict)
|
||||||
_positions: dict[str, Position] = {}
|
_positions: dict[str, Position] = {}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue