# phoenix-perps-service Specification ## Purpose Read actual Phoenix perpetual positions for a Solana authority without signing or modifying accounts, preserving precise current USD notional and subaccount identities. ## Requirements ### Requirement: Read every active position under the authority The integration SHALL read official Phoenix REST trader state for the requested wallet authority at PDA index 0. It SHALL include nonzero positions from cross-margin and isolated subaccounts, preserve subaccount/symbol identity independently of sequence numbers, and return an immutable deterministically ordered result. No signing, trading or account activation SHALL occur. #### Scenario: Cross and isolated positions share a symbol - **WHEN** subaccounts 0 and 2 both have a nonzero SOL position - **THEN** both positions are returned with distinct identities - **AND** zero-sized positions are excluded ### Requirement: Current USD notional uses documented market units Position direction SHALL follow signed quantity. USD size SHALL be the absolute current notional, calculated using exact decimal arithmetic from base lots divided by 10 to the market's base-lot decimal exponent and multiplied by its current mark price. Collateral, entry value and raw lot counts SHALL NOT be used as USD size. Missing conversion data SHALL fail the read. #### Scenario: Convert a short position - **WHEN** a position has -125 base lots, base-lot exponent 2 and mark price 104.45 USD - **THEN** it represents -1.25 base units, Short direction and 130.5625 USD notional ### Requirement: Read failures cannot masquerade as empty portfolios HTTP, authentication, malformed schema, identity mismatch and numeric conversion errors SHALL fail the read. Requests SHALL have bounded timeouts. Only a valid response with no nonzero positions SHALL produce an empty result. Present mark prices SHALL be positive and finite; an explicitly absent mark SHALL preserve positions and quantities with unavailable price-dependent valuations. #### Scenario: Missing mark price - **WHEN** a valid mark response has no mark price for a held position - **THEN** the position and its TWAP quantities remain present with unknown USD valuations - **AND** affected aggregate valuations remain unknown #### Scenario: Rejected access or invalid price - **WHEN** an HTTP request is rejected or a present mark price is invalid - **THEN** the read fails instead of returning an empty or partial portfolio #### Scenario: Empty account - **WHEN** a valid trader snapshot has no subaccounts or no nonzero positions - **THEN** an empty result is returned without market-price or TWAP requests #### Scenario: Public API rate limit - **WHEN** the shared adapter issues requests for PROD and TEST - **THEN** request starts SHALL be spaced at least one second apart - **AND** HTTP 429 SHALL fail the lookup and establish a shared cooldown from Retry-After (seconds or HTTP date, 60 seconds fallback) - **AND** lookups during cooldown SHALL fail without external calls, with no immediate retry ### Requirement: Separate account capital and precise position metrics The reader SHALL return immutable account balances separately from positions, including funded empty Cross accounts. Quote lots SHALL convert at 1e-6 USD. Price PnL SHALL use precise virtual quote and signed base amounts at mark. Initial position margin SHALL follow size-dependent tiers including venue interpolation and rounding. Unsupported non-USDC collateral SHALL make affected valuations unavailable instead of being ignored. #### Scenario: Size between margin tiers - **WHEN** a position lies between two leverage tiers - **THEN** its initial margin follows interpolated integer leverage and upward quote-lot rounding, rather than the market's maximum leverage #### Scenario: Unsupported spot collateral - **WHEN** an account has nonzero spot collateral that cannot be valued reliably - **THEN** collateral, equity and closing Value are unavailable while independent exposure and price PnL remain available ### Requirement: Estimated account and isolated closing proceeds Equity SHALL include collateral, undiscounted price PnL and signed unsettled funding once. Estimated Value SHALL subtract estimated closing taker fees with account fee overrides. Settled fees/funding SHALL NOT be subtracted again. Isolated position leverage/ROI SHALL use actual collateral; Cross position leverage/ROI SHALL remain unavailable unless their venue convention is verified. #### Scenario: Funding signs and fee override - **WHEN** collateral is 100 USD, PnL 5 USD, unsettled funding -2 USD, and estimated exit fee 1 USD - **THEN** equity is 103 USD and estimated Value 102 USD - **AND** effective Cross leverage uses 103 USD as its denominator ### Requirement: Read precise TWAP snapshots for held markets The reader SHALL read official TWAP snapshots through its existing paced transport and associate orders by authority, PDA, subaccount and market identity. Only orders with actual fills and remaining children on an existing position SHALL be exposed. Quantities SHALL use exact lot conversion and explicit/legacy dust semantics. Unavailable size inputs SHALL remain unknown. Existing mark prices SHALL be reused without Ticker reads. #### Scenario: Explicit and legacy dust - **WHEN** total children are 5, regular size 10 lots and explicit dust count/size are 2/3 - **THEN** total size is 36 lots and the fourth child is 3 lots - **AND** legacy zero dust count with size 3 instead represents four regular children and a final 3-lot child #### Scenario: Identity mismatch or unfilled order - **WHEN** authority/PDA/subaccount/asset identities disagree or an order has no fills - **THEN** disagreement fails the read, while a valid unfilled order is absent from returned positions' TWAP data ### Requirement: TWAP time estimates disclose their slot assumption The reader SHALL estimate future execution times from snapshot slot, due slot and cooldown using a documented nominal slot duration and response observation time. Completion SHALL derive from remaining executions, never expiry. Already-due schedules, invalidated completion schedules and unrepresentable estimates SHALL remain unavailable instead of predicting fills. #### Scenario: Expiry before planned completion - **WHEN** the scheduled final child lies beyond the order's expiry - **THEN** the reader does not provide that schedule as an estimated completion time ### Requirement: Read venue account health independently of TWAP The reader SHALL resolve the official trader account for authority/PDA/subaccount and read its venue risk classification, effective collateral, maintenance margin and position liquidation prices. It SHALL validate identities and amounts, use venue reference prices with original observation times and normalize sentinel liquidation prices to unavailable. Existing pacing, cooldown, timeout and failure retention contracts SHALL apply without signing or TWAP dependence. #### Scenario: Same-symbol isolated and Cross accounts - **WHEN** the wallet holds the same market in multiple accounts without active TWAPs - **THEN** each visible account receives only its own reported risk and liquidation data - **AND** a mismatched trader identity or position size fails the observation #### Scenario: Missing or unsupported risk field - **WHEN** a response has missing optional risk values or an unknown tier - **THEN** those values remain unavailable without assuming a safe state - **AND** a nonpositive liquidation-price sentinel does not invalidate independent account health