Better doc strings and detailed comments

lifo_pps_ib
Tyler Goodlet 2022-06-11 16:18:05 -04:00
parent ce1eb11b59
commit de77c7d209
2 changed files with 50 additions and 13 deletions

View File

@ -312,9 +312,14 @@ async def trades_dialogue(
accounts.add(account) accounts.add(account)
pp_msgs = {} pp_msgs = {}
# process pp value reported from ib's system. we only use these
# to cross-check sizing since average pricing on their end uses
# the so called (bs) "FIFO" style which more or less results in
# a price that's not useful for traders who want to not lose
# money.. xb
for client in aioclients.values(): for client in aioclients.values():
for pos in client.positions(): for pos in client.positions():
msg = pack_position(pos) msg = pack_position(pos)
msg.account = accounts_def.inverse[msg.account] msg.account = accounts_def.inverse[msg.account]
pp_msgs[msg.symbol] = msg pp_msgs[msg.symbol] = msg
@ -322,8 +327,14 @@ async def trades_dialogue(
assert msg.account in accounts, ( assert msg.account in accounts, (
f'Position for unknown account: {msg.account}') f'Position for unknown account: {msg.account}')
# built-out piker pps from trade ledger, underneath using
# LIFO style breakeven pricing calcs.
trades_by_account: dict = {} trades_by_account: dict = {}
conf = get_config() conf = get_config()
# retreive new trade executions from the last session
# and/or day's worth of trading and convert into trade
# records suitable for a local ledger file.
for proxy in proxies.values(): for proxy in proxies.values():
trade_entries = await proxy.trades() trade_entries = await proxy.trades()
records = trades_to_records( records = trades_to_records(
@ -332,18 +343,27 @@ async def trades_dialogue(
) )
trades_by_account.update(records) trades_by_account.update(records)
# write recent session's trades to the user's (local) ledger
# file.
for acctid, trades_by_id in trades_by_account.items(): for acctid, trades_by_id in trades_by_account.items():
with config.open_trade_ledger('ib', acctid) as ledger: with config.open_trade_ledger('ib', acctid) as ledger:
ledger.update(trades_by_id) ledger.update(trades_by_id)
# (incrementally) update the user's pps in mem and
# in the `pps.toml`.
records = norm_trade_records(trades_by_id) records = norm_trade_records(trades_by_id)
active = update_pps_conf('ib', acctid, records) active = update_pps_conf('ib', acctid, records)
# relay re-formatted pps as msgs to the ems.
for fqsn, pp in active.items(): for fqsn, pp in active.items():
ibppmsg = pp_msgs[fqsn.rstrip('.ib')] ibppmsg = pp_msgs[fqsn.rstrip('.ib')]
msg = BrokerdPosition( msg = BrokerdPosition(
broker='ib', broker='ib',
# account=acctid + '.ib', # account=acctid + '.ib',
# XXX: ok so this is annoying, we're relaying
# an account name with the backend suffix prefixed
# but when reading accounts from ledgers
account=ibppmsg.account, account=ibppmsg.account,
# XXX: the `.ib` is stripped..? # XXX: the `.ib` is stripped..?
symbol=ibppmsg.symbol, symbol=ibppmsg.symbol,
@ -614,6 +634,7 @@ def norm_trade_records(
def trades_to_records( def trades_to_records(
accounts: bidict, accounts: bidict,
trade_entries: list[object], trade_entries: list[object],
source_type: str = 'api', source_type: str = 'api',

View File

@ -21,7 +21,6 @@ that doesn't try to cuk most humans who prefer to not lose their moneys..
''' '''
from typing import ( from typing import (
Any,
Optional, Optional,
Union, Union,
) )
@ -153,14 +152,15 @@ def update_pps(
Compile a set of positions from a trades ledger. Compile a set of positions from a trades ledger.
''' '''
pps: dict[str, Position] = pps or {} pps: dict[str, Position] = pps or {}
# lifo update all pps from records # lifo update all pps from records
for r in records: for r in records:
key = r.fqsn or r.symkey
pp = pps.setdefault( pp = pps.setdefault(
key, r.fqsn or r.symkey,
# if no existing pp, allocate fresh one.
Position( Position(
Symbol.from_fqsn( Symbol.from_fqsn(
r.fqsn, r.fqsn,
@ -173,6 +173,11 @@ def update_pps(
# don't do updates for ledger records we already have # don't do updates for ledger records we already have
# included in the current pps state. # included in the current pps state.
if r.tid in pp.fills: if r.tid in pp.fills:
# NOTE: likely you'll see repeats of the same
# ``TradeRecord`` passed in here if/when you are restarting
# a ``brokerd.ib`` where the API will re-report trades from
# the current session, so we need to make sure we don't
# "double count" these in pp calculations.
continue continue
# lifo style average price calc # lifo style average price calc
@ -187,7 +192,16 @@ def _split_active(
pps: dict[str, Position], pps: dict[str, Position],
) -> tuple[dict, dict]: ) -> tuple[dict, dict]:
'''
Split pps into those that are "active" (non-zero size) and "closed"
(zero size) and return in 2 dicts.
Returning the "closed" set is important for updating the pps state
in any ``pps.toml`` such that we remove entries which are no longer
part of any "VaR" set (well presumably, except of course your liquidity
asset could be full of "risk" XD ).
'''
active = {} active = {}
closed = {} closed = {}
@ -207,8 +221,14 @@ def load_pps_from_ledger(
brokername: str, brokername: str,
acctname: str, acctname: str,
) -> dict[str, Any]: ) -> tuple[dict, dict]:
'''
Open a ledger file by broker name and account and read in and
process any trade records into our normalized ``TradeRecord``
form and then pass these into the position processing routine
and deliver the two dict-sets of the active and closed pps.
'''
with config.open_trade_ledger( with config.open_trade_ledger(
brokername, brokername,
acctname, acctname,
@ -217,10 +237,8 @@ def load_pps_from_ledger(
brokermod = get_brokermod(brokername) brokermod = get_brokermod(brokername)
records = brokermod.norm_trade_records(ledger) records = brokermod.norm_trade_records(ledger)
pps = update_pps( pps = update_pps(brokername, records)
brokername,
records,
)
return _split_active(pps) return _split_active(pps)
@ -282,14 +300,12 @@ def update_pps_conf(
config.write( config.write(
conf, conf,
'pps', 'pps',
# TODO: make nested tables and/or inline tables work?
# encoder=config.toml.Encoder(preserve=True), # encoder=config.toml.Encoder(preserve=True),
) )
return active return active
# from pprint import pprint
# pprint(conf)
if __name__ == '__main__': if __name__ == '__main__':
update_pps_conf('ib', 'algopaper') update_pps_conf('ib', 'algopaper')