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)
# ensure a last price gets filled in before we deliver quote
for _ in range(1):
for _ in range(100):
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?')
ticker = await ticker.updateEvent
else:
@ -792,7 +792,7 @@ async def load_aio_clients(
try_ports = list(ports.values())
ports = try_ports if port is None else [port]
# we_connected = []
connect_timeout = 1 if platform.system() != 'Windows' else 2
connect_timeout = 2
combos = list(itertools.product(hosts, ports))
# allocate new and/or reload disconnected but cached clients
@ -1428,8 +1428,14 @@ async def stream_quotes(
'''
# TODO: support multiple subscriptions
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(
method='get_quote',
symbol=sym,

View File

@ -29,7 +29,8 @@ from ._messages import BrokerdPosition, Status
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?
@ -61,6 +62,15 @@ class Position(BaseModel):
self.avg_price = avg_price
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({
'currency': '$ size',
@ -114,7 +124,8 @@ class Allocator(BaseModel):
def step_sizes(
self,
) -> (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
@ -142,7 +153,8 @@ class Allocator(BaseModel):
action: str,
) -> 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.
'''
@ -250,7 +262,8 @@ class Allocator(BaseModel):
pp: Position,
) -> 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)

View File

@ -21,6 +21,7 @@ Text entry "forms" widgets (mostly for configuration and UI user input).
from __future__ import annotations
from contextlib import asynccontextmanager
from functools import partial
from math import floor
from typing import (
Optional, Any, Callable, Awaitable
)
@ -542,7 +543,7 @@ class FillStatusBar(QProgressBar):
'''
border_px: int = 2
slot_margin_px: int = 2
slot_margin_px: int = 1
def __init__(
self,
@ -553,7 +554,11 @@ class FillStatusBar(QProgressBar):
) -> None:
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.setFormat('') # label format
@ -567,17 +572,12 @@ class FillStatusBar(QProgressBar):
) -> 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)
h = self.height()
# TODO: compute "used height" thus far and mostly fill the rest
tot_slot_h, r = divmod(h, slots)
self.setStyleSheet(
f"""
QProgressBar {{
@ -592,21 +592,28 @@ class FillStatusBar(QProgressBar):
border: {self.border_px}px solid {hcolor('default_light')};
border-radius: 2px;
}}
QProgressBar::chunk {{
background-color: {hcolor('default_spotlight')};
color: {hcolor('bracket')};
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-top: {slot_margin_px*2}px;
# color: #19232D;

View File

@ -71,10 +71,10 @@ async def update_pnl_from_feed(
log.info(f'Starting pnl display for {pp.alloc.account}')
if live.size < 0:
types = ('ask', 'last', 'last', 'utrade')
types = ('ask', 'last', 'last', 'dark_trade')
elif live.size > 0:
types = ('bid', 'last', 'last', 'utrade')
types = ('bid', 'last', 'last', 'dark_trade')
else:
log.info(f'No position (yet) for {tracker.alloc.account}@{key}')
@ -119,7 +119,8 @@ async def update_pnl_from_feed(
@dataclass
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.
'''
@ -151,7 +152,8 @@ class SettingsPane:
key: str,
) -> 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}')
@ -164,7 +166,8 @@ class SettingsPane:
value: str,
) -> bool:
'''Called on any order pane edit field value change.
'''
Called on any order pane edit field value change.
'''
mode = self.order_mode
@ -219,16 +222,36 @@ class SettingsPane:
else:
value = puterize(value)
if key == 'limit':
pp = mode.current_pp.live_pp
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
else:
size = pp.size
if size > value:
log.error(
f'limit must > then current pp: {size}'
)
raise ValueError
alloc.units_limit = value
elif key == 'slots':
if value <= 0:
raise ValueError('slots must be > 0')
alloc.slots = int(value)
else:
raise ValueError(f'Unknown setting {key}')
log.error(f'Unknown setting {key}')
raise ValueError
log.info(f'settings change: {key}: {value}')
@ -363,7 +386,8 @@ def position_line(
marker: Optional[LevelMarker] = None,
) -> 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,
"{piker, private, personal, puny, <place your p-word here>} position".
@ -417,7 +441,8 @@ def position_line(
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.
Graphically composed of a level line and marker as well as labels
@ -497,7 +522,8 @@ class PositionTracker:
@property
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
@ -507,7 +533,8 @@ class PositionTracker:
marker: LevelMarker
) -> None:
'''Update all labels.
'''
Update all labels.
Meant to be called from the maker ``.paint()``
for immediate, lag free label draws.

View File

@ -107,7 +107,8 @@ def on_level_change_update_next_order_info(
@dataclass
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".
This is the other "main" mode that pairs with "view mode" (when