From 1b577eebf6f97e4e38411513aebd587fb9121ee6 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Wed, 24 May 2023 15:30:17 -0400 Subject: [PATCH] Change over the UI layer to use `MktPair` Including changing to `LinkedSplits.mkt: MktPair` and adding an explicit setter method for setting it and being sure that nothing breaks in the display system init! For this commit we leave in warning access to `LinkedSplits.symbol` but will remove in following commit. --- piker/data/feed.py | 2 +- piker/ui/_chart.py | 38 ++++++++++++++++++++---------- piker/ui/_cursor.py | 4 ++-- piker/ui/_dataviz.py | 51 +++++++++++++++++++++++------------------ piker/ui/_display.py | 37 ++++++++++++++++-------------- piker/ui/_fsp.py | 9 ++++---- piker/ui/_position.py | 15 +++++++----- piker/ui/_signalling.py | 5 +++- piker/ui/order_mode.py | 45 +++++++++++++++++++----------------- 9 files changed, 120 insertions(+), 86 deletions(-) diff --git a/piker/data/feed.py b/piker/data/feed.py index 88d2a386..1714cf19 100644 --- a/piker/data/feed.py +++ b/piker/data/feed.py @@ -907,7 +907,7 @@ async def open_feed( for fqme, flume_msg in flumes_msg_dict.items(): flume = Flume.from_msg(flume_msg) - # assert flume.symbol.fqme == fqme + # assert flume.mkt.fqme == fqme feed.flumes[fqme] = flume # TODO: do we need this? diff --git a/piker/ui/_chart.py b/piker/ui/_chart.py index 13ec23c3..b2da3fa2 100644 --- a/piker/ui/_chart.py +++ b/piker/ui/_chart.py @@ -68,7 +68,10 @@ from ..data.feed import ( Feed, Flume, ) -from ..accounting._mktinfo import Symbol +from ..accounting import ( + MktPair, + Symbol, +) from ..log import get_logger from ._interaction import ChartView from ._forms import FieldsForm @@ -287,7 +290,7 @@ class GodWidget(QWidget): pp_nav.hide() # set window titlebar info - symbol = self.rt_linked.symbol + symbol = self.rt_linked.mkt if symbol is not None: self.window.setWindowTitle( f'{symbol.fqme} ' @@ -452,7 +455,7 @@ class LinkedSplits(QWidget): # update the UI for a given "chart instance". self.display_state: DisplayState | None = None - self._symbol: Symbol = None + self._mkt: MktPair | Symbol = None def on_splitter_adjust( self, @@ -474,9 +477,20 @@ class LinkedSplits(QWidget): **kwargs, ) + def set_mkt_info( + self, + mkt: MktPair, + ) -> None: + self._mkt = mkt + @property - def symbol(self) -> Symbol: - return self._symbol + def mkt(self) -> MktPair: + return self._mkt + + @property + def symbol(self) -> Symbol | MktPair: + log.warning(f'{type(self)}.symbol is now deprecated use .mkt!') + return self.mkt def set_split_sizes( self, @@ -521,7 +535,7 @@ class LinkedSplits(QWidget): def plot_ohlc_main( self, - symbol: Symbol, + mkt: MktPair, shm: ShmArray, flume: Flume, sidepane: FieldsForm, @@ -540,7 +554,7 @@ class LinkedSplits(QWidget): # add crosshairs self.cursor = Cursor( linkedsplits=self, - digits=symbol.tick_size_digits, + digits=mkt.price_tick_digits, ) # NOTE: atm the first (and only) OHLC price chart for the symbol @@ -548,7 +562,7 @@ class LinkedSplits(QWidget): # be no distinction since we will have multiple symbols per # view as part of "aggregate feeds". self.chart = self.add_plot( - name=symbol.fqme, + name=mkt.fqme, shm=shm, flume=flume, style=style, @@ -1030,7 +1044,7 @@ class ChartPlotWidget(pg.PlotWidget): ''' view = vb or self.view viz = self.main_viz - l, r = viz.view_range() + left, right = viz.view_range() x_shift = viz.index_step() * datums if datums >= 300: @@ -1040,8 +1054,8 @@ class ChartPlotWidget(pg.PlotWidget): # should trigger broadcast on all overlays right? view.setXRange( - min=l + x_shift, - max=r + x_shift, + min=left + x_shift, + max=right + x_shift, # TODO: holy shit, wtf dude... why tf would this not be 0 by # default... speechless. @@ -1227,7 +1241,7 @@ class ChartPlotWidget(pg.PlotWidget): # if the sticky is for our symbol # use the tick size precision for display name = name or pi.name - sym = self.linked.symbol + sym = self.linked.mkt digits = None if name == sym.key: digits = sym.tick_size_digits diff --git a/piker/ui/_cursor.py b/piker/ui/_cursor.py index 83986762..0a2c82b1 100644 --- a/piker/ui/_cursor.py +++ b/piker/ui/_cursor.py @@ -228,7 +228,7 @@ class ContentsLabel(pg.LabelItem): 'bar_wap', ] ], - name=name, + # name=name, index=ix, ) ) @@ -363,7 +363,7 @@ class Cursor(pg.GraphicsObject): # value used for rounding y-axis discreet tick steps # computing once, up front, here cuz why not - mkt = self.linked._symbol + mkt = self.linked.mkt self._y_tick_mult = 1/float(mkt.price_tick) # line width in view coordinates diff --git a/piker/ui/_dataviz.py b/piker/ui/_dataviz.py index 721483e1..a24c7d5c 100644 --- a/piker/ui/_dataviz.py +++ b/piker/ui/_dataviz.py @@ -436,12 +436,12 @@ class Viz(Struct): else: if x_range is None: ( - l, + xl, _, lbar, rbar, _, - r, + xr, ) = self.datums_range() profiler(f'{self.name} got bars range') @@ -585,12 +585,12 @@ class Viz(Struct): Return a range tuple for the datums present in view. ''' - l, r = view_range or self.view_range() + xl, xr = view_range or self.view_range() index_field: str = index_field or self.index_field if index_field == 'index': - l: int = round(l) - r: int = round(r) + xl: int = round(xl) + xr: int = round(xr) if array is None: array = self.shm.array @@ -601,12 +601,12 @@ class Viz(Struct): # invalid view state if ( - r < l - or l < 0 - or r < 0 + xr < xl + or xl < 0 + or xr < 0 or ( - l > last - and r > last + xl > last + and xr > last ) ): leftmost: int = first @@ -616,12 +616,12 @@ class Viz(Struct): # determine first and last datums in view determined by # l -> r view range. rightmost = max( - min(last, ceil(r)), + min(last, ceil(xr)), first, ) leftmost = min( - max(first, floor(l)), + max(first, floor(xl)), last, rightmost - 1, ) @@ -632,12 +632,12 @@ class Viz(Struct): self.vs.xrange = leftmost, rightmost return ( - l, # left x-in-view + xl, # left x-in-view first, # first datum leftmost, rightmost, last, # last_datum - r, # right-x-in-view + xr, # right-x-in-view ) def read( @@ -665,12 +665,12 @@ class Viz(Struct): profiler('self.shm.array READ') ( - l, + xl, ifirst, lbar, rbar, ilast, - r, + xr, ) = self.datums_range( index_field=index_field, array=array, @@ -715,8 +715,8 @@ class Viz(Struct): # a uniform time stamp step size? else: # get read-relative indices adjusting for master shm index. - lbar_i = max(l, ifirst) - ifirst - rbar_i = min(r, ilast) - ifirst + lbar_i = max(xl, ifirst) - ifirst + rbar_i = min(xr, ilast) - ifirst # NOTE: the slice here does NOT include the extra ``+ 1`` # BUT the ``in_view`` slice DOES.. @@ -1244,18 +1244,25 @@ class Viz(Struct): ''' # get most recent right datum index in-view - l, start, datum_start, datum_stop, stop, r = self.datums_range() + ( + xl, + start, + datum_start, + datum_stop, + stop, + xr, + ) = self.datums_range() lasts = self.shm.array[-1] i_step = lasts['index'] # last index-specific step. i_step_t = lasts['time'] # last time step. - # fqme = self.flume.symbol.fqme + # fqme = self.flume.mkt.fqme # check if "last (is) in view" -> is a real-time update necessary? if self.index_field == 'index': - liv = (r >= i_step) + liv = (xr >= i_step) else: - liv = (r >= i_step_t) + liv = (xr >= i_step_t) # compute the first available graphic obj's x-units-per-pixel # TODO: make this not loop through all vizs each time! diff --git a/piker/ui/_display.py b/piker/ui/_display.py index 04b363b1..c747eb31 100644 --- a/piker/ui/_display.py +++ b/piker/ui/_display.py @@ -37,6 +37,9 @@ import pyqtgraph as pg from msgspec import field # from .. import brokers +from ..accounting import ( + MktPair, +) from ..data.feed import ( open_feed, Feed, @@ -319,8 +322,8 @@ async def graphics_update_loop( for fqme, flume in feed.flumes.items(): ohlcv = flume.rt_shm hist_ohlcv = flume.hist_shm - symbol = flume.mkt - fqme = symbol.fqme + mkt = flume.mkt + fqme = mkt.fqme # update last price sticky fast_viz = fast_chart._vizs[fqme] @@ -360,13 +363,13 @@ async def graphics_update_loop( last, volume = ohlcv.array[-1][['close', 'volume']] - symbol = flume.mkt + mkt = flume.mkt l1 = L1Labels( fast_pi, # determine precision/decimal lengths - digits=symbol.tick_size_digits, - size_digits=symbol.lot_size_digits, + digits=mkt.price_tick_digits, + size_digits=mkt.size_tick_digits, ) # TODO: @@ -449,7 +452,7 @@ async def graphics_update_loop( and quote_rate >= display_rate ): pass - # log.warning(f'High quote rate {symbol.key}: {quote_rate}') + # log.warning(f'High quote rate {mkt.fqme}: {quote_rate}') last_quote_s = time.time() @@ -1224,7 +1227,7 @@ async def display_symbol_data( # tf_key = tf_in_1s[step_size_s] godwidget.window.setWindowTitle( f'{fqmes} ' - # f'tick:{symbol.tick_size} ' + # f'tick:{mkt.tick_size} ' # f'step:{tf_key} ' ) # generate order mode side-pane UI @@ -1234,8 +1237,8 @@ async def display_symbol_data( godwidget.pp_pane = pp_pane # create top history view chart above the "main rt chart". - rt_linked = godwidget.rt_linked - hist_linked = godwidget.hist_linked + rt_linked: LinkedSplits = godwidget.rt_linked + hist_linked: LinkedSplits = godwidget.hist_linked # NOTE: here we insert the slow-history chart set into # the fast chart's splitter -> so it's a splitter of charts @@ -1279,17 +1282,17 @@ async def display_symbol_data( # TODO NOTE: THIS CONTROLS WHAT SYMBOL IS USED FOR ORDER MODE # SUBMISSIONS, we need to make this switch based on selection. - rt_linked._symbol = flume.mkt - hist_linked._symbol = flume.mkt + rt_linked.set_mkt_info(flume.mkt) + hist_linked.set_mkt_info(flume.mkt) ohlcv: ShmArray = flume.rt_shm hist_ohlcv: ShmArray = flume.hist_shm - symbol = flume.mkt - fqme = symbol.fqme + mkt: MktPair = flume.mkt + fqme = mkt.fqme hist_chart = hist_linked.plot_ohlc_main( - symbol, + mkt, hist_ohlcv, flume, # in the case of history chart we explicitly set `False` @@ -1311,7 +1314,7 @@ async def display_symbol_data( hist_linked.cursor.always_show_xlabel = False rt_chart = rt_linked.plot_ohlc_main( - symbol, + mkt, ohlcv, flume, # in the case of history chart we explicitly set `False` @@ -1378,8 +1381,8 @@ async def display_symbol_data( ohlcv: ShmArray = flume.rt_shm hist_ohlcv: ShmArray = flume.hist_shm - symbol = flume.mkt - fqme = symbol.fqme + mkt = flume.mkt + fqme = mkt.fqme hist_pi = hist_chart.overlay_plotitem( name=fqme, diff --git a/piker/ui/_fsp.py b/piker/ui/_fsp.py index f942ff14..b4aa2b10 100644 --- a/piker/ui/_fsp.py +++ b/piker/ui/_fsp.py @@ -29,7 +29,6 @@ from typing import ( Any, ) -import numpy as np import msgspec import tractor import pyqtgraph as pg @@ -428,7 +427,7 @@ class FspAdmin: in self._flow_registry.items() ], - ) as (ctx, last_index), + ) as (ctx, _), ctx.open_stream() as stream, ): @@ -486,8 +485,10 @@ class FspAdmin: readonly=True, ) - portal = self.cluster.get(worker_name) or self.rr_next_portal() - provider_tag = portal.channel.uid + portal: tractor.Portal = ( + self.cluster.get(worker_name) + or self.rr_next_portal() + ) # TODO: this should probably be turned into a # ``Cascade`` type which describes the routing diff --git a/piker/ui/_position.py b/piker/ui/_position.py index 59ab434d..a2e6c19e 100644 --- a/piker/ui/_position.py +++ b/piker/ui/_position.py @@ -45,7 +45,10 @@ from ..calc import ( pnl, puterize, ) -from ..accounting._allocate import Allocator +from ..accounting import ( + Allocator, + MktPair, +) from ..accounting import ( Position, ) @@ -244,7 +247,7 @@ class SettingsPane: # a ``brokerd`) then error and switch back to the last # selection. if tracker is None: - sym = old_tracker.charts[0].linked.symbol.key + sym: str = old_tracker.charts[0].linked.mkt.fqme log.error( f'Account `{account_name}` can not be set for {sym}' ) @@ -415,9 +418,10 @@ class SettingsPane: ''' mode = self.order_mode - sym = mode.chart.linked.symbol + mkt: MktPair = mode.chart.linked.mkt size = tracker.live_pp.size - flume: Feed = mode.feed.flumes[sym.fqme] + fqme: str = mkt.fqme + flume: Feed = mode.feed.flumes[fqme] pnl_value = 0 if size: @@ -430,7 +434,6 @@ class SettingsPane: # maybe start update task global _pnl_tasks - fqme = sym.fqme if fqme not in _pnl_tasks: _pnl_tasks[fqme] = True self.order_mode.nursery.start_soon( @@ -555,7 +558,7 @@ class Nav(Struct): ''' for key, chart in self.charts.items(): - size_digits = size_digits or chart.linked.symbol.lot_size_digits + size_digits = size_digits or chart.linked.mkt.size_tick_digits line = self.lines.get(key) level_marker = self.level_markers[key] pp_label = self.pp_labels[key] diff --git a/piker/ui/_signalling.py b/piker/ui/_signalling.py index 13bc2fc8..c952b49d 100644 --- a/piker/ui/_signalling.py +++ b/piker/ui/_signalling.py @@ -23,7 +23,10 @@ WARNING: this code likely doesn't work at all (yet) """ import numpy as np import pyqtgraph as pg -from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt5 import ( + QtCore, + QtWidgets, +) from .quantdom.charts import CenteredTextItem from .quantdom.base import Quotes diff --git a/piker/ui/order_mode.py b/piker/ui/order_mode.py index 44558251..21f7bd22 100644 --- a/piker/ui/order_mode.py +++ b/piker/ui/order_mode.py @@ -36,17 +36,18 @@ import trio from PyQt5.QtCore import Qt from .. import config -from ..accounting import Position -from ..accounting._allocate import ( +from ..accounting import ( + Allocator, + Position, mk_allocator, + MktPair, + Symbol, ) from ..clearing._client import ( open_ems, OrderClient, ) from ._style import _font -from ..accounting._mktinfo import Symbol -from ..accounting import MktPair from ..data.feed import ( Feed, Flume, @@ -93,7 +94,7 @@ class Dialog(Struct): order: Order symbol: str lines: list[LevelLine] - last_status_close: Callable = lambda: None + last_status_close: Callable | None = None msgs: dict[str, dict] = {} fills: dict[str, Any] = {} @@ -288,10 +289,10 @@ class OrderMode: # since that's illogical / a no-op. return - symbol = self.chart.linked.symbol + mkt: MktPair = self.chart.linked.mkt # NOTE : we could also use instead, - # symbol.quantize(price, quantity_type='price') + # mkt.quantize(price, quantity_type='price') # but it returns a Decimal and it's probably gonna # be slower? # TODO: should we be enforcing this precision @@ -301,7 +302,7 @@ class OrderMode: price = round( price, - ndigits=symbol.tick_size_digits, + ndigits=mkt.size_tick_digits, ) order = self._staged_order = Order( @@ -309,8 +310,8 @@ class OrderMode: price=price, account=self.current_pp.alloc.account, size=0, - symbol=symbol, - brokers=[symbol.broker], + symbol=mkt.fqme, + brokers=[mkt.broker], oid='', # filled in on submit exec_mode=trigger_type, # dark or live ) @@ -457,10 +458,10 @@ class OrderMode: the EMS, adjust mirrored level line on secondary chart. ''' - mktinfo = self.chart.linked.symbol + mktinfo: MktPair = self.chart.linked.mkt level = round( line.value(), - ndigits=mktinfo.tick_size_digits, + ndigits=mktinfo.size_tick_digits, ) # updated by level change callback set in ``.new_line_from_order()`` dialog = line.dialog @@ -497,7 +498,9 @@ class OrderMode: # a submission is the start of a new order dialog dialog = self.dialogs[uuid] dialog.lines = lines - dialog.last_status_close() + cls: Callable | None = dialog.last_status_close + if cls: + cls() for line in lines: @@ -549,7 +552,7 @@ class OrderMode: # XXX: seems to fail on certain types of races? # assert len(lines) == 2 if lines: - flume: Flume = self.feed.flumes[chart.linked.symbol.fqme] + flume: Flume = self.feed.flumes[chart.linked.mkt.fqme] _, _, ratio = flume.get_ds_info() for chart, shm in [ @@ -740,15 +743,15 @@ async def open_order_mode( lines = LineEditor(godw=godw) arrows = ArrowEditor(godw=godw) - # symbol id - symbol = chart.linked.symbol + # market endpoint info + mkt: MktPair = chart.linked.mkt # map of per-provider account keys to position tracker instances trackers: dict[str, PositionTracker] = {} # load account names from ``brokers.toml`` accounts_def = config.load_accounts( - providers=[symbol.broker], + providers=[mkt.broker], ) # XXX: ``brokerd`` delivers a set of account names that it @@ -771,17 +774,17 @@ async def open_order_mode( # net-zero pp startup_pp = Position( - mkt=symbol, + mkt=mkt, size=0, ppu=0, # XXX: BLEH, do we care about this on the client side? - bs_mktid=symbol.key, + bs_mktid=mkt.key, ) # allocator config - alloc = mk_allocator( - symbol=symbol, + alloc: Allocator = mk_allocator( + mkt=mkt, account=account_name, # if this startup size is greater the allocator limit,