Struct mango_v4::health::HealthCache
source · pub struct HealthCache {
pub token_infos: Vec<TokenInfo>,
/* private fields */
}
Expand description
Store information needed to compute account health
This is called a cache, because it extracts information from a MangoAccount and the Bank, Perp, oracle accounts once and then allows computing different types of health.
For compute-saving reasons, it also allows applying adjustments to the extracted positions. That’s often helpful for instructions that want to re-compute health after having made small, well-known changes to an account. Recomputing the HealthCache from scratch would be significantly more expensive.
However, there’s a real risk of getting the adjustments wrong and computing an inconsistent result, so particular care needs to be taken when this is done.
Fields§
§token_infos: Vec<TokenInfo>
Implementations§
source§impl HealthCache
impl HealthCache
pub fn health(&self, health_type: HealthType) -> I80F48
sourcepub fn health_ratio(&self, health_type: HealthType) -> I80F48
pub fn health_ratio(&self, health_type: HealthType) -> I80F48
The health ratio is
- 0 if health is 0 - meaning assets = liabs
- 100 if there’s 2x as many assets as liabs
- 200 if there’s 3x as many assets as liabs
- MAX if liabs = 0
Maybe talking about the collateralization ratio assets/liabs is more intuitive?
pub fn health_assets_and_liabs_stable_assets( &self, health_type: HealthType ) -> (I80F48, I80F48)
pub fn health_assets_and_liabs_stable_liabs( &self, health_type: HealthType ) -> (I80F48, I80F48)
sourcepub fn assets_and_liabs(&self) -> (I80F48, I80F48)
pub fn assets_and_liabs(&self) -> (I80F48, I80F48)
Computes the account assets and liabilities marked to market.
Contrary to health_assets_and_liabs, there’s no health weighing or adjustment for stable prices. It uses oracle prices directly.
Returns (assets, liabilities)
sourcepub fn leverage(&self) -> I80F48
pub fn leverage(&self) -> I80F48
Computes the account leverage as ratio of liabs / (assets - liabs)
The goal of this function is to provide a quick overview over the accounts balance sheet. It’s not actually used to make any margin decisions internally and doesn’t account for open orders or stable / oracle price differences. Use health_ratio to make risk decisions.
pub fn token_info(&self, token_index: TokenIndex) -> Result<&TokenInfo>
pub fn token_info_index(&self, token_index: TokenIndex) -> Result<usize>
pub fn has_token_info(&self, token_index: TokenIndex) -> bool
pub fn perp_info(&self, perp_market_index: PerpMarketIndex) -> Result<&PerpInfo>
sourcepub fn adjust_token_balance(
&mut self,
bank: &Bank,
change: I80F48
) -> Result<()>
pub fn adjust_token_balance( &mut self, bank: &Bank, change: I80F48 ) -> Result<()>
Changes the cached user account token balance.
sourcepub fn recompute_serum3_info(
&mut self,
serum_account: &Serum3Orders,
open_orders: &OpenOrdersSlim,
free_base_change: I80F48,
free_quote_change: I80F48
) -> Result<()>
pub fn recompute_serum3_info( &mut self, serum_account: &Serum3Orders, open_orders: &OpenOrdersSlim, free_base_change: I80F48, free_quote_change: I80F48 ) -> Result<()>
Recompute the cached information about a serum market.
WARNING: You must also call recompute_token_weights() after all bank deposit/withdraw changes!
sourcepub fn recompute_openbook_v2_info(
&mut self,
open_orders: &OpenbookV2Orders,
open_orders_account: &OpenOrdersAccount,
free_base_change: I80F48,
free_quote_change: I80F48
) -> Result<()>
pub fn recompute_openbook_v2_info( &mut self, open_orders: &OpenbookV2Orders, open_orders_account: &OpenOrdersAccount, free_base_change: I80F48, free_quote_change: I80F48 ) -> Result<()>
Recompute the cached information about a serum market.
WARNING: You must also call recompute_token_weights() after all bank deposit/withdraw changes!
pub fn recompute_perp_info( &mut self, perp_position: &PerpPosition, perp_market: &PerpMarket ) -> Result<()>
sourcepub fn has_liq_spot_assets(&self) -> bool
pub fn has_liq_spot_assets(&self) -> bool
Liquidatable spot assets mean: actual token deposits and also a positive effective token balance and is available for asset liquidation
sourcepub fn has_liq_spot_borrows(&self) -> bool
pub fn has_liq_spot_borrows(&self) -> bool
Liquidatable spot borrows mean: actual token borrows plus a negative effective token balance
pub fn has_possible_spot_liquidations(&self) -> bool
pub fn has_spot_open_orders_funds(&self) -> bool
pub fn has_perp_open_orders(&self) -> bool
pub fn has_perp_base_positions(&self) -> bool
pub fn has_perp_open_fills(&self) -> bool
pub fn has_perp_positive_pnl_no_base(&self) -> bool
pub fn has_perp_negative_pnl_no_base(&self) -> bool
sourcepub fn has_phase1_liquidatable(&self) -> bool
pub fn has_phase1_liquidatable(&self) -> bool
Phase1 is spot/perp order cancellation and spot settlement since neither of these come at a cost to the liqee
pub fn require_after_phase1_liquidation(&self) -> Result<()>
pub fn in_phase1_liquidation(&self) -> bool
sourcepub fn has_phase2_liquidatable(&self) -> bool
pub fn has_phase2_liquidatable(&self) -> bool
Phase2 is for:
- token-token liquidation
- liquidation of perp base positions (an open fill isn’t liquidatable, but it changes the base position, so need to wait for it to be processed…)
- bringing positive trusted perp pnl into the spot realm
pub fn require_after_phase2_liquidation(&self) -> Result<()>
pub fn in_phase2_liquidation(&self) -> bool
sourcepub fn has_phase3_liquidatable(&self) -> bool
pub fn has_phase3_liquidatable(&self) -> bool
Phase3 is bankruptcy:
- token bankruptcy
- perp bankruptcy
pub fn in_phase3_liquidation(&self) -> bool
sourcepub fn effective_token_balances(
&self,
health_type: HealthType
) -> Vec<TokenBalance>
pub fn effective_token_balances( &self, health_type: HealthType ) -> Vec<TokenBalance>
Returns token balances that account for spot and perp contributions
Spot contributions are just the regular deposits or borrows, as well as from free funds on spot open orders accounts.
Perp contributions come from perp positions in markets that use the token as a settle token: For these the hupnl is added to the total because that’s the risk-adjusted expected to be gained or lost from settlement.
sourcepub fn perp_max_settle(&self, settle_token_index: TokenIndex) -> Result<I80F48>
pub fn perp_max_settle(&self, settle_token_index: TokenIndex) -> Result<I80F48>
Returns how much pnl is settleable for a given settle token.
The idea of this limit is that settlement is only permissible as long as there are non-perp assets that back it. If an account with 1 USD deposited somehow gets a large negative perp upnl, it should not be allowed to settle that perp loss into the spot world fully (because of perp/spot isolation, translating perp losses and gains into tokens is restricted). Only 1 USD worth would be allowed.
Effectively, there’s a health variant “perp settle health” that ignores negative token contributions from perp markets. Settlement is allowed as long as perp settle health remains >= 0.
For example, if perp_settle_health is 50 USD, then the settleable amount in SOL would depend on the SOL price, the user’s current spot balance and the SOL weights: We need to compute how much the user’s spot SOL balance may decrease before the perp_settle_health becomes zero.
Note that the account’s actual health would not change during settling negative upnl: the spot balance goes down but the perp hupnl goes up accordingly.
Examples:
- An account may have maint_health < 0, but settling perp pnl could still be allowed. (+100 USDC health, -50 USDT health, -50 perp health -> allow settling 50 health worth)
- Positive health from trusted pnl markets counts
- If overall health is 0 with two trusted perp pnl < 0, settling may still be possible. (+100 USDC health, -150 perp1 health, -150 perp2 health -> allow settling 100 health worth)
- Positive trusted perp pnl can enable settling. (+100 trusted perp1 health, -100 perp2 health -> allow settling of 100 health worth)
pub fn total_spot_potential( &self, health_type: HealthType, token_index: TokenIndex ) -> Result<I80F48>
sourcepub fn check_has_all_spot_infos_for_token(
&self,
account: &MangoAccountRef<'_>,
token_index: TokenIndex
) -> Result<()>
pub fn check_has_all_spot_infos_for_token( &self, account: &MangoAccountRef<'_>, token_index: TokenIndex ) -> Result<()>
Verifies that the health cache has information on all account’s active spot markets that touch the token_index
source§impl HealthCache
impl HealthCache
pub fn is_liquidatable(&self) -> bool
sourcepub fn max_swap_source_for_health_ratio_ignoring_limits(
&self,
account: &MangoAccountValue,
source_bank: &Bank,
source_oracle_price: I80F48,
target_bank: &Bank,
price: I80F48,
min_ratio: I80F48
) -> Result<I80F48>
pub fn max_swap_source_for_health_ratio_ignoring_limits( &self, account: &MangoAccountValue, source_bank: &Bank, source_oracle_price: I80F48, target_bank: &Bank, price: I80F48, min_ratio: I80F48 ) -> Result<I80F48>
Verifies neither the net borrow or deposit limits
pub fn max_swap_source_for_health_ratio_with_limits( &self, account: &MangoAccountValue, source_bank: &Bank, source_oracle_price: I80F48, target_bank: &Bank, price: I80F48, min_ratio: I80F48 ) -> Result<I80F48>
sourcepub fn max_swap_source_for_health_fn(
&self,
account: &MangoAccountValue,
source_bank: &Bank,
source_oracle_price: I80F48,
target_bank: &Bank,
price: I80F48,
min_fn_value: I80F48,
target_fn: fn(_: &HealthCache) -> I80F48
) -> Result<I80F48>
pub fn max_swap_source_for_health_fn( &self, account: &MangoAccountValue, source_bank: &Bank, source_oracle_price: I80F48, target_bank: &Bank, price: I80F48, min_fn_value: I80F48, target_fn: fn(_: &HealthCache) -> I80F48 ) -> Result<I80F48>
How many source native tokens may be swapped for target tokens while staying above the min_ratio health ratio.
price
: The amount of target native you receive for one source native. So if we
swap BTC -> SOL and they’re at ui prices of $20000 and $40, that means price
should be 500000 native_SOL for a native_BTC. Because 1 BTC gives you 500 SOL
so 1e6 native_BTC gives you 500e9 native_SOL.
Positions for the source and deposit token index must already exist in the account.
NOTE: keep getMaxSourceForTokenSwap in ts/client in sync with changes here
sourcepub fn max_perp_for_health_ratio(
&self,
perp_market_index: PerpMarketIndex,
price: I80F48,
side: PerpOrderSide,
min_ratio: I80F48
) -> Result<i64>
pub fn max_perp_for_health_ratio( &self, perp_market_index: PerpMarketIndex, price: I80F48, side: PerpOrderSide, min_ratio: I80F48 ) -> Result<i64>
NOTE: keep getMaxSourceForTokenSwap in ts/client in sync with changes here
pub fn max_borrow_for_health_ratio( &self, account: &MangoAccountValue, bank: &Bank, min_ratio: I80F48 ) -> Result<I80F48>
Trait Implementations§
source§impl Clone for HealthCache
impl Clone for HealthCache
source§fn clone(&self) -> HealthCache
fn clone(&self) -> HealthCache
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read more