Add mouse drag order update support to UI
parent
6851bacd0a
commit
de5a69c59c
|
@ -244,10 +244,13 @@ class LineEditor:
|
||||||
|
|
||||||
symbol = chart._lc.symbol
|
symbol = chart._lc.symbol
|
||||||
|
|
||||||
line = self._stage_line
|
# line = self._stage_line
|
||||||
if not line:
|
# if not line:
|
||||||
# add a "staged" cursor-tracking line to view
|
# add a "staged" cursor-tracking line to view
|
||||||
# and cash it in a a var
|
# and cash it in a a var
|
||||||
|
if self._active_staged_line:
|
||||||
|
self.unstage_line()
|
||||||
|
|
||||||
line = order_line(
|
line = order_line(
|
||||||
chart,
|
chart,
|
||||||
|
|
||||||
|
@ -271,38 +274,36 @@ class LineEditor:
|
||||||
# line.label._use_extra_fields = size is not None
|
# line.label._use_extra_fields = size is not None
|
||||||
|
|
||||||
# cache staging line after creation
|
# cache staging line after creation
|
||||||
self._stage_line = line
|
# self._stage_line = line
|
||||||
|
|
||||||
else:
|
# else:
|
||||||
# apply input settings to existing staging line
|
# # apply input settings to existing staging line
|
||||||
# label = line.label
|
# # label = line.label
|
||||||
|
|
||||||
# disable order size and other extras in label
|
# # disable order size and other extras in label
|
||||||
# label._use_extra_fields = size is not None
|
# # label._use_extra_fields = size is not None
|
||||||
# label.size = size
|
# # label.size = size
|
||||||
|
|
||||||
# label.color = color
|
# # label.color = color
|
||||||
|
|
||||||
# Use the existing staged line instead but copy
|
# # Use the existing staged line instead but copy
|
||||||
# over it's current style "properties".
|
# # over it's current style "properties".
|
||||||
# Saves us allocating more mem / objects repeatedly
|
# # Saves us allocating more mem / objects repeatedly
|
||||||
line._hoh = hl_on_hover
|
# line._hoh = hl_on_hover
|
||||||
line._dotted = dotted
|
# line._dotted = dotted
|
||||||
line.color = color
|
# line.color = color
|
||||||
line.setMouseHover(hl_on_hover)
|
# line.setMouseHover(hl_on_hover)
|
||||||
line.show()
|
# line.show()
|
||||||
line.show_labels()
|
# line.show_labels()
|
||||||
|
|
||||||
# XXX: must have this to trigger updated
|
# # XXX: must have this to trigger updated
|
||||||
# label contents rendering
|
# # label contents rendering
|
||||||
line.set_level(level=y)
|
# line.set_level(level=y)
|
||||||
|
|
||||||
self._active_staged_line = line
|
self._active_staged_line = line
|
||||||
|
|
||||||
# hide crosshair y-line and label
|
# hide crosshair y-line and label
|
||||||
cg = cursor.graphics[chart]
|
cursor.hide_xhair()
|
||||||
cg['hl'].hide()
|
|
||||||
cg['yl'].hide()
|
|
||||||
|
|
||||||
# add line to cursor trackers
|
# add line to cursor trackers
|
||||||
cursor._trackers.add(line)
|
cursor._trackers.add(line)
|
||||||
|
@ -313,45 +314,45 @@ class LineEditor:
|
||||||
"""Inverse of ``.stage_line()``.
|
"""Inverse of ``.stage_line()``.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
chart = self.chart._cursor.active_plot
|
# chart = self.chart._cursor.active_plot
|
||||||
chart.setCursor(QtCore.Qt.ArrowCursor)
|
# # chart.setCursor(QtCore.Qt.ArrowCursor)
|
||||||
cursor = chart._cursor
|
cursor = self.chart._cursor
|
||||||
|
|
||||||
# delete "staged" cursor tracking line from view
|
# delete "staged" cursor tracking line from view
|
||||||
line = self._active_staged_line
|
line = self._active_staged_line
|
||||||
if line:
|
if line:
|
||||||
cursor._trackers.remove(line)
|
cursor._trackers.remove(line)
|
||||||
|
line.delete()
|
||||||
|
|
||||||
self._active_staged_line = None
|
self._active_staged_line = None
|
||||||
|
|
||||||
sl = self._stage_line
|
# sl = self._stage_line
|
||||||
if sl:
|
# if sl:
|
||||||
sl.hide()
|
# sl.hide()
|
||||||
sl.hide_labels()
|
# sl.hide_labels()
|
||||||
|
|
||||||
# show the crosshair y line and label
|
# show the crosshair y line and label
|
||||||
cg = cursor.graphics[chart]
|
cursor.show_xhair()
|
||||||
cg['hl'].show()
|
|
||||||
cg['yl'].show()
|
|
||||||
|
|
||||||
def create_order_line(
|
def create_order_line(
|
||||||
self,
|
self,
|
||||||
uuid: str,
|
uuid: str,
|
||||||
|
level: float,
|
||||||
|
chart: 'ChartPlotWidget', # noqa
|
||||||
size: float,
|
size: float,
|
||||||
) -> LevelLine:
|
) -> LevelLine:
|
||||||
|
|
||||||
line = self._active_staged_line
|
line = self._active_staged_line
|
||||||
if not line:
|
if not line:
|
||||||
raise RuntimeError("No line commit is currently staged!?")
|
raise RuntimeError("No line is currently staged!?")
|
||||||
|
|
||||||
chart = self.chart._cursor.active_plot
|
|
||||||
y = chart._cursor._datum_xy[1]
|
|
||||||
sym = chart._lc.symbol
|
sym = chart._lc.symbol
|
||||||
|
|
||||||
line = order_line(
|
line = order_line(
|
||||||
chart,
|
chart,
|
||||||
|
|
||||||
# label fields default values
|
# label fields default values
|
||||||
level=y,
|
level=level,
|
||||||
level_digits=sym.digits(),
|
level_digits=sym.digits(),
|
||||||
|
|
||||||
size=size,
|
size=size,
|
||||||
|
@ -361,12 +362,14 @@ class LineEditor:
|
||||||
color=line.color,
|
color=line.color,
|
||||||
dotted=line._dotted,
|
dotted=line._dotted,
|
||||||
)
|
)
|
||||||
|
|
||||||
# for now, until submission reponse arrives
|
# for now, until submission reponse arrives
|
||||||
line.hide_labels()
|
line.hide_labels()
|
||||||
|
|
||||||
# register for later lookup/deletion
|
# register for later lookup/deletion
|
||||||
self._order_lines[uuid] = line
|
self._order_lines[uuid] = line
|
||||||
return line, y
|
|
||||||
|
return line
|
||||||
|
|
||||||
def commit_line(self, uuid: str) -> LevelLine:
|
def commit_line(self, uuid: str) -> LevelLine:
|
||||||
"""Commit a "staged line" to view.
|
"""Commit a "staged line" to view.
|
||||||
|
@ -375,16 +378,14 @@ class LineEditor:
|
||||||
graphic in view.
|
graphic in view.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if uuid is None:
|
|
||||||
breakpoint()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
line = self._order_lines[uuid]
|
line = self._order_lines[uuid]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
log.warning(f'No line for {uuid} could be found?')
|
log.warning(f'No line for {uuid} could be found?')
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
line.oid = uuid
|
assert line.oid == uuid
|
||||||
|
# line.oid = uuid
|
||||||
# line.set_level(line.level)
|
# line.set_level(line.level)
|
||||||
line.show_labels()
|
line.show_labels()
|
||||||
# line.label.show()
|
# line.label.show()
|
||||||
|
@ -448,7 +449,7 @@ class ArrowEditor:
|
||||||
angle = {
|
angle = {
|
||||||
'up': 90,
|
'up': 90,
|
||||||
'down': -90,
|
'down': -90,
|
||||||
None: 180, # pointing to right
|
None: 180, # pointing to right (as in an alert)
|
||||||
}[pointing]
|
}[pointing]
|
||||||
|
|
||||||
arrow = pg.ArrowItem(
|
arrow = pg.ArrowItem(
|
||||||
|
@ -480,6 +481,11 @@ class ArrowEditor:
|
||||||
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"
|
||||||
|
(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.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
chart: 'ChartPlotWidget' # type: ignore # noqa
|
chart: 'ChartPlotWidget' # type: ignore # noqa
|
||||||
book: OrderBook
|
book: OrderBook
|
||||||
|
@ -581,6 +587,7 @@ class OrderMode:
|
||||||
msg = self.book._sent_orders.pop(uuid, None)
|
msg = self.book._sent_orders.pop(uuid, None)
|
||||||
if msg is not None:
|
if msg is not None:
|
||||||
self.lines.remove_line(uuid=uuid)
|
self.lines.remove_line(uuid=uuid)
|
||||||
|
self.chart._cursor.show_xhair()
|
||||||
else:
|
else:
|
||||||
log.warning(
|
log.warning(
|
||||||
f'Received cancel for unsubmitted order {pformat(msg)}'
|
f'Received cancel for unsubmitted order {pformat(msg)}'
|
||||||
|
@ -601,24 +608,61 @@ class OrderMode:
|
||||||
|
|
||||||
size = size or self._size
|
size = size or self._size
|
||||||
|
|
||||||
# make line graphic
|
chart = self.chart._cursor.active_plot
|
||||||
line, y = self.lines.create_order_line(
|
y = chart._cursor._datum_xy[1]
|
||||||
uid,
|
|
||||||
size=size,
|
symbol = self.chart._lc._symbol
|
||||||
)
|
|
||||||
line.oid = uid
|
|
||||||
|
|
||||||
# send order cmd to ems
|
# send order cmd to ems
|
||||||
self.book.send(
|
self.book.send(
|
||||||
uuid=uid,
|
uuid=uid,
|
||||||
symbol=self.chart._lc._symbol,
|
symbol=symbol.key,
|
||||||
|
brokers=symbol.brokers,
|
||||||
price=y,
|
price=y,
|
||||||
size=size,
|
size=size,
|
||||||
action=self._action,
|
action=self._action,
|
||||||
exec_mode=self._exec_mode,
|
exec_mode=self._exec_mode,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# make line graphic if order push was
|
||||||
|
# sucessful
|
||||||
|
line = self.lines.create_order_line(
|
||||||
|
uid,
|
||||||
|
level=y,
|
||||||
|
chart=chart,
|
||||||
|
size=size,
|
||||||
|
)
|
||||||
|
line.oid = uid
|
||||||
|
|
||||||
|
# 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
|
return line
|
||||||
|
|
||||||
|
def cancel_order_under_cursor(self) -> None:
|
||||||
|
for line in self.lines.lines_under_cursor():
|
||||||
|
self.book.cancel(uuid=line.oid)
|
||||||
|
|
||||||
|
# order-line modify handlers
|
||||||
|
def order_line_modify_start(
|
||||||
|
self,
|
||||||
|
line: LevelLine,
|
||||||
|
) -> None:
|
||||||
|
print(f'Line modify: {line}')
|
||||||
|
# cancel original order until new position is found
|
||||||
|
|
||||||
|
def order_line_modify_complete(
|
||||||
|
self,
|
||||||
|
line: LevelLine,
|
||||||
|
) -> None:
|
||||||
|
self.book.update(
|
||||||
|
uuid=line.oid,
|
||||||
|
|
||||||
|
# TODO: should we round this to a nearest tick here?
|
||||||
|
price=line.value(),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
async def open_order_mode(
|
async def open_order_mode(
|
||||||
|
@ -943,7 +987,7 @@ class ChartView(ViewBox):
|
||||||
self.select_box.clear()
|
self.select_box.clear()
|
||||||
|
|
||||||
# cancel order or clear graphics
|
# cancel order or clear graphics
|
||||||
if key == QtCore.Qt.Key_C:
|
if key == QtCore.Qt.Key_C or key == QtCore.Qt.Key_Delete:
|
||||||
# delete any lines under the cursor
|
# delete any lines under the cursor
|
||||||
mode = self.mode
|
mode = self.mode
|
||||||
for line in mode.lines.lines_under_cursor():
|
for line in mode.lines.lines_under_cursor():
|
||||||
|
@ -966,14 +1010,6 @@ class ChartView(ViewBox):
|
||||||
elif key == QtCore.Qt.Key_A:
|
elif key == QtCore.Qt.Key_A:
|
||||||
self.mode.set_exec('alert')
|
self.mode.set_exec('alert')
|
||||||
|
|
||||||
# delete orders under cursor
|
|
||||||
elif key == QtCore.Qt.Key_Delete:
|
|
||||||
|
|
||||||
# delete any lines under the cursor
|
|
||||||
mode = self.mode
|
|
||||||
for line in mode.lines.lines_under_cursor():
|
|
||||||
mode.book.cancel(uuid=line.oid)
|
|
||||||
|
|
||||||
# XXX: Leaving this for light reference purposes, there
|
# XXX: Leaving this for light reference purposes, there
|
||||||
# seems to be some work to at least gawk at for history mgmt.
|
# seems to be some work to at least gawk at for history mgmt.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue