Fix double cancel bug!
Not sure how this lasted so long without complaint (literally since we added history 1m OHLC it seems; guess it means most backends are pretty tolerant XD ) but we've been sending 2 cancels per order (dialog) due to the mirrored lines on each chart: 1s and 1m. This fixes that by reworking the `OrderMode` methods to be a bit more sane and less conflated with the graphics (lines) layer. Deatz: - add new methods: - `.oids_from_lines()` line -> oid extraction, - `.cancel_orders()` which makes the order client cancel requests from a `oids: list[str]`. - re-impl `.cancel_all_orders()` and `.cancel_orders_under_cursor()` to use the above methods thus fixing the original bug B)basic_buy_bot
parent
84613cd596
commit
b28b38afab
|
@ -31,6 +31,7 @@ from typing import (
|
||||||
)
|
)
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
from bidict import bidict
|
||||||
import tractor
|
import tractor
|
||||||
import trio
|
import trio
|
||||||
from PyQt5.QtCore import Qt
|
from PyQt5.QtCore import Qt
|
||||||
|
@ -601,50 +602,65 @@ class OrderMode:
|
||||||
)
|
)
|
||||||
|
|
||||||
def cancel_orders_under_cursor(self) -> list[str]:
|
def cancel_orders_under_cursor(self) -> list[str]:
|
||||||
return self.cancel_orders_from_lines(
|
return self.cancel_orders(
|
||||||
|
self.oids_from_lines(
|
||||||
self.lines.lines_under_cursor()
|
self.lines.lines_under_cursor()
|
||||||
)
|
)
|
||||||
|
|
||||||
def cancel_all_orders(self) -> list[str]:
|
|
||||||
'''
|
|
||||||
Cancel all orders for the current chart.
|
|
||||||
|
|
||||||
'''
|
|
||||||
return self.cancel_orders_from_lines(
|
|
||||||
self.lines.all_lines()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def cancel_orders_from_lines(
|
def oids_from_lines(
|
||||||
self,
|
self,
|
||||||
lines: list[LevelLine],
|
lines: list[LevelLine],
|
||||||
|
|
||||||
) -> list[str]:
|
) -> list[Dialog]:
|
||||||
|
|
||||||
ids: list = []
|
oids: set[str] = set()
|
||||||
if lines:
|
for line in lines:
|
||||||
|
dialog: Dialog = getattr(line, 'dialog', None)
|
||||||
|
oid: str = dialog.uuid
|
||||||
|
if (
|
||||||
|
dialog
|
||||||
|
and oid not in oids
|
||||||
|
):
|
||||||
|
oids.add(oid)
|
||||||
|
|
||||||
|
return oids
|
||||||
|
|
||||||
|
def cancel_orders(
|
||||||
|
self,
|
||||||
|
oids: list[str],
|
||||||
|
|
||||||
|
) -> None:
|
||||||
|
'''
|
||||||
|
Cancel all orders from a list of order ids: `oids`.
|
||||||
|
|
||||||
|
'''
|
||||||
key = self.multistatus.open_status(
|
key = self.multistatus.open_status(
|
||||||
f'cancelling {len(lines)} orders',
|
f'cancelling {len(oids)} orders',
|
||||||
final_msg=f'cancelled {len(lines)} orders',
|
final_msg=f'cancelled orders:\n{oids}',
|
||||||
group_key=True
|
group_key=True
|
||||||
)
|
)
|
||||||
|
for oid in oids:
|
||||||
# cancel all active orders and triggers
|
dialog: Dialog = self.dialogs[oid]
|
||||||
for line in lines:
|
self.client.cancel_nowait(uuid=oid)
|
||||||
dialog = getattr(line, 'dialog', None)
|
|
||||||
|
|
||||||
if dialog:
|
|
||||||
oid = dialog.uuid
|
|
||||||
|
|
||||||
cancel_status_close = self.multistatus.open_status(
|
cancel_status_close = self.multistatus.open_status(
|
||||||
f'cancelling order {oid}',
|
f'cancelling order {oid}',
|
||||||
group_key=key,
|
group_key=key,
|
||||||
)
|
)
|
||||||
dialog.last_status_close = cancel_status_close
|
dialog.last_status_close = cancel_status_close
|
||||||
|
|
||||||
ids.append(oid)
|
def cancel_all_orders(self) -> None:
|
||||||
self.client.cancel_nowait(uuid=oid)
|
'''
|
||||||
|
Cancel all unique orders / executions by extracting unique
|
||||||
|
order ids from all order lines and then submitting cancel
|
||||||
|
requests for each dialog.
|
||||||
|
|
||||||
return ids
|
'''
|
||||||
|
return self.cancel_orders(
|
||||||
|
self.oids_from_lines(
|
||||||
|
self.lines.all_lines()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def load_unknown_dialog_from_msg(
|
def load_unknown_dialog_from_msg(
|
||||||
self,
|
self,
|
||||||
|
@ -750,7 +766,7 @@ async def open_order_mode(
|
||||||
trackers: dict[str, PositionTracker] = {}
|
trackers: dict[str, PositionTracker] = {}
|
||||||
|
|
||||||
# load account names from ``brokers.toml``
|
# load account names from ``brokers.toml``
|
||||||
accounts_def = config.load_accounts(
|
accounts_def: bidict[str, str | None] = config.load_accounts(
|
||||||
providers=[mkt.broker],
|
providers=[mkt.broker],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1135,8 +1151,9 @@ async def process_trade_msg(
|
||||||
action = order.action
|
action = order.action
|
||||||
details = msg.brokerd_msg
|
details = msg.brokerd_msg
|
||||||
|
|
||||||
# TODO: put the actual exchange timestamp?
|
# TODO: state tracking:
|
||||||
# TODO: some kinda progress system?
|
# - put the actual exchange timestamp?
|
||||||
|
# - some kinda progress system?
|
||||||
|
|
||||||
# NOTE: currently the ``kraken`` openOrders sub
|
# NOTE: currently the ``kraken`` openOrders sub
|
||||||
# doesn't deliver their engine timestamp as part of
|
# doesn't deliver their engine timestamp as part of
|
||||||
|
|
Loading…
Reference in New Issue