Merge pull request #288 from pikers/pp_bar_fixes

pp bar fixes
kraken_editorder
goodboy 2022-03-04 09:18:45 -05:00 committed by GitHub
commit bc59d476b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 90 additions and 36 deletions

View File

@ -517,9 +517,9 @@ class Client:
contract, ticker, details = await self.get_sym_details(symbol) contract, ticker, details = await self.get_sym_details(symbol)
# ensure a last price gets filled in before we deliver quote # ensure a last price gets filled in before we deliver quote
for _ in range(1): for _ in range(100):
if isnan(ticker.last): if isnan(ticker.last):
await asyncio.sleep(0.1) await asyncio.sleep(0.01)
log.warning(f'Quote for {symbol} timed out: market is closed?') log.warning(f'Quote for {symbol} timed out: market is closed?')
ticker = await ticker.updateEvent ticker = await ticker.updateEvent
else: else:
@ -792,7 +792,7 @@ async def load_aio_clients(
try_ports = list(ports.values()) try_ports = list(ports.values())
ports = try_ports if port is None else [port] ports = try_ports if port is None else [port]
# we_connected = [] # we_connected = []
connect_timeout = 1 if platform.system() != 'Windows' else 2 connect_timeout = 2
combos = list(itertools.product(hosts, ports)) combos = list(itertools.product(hosts, ports))
# allocate new and/or reload disconnected but cached clients # allocate new and/or reload disconnected but cached clients
@ -1428,8 +1428,14 @@ async def stream_quotes(
''' '''
# TODO: support multiple subscriptions # TODO: support multiple subscriptions
sym = symbols[0] sym = symbols[0]
details: Optional[dict] = None
with trio.fail_after(16): contract, first_ticker, details = await _trio_run_client_method(
method='get_sym_details',
symbol=sym,
)
with trio.move_on_after(1):
contract, first_ticker, details = await _trio_run_client_method( contract, first_ticker, details = await _trio_run_client_method(
method='get_quote', method='get_quote',
symbol=sym, symbol=sym,

View File

@ -29,7 +29,8 @@ from ._messages import BrokerdPosition, Status
class Position(BaseModel): class Position(BaseModel):
'''Basic pp (personal position) model with attached fills history. '''
Basic pp (personal position) model with attached fills history.
This type should be IPC wire ready? This type should be IPC wire ready?
@ -61,6 +62,15 @@ class Position(BaseModel):
self.avg_price = avg_price self.avg_price = avg_price
self.size = size self.size = size
@property
def dsize(self) -> float:
'''
The "dollar" size of the pp, normally in trading (fiat) unit
terms.
'''
return self.avg_price * self.size
_size_units = bidict({ _size_units = bidict({
'currency': '$ size', 'currency': '$ size',
@ -114,7 +124,8 @@ class Allocator(BaseModel):
def step_sizes( def step_sizes(
self, self,
) -> (float, float): ) -> (float, float):
'''Return the units size for each unit type as a tuple. '''
Return the units size for each unit type as a tuple.
''' '''
slots = self.slots slots = self.slots
@ -142,7 +153,8 @@ class Allocator(BaseModel):
action: str, action: str,
) -> dict: ) -> dict:
'''Generate order request info for the "next" submittable order '''
Generate order request info for the "next" submittable order
depending on position / order entry config. depending on position / order entry config.
''' '''
@ -250,7 +262,8 @@ class Allocator(BaseModel):
pp: Position, pp: Position,
) -> float: ) -> float:
'''Calc and return the number of slots used by this ``Position``. '''
Calc and return the number of slots used by this ``Position``.
''' '''
abs_pp_size = abs(pp.size) abs_pp_size = abs(pp.size)

View File

@ -21,6 +21,7 @@ Text entry "forms" widgets (mostly for configuration and UI user input).
from __future__ import annotations from __future__ import annotations
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from functools import partial from functools import partial
from math import floor
from typing import ( from typing import (
Optional, Any, Callable, Awaitable Optional, Any, Callable, Awaitable
) )
@ -542,7 +543,7 @@ class FillStatusBar(QProgressBar):
''' '''
border_px: int = 2 border_px: int = 2
slot_margin_px: int = 2 slot_margin_px: int = 1
def __init__( def __init__(
self, self,
@ -553,7 +554,11 @@ class FillStatusBar(QProgressBar):
) -> None: ) -> None:
super().__init__(parent=parent) super().__init__(parent=parent)
self.approx_h = approx_height_px
self.approx_h = int(round(approx_height_px))
self.setMinimumHeight(self.approx_h)
self.setMaximumHeight(self.approx_h)
self.font_size = font_size self.font_size = font_size
self.setFormat('') # label format self.setFormat('') # label format
@ -567,17 +572,12 @@ class FillStatusBar(QProgressBar):
) -> None: ) -> None:
approx_h = self.approx_h
# TODO: compute "used height" thus far and mostly fill the rest
tot_slot_h, r = divmod(
approx_h,
slots,
)
clipped = int(slots * tot_slot_h + 2*self.border_px)
self.setMaximumHeight(clipped)
slot_height_px = tot_slot_h - 2*self.slot_margin_px
self.setOrientation(Qt.Vertical) self.setOrientation(Qt.Vertical)
h = self.height()
# TODO: compute "used height" thus far and mostly fill the rest
tot_slot_h, r = divmod(h, slots)
self.setStyleSheet( self.setStyleSheet(
f""" f"""
QProgressBar {{ QProgressBar {{
@ -592,21 +592,28 @@ class FillStatusBar(QProgressBar):
border: {self.border_px}px solid {hcolor('default_light')}; border: {self.border_px}px solid {hcolor('default_light')};
border-radius: 2px; border-radius: 2px;
}} }}
QProgressBar::chunk {{ QProgressBar::chunk {{
background-color: {hcolor('default_spotlight')}; background-color: {hcolor('default_spotlight')};
color: {hcolor('bracket')}; color: {hcolor('bracket')};
border-radius: 2px; border-radius: 2px;
margin: {self.slot_margin_px}px;
height: {slot_height_px}px;
}} }}
""" """
) )
# to set a discrete "block" per slot...
# XXX: couldn't get the discrete math to work here such
# that it was always correctly showing a discretized value
# up to the limit; not sure if it's the ``.setRange()``
# / ``.setValue()`` api or not but i was able to get something
# close screwing with the divmod above above but after so large
# a value it would always be less chunks then the correct
# value..
# margin: {self.slot_margin_px}px;
# height: {slot_height_px}px;
# margin-bottom: {slot_margin_px*2}px; # margin-bottom: {slot_margin_px*2}px;
# margin-top: {slot_margin_px*2}px; # margin-top: {slot_margin_px*2}px;
# color: #19232D; # color: #19232D;

View File

@ -71,10 +71,10 @@ async def update_pnl_from_feed(
log.info(f'Starting pnl display for {pp.alloc.account}') log.info(f'Starting pnl display for {pp.alloc.account}')
if live.size < 0: if live.size < 0:
types = ('ask', 'last', 'last', 'utrade') types = ('ask', 'last', 'last', 'dark_trade')
elif live.size > 0: elif live.size > 0:
types = ('bid', 'last', 'last', 'utrade') types = ('bid', 'last', 'last', 'dark_trade')
else: else:
log.info(f'No position (yet) for {tracker.alloc.account}@{key}') log.info(f'No position (yet) for {tracker.alloc.account}@{key}')
@ -119,7 +119,8 @@ async def update_pnl_from_feed(
@dataclass @dataclass
class SettingsPane: class SettingsPane:
'''Composite set of widgets plus an allocator model for configuring '''
Composite set of widgets plus an allocator model for configuring
order entry sizes and position limits per tradable instrument. order entry sizes and position limits per tradable instrument.
''' '''
@ -151,7 +152,8 @@ class SettingsPane:
key: str, key: str,
) -> None: ) -> None:
'''Called on any order pane drop down selection change. '''
Called on any order pane drop down selection change.
''' '''
log.info(f'selection input {key}:{text}') log.info(f'selection input {key}:{text}')
@ -164,7 +166,8 @@ class SettingsPane:
value: str, value: str,
) -> bool: ) -> bool:
'''Called on any order pane edit field value change. '''
Called on any order pane edit field value change.
''' '''
mode = self.order_mode mode = self.order_mode
@ -219,16 +222,36 @@ class SettingsPane:
else: else:
value = puterize(value) value = puterize(value)
if key == 'limit': if key == 'limit':
pp = mode.current_pp.live_pp
if size_unit == 'currency': if size_unit == 'currency':
dsize = pp.dsize
if dsize > value:
log.error(
f'limit must > then current pp: {dsize}'
)
raise ValueError
alloc.currency_limit = value alloc.currency_limit = value
else: else:
size = pp.size
if size > value:
log.error(
f'limit must > then current pp: {size}'
)
raise ValueError
alloc.units_limit = value alloc.units_limit = value
elif key == 'slots': elif key == 'slots':
if value <= 0:
raise ValueError('slots must be > 0')
alloc.slots = int(value) alloc.slots = int(value)
else: else:
raise ValueError(f'Unknown setting {key}') log.error(f'Unknown setting {key}')
raise ValueError
log.info(f'settings change: {key}: {value}') log.info(f'settings change: {key}: {value}')
@ -363,7 +386,8 @@ def position_line(
marker: Optional[LevelMarker] = None, marker: Optional[LevelMarker] = None,
) -> LevelLine: ) -> LevelLine:
'''Convenience routine to create a line graphic representing a "pp" '''
Convenience routine to create a line graphic representing a "pp"
aka the acro for a, aka the acro for a,
"{piker, private, personal, puny, <place your p-word here>} position". "{piker, private, personal, puny, <place your p-word here>} position".
@ -417,7 +441,8 @@ def position_line(
class PositionTracker: class PositionTracker:
'''Track and display real-time positions for a single symbol '''
Track and display real-time positions for a single symbol
over multiple accounts on a single chart. over multiple accounts on a single chart.
Graphically composed of a level line and marker as well as labels Graphically composed of a level line and marker as well as labels
@ -497,7 +522,8 @@ class PositionTracker:
@property @property
def pane(self) -> FieldsForm: def pane(self) -> FieldsForm:
'''Return handle to pp side pane form. '''
Return handle to pp side pane form.
''' '''
return self.chart.linked.godwidget.pp_pane return self.chart.linked.godwidget.pp_pane
@ -507,7 +533,8 @@ class PositionTracker:
marker: LevelMarker marker: LevelMarker
) -> None: ) -> None:
'''Update all labels. '''
Update all labels.
Meant to be called from the maker ``.paint()`` Meant to be called from the maker ``.paint()``
for immediate, lag free label draws. for immediate, lag free label draws.

View File

@ -107,7 +107,8 @@ def on_level_change_update_next_order_info(
@dataclass @dataclass
class OrderMode: class OrderMode:
'''Major UX mode for placing orders on a chart view providing so '''
Major UX mode for placing orders on a chart view providing so
called, "chart trading". called, "chart trading".
This is the other "main" mode that pairs with "view mode" (when This is the other "main" mode that pairs with "view mode" (when