Today was one of those days where the system looked correct on the surface, but the truth only showed up once I forced myself to follow the evidence all the way down.
What I worked on
I deep-dived into a strange inconsistency in Egis:
a position (ID 101) was clearly closed, yet both realised PnL and commission were missing.
At first glance, this smelled like a data bug or a sync race condition. But after building a dedicated debug command and inspecting positions-debug.log, the picture became much clearer.
I traced the entire lifecycle of the position:
- Opened correctly
- TP/SL orders existed
- Closed timestamp was set
- But no closing order was ever matched, so no closing trades were picked up
- The system silently fell back to a “minimal close” path
That fallback marked the position as closed, but intentionally left:
- realized_pnl = null
- commission = null
- close_exchange_order_id = null
So the system was honest… but dangerously quiet.
The real root cause
The bug was not in Egis’ core logic.
It was a Binance Futures edge case that slipped through our assumptions:
- When TP or SL triggers on Binance Futures, the executed order type is not MARKET
- It is TAKE_PROFIT_MARKET or STOP_MARKET
- Our closing-order matcher explicitly filtered those out
That single filter caused a chain reaction:
- Closing order not detected
- Closing trades not matched
- Realised PnL + fee never computed
- Fallback “manual_or_other” close triggered
- Position ended up closed but incomplete
The quantity-matching logic then made things worse by trusting a stale position_amt, guaranteeing the fallback path would also fail.
What I learned (important)
- Silent fallbacks are dangerousA system that “keeps going” without screaming is worse than one that crashes.
- Exchange semantics matter more than documentationBinance UI was correct. My assumptions about order types were not.
- A closed position without PnL is not “done”Closure must be treated as an invariant:closed ⇒ realised_pnl + commission + close_order_id must exist
- Debug commands are first-class toolsBuilding egis:debug:position paid off immediately.Logs beat intuition every time.
- Backfill must be intentional, not accidentalAny time the system cannot fully reconcile a close, it should:
- mark the position as needing backfill
- log structured evidence
- be repairable later in a deterministic way
Direction going forward
From this investigation, I defined clear prevention rules for Egis:
- Accept TP/SL market order types explicitly
- Resolve expected close quantity from reliable sources (open fills first)
- Never silently close a position with missing financials
- Persist “closure incomplete” state and backfill it via commands
- Treat evidence logs as part of the system, not a debugging afterthought
Today wasn’t about adding features.
It was about earning trust in the data.
And that’s the kind of progress that actually compounds.
