Start input handling **after** order mode is up
parent
29d3ad59dc
commit
8dd5bbf4fa
|
@ -158,18 +158,20 @@ class GodWidget(QtGui.QWidget):
|
|||
# self.toolbar_layout.addWidget(self.strategy_box)
|
||||
|
||||
def load_symbol(
|
||||
|
||||
self,
|
||||
providername: str,
|
||||
symbol_key: str,
|
||||
loglevel: str,
|
||||
ohlc: bool = True,
|
||||
reset: bool = False,
|
||||
) -> None:
|
||||
"""Load a new contract into the charting app.
|
||||
|
||||
) -> trio.Event:
|
||||
'''Load a new contract into the charting app.
|
||||
|
||||
Expects a ``numpy`` structured array containing all the ohlcv fields.
|
||||
|
||||
"""
|
||||
'''
|
||||
# our symbol key style is always lower case
|
||||
symbol_key = symbol_key.lower()
|
||||
|
||||
|
@ -178,6 +180,8 @@ class GodWidget(QtGui.QWidget):
|
|||
|
||||
linkedsplits = self.get_chart_symbol(fqsn)
|
||||
|
||||
order_mode_started = trio.Event()
|
||||
|
||||
if not self.vbox.isEmpty():
|
||||
# XXX: this is CRITICAL especially with pixel buffer caching
|
||||
self.linkedsplits.hide()
|
||||
|
@ -200,10 +204,15 @@ class GodWidget(QtGui.QWidget):
|
|||
providername,
|
||||
symbol_key,
|
||||
loglevel,
|
||||
order_mode_started,
|
||||
)
|
||||
|
||||
self.set_chart_symbol(fqsn, linkedsplits)
|
||||
|
||||
else:
|
||||
# symbol is already loaded and ems ready
|
||||
order_mode_started.set()
|
||||
|
||||
self.vbox.addWidget(linkedsplits)
|
||||
|
||||
# chart is already in memory so just focus it
|
||||
|
@ -223,6 +232,8 @@ class GodWidget(QtGui.QWidget):
|
|||
f'tick:{symbol.tick_size}'
|
||||
)
|
||||
|
||||
return order_mode_started
|
||||
|
||||
|
||||
class LinkedSplits(QtGui.QWidget):
|
||||
'''
|
||||
|
@ -1527,6 +1538,8 @@ async def display_symbol_data(
|
|||
sym: str,
|
||||
loglevel: str,
|
||||
|
||||
order_mode_started: trio.Event,
|
||||
|
||||
) -> None:
|
||||
'''Spawn a real-time displayed and updated chart for provider symbol.
|
||||
|
||||
|
@ -1623,7 +1636,6 @@ async def display_symbol_data(
|
|||
},
|
||||
})
|
||||
|
||||
|
||||
# load initial fsp chain (otherwise known as "indicators")
|
||||
n.start_soon(
|
||||
spawn_fsps,
|
||||
|
@ -1644,6 +1656,7 @@ async def display_symbol_data(
|
|||
wap_in_history,
|
||||
)
|
||||
|
||||
# TODO: instead we should start based on instrument trading hours?
|
||||
# wait for a first quote before we start any update tasks
|
||||
# quote = await feed.receive()
|
||||
# log.info(f'Received first quote {quote}')
|
||||
|
@ -1651,24 +1664,11 @@ async def display_symbol_data(
|
|||
n.start_soon(
|
||||
check_for_new_bars,
|
||||
feed,
|
||||
# delay,
|
||||
ohlcv,
|
||||
linkedsplits
|
||||
)
|
||||
|
||||
# interactive testing
|
||||
# n.start_soon(
|
||||
# test_bed,
|
||||
# ohlcv,
|
||||
# chart,
|
||||
# linkedsplits,
|
||||
# )
|
||||
|
||||
# start async input handling for chart's view
|
||||
# await godwidget._task_stack.enter_async_context(
|
||||
async with chart._vb.open_async_input_handler():
|
||||
|
||||
await start_order_mode(chart, symbol, provider)
|
||||
await start_order_mode(chart, symbol, provider, order_mode_started)
|
||||
|
||||
|
||||
async def load_providers(
|
||||
|
@ -1773,7 +1773,7 @@ async def _async_main(
|
|||
symbol, _, provider = sym.rpartition('.')
|
||||
|
||||
# this internally starts a ``display_symbol_data()`` task above
|
||||
godwidget.load_symbol(provider, symbol, loglevel)
|
||||
order_mode_ready = godwidget.load_symbol(provider, symbol, loglevel)
|
||||
|
||||
# spin up a search engine for the local cached symbol set
|
||||
async with _search.register_symbol_search(
|
||||
|
@ -1791,6 +1791,8 @@ async def _async_main(
|
|||
# the chart's select cache
|
||||
root_n.start_soon(load_providers, brokernames, loglevel)
|
||||
|
||||
await order_mode_ready.wait()
|
||||
|
||||
# start handling search bar kb inputs
|
||||
async with (
|
||||
|
||||
|
|
|
@ -26,8 +26,9 @@ from typing import Optional, Dict, Callable, Any
|
|||
import uuid
|
||||
|
||||
import pyqtgraph as pg
|
||||
import trio
|
||||
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
|
||||
|
@ -108,6 +109,10 @@ class OrderMode:
|
|||
"""Set execution mode.
|
||||
|
||||
"""
|
||||
# not initialized yet
|
||||
if not self.chart._cursor:
|
||||
return
|
||||
|
||||
self._action = action
|
||||
self.lines.stage_line(
|
||||
|
||||
|
@ -306,10 +311,14 @@ async def open_order_mode(
|
|||
|
||||
|
||||
async def start_order_mode(
|
||||
|
||||
chart: 'ChartPlotWidget', # noqa
|
||||
symbol: Symbol,
|
||||
brokername: str,
|
||||
|
||||
# task_status: TaskStatus[trio.Event] = trio.TASK_STATUS_IGNORED,
|
||||
started: trio.Event,
|
||||
|
||||
) -> None:
|
||||
'''Activate chart-trader order mode loop:
|
||||
- connect to emsd
|
||||
|
@ -322,7 +331,11 @@ async def start_order_mode(
|
|||
# spawn EMS actor-service
|
||||
async with (
|
||||
open_ems(brokername, symbol) as (book, trades_stream, positions),
|
||||
open_order_mode(symbol, chart, book) as order_mode
|
||||
open_order_mode(symbol, chart, book) as order_mode,
|
||||
|
||||
# # start async input handling for chart's view
|
||||
# # await godwidget._task_stack.enter_async_context(
|
||||
# chart._vb.open_async_input_handler(),
|
||||
):
|
||||
|
||||
# update any exising positions
|
||||
|
@ -345,83 +358,90 @@ async def start_order_mode(
|
|||
# Begin order-response streaming
|
||||
done()
|
||||
|
||||
# this is where we receive **back** messages
|
||||
# about executions **from** the EMS actor
|
||||
async for msg in trades_stream:
|
||||
# start async input handling for chart's view
|
||||
async with chart._vb.open_async_input_handler():
|
||||
|
||||
fmsg = pformat(msg)
|
||||
log.info(f'Received order msg:\n{fmsg}')
|
||||
# signal to top level symbol loading task we're ready
|
||||
# to handle input since the ems connection is ready
|
||||
started.set()
|
||||
|
||||
name = msg['name']
|
||||
if name in (
|
||||
'position',
|
||||
):
|
||||
# show line label once order is live
|
||||
order_mode.on_position_update(msg)
|
||||
continue
|
||||
# this is where we receive **back** messages
|
||||
# about executions **from** the EMS actor
|
||||
async for msg in trades_stream:
|
||||
|
||||
resp = msg['resp']
|
||||
oid = msg['oid']
|
||||
fmsg = pformat(msg)
|
||||
log.info(f'Received order msg:\n{fmsg}')
|
||||
|
||||
# response to 'action' request (buy/sell)
|
||||
if resp in (
|
||||
'dark_submitted',
|
||||
'broker_submitted'
|
||||
):
|
||||
|
||||
# show line label once order is live
|
||||
order_mode.on_submit(oid)
|
||||
|
||||
# resp to 'cancel' request or error condition
|
||||
# for action request
|
||||
elif resp in (
|
||||
'broker_cancelled',
|
||||
'broker_inactive',
|
||||
'dark_cancelled'
|
||||
):
|
||||
# delete level line from view
|
||||
order_mode.on_cancel(oid)
|
||||
|
||||
elif resp in (
|
||||
'dark_triggered'
|
||||
):
|
||||
log.info(f'Dark order triggered for {fmsg}')
|
||||
|
||||
elif resp in (
|
||||
'alert_triggered'
|
||||
):
|
||||
# should only be one "fill" for an alert
|
||||
# add a triangle and remove the level line
|
||||
order_mode.on_fill(
|
||||
oid,
|
||||
price=msg['trigger_price'],
|
||||
arrow_index=get_index(time.time())
|
||||
)
|
||||
await order_mode.on_exec(oid, msg)
|
||||
|
||||
# response to completed 'action' request for buy/sell
|
||||
elif resp in (
|
||||
'broker_executed',
|
||||
):
|
||||
await order_mode.on_exec(oid, msg)
|
||||
|
||||
# each clearing tick is responded individually
|
||||
elif resp in ('broker_filled',):
|
||||
|
||||
known_order = book._sent_orders.get(oid)
|
||||
if not known_order:
|
||||
log.warning(f'order {oid} is unknown')
|
||||
name = msg['name']
|
||||
if name in (
|
||||
'position',
|
||||
):
|
||||
# show line label once order is live
|
||||
order_mode.on_position_update(msg)
|
||||
continue
|
||||
|
||||
action = known_order.action
|
||||
details = msg['brokerd_msg']
|
||||
resp = msg['resp']
|
||||
oid = msg['oid']
|
||||
|
||||
# TODO: some kinda progress system
|
||||
order_mode.on_fill(
|
||||
oid,
|
||||
price=details['price'],
|
||||
pointing='up' if action == 'buy' else 'down',
|
||||
# response to 'action' request (buy/sell)
|
||||
if resp in (
|
||||
'dark_submitted',
|
||||
'broker_submitted'
|
||||
):
|
||||
|
||||
# TODO: put the actual exchange timestamp
|
||||
arrow_index=get_index(details['broker_time']),
|
||||
)
|
||||
# show line label once order is live
|
||||
order_mode.on_submit(oid)
|
||||
|
||||
# resp to 'cancel' request or error condition
|
||||
# for action request
|
||||
elif resp in (
|
||||
'broker_cancelled',
|
||||
'broker_inactive',
|
||||
'dark_cancelled'
|
||||
):
|
||||
# delete level line from view
|
||||
order_mode.on_cancel(oid)
|
||||
|
||||
elif resp in (
|
||||
'dark_triggered'
|
||||
):
|
||||
log.info(f'Dark order triggered for {fmsg}')
|
||||
|
||||
elif resp in (
|
||||
'alert_triggered'
|
||||
):
|
||||
# should only be one "fill" for an alert
|
||||
# add a triangle and remove the level line
|
||||
order_mode.on_fill(
|
||||
oid,
|
||||
price=msg['trigger_price'],
|
||||
arrow_index=get_index(time.time())
|
||||
)
|
||||
await order_mode.on_exec(oid, msg)
|
||||
|
||||
# response to completed 'action' request for buy/sell
|
||||
elif resp in (
|
||||
'broker_executed',
|
||||
):
|
||||
await order_mode.on_exec(oid, msg)
|
||||
|
||||
# each clearing tick is responded individually
|
||||
elif resp in ('broker_filled',):
|
||||
|
||||
known_order = book._sent_orders.get(oid)
|
||||
if not known_order:
|
||||
log.warning(f'order {oid} is unknown')
|
||||
continue
|
||||
|
||||
action = known_order.action
|
||||
details = msg['brokerd_msg']
|
||||
|
||||
# TODO: some kinda progress system
|
||||
order_mode.on_fill(
|
||||
oid,
|
||||
price=details['price'],
|
||||
pointing='up' if action == 'buy' else 'down',
|
||||
|
||||
# TODO: put the actual exchange timestamp
|
||||
arrow_index=get_index(details['broker_time']),
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue