Add order cancellation and submission statuses

Generalize the methods for cancelling groups of orders (all or those
under cursor) and add new group status support such that statuses for
each cancel or order submission is displayed in the status bar. In the
"cancel-all-orders" case, use the new group status stuff.
asyncify_input_modes
Tyler Goodlet 2021-06-17 17:00:57 -04:00
parent 572f984d06
commit eeeeb29f71
2 changed files with 86 additions and 12 deletions

View File

@ -125,7 +125,9 @@ def get_orders(
if _orders is None:
# setup local ui event streaming channels for request/resp
# streamging with EMS daemon
_orders = OrderBook(*trio.open_memory_channel(1))
_orders = OrderBook(
*trio.open_memory_channel(100),
)
return _orders

View File

@ -28,10 +28,10 @@ import uuid
import pyqtgraph as pg
from pydantic import BaseModel
import trio
# from trio_typing import TaskStatus
from ._graphics._lines import LevelLine, position_line
from ._editors import LineEditor, ArrowEditor, _order_lines
from ._window import MultiStatus, main_window
from ..clearing._client import open_ems, OrderBook
from ..data._source import Symbol
from ..log import get_logger
@ -49,18 +49,28 @@ class Position(BaseModel):
@dataclass
class OrderMode:
"""Major mode for placing orders on a chart view.
'''Major mode for placing orders on a chart view.
This is the default mode that pairs with "follow mode"
(when wathing the rt price update at the current time step)
and allows entering orders using the ``a, d, f`` keys and
cancelling moused-over orders with the ``c`` key.
and allows entering orders using mouse and keyboard.
"""
Current manual:
a -> alert
s/ctrl -> submission type modifier {on: live, off: dark}
f (fill) -> buy limit order
d (dump) -> sell limit order
c (cancel) -> cancel order under cursor
cc -> cancel all submitted orders on chart
mouse click and drag -> modify current order under cursor
'''
chart: 'ChartPlotWidget' # type: ignore # noqa
book: OrderBook
lines: LineEditor
arrows: ArrowEditor
status_bar: MultiStatus
_colors = {
'alert': 'alert_yellow',
'buy': 'buy_green',
@ -72,7 +82,8 @@ class OrderMode:
_position: Dict[str, Any] = field(default_factory=dict)
_position_line: dict = None
key_map: Dict[str, Callable] = field(default_factory=dict)
_pending_submissions: dict[str, (LevelLine, Callable)] = field(
default_factory=dict)
def on_position_update(
self,
@ -134,6 +145,13 @@ class OrderMode:
"""
line = self.lines.commit_line(uuid)
pending = self._pending_submissions.get(uuid)
if pending:
order_line, func = pending
assert order_line is line
func()
return line
def on_fill(
@ -191,6 +209,10 @@ class OrderMode:
self.lines.remove_line(uuid=uuid)
self.chart._cursor.show_xhair()
pending = self._pending_submissions.pop(uuid, None)
if pending:
order_line, func = pending
func()
else:
log.warning(
f'Received cancel for unsubmitted order {pformat(msg)}'
@ -245,17 +267,67 @@ class OrderMode:
)
line.oid = uid
# enter submission which will be popped once a response
# from the EMS is received to move the order to a different# status
self._pending_submissions[uid] = (
line,
self.status_bar.open_status(
f'submitting {self._exec_mode}-{action}',
final_msg=f'submitted {self._exec_mode}-{action}',
clear_on_next=True,
)
)
# hook up mouse drag handlers
line._on_drag_start = self.order_line_modify_start
line._on_drag_end = self.order_line_modify_complete
return line
def cancel_order_under_cursor(self) -> None:
for line in self.lines.lines_under_cursor():
self.book.cancel(uuid=line.oid)
def cancel_orders_under_cursor(self) -> list[str]:
return self.cancel_orders_from_lines(
self.lines.lines_under_cursor()
)
def cancel_all_orders(self) -> list[str]:
return self.cancel_orders_from_lines(
self.lines.all_lines()
)
def cancel_orders_from_lines(
self,
lines: list[LevelLine],
) -> list[str]:
ids: list = []
if lines:
key = self.status_bar.open_status(
f'cancelling {len(lines)} orders',
final_msg=f'cancelled {len(lines)} orders',
group_key=True
)
# cancel all active orders and triggers
for line in lines:
oid = getattr(line, 'oid', None)
if oid:
self._pending_submissions[oid] = (
line,
self.status_bar.open_status(
f'cancelling order {oid[:6]}',
group_key=key,
),
)
ids.append(oid)
self.book.cancel(uuid=oid)
return ids
# order-line modify handlers
def order_line_modify_start(
self,
line: LevelLine,
@ -281,13 +353,14 @@ async def open_order_mode(
chart: pg.PlotWidget,
book: OrderBook,
):
status_bar: MultiStatus = main_window().status_bar
view = chart._vb
lines = LineEditor(chart=chart, _order_lines=_order_lines)
arrows = ArrowEditor(chart, {})
log.info("Opening order mode")
mode = OrderMode(chart, book, lines, arrows)
mode = OrderMode(chart, book, lines, arrows, status_bar)
view.mode = mode
asset_type = symbol.type_key
@ -318,7 +391,6 @@ async def start_order_mode(
symbol: Symbol,
brokername: str,
# task_status: TaskStatus[trio.Event] = trio.TASK_STATUS_IGNORED,
started: trio.Event,
) -> None: