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
parent
572f984d06
commit
eeeeb29f71
|
@ -125,7 +125,9 @@ def get_orders(
|
||||||
if _orders is None:
|
if _orders is None:
|
||||||
# setup local ui event streaming channels for request/resp
|
# setup local ui event streaming channels for request/resp
|
||||||
# streamging with EMS daemon
|
# streamging with EMS daemon
|
||||||
_orders = OrderBook(*trio.open_memory_channel(1))
|
_orders = OrderBook(
|
||||||
|
*trio.open_memory_channel(100),
|
||||||
|
)
|
||||||
|
|
||||||
return _orders
|
return _orders
|
||||||
|
|
||||||
|
|
|
@ -28,10 +28,10 @@ import uuid
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
import trio
|
import trio
|
||||||
# from trio_typing import TaskStatus
|
|
||||||
|
|
||||||
from ._graphics._lines import LevelLine, position_line
|
from ._graphics._lines import LevelLine, position_line
|
||||||
from ._editors import LineEditor, ArrowEditor, _order_lines
|
from ._editors import LineEditor, ArrowEditor, _order_lines
|
||||||
|
from ._window import MultiStatus, main_window
|
||||||
from ..clearing._client import open_ems, OrderBook
|
from ..clearing._client import open_ems, OrderBook
|
||||||
from ..data._source import Symbol
|
from ..data._source import Symbol
|
||||||
from ..log import get_logger
|
from ..log import get_logger
|
||||||
|
@ -49,18 +49,28 @@ class Position(BaseModel):
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class OrderMode:
|
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"
|
This is the default mode that pairs with "follow mode"
|
||||||
(when wathing the rt price update at the current time step)
|
(when wathing the rt price update at the current time step)
|
||||||
and allows entering orders using the ``a, d, f`` keys and
|
and allows entering orders using mouse and keyboard.
|
||||||
cancelling moused-over orders with the ``c`` key.
|
|
||||||
|
|
||||||
"""
|
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
|
chart: 'ChartPlotWidget' # type: ignore # noqa
|
||||||
book: OrderBook
|
book: OrderBook
|
||||||
lines: LineEditor
|
lines: LineEditor
|
||||||
arrows: ArrowEditor
|
arrows: ArrowEditor
|
||||||
|
status_bar: MultiStatus
|
||||||
|
|
||||||
_colors = {
|
_colors = {
|
||||||
'alert': 'alert_yellow',
|
'alert': 'alert_yellow',
|
||||||
'buy': 'buy_green',
|
'buy': 'buy_green',
|
||||||
|
@ -72,7 +82,8 @@ class OrderMode:
|
||||||
_position: Dict[str, Any] = field(default_factory=dict)
|
_position: Dict[str, Any] = field(default_factory=dict)
|
||||||
_position_line: dict = None
|
_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(
|
def on_position_update(
|
||||||
self,
|
self,
|
||||||
|
@ -134,6 +145,13 @@ class OrderMode:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
line = self.lines.commit_line(uuid)
|
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
|
return line
|
||||||
|
|
||||||
def on_fill(
|
def on_fill(
|
||||||
|
@ -191,6 +209,10 @@ class OrderMode:
|
||||||
self.lines.remove_line(uuid=uuid)
|
self.lines.remove_line(uuid=uuid)
|
||||||
self.chart._cursor.show_xhair()
|
self.chart._cursor.show_xhair()
|
||||||
|
|
||||||
|
pending = self._pending_submissions.pop(uuid, None)
|
||||||
|
if pending:
|
||||||
|
order_line, func = pending
|
||||||
|
func()
|
||||||
else:
|
else:
|
||||||
log.warning(
|
log.warning(
|
||||||
f'Received cancel for unsubmitted order {pformat(msg)}'
|
f'Received cancel for unsubmitted order {pformat(msg)}'
|
||||||
|
@ -245,17 +267,67 @@ class OrderMode:
|
||||||
)
|
)
|
||||||
line.oid = uid
|
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
|
# hook up mouse drag handlers
|
||||||
line._on_drag_start = self.order_line_modify_start
|
line._on_drag_start = self.order_line_modify_start
|
||||||
line._on_drag_end = self.order_line_modify_complete
|
line._on_drag_end = self.order_line_modify_complete
|
||||||
|
|
||||||
return line
|
return line
|
||||||
|
|
||||||
def cancel_order_under_cursor(self) -> None:
|
def cancel_orders_under_cursor(self) -> list[str]:
|
||||||
for line in self.lines.lines_under_cursor():
|
return self.cancel_orders_from_lines(
|
||||||
self.book.cancel(uuid=line.oid)
|
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
|
# order-line modify handlers
|
||||||
|
|
||||||
def order_line_modify_start(
|
def order_line_modify_start(
|
||||||
self,
|
self,
|
||||||
line: LevelLine,
|
line: LevelLine,
|
||||||
|
@ -281,13 +353,14 @@ async def open_order_mode(
|
||||||
chart: pg.PlotWidget,
|
chart: pg.PlotWidget,
|
||||||
book: OrderBook,
|
book: OrderBook,
|
||||||
):
|
):
|
||||||
|
status_bar: MultiStatus = main_window().status_bar
|
||||||
view = chart._vb
|
view = chart._vb
|
||||||
lines = LineEditor(chart=chart, _order_lines=_order_lines)
|
lines = LineEditor(chart=chart, _order_lines=_order_lines)
|
||||||
arrows = ArrowEditor(chart, {})
|
arrows = ArrowEditor(chart, {})
|
||||||
|
|
||||||
log.info("Opening order mode")
|
log.info("Opening order mode")
|
||||||
|
|
||||||
mode = OrderMode(chart, book, lines, arrows)
|
mode = OrderMode(chart, book, lines, arrows, status_bar)
|
||||||
view.mode = mode
|
view.mode = mode
|
||||||
|
|
||||||
asset_type = symbol.type_key
|
asset_type = symbol.type_key
|
||||||
|
@ -318,7 +391,6 @@ async def start_order_mode(
|
||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
brokername: str,
|
brokername: str,
|
||||||
|
|
||||||
# task_status: TaskStatus[trio.Event] = trio.TASK_STATUS_IGNORED,
|
|
||||||
started: trio.Event,
|
started: trio.Event,
|
||||||
|
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
Loading…
Reference in New Issue