Port to order pane apis

fsp_feeds
Tyler Goodlet 2021-08-23 14:48:20 -04:00
parent bc2f4186fd
commit 206af0d575
3 changed files with 93 additions and 70 deletions

View File

@ -44,6 +44,7 @@ import pydantic
from ._event import open_handlers
from ._style import hcolor, _font, _font_small, DpiAwareFont
from .. import brokers
class FontAndChartAwareLineEdit(QLineEdit):
@ -366,11 +367,15 @@ async def handle_field_input(
# process field input
if key in (Qt.Key_Enter, Qt.Key_Return):
value = widget.text()
key = widget._key
old = getattr(model, key)
try:
setattr(model, key, value)
except pydantic.error_wrappers.ValidationError:
setattr(model, key, old)
widget.setText(str(old))
@ -380,16 +385,14 @@ async def handle_field_input(
def mk_form(
model: pydantic.BaseModel,
parent: QWidget,
fields_schema: dict,
) -> FieldsForm:
form = FieldsForm(parent=parent)
# TODO: generate components from model
# instead of schema dict (aka use an ORM)
form.model = model
form = FieldsForm(parent=parent)
# generate sub-components from schema dict
for key, config in fields_schema.items():
@ -413,18 +416,6 @@ def mk_form(
values
)
def write_model(text: str, key: str):
print(f'{text}')
setattr(form.model, key, text)
print(form.model)
w.currentTextChanged.connect(
partial(
write_model,
key=key,
)
)
w._key = key
return form
@ -438,7 +429,7 @@ async def open_form_input_handling(
) -> FieldsForm:
assert form.model, f'{form} must define a `.model`'
# assert form.model, f'{form} must define a `.model`'
async with open_handlers(
@ -630,31 +621,27 @@ def mk_fill_status_bar(
slots = 4
bar.set_slots(slots, value=0)
return hbox, bar
return hbox, bar, left_label, top_label, bottom_label
def mk_order_pane_layout(
parent: QWidget,
# accounts: dict[str, Optional[str]],
font_size: int = _font_small.px_size - 2
) -> FieldsForm:
from ._position import mk_alloc
# TODO: some kinda pydantic sub-type
# that enforces a composite widget attr er sumthin..
# as part of our ORM thingers.
alloc = mk_alloc()
accounts = brokers.config.load_accounts()
# TODO: maybe just allocate the whole fields form here
# and expect an async ctx entry?
form = mk_form(
parent=parent,
model=alloc,
fields_schema={
'account': {
'type': 'select',
'default_value': alloc._accounts.keys()
'default_value': accounts.keys(),
},
'size_unit': {
'label': '**allocate**:',
@ -670,8 +657,8 @@ def mk_order_pane_layout(
'type': 'select',
'default_value': ['uniform'],
},
'size': {
'label': '**size**:',
'limit': {
'label': '**limit**:',
'type': 'edit',
'default_value': 5000,
},
@ -683,7 +670,6 @@ def mk_order_pane_layout(
},
)
form._font_size = font_size
alloc._widget = form
# top level pane layout
# XXX: see ``FieldsForm.__init__()`` for why we can't do basic
@ -693,8 +679,15 @@ def mk_order_pane_layout(
# _, h = form.width(), form.height()
# print(f'w, h: {w, h}')
hbox, fill_bar = mk_fill_status_bar(form, pane_vbox=vbox)
hbox, fill_bar, left_label, bottom_label, top_label = mk_fill_status_bar(
form, pane_vbox=vbox
)
# TODO: would be nice to have some better way of reffing these over
# monkey patching...
form.fill_bar = fill_bar
form.left_label = left_label
form.bottom_label = bottom_label
form.top_label = top_label
# add pp fill bar + spacing
vbox.addLayout(hbox, stretch=1/3)
@ -702,9 +695,9 @@ def mk_order_pane_layout(
feed_label = form.add_field_label(
dedent("""
brokerd.ib\n
|_@localhost:8509\n
|_consumers: 4\n
|_streams: 9\n
|_@{host}:{port}\n
|_consumers: {cons}\n
|_streams: {streams}\n
"""),
font_size=_font.px_size - 5,
)
@ -722,5 +715,4 @@ def mk_order_pane_layout(
vbox.setSpacing(36)
form.show()
return form

View File

@ -261,14 +261,16 @@ async def handle_viewmode_kb_inputs(
):
# hot key to set order slots size
num = int(text)
pp = order_mode.pp
pp_pane = pp.pane
pp_pane.model.slots = num
edit = pp_pane.fields['slots']
pp_pane = order_mode.pane
pp_pane.alloc.slots = num
edit = pp_pane.form.fields['slots']
edit.setText(text)
edit.selectAll()
on_next_release = edit.deselect
pp.init_status_ui()
pp_pane.init_status_ui()
else: # none active

View File

@ -19,6 +19,7 @@ Chart trading, the only way to scalp.
"""
from dataclasses import dataclass, field
from functools import partial
from pprint import pformat
import time
from typing import Optional, Dict, Callable, Any
@ -28,15 +29,16 @@ from pydantic import BaseModel
import tractor
import trio
from .. import brokers
from ..clearing._client import open_ems, OrderBook
from ..data._source import Symbol
from ..log import get_logger
from ._editors import LineEditor, ArrowEditor
from ._lines import order_line, LevelLine
from ._position import PositionTracker
from ._position import PositionTracker, OrderModePane, mk_alloc
from ._window import MultiStatus
from ..clearing._messages import Order
# from ._forms import FieldsForm
from ._forms import open_form_input_handling
log = get_logger(__name__)
@ -88,6 +90,8 @@ class OrderMode:
multistatus: MultiStatus
pp: PositionTracker
allocator: 'Allocator' # noqa
pane: OrderModePane
active: bool = False
name: str = 'order'
@ -127,31 +131,16 @@ class OrderMode:
) else False,
**line_kwargs,
)
# define a callback applied for each level change to the line
# which will recompute the order size based on allocator
# settings:
def update_from_size_calc(y: float) -> None:
order_info = self.allocator.get_order_info(
symbol=symbol,
price=y,
action=order.action,
)
line.update_labels(order_info)
order.price = y
order.size = order_info['size']
# return is used to update labels implicitly
return order_info
update_from_size_calc(order.price)
# set level update cb
# line._on_level_change = partial(update_from_size_calc, order=order)
line._on_level_change = update_from_size_calc
# set level update callback to order pane method and update once
# immediately
line._on_level_change = partial(
self.pane.on_level_change_update_next_order_info,
line=line,
order=order,
)
line._on_level_change(order.price)
return line
@ -493,16 +482,52 @@ async def run_order_mode(
),
):
log.info(f'Opening order mode for {brokername}.{symbol.key}')
view = chart.view
# annotations editors
lines = LineEditor(chart=chart)
arrows = ArrowEditor(chart, {})
log.info("Opening order mode")
# allocator
alloc = mk_alloc(
symbol=symbol,
accounts=brokers.config.load_accounts()
)
# form = chart.linked.godwidget.pp_pane.model
form = chart.sidepane
form.model = alloc
alloc = chart.linked.godwidget.pp_pane.model
pp_tracker = PositionTracker(chart, alloc=alloc)
pp_tracker.hide()
alloc._position = pp_tracker
# order pane widgets and allocation model
order_pane = OrderModePane(
tracker=pp_tracker,
form=form,
alloc=alloc,
fill_bar=form.fill_bar,
pnl_label=form.left_label,
step_label=form.bottom_label,
limit_label=form.top_label,
)
for key in ('account', 'size_unit', 'disti_weight'):
w = form.fields[key]
def write_model(text: str, key: str):
print(f'{text}')
setattr(alloc, key, text)
print(alloc)
w.currentTextChanged.connect(
partial(
write_model,
key=key,
)
)
mode = OrderMode(
chart,
@ -512,6 +537,7 @@ async def run_order_mode(
multistatus,
pp_tracker,
allocator=alloc,
pane=order_pane,
)
# TODO: create a mode "manager" of sorts?
@ -529,7 +555,6 @@ async def run_order_mode(
pp_tracker.update(msg, position=pp_tracker.startup_pp)
pp_tracker.update(msg)
# default entry sizing
if asset_type in ('stock', 'crypto', 'forex'):
alloc.size_unit = '$ size'
@ -544,11 +569,11 @@ async def run_order_mode(
pp_tracker.pane.fields['slots'].setText(str(alloc.slots))
# make entry step 1.0
alloc.size = slots
pp_tracker.pane.fields['size'].setText(str(alloc.size))
alloc.units_size = slots
pp_tracker.pane.fields['size'].setText(str(alloc.units_size))
# make fill bar and positioning snapshot
pp_tracker.init_status_ui()
order_pane.init_status_ui()
# TODO: this should go onto some sort of
# data-view strimg thinger..right?
@ -572,7 +597,11 @@ async def run_order_mode(
async with (
chart.view.open_async_input_handler(),
# TODO: config form handler nursery
# pp pane kb inputs
open_form_input_handling(
form,
focus_next=chart.linked.godwidget,
),
):