Add order-cancel debugging and multiline kbd logs
Add verbose logging + error handling for order cancellation hotkey path and multiline style for view-mode kb msgs. Deats, - add `Cursor.is_hovered()` to check hover state - log warnings when no orders cancelled via <c> hotkey - add try-except around `.cancel_orders_under_cursor()` - log `cur._hovered` state in `.ui._lines` hover handlers - change `Dialog.cancel_orders()` to return `list[Dialog]` - fix import: `Flume` from `.data.flows` vs `.data.feed` - comment-out multi-status msgs in order submit/cancel Also, - convert all multiline kbd `if` conditionals to use `and` on separate lines for consistency - move `import tractor` to top of `._interaction` - change `print()` to `log.debug()` in `LevelLine` - fix type annotation spacing: `Callable|None` vs `Callable | None` (this commit msg was generated in some part by [`claude-code`][claude-code-gh]) [claude-code-gh]: https://github.com/anthropics/claude-codeorder_line_cancel_nowork_debugging
parent
12c346d846
commit
3db0cf9054
|
|
@ -413,9 +413,18 @@ class Cursor(pg.GraphicsObject):
|
||||||
self,
|
self,
|
||||||
item: pg.GraphicsObject,
|
item: pg.GraphicsObject,
|
||||||
) -> None:
|
) -> None:
|
||||||
assert getattr(item, 'delete'), f"{item} must define a ``.delete()``"
|
assert getattr(
|
||||||
|
item,
|
||||||
|
'delete',
|
||||||
|
), f"{item} must define a ``.delete()``"
|
||||||
self._hovered.add(item)
|
self._hovered.add(item)
|
||||||
|
|
||||||
|
def is_hovered(
|
||||||
|
self,
|
||||||
|
item: pg.GraphicsObject,
|
||||||
|
) -> bool:
|
||||||
|
return item in self._hovered
|
||||||
|
|
||||||
def add_plot(
|
def add_plot(
|
||||||
self,
|
self,
|
||||||
plot: ChartPlotWidget, # noqa
|
plot: ChartPlotWidget, # noqa
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ from piker.ui.qt import QLineF
|
||||||
from ..data._sharedmem import (
|
from ..data._sharedmem import (
|
||||||
ShmArray,
|
ShmArray,
|
||||||
)
|
)
|
||||||
from ..data.feed import Flume
|
from ..data.flows import Flume
|
||||||
from ..data._formatters import (
|
from ..data._formatters import (
|
||||||
IncrementalFormatter,
|
IncrementalFormatter,
|
||||||
OHLCBarsFmtr, # Plain OHLC renderer
|
OHLCBarsFmtr, # Plain OHLC renderer
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ from pyqtgraph import (
|
||||||
functions as fn,
|
functions as fn,
|
||||||
)
|
)
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
import tractor
|
||||||
import trio
|
import trio
|
||||||
|
|
||||||
from piker.ui.qt import (
|
from piker.ui.qt import (
|
||||||
|
|
@ -72,7 +73,10 @@ if TYPE_CHECKING:
|
||||||
GodWidget,
|
GodWidget,
|
||||||
)
|
)
|
||||||
from ._dataviz import Viz
|
from ._dataviz import Viz
|
||||||
from .order_mode import OrderMode
|
from .order_mode import (
|
||||||
|
OrderMode,
|
||||||
|
Dialog,
|
||||||
|
)
|
||||||
from ._display import DisplayState
|
from ._display import DisplayState
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -130,7 +134,12 @@ async def handle_viewmode_kb_inputs(
|
||||||
|
|
||||||
async for kbmsg in recv_chan:
|
async for kbmsg in recv_chan:
|
||||||
event, etype, key, mods, text = kbmsg.to_tuple()
|
event, etype, key, mods, text = kbmsg.to_tuple()
|
||||||
log.debug(f'key: {key}, mods: {mods}, text: {text}')
|
log.debug(
|
||||||
|
f'View-mode kb-msg received,\n'
|
||||||
|
f'mods: {mods!r}\n'
|
||||||
|
f'key: {key!r}\n'
|
||||||
|
f'text: {text!r}\n'
|
||||||
|
)
|
||||||
now = time.time()
|
now = time.time()
|
||||||
period = now - last
|
period = now - last
|
||||||
|
|
||||||
|
|
@ -158,8 +167,12 @@ async def handle_viewmode_kb_inputs(
|
||||||
# have no previous keys or we do and the min_tap period is
|
# have no previous keys or we do and the min_tap period is
|
||||||
# met
|
# met
|
||||||
if (
|
if (
|
||||||
not fast_key_seq or
|
not fast_key_seq
|
||||||
period <= min_tap and fast_key_seq
|
or (
|
||||||
|
period <= min_tap
|
||||||
|
and
|
||||||
|
fast_key_seq
|
||||||
|
)
|
||||||
):
|
):
|
||||||
fast_key_seq.append(text)
|
fast_key_seq.append(text)
|
||||||
log.debug(f'fast keys seqs {fast_key_seq}')
|
log.debug(f'fast keys seqs {fast_key_seq}')
|
||||||
|
|
@ -174,7 +187,8 @@ async def handle_viewmode_kb_inputs(
|
||||||
# UI REPL-shell, with ctrl-p (for "pause")
|
# UI REPL-shell, with ctrl-p (for "pause")
|
||||||
if (
|
if (
|
||||||
ctrl
|
ctrl
|
||||||
and key in {
|
and
|
||||||
|
key in {
|
||||||
Qt.Key_P,
|
Qt.Key_P,
|
||||||
}
|
}
|
||||||
):
|
):
|
||||||
|
|
@ -184,7 +198,6 @@ async def handle_viewmode_kb_inputs(
|
||||||
vlm_chart = chart.linked.subplots['volume'] # noqa
|
vlm_chart = chart.linked.subplots['volume'] # noqa
|
||||||
vlm_viz = vlm_chart.main_viz # noqa
|
vlm_viz = vlm_chart.main_viz # noqa
|
||||||
dvlm_pi = vlm_chart._vizs['dolla_vlm'].plot # noqa
|
dvlm_pi = vlm_chart._vizs['dolla_vlm'].plot # noqa
|
||||||
import tractor
|
|
||||||
await tractor.pause()
|
await tractor.pause()
|
||||||
view.interact_graphics_cycle()
|
view.interact_graphics_cycle()
|
||||||
|
|
||||||
|
|
@ -192,7 +205,8 @@ async def handle_viewmode_kb_inputs(
|
||||||
# shown data `Viz`s for the current chart app.
|
# shown data `Viz`s for the current chart app.
|
||||||
if (
|
if (
|
||||||
ctrl
|
ctrl
|
||||||
and key in {
|
and
|
||||||
|
key in {
|
||||||
Qt.Key_R,
|
Qt.Key_R,
|
||||||
}
|
}
|
||||||
):
|
):
|
||||||
|
|
@ -231,7 +245,8 @@ async def handle_viewmode_kb_inputs(
|
||||||
key == Qt.Key_Escape
|
key == Qt.Key_Escape
|
||||||
or (
|
or (
|
||||||
ctrl
|
ctrl
|
||||||
and key == Qt.Key_C
|
and
|
||||||
|
key == Qt.Key_C
|
||||||
)
|
)
|
||||||
):
|
):
|
||||||
# ctrl-c as cancel
|
# ctrl-c as cancel
|
||||||
|
|
@ -242,17 +257,35 @@ async def handle_viewmode_kb_inputs(
|
||||||
# cancel order or clear graphics
|
# cancel order or clear graphics
|
||||||
if (
|
if (
|
||||||
key == Qt.Key_C
|
key == Qt.Key_C
|
||||||
or key == Qt.Key_Delete
|
or
|
||||||
|
key == Qt.Key_Delete
|
||||||
):
|
):
|
||||||
|
# log.info('Handling <c> hotkey!')
|
||||||
|
try:
|
||||||
|
dialogs: list[Dialog] = order_mode.cancel_orders_under_cursor()
|
||||||
|
except BaseException:
|
||||||
|
log.exception('Failed to cancel orders !?\n')
|
||||||
|
await tractor.pause()
|
||||||
|
|
||||||
order_mode.cancel_orders_under_cursor()
|
if not dialogs:
|
||||||
|
log.warning(
|
||||||
|
'No orders were cancelled?\n'
|
||||||
|
'Is there an order-line under the cursor?\n'
|
||||||
|
'If you think there IS your DE might be "hiding the mouse" before '
|
||||||
|
'we rx the keyboard input via Qt..\n'
|
||||||
|
'=> Check your DE and/or TWM settings to be sure! <=\n'
|
||||||
|
)
|
||||||
|
# ^TODO?, some way to detect if there's lines and
|
||||||
|
# the DE is cuckin with things?
|
||||||
|
# await tractor.pause()
|
||||||
|
|
||||||
# View modes
|
# View modes
|
||||||
if (
|
if (
|
||||||
ctrl
|
ctrl
|
||||||
and (
|
and (
|
||||||
key == Qt.Key_Equal
|
key == Qt.Key_Equal
|
||||||
or key == Qt.Key_I
|
or
|
||||||
|
key == Qt.Key_I
|
||||||
)
|
)
|
||||||
):
|
):
|
||||||
view.wheelEvent(
|
view.wheelEvent(
|
||||||
|
|
@ -264,7 +297,8 @@ async def handle_viewmode_kb_inputs(
|
||||||
ctrl
|
ctrl
|
||||||
and (
|
and (
|
||||||
key == Qt.Key_Minus
|
key == Qt.Key_Minus
|
||||||
or key == Qt.Key_O
|
or
|
||||||
|
key == Qt.Key_O
|
||||||
)
|
)
|
||||||
):
|
):
|
||||||
view.wheelEvent(
|
view.wheelEvent(
|
||||||
|
|
@ -275,7 +309,8 @@ async def handle_viewmode_kb_inputs(
|
||||||
|
|
||||||
elif (
|
elif (
|
||||||
not ctrl
|
not ctrl
|
||||||
and key == Qt.Key_R
|
and
|
||||||
|
key == Qt.Key_R
|
||||||
):
|
):
|
||||||
# NOTE: seems that if we don't yield a Qt render
|
# NOTE: seems that if we don't yield a Qt render
|
||||||
# cycle then the m4 downsampled curves will show here
|
# cycle then the m4 downsampled curves will show here
|
||||||
|
|
@ -477,7 +512,8 @@ async def handle_viewmode_mouse(
|
||||||
# view.raiseContextMenu(event)
|
# view.raiseContextMenu(event)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
view.order_mode.active and
|
view.order_mode.active
|
||||||
|
and
|
||||||
button == QtCore.Qt.LeftButton
|
button == QtCore.Qt.LeftButton
|
||||||
):
|
):
|
||||||
# when in order mode, submit execution
|
# when in order mode, submit execution
|
||||||
|
|
@ -781,7 +817,8 @@ class ChartView(ViewBox):
|
||||||
|
|
||||||
# Scale or translate based on mouse button
|
# Scale or translate based on mouse button
|
||||||
if btn & (
|
if btn & (
|
||||||
QtCore.Qt.LeftButton | QtCore.Qt.MidButton
|
QtCore.Qt.LeftButton
|
||||||
|
| QtCore.Qt.MidButton
|
||||||
):
|
):
|
||||||
# zoom y-axis ONLY when click-n-drag on it
|
# zoom y-axis ONLY when click-n-drag on it
|
||||||
# if axis == 1:
|
# if axis == 1:
|
||||||
|
|
|
||||||
|
|
@ -51,10 +51,13 @@ from ._anchors import (
|
||||||
from ..calc import humanize
|
from ..calc import humanize
|
||||||
from ._label import Label
|
from ._label import Label
|
||||||
from ._style import hcolor, _font
|
from ._style import hcolor, _font
|
||||||
|
from ..log import get_logger
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from ._cursor import Cursor
|
from ._cursor import Cursor
|
||||||
|
|
||||||
|
log = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
# TODO: probably worth investigating if we can
|
# TODO: probably worth investigating if we can
|
||||||
# make .boundingRect() faster:
|
# make .boundingRect() faster:
|
||||||
|
|
@ -346,7 +349,7 @@ class LevelLine(pg.InfiniteLine):
|
||||||
|
|
||||||
) -> None:
|
) -> None:
|
||||||
# TODO: enter labels edit mode
|
# TODO: enter labels edit mode
|
||||||
print(f'double click {ev}')
|
log.debug(f'double click {ev}')
|
||||||
|
|
||||||
def paint(
|
def paint(
|
||||||
self,
|
self,
|
||||||
|
|
@ -460,10 +463,19 @@ class LevelLine(pg.InfiniteLine):
|
||||||
# hovered
|
# hovered
|
||||||
if (
|
if (
|
||||||
not ev.isExit()
|
not ev.isExit()
|
||||||
and ev.acceptDrags(QtCore.Qt.LeftButton)
|
and
|
||||||
|
ev.acceptDrags(QtCore.Qt.LeftButton)
|
||||||
):
|
):
|
||||||
# if already hovered we don't need to run again
|
# if already hovered we don't need to run again
|
||||||
if self.mouseHovering is True:
|
if (
|
||||||
|
self.mouseHovering is True
|
||||||
|
and
|
||||||
|
cur.is_hovered(self)
|
||||||
|
):
|
||||||
|
log.debug(
|
||||||
|
f'Already hovering ??\n'
|
||||||
|
f'cur._hovered: {cur._hovered!r}\n'
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.only_show_markers_on_hover:
|
if self.only_show_markers_on_hover:
|
||||||
|
|
@ -480,6 +492,7 @@ class LevelLine(pg.InfiniteLine):
|
||||||
cur._y_label_update = False
|
cur._y_label_update = False
|
||||||
|
|
||||||
# add us to cursor state
|
# add us to cursor state
|
||||||
|
log.debug(f'Adding line {self!r}\n')
|
||||||
cur.add_hovered(self)
|
cur.add_hovered(self)
|
||||||
|
|
||||||
if self._hide_xhair_on_hover:
|
if self._hide_xhair_on_hover:
|
||||||
|
|
@ -507,6 +520,7 @@ class LevelLine(pg.InfiniteLine):
|
||||||
|
|
||||||
self.currentPen = self.pen
|
self.currentPen = self.pen
|
||||||
|
|
||||||
|
log.debug(f'Removing line {self!r}\n')
|
||||||
cur._hovered.remove(self)
|
cur._hovered.remove(self)
|
||||||
|
|
||||||
if self.only_show_markers_on_hover:
|
if self.only_show_markers_on_hover:
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,6 @@ from ._style import _font
|
||||||
from ._forms import open_form_input_handling
|
from ._forms import open_form_input_handling
|
||||||
from ._notify import notify_from_ems_status_msg
|
from ._notify import notify_from_ems_status_msg
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from ._chart import (
|
from ._chart import (
|
||||||
ChartPlotWidget,
|
ChartPlotWidget,
|
||||||
|
|
@ -436,7 +435,7 @@ class OrderMode:
|
||||||
lines=lines,
|
lines=lines,
|
||||||
last_status_close=self.multistatus.open_status(
|
last_status_close=self.multistatus.open_status(
|
||||||
f'submitting {order.exec_mode}-{order.action}',
|
f'submitting {order.exec_mode}-{order.action}',
|
||||||
final_msg=f'submitted {order.exec_mode}-{order.action}',
|
# final_msg=f'submitted {order.exec_mode}-{order.action}',
|
||||||
clear_on_next=True,
|
clear_on_next=True,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -658,7 +657,7 @@ class OrderMode:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def cancel_orders_under_cursor(self) -> list[str]:
|
def cancel_orders_under_cursor(self) -> list[Dialog]:
|
||||||
return self.cancel_orders(
|
return self.cancel_orders(
|
||||||
self.oids_from_lines(
|
self.oids_from_lines(
|
||||||
self.lines.lines_under_cursor()
|
self.lines.lines_under_cursor()
|
||||||
|
|
@ -687,24 +686,28 @@ class OrderMode:
|
||||||
self,
|
self,
|
||||||
oids: list[str],
|
oids: list[str],
|
||||||
|
|
||||||
) -> None:
|
) -> list[Dialog]:
|
||||||
'''
|
'''
|
||||||
Cancel all orders from a list of order ids: `oids`.
|
Cancel all orders from a list of order ids: `oids`.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
key = self.multistatus.open_status(
|
# key = self.multistatus.open_status(
|
||||||
f'cancelling {len(oids)} orders',
|
# f'cancelling {len(oids)} orders',
|
||||||
final_msg=f'cancelled orders:\n{oids}',
|
# final_msg=f'cancelled orders:\n{oids}',
|
||||||
group_key=True
|
# group_key=True
|
||||||
)
|
# )
|
||||||
|
dialogs: list[Dialog] = []
|
||||||
for oid in oids:
|
for oid in oids:
|
||||||
if dialog := self.dialogs.get(oid):
|
if dialog := self.dialogs.get(oid):
|
||||||
self.client.cancel_nowait(uuid=oid)
|
self.client.cancel_nowait(uuid=oid)
|
||||||
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
|
||||||
|
dialogs.append(dialog)
|
||||||
|
|
||||||
|
return dialogs
|
||||||
|
|
||||||
def cancel_all_orders(self) -> None:
|
def cancel_all_orders(self) -> None:
|
||||||
'''
|
'''
|
||||||
|
|
@ -776,7 +779,6 @@ class OrderMode:
|
||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
async def open_order_mode(
|
async def open_order_mode(
|
||||||
|
|
||||||
feed: Feed,
|
feed: Feed,
|
||||||
godw: GodWidget,
|
godw: GodWidget,
|
||||||
fqme: str,
|
fqme: str,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue