102: EMC Perps: show liquidation risk and account health

This commit is contained in:
2026-10-26 06:05:26 +01:00
parent 2f30712004
commit e71a8daa8d
30 changed files with 1070 additions and 48 deletions
+62 -5
View File
@@ -445,7 +445,9 @@ og alarmer beholder deres afhængigheder og cache.
Servicen læser asynkront ved start og venter 60 sekunder efter hvert fuldført gennemløb.
Runder overlapper ikke og afhænger ikke af EMC's synlighed. Jupiter-overblikket bruger
ét REST-opslag pr. wallet. Phoenix bruger trader-state, metadata, én mark price pr.
unikt åbent marked og ét TWAP-opslag, når der er positioner. Begge har 10 sekunders request-timeout; Phoenix bevarer fælles
unikt åbent marked, ét TWAP-opslag, når der er positioner, og et risikolæs pr. synlig
konto. Lokal trader-adresseafledning bruger den eksisterende Solana-afhængighed.
Begge har 10 sekunders request-timeout; Phoenix bevarer fælles
pacing og 429-cooldown. En fuld opdatering tager opslagstid plus pausen, ikke nødvendigvis
ét minut. Implementeringens `close()` afbryder worker'en; consumer-API'et har kun læsning.
@@ -457,7 +459,7 @@ oprindelige succes-tidspunkt. Andre wallets/venues forsøges stadig. Et gyldigt
rydder den pågældende scope og kan totalisere nul; HTTP-/formatfejl kan ikke. En gyldig
Cross-konto med kapital bevares, selv om dens sidste position lukkes.
EMC viser **Position | Direction | Margin | Collateral | Leverage | Exposure | Value | uPnL | TWAP**
EMC viser **Position | Risk | Direction | Margin | Collateral | Leverage | Exposure | Value | uPnL | TWAP**
under den synlige rod **Perpetual Contracts**. Isolerede positioner har wallet → venue →
position; Phoenix Cross har wallet → venue → Cross → position. Positionens konto-ID
bestemmer identitet og tilhørsforhold, aldrig instrumentteksten. Wallets følger den
@@ -465,7 +467,8 @@ hidtidige konfiguration med Jupiter før Phoenix. En venue uden positioner eller
skjules og vises igen, når der kommer indhold. Skjulte venues indgår fortsat i snapshot
og totaler; deres læsestatus findes på wallet-rækkens tooltip. En Cross-konto med kapital
holder derfor Phoenix synlig, selv uden åbne positioner. Eksisterende foldestatus, markering og
rækkeobjekter bevares; uændrede snapshots opdaterer ikke træet. Vinduesstart er 1100 × 600,
rækkeobjekter bevares; kun ændrede rækkeværdier eller børn opdateres, også når risikodata
ældes i et ellers uændret snapshot. Vinduesstart er 1100 × 600,
og smallere vinduer kan scrolle vandret, når kolonnernes minimumsbredder kræver det.
TWAP vises kun på en eksisterende Phoenix-position, når ordren selv har et faktisk
@@ -493,8 +496,8 @@ positiv Collateral. På Cross-positioner er Collateral et initialt marginkrav i
ikke særskilt ejet kapital. Cross-gruppens leverage er bruttoeksponering / udiskonteret
equity før estimerede exitgebyrer. Cross-positionernes leverage og ROI-procent er
utilgængelige, fordi Phoenix-konventionerne ikke er verificeret; dollar-uPnL vises.
Cross-positioners Value er ikke entydigt defineret og vises som —. Kontoudnyttelse er
ikke implementeret.
Cross-positioners Value er ikke entydigt defineret og vises som —. Risk viser særskilt
vedligeholdelsesmarginens udnyttelse; det er ikke samlet initial-marginudnyttelse eller fri købekraft.
Value er et estimat ved referencepriser, ikke et eksekverbart tilbud. Phoenix medregner
collateral, pris-uPnL og signed uafregnet funding og fratrækker estimerede takergebyrer
@@ -515,5 +518,59 @@ på wallet-rækkens tooltip. Gamle tal beskrives ikke som nye.
EMC spørger hver miljøservice straks ved åbning og hvert tredje sekund uden at blokere
JavaFX-tråden. Skjul/luk stopper kun EMC-polling. Der er ingen sample-data, Refresh-knap,
handel, signering, kontoaktivering eller automatisk genstart af Hub'en i denne læsevej.
### Risiko i Perps
Risk står ved positionsnavnet og bruger tekst og en statusprik, mens Long/Short-
baggrundene bevares. På isolerede positioner vises rapporteret likvideringsafstand:
```text
Long: 100 × (venue-referencepris − likvideringspris) / venue-referencepris
Short: 100 × (likvideringspris − venue-referencepris) / venue-referencepris
```
Ejeren valgte 24. oktober 2026 **neutral positiv afstand og rød ved nået/overskredet
grænse**. Der er ingen generelle grøn/gul/rød-grænser pr. marked. Positiv uPnL eller
lav leverage tildeler ikke en sikkerhedsstatus. Negativ afstand bevarer fortegnet;
det er en observeret grænseoverskridelse, ikke bevis for gennemført likvidering.
Manglende, nul og negative sentinel-priser er ukendte, ikke uendelig sikkerhed.
Tooltip viser venue-priser, præcis afstand, eventuel rapporteret tier og observationstid.
Phoenix' egne tiers bruger grøn **OK**, gul **At risk**, orange **Cancellable** og
rød **Liquidatable**, **Backstop** eller **High risk**. En selvstændigt gyldig
kontoklasse kan bruges, selv om en positiv likvideringspris mangler. På Cross-kontoen:
```text
MM utilization = 100 × maintenance margin / positiv effective collateral
USD headroom = effective collateral − maintenance margin
```
MM er marginudnyttelse, ikke likvideringssandsynlighed eller en prisafstand. Phoenix'
præcise tier styrer likvideringsstatus; visningsafrunding bruges ikke til klassifikation.
Ved ikke-positiv effektiv sikkerhed er procenten utilgængelig. En kendt tom konto
uden vedligeholdelseskrav vises som **No positions**; det lover ikke noget om fremtidige
ordrefills. Manglende nødvendige data eller modstridende
Safe-data må ikke vises grønt. Cross-positioner viser **Shared** med konto-ID i tooltip,
og kontoens risiko tælles kun én gang uanset antallet af positioner.
Grupper viser værste kendte risiko og antal ukendte/forældede scopes uden gennemsnit
af afstande eller MM-procenter. En neutral afstand gør ikke hele gruppen grøn; **Distance
only** angiver, at der ikke er tildelt en sikkerhedsklasse. Før første succes er en
venue ukendt. En tidligere tom venue kan også blive forældet, selv om dens overskrift
er skjult. Kendt kritisk risiko forbliver rød med usikkerhedsmarkering efter fejl/aldring.
Risikodata bliver **Stale** ved fem minutter fra ældste nødvendige observation,
straks ved venue- eller snapshot-læsefejl eller ved et fremtidigt tidsstempel. Også
et fejlet `getPositionsSnapshot()` genviser den beholdte observation med fejlstatus.
Fem minutter er en grænse
for datakvalitet, ikke en garanti for sikkerhed i perioden. Langsomme normale runder
kan derfor give Stale. Den eksisterende tresekunders UI-polling genvurderer alder,
også når servicen returnerer samme snapshot, uden en ny timer eller flere venue-kald.
Forældet eller ufuldstændig ikke-kritisk risiko får ingen grøn statusprik.
Tidsstempler er modtagelsestider; API-lag og separate pris-/kontolæs begrænser aktualiteten.
Visningen viser senest observeret risiko og er ikke en livealarm. Datakilderne er
beskrevet i [Jupiter-overblikket](JupiterPerpsOverview.md) og
[Phoenix-risikolæsningen](PhoenixPerps.md#venue-reported-account-risk).
Den kanoniske systembeskrivelse findes i
[Evelyn: services og status](../../r35157_docs/projects/evelyn/README.md#evelynperpsservice).
+10
View File
@@ -26,12 +26,22 @@ amounts fail the read.
| uPnL | `pnlBeforeFeesUsd / 10^6`, price PnL before separately reported fees |
| uPnL percent | 100 × uPnL / positive Collateral |
| Value | Unavailable; API net-value semantics have not passed verification |
| Risk reference price | Positive `markPriceUsd / 10^6` from the same response |
| Reported liquidation price | Positive `liquidationPriceUsd / 10^6`; missing/nonpositive values are unavailable |
All amounts are parsed as decimal integers and converted exactly. The API's
`pnlBeforeFeesPct` is already percentage points (95.48 means 95.48%), but the
overview derives the requested percentage against precise collateral itself.
The API's rounded `leverage` is likewise not used for the derived ratio.
The overview preserves one original response observation time on all positions.
It does not treat a position's `updatedTime` as proof of current price freshness.
Risk uses the venue's reported prices, with no new liquidation-price formula or
Ticker dependency. Missing/sentinel prices retain the position and its independent
metrics. Present malformed amounts still fail the read. Isolated signed distance,
the owner's neutral-distance policy and expiration are described in
[Perps risk presentation](Evelyn.md#risiko-i-perps).
## Why API Value is not displayed
On 24 October 2026 the funded configured wallet's six API sizes and collateral
+52 -6
View File
@@ -1,10 +1,12 @@
# Phoenix Perps read-only integration
`PhoenixPerpsService`, `PhoenixPerpsAccount`, `PhoenixPerpsPosition` and `PhoenixTwapOrder` live in
`PhoenixPerpsService`, `PhoenixPerpsAccount`, `PhoenixPerpsPosition`, `PhoenixAccountRisk` and `PhoenixTwapOrder` 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
Perps processes. Each process owns its own wallet list, refresh worker and snapshot.
The adapter also receives the existing `SolanaBlockChain` for local trader PDA
derivation only; risk lookup does not use its RPC or signing operations.
See [Evelyn](Evelyn.md#12-perps-service-og-mission-control) for consumer behavior and
[the canonical system overview](../../r35157_docs/projects/evelyn/README.md#evelynperpsservice)
for configuration and deployment status.
@@ -31,10 +33,17 @@ The implementation uses these official endpoints at `https://perp-api.phoenix.tr
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).
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 needs only the first request. Otherwise metadata is fetched once
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. Request starts are spaced at least one second apart across both environments to avoid
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
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
@@ -92,13 +101,49 @@ external data; EMC's three-second polling remains unchanged.
Positions and prices are separate REST reads and can belong to different slots.
This is a periodic current-notional estimate, not an atomic exchange valuation.
A cycle's duration includes all sequential reads and request pacing before the
60-second pause (32 active markets need at least about 34 seconds for their reads). Failed
60-second pause (32 active markets and one visible account need at least about 35 seconds for their reads). Failed
reads can leave old data visible indefinitely. A visible venue shows `(retained)` after
a failed refresh; cell tooltips include the last-success time. Childless venues are hidden,
with failed or pending first-read status available in their wallet's tooltip. Such unknown
scopes cannot contribute fabricated zero totals.
Trader PDA indices other than 0, streaming and position management are out of scope.
## Venue-reported account risk
The [official address derivation](https://github.com/Ellipsis-Labs/rise-public/blob/master/ts/src/pdas.ts)
uses program `EtrnLzgbS7nMMy5fbD42kXiUzGg8XQzJ972Xtk1cjWih` and seeds
`trader`, authority bytes, a one-byte PDA index and a one-byte subaccount index.
The adapter uses the existing local Solana derivation, validates the returned
authority/trader key/PDA/subaccount, and verifies the nonzero position membership
and signed quantities against trader state. A fill during the separate reads can
therefore cause a retained failed observation rather than attach risk to mismatched
position state. Lookup works without any active TWAP.
TraderView returns `riskState`, `riskTier`, `effectiveCollateral`,
`maintenanceMargin` and position `liquidationPrice`. The actual deployed amount
objects contain integer `value` and `decimals`; the reader computes exact decimal
amounts with decimal exponents from -18 through 18 and ignores formatted `ui` strings.
Positive liquidation prices are
retained; `-1`, zero, other nonpositive values and absent prices are unavailable.
They are not zero risk or infinite safety. Optional missing fields and unsupported
future tiers cannot silently become Safe. Malformed amounts, identity mismatches
and rejected HTTP reads fail the complete wallet/venue observation.
Cross risk belongs to the shared account. The reported effective collateral can
include funding, discounted positive PnL and collateral haircuts; it is distinct
from the overview's undiscounted equity and estimated closing Value. Risk therefore
can be available even where the older capital valuation cannot value spot collateral.
The reported thresholds and tier are preserved without inventing a liquidation engine.
See [Phoenix account health](https://docs.phoenix.trade/phoenix/margin-and-risk/account-health)
and [margin math](https://docs.phoenix.trade/phoenix/margin-and-risk/margin-math).
Account risk carries its original response receipt time. Isolated risk combines
that account's reported liquidation price with its already fetched Phoenix mark;
its observation time is the older receipt. Prices and account data are separate
reads and can lag the chain. Existing failures retain original timestamps. The
[Risk presentation](Evelyn.md#risiko-i-perps) defines five-minute expiration,
neutral isolated distance, venue tier colors and group summaries.
## TWAP observations
TWAP data is matched by requested authority, PDA index, subaccount and market `assetId`
@@ -202,8 +247,9 @@ venue's displayed conventions have not been verified; the UI explains this and
shows dollar PnL. Isolated leverage/ROI use actual collateral. Cross position
Value is inapplicable; Cross account Value counts all shared capital once,
including free collateral when its last position closes. Other aggregate ratios
are blank. No account margin-utilization percentage is claimed; orders/risk
adjustments are not included in such a metric.
are blank. Risk separately displays reported maintenance-margin utilization
against effective collateral. It is not total initial-margin utilization, free
buying power or the ratio used for the Leverage column.
Value is an estimate at separately read reference prices, not an executable quote.
Slippage, price impact, swaps, network fees, account rent, future funding and