1pub mod value;
3
4pub 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
23pub trait MarketCalculations {
25 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 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 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 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 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}