gmsol_sdk/market/
mod.rs

1/// Value.
2pub mod value;
3
4/// Market Status.
5pub mod status;
6
7use gmsol_model::{
8    num::{MulDiv, Unsigned},
9    num_traits::Zero,
10    price::Prices,
11    Balance, BaseMarket, BaseMarketExt, BorrowingFeeMarketExt, PerpMarket, PerpMarketExt,
12    PerpMarketMutExt,
13};
14use gmsol_programs::model::MarketModel;
15
16use crate::constants;
17
18pub use self::{
19    status::MarketStatus,
20    value::{SignedValue, Value},
21};
22
23/// Market Calculations.
24pub trait MarketCalculations {
25    /// Calculate market status.
26    fn status(&self, prices: &Prices<u128>) -> crate::Result<MarketStatus>;
27}
28
29impl MarketCalculations for MarketModel {
30    fn status(&self, prices: &Prices<u128>) -> crate::Result<MarketStatus> {
31        // Calculate open interests.
32        let open_interest = self.open_interest()?;
33        let open_interest_for_long = open_interest.long_amount()?;
34        let open_interest_for_short = open_interest.short_amount()?;
35        let open_interest_in_tokens = self.open_interest_in_tokens()?;
36
37        // Calculate funding rates.
38        let (funding_rate_per_second_for_long, funding_rate_per_second_for_short) = {
39            if open_interest_for_long == 0 || open_interest_for_short == 0 {
40                (0, 0)
41            } else {
42                let (funding_factor_per_second, longs_pay_shorts, _) = self
43                    .clone()
44                    .update_funding(prices)?
45                    .next_funding_factor_per_second(
46                        self.passed_in_seconds_for_funding()?,
47                        &open_interest_for_long,
48                        &open_interest_for_short,
49                    )?;
50                let size_of_paying_side = if longs_pay_shorts {
51                    open_interest_for_long
52                } else {
53                    open_interest_for_short
54                };
55                let funding_rate_per_second_for_long = if longs_pay_shorts {
56                    funding_factor_per_second
57                        .checked_mul_div_ceil(&size_of_paying_side, &open_interest_for_long)
58                        .ok_or_else(|| {
59                            crate::Error::custom("failed to calculate funding rate for long")
60                        })?
61                        .to_signed()?
62                } else {
63                    funding_factor_per_second
64                        .checked_mul_div(&size_of_paying_side, &open_interest_for_long)
65                        .ok_or_else(|| {
66                            crate::Error::custom("failed to calculate funding rate for long")
67                        })?
68                        .to_opposite_signed()?
69                };
70                let funding_rate_per_second_for_short = if !longs_pay_shorts {
71                    funding_factor_per_second
72                        .checked_mul_div_ceil(&size_of_paying_side, &open_interest_for_short)
73                        .ok_or_else(|| {
74                            crate::Error::custom("failed to calculate funding rate for short")
75                        })?
76                        .to_signed()?
77                } else {
78                    funding_factor_per_second
79                        .checked_mul_div(&size_of_paying_side, &open_interest_for_short)
80                        .ok_or_else(|| {
81                            crate::Error::custom("failed to calculate funding rate for short")
82                        })?
83                        .to_opposite_signed()?
84                };
85
86                (
87                    funding_rate_per_second_for_long,
88                    funding_rate_per_second_for_short,
89                )
90            }
91        };
92
93        // Calculate liquidities.
94        let reserved_value_for_long = self.reserved_value(&prices.index_token_price, true)?;
95        let reserved_value_for_short = self.reserved_value(&prices.index_token_price, false)?;
96        let pool_value_without_pnl_for_long = Value {
97            min: self.pool_value_without_pnl_for_one_side(prices, true, false)?,
98            max: self.pool_value_without_pnl_for_one_side(prices, true, true)?,
99        };
100        let pool_value_without_pnl_for_short = Value {
101            min: self.pool_value_without_pnl_for_one_side(prices, false, false)?,
102            max: self.pool_value_without_pnl_for_one_side(prices, false, true)?,
103        };
104        let reserve_factor = self
105            .reserve_factor()?
106            .min(self.open_interest_reserve_factor()?);
107        let max_reserve_value_for_long = gmsol_model::utils::apply_factor::<
108            _,
109            { constants::MARKET_DECIMALS },
110        >(
111            &pool_value_without_pnl_for_long.min, &reserve_factor
112        )
113        .ok_or_else(|| crate::Error::custom("failed to calculate max reserved value for long"))?;
114        let max_reserve_value_for_short = gmsol_model::utils::apply_factor::<
115            _,
116            { constants::MARKET_DECIMALS },
117        >(
118            &pool_value_without_pnl_for_short.min, &reserve_factor
119        )
120        .ok_or_else(|| crate::Error::custom("failed to calculate max reserved value for short"))?;
121        let max_liquidity_for_long = max_reserve_value_for_long.min(self.max_open_interest(true)?);
122        let max_liquidity_for_short =
123            max_reserve_value_for_short.min(self.max_open_interest(false)?);
124
125        // Calculate min collateral factor.
126        let min_collateral_factor = *self.position_params()?.min_collateral_factor();
127        let min_collateral_factor_for_long = self
128            .min_collateral_factor_for_open_interest(&Zero::zero(), true)?
129            .max(min_collateral_factor);
130        let min_collateral_factor_for_short = self
131            .min_collateral_factor_for_open_interest(&Zero::zero(), false)?
132            .max(min_collateral_factor);
133
134        Ok(MarketStatus {
135            funding_rate_per_second_for_long,
136            funding_rate_per_second_for_short,
137            borrowing_rate_per_second_for_long: self.borrowing_factor_per_second(true, prices)?,
138            borrowing_rate_per_second_for_short: self.borrowing_factor_per_second(false, prices)?,
139            pending_pnl_for_long: SignedValue {
140                min: self.pnl(&prices.index_token_price, true, false)?,
141                max: self.pnl(&prices.index_token_price, true, true)?,
142            },
143            pending_pnl_for_short: SignedValue {
144                min: self.pnl(&prices.index_token_price, false, false)?,
145                max: self.pnl(&prices.index_token_price, false, true)?,
146            },
147            reserved_value_for_long,
148            reserved_value_for_short,
149            max_reserve_value_for_long,
150            max_reserve_value_for_short,
151            pool_value_without_pnl_for_long,
152            pool_value_without_pnl_for_short,
153            liquidity_for_long: max_liquidity_for_long.saturating_sub(reserved_value_for_long),
154            liquidity_for_short: max_liquidity_for_short.saturating_sub(reserved_value_for_short),
155            max_liquidity_for_long,
156            max_liquidity_for_short,
157            open_interest_for_long,
158            open_interest_for_short,
159            open_interest_in_tokens_for_long: open_interest_in_tokens.long_amount()?,
160            open_interest_in_tokens_for_short: open_interest_in_tokens.short_amount()?,
161            min_collateral_factor_for_long,
162            min_collateral_factor_for_short,
163        })
164    }
165}