140 lines
11 KiB
Markdown
140 lines
11 KiB
Markdown
# evelyn-perps-service Specification
|
|
|
|
## Purpose
|
|
Provide a view-only source of current Evelyn perpetual positions independently of Mission Control presentation and refresh timing.
|
|
|
|
## Requirements
|
|
|
|
### Requirement: Read-only current positions snapshot
|
|
The Perps service SHALL expose only a read operation returning its complete current in-memory snapshot. Wallets, venues within wallets, and positions within venues SHALL have stable identifiers across reads. Responses SHALL be immutable domain data without UI components, colors or formatting. Reading the snapshot SHALL make no Jupiter or Phoenix requests.
|
|
|
|
#### Scenario: Repeated reads
|
|
- **WHEN** clients repeatedly retrieve the started service's snapshot
|
|
- **THEN** they receive the latest published positions with stable identifiers and cannot mutate service-owned collections
|
|
- **AND** the reads trigger no exchange requests or position-management operations
|
|
|
|
### Requirement: Hub owns Perps startup
|
|
The service SHALL run as two separate Hub-managed processes registered as `evelyn.perps.test` and `evelyn.perps.prod`. The service API SHALL expose no lifecycle operations. Snapshot reads before process startup SHALL fail clearly. Startup SHALL schedule asynchronous retrieval without waiting for integration I/O.
|
|
|
|
#### Scenario: Service starts
|
|
- **WHEN** the Hub starts either registered Perps process
|
|
- **THEN** its service view is available without waiting for retrieval, initially empty until data arrives
|
|
- **AND** no placeholder positions are generated before successful retrieval
|
|
|
|
### Requirement: Wallet configuration belongs to service construction
|
|
The Hub SHALL supply the six PROD wallet addresses and one TEST wallet address specified in issue #98, a read-only Jupiter overview reader and a read-only Phoenix integration at construction. Each service SHALL retain immutable configuration and own its snapshot. Wallet addresses SHALL be used as stable identities and display labels. EMC SHALL neither own nor pass wallet configuration; reads SHALL remain parameterless. Existing Jupiter trading/alarm services SHALL retain their behavior.
|
|
|
|
#### Scenario: Separate configured instances
|
|
- **WHEN** the Hub constructs and starts both instances
|
|
- **THEN** each instance queries only its configured wallets through its injected integrations
|
|
- **AND** the implementation does not define the wallet list internally
|
|
|
|
### Requirement: Background Jupiter refresh
|
|
The service SHALL refresh immediately after startup and wait 60 seconds after completed cycles without overlap or dependence on EMC visibility. It SHALL use a dedicated read-only Jupiter overview and the Phoenix account reader. Snapshot reads SHALL make no integration calls. No signing or position-management operation SHALL occur; existing transaction/alarm reads SHALL retain their behavior.
|
|
|
|
#### Scenario: Background update while EMC is hidden
|
|
- **WHEN** EMC is hidden and the next refresh is due
|
|
- **THEN** the service refreshes configured wallets and publishes immutable snapshots
|
|
- **AND** all UI snapshot reads remain in-memory
|
|
|
|
### Requirement: Position mapping is stable and complete
|
|
The service SHALL preserve Jupiter position-account identities and its existing USD position-size basis. Phoenix SHALL preserve PDA/subaccount/symbol identities and absolute current notional. Isolated positions SHALL remain directly under venues; Cross accounts SHALL own their positions and shared balances separately. Wallet and position ordering SHALL be deterministic. No account membership SHALL be inferred from instrument labels.
|
|
|
|
#### Scenario: Same-market cross and isolated positions
|
|
- **WHEN** a Phoenix wallet holds SOL in Cross and an isolated subaccount
|
|
- **THEN** both positions retain distinct IDs and their actual account membership
|
|
|
|
#### Scenario: Changed and unknown positions
|
|
- **WHEN** a successful read returns newly opened positions including an unknown token mint
|
|
- **THEN** all returned positions appear with stable IDs and exact USD sizes, and the unknown mint is displayed rather than dropped
|
|
|
|
### Requirement: Refresh failures are isolated per wallet
|
|
A failed read or mapping SHALL retain the last successful data for that wallet and venue, log the failure and allow other wallets and venues to refresh. Successful empty results SHALL remove only that wallet/venue's previous positions. Interruption SHALL stop the current cycle. Failed first reads SHALL not invent positions.
|
|
|
|
#### Scenario: Failure followed by recovery
|
|
- **WHEN** one wallet fails while another succeeds
|
|
- **THEN** only the successful wallet/venue's data is replaced
|
|
- **AND** a later successful empty read clears the recovered wallet/venue's previous positions
|
|
|
|
#### Scenario: One venue fails
|
|
- **WHEN** Phoenix fails for a wallet while Jupiter succeeds, or vice versa
|
|
- **THEN** only the successful venue is updated and the failed venue retains its previous data
|
|
- **AND** subsequent wallets are still attempted
|
|
|
|
### Requirement: Complete gross and account-aware totals
|
|
Exposure and dollar price PnL SHALL sum through all levels. Exposure SHALL be gross, with positive absolute notionals. Capital and closing Value SHALL count isolated positions and shared Cross accounts once. Missing required components SHALL make only the affected total unavailable. Successfully read empty scopes SHALL total zero. Leverage and PnL percentages SHALL NOT be aggregated.
|
|
|
|
#### Scenario: Opposite directions and shared collateral
|
|
- **WHEN** two Cross positions have notionals 100 USD Long and 100 USD Short, shared collateral 80 USD, combined PnL 5 USD and closing fees 1 USD
|
|
- **THEN** exposure totals 200 USD, collateral 80 USD and Value 84 USD at account, venue, wallet and root levels
|
|
- **AND** collapsing any UI group does not change totals
|
|
|
|
#### Scenario: First read fails
|
|
- **WHEN** one configured venue has never been read successfully
|
|
- **THEN** it remains unknown and cannot silently produce complete portfolio totals
|
|
|
|
### Requirement: Retained observations communicate status
|
|
Each venue SHALL carry its last-success time and whether the latest attempt failed. Failure SHALL preserve positions and account balances independently per wallet/venue. A valid funded empty Cross account SHALL remain visible. Retained data SHALL NOT be described as fresh.
|
|
|
|
#### Scenario: Last Cross position closes
|
|
- **WHEN** a successful refresh returns a Cross account with nonzero collateral and no positions
|
|
- **THEN** its capital and Value remain included without synthetic positions
|
|
|
|
#### Scenario: Retained last success
|
|
- **WHEN** a subsequent read fails
|
|
- **THEN** its previous observations remain available with their original success time and failure indication
|
|
|
|
### Requirement: TWAP observations belong to existing filled positions
|
|
The service SHALL publish immutable TWAP observations on matching existing Phoenix positions whose order has a positive actual fill and remaining executions, and account-owned warnings for eligible unresolved orders. It SHALL preserve counters, quantities, nullable price and observation/estimated times without UI formatting. No new position SHALL be synthesized. TWAP errors SHALL retain the complete prior venue observation with failure status. Polling frequency SHALL remain unchanged.
|
|
|
|
#### Scenario: Unfilled order or no position
|
|
- **WHEN** an active TWAP has no actual fills or no matching open position
|
|
- **THEN** a zero-fill order is absent from every overview row and cannot create a visible venue
|
|
- **AND** an eligible filled outstanding order without a position is preserved as a warning on its actual account scope
|
|
|
|
#### Scenario: TWAP read fails
|
|
- **WHEN** the TWAP read fails after a successful venue observation
|
|
- **THEN** prior positions, TWAP observations and original timestamps remain with failed venue status
|
|
- **AND** other venues and wallets continue refreshing
|
|
|
|
#### Scenario: Filled order without position
|
|
- **WHEN** a filled outstanding order cannot match an open position
|
|
- **THEN** its warning retains the real account identity and Cross accounts remain present even without capital or positions
|
|
- **AND** warning-only data does not synthesize positions or valuations
|
|
|
|
#### Scenario: Warning recovery and retention
|
|
- **WHEN** a successful observation resolves or removes a warned order
|
|
- **THEN** its warning is cleared while unrelated warnings remain
|
|
- **AND** failed reads instead retain warnings and their original times
|
|
|
|
### Requirement: Risk observations preserve scope and exact meaning
|
|
Snapshots SHALL preserve isolated risk prices and Cross account tiers/thresholds with original observation times. Signed price distance SHALL use the current venue reference as denominator and preserve boundary crossing. Cross MM utilization SHALL use effective collateral, with nonpositive denominators unavailable. Group risk SHALL count each isolated position and shared account once and retain worst known severity plus unknown/stale counts without averaging.
|
|
|
|
#### Scenario: Shared positions and incomplete data
|
|
- **WHEN** a Cross account owns multiple positions and another scope has unknown risk
|
|
- **THEN** account risk contributes once and the aggregate exposes the unknown count
|
|
- **AND** its closing Value is not substituted for effective collateral
|
|
|
|
#### Scenario: Boundary and zero denominator
|
|
- **WHEN** isolated distance reaches/crosses zero or effective collateral is nonpositive
|
|
- **THEN** the signed boundary is preserved or MM percentage is unavailable respectively
|
|
- **AND** display rounding does not determine risk classification
|
|
|
|
### Requirement: Value estimates preserve their sources through totals
|
|
Snapshots SHALL preserve Jupiter's reported Value and identify available Jupiter and Phoenix Values as estimates. Every complete Value total SHALL inherit its contributing estimate sources independently of UI expansion. Missing required values SHALL keep totals unavailable. Cross capital SHALL count once. Failed reads SHALL retain the prior values, qualifications and original times with failure status; success SHALL replace them.
|
|
|
|
#### Scenario: Mixed complete totals
|
|
- **WHEN** a wallet has a Jupiter estimate of 12 USD and a Phoenix Cross account estimate of 84 USD with multiple children
|
|
- **THEN** wallet and root Value are 96 USD and identify both estimate sources
|
|
- **AND** collapsing any group changes neither total nor qualification
|
|
|
|
#### Scenario: Missing contribution and successful empty scope
|
|
- **WHEN** a required Jupiter Value is missing
|
|
- **THEN** the dependent Value totals remain unavailable without losing other metrics
|
|
- **AND** a successfully read empty scope can still contribute zero
|
|
|
|
#### Scenario: Failed estimate and recovery
|
|
- **WHEN** a valid Jupiter estimate is followed by a malformed observation
|
|
- **THEN** the original estimate, its qualification and success/observation times remain with failure status
|
|
- **AND** successful subsequent observations replace the estimate, including replacing it with missing Value or clearing an empty scope
|