Don't override `Account.pps: dict` entries..
Despite a `.bs_mktid` ideally being a bijection with `MktPair.fqme` values, apparently some backends (cough IB) will switch the .<venue>` part in txn records resulting in multiple account-conf-file sections for the same dst asset. Obviously that means we can't allocate new `Position` entries keyed by that `bs_mktid`, instead be sure to **update them instead**! Deats, - add case logic to avoid pp overwrites using a `pp_objs.get()` check. - warn on duplicated pos entries whenever the current account-file entry's `mkt` doesn't match the pre-existing position's. - mk `Position.add_clear()` return a `bool` indicating if the record was newly added, warn when it was already existing/added prior. Also, - drop the already deprecated `open_pps()`, also from sub-pkg exports. - draft TODO for `Position.summary()` idea as a replacement for `BrokerdPosition`-msgs.qt_w_graceful_SIGINT
parent
6cc3518143
commit
b0f273f091
|
@ -33,7 +33,6 @@ from ._pos import (
|
||||||
Account,
|
Account,
|
||||||
load_account,
|
load_account,
|
||||||
load_account_from_ledger,
|
load_account_from_ledger,
|
||||||
open_pps,
|
|
||||||
open_account,
|
open_account,
|
||||||
Position,
|
Position,
|
||||||
)
|
)
|
||||||
|
@ -68,7 +67,6 @@ __all__ = [
|
||||||
'load_account_from_ledger',
|
'load_account_from_ledger',
|
||||||
'mk_allocator',
|
'mk_allocator',
|
||||||
'open_account',
|
'open_account',
|
||||||
'open_pps',
|
|
||||||
'open_trade_ledger',
|
'open_trade_ledger',
|
||||||
'unpack_fqme',
|
'unpack_fqme',
|
||||||
'DerivTypes',
|
'DerivTypes',
|
||||||
|
|
|
@ -353,13 +353,12 @@ class Position(Struct):
|
||||||
) -> bool:
|
) -> bool:
|
||||||
'''
|
'''
|
||||||
Update clearing table by calculating the rolling ppu and
|
Update clearing table by calculating the rolling ppu and
|
||||||
(accumulative) size in both the clears entry and local
|
(accumulative) size in both the clears entry and local attrs
|
||||||
attrs state.
|
state.
|
||||||
|
|
||||||
Inserts are always done in datetime sorted order.
|
Inserts are always done in datetime sorted order.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
# added: bool = False
|
|
||||||
tid: str = t.tid
|
tid: str = t.tid
|
||||||
if tid in self._events:
|
if tid in self._events:
|
||||||
log.debug(
|
log.debug(
|
||||||
|
@ -367,7 +366,7 @@ class Position(Struct):
|
||||||
f'\n'
|
f'\n'
|
||||||
f'{t}\n'
|
f'{t}\n'
|
||||||
)
|
)
|
||||||
# return added
|
return False
|
||||||
|
|
||||||
# TODO: apparently this IS possible with a dict but not
|
# TODO: apparently this IS possible with a dict but not
|
||||||
# common and probably not that beneficial unless we're also
|
# common and probably not that beneficial unless we're also
|
||||||
|
@ -448,6 +447,12 @@ class Position(Struct):
|
||||||
# def suggest_split(self) -> float:
|
# def suggest_split(self) -> float:
|
||||||
# ...
|
# ...
|
||||||
|
|
||||||
|
# ?TODO, for sending rendered state over the wire?
|
||||||
|
# def summary(self) -> PositionSummary:
|
||||||
|
# do minimal conversion to a subset of fields
|
||||||
|
# currently defined in `.clearing._messages.BrokerdPosition`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Account(Struct):
|
class Account(Struct):
|
||||||
'''
|
'''
|
||||||
|
@ -491,9 +496,9 @@ class Account(Struct):
|
||||||
|
|
||||||
def update_from_ledger(
|
def update_from_ledger(
|
||||||
self,
|
self,
|
||||||
ledger: TransactionLedger | dict[str, Transaction],
|
ledger: TransactionLedger|dict[str, Transaction],
|
||||||
cost_scalar: float = 2,
|
cost_scalar: float = 2,
|
||||||
symcache: SymbologyCache | None = None,
|
symcache: SymbologyCache|None = None,
|
||||||
|
|
||||||
_mktmap_table: dict[str, MktPair] | None = None,
|
_mktmap_table: dict[str, MktPair] | None = None,
|
||||||
|
|
||||||
|
@ -714,7 +719,7 @@ class Account(Struct):
|
||||||
# XXX WTF: if we use a tomlkit.Integer here we get this
|
# XXX WTF: if we use a tomlkit.Integer here we get this
|
||||||
# super weird --1 thing going on for cumsize!?1!
|
# super weird --1 thing going on for cumsize!?1!
|
||||||
# NOTE: the fix was to always float() the size value loaded
|
# NOTE: the fix was to always float() the size value loaded
|
||||||
# in open_pps() below!
|
# in open_account() below!
|
||||||
config.write(
|
config.write(
|
||||||
config=self.conf,
|
config=self.conf,
|
||||||
path=self.conf_path,
|
path=self.conf_path,
|
||||||
|
@ -898,7 +903,6 @@ def open_account(
|
||||||
clears_table['dt'] = dt
|
clears_table['dt'] = dt
|
||||||
trans.append(Transaction(
|
trans.append(Transaction(
|
||||||
fqme=bs_mktid,
|
fqme=bs_mktid,
|
||||||
# sym=mkt,
|
|
||||||
bs_mktid=bs_mktid,
|
bs_mktid=bs_mktid,
|
||||||
tid=tid,
|
tid=tid,
|
||||||
# XXX: not sure why sometimes these are loaded as
|
# XXX: not sure why sometimes these are loaded as
|
||||||
|
@ -921,11 +925,22 @@ def open_account(
|
||||||
):
|
):
|
||||||
expiry: pendulum.DateTime = pendulum.parse(expiry)
|
expiry: pendulum.DateTime = pendulum.parse(expiry)
|
||||||
|
|
||||||
pp = pp_objs[bs_mktid] = Position(
|
# !XXX, should never be duplicates over
|
||||||
mkt,
|
# a backend-(broker)-system's unique market-IDs!
|
||||||
split_ratio=split_ratio,
|
if pos := pp_objs.get(bs_mktid):
|
||||||
bs_mktid=bs_mktid,
|
if mkt != pos.mkt:
|
||||||
)
|
log.warning(
|
||||||
|
f'Duplicated position but diff `MktPair.fqme` ??\n'
|
||||||
|
f'bs_mktid: {bs_mktid!r}\n'
|
||||||
|
f'pos.mkt: {pos.mkt}\n'
|
||||||
|
f'mkt: {mkt}\n'
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
pos = pp_objs[bs_mktid] = Position(
|
||||||
|
mkt,
|
||||||
|
split_ratio=split_ratio,
|
||||||
|
bs_mktid=bs_mktid,
|
||||||
|
)
|
||||||
|
|
||||||
# XXX: super critical, we need to be sure to include
|
# XXX: super critical, we need to be sure to include
|
||||||
# all pps.toml clears to avoid reusing clears that were
|
# all pps.toml clears to avoid reusing clears that were
|
||||||
|
@ -933,8 +948,13 @@ def open_account(
|
||||||
# state, since today's records may have already been
|
# state, since today's records may have already been
|
||||||
# processed!
|
# processed!
|
||||||
for t in trans:
|
for t in trans:
|
||||||
pp.add_clear(t)
|
added: bool = pos.add_clear(t)
|
||||||
|
if not added:
|
||||||
|
log.warning(
|
||||||
|
f'Txn already recorded in pp ??\n'
|
||||||
|
f'\n'
|
||||||
|
f'{t}\n'
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
yield acnt
|
yield acnt
|
||||||
finally:
|
finally:
|
||||||
|
@ -942,20 +962,6 @@ def open_account(
|
||||||
acnt.write_config()
|
acnt.write_config()
|
||||||
|
|
||||||
|
|
||||||
# TODO: drop the old name and THIS!
|
|
||||||
@cm
|
|
||||||
def open_pps(
|
|
||||||
*args,
|
|
||||||
**kwargs,
|
|
||||||
) -> Generator[Account, None, None]:
|
|
||||||
log.warning(
|
|
||||||
'`open_pps()` is now deprecated!\n'
|
|
||||||
'Please use `with open_account() as cnt:`'
|
|
||||||
)
|
|
||||||
with open_account(*args, **kwargs) as acnt:
|
|
||||||
yield acnt
|
|
||||||
|
|
||||||
|
|
||||||
def load_account_from_ledger(
|
def load_account_from_ledger(
|
||||||
|
|
||||||
brokername: str,
|
brokername: str,
|
||||||
|
|
Loading…
Reference in New Issue