Drop the open ctx mng; add wip pp label

fsp_feeds
Tyler Goodlet 2021-07-16 18:32:56 -04:00
parent 69091a894f
commit d21112dcd7
2 changed files with 97 additions and 60 deletions

View File

@ -65,7 +65,7 @@ from .. import data
from ..log import get_logger from ..log import get_logger
from ._exec import run_qtractor from ._exec import run_qtractor
from ._interaction import ChartView from ._interaction import ChartView
from .order_mode import start_order_mode from .order_mode import run_order_mode
from .. import fsp from .. import fsp
from ..data import feed from ..data import feed
@ -1574,7 +1574,7 @@ async def display_symbol_data(
linkedsplits linkedsplits
) )
await start_order_mode(chart, symbol, provider, order_mode_started) await run_order_mode(chart, symbol, provider, order_mode_started)
async def load_provider_search( async def load_provider_search(

View File

@ -18,23 +18,24 @@
Chart trading, the only way to scalp. Chart trading, the only way to scalp.
""" """
from contextlib import asynccontextmanager
from dataclasses import dataclass, field from dataclasses import dataclass, field
from pprint import pformat from pprint import pformat
import time import time
from typing import Optional, Dict, Callable, Any from typing import Optional, Dict, Callable, Any
import uuid import uuid
import pyqtgraph as pg
from pydantic import BaseModel from pydantic import BaseModel
import tractor
import trio import trio
from ._lines import LevelLine, position_line from ._anchors import marker_right_points
from ._editors import LineEditor, ArrowEditor
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
from ._editors import LineEditor, ArrowEditor
from ._label import Label
from ._lines import LevelLine, position_line
from ._window import MultiStatus, main_window
log = get_logger(__name__) log = get_logger(__name__)
@ -91,6 +92,10 @@ class OrderMode:
lines: LineEditor lines: LineEditor
arrows: ArrowEditor arrows: ArrowEditor
status_bar: MultiStatus status_bar: MultiStatus
# pp status info
label: Label
name: str = 'order' name: str = 'order'
_colors = { _colors = {
@ -381,50 +386,11 @@ class OrderMode:
) )
@asynccontextmanager async def run_order_mode(
async def open_order_mode(
symbol: Symbol,
chart: pg.PlotWidget,
book: OrderBook,
):
status_bar: MultiStatus = main_window().status_bar
view = chart._vb
lines = LineEditor(chart=chart)
arrows = ArrowEditor(chart, {})
log.info("Opening order mode")
mode = OrderMode(chart, book, lines, arrows, status_bar)
view.mode = mode
asset_type = symbol.type_key
if asset_type == 'stock':
mode._size = 100.0
elif asset_type in ('future', 'option', 'futures_option'):
mode._size = 1.0
else: # to be safe
mode._size = 1.0
try:
yield mode
finally:
# XXX special teardown handling like for ex.
# - cancelling orders if needed?
# - closing positions if desired?
# - switching special condition orders to safer/more reliable variants
log.info("Closing order mode")
async def start_order_mode(
chart: 'ChartPlotWidget', # noqa chart: 'ChartPlotWidget', # noqa
symbol: Symbol, symbol: Symbol,
brokername: str, brokername: str,
started: trio.Event, started: trio.Event,
) -> None: ) -> None:
@ -436,19 +402,90 @@ async def start_order_mode(
''' '''
done = chart.window().status_bar.open_status('starting order mode..') done = chart.window().status_bar.open_status('starting order mode..')
book: OrderBook
trades_stream: tractor.MsgStream
positions: dict
# spawn EMS actor-service # spawn EMS actor-service
async with ( async with (
open_ems(brokername, symbol) as (book, trades_stream, positions),
open_order_mode(symbol, chart, book) as order_mode, open_ems(brokername, symbol) as (
book,
trades_stream,
positions
),
# # start async input handling for chart's view # # start async input handling for chart's view
# # await godwidget._task_stack.enter_async_context( # # await godwidget._task_stack.enter_async_context(
# chart._vb.open_async_input_handler(), # chart._vb.open_async_input_handler(),
): ):
status_bar: MultiStatus = main_window().status_bar
view = chart._vb
lines = LineEditor(chart=chart)
arrows = ArrowEditor(chart, {})
log.info("Opening order mode")
pp_label = Label(
view=view,
color='default_light',
# this is "static" label
# update_on_range_change=False,
fmt_str='\n'.join((
'size: {entry_count}',
'% port: {percent_of_port}',
# '$val: {base_unit_value}',
)),
fields={
'entry_count': 0,
'percent_of_port': 0,
'base_unit_value': 0,
},
)
pp_label.render()
from PyQt5.QtCore import QPointF
# order line endpoint anchor
def bottom_marker_right() -> QPointF:
return QPointF(
marker_right_points(chart)[0] - pp_label.w,
view.height() - pp_label.h,
)
# TODO: position on botto if l1/book is on top side
pp_label.scene_anchor = bottom_marker_right
pp_label.hide()
mode = OrderMode(
chart,
book,
lines,
arrows,
status_bar,
label=pp_label,
)
view.mode = mode
asset_type = symbol.type_key
# default entry sizing
if asset_type == 'stock':
mode._size = 100.0
elif asset_type in ('future', 'option', 'futures_option'):
mode._size = 1.0
else: # to be safe
mode._size = 1.0
# update any exising positions # update any exising positions
for sym, msg in positions.items(): for sym, msg in positions.items():
order_mode.on_position_update(msg) mode.on_position_update(msg)
def get_index(time: float): def get_index(time: float):
@ -485,13 +522,13 @@ async def start_order_mode(
'position', 'position',
): ):
# show line label once order is live # show line label once order is live
order_mode.on_position_update(msg) mode.on_position_update(msg)
continue continue
resp = msg['resp'] resp = msg['resp']
oid = msg['oid'] oid = msg['oid']
dialog = order_mode.dialogs[oid] dialog = mode.dialogs[oid]
# record message to dialog tracking # record message to dialog tracking
dialog.msgs[oid] = msg dialog.msgs[oid] = msg
@ -502,7 +539,7 @@ async def start_order_mode(
): ):
# show line label once order is live # show line label once order is live
order_mode.on_submit(oid) mode.on_submit(oid)
# resp to 'cancel' request or error condition # resp to 'cancel' request or error condition
# for action request # for action request
@ -512,7 +549,7 @@ async def start_order_mode(
'dark_cancelled' 'dark_cancelled'
): ):
# delete level line from view # delete level line from view
order_mode.on_cancel(oid) mode.on_cancel(oid)
elif resp in ( elif resp in (
'dark_triggered' 'dark_triggered'
@ -524,23 +561,23 @@ async def start_order_mode(
): ):
# should only be one "fill" for an alert # should only be one "fill" for an alert
# add a triangle and remove the level line # add a triangle and remove the level line
order_mode.on_fill( mode.on_fill(
oid, oid,
price=msg['trigger_price'], price=msg['trigger_price'],
arrow_index=get_index(time.time()), arrow_index=get_index(time.time()),
) )
order_mode.lines.remove_line(uuid=oid) mode.lines.remove_line(uuid=oid)
await order_mode.on_exec(oid, msg) await mode.on_exec(oid, msg)
# response to completed 'action' request for buy/sell # response to completed 'action' request for buy/sell
elif resp in ( elif resp in (
'broker_executed', 'broker_executed',
): ):
# right now this is just triggering a system alert # right now this is just triggering a system alert
await order_mode.on_exec(oid, msg) await mode.on_exec(oid, msg)
if msg['brokerd_msg']['remaining'] == 0: if msg['brokerd_msg']['remaining'] == 0:
order_mode.lines.remove_line(uuid=oid) mode.lines.remove_line(uuid=oid)
# each clearing tick is responded individually # each clearing tick is responded individually
elif resp in ('broker_filled',): elif resp in ('broker_filled',):
@ -554,7 +591,7 @@ async def start_order_mode(
details = msg['brokerd_msg'] details = msg['brokerd_msg']
# TODO: some kinda progress system # TODO: some kinda progress system
order_mode.on_fill( mode.on_fill(
oid, oid,
price=details['price'], price=details['price'],
pointing='up' if action == 'buy' else 'down', pointing='up' if action == 'buy' else 'down',