103: EMC Perps: propagate Phoenix TWAP warnings through the tree to Perpetual Contracts

This commit is contained in:
2026-10-26 06:38:53 +01:00
parent e71a8daa8d
commit cfb49ed896
22 changed files with 797 additions and 7696 deletions
+32 -18
View File
@@ -1,6 +1,6 @@
# Phoenix Perps read-only integration
`PhoenixPerpsService`, `PhoenixPerpsAccount`, `PhoenixPerpsPosition`, `PhoenixAccountRisk` and `PhoenixTwapOrder` live in
`PhoenixPerpsService`, `PhoenixPerpsAccount`, `PhoenixPerpsPosition`, `PhoenixAccountRisk`, `PhoenixTwapOrder` and `PhoenixTwapWarning` live in
`com.r35157.libs.phoenix.perps`; the REST implementation is in `impl.ref`.
They contain no Evelyn/UI types or signing/trading operations. NenjimHub creates
one adapter without a portfolio cache as `phoenix.perps.default` and injects it into both Evelyn
@@ -31,19 +31,21 @@ The implementation uses these official endpoints at `https://perp-api.phoenix.tr
position remains visible with unknown price-dependent metrics when the mark is absent.
A present nonpositive or malformed price still fails the lookup.
4. [`GET /v1/trader/{authority}/twap?traderPdaIndex=0`](https://github.com/Ellipsis-Labs/rise-public/blob/master/ts/src/api/traders/client.ts)
supplies active TWAP snapshots when the wallet has held positions. Only filled orders
with remaining children on matching existing positions are returned; see [TWAP observations](#twap-observations).
supplies TWAP snapshots for every wallet with existing subaccounts, including accounts
without positions. Filled outstanding orders become matched progress or warning observations;
zero-fill and completed orders remain invisible. See [TWAP observations](#twap-observations).
5. [`GET /v1/view/trader/{pubkey}`](https://docs.phoenix.trade/api/trader/get-trader)
supplies risk for each visible account, including funded empty Cross accounts.
Its key is the derived trader account, not the wallet or a TWAP key. See
[venue-reported account risk](#venue-reported-account-risk).
An empty trader state with no visible funded account needs only the first request.
A funded empty Cross account additionally needs its risk read, without market/TWAP reads.
Otherwise metadata is fetched once
and each active symbol's price once per wallet lookup, including when that symbol is
held in several subaccounts, followed by one TWAP read and each visible account's
risk read. Request starts are spaced at least one second apart across both environments to avoid
A trader state with no subaccounts needs only the first request. Otherwise TWAP is
read immediately after state, with its original response receipt time preserved.
Metadata is fetched once if there are held positions or filled outstanding TWAPs;
marks are fetched only for distinct held symbols, followed by each visible account's
risk read. Registered empty accounts without relevant TWAPs need no metadata or
marks; funded or warning-only empty Cross accounts also receive their risk read.
Request starts are spaced at least one second apart across both environments to avoid
bursts of per-market reads. Each HTTP request has a 10-second timeout and uses the
Hub's existing HTTP client (no redirects by default). On HTTP 429 the adapter respects
`Retry-After` (seconds or HTTP date; 60 seconds if missing/invalid). Further calls
@@ -93,9 +95,9 @@ following each completed cycle. Jupiter and Phoenix are attempted independently
each configured wallet. Successful results replace only that wallet/venue; failures
log wallet and venue and retain its last successful result. A valid empty result
replaces that venue's positions and account balances. EMC hides the venue heading
when it has neither position rows nor Cross accounts; its read status remains in
when it has neither position rows, Cross accounts nor TWAP warnings; its read status remains in
the wallet tooltip and the scope still contributes to snapshot totals.
Funded Cross accounts remain visible when they no longer hold positions. Snapshot reads never fetch
Funded Cross accounts and Cross accounts with eligible warnings remain visible when they no longer hold positions. Snapshot reads never fetch
external data; EMC's three-second polling remains unchanged.
Positions and prices are separate REST reads and can belong to different slots.
@@ -147,13 +149,25 @@ neutral isolated distance, venue tier colors and group summaries.
## TWAP observations
TWAP data is matched by requested authority, PDA index, subaccount and market `assetId`
using Phoenix metadata. Only an existing nonzero position can carry a TWAP, and the
order itself must have `baseLotsFilled > 0` and remaining children. A new order without
fills stays invisible even if the market already has a position. No TWAP-only row or
group total is created. A successful snapshot without that active order clears its
TWAP data. A failed or invalid TWAP read fails the whole wallet/venue observation,
using Phoenix metadata. Only an existing nonzero position carries a progressbar, but
an eligible order that cannot be matched is preserved in its account's immutable
warning list. The order itself must have `baseLotsFilled > 0` and remaining children.
A new order without fills stays invisible everywhere, even if the market already
has a position; completed orders also create no warning. No synthetic position or
monetary group total is created. A successful snapshot without that active order
clears its progress and warning data. A failed or invalid TWAP read fails the whole wallet/venue observation,
retaining the previous complete snapshot and its original timestamps as `(retained)`.
Warnings retain the TWAP address/order sequence, asset and subaccount IDs, raw
execution/fill counters and original receipt time. Missing market metadata or no
matching open position is an observed mismatch, not proof of delisting, cancellation
or stopped execution. Missing conversion data is shown as raw lots/unknown values;
warning-only markets do not trigger mark-price requests. A matched order with no
usable future next-execution estimate keeps its progress plus a timing warning.
Account/schema/counter mismatches still fail the read; valid missing-market warnings
do not discard independent positions or account risk. See the [EMC warning presentation](Evelyn.md#twap-advarsler)
for exact placement, ancestor propagation and retained/stale qualifications.
The [SDK snapshot](https://github.com/Ellipsis-Labs/rise-public/blob/master/ts/src/api/traders/twap.ts)
reports `nChildOrders` as the total execution count including dust. With explicit
`nDustOrders > 0`, regular count is total minus dust count. Legacy zero/omitted dust
@@ -184,8 +198,8 @@ EMC appends **TWAP** after uPnL. Its progressbar overlays a snapshot duration wi
unbounded total hours, such as `≈ 28:32:10` or `≈ 128:32:10`. It updates only with new
snapshots and is explicitly as of the tooltip's `Updated` time. Due/unavailable
timing shows `Due / unknown`; a failed venue shows `Retained` instead of a fresh
countdown. Other venues, positions without a relevant order and all groups have
empty TWAP cells. Tooltips show progress, `Estimated completion`, total/next/fill
countdown. Cells without relevant progress or warnings stay empty. Groups show warning
summaries when applicable, never aggregated progressbars. Tooltips show progress, `Estimated completion`, total/next/fill
quantities, different dust sizes where relevant, observation time and limitations.
Total and next-child USD values reuse that position's already fetched Phoenix mark,