147 lines
5.4 KiB
Markdown
147 lines
5.4 KiB
Markdown
# Clearing And Ledger Gotchas
|
|
|
|
## Trade dialog dies immediately after a fill
|
|
|
|
Likely cause: an explicit ledger/account write in the fill handler, or
|
|
a later context-exit write, raised after event publication.
|
|
|
|
Inspect, in order:
|
|
|
|
1. the first non-cancellation exception in the actor traceback;
|
|
2. `PaperBoi.fake_fill()` or the live backend fill handler;
|
|
3. explicit and context-exit `write_config()` calls;
|
|
4. FQME/`bs_mktid` qualification and TOML-compatible values;
|
|
5. the persisted ledger/account files for a partial update.
|
|
|
|
Tractor cancellation logs are often the consequence. Root-cause the
|
|
inner serialization, lookup, or normalization exception first.
|
|
|
|
## `MktPair` has no `len()` in RapidFuzz
|
|
|
|
Cause: a mapping of string keys to `MktPair` values was passed directly
|
|
to `rapidfuzz.process.extract()`. Mapping values become fuzzy choices.
|
|
|
|
Fix: search a list/view of string keys and resolve matched keys back
|
|
through the original mapping. Do not add sequence methods to `MktPair`
|
|
and do not use `processor=str` when aliases must be preserved.
|
|
|
|
## Fuzzy qualification raises `IndexError`
|
|
|
|
Cause: the caller selected the first match from an empty result after
|
|
the score cutoff rejected every key.
|
|
|
|
Decide explicitly whether to retain the input identity, reject the
|
|
record with a descriptive exception, or obtain missing market metadata.
|
|
Do not lower the cutoff blindly; the wrong market corrupts accounting.
|
|
|
|
## Cancel is ignored or sent with the wrong ID
|
|
|
|
Cause: confusion between client `oid` and backend `reqid`, commonly
|
|
during cancel-before-ack ordering.
|
|
|
|
Verify the ack installed both mapping directions and that
|
|
`Status.cancel_called` survives until `reqid` exists. Log both IDs and
|
|
the actor/backend account at every transition.
|
|
|
|
## Fills appear but positions do not move
|
|
|
|
Check these boundaries:
|
|
|
|
- the backend emitted `BrokerdFill` but never normalized a transaction;
|
|
- transaction size lost its buy/sell sign;
|
|
- `tid` collided with an existing position event;
|
|
- `Transaction.bs_mktid` selected a different `Account.pps` key;
|
|
- `mktmaps` lacked the exact transaction identity;
|
|
- position publication happened before accounting update;
|
|
- the backend intentionally reports venue positions instead of local
|
|
ledger-derived positions.
|
|
|
|
## Duplicate or inflated position size
|
|
|
|
Do not deduplicate by price/time alone. Confirm stable transaction IDs,
|
|
chronological sorting, and `Position.add_clear()` idempotence. Broker
|
|
execution IDs and order IDs are not interchangeable.
|
|
|
|
For partial fills, several `tid`s may correctly share one order
|
|
`reqid`. Collapsing them loses clears; replaying one `tid` twice
|
|
inflates nothing only if the dedupe boundary is preserved.
|
|
|
|
Current paper fills use `tid=oid`, so later partials overwrite the
|
|
ledger record and are deduplicated out of the position. Treat paper
|
|
partial fills as broken until each clear receives a stable unique ID.
|
|
|
|
## Paper and live state disagree
|
|
|
|
Paper uses normalized local transactions and can use the full FQME as
|
|
its account position key. A live backend may use native IDs, raw ledger
|
|
records, or venue-reported positions.
|
|
|
|
Compare normalized `Transaction`s and emitted `BrokerdPosition`s, not
|
|
raw TOML dictionaries across backends.
|
|
|
|
## Account appears under the wrong name
|
|
|
|
Separate UI/EMS account aliases from backend account IDs and ledger file
|
|
names. Backends may prefix account names for routing while persistence
|
|
uses an unprefixed native account key.
|
|
|
|
Trace account identity through `open_ems()`, broker dialog startup,
|
|
ledger opening, and `BrokerdPosition.account` before changing naming.
|
|
|
|
## A module-global cache is unexpectedly empty
|
|
|
|
Symcache, clients, contracts, and order tables are actor-local. Data
|
|
loaded in `datad` is not automatically available in `brokerd` or
|
|
`paperboi`. Also, `_symcache._caches` is currently read but never
|
|
populated, so do not assume repeated `open_symcache()` calls hit it.
|
|
|
|
Load `piker-conc-expert` and audit actor-local globals, async caches,
|
|
and dialog startup warming. Never rely on an import side effect from a
|
|
sibling actor.
|
|
|
|
## Teardown emits a cancellation storm
|
|
|
|
Find the first application exception. Structured cancellation then
|
|
closes feed streams, broker streams, and nested contexts. Avoid masking
|
|
the originating exception with broad cancellation handling.
|
|
|
|
For stream ownership and context cancellation semantics, use
|
|
`piker-conc-expert`.
|
|
|
|
## Broker status is logged as unhandled
|
|
|
|
EMS currently accepts only ack-correlated `open`, `closed`, and
|
|
`canceled` broker statuses. Declared `pending` and backend-produced
|
|
`fill`/`filled` variants fall through, as do statuses arriving before
|
|
ack. Verify producer vocabulary and ack ordering before adding another
|
|
consumer branch.
|
|
|
|
## Another client sees order or position events
|
|
|
|
Current translation broadcasts order updates by FQME and positions to
|
|
all attached clients; `Router.dialogs` is not used as an event privacy
|
|
filter. Treat subscriber isolation as incomplete, not guaranteed.
|
|
|
|
## Debug breadcrumb
|
|
|
|
Capture one row per event with:
|
|
|
|
```text
|
|
actor, backend, account, fqme, bs_mktid,
|
|
oid, reqid, venue_order_id, tid,
|
|
message_type, status, action, signed_size, price, timestamp
|
|
```
|
|
|
|
Then compare:
|
|
|
|
1. client command order;
|
|
2. EMS status history;
|
|
3. broker event order;
|
|
4. normalized transactions;
|
|
5. position event IDs and computed size/PPU;
|
|
6. ledger/account disk state;
|
|
7. emitted position summaries.
|
|
|
|
This separates protocol loss, identity skew, accounting math, and
|
|
persistence failure without guessing from UI state.
|