Always cancel (loaded) zero-priced orders
Ran into this trading a peenee where a dark got (mistakenly) submitted at a price of 0 and then that consecutively broke upstream allocator/pp code due to a divide-by-zero.. So instead always check for a zero-price (since that should never ever be valid in any market) and instead cancel any such order in the EMS and return `None` so that upstream callers can ignore it without crash handling.distribute_dis
parent
e4ce79f720
commit
83d1f117a8
|
@ -358,7 +358,7 @@ class OrderMode:
|
||||||
send_msg: bool = True,
|
send_msg: bool = True,
|
||||||
order: Order | None = None,
|
order: Order | None = None,
|
||||||
|
|
||||||
) -> Dialog:
|
) -> Dialog | None:
|
||||||
'''
|
'''
|
||||||
Send execution order to EMS return a level line to
|
Send execution order to EMS return a level line to
|
||||||
represent the order on a chart.
|
represent the order on a chart.
|
||||||
|
@ -378,6 +378,16 @@ class OrderMode:
|
||||||
'oid': oid,
|
'oid': oid,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if order.price <= 0:
|
||||||
|
log.error(
|
||||||
|
'*!? Invalid `Order.price <= 0` ?!*\n'
|
||||||
|
# TODO: make this present multi-line in object form
|
||||||
|
# like `ib_insync.contracts.Contract.__repr__()`
|
||||||
|
f'{order}\n'
|
||||||
|
)
|
||||||
|
self.cancel_orders([order.oid])
|
||||||
|
return None
|
||||||
|
|
||||||
lines = self.lines_from_order(
|
lines = self.lines_from_order(
|
||||||
order,
|
order,
|
||||||
show_markers=True,
|
show_markers=True,
|
||||||
|
@ -663,7 +673,7 @@ class OrderMode:
|
||||||
self,
|
self,
|
||||||
msg: Status,
|
msg: Status,
|
||||||
|
|
||||||
) -> Dialog:
|
) -> Dialog | None:
|
||||||
# NOTE: the `.order` attr **must** be set with the
|
# NOTE: the `.order` attr **must** be set with the
|
||||||
# equivalent order msg in order to be loaded.
|
# equivalent order msg in order to be loaded.
|
||||||
order = msg.req
|
order = msg.req
|
||||||
|
@ -694,12 +704,15 @@ class OrderMode:
|
||||||
fqsn=fqme,
|
fqsn=fqme,
|
||||||
info={},
|
info={},
|
||||||
)
|
)
|
||||||
dialog = self.submit_order(
|
maybe_dialog: Dialog | None = self.submit_order(
|
||||||
send_msg=False,
|
send_msg=False,
|
||||||
order=order,
|
order=order,
|
||||||
)
|
)
|
||||||
assert self.dialogs[oid] == dialog
|
if maybe_dialog is None:
|
||||||
return dialog
|
return None
|
||||||
|
|
||||||
|
assert self.dialogs[oid] == maybe_dialog
|
||||||
|
return maybe_dialog
|
||||||
|
|
||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
|
@ -1079,8 +1092,25 @@ async def process_trade_msg(
|
||||||
)
|
)
|
||||||
):
|
):
|
||||||
msg.req = order
|
msg.req = order
|
||||||
dialog = mode.load_unknown_dialog_from_msg(msg)
|
dialog: (
|
||||||
mode.on_submit(oid)
|
Dialog
|
||||||
|
# NOTE: on an invalid order submission (eg.
|
||||||
|
# price <=0) the downstream APIs may return
|
||||||
|
# a null.
|
||||||
|
| None
|
||||||
|
) = mode.load_unknown_dialog_from_msg(msg)
|
||||||
|
|
||||||
|
# cancel any invalid pre-existing order!
|
||||||
|
if dialog is None:
|
||||||
|
log.warning(
|
||||||
|
'Order was ignored/invalid?\n'
|
||||||
|
f'{order}'
|
||||||
|
)
|
||||||
|
|
||||||
|
# if valid, display the order line the same as if
|
||||||
|
# it was submitted during this UI session.
|
||||||
|
else:
|
||||||
|
mode.on_submit(oid)
|
||||||
|
|
||||||
case Status(resp='error'):
|
case Status(resp='error'):
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue