From 5333d25bf62098d971d6f99fa05f95240eefd746 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Mon, 6 Sep 2021 21:27:53 -0400 Subject: [PATCH] Better separation of UI vs. allocator settings Get rid of `PositionTracker.init_status_ui()` and instead make a helper func `mk_allocator()` which takes in the alloc and adjusts default settings on the allocator alone (which is expected to be passed in). Expect a `Position` instance to be passed into the tracker which will be looked up for UI updates. Move *update-from-position-msg* ops into a `Position.update_from_msg()` method. --- piker/ui/_position.py | 160 ++++++++++++++++++++++-------------------- 1 file changed, 83 insertions(+), 77 deletions(-) diff --git a/piker/ui/_position.py b/piker/ui/_position.py index 3d5364ad..8cff1b95 100644 --- a/piker/ui/_position.py +++ b/piker/ui/_position.py @@ -63,6 +63,24 @@ class Position(BaseModel): # ordered record of known constituent trade messages fills: list[Status] = [] + def update_from_msg( + self, + msg: BrokerdPosition, + + ) -> None: + + # XXX: better place to do this? + symbol = self.symbol + + lot_size_digits = symbol.lot_size_digits + avg_price, size = ( + round(msg['avg_price'], ndigits=symbol.tick_size_digits), + round(msg['size'], ndigits=lot_size_digits), + ) + + self.avg_price = avg_price + self.size = size + _size_units = bidict({ 'currency': '$ size', @@ -250,6 +268,60 @@ class Allocator(BaseModel): return round(prop * self.slots) +def mk_allocator( + + alloc: Allocator, + startup_pp: Position, + config_section: dict = {}, + +) -> (float, Allocator): + + asset_type = alloc.symbol.type_key + + # load and retreive user settings for default allocations + # ``config.toml`` + slots = 4 + currency_limit = 5e3 + + alloc.slots = slots + alloc.currency_limit = currency_limit + + # default entry sizing + if asset_type in ('stock', 'crypto', 'forex'): + + alloc.size_unit = '$ size' + + elif asset_type in ('future', 'option', 'futures_option'): + + # since it's harder to know how currency "applies" in this case + # given leverage properties + alloc.size_unit = '# units' + + # set units limit to slots size thus making make the next + # entry step 1.0 + alloc.units_limit = slots + + # if the current position is already greater then the limit + # settings, increase the limit to the current position + if alloc.size_unit == 'currency': + startup_size = startup_pp.size * startup_pp.avg_price + + if startup_size > alloc.currency_limit: + alloc.currency_limit = round(startup_size, ndigits=2) + + limit_text = alloc.currency_limit + + else: + startup_size = startup_pp.size + + if startup_size > alloc.units_limit: + alloc.units_limit = startup_size + + limit_text = alloc.units_limit + + return limit_text, alloc + + @dataclass class SettingsPane: '''Composite set of widgets plus an allocator model for configuring @@ -356,59 +428,6 @@ class SettingsPane: # UI in some way? return True - def init_status_ui( - self, - ): - alloc = self.alloc - asset_type = alloc.symbol.type_key - # form = self.form - - # TODO: pull from piker.toml - # default config - slots = 4 - currency_limit = 5e3 - - startup_pp = self.tracker.startup_pp - - alloc.slots = slots - alloc.currency_limit = currency_limit - - # default entry sizing - if asset_type in ('stock', 'crypto', 'forex'): - - alloc.size_unit = '$ size' - - elif asset_type in ('future', 'option', 'futures_option'): - - # since it's harder to know how currency "applies" in this case - # given leverage properties - alloc.size_unit = '# units' - - # set units limit to slots size thus making make the next - # entry step 1.0 - alloc.units_limit = slots - - # if the current position is already greater then the limit - # settings, increase the limit to the current position - if alloc.size_unit == 'currency': - startup_size = startup_pp.size * startup_pp.avg_price - - if startup_size > alloc.currency_limit: - alloc.currency_limit = round(startup_size, ndigits=2) - - limit_text = alloc.currency_limit - - else: - startup_size = startup_pp.size - - if startup_size > alloc.units_limit: - alloc.units_limit = startup_size - - limit_text = alloc.units_limit - - self.on_ui_settings_change('limit', limit_text) - self.update_status_ui(size=startup_size) - def update_status_ui( self, size: float = None, @@ -533,9 +552,9 @@ class PositionTracker: # inputs chart: 'ChartPlotWidget' # noqa alloc: Allocator + startup_pp: Position # allocated - startup_pp: Position live_pp: Position pp_label: Label size_label: Label @@ -547,17 +566,14 @@ class PositionTracker: self, chart: 'ChartPlotWidget', # noqa alloc: Allocator, + startup_pp: Position, ) -> None: self.chart = chart self.alloc = alloc - self.live_pp = Position( - symbol=chart.linked.symbol, - size=0, - avg_price=0, - ) - self.startup_pp = self.live_pp.copy() + self.startup_pp = startup_pp + self.live_pp = startup_pp.copy() view = chart.getViewBox() @@ -622,9 +638,8 @@ class PositionTracker: self.pp_label.update() self.size_label.update() - def update_from_pp_msg( + def update_from_pp( self, - msg: BrokerdPosition, position: Optional[Position] = None, ) -> None: @@ -632,23 +647,14 @@ class PositionTracker: EMS ``BrokerdPosition`` msg. ''' - # XXX: better place to do this? - symbol = self.chart.linked.symbol - lot_size_digits = symbol.lot_size_digits - avg_price, size = ( - round(msg['avg_price'], ndigits=symbol.tick_size_digits), - round(msg['size'], ndigits=lot_size_digits), - ) - # live pp updates pp = position or self.live_pp - pp.avg_price = avg_price - pp.size = size + # pp.update_from_msg(msg) self.update_line( - avg_price, - size, - lot_size_digits, + pp.avg_price, + pp.size, + self.chart.linked.symbol.lot_size_digits, ) # label updates @@ -656,11 +662,11 @@ class PositionTracker: self.alloc.slots_used(pp), ndigits=1) self.size_label.render() - if size == 0: + if pp.size == 0: self.hide() else: - self._level_marker.level = avg_price + self._level_marker.level = pp.avg_price # these updates are critical to avoid lag on view/scene changes self._level_marker.update() # trigger paint