`ib`: only process ledger-txs once per client
Previous we were re-processing all ledgers for every position msg received from the API, per client.. Instead do that once in a first pass and drop all key-miss lookups for `bs_mktid`s; it should never happen. Better typing for in-routine vars, convert pos msg/objects to `dict` prior to logging so it's sane to read on console. Skip processing specifically option contracts for now.pre_overruns_ctxcancelled
parent
f0d181e3f7
commit
c3686185c1
|
@ -38,6 +38,7 @@ from trio_typing import TaskStatus
|
|||
import tractor
|
||||
from ib_insync.contract import (
|
||||
Contract,
|
||||
Option,
|
||||
)
|
||||
from ib_insync.order import (
|
||||
Trade,
|
||||
|
@ -88,14 +89,17 @@ from .api import (
|
|||
def pack_position(
|
||||
pos: IbPosition
|
||||
|
||||
) -> dict[str, Any]:
|
||||
) -> tuple[
|
||||
str,
|
||||
dict[str, Any]
|
||||
]:
|
||||
|
||||
con = pos.contract
|
||||
fqsn, calc_price = con2fqsn(con)
|
||||
|
||||
# TODO: options contracts into a sane format..
|
||||
return (
|
||||
con.conId,
|
||||
str(con.conId),
|
||||
BrokerdPosition(
|
||||
broker='ib',
|
||||
account=pos.account,
|
||||
|
@ -383,20 +387,19 @@ async def update_and_audit_msgs(
|
|||
# raise ValueError(
|
||||
log.error(
|
||||
f'POSITION MISMATCH ib <-> piker ledger:\n'
|
||||
f'ib: {ibppmsg}\n'
|
||||
f'piker: {msg}\n'
|
||||
f'reverse_split_ratio: {reverse_split_ratio}\n'
|
||||
f'split_ratio: {split_ratio}\n\n'
|
||||
'FIGURE OUT WHY TF YOUR LEDGER IS OFF!?!?\n\n'
|
||||
'If you are expecting a (reverse) split in this '
|
||||
'instrument you should probably put the following '
|
||||
'instrument you should probably put the following\n\n'
|
||||
f'in the `pps.toml` section:\n{entry}'
|
||||
f'IB:\nm{ibppmsg.to_dict()}\n\n'
|
||||
f'PIKER:\n{msg.to_dict()}\n\n'
|
||||
# f'reverse_split_ratio: {reverse_split_ratio}\n'
|
||||
# f'split_ratio: {split_ratio}\n\n'
|
||||
)
|
||||
msg.size = ibsize
|
||||
|
||||
if ibppmsg.avg_price != msg.avg_price:
|
||||
|
||||
# TODO: make this a "propoganda" log level?
|
||||
# TODO: make this a "propaganda" log level?
|
||||
log.warning(
|
||||
'The mega-cucks at IB want you to believe with their '
|
||||
f'"FIFO" positioning for {msg.symbol}:\n'
|
||||
|
@ -425,10 +428,10 @@ async def update_and_audit_msgs(
|
|||
if validate and p.size:
|
||||
# raise ValueError(
|
||||
log.error(
|
||||
f'UNEXPECTED POSITION says ib:\n'
|
||||
f'piker: {msg}\n'
|
||||
f'UNEXPECTED POSITION says IB:\n'
|
||||
'YOU SHOULD FIGURE OUT WHY TF YOUR LEDGER IS OFF!?\n'
|
||||
'THEY LIQUIDATED YOU OR YOUR MISSING LEDGER RECORDS!?'
|
||||
'THEY LIQUIDATED YOU OR YOUR MISSING LEDGER RECORDS!?\n'
|
||||
f'PIKER:\n{msg.to_dict()}\n'
|
||||
)
|
||||
msgs.append(msg)
|
||||
|
||||
|
@ -611,6 +614,8 @@ async def trades_dialogue(
|
|||
# api clients which report trades for **this session**.
|
||||
trades = await proxy.trades()
|
||||
if trades:
|
||||
trans_by_acct: dict[str, Transaction]
|
||||
api_to_ledger_entries: dict[str, dict]
|
||||
(
|
||||
trans_by_acct,
|
||||
api_to_ledger_entries,
|
||||
|
@ -637,17 +642,30 @@ async def trades_dialogue(
|
|||
if trans:
|
||||
table.update_from_trans(trans)
|
||||
|
||||
trans = norm_trade_records(ledger)
|
||||
table.update_from_trans(trans)
|
||||
|
||||
# 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
|
||||
# -> collect all ib-pp reported positions so that we can be
|
||||
# sure know which positions to update from the ledger if
|
||||
# any are missing from the ``pps.toml``
|
||||
pos: IbPosition # named tuple actually
|
||||
for pos in client.positions():
|
||||
# collect all ib-pp reported positions so that we can be
|
||||
# sure know which positions to update from the ledger if
|
||||
# any are missing from the ``pps.toml``
|
||||
bs_mktid, msg = pack_position(pos)
|
||||
|
||||
# NOTE XXX: we skip options for now since we don't
|
||||
# yet support the symbology nor the live feeds.
|
||||
if isinstance(pos.contract, Option):
|
||||
log.warning(
|
||||
f'Option contracts not supported for now:\n'
|
||||
f'{pos._asdict()}'
|
||||
)
|
||||
continue
|
||||
|
||||
bs_mktid, msg = pack_position(pos)
|
||||
acctid = msg.account = accounts_def.inverse[msg.account]
|
||||
acctid = acctid.strip('ib.')
|
||||
cids2pps[(acctid, bs_mktid)] = msg
|
||||
|
@ -663,29 +681,6 @@ async def trades_dialogue(
|
|||
not pp
|
||||
or pp.size != msg.size
|
||||
):
|
||||
trans = norm_trade_records(ledger)
|
||||
table.update_from_trans(trans)
|
||||
|
||||
# XXX: not sure exactly why it wouldn't be in
|
||||
# the updated output (maybe this is a bug?) but
|
||||
# if you create a pos from TWS and then load it
|
||||
# from the api trades it seems we get a key
|
||||
# error from ``update[bs_mktid]`` ?
|
||||
pp = table.pps.get(bs_mktid)
|
||||
if not pp:
|
||||
log.error(
|
||||
f'The contract id for {msg} may have '
|
||||
f'changed to {bs_mktid}\nYou may need to '
|
||||
'adjust your ledger for this, skipping '
|
||||
'for now.'
|
||||
)
|
||||
continue
|
||||
|
||||
# XXX: not sure exactly why it wouldn't be in
|
||||
# the updated output (maybe this is a bug?) but
|
||||
# if you create a pos from TWS and then load it
|
||||
# from the api trades it seems we get a key
|
||||
# error from ``update[bs_mktid]`` ?
|
||||
pp = table.pps[bs_mktid]
|
||||
pairinfo = pp.symbol
|
||||
if msg.size != pp.size:
|
||||
|
|
Loading…
Reference in New Issue