99: Add read-only Phoenix Perps positions to EvelynPerpsService
This commit is contained in:
+25
-12
@@ -436,24 +436,37 @@ Price Index beregnes og vises, mens de øvrige fem felter fortsat er nul. Legacy
|
||||
|
||||
`EvelynPerpsService` udleverer et immutable `PerpsSnapshot` gennem det parameterløse
|
||||
`getPositionsSnapshot()`. Læsning foretager ingen integrationskald. Hub'en starter separate processer
|
||||
`evelyn.perps.prod` og `evelyn.perps.test` og injicerer de tilsvarende eksisterende `JupiterPerpsService`-views.
|
||||
`evelyn.perps.prod` og `evelyn.perps.test`, injicerer de tilsvarende eksisterende `JupiterPerpsService`-views
|
||||
og en fælles `PhoenixPerpsService` uden positionscache registreret som `phoenix.perps.default`.
|
||||
`PerpsWalletConfiguration` indeholder en `SolanaWalletId`-adresse, der også bruges som række-ID og label.
|
||||
Hub'en ejer de hardcodede lister: seks PROD-adresser og én TEST-adresse fra issue #98.
|
||||
Begge integrationer læser de samme wallets i det pågældende miljø.
|
||||
|
||||
Servicen henter åbne Jupiter-positioner asynkront ved start og venter 60 sekunder efter hvert gennemløb,
|
||||
så runder ikke overlapper. Den eksisterende Solana-cache med 60 sekunders TTL bevares. Data er derfor ikke
|
||||
øjeblikkelige børsdata. Positionskontoen er stabilt ID; retning og `positionSize()` vises, kendte mints
|
||||
bliver SOL-PERP/BTC-PERP/ETH-PERP, og ukendte mints vises som adressen. Positioner sorteres efter konto.
|
||||
Servicen henter åbne Jupiter- og Phoenix-positioner asynkront ved start og venter 60 sekunder efter hvert
|
||||
fuldført gennemløb, så runder ikke overlapper. Den eksisterende Solana-cache med 60 sekunders TTL bevares
|
||||
for Jupiter. Phoenix læses gennem REST med 10 sekunders timeout pr. request, mindst ét sekund mellem
|
||||
request-start på tværs af miljøer og fælles cooldown ved HTTP 429. Data er periodiske snapshots.
|
||||
|
||||
Før første vellykkede opslag er der ingen positioner. Hver wallets succes publiceres i et nyt snapshot;
|
||||
fejl logges og bevarer den wallets sidste data uden at afbryde de øvrige. Et vellykket tomt svar fjerner
|
||||
positionerne, men bevarer wallet/Jupiter-gruppen. Der vises ingen indikator for forældede data.
|
||||
Implementationens `close()` afbryder worker'en; consumer-API'et indeholder kun læsning.
|
||||
Jupiters positionskonto er stabilt ID; retning og `positionSize()` vises, kendte mints bliver
|
||||
SOL-PERP/BTC-PERP/ETH-PERP, og ukendte mints vises som adressen. Positioner sorteres efter konto.
|
||||
Phoenix bruger authority-wallet og trader PDA index 0 med alle returnerede cross/isolated-subaccounts.
|
||||
Kun nonzero-positioner medtages. ID og sortering bygger på PDA-index, subaccount-index og markedssymbol;
|
||||
sekvensnumre indgår ikke. Retningen kommer fra signed quantity, label er fx SOL-PERP, og USD-størrelsen er
|
||||
absolut base-mængde gange mark price, beregnet med decimalpræcision. Se [Phoenix-integrationen](PhoenixPerps.md)
|
||||
for dokumenterede enheder, endpoints og begrænsninger.
|
||||
|
||||
Før første vellykkede opslag er der ingen positioner. Succes publiceres i et nyt snapshot pr. wallet/venue;
|
||||
fejl logges og bevarer netop den kombinations sidste data. De øvrige venues og wallets forsøges stadig.
|
||||
Et vellykket tomt svar fjerner kun den pågældende venues positioner og bevarer gruppen.
|
||||
Fejl i HTTP, authentication, svarformat eller konvertering er ikke tomme porteføljer.
|
||||
Der vises ingen indikator for forældede data. Implementationens `close()` afbryder worker'en;
|
||||
consumer-API'et indeholder kun læsning.
|
||||
|
||||
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; services fortsætter. Træstruktur, tre kolonner, farver, formatering,
|
||||
foldestatus og markering bevares for eksisterende rækker. Nye/lukkede positioner afstemmes efter ID.
|
||||
Der er ingen sample-positioner, Phoenix-eksempler, sample-tekster, Refresh-knap eller handel.
|
||||
Skjul/luk stopper kun EMC-polling; services fortsætter. Træet er wallet → venue → position med Jupiter før
|
||||
Phoenix og uden et ekstra subaccount-niveau. Tre kolonner, farver, formatering, foldestatus og markering
|
||||
bevares for eksisterende rækker. Nye/lukkede positioner afstemmes efter ID.
|
||||
Der er ingen sample-data, Refresh-knap, handel, signering eller kontoaktivering i denne læsevej.
|
||||
|
||||
Den kanoniske systembeskrivelse findes i
|
||||
[Evelyn: services og status](../../r35157_docs/projects/evelyn/README.md#evelynperpsservice).
|
||||
|
||||
+4
-1
@@ -289,12 +289,15 @@ Mission Control kræver både `evelyn.perps.prod` og `evelyn.perps.test` før `e
|
||||
i den private `conf/NenjimHub.conf`. Erstat den tidligere `evelyn.perps.default`-linje med de to nye ID'er;
|
||||
det gamle ID accepteres ikke længere. Hub'en konstruerer, registrerer og starter to separate
|
||||
`EvelynPerpsServiceImpl`-processer med separate hardcodede wallet-lister og tilhørende Jupiter-integrationer.
|
||||
Begge får desuden den fælles `PhoenixPerpsService` uden positionscache, som Hub'en registrerer passivt som
|
||||
`phoenix.perps.default`; den skal ikke tilføjes til `[AUTO_START]`.
|
||||
Hub'en injicerer deres read-only
|
||||
service-views til de tilsvarende miljøfaner i EMC. Process Manager viser begge ID'er efter vellykket startup.
|
||||
Den lokale udviklingskonfiguration er opdateret; andre deployments med EMC skal migreres tilsvarende.
|
||||
Udeladt eller forkert rækkefølge giver en tydelig konstruktionsfejl uden automatisk indsættelse.
|
||||
Det minimale versionsstyrede bootstrap-eksempel er uændret. Hver service ejer sit eget snapshot og
|
||||
opdaterer det fra Jupiter i baggrunden med 60 sekunders pause mellem gennemløb. EMC-læsninger bruger kun
|
||||
opdaterer det fra Jupiter og Phoenix i baggrunden med 60 sekunders pause efter fuldførte gennemløb.
|
||||
Sidste vellykkede data bevares separat pr. wallet og venue. EMC-læsninger bruger kun
|
||||
det publicerede snapshot. Wallet-listerne fra issue #98 indeholder seks PROD-adresser og én TEST-adresse.
|
||||
|
||||
Hvis `evelyn.iou-burner.prod` vælges, skal både `assetaz.ticker.default` og
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
# Phoenix Perps read-only integration
|
||||
|
||||
`PhoenixPerpsService` and `PhoenixPerpsPosition` 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.
|
||||
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.
|
||||
|
||||
## REST reads and account model
|
||||
|
||||
The implementation uses these official endpoints at `https://perp-api.phoenix.trade`:
|
||||
|
||||
1. [`GET /v1/trader/state/{authority}?traderPdaIndex=0`](https://docs.phoenix.trade/api/trader/get-trader-state)
|
||||
returns the wallet authority's version-1 snapshot and subaccounts. The
|
||||
[account model](https://docs.phoenix.trade/sdk/accounts) currently uses trader PDA
|
||||
index 0 for user accounts. Subaccount 0 is cross-margin; other returned subaccounts
|
||||
are isolated. Read every returned subaccount and include only nonzero
|
||||
`basePositionLots`. An omitted `positions` field is documented as optional and
|
||||
means empty; null or a wrong type is rejected.
|
||||
2. [`GET /v1/view/exchange/markets`](https://docs.phoenix.trade/api/exchange/list-markets)
|
||||
supplies each symbol's `baseLotsDecimals`.
|
||||
3. [`GET /v1/market/{symbol}/mark-price`](https://docs.phoenix.trade/api/exchange/get-mark-price)
|
||||
supplies `markPrice.price` in USD. The API permits an absent mark price; a held
|
||||
position without a valid positive price fails the lookup rather than appearing as zero.
|
||||
|
||||
An empty trader state needs only the first request. Otherwise metadata is fetched once
|
||||
and each active symbol's price once per wallet lookup, including when that symbol is
|
||||
held in several subaccounts. 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
|
||||
fail fast during that shared cooldown, letting Jupiter and other wallet attempts
|
||||
continue; the normal refresh cycle retries later. There are no automatic
|
||||
retries, new API keys or authentication/signing flows. Public reads worked during
|
||||
verification, despite generated API security annotations referring to bearer auth.
|
||||
HTTP failures, including 401/403/404/429, are errors rather than empty portfolios.
|
||||
The shared pacing follows Phoenix's [rate-limit guidance](https://docs.phoenix.trade/sdk/ws-api-best-practices);
|
||||
it does not guarantee a fixed quota.
|
||||
|
||||
## Units, precision and identity
|
||||
|
||||
The official [SDK's `baseLotsToBaseUnits`](https://github.com/Ellipsis-Labs/rise-public/blob/master/ts/src/units.ts)
|
||||
uses `lots / 10 ** baseLotsDecimals`; the exponent may be negative. The adapter uses:
|
||||
|
||||
```text
|
||||
quantity = BigDecimal(basePositionLots).scaleByPowerOfTen(-baseLotsDecimals)
|
||||
sizeUsd = abs(quantity) * markPrice.price
|
||||
```
|
||||
|
||||
All lot counts use `BigInteger`; conversion and multiplication use `BigDecimal`
|
||||
without a rounding context. Jackson parses JSON price numbers directly as decimal,
|
||||
without a `double` intermediate. For example, 2,144 SOL lots at `baseLotsDecimals=2`
|
||||
are 21.44 SOL; at a mark price of 104.45 USD, notional is 2,239.408 USD. Entry price,
|
||||
collateral, virtual quote lots and margin are not substitutes for current notional.
|
||||
Rounding to cents occurs only in the existing EMC display formatter.
|
||||
|
||||
Within each wallet's Phoenix venue, identity is `traderPdaIndex:subaccountIndex:symbol`.
|
||||
Sequence numbers do not affect identity. Rows sort by PDA index, subaccount index
|
||||
and symbol; labels use `SYMBOL-PERP`, with no extra subaccount tree level. Positive
|
||||
quantity means Long and negative means Short. Thus two SOL subaccounts remain two
|
||||
rows even though their labels match.
|
||||
|
||||
Authority/PDA identity, snapshot version, arrays, symbols, duplicate subaccounts or
|
||||
positions, integer lots, metadata and prices are validated. A malformed lookup fails
|
||||
as a whole; it never publishes a partially decoded portfolio. The shared Jackson
|
||||
mapper is copied so strict parsing does not change other integrations.
|
||||
|
||||
## Refresh behavior and limitations
|
||||
|
||||
Each Evelyn process performs an initial background refresh, then waits 60 seconds
|
||||
following each completed cycle. Jupiter and Phoenix are attempted independently for
|
||||
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
|
||||
clears only that venue's positions, preserving its group. 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.
|
||||
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 33 seconds for their reads). Failed
|
||||
reads can leave old data visible indefinitely; there is no stale/error indicator yet.
|
||||
Trader PDA indices other than 0, streaming and position management are out of scope.
|
||||
Reference in New Issue
Block a user