pub trait PortfolioService: Send + Sync {
// Required methods
fn get_portfolio<'life0, 'life1, 'async_trait>(
&'life0 self,
account: &'life1 WalletAddress,
) -> Pin<Box<dyn Future<Output = Portfolio> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn get_portfolio_balance<'life0, 'life1, 'async_trait>(
&'life0 self,
account: &'life1 WalletAddress,
) -> Pin<Box<dyn Future<Output = Option<PortfolioBalance>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn all_portfolios<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = HashMap<WalletAddress, PortfolioBalance>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn apply_event<'life0, 'life1, 'async_trait>(
&'life0 self,
event: &'life1 EngineMessage,
) -> Pin<Box<dyn Future<Output = Result<Vec<PortfolioChange>, PortfolioError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn remove_expired_position<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
wallet: &'life1 WalletAddress,
symbol: &'life2 str,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn apply_hypercore_position_update<'life0, 'life1, 'async_trait>(
&'life0 self,
update: &'life1 HypercorePositionUpdate,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn set_hypercore_position<'life0, 'life1, 'async_trait>(
&'life0 self,
update: &'life1 HypercorePositionUpdate,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn as_any(&self) -> &dyn Any;
fn calculate_fill_accounting<'life0, 'life1, 'async_trait>(
&'life0 self,
fill: &'life1 Fill,
) -> Pin<Box<dyn Future<Output = Result<FillAccounting, PortfolioError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn apply_fill_to_memory<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
wallet: &'life1 WalletAddress,
symbol: &'life2 str,
side: &'life3 Side,
price: Decimal,
quantity: Decimal,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait;
}Expand description
Portfolio state management interface.
Pure state mutation for portfolio positions, balances, and P&L. Used by engine, API, and liquidator on the hot path.
Accounts are created lazily. get_portfolio always succeeds and returns
an empty portfolio (zero balance, no positions) if the account doesn’t exist.
Required Methods§
Sourcefn get_portfolio<'life0, 'life1, 'async_trait>(
&'life0 self,
account: &'life1 WalletAddress,
) -> Pin<Box<dyn Future<Output = Portfolio> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn get_portfolio<'life0, 'life1, 'async_trait>(
&'life0 self,
account: &'life1 WalletAddress,
) -> Pin<Box<dyn Future<Output = Portfolio> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Get current portfolio state for an account (API format).
Returns empty portfolio if account doesn’t exist. Must be O(1).
Sourcefn get_portfolio_balance<'life0, 'life1, 'async_trait>(
&'life0 self,
account: &'life1 WalletAddress,
) -> Pin<Box<dyn Future<Output = Option<PortfolioBalance>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn get_portfolio_balance<'life0, 'life1, 'async_trait>(
&'life0 self,
account: &'life1 WalletAddress,
) -> Pin<Box<dyn Future<Output = Option<PortfolioBalance>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Get internal balance state for risk/margin calculations.
Returns None if account doesn’t exist (no lazy creation). This is the raw internal state, not the API-formatted Portfolio.
Sourcefn all_portfolios<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = HashMap<WalletAddress, PortfolioBalance>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn all_portfolios<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = HashMap<WalletAddress, PortfolioBalance>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Get all portfolios as a snapshot.
Returns a clone of all in-memory portfolio state. Used for persistence/snapshots and open interest calculations.
Sourcefn apply_event<'life0, 'life1, 'async_trait>(
&'life0 self,
event: &'life1 EngineMessage,
) -> Pin<Box<dyn Future<Output = Result<Vec<PortfolioChange>, PortfolioError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn apply_event<'life0, 'life1, 'async_trait>(
&'life0 self,
event: &'life1 EngineMessage,
) -> Pin<Box<dyn Future<Output = Result<Vec<PortfolioChange>, PortfolioError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Apply an event from the matching engine.
Pure state mutation - updates positions and balances. Events: OrderFilled, OrderUpdate, OrderCanceled, PositionExpired.
Returns a list of PortfolioChange structs, one per affected wallet.
For fills, this includes both taker and maker. For other events, typically one.
Returns empty vec if no portfolio state changed (e.g., unhandled event type).
§Errors
Returns PortfolioError::LedgerError if realized PnL cannot be applied to
the ledger. This is a CRITICAL failure - callers should halt processing.
Sourcefn remove_expired_position<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
wallet: &'life1 WalletAddress,
symbol: &'life2 str,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn remove_expired_position<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
wallet: &'life1 WalletAddress,
symbol: &'life2 str,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Remove an expired position from memory without applying a cash delta.
Settlement accounting is owned by the settlement persistence path. Projection code uses this to clean up positions without double-crediting the ledger.
Sourcefn apply_hypercore_position_update<'life0, 'life1, 'async_trait>(
&'life0 self,
update: &'life1 HypercorePositionUpdate,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn apply_hypercore_position_update<'life0, 'life1, 'async_trait>(
&'life0 self,
update: &'life1 HypercorePositionUpdate,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Apply perp position update from Hypercore Position Service (incremental diff).
Used for snapshot=false updates. Idempotent - safe to apply the same update multiple times.
Sourcefn set_hypercore_position<'life0, 'life1, 'async_trait>(
&'life0 self,
update: &'life1 HypercorePositionUpdate,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn set_hypercore_position<'life0, 'life1, 'async_trait>(
&'life0 self,
update: &'life1 HypercorePositionUpdate,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Set perp position from Hypercore Position Service (snapshot).
Used for snapshot=true updates. Sets/replaces a single perp position. Called on service startup for initial state sync.
Sourcefn as_any(&self) -> &dyn Any
fn as_any(&self) -> &dyn Any
Returns a reference to self as Any for downcasting.
This is used to access implementation-specific methods like
set_ledger and set_tier_cache on PortfolioServiceImpl.
Sourcefn calculate_fill_accounting<'life0, 'life1, 'async_trait>(
&'life0 self,
fill: &'life1 Fill,
) -> Pin<Box<dyn Future<Output = Result<FillAccounting, PortfolioError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn calculate_fill_accounting<'life0, 'life1, 'async_trait>(
&'life0 self,
fill: &'life1 Fill,
) -> Pin<Box<dyn Future<Output = Result<FillAccounting, PortfolioError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Calculate the accounting delta that would result from applying a fill.
This is a pure calculation with no side effects - used to determine what to write to the ledger in the atomic DB transaction.
Sourcefn apply_fill_to_memory<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
wallet: &'life1 WalletAddress,
symbol: &'life2 str,
side: &'life3 Side,
price: Decimal,
quantity: Decimal,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn apply_fill_to_memory<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
wallet: &'life1 WalletAddress,
symbol: &'life2 str,
side: &'life3 Side,
price: Decimal,
quantity: Decimal,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Apply a fill’s position changes to in-memory state only.
This does NOT update the ledger - that’s handled by the atomic DB transaction. Call this only after the DB transaction succeeds.