diff --git a/piker/accounting/_ledger.py b/piker/accounting/_ledger.py index f4cb3f38..fd7a50ff 100644 --- a/piker/accounting/_ledger.py +++ b/piker/accounting/_ledger.py @@ -211,9 +211,16 @@ class TransactionLedger(UserDict): Return entire output from ``.iter_txns()`` in a ``dict``. ''' - return { - t.tid: t for t in self.iter_txns(symcache=symcache) - } + txns: dict[str, Transaction] = {} + for t in self.iter_txns(symcache=symcache): + + if not t: + log.warning(f'{self.mod.name}:{self.account} TXN is -> {t}') + continue + + txns[t.tid] = t + + return txns def write_config(self) -> None: ''' @@ -386,7 +393,7 @@ def open_trade_ledger( account=account, mod=mod, symcache=symcache, - tx_sort=tx_sort, + tx_sort=getattr(mod, 'tx_sort', tx_sort), ) try: yield ledger diff --git a/piker/accounting/_pos.py b/piker/accounting/_pos.py index 90b179f8..1e159083 100644 --- a/piker/accounting/_pos.py +++ b/piker/accounting/_pos.py @@ -144,12 +144,11 @@ class Position(Struct): # def bep() -> float: # ... - def clearsdict(self) -> dict[str, dict]: - clears: dict[str, dict] = ppu( + def clearsitems(self) -> list[(str, dict)]: + return ppu( self.iter_by_type('clear'), as_ledger=True ) - return clears def iter_by_type( self, @@ -195,7 +194,7 @@ class Position(Struct): cumsize: float = 0 clears_since_zero: list[dict] = [] - for tid, cleardict in self.clearsdict().items(): + for tid, cleardict in self.clearsitems(): cumsize = float( # self.mkt.quantize(cumsize + cleardict['tx'].size self.mkt.quantize(cleardict['cumsize']) @@ -295,6 +294,8 @@ class Position(Struct): ) -> None: mkt: MktPair = self.mkt + now_dt: pendulum.DateTime = now() + now_str: str = str(now_dt) # NOTE WARNING XXX: we summarize the pos with a single # summary transaction (for now) until we either pass THIS @@ -303,13 +304,16 @@ class Position(Struct): t = Transaction( fqme=mkt.fqme, bs_mktid=mkt.bs_mktid, - tid='unknown', size=msg['size'], price=msg['avg_price'], cost=0, + # NOTE: special provisions required! + # - tid needs to be unique or this txn will be ignored!! + tid=now_str, + # TODO: also figure out how to avoid this! - dt=now(), + dt=now_dt, ) self.add_clear(t) @@ -342,11 +346,11 @@ class Position(Struct): Inserts are always done in datetime sorted order. ''' - added: bool = False + # added: bool = False tid: str = t.tid if tid in self._events: log.warning(f'{t} is already added?!') - return added + # return added # TODO: apparently this IS possible with a dict but not # common and probably not that beneficial unless we're also @@ -390,9 +394,9 @@ class Position(Struct): if self.expired(): return 0. - clears: list[dict] = list(self.clearsdict().values()) + clears: list[(str, dict)] = self.clearsitems() if clears: - return clears[-1]['cumsize'] + return clears[-1][1]['cumsize'] else: return 0. diff --git a/piker/accounting/calc.py b/piker/accounting/calc.py index db777140..ee349092 100644 --- a/piker/accounting/calc.py +++ b/piker/accounting/calc.py @@ -43,6 +43,7 @@ if TYPE_CHECKING: TransactionLedger, ) + def ppu( clears: Iterator[Transaction], @@ -56,7 +57,7 @@ def ppu( # new position fields inserted alongside each entry. as_ledger: bool = False, -) -> float: +) -> float | list[(str, dict)]: ''' Compute the "price-per-unit" price for the given non-zero sized rolling position. @@ -86,7 +87,8 @@ def ppu( ''' asize_h: list[float] = [] # historical accumulative size ppu_h: list[float] = [] # historical price-per-unit - ledger: dict[str, dict] = {} + # ledger: dict[str, dict] = {} + ledger: list[dict] = [] t: Transaction for t in clears: @@ -95,16 +97,10 @@ def ppu( is_clear: bool = not isinstance(clear_price, str) last_accum_size = asize_h[-1] if asize_h else 0 - accum_size = last_accum_size + clear_size + accum_size: float = last_accum_size + clear_size accum_sign = copysign(1, accum_size) - sign_change: bool = False - if accum_size == 0: - ppu_h.append(0) - asize_h.append(0) - continue - # on transfers we normally write some non-valid # price since withdrawal to another account/wallet # has nothing to do with inter-asset-market prices. @@ -170,9 +166,6 @@ def ppu( else: ppu = cost_basis / abs_new_size - # ppu_h.append(ppu) - # asize_h.append(accum_size) - else: # TODO: for PPU we should probably handle txs out # (aka withdrawals) similarly by simply not having @@ -185,8 +178,6 @@ def ppu( # need to be updated since the ppu remains constant # and gets weighted by the new size. ppu: float = ppu_h[-1] # set to previous value - # ppu_h.append(ppu_h[-1]) - # asize_h.append(accum_size) # extend with new rolling metric for this step ppu_h.append(ppu) @@ -194,13 +185,17 @@ def ppu( # ledger[t.tid] = { # 'txn': t, - ledger[t.tid] = t.to_dict() | { - 'ppu': ppu, - 'cumsize': accum_size, - 'sign_change': sign_change, + # ledger[t.tid] = t.to_dict() | { + ledger.append(( + t.tid, + t.to_dict() | { + 'ppu': ppu, + 'cumsize': accum_size, + 'sign_change': sign_change, - # TODO: cum_pnl, bep - } + # TODO: cum_pnl, bep + } + )) final_ppu = ppu_h[-1] if ppu_h else 0 # TODO: once we have etypes in all ledger entries..