Perp: Allow setting pnl asset weights (#391)
This replaces the previous distinction between trusted and untrusted markets, they are equivalent to setting the asset weights to 1 or 0 instead. This way, we can weigh positive pnl in the trusted case at less than 1 which is more correct from a risk point of view and allows for more flexibility when it comes to liquidation. Co-authored-by: microwavedcola1 <microwavedcola@gmail.com>
This commit is contained in:
parent
da1dfb2c3c
commit
ec99376a8f
|
@ -436,8 +436,22 @@ mod tests {
|
||||||
let oo1key = oo1.pubkey;
|
let oo1key = oo1.pubkey;
|
||||||
oo1.data().native_pc_total = 20;
|
oo1.data().native_pc_total = 20;
|
||||||
|
|
||||||
let mut perp1 = mock_perp_market(group, oracle2.pubkey, oracle2_price, 9, 0.2, 0.1);
|
let mut perp1 = mock_perp_market(
|
||||||
let mut perp2 = mock_perp_market(group, oracle1.pubkey, oracle1_price, 8, 0.2, 0.1);
|
group,
|
||||||
|
oracle2.pubkey,
|
||||||
|
oracle2_price,
|
||||||
|
9,
|
||||||
|
(0.2, 0.1),
|
||||||
|
(0.05, 0.02),
|
||||||
|
);
|
||||||
|
let mut perp2 = mock_perp_market(
|
||||||
|
group,
|
||||||
|
oracle1.pubkey,
|
||||||
|
oracle1_price,
|
||||||
|
8,
|
||||||
|
(0.2, 0.1),
|
||||||
|
(0.05, 0.02),
|
||||||
|
);
|
||||||
|
|
||||||
let oracle1_account_info = oracle1.as_account_info();
|
let oracle1_account_info = oracle1.as_account_info();
|
||||||
let oracle2_account_info = oracle2.as_account_info();
|
let oracle2_account_info = oracle2.as_account_info();
|
||||||
|
|
|
@ -209,10 +209,12 @@ pub(crate) struct Serum3Reserved {
|
||||||
#[derive(Clone, AnchorDeserialize, AnchorSerialize, Debug)]
|
#[derive(Clone, AnchorDeserialize, AnchorSerialize, Debug)]
|
||||||
pub struct PerpInfo {
|
pub struct PerpInfo {
|
||||||
pub perp_market_index: PerpMarketIndex,
|
pub perp_market_index: PerpMarketIndex,
|
||||||
pub maint_asset_weight: I80F48,
|
pub maint_base_asset_weight: I80F48,
|
||||||
pub init_asset_weight: I80F48,
|
pub init_base_asset_weight: I80F48,
|
||||||
pub maint_liab_weight: I80F48,
|
pub maint_base_liab_weight: I80F48,
|
||||||
pub init_liab_weight: I80F48,
|
pub init_base_liab_weight: I80F48,
|
||||||
|
pub maint_pnl_asset_weight: I80F48,
|
||||||
|
pub init_pnl_asset_weight: I80F48,
|
||||||
pub base_lot_size: i64,
|
pub base_lot_size: i64,
|
||||||
pub base_lots: i64,
|
pub base_lots: i64,
|
||||||
pub bids_base_lots: i64,
|
pub bids_base_lots: i64,
|
||||||
|
@ -221,7 +223,6 @@ pub struct PerpInfo {
|
||||||
pub quote: I80F48,
|
pub quote: I80F48,
|
||||||
pub prices: Prices,
|
pub prices: Prices,
|
||||||
pub has_open_orders: bool,
|
pub has_open_orders: bool,
|
||||||
pub trusted_market: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PerpInfo {
|
impl PerpInfo {
|
||||||
|
@ -237,10 +238,12 @@ impl PerpInfo {
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
perp_market_index: perp_market.perp_market_index,
|
perp_market_index: perp_market.perp_market_index,
|
||||||
init_asset_weight: perp_market.init_asset_weight,
|
init_base_asset_weight: perp_market.init_base_asset_weight,
|
||||||
init_liab_weight: perp_market.init_liab_weight,
|
init_base_liab_weight: perp_market.init_base_liab_weight,
|
||||||
maint_asset_weight: perp_market.maint_asset_weight,
|
maint_base_asset_weight: perp_market.maint_base_asset_weight,
|
||||||
maint_liab_weight: perp_market.maint_liab_weight,
|
maint_base_liab_weight: perp_market.maint_base_liab_weight,
|
||||||
|
init_pnl_asset_weight: perp_market.init_pnl_asset_weight,
|
||||||
|
maint_pnl_asset_weight: perp_market.maint_pnl_asset_weight,
|
||||||
base_lot_size: perp_market.base_lot_size,
|
base_lot_size: perp_market.base_lot_size,
|
||||||
base_lots,
|
base_lots,
|
||||||
bids_base_lots: perp_position.bids_base_lots,
|
bids_base_lots: perp_position.bids_base_lots,
|
||||||
|
@ -248,14 +251,15 @@ impl PerpInfo {
|
||||||
quote: quote_current,
|
quote: quote_current,
|
||||||
prices,
|
prices,
|
||||||
has_open_orders: perp_position.has_open_orders(),
|
has_open_orders: perp_position.has_open_orders(),
|
||||||
trusted_market: perp_market.trusted_market(),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Total health contribution from perp balances
|
/// Total health contribution from perp balances
|
||||||
///
|
///
|
||||||
/// Due to isolation of perp markets, users may never borrow against perp
|
/// For fully isolated perp markets, users may never borrow against unsettled
|
||||||
/// positions in untrusted without settling first: perp health is capped at zero.
|
/// positive perp pnl, there pnl_asset_weight == 0 and there can't be positive
|
||||||
|
/// health contributions from these perp market. We sometimes call these markets
|
||||||
|
/// "untrusted markets".
|
||||||
///
|
///
|
||||||
/// Users need to settle their perp pnl with other perp market participants
|
/// Users need to settle their perp pnl with other perp market participants
|
||||||
/// in order to realize their gains if they want to use them as collateral.
|
/// in order to realize their gains if they want to use them as collateral.
|
||||||
|
@ -264,32 +268,43 @@ impl PerpInfo {
|
||||||
/// zero (if users could borrow against their perp balances they might now
|
/// zero (if users could borrow against their perp balances they might now
|
||||||
/// be bankrupt) or suddenly increase a lot (if users could borrow against perp
|
/// be bankrupt) or suddenly increase a lot (if users could borrow against perp
|
||||||
/// balances they could now borrow other assets).
|
/// balances they could now borrow other assets).
|
||||||
|
///
|
||||||
|
/// Other markets may be liquid enough that we have enough confidence to allow
|
||||||
|
/// users to borrow against unsettled positive pnl to some extend. In these cases,
|
||||||
|
/// the pnl asset weights would be >0.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn health_contribution(&self, health_type: HealthType) -> I80F48 {
|
pub fn health_contribution(&self, health_type: HealthType) -> I80F48 {
|
||||||
let c = self.uncapped_health_contribution(health_type);
|
let contribution = self.unweighted_health_contribution(health_type);
|
||||||
|
|
||||||
if self.trusted_market {
|
if contribution > 0 {
|
||||||
c
|
let asset_weight = match health_type {
|
||||||
|
HealthType::Init => self.init_pnl_asset_weight,
|
||||||
|
HealthType::Maint => self.maint_pnl_asset_weight,
|
||||||
|
};
|
||||||
|
|
||||||
|
cm!(asset_weight * contribution)
|
||||||
} else {
|
} else {
|
||||||
c.min(I80F48::ZERO)
|
contribution
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn uncapped_health_contribution(&self, health_type: HealthType) -> I80F48 {
|
pub fn unweighted_health_contribution(&self, health_type: HealthType) -> I80F48 {
|
||||||
let order_execution_case = |orders_base_lots: i64, order_price: I80F48| {
|
let order_execution_case = |orders_base_lots: i64, order_price: I80F48| {
|
||||||
let net_base_native =
|
let net_base_native =
|
||||||
I80F48::from(cm!((self.base_lots + orders_base_lots) * self.base_lot_size));
|
I80F48::from(cm!((self.base_lots + orders_base_lots) * self.base_lot_size));
|
||||||
let (weight, base_price) = match (health_type, net_base_native.is_negative()) {
|
let (weight, base_price) = match (health_type, net_base_native.is_negative()) {
|
||||||
(HealthType::Init, true) => (self.init_liab_weight, self.prices.liab(health_type)),
|
(HealthType::Init, true) => {
|
||||||
|
(self.init_base_liab_weight, self.prices.liab(health_type))
|
||||||
|
}
|
||||||
(HealthType::Init, false) => {
|
(HealthType::Init, false) => {
|
||||||
(self.init_asset_weight, self.prices.asset(health_type))
|
(self.init_base_asset_weight, self.prices.asset(health_type))
|
||||||
}
|
}
|
||||||
(HealthType::Maint, true) => {
|
(HealthType::Maint, true) => {
|
||||||
(self.maint_liab_weight, self.prices.liab(health_type))
|
(self.maint_base_liab_weight, self.prices.liab(health_type))
|
||||||
}
|
}
|
||||||
(HealthType::Maint, false) => {
|
(HealthType::Maint, false) => {
|
||||||
(self.maint_asset_weight, self.prices.asset(health_type))
|
(self.maint_base_asset_weight, self.prices.asset(health_type))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Total value of the order-execution adjusted base position
|
// Total value of the order-execution adjusted base position
|
||||||
|
@ -437,10 +452,10 @@ impl HealthCache {
|
||||||
self.perp_infos.iter().any(|p| p.base_lots != 0)
|
self.perp_infos.iter().any(|p| p.base_lots != 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_perp_positive_trusted_pnl_without_base_position(&self) -> bool {
|
pub fn has_perp_positive_maint_pnl_without_base_position(&self) -> bool {
|
||||||
self.perp_infos
|
self.perp_infos
|
||||||
.iter()
|
.iter()
|
||||||
.any(|p| p.trusted_market && p.base_lots == 0 && p.quote > 0)
|
.any(|p| p.maint_pnl_asset_weight > 0 && p.base_lots == 0 && p.quote > 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_perp_negative_pnl(&self) -> bool {
|
pub fn has_perp_negative_pnl(&self) -> bool {
|
||||||
|
@ -473,7 +488,7 @@ impl HealthCache {
|
||||||
pub fn has_phase2_liquidatable(&self) -> bool {
|
pub fn has_phase2_liquidatable(&self) -> bool {
|
||||||
self.has_spot_assets() && self.has_spot_borrows()
|
self.has_spot_assets() && self.has_spot_borrows()
|
||||||
|| self.has_perp_base_positions()
|
|| self.has_perp_base_positions()
|
||||||
|| self.has_perp_positive_trusted_pnl_without_base_position()
|
|| self.has_perp_positive_maint_pnl_without_base_position()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn require_after_phase2_liquidation(&self) -> Result<()> {
|
pub fn require_after_phase2_liquidation(&self) -> Result<()> {
|
||||||
|
@ -487,7 +502,7 @@ impl HealthCache {
|
||||||
MangoError::HasLiquidatablePerpBasePosition
|
MangoError::HasLiquidatablePerpBasePosition
|
||||||
);
|
);
|
||||||
require!(
|
require!(
|
||||||
!self.has_perp_positive_trusted_pnl_without_base_position(),
|
!self.has_perp_positive_maint_pnl_without_base_position(),
|
||||||
MangoError::HasLiquidatableTrustedPerpPnl
|
MangoError::HasLiquidatableTrustedPerpPnl
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -636,12 +651,8 @@ impl HealthCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
for perp_info in self.perp_infos.iter() {
|
for perp_info in self.perp_infos.iter() {
|
||||||
if perp_info.trusted_market {
|
let positive_contrib = perp_info.health_contribution(health_type).max(I80F48::ZERO);
|
||||||
let positive_contrib = perp_info
|
cm!(health += positive_contrib);
|
||||||
.uncapped_health_contribution(health_type)
|
|
||||||
.max(I80F48::ZERO);
|
|
||||||
cm!(health += positive_contrib);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
health
|
health
|
||||||
}
|
}
|
||||||
|
@ -842,7 +853,7 @@ mod tests {
|
||||||
oo1.data().native_coin_free = 3;
|
oo1.data().native_coin_free = 3;
|
||||||
oo1.data().referrer_rebates_accrued = 2;
|
oo1.data().referrer_rebates_accrued = 2;
|
||||||
|
|
||||||
let mut perp1 = mock_perp_market(group, oracle2.pubkey, 5.0, 9, 0.2, 0.1);
|
let mut perp1 = mock_perp_market(group, oracle2.pubkey, 5.0, 9, (0.2, 0.1), (0.05, 0.02));
|
||||||
let perpaccount = account.ensure_perp_position(9, 1).unwrap().0;
|
let perpaccount = account.ensure_perp_position(9, 1).unwrap().0;
|
||||||
perpaccount.record_trade(perp1.data(), 3, -I80F48::from(310u16));
|
perpaccount.record_trade(perp1.data(), 3, -I80F48::from(310u16));
|
||||||
perpaccount.bids_base_lots = 7;
|
perpaccount.bids_base_lots = 7;
|
||||||
|
@ -966,7 +977,7 @@ mod tests {
|
||||||
oo2.data().native_pc_total = testcase.oo_1_3.0;
|
oo2.data().native_pc_total = testcase.oo_1_3.0;
|
||||||
oo2.data().native_coin_total = testcase.oo_1_3.1;
|
oo2.data().native_coin_total = testcase.oo_1_3.1;
|
||||||
|
|
||||||
let mut perp1 = mock_perp_market(group, oracle2.pubkey, 5.0, 9, 0.2, 0.1);
|
let mut perp1 = mock_perp_market(group, oracle2.pubkey, 5.0, 9, (0.2, 0.1), (0.05, 0.02));
|
||||||
let perpaccount = account.ensure_perp_position(9, 1).unwrap().0;
|
let perpaccount = account.ensure_perp_position(9, 1).unwrap().0;
|
||||||
perpaccount.record_trade(
|
perpaccount.record_trade(
|
||||||
perp1.data(),
|
perp1.data(),
|
||||||
|
@ -1033,27 +1044,27 @@ mod tests {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
TestHealth1Case {
|
TestHealth1Case {
|
||||||
// 2
|
// 2: weighted positive perp pnl
|
||||||
perp1: (-1, 100, 0, 0),
|
perp1: (-1, 100, 0, 0),
|
||||||
expected_health: 0.0,
|
expected_health: 0.95 * (100.0 - 1.2 * 1.0 * base_lots_to_quote),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
TestHealth1Case {
|
TestHealth1Case {
|
||||||
// 3
|
// 3: negative perp pnl is not weighted
|
||||||
perp1: (1, -100, 0, 0),
|
perp1: (1, -100, 0, 0),
|
||||||
expected_health: -100.0 + 0.8 * 1.0 * base_lots_to_quote,
|
expected_health: -100.0 + 0.8 * 1.0 * base_lots_to_quote,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
TestHealth1Case {
|
TestHealth1Case {
|
||||||
// 4
|
// 4: perp health
|
||||||
perp1: (10, 100, 0, 0),
|
perp1: (10, 100, 0, 0),
|
||||||
expected_health: 0.0,
|
expected_health: 0.95 * (100.0 + 0.8 * 10.0 * base_lots_to_quote),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
TestHealth1Case {
|
TestHealth1Case {
|
||||||
// 5
|
// 5: perp health
|
||||||
perp1: (30, -100, 0, 0),
|
perp1: (30, -100, 0, 0),
|
||||||
expected_health: 0.0,
|
expected_health: 0.95 * (-100.0 + 0.8 * 30.0 * base_lots_to_quote),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
TestHealth1Case { // 6, reserved oo funds
|
TestHealth1Case { // 6, reserved oo funds
|
||||||
|
|
|
@ -310,12 +310,13 @@ impl HealthCache {
|
||||||
let prices = &perp_info.prices;
|
let prices = &perp_info.prices;
|
||||||
let base_lot_size = I80F48::from(perp_info.base_lot_size);
|
let base_lot_size = I80F48::from(perp_info.base_lot_size);
|
||||||
|
|
||||||
// If the price is sufficiently good then health will just increase from trading
|
// If the price is sufficiently good then health will just increase from trading.
|
||||||
// TODO: This is not actually correct, since perp health for untrusted markets can't go above 0
|
// It's ok to ignore the pnl_asset_weight here because we'll jump out early if this
|
||||||
|
// slope is >=0, and the extra asset weight would just decrease it.
|
||||||
let final_health_slope = if direction == 1 {
|
let final_health_slope = if direction == 1 {
|
||||||
perp_info.init_asset_weight * prices.asset(health_type) - price
|
perp_info.init_base_asset_weight * prices.asset(health_type) - price
|
||||||
} else {
|
} else {
|
||||||
price - perp_info.init_liab_weight * prices.liab(health_type)
|
price - perp_info.init_base_liab_weight * prices.liab(health_type)
|
||||||
};
|
};
|
||||||
if final_health_slope >= 0 {
|
if final_health_slope >= 0 {
|
||||||
return Ok(i64::MAX);
|
return Ok(i64::MAX);
|
||||||
|
@ -374,8 +375,7 @@ impl HealthCache {
|
||||||
let perp_info = &start_cache.perp_infos[perp_info_index];
|
let perp_info = &start_cache.perp_infos[perp_info_index];
|
||||||
let start_health_uncapped = start_health
|
let start_health_uncapped = start_health
|
||||||
- perp_info.health_contribution(HealthType::Init)
|
- perp_info.health_contribution(HealthType::Init)
|
||||||
+ perp_info.uncapped_health_contribution(HealthType::Init);
|
+ perp_info.unweighted_health_contribution(HealthType::Init);
|
||||||
|
|
||||||
// We add 1 here because health is computed for truncated base_lots and we want to guarantee
|
// We add 1 here because health is computed for truncated base_lots and we want to guarantee
|
||||||
// zero_health_ratio <= 0.
|
// zero_health_ratio <= 0.
|
||||||
let zero_health_amount = case1_start_i80f48
|
let zero_health_amount = case1_start_i80f48
|
||||||
|
@ -938,10 +938,12 @@ mod tests {
|
||||||
let base_lot_size = 100;
|
let base_lot_size = 100;
|
||||||
let default_perp_info = |x| PerpInfo {
|
let default_perp_info = |x| PerpInfo {
|
||||||
perp_market_index: 0,
|
perp_market_index: 0,
|
||||||
maint_asset_weight: I80F48::from_num(1.0 - x),
|
maint_base_asset_weight: I80F48::from_num(1.0 - x),
|
||||||
init_asset_weight: I80F48::from_num(1.0 - x),
|
init_base_asset_weight: I80F48::from_num(1.0 - x),
|
||||||
maint_liab_weight: I80F48::from_num(1.0 + x),
|
maint_base_liab_weight: I80F48::from_num(1.0 + x),
|
||||||
init_liab_weight: I80F48::from_num(1.0 + x),
|
init_base_liab_weight: I80F48::from_num(1.0 + x),
|
||||||
|
maint_pnl_asset_weight: I80F48::from_num(0.6),
|
||||||
|
init_pnl_asset_weight: I80F48::from_num(0.6),
|
||||||
base_lot_size,
|
base_lot_size,
|
||||||
base_lots: 0,
|
base_lots: 0,
|
||||||
bids_base_lots: 0,
|
bids_base_lots: 0,
|
||||||
|
@ -949,7 +951,6 @@ mod tests {
|
||||||
quote: I80F48::ZERO,
|
quote: I80F48::ZERO,
|
||||||
prices: Prices::new_single_price(I80F48::from_num(2.0)),
|
prices: Prices::new_single_price(I80F48::from_num(2.0)),
|
||||||
has_open_orders: false,
|
has_open_orders: false,
|
||||||
trusted_market: false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let health_cache = HealthCache {
|
let health_cache = HealthCache {
|
||||||
|
@ -1088,7 +1089,7 @@ mod tests {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut perp1 = mock_perp_market(group, oracle1.pubkey, 1.0, 9, 0.2, 0.1);
|
let mut perp1 = mock_perp_market(group, oracle1.pubkey, 1.0, 9, (0.2, 0.1), (0.05, 0.02));
|
||||||
perp1.data().long_funding = I80F48::from_num(10.1);
|
perp1.data().long_funding = I80F48::from_num(10.1);
|
||||||
let perpaccount = account.ensure_perp_position(9, 1).unwrap().0;
|
let perpaccount = account.ensure_perp_position(9, 1).unwrap().0;
|
||||||
perpaccount.record_trade(perp1.data(), 10, I80F48::from(-110));
|
perpaccount.record_trade(perp1.data(), 10, I80F48::from(-110));
|
||||||
|
@ -1126,8 +1127,8 @@ mod tests {
|
||||||
|
|
||||||
let mut oo1 = TestAccount::<OpenOrders>::new_zeroed();
|
let mut oo1 = TestAccount::<OpenOrders>::new_zeroed();
|
||||||
|
|
||||||
let mut perp1 = mock_perp_market(group, oracle1.pubkey, 1.0, 9, 0.2, 0.1);
|
let mut perp1 = mock_perp_market(group, oracle1.pubkey, 1.0, 9, (0.2, 0.1), (0.05, 0.02));
|
||||||
let mut perp2 = mock_perp_market(group, oracle2.pubkey, 5.0, 8, 0.2, 0.1);
|
let mut perp2 = mock_perp_market(group, oracle2.pubkey, 5.0, 8, (0.2, 0.1), (0.05, 0.02));
|
||||||
|
|
||||||
let oracle1_account_info = oracle1.as_account_info();
|
let oracle1_account_info = oracle1.as_account_info();
|
||||||
let oracle2_account_info = oracle2.as_account_info();
|
let oracle2_account_info = oracle2.as_account_info();
|
||||||
|
@ -1180,7 +1181,7 @@ mod tests {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut perp1 = mock_perp_market(group, oracle1.pubkey, 1.0, 9, 0.2, 0.1);
|
let mut perp1 = mock_perp_market(group, oracle1.pubkey, 1.0, 9, (0.2, 0.1), (0.05, 0.02));
|
||||||
perp1.data().stable_price_model.stable_price = 0.5;
|
perp1.data().stable_price_model.stable_price = 0.5;
|
||||||
let perpaccount = account3.ensure_perp_position(9, 1).unwrap().0;
|
let perpaccount = account3.ensure_perp_position(9, 1).unwrap().0;
|
||||||
perpaccount.record_trade(perp1.data(), 10, I80F48::from(-100));
|
perpaccount.record_trade(perp1.data(), 10, I80F48::from(-100));
|
||||||
|
|
|
@ -108,17 +108,19 @@ pub fn mock_perp_market(
|
||||||
oracle: Pubkey,
|
oracle: Pubkey,
|
||||||
price: f64,
|
price: f64,
|
||||||
market_index: PerpMarketIndex,
|
market_index: PerpMarketIndex,
|
||||||
init_weights: f64,
|
base_weights: (f64, f64),
|
||||||
maint_weights: f64,
|
pnl_weights: (f64, f64),
|
||||||
) -> TestAccount<PerpMarket> {
|
) -> TestAccount<PerpMarket> {
|
||||||
let mut pm = TestAccount::<PerpMarket>::new_zeroed();
|
let mut pm = TestAccount::<PerpMarket>::new_zeroed();
|
||||||
pm.data().group = group;
|
pm.data().group = group;
|
||||||
pm.data().oracle = oracle;
|
pm.data().oracle = oracle;
|
||||||
pm.data().perp_market_index = market_index;
|
pm.data().perp_market_index = market_index;
|
||||||
pm.data().init_asset_weight = I80F48::from_num(1.0 - init_weights);
|
pm.data().init_base_asset_weight = I80F48::from_num(1.0 - base_weights.0);
|
||||||
pm.data().init_liab_weight = I80F48::from_num(1.0 + init_weights);
|
pm.data().init_base_liab_weight = I80F48::from_num(1.0 + base_weights.0);
|
||||||
pm.data().maint_asset_weight = I80F48::from_num(1.0 - maint_weights);
|
pm.data().maint_base_asset_weight = I80F48::from_num(1.0 - base_weights.1);
|
||||||
pm.data().maint_liab_weight = I80F48::from_num(1.0 + maint_weights);
|
pm.data().maint_base_liab_weight = I80F48::from_num(1.0 + base_weights.1);
|
||||||
|
pm.data().init_pnl_asset_weight = I80F48::from_num(1.0 - pnl_weights.0);
|
||||||
|
pm.data().maint_pnl_asset_weight = I80F48::from_num(1.0 - pnl_weights.1);
|
||||||
pm.data().quote_lot_size = 100;
|
pm.data().quote_lot_size = 100;
|
||||||
pm.data().base_lot_size = 10;
|
pm.data().base_lot_size = 10;
|
||||||
pm.data().stable_price_model.reset_to_price(price, 0);
|
pm.data().stable_price_model.reset_to_price(price, 0);
|
||||||
|
|
|
@ -56,10 +56,12 @@ pub fn perp_create_market(
|
||||||
base_decimals: u8,
|
base_decimals: u8,
|
||||||
quote_lot_size: i64,
|
quote_lot_size: i64,
|
||||||
base_lot_size: i64,
|
base_lot_size: i64,
|
||||||
maint_asset_weight: f32,
|
maint_base_asset_weight: f32,
|
||||||
init_asset_weight: f32,
|
init_base_asset_weight: f32,
|
||||||
maint_liab_weight: f32,
|
maint_base_liab_weight: f32,
|
||||||
init_liab_weight: f32,
|
init_base_liab_weight: f32,
|
||||||
|
maint_pnl_asset_weight: f32,
|
||||||
|
init_pnl_asset_weight: f32,
|
||||||
liquidation_fee: f32,
|
liquidation_fee: f32,
|
||||||
maker_fee: f32,
|
maker_fee: f32,
|
||||||
taker_fee: f32,
|
taker_fee: f32,
|
||||||
|
@ -67,7 +69,6 @@ pub fn perp_create_market(
|
||||||
max_funding: f32,
|
max_funding: f32,
|
||||||
impact_quantity: i64,
|
impact_quantity: i64,
|
||||||
group_insurance_fund: bool,
|
group_insurance_fund: bool,
|
||||||
trusted_market: bool,
|
|
||||||
fee_penalty: f32,
|
fee_penalty: f32,
|
||||||
settle_fee_flat: f32,
|
settle_fee_flat: f32,
|
||||||
settle_fee_amount_threshold: f32,
|
settle_fee_amount_threshold: f32,
|
||||||
|
@ -93,7 +94,7 @@ pub fn perp_create_market(
|
||||||
group: ctx.accounts.group.key(),
|
group: ctx.accounts.group.key(),
|
||||||
settle_token_index,
|
settle_token_index,
|
||||||
perp_market_index,
|
perp_market_index,
|
||||||
trusted_market: u8::from(trusted_market),
|
blocked1: 0,
|
||||||
group_insurance_fund: u8::from(group_insurance_fund),
|
group_insurance_fund: u8::from(group_insurance_fund),
|
||||||
bump: *ctx.bumps.get("perp_market").ok_or(MangoError::SomeError)?,
|
bump: *ctx.bumps.get("perp_market").ok_or(MangoError::SomeError)?,
|
||||||
base_decimals,
|
base_decimals,
|
||||||
|
@ -106,10 +107,10 @@ pub fn perp_create_market(
|
||||||
stable_price_model: StablePriceModel::default(),
|
stable_price_model: StablePriceModel::default(),
|
||||||
quote_lot_size,
|
quote_lot_size,
|
||||||
base_lot_size,
|
base_lot_size,
|
||||||
maint_asset_weight: I80F48::from_num(maint_asset_weight),
|
maint_base_asset_weight: I80F48::from_num(maint_base_asset_weight),
|
||||||
init_asset_weight: I80F48::from_num(init_asset_weight),
|
init_base_asset_weight: I80F48::from_num(init_base_asset_weight),
|
||||||
maint_liab_weight: I80F48::from_num(maint_liab_weight),
|
maint_base_liab_weight: I80F48::from_num(maint_base_liab_weight),
|
||||||
init_liab_weight: I80F48::from_num(init_liab_weight),
|
init_base_liab_weight: I80F48::from_num(init_base_liab_weight),
|
||||||
open_interest: 0,
|
open_interest: 0,
|
||||||
seq_num: 0,
|
seq_num: 0,
|
||||||
registration_time: now_ts,
|
registration_time: now_ts,
|
||||||
|
@ -132,7 +133,10 @@ pub fn perp_create_market(
|
||||||
padding3: Default::default(),
|
padding3: Default::default(),
|
||||||
settle_pnl_limit_window_size_ts,
|
settle_pnl_limit_window_size_ts,
|
||||||
reduce_only: 0,
|
reduce_only: 0,
|
||||||
reserved: [0; 1943],
|
padding4: Default::default(),
|
||||||
|
maint_pnl_asset_weight: I80F48::from_num(maint_pnl_asset_weight),
|
||||||
|
init_pnl_asset_weight: I80F48::from_num(init_pnl_asset_weight),
|
||||||
|
reserved: [0; 1904],
|
||||||
};
|
};
|
||||||
|
|
||||||
let oracle_price =
|
let oracle_price =
|
||||||
|
|
|
@ -28,10 +28,12 @@ pub fn perp_edit_market(
|
||||||
oracle_opt: Option<Pubkey>,
|
oracle_opt: Option<Pubkey>,
|
||||||
oracle_config_opt: Option<OracleConfigParams>,
|
oracle_config_opt: Option<OracleConfigParams>,
|
||||||
base_decimals_opt: Option<u8>,
|
base_decimals_opt: Option<u8>,
|
||||||
maint_asset_weight_opt: Option<f32>,
|
maint_base_asset_weight_opt: Option<f32>,
|
||||||
init_asset_weight_opt: Option<f32>,
|
init_base_asset_weight_opt: Option<f32>,
|
||||||
maint_liab_weight_opt: Option<f32>,
|
maint_base_liab_weight_opt: Option<f32>,
|
||||||
init_liab_weight_opt: Option<f32>,
|
init_base_liab_weight_opt: Option<f32>,
|
||||||
|
maint_pnl_asset_weight_opt: Option<f32>,
|
||||||
|
init_pnl_asset_weight_opt: Option<f32>,
|
||||||
liquidation_fee_opt: Option<f32>,
|
liquidation_fee_opt: Option<f32>,
|
||||||
maker_fee_opt: Option<f32>,
|
maker_fee_opt: Option<f32>,
|
||||||
taker_fee_opt: Option<f32>,
|
taker_fee_opt: Option<f32>,
|
||||||
|
@ -39,7 +41,6 @@ pub fn perp_edit_market(
|
||||||
max_funding_opt: Option<f32>,
|
max_funding_opt: Option<f32>,
|
||||||
impact_quantity_opt: Option<i64>,
|
impact_quantity_opt: Option<i64>,
|
||||||
group_insurance_fund_opt: Option<bool>,
|
group_insurance_fund_opt: Option<bool>,
|
||||||
trusted_market_opt: Option<bool>,
|
|
||||||
fee_penalty_opt: Option<f32>,
|
fee_penalty_opt: Option<f32>,
|
||||||
settle_fee_flat_opt: Option<f32>,
|
settle_fee_flat_opt: Option<f32>,
|
||||||
settle_fee_amount_threshold_opt: Option<f32>,
|
settle_fee_amount_threshold_opt: Option<f32>,
|
||||||
|
@ -82,17 +83,23 @@ pub fn perp_edit_market(
|
||||||
// quote_lot_size
|
// quote_lot_size
|
||||||
// base_lot_size
|
// base_lot_size
|
||||||
|
|
||||||
if let Some(maint_asset_weight) = maint_asset_weight_opt {
|
if let Some(maint_base_asset_weight) = maint_base_asset_weight_opt {
|
||||||
perp_market.maint_asset_weight = I80F48::from_num(maint_asset_weight);
|
perp_market.maint_base_asset_weight = I80F48::from_num(maint_base_asset_weight);
|
||||||
}
|
}
|
||||||
if let Some(init_asset_weight) = init_asset_weight_opt {
|
if let Some(init_base_asset_weight) = init_base_asset_weight_opt {
|
||||||
perp_market.init_asset_weight = I80F48::from_num(init_asset_weight);
|
perp_market.init_base_asset_weight = I80F48::from_num(init_base_asset_weight);
|
||||||
}
|
}
|
||||||
if let Some(maint_liab_weight) = maint_liab_weight_opt {
|
if let Some(maint_base_liab_weight) = maint_base_liab_weight_opt {
|
||||||
perp_market.maint_liab_weight = I80F48::from_num(maint_liab_weight);
|
perp_market.maint_base_liab_weight = I80F48::from_num(maint_base_liab_weight);
|
||||||
}
|
}
|
||||||
if let Some(init_liab_weight) = init_liab_weight_opt {
|
if let Some(init_base_liab_weight) = init_base_liab_weight_opt {
|
||||||
perp_market.init_liab_weight = I80F48::from_num(init_liab_weight);
|
perp_market.init_base_liab_weight = I80F48::from_num(init_base_liab_weight);
|
||||||
|
}
|
||||||
|
if let Some(maint_pnl_asset_weight) = maint_pnl_asset_weight_opt {
|
||||||
|
perp_market.maint_pnl_asset_weight = I80F48::from_num(maint_pnl_asset_weight);
|
||||||
|
}
|
||||||
|
if let Some(init_pnl_asset_weight) = init_pnl_asset_weight_opt {
|
||||||
|
perp_market.init_pnl_asset_weight = I80F48::from_num(init_pnl_asset_weight);
|
||||||
}
|
}
|
||||||
if let Some(liquidation_fee) = liquidation_fee_opt {
|
if let Some(liquidation_fee) = liquidation_fee_opt {
|
||||||
perp_market.liquidation_fee = I80F48::from_num(liquidation_fee);
|
perp_market.liquidation_fee = I80F48::from_num(liquidation_fee);
|
||||||
|
@ -140,9 +147,6 @@ pub fn perp_edit_market(
|
||||||
if let Some(group_insurance_fund) = group_insurance_fund_opt {
|
if let Some(group_insurance_fund) = group_insurance_fund_opt {
|
||||||
perp_market.set_elligible_for_group_insurance_fund(group_insurance_fund);
|
perp_market.set_elligible_for_group_insurance_fund(group_insurance_fund);
|
||||||
}
|
}
|
||||||
if let Some(trusted_market) = trusted_market_opt {
|
|
||||||
perp_market.trusted_market = u8::from(trusted_market);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(settle_fee_flat) = settle_fee_flat_opt {
|
if let Some(settle_fee_flat) = settle_fee_flat_opt {
|
||||||
perp_market.settle_fee_flat = settle_fee_flat;
|
perp_market.settle_fee_flat = settle_fee_flat;
|
||||||
|
|
|
@ -99,63 +99,62 @@ pub fn perp_liq_base_position(
|
||||||
|
|
||||||
// Take over the liqee's base in exchange for quote
|
// Take over the liqee's base in exchange for quote
|
||||||
require_msg!(liqee_base_lots != 0, "liqee base position is zero");
|
require_msg!(liqee_base_lots != 0, "liqee base position is zero");
|
||||||
let (base_transfer, quote_transfer) =
|
let (base_transfer, quote_transfer) = if liqee_base_lots > 0 {
|
||||||
if liqee_base_lots > 0 {
|
require_msg!(
|
||||||
require_msg!(
|
max_base_transfer > 0,
|
||||||
max_base_transfer > 0,
|
"max_base_transfer must be positive when liqee's base_position is positive"
|
||||||
"max_base_transfer must be positive when liqee's base_position is positive"
|
);
|
||||||
);
|
|
||||||
|
|
||||||
// health gets reduced by `base * price * perp_init_asset_weight`
|
// health gets reduced by `base * price * perp_init_asset_weight`
|
||||||
// and increased by `base * price * (1 - liq_fee) * quote_init_asset_weight`
|
// and increased by `base * price * (1 - liq_fee) * quote_init_asset_weight`
|
||||||
let quote_init_asset_weight = I80F48::ONE;
|
let quote_init_asset_weight = I80F48::ONE;
|
||||||
let fee_factor = cm!(I80F48::ONE - perp_market.liquidation_fee);
|
let fee_factor = cm!(I80F48::ONE - perp_market.liquidation_fee);
|
||||||
let health_per_lot = cm!(price_per_lot
|
let health_per_lot = cm!(price_per_lot
|
||||||
* (-perp_market.init_asset_weight + quote_init_asset_weight * fee_factor));
|
* (-perp_market.init_base_asset_weight + quote_init_asset_weight * fee_factor));
|
||||||
|
|
||||||
// number of lots to transfer to bring health to zero, rounded up
|
// number of lots to transfer to bring health to zero, rounded up
|
||||||
let base_transfer_for_zero: i64 = cm!(-liqee_init_health / health_per_lot)
|
let base_transfer_for_zero: i64 = cm!(-liqee_init_health / health_per_lot)
|
||||||
.checked_ceil()
|
.checked_ceil()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.checked_to_num()
|
.checked_to_num()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let base_transfer = base_transfer_for_zero
|
let base_transfer = base_transfer_for_zero
|
||||||
.min(liqee_base_lots)
|
.min(liqee_base_lots)
|
||||||
.min(max_base_transfer)
|
.min(max_base_transfer)
|
||||||
.max(0);
|
.max(0);
|
||||||
let quote_transfer = cm!(-I80F48::from(base_transfer) * price_per_lot * fee_factor);
|
let quote_transfer = cm!(-I80F48::from(base_transfer) * price_per_lot * fee_factor);
|
||||||
|
|
||||||
(base_transfer, quote_transfer) // base > 0, quote < 0
|
(base_transfer, quote_transfer) // base > 0, quote < 0
|
||||||
} else {
|
} else {
|
||||||
// liqee_base_lots < 0
|
// liqee_base_lots < 0
|
||||||
require_msg!(
|
require_msg!(
|
||||||
max_base_transfer < 0,
|
max_base_transfer < 0,
|
||||||
"max_base_transfer must be negative when liqee's base_position is positive"
|
"max_base_transfer must be negative when liqee's base_position is positive"
|
||||||
);
|
);
|
||||||
|
|
||||||
// health gets increased by `base * price * perp_init_liab_weight`
|
// health gets increased by `base * price * perp_init_liab_weight`
|
||||||
// and reduced by `base * price * (1 + liq_fee) * quote_init_liab_weight`
|
// and reduced by `base * price * (1 + liq_fee) * quote_init_liab_weight`
|
||||||
let quote_init_liab_weight = I80F48::ONE;
|
let quote_init_liab_weight = I80F48::ONE;
|
||||||
let fee_factor = cm!(I80F48::ONE + perp_market.liquidation_fee);
|
let fee_factor = cm!(I80F48::ONE + perp_market.liquidation_fee);
|
||||||
let health_per_lot = cm!(price_per_lot
|
let health_per_lot = cm!(price_per_lot
|
||||||
* (perp_market.init_liab_weight - quote_init_liab_weight * fee_factor));
|
* (perp_market.init_base_liab_weight - quote_init_liab_weight * fee_factor));
|
||||||
|
|
||||||
// (negative) number of lots to transfer to bring health to zero, rounded away from zero
|
// (negative) number of lots to transfer to bring health to zero, rounded away from zero
|
||||||
let base_transfer_for_zero: i64 = cm!(liqee_init_health / health_per_lot)
|
let base_transfer_for_zero: i64 = cm!(liqee_init_health / health_per_lot)
|
||||||
.checked_floor()
|
.checked_floor()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.checked_to_num()
|
.checked_to_num()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let base_transfer = base_transfer_for_zero
|
let base_transfer = base_transfer_for_zero
|
||||||
.max(liqee_base_lots)
|
.max(liqee_base_lots)
|
||||||
.max(max_base_transfer)
|
.max(max_base_transfer)
|
||||||
.min(0);
|
.min(0);
|
||||||
let quote_transfer = cm!(-I80F48::from(base_transfer) * price_per_lot * fee_factor);
|
let quote_transfer = cm!(-I80F48::from(base_transfer) * price_per_lot * fee_factor);
|
||||||
|
|
||||||
(base_transfer, quote_transfer) // base < 0, quote > 0
|
(base_transfer, quote_transfer) // base < 0, quote > 0
|
||||||
};
|
};
|
||||||
|
|
||||||
// Execute the transfer. This is essentially a forced trade and updates the
|
// Execute the transfer. This is essentially a forced trade and updates the
|
||||||
// liqee and liqors entry and break even prices.
|
// liqee and liqors entry and break even prices.
|
||||||
|
|
|
@ -434,10 +434,12 @@ pub mod mango_v4 {
|
||||||
base_decimals: u8,
|
base_decimals: u8,
|
||||||
quote_lot_size: i64,
|
quote_lot_size: i64,
|
||||||
base_lot_size: i64,
|
base_lot_size: i64,
|
||||||
maint_asset_weight: f32,
|
maint_base_asset_weight: f32,
|
||||||
init_asset_weight: f32,
|
init_base_asset_weight: f32,
|
||||||
maint_liab_weight: f32,
|
maint_base_liab_weight: f32,
|
||||||
init_liab_weight: f32,
|
init_base_liab_weight: f32,
|
||||||
|
maint_pnl_asset_weight: f32,
|
||||||
|
init_pnl_asset_weight: f32,
|
||||||
liquidation_fee: f32,
|
liquidation_fee: f32,
|
||||||
maker_fee: f32,
|
maker_fee: f32,
|
||||||
taker_fee: f32,
|
taker_fee: f32,
|
||||||
|
@ -445,7 +447,6 @@ pub mod mango_v4 {
|
||||||
max_funding: f32,
|
max_funding: f32,
|
||||||
impact_quantity: i64,
|
impact_quantity: i64,
|
||||||
group_insurance_fund: bool,
|
group_insurance_fund: bool,
|
||||||
trusted_market: bool,
|
|
||||||
fee_penalty: f32,
|
fee_penalty: f32,
|
||||||
settle_fee_flat: f32,
|
settle_fee_flat: f32,
|
||||||
settle_fee_amount_threshold: f32,
|
settle_fee_amount_threshold: f32,
|
||||||
|
@ -463,10 +464,12 @@ pub mod mango_v4 {
|
||||||
base_decimals,
|
base_decimals,
|
||||||
quote_lot_size,
|
quote_lot_size,
|
||||||
base_lot_size,
|
base_lot_size,
|
||||||
maint_asset_weight,
|
maint_base_asset_weight,
|
||||||
init_asset_weight,
|
init_base_asset_weight,
|
||||||
maint_liab_weight,
|
maint_base_liab_weight,
|
||||||
init_liab_weight,
|
init_base_liab_weight,
|
||||||
|
maint_pnl_asset_weight,
|
||||||
|
init_pnl_asset_weight,
|
||||||
liquidation_fee,
|
liquidation_fee,
|
||||||
maker_fee,
|
maker_fee,
|
||||||
taker_fee,
|
taker_fee,
|
||||||
|
@ -474,7 +477,6 @@ pub mod mango_v4 {
|
||||||
max_funding,
|
max_funding,
|
||||||
impact_quantity,
|
impact_quantity,
|
||||||
group_insurance_fund,
|
group_insurance_fund,
|
||||||
trusted_market,
|
|
||||||
fee_penalty,
|
fee_penalty,
|
||||||
settle_fee_flat,
|
settle_fee_flat,
|
||||||
settle_fee_amount_threshold,
|
settle_fee_amount_threshold,
|
||||||
|
@ -490,10 +492,12 @@ pub mod mango_v4 {
|
||||||
oracle_opt: Option<Pubkey>,
|
oracle_opt: Option<Pubkey>,
|
||||||
oracle_config_opt: Option<OracleConfigParams>,
|
oracle_config_opt: Option<OracleConfigParams>,
|
||||||
base_decimals_opt: Option<u8>,
|
base_decimals_opt: Option<u8>,
|
||||||
maint_asset_weight_opt: Option<f32>,
|
maint_base_asset_weight_opt: Option<f32>,
|
||||||
init_asset_weight_opt: Option<f32>,
|
init_base_asset_weight_opt: Option<f32>,
|
||||||
maint_liab_weight_opt: Option<f32>,
|
maint_base_liab_weight_opt: Option<f32>,
|
||||||
init_liab_weight_opt: Option<f32>,
|
init_base_liab_weight_opt: Option<f32>,
|
||||||
|
maint_pnl_asset_weight_opt: Option<f32>,
|
||||||
|
init_pnl_asset_weight_opt: Option<f32>,
|
||||||
liquidation_fee_opt: Option<f32>,
|
liquidation_fee_opt: Option<f32>,
|
||||||
maker_fee_opt: Option<f32>,
|
maker_fee_opt: Option<f32>,
|
||||||
taker_fee_opt: Option<f32>,
|
taker_fee_opt: Option<f32>,
|
||||||
|
@ -501,7 +505,6 @@ pub mod mango_v4 {
|
||||||
max_funding_opt: Option<f32>,
|
max_funding_opt: Option<f32>,
|
||||||
impact_quantity_opt: Option<i64>,
|
impact_quantity_opt: Option<i64>,
|
||||||
group_insurance_fund_opt: Option<bool>,
|
group_insurance_fund_opt: Option<bool>,
|
||||||
trusted_market_opt: Option<bool>,
|
|
||||||
fee_penalty_opt: Option<f32>,
|
fee_penalty_opt: Option<f32>,
|
||||||
settle_fee_flat_opt: Option<f32>,
|
settle_fee_flat_opt: Option<f32>,
|
||||||
settle_fee_amount_threshold_opt: Option<f32>,
|
settle_fee_amount_threshold_opt: Option<f32>,
|
||||||
|
@ -518,10 +521,12 @@ pub mod mango_v4 {
|
||||||
oracle_opt,
|
oracle_opt,
|
||||||
oracle_config_opt,
|
oracle_config_opt,
|
||||||
base_decimals_opt,
|
base_decimals_opt,
|
||||||
maint_asset_weight_opt,
|
maint_base_asset_weight_opt,
|
||||||
init_asset_weight_opt,
|
init_base_asset_weight_opt,
|
||||||
maint_liab_weight_opt,
|
maint_base_liab_weight_opt,
|
||||||
init_liab_weight_opt,
|
init_base_liab_weight_opt,
|
||||||
|
maint_pnl_asset_weight_opt,
|
||||||
|
init_pnl_asset_weight_opt,
|
||||||
liquidation_fee_opt,
|
liquidation_fee_opt,
|
||||||
maker_fee_opt,
|
maker_fee_opt,
|
||||||
taker_fee_opt,
|
taker_fee_opt,
|
||||||
|
@ -529,7 +534,6 @@ pub mod mango_v4 {
|
||||||
max_funding_opt,
|
max_funding_opt,
|
||||||
impact_quantity_opt,
|
impact_quantity_opt,
|
||||||
group_insurance_fund_opt,
|
group_insurance_fund_opt,
|
||||||
trusted_market_opt,
|
|
||||||
fee_penalty_opt,
|
fee_penalty_opt,
|
||||||
settle_fee_flat_opt,
|
settle_fee_flat_opt,
|
||||||
settle_fee_amount_threshold_opt,
|
settle_fee_amount_threshold_opt,
|
||||||
|
|
|
@ -88,10 +88,10 @@ mod tests {
|
||||||
let mut perp_market = PerpMarket::zeroed();
|
let mut perp_market = PerpMarket::zeroed();
|
||||||
perp_market.quote_lot_size = 1;
|
perp_market.quote_lot_size = 1;
|
||||||
perp_market.base_lot_size = 1;
|
perp_market.base_lot_size = 1;
|
||||||
perp_market.maint_asset_weight = I80F48::ONE;
|
perp_market.maint_base_asset_weight = I80F48::ONE;
|
||||||
perp_market.maint_liab_weight = I80F48::ONE;
|
perp_market.maint_base_liab_weight = I80F48::ONE;
|
||||||
perp_market.init_asset_weight = I80F48::ONE;
|
perp_market.init_base_asset_weight = I80F48::ONE;
|
||||||
perp_market.init_liab_weight = I80F48::ONE;
|
perp_market.init_base_liab_weight = I80F48::ONE;
|
||||||
|
|
||||||
(perp_market, oracle_price, event_queue, book)
|
(perp_market, oracle_price, event_queue, book)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,8 @@ pub struct PerpMarket {
|
||||||
/// Lookup indices
|
/// Lookup indices
|
||||||
pub perp_market_index: PerpMarketIndex,
|
pub perp_market_index: PerpMarketIndex,
|
||||||
|
|
||||||
/// May this market contribute positive values to health?
|
// Used to store trusted_market here
|
||||||
pub trusted_market: u8,
|
pub blocked1: u8,
|
||||||
|
|
||||||
/// Is this market covered by the group insurance fund?
|
/// Is this market covered by the group insurance fund?
|
||||||
pub group_insurance_fund: u8,
|
pub group_insurance_fund: u8,
|
||||||
|
@ -56,10 +56,10 @@ pub struct PerpMarket {
|
||||||
|
|
||||||
// These weights apply to the base asset, the quote token is always assumed to be
|
// These weights apply to the base asset, the quote token is always assumed to be
|
||||||
// the health-reference token and have 1 for price and weights
|
// the health-reference token and have 1 for price and weights
|
||||||
pub maint_asset_weight: I80F48,
|
pub maint_base_asset_weight: I80F48,
|
||||||
pub init_asset_weight: I80F48,
|
pub init_base_asset_weight: I80F48,
|
||||||
pub maint_liab_weight: I80F48,
|
pub maint_base_liab_weight: I80F48,
|
||||||
pub init_liab_weight: I80F48,
|
pub init_base_liab_weight: I80F48,
|
||||||
|
|
||||||
pub open_interest: i64,
|
pub open_interest: i64,
|
||||||
|
|
||||||
|
@ -114,8 +114,12 @@ pub struct PerpMarket {
|
||||||
pub settle_pnl_limit_window_size_ts: u64,
|
pub settle_pnl_limit_window_size_ts: u64,
|
||||||
|
|
||||||
pub reduce_only: u8,
|
pub reduce_only: u8,
|
||||||
|
pub padding4: [u8; 7],
|
||||||
|
|
||||||
pub reserved: [u8; 1943],
|
pub maint_pnl_asset_weight: I80F48,
|
||||||
|
pub init_pnl_asset_weight: I80F48,
|
||||||
|
|
||||||
|
pub reserved: [u8; 1904],
|
||||||
}
|
}
|
||||||
|
|
||||||
const_assert_eq!(
|
const_assert_eq!(
|
||||||
|
@ -149,7 +153,9 @@ const_assert_eq!(
|
||||||
+ 8
|
+ 8
|
||||||
+ 8
|
+ 8
|
||||||
+ 1
|
+ 1
|
||||||
+ 1943
|
+ 7
|
||||||
|
+ 2 * 16
|
||||||
|
+ 1904
|
||||||
);
|
);
|
||||||
const_assert_eq!(size_of::<PerpMarket>(), 2808);
|
const_assert_eq!(size_of::<PerpMarket>(), 2808);
|
||||||
const_assert_eq!(size_of::<PerpMarket>() % 8, 0);
|
const_assert_eq!(size_of::<PerpMarket>() % 8, 0);
|
||||||
|
@ -173,10 +179,6 @@ impl PerpMarket {
|
||||||
self.group_insurance_fund = u8::from(v);
|
self.group_insurance_fund = u8::from(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trusted_market(&self) -> bool {
|
|
||||||
self.trusted_market == 1
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn settle_pnl_limit_factor(&self) -> I80F48 {
|
pub fn settle_pnl_limit_factor(&self) -> I80F48 {
|
||||||
I80F48::from_num(self.settle_pnl_limit_factor)
|
I80F48::from_num(self.settle_pnl_limit_factor)
|
||||||
}
|
}
|
||||||
|
@ -288,8 +290,8 @@ impl PerpMarket {
|
||||||
oracle_price: I80F48,
|
oracle_price: I80F48,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match side {
|
match side {
|
||||||
Side::Bid => native_price <= cm!(self.maint_liab_weight * oracle_price),
|
Side::Bid => native_price <= cm!(self.maint_base_liab_weight * oracle_price),
|
||||||
Side::Ask => native_price >= cm!(self.maint_asset_weight * oracle_price),
|
Side::Ask => native_price >= cm!(self.maint_base_asset_weight * oracle_price),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,7 +321,7 @@ impl PerpMarket {
|
||||||
group: Pubkey::new_unique(),
|
group: Pubkey::new_unique(),
|
||||||
settle_token_index: 0,
|
settle_token_index: 0,
|
||||||
perp_market_index: 0,
|
perp_market_index: 0,
|
||||||
trusted_market: 0,
|
blocked1: 0,
|
||||||
group_insurance_fund: 0,
|
group_insurance_fund: 0,
|
||||||
bump: 0,
|
bump: 0,
|
||||||
base_decimals: 0,
|
base_decimals: 0,
|
||||||
|
@ -336,10 +338,10 @@ impl PerpMarket {
|
||||||
stable_price_model: StablePriceModel::default(),
|
stable_price_model: StablePriceModel::default(),
|
||||||
quote_lot_size: 1,
|
quote_lot_size: 1,
|
||||||
base_lot_size: 1,
|
base_lot_size: 1,
|
||||||
maint_asset_weight: I80F48::from(1),
|
maint_base_asset_weight: I80F48::from(1),
|
||||||
init_asset_weight: I80F48::from(1),
|
init_base_asset_weight: I80F48::from(1),
|
||||||
maint_liab_weight: I80F48::from(1),
|
maint_base_liab_weight: I80F48::from(1),
|
||||||
init_liab_weight: I80F48::from(1),
|
init_base_liab_weight: I80F48::from(1),
|
||||||
open_interest: 0,
|
open_interest: 0,
|
||||||
seq_num: 0,
|
seq_num: 0,
|
||||||
registration_time: 0,
|
registration_time: 0,
|
||||||
|
@ -362,7 +364,10 @@ impl PerpMarket {
|
||||||
padding3: Default::default(),
|
padding3: Default::default(),
|
||||||
settle_pnl_limit_window_size_ts: 24 * 60 * 60,
|
settle_pnl_limit_window_size_ts: 24 * 60 * 60,
|
||||||
reduce_only: 0,
|
reduce_only: 0,
|
||||||
reserved: [0; 1943],
|
padding4: Default::default(),
|
||||||
|
maint_pnl_asset_weight: I80F48::ONE,
|
||||||
|
init_pnl_asset_weight: I80F48::ONE,
|
||||||
|
reserved: [0; 1904],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2543,15 +2543,16 @@ pub struct PerpCreateMarketInstruction {
|
||||||
pub base_decimals: u8,
|
pub base_decimals: u8,
|
||||||
pub quote_lot_size: i64,
|
pub quote_lot_size: i64,
|
||||||
pub base_lot_size: i64,
|
pub base_lot_size: i64,
|
||||||
pub maint_asset_weight: f32,
|
pub maint_base_asset_weight: f32,
|
||||||
pub init_asset_weight: f32,
|
pub init_base_asset_weight: f32,
|
||||||
pub maint_liab_weight: f32,
|
pub maint_base_liab_weight: f32,
|
||||||
pub init_liab_weight: f32,
|
pub init_base_liab_weight: f32,
|
||||||
|
pub maint_pnl_asset_weight: f32,
|
||||||
|
pub init_pnl_asset_weight: f32,
|
||||||
pub liquidation_fee: f32,
|
pub liquidation_fee: f32,
|
||||||
pub maker_fee: f32,
|
pub maker_fee: f32,
|
||||||
pub taker_fee: f32,
|
pub taker_fee: f32,
|
||||||
pub group_insurance_fund: bool,
|
pub group_insurance_fund: bool,
|
||||||
pub trusted_market: bool,
|
|
||||||
pub fee_penalty: f32,
|
pub fee_penalty: f32,
|
||||||
pub settle_fee_flat: f32,
|
pub settle_fee_flat: f32,
|
||||||
pub settle_fee_amount_threshold: f32,
|
pub settle_fee_amount_threshold: f32,
|
||||||
|
@ -2599,10 +2600,12 @@ impl ClientInstruction for PerpCreateMarketInstruction {
|
||||||
perp_market_index: self.perp_market_index,
|
perp_market_index: self.perp_market_index,
|
||||||
quote_lot_size: self.quote_lot_size,
|
quote_lot_size: self.quote_lot_size,
|
||||||
base_lot_size: self.base_lot_size,
|
base_lot_size: self.base_lot_size,
|
||||||
maint_asset_weight: self.maint_asset_weight,
|
maint_base_asset_weight: self.maint_base_asset_weight,
|
||||||
init_asset_weight: self.init_asset_weight,
|
init_base_asset_weight: self.init_base_asset_weight,
|
||||||
maint_liab_weight: self.maint_liab_weight,
|
maint_base_liab_weight: self.maint_base_liab_weight,
|
||||||
init_liab_weight: self.init_liab_weight,
|
init_base_liab_weight: self.init_base_liab_weight,
|
||||||
|
maint_pnl_asset_weight: self.maint_pnl_asset_weight,
|
||||||
|
init_pnl_asset_weight: self.init_pnl_asset_weight,
|
||||||
liquidation_fee: self.liquidation_fee,
|
liquidation_fee: self.liquidation_fee,
|
||||||
maker_fee: self.maker_fee,
|
maker_fee: self.maker_fee,
|
||||||
taker_fee: self.taker_fee,
|
taker_fee: self.taker_fee,
|
||||||
|
@ -2611,7 +2614,6 @@ impl ClientInstruction for PerpCreateMarketInstruction {
|
||||||
impact_quantity: 100,
|
impact_quantity: 100,
|
||||||
base_decimals: self.base_decimals,
|
base_decimals: self.base_decimals,
|
||||||
group_insurance_fund: self.group_insurance_fund,
|
group_insurance_fund: self.group_insurance_fund,
|
||||||
trusted_market: self.trusted_market,
|
|
||||||
fee_penalty: self.fee_penalty,
|
fee_penalty: self.fee_penalty,
|
||||||
settle_fee_flat: self.settle_fee_flat,
|
settle_fee_flat: self.settle_fee_flat,
|
||||||
settle_fee_amount_threshold: self.settle_fee_amount_threshold,
|
settle_fee_amount_threshold: self.settle_fee_amount_threshold,
|
||||||
|
@ -2656,10 +2658,12 @@ fn perp_edit_instruction_default() -> mango_v4::instruction::PerpEditMarket {
|
||||||
oracle_opt: None,
|
oracle_opt: None,
|
||||||
oracle_config_opt: None,
|
oracle_config_opt: None,
|
||||||
base_decimals_opt: None,
|
base_decimals_opt: None,
|
||||||
maint_asset_weight_opt: None,
|
maint_base_asset_weight_opt: None,
|
||||||
init_asset_weight_opt: None,
|
init_base_asset_weight_opt: None,
|
||||||
maint_liab_weight_opt: None,
|
maint_base_liab_weight_opt: None,
|
||||||
init_liab_weight_opt: None,
|
init_base_liab_weight_opt: None,
|
||||||
|
maint_pnl_asset_weight_opt: None,
|
||||||
|
init_pnl_asset_weight_opt: None,
|
||||||
liquidation_fee_opt: None,
|
liquidation_fee_opt: None,
|
||||||
maker_fee_opt: None,
|
maker_fee_opt: None,
|
||||||
taker_fee_opt: None,
|
taker_fee_opt: None,
|
||||||
|
@ -2667,7 +2671,6 @@ fn perp_edit_instruction_default() -> mango_v4::instruction::PerpEditMarket {
|
||||||
max_funding_opt: None,
|
max_funding_opt: None,
|
||||||
impact_quantity_opt: None,
|
impact_quantity_opt: None,
|
||||||
group_insurance_fund_opt: None,
|
group_insurance_fund_opt: None,
|
||||||
trusted_market_opt: None,
|
|
||||||
fee_penalty_opt: None,
|
fee_penalty_opt: None,
|
||||||
settle_fee_flat_opt: None,
|
settle_fee_flat_opt: None,
|
||||||
settle_fee_amount_threshold_opt: None,
|
settle_fee_amount_threshold_opt: None,
|
||||||
|
|
|
@ -215,10 +215,10 @@ async fn test_health_compute_perp() -> Result<(), TransportError> {
|
||||||
perp_market_index: perp_market_index as PerpMarketIndex,
|
perp_market_index: perp_market_index as PerpMarketIndex,
|
||||||
quote_lot_size: 10,
|
quote_lot_size: 10,
|
||||||
base_lot_size: 100,
|
base_lot_size: 100,
|
||||||
maint_asset_weight: 0.975,
|
maint_base_asset_weight: 0.975,
|
||||||
init_asset_weight: 0.95,
|
init_base_asset_weight: 0.95,
|
||||||
maint_liab_weight: 1.025,
|
maint_base_liab_weight: 1.025,
|
||||||
init_liab_weight: 1.05,
|
init_base_liab_weight: 1.05,
|
||||||
liquidation_fee: 0.012,
|
liquidation_fee: 0.012,
|
||||||
maker_fee: 0.0002,
|
maker_fee: 0.0002,
|
||||||
taker_fee: 0.000,
|
taker_fee: 0.000,
|
||||||
|
|
|
@ -56,10 +56,10 @@ async fn test_liq_perps_force_cancel() -> Result<(), TransportError> {
|
||||||
perp_market_index: 0,
|
perp_market_index: 0,
|
||||||
quote_lot_size: 10,
|
quote_lot_size: 10,
|
||||||
base_lot_size: 100,
|
base_lot_size: 100,
|
||||||
maint_asset_weight: 0.8,
|
maint_base_asset_weight: 0.8,
|
||||||
init_asset_weight: 0.6,
|
init_base_asset_weight: 0.6,
|
||||||
maint_liab_weight: 1.2,
|
maint_base_liab_weight: 1.2,
|
||||||
init_liab_weight: 1.4,
|
init_base_liab_weight: 1.4,
|
||||||
liquidation_fee: 0.05,
|
liquidation_fee: 0.05,
|
||||||
maker_fee: 0.0,
|
maker_fee: 0.0,
|
||||||
taker_fee: 0.0,
|
taker_fee: 0.0,
|
||||||
|
@ -261,10 +261,10 @@ async fn test_liq_perps_base_position_and_bankruptcy() -> Result<(), TransportEr
|
||||||
perp_market_index: 0,
|
perp_market_index: 0,
|
||||||
quote_lot_size: 10,
|
quote_lot_size: 10,
|
||||||
base_lot_size: 100,
|
base_lot_size: 100,
|
||||||
maint_asset_weight: 0.8,
|
maint_base_asset_weight: 0.8,
|
||||||
init_asset_weight: 0.6,
|
init_base_asset_weight: 0.6,
|
||||||
maint_liab_weight: 1.2,
|
maint_base_liab_weight: 1.2,
|
||||||
init_liab_weight: 1.4,
|
init_base_liab_weight: 1.4,
|
||||||
liquidation_fee: 0.05,
|
liquidation_fee: 0.05,
|
||||||
maker_fee: 0.0,
|
maker_fee: 0.0,
|
||||||
taker_fee: 0.0,
|
taker_fee: 0.0,
|
||||||
|
@ -843,10 +843,10 @@ async fn test_liq_perps_bankruptcy() -> Result<(), TransportError> {
|
||||||
perp_market_index,
|
perp_market_index,
|
||||||
quote_lot_size: 1,
|
quote_lot_size: 1,
|
||||||
base_lot_size: 100,
|
base_lot_size: 100,
|
||||||
maint_asset_weight: 0.8,
|
maint_base_asset_weight: 0.8,
|
||||||
init_asset_weight: 0.6,
|
init_base_asset_weight: 0.6,
|
||||||
maint_liab_weight: 1.2,
|
maint_base_liab_weight: 1.2,
|
||||||
init_liab_weight: 1.4,
|
init_base_liab_weight: 1.4,
|
||||||
liquidation_fee: 0.05,
|
liquidation_fee: 0.05,
|
||||||
maker_fee: 0.0,
|
maker_fee: 0.0,
|
||||||
taker_fee: 0.0,
|
taker_fee: 0.0,
|
||||||
|
|
|
@ -76,10 +76,10 @@ async fn test_perp_fixed() -> Result<(), TransportError> {
|
||||||
perp_market_index: 0,
|
perp_market_index: 0,
|
||||||
quote_lot_size: 10,
|
quote_lot_size: 10,
|
||||||
base_lot_size: 100,
|
base_lot_size: 100,
|
||||||
maint_asset_weight: 0.975,
|
maint_base_asset_weight: 0.975,
|
||||||
init_asset_weight: 0.95,
|
init_base_asset_weight: 0.95,
|
||||||
maint_liab_weight: 1.025,
|
maint_base_liab_weight: 1.025,
|
||||||
init_liab_weight: 1.05,
|
init_base_liab_weight: 1.05,
|
||||||
liquidation_fee: 0.012,
|
liquidation_fee: 0.012,
|
||||||
maker_fee: -0.0001,
|
maker_fee: -0.0001,
|
||||||
taker_fee: 0.0002,
|
taker_fee: 0.0002,
|
||||||
|
@ -520,10 +520,10 @@ async fn test_perp_oracle_peg() -> Result<(), TransportError> {
|
||||||
perp_market_index: 0,
|
perp_market_index: 0,
|
||||||
quote_lot_size: 10,
|
quote_lot_size: 10,
|
||||||
base_lot_size: 10000,
|
base_lot_size: 10000,
|
||||||
maint_asset_weight: 0.975,
|
maint_base_asset_weight: 0.975,
|
||||||
init_asset_weight: 0.95,
|
init_base_asset_weight: 0.95,
|
||||||
maint_liab_weight: 1.025,
|
maint_base_liab_weight: 1.025,
|
||||||
init_liab_weight: 1.05,
|
init_base_liab_weight: 1.05,
|
||||||
liquidation_fee: 0.012,
|
liquidation_fee: 0.012,
|
||||||
maker_fee: -0.0001,
|
maker_fee: -0.0001,
|
||||||
taker_fee: 0.0002,
|
taker_fee: 0.0002,
|
||||||
|
|
|
@ -73,10 +73,10 @@ async fn test_perp_settle_pnl() -> Result<(), TransportError> {
|
||||||
perp_market_index: 0,
|
perp_market_index: 0,
|
||||||
quote_lot_size: 10,
|
quote_lot_size: 10,
|
||||||
base_lot_size: 100,
|
base_lot_size: 100,
|
||||||
maint_asset_weight: 0.975,
|
maint_base_asset_weight: 0.975,
|
||||||
init_asset_weight: 0.95,
|
init_base_asset_weight: 0.95,
|
||||||
maint_liab_weight: 1.025,
|
maint_base_liab_weight: 1.025,
|
||||||
init_liab_weight: 1.05,
|
init_base_liab_weight: 1.05,
|
||||||
liquidation_fee: 0.012,
|
liquidation_fee: 0.012,
|
||||||
maker_fee: 0.0002,
|
maker_fee: 0.0002,
|
||||||
taker_fee: 0.000,
|
taker_fee: 0.000,
|
||||||
|
@ -103,10 +103,10 @@ async fn test_perp_settle_pnl() -> Result<(), TransportError> {
|
||||||
perp_market_index: 1,
|
perp_market_index: 1,
|
||||||
quote_lot_size: 10,
|
quote_lot_size: 10,
|
||||||
base_lot_size: 100,
|
base_lot_size: 100,
|
||||||
maint_asset_weight: 0.975,
|
maint_base_asset_weight: 0.975,
|
||||||
init_asset_weight: 0.95,
|
init_base_asset_weight: 0.95,
|
||||||
maint_liab_weight: 1.025,
|
maint_base_liab_weight: 1.025,
|
||||||
init_liab_weight: 1.05,
|
init_base_liab_weight: 1.05,
|
||||||
liquidation_fee: 0.012,
|
liquidation_fee: 0.012,
|
||||||
maker_fee: 0.0002,
|
maker_fee: 0.0002,
|
||||||
taker_fee: 0.000,
|
taker_fee: 0.000,
|
||||||
|
@ -576,10 +576,10 @@ async fn test_perp_settle_pnl_fees() -> Result<(), TransportError> {
|
||||||
perp_market_index: 0,
|
perp_market_index: 0,
|
||||||
quote_lot_size: 10,
|
quote_lot_size: 10,
|
||||||
base_lot_size: 100,
|
base_lot_size: 100,
|
||||||
maint_asset_weight: 1.0,
|
maint_base_asset_weight: 1.0,
|
||||||
init_asset_weight: 1.0,
|
init_base_asset_weight: 1.0,
|
||||||
maint_liab_weight: 1.0,
|
maint_base_liab_weight: 1.0,
|
||||||
init_liab_weight: 1.0,
|
init_base_liab_weight: 1.0,
|
||||||
liquidation_fee: 0.0,
|
liquidation_fee: 0.0,
|
||||||
maker_fee: 0.0,
|
maker_fee: 0.0,
|
||||||
taker_fee: 0.0,
|
taker_fee: 0.0,
|
||||||
|
@ -848,10 +848,10 @@ async fn test_perp_pnl_settle_limit() -> Result<(), TransportError> {
|
||||||
perp_market_index: 0,
|
perp_market_index: 0,
|
||||||
quote_lot_size: 10,
|
quote_lot_size: 10,
|
||||||
base_lot_size: 100,
|
base_lot_size: 100,
|
||||||
maint_asset_weight: 0.975,
|
maint_base_asset_weight: 0.975,
|
||||||
init_asset_weight: 0.95,
|
init_base_asset_weight: 0.95,
|
||||||
maint_liab_weight: 1.025,
|
maint_base_liab_weight: 1.025,
|
||||||
init_liab_weight: 1.05,
|
init_base_liab_weight: 1.05,
|
||||||
liquidation_fee: 0.012,
|
liquidation_fee: 0.012,
|
||||||
maker_fee: 0.0,
|
maker_fee: 0.0,
|
||||||
taker_fee: 0.0,
|
taker_fee: 0.0,
|
||||||
|
|
|
@ -152,10 +152,10 @@ async fn test_perp_settle_fees() -> Result<(), TransportError> {
|
||||||
perp_market_index: 0,
|
perp_market_index: 0,
|
||||||
quote_lot_size: 10,
|
quote_lot_size: 10,
|
||||||
base_lot_size: 100,
|
base_lot_size: 100,
|
||||||
maint_asset_weight: 0.975,
|
maint_base_asset_weight: 0.975,
|
||||||
init_asset_weight: 0.95,
|
init_base_asset_weight: 0.95,
|
||||||
maint_liab_weight: 1.025,
|
maint_base_liab_weight: 1.025,
|
||||||
init_liab_weight: 1.05,
|
init_base_liab_weight: 1.05,
|
||||||
liquidation_fee: 0.012,
|
liquidation_fee: 0.012,
|
||||||
maker_fee: 0.0002,
|
maker_fee: 0.0002,
|
||||||
taker_fee: 0.000,
|
taker_fee: 0.000,
|
||||||
|
@ -182,10 +182,10 @@ async fn test_perp_settle_fees() -> Result<(), TransportError> {
|
||||||
perp_market_index: 1,
|
perp_market_index: 1,
|
||||||
quote_lot_size: 10,
|
quote_lot_size: 10,
|
||||||
base_lot_size: 100,
|
base_lot_size: 100,
|
||||||
maint_asset_weight: 0.975,
|
maint_base_asset_weight: 0.975,
|
||||||
init_asset_weight: 0.95,
|
init_base_asset_weight: 0.95,
|
||||||
maint_liab_weight: 1.025,
|
maint_base_liab_weight: 1.025,
|
||||||
init_liab_weight: 1.05,
|
init_base_liab_weight: 1.05,
|
||||||
liquidation_fee: 0.012,
|
liquidation_fee: 0.012,
|
||||||
maker_fee: 0.0002,
|
maker_fee: 0.0002,
|
||||||
taker_fee: 0.000,
|
taker_fee: 0.000,
|
||||||
|
|
|
@ -251,10 +251,10 @@ async fn test_perp_reduce_only() -> Result<(), TransportError> {
|
||||||
perp_market_index: 0,
|
perp_market_index: 0,
|
||||||
quote_lot_size: 10,
|
quote_lot_size: 10,
|
||||||
base_lot_size: 100,
|
base_lot_size: 100,
|
||||||
maint_asset_weight: 0.975,
|
maint_base_asset_weight: 0.975,
|
||||||
init_asset_weight: 0.95,
|
init_base_asset_weight: 0.95,
|
||||||
maint_liab_weight: 1.025,
|
maint_base_liab_weight: 1.025,
|
||||||
init_liab_weight: 1.05,
|
init_base_liab_weight: 1.05,
|
||||||
liquidation_fee: 0.012,
|
liquidation_fee: 0.012,
|
||||||
maker_fee: 0.0002,
|
maker_fee: 0.0002,
|
||||||
taker_fee: 0.000,
|
taker_fee: 0.000,
|
||||||
|
|
|
@ -31,17 +31,19 @@ function mockBankAndOracle(
|
||||||
|
|
||||||
function mockPerpMarket(
|
function mockPerpMarket(
|
||||||
perpMarketIndex: number,
|
perpMarketIndex: number,
|
||||||
maintWeight: number,
|
maintBaseWeight: number,
|
||||||
initWeight: number,
|
initBaseWeight: number,
|
||||||
baseLotSize: number,
|
baseLotSize: number,
|
||||||
price: number,
|
price: number,
|
||||||
): PerpMarket {
|
): PerpMarket {
|
||||||
return {
|
return {
|
||||||
perpMarketIndex,
|
perpMarketIndex,
|
||||||
maintAssetWeight: I80F48.fromNumber(1 - maintWeight),
|
maintBaseAssetWeight: I80F48.fromNumber(1 - maintBaseWeight),
|
||||||
initAssetWeight: I80F48.fromNumber(1 - initWeight),
|
initBaseAssetWeight: I80F48.fromNumber(1 - initBaseWeight),
|
||||||
maintLiabWeight: I80F48.fromNumber(1 + maintWeight),
|
maintBaseLiabWeight: I80F48.fromNumber(1 + maintBaseWeight),
|
||||||
initLiabWeight: I80F48.fromNumber(1 + initWeight),
|
initBaseLiabWeight: I80F48.fromNumber(1 + initBaseWeight),
|
||||||
|
maintPnlAssetWeight: I80F48.fromNumber(1 - 0.02),
|
||||||
|
initPnlAssetWeight: I80F48.fromNumber(1 - 0.05),
|
||||||
price: I80F48.fromNumber(price),
|
price: I80F48.fromNumber(price),
|
||||||
stablePriceModel: { stablePrice: price } as StablePriceModel,
|
stablePriceModel: { stablePrice: price } as StablePriceModel,
|
||||||
quoteLotSize: new BN(100),
|
quoteLotSize: new BN(100),
|
||||||
|
@ -231,7 +233,9 @@ describe('Health Cache', () => {
|
||||||
const hc = new HealthCache([ti1, ti2, ti3], [si1, si2], [pi1]);
|
const hc = new HealthCache([ti1, ti2, ti3], [si1, si2], [pi1]);
|
||||||
const health = hc.health(HealthType.init).toNumber();
|
const health = hc.health(HealthType.init).toNumber();
|
||||||
console.log(
|
console.log(
|
||||||
` - case "${fixture.name}" health ${health.toFixed(3).padStart(10)}`,
|
` - case "${fixture.name}" health ${health
|
||||||
|
.toFixed(3)
|
||||||
|
.padStart(10)}, expected ${fixture.expectedHealth}`,
|
||||||
);
|
);
|
||||||
expect(health - fixture.expectedHealth).lessThan(0.0000001);
|
expect(health - fixture.expectedHealth).lessThan(0.0000001);
|
||||||
}
|
}
|
||||||
|
@ -276,18 +280,18 @@ describe('Health Cache', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
testFixture({
|
testFixture({
|
||||||
name: '2',
|
name: '2: weighted positive perp pnl',
|
||||||
token1: 0,
|
token1: 0,
|
||||||
token2: 0,
|
token2: 0,
|
||||||
token3: 0,
|
token3: 0,
|
||||||
oo12: [0, 0],
|
oo12: [0, 0],
|
||||||
oo13: [0, 0],
|
oo13: [0, 0],
|
||||||
perp1: [-10, 100, 0, 0],
|
perp1: [-1, 100, 0, 0],
|
||||||
expectedHealth: 0,
|
expectedHealth: 0.95 * (100.0 - 1.2 * 1.0 * baseLotsToQuote),
|
||||||
});
|
});
|
||||||
|
|
||||||
testFixture({
|
testFixture({
|
||||||
name: '3',
|
name: '3: negative perp pnl is not weighted',
|
||||||
token1: 0,
|
token1: 0,
|
||||||
token2: 0,
|
token2: 0,
|
||||||
token3: 0,
|
token3: 0,
|
||||||
|
@ -298,25 +302,25 @@ describe('Health Cache', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
testFixture({
|
testFixture({
|
||||||
name: '4',
|
name: '4: perp health',
|
||||||
token1: 0,
|
token1: 0,
|
||||||
token2: 0,
|
token2: 0,
|
||||||
token3: 0,
|
token3: 0,
|
||||||
oo12: [0, 0],
|
oo12: [0, 0],
|
||||||
oo13: [0, 0],
|
oo13: [0, 0],
|
||||||
perp1: [10, 100, 0, 0],
|
perp1: [10, 100, 0, 0],
|
||||||
expectedHealth: 0,
|
expectedHealth: 0.95 * (100.0 + 0.8 * 10.0 * baseLotsToQuote),
|
||||||
});
|
});
|
||||||
|
|
||||||
testFixture({
|
testFixture({
|
||||||
name: '5',
|
name: '5: perp health',
|
||||||
token1: 0,
|
token1: 0,
|
||||||
token2: 0,
|
token2: 0,
|
||||||
token3: 0,
|
token3: 0,
|
||||||
oo12: [0, 0],
|
oo12: [0, 0],
|
||||||
oo13: [0, 0],
|
oo13: [0, 0],
|
||||||
perp1: [30, -100, 0, 0],
|
perp1: [30, -100, 0, 0],
|
||||||
expectedHealth: 0,
|
expectedHealth: 0.95 * (-100.0 + 0.8 * 30.0 * baseLotsToQuote),
|
||||||
});
|
});
|
||||||
|
|
||||||
testFixture({
|
testFixture({
|
||||||
|
@ -326,7 +330,7 @@ describe('Health Cache', () => {
|
||||||
token3: -10,
|
token3: -10,
|
||||||
oo12: [1, 1],
|
oo12: [1, 1],
|
||||||
oo13: [1, 1],
|
oo13: [1, 1],
|
||||||
perp1: [30, -100, 0, 0],
|
perp1: [0, 0, 0, 0],
|
||||||
expectedHealth:
|
expectedHealth:
|
||||||
// tokens
|
// tokens
|
||||||
-100.0 * 1.2 -
|
-100.0 * 1.2 -
|
||||||
|
|
|
@ -206,13 +206,11 @@ export class HealthCache {
|
||||||
health.iadd(contrib);
|
health.iadd(contrib);
|
||||||
}
|
}
|
||||||
for (const perpInfo of this.perpInfos) {
|
for (const perpInfo of this.perpInfos) {
|
||||||
if (perpInfo.trustedMarket) {
|
const positiveContrib = perpInfo
|
||||||
const positiveContrib = perpInfo
|
.healthContribution(HealthType.maint)
|
||||||
.uncappedHealthContribution(HealthType.maint)
|
.max(ZERO_I80F48());
|
||||||
.max(ZERO_I80F48());
|
// console.log(` - pi ${positiveContrib}`);
|
||||||
// console.log(` - pi ${positiveContrib}`);
|
health.iadd(positiveContrib);
|
||||||
health.iadd(positiveContrib);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return health;
|
return health;
|
||||||
}
|
}
|
||||||
|
@ -1052,8 +1050,12 @@ export class HealthCache {
|
||||||
// If the price is sufficiently good then health will just increase from trading
|
// If the price is sufficiently good then health will just increase from trading
|
||||||
const finalHealthSlope =
|
const finalHealthSlope =
|
||||||
direction == 1
|
direction == 1
|
||||||
? perpInfo.initAssetWeight.mul(prices.asset(HealthType.init)).sub(price)
|
? perpInfo.initBaseAssetWeight
|
||||||
: price.sub(perpInfo.initLiabWeight.mul(prices.liab(HealthType.init)));
|
.mul(prices.asset(HealthType.init))
|
||||||
|
.sub(price)
|
||||||
|
: price.sub(
|
||||||
|
perpInfo.initBaseLiabWeight.mul(prices.liab(HealthType.init)),
|
||||||
|
);
|
||||||
if (finalHealthSlope.gte(ZERO_I80F48())) {
|
if (finalHealthSlope.gte(ZERO_I80F48())) {
|
||||||
return MAX_I80F48();
|
return MAX_I80F48();
|
||||||
}
|
}
|
||||||
|
@ -1123,7 +1125,7 @@ export class HealthCache {
|
||||||
const perpInfo = startCache.perpInfos[perpInfoIndex];
|
const perpInfo = startCache.perpInfos[perpInfoIndex];
|
||||||
const startHealthUncapped = startHealth
|
const startHealthUncapped = startHealth
|
||||||
.sub(perpInfo.healthContribution(HealthType.init))
|
.sub(perpInfo.healthContribution(HealthType.init))
|
||||||
.add(perpInfo.uncappedHealthContribution(HealthType.init));
|
.add(perpInfo.unweightedHealthContribution(HealthType.init));
|
||||||
|
|
||||||
const zeroHealthAmount = case1Start
|
const zeroHealthAmount = case1Start
|
||||||
.sub(startHealthUncapped.div(finalHealthSlope).div(baseLotSize))
|
.sub(startHealthUncapped.div(finalHealthSlope).div(baseLotSize))
|
||||||
|
@ -1420,10 +1422,12 @@ export class Serum3Info {
|
||||||
export class PerpInfo {
|
export class PerpInfo {
|
||||||
constructor(
|
constructor(
|
||||||
public perpMarketIndex: number,
|
public perpMarketIndex: number,
|
||||||
public maintAssetWeight: I80F48,
|
public maintBaseAssetWeight: I80F48,
|
||||||
public initAssetWeight: I80F48,
|
public initBaseAssetWeight: I80F48,
|
||||||
public maintLiabWeight: I80F48,
|
public maintBaseLiabWeight: I80F48,
|
||||||
public initLiabWeight: I80F48,
|
public initBaseLiabWeight: I80F48,
|
||||||
|
public maintPnlAssetWeight: I80F48,
|
||||||
|
public initPnlAssetWeight: I80F48,
|
||||||
public baseLotSize: BN,
|
public baseLotSize: BN,
|
||||||
public baseLots: BN,
|
public baseLots: BN,
|
||||||
public bidsBaseLots: BN,
|
public bidsBaseLots: BN,
|
||||||
|
@ -1431,16 +1435,17 @@ export class PerpInfo {
|
||||||
public quote: I80F48,
|
public quote: I80F48,
|
||||||
public prices: Prices,
|
public prices: Prices,
|
||||||
public hasOpenOrders: boolean,
|
public hasOpenOrders: boolean,
|
||||||
public trustedMarket: boolean,
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
static fromDto(dto: PerpInfoDto): PerpInfo {
|
static fromDto(dto: PerpInfoDto): PerpInfo {
|
||||||
return new PerpInfo(
|
return new PerpInfo(
|
||||||
dto.perpMarketIndex,
|
dto.perpMarketIndex,
|
||||||
I80F48.from(dto.maintAssetWeight),
|
I80F48.from(dto.maintBaseAssetWeight),
|
||||||
I80F48.from(dto.initAssetWeight),
|
I80F48.from(dto.initBaseAssetWeight),
|
||||||
I80F48.from(dto.maintLiabWeight),
|
I80F48.from(dto.maintBaseLiabWeight),
|
||||||
I80F48.from(dto.initLiabWeight),
|
I80F48.from(dto.initBaseLiabWeight),
|
||||||
|
I80F48.from(dto.maintPnlAssetWeight),
|
||||||
|
I80F48.from(dto.initPnlAssetWeight),
|
||||||
dto.baseLotSize,
|
dto.baseLotSize,
|
||||||
dto.baseLots,
|
dto.baseLots,
|
||||||
dto.bidsBaseLots,
|
dto.bidsBaseLots,
|
||||||
|
@ -1451,7 +1456,6 @@ export class PerpInfo {
|
||||||
I80F48.from(dto.prices.stable),
|
I80F48.from(dto.prices.stable),
|
||||||
),
|
),
|
||||||
dto.hasOpenOrders,
|
dto.hasOpenOrders,
|
||||||
dto.trustedMarket,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1473,10 +1477,12 @@ export class PerpInfo {
|
||||||
|
|
||||||
return new PerpInfo(
|
return new PerpInfo(
|
||||||
perpMarket.perpMarketIndex,
|
perpMarket.perpMarketIndex,
|
||||||
perpMarket.maintAssetWeight,
|
perpMarket.maintBaseAssetWeight,
|
||||||
perpMarket.initAssetWeight,
|
perpMarket.initBaseAssetWeight,
|
||||||
perpMarket.maintLiabWeight,
|
perpMarket.maintBaseLiabWeight,
|
||||||
perpMarket.initLiabWeight,
|
perpMarket.initBaseLiabWeight,
|
||||||
|
perpMarket.maintPnlAssetWeight,
|
||||||
|
perpMarket.initPnlAssetWeight,
|
||||||
perpMarket.baseLotSize,
|
perpMarket.baseLotSize,
|
||||||
baseLots,
|
baseLots,
|
||||||
perpPosition.bidsBaseLots,
|
perpPosition.bidsBaseLots,
|
||||||
|
@ -1487,17 +1493,22 @@ export class PerpInfo {
|
||||||
I80F48.fromNumber(perpMarket.stablePriceModel.stablePrice),
|
I80F48.fromNumber(perpMarket.stablePriceModel.stablePrice),
|
||||||
),
|
),
|
||||||
perpPosition.hasOpenOrders(),
|
perpPosition.hasOpenOrders(),
|
||||||
perpMarket.trustedMarket,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
healthContribution(healthType: HealthType | undefined): I80F48 {
|
healthContribution(healthType: HealthType | undefined): I80F48 {
|
||||||
return this.trustedMarket
|
const contrib = this.unweightedHealthContribution(healthType);
|
||||||
? this.uncappedHealthContribution(healthType)
|
if (contrib.gt(ZERO_I80F48())) {
|
||||||
: this.uncappedHealthContribution(healthType).min(ZERO_I80F48());
|
const assetWeight =
|
||||||
|
healthType == HealthType.init
|
||||||
|
? this.initPnlAssetWeight
|
||||||
|
: this.maintPnlAssetWeight;
|
||||||
|
return assetWeight.mul(contrib);
|
||||||
|
}
|
||||||
|
return contrib;
|
||||||
}
|
}
|
||||||
|
|
||||||
uncappedHealthContribution(healthType: HealthType | undefined): I80F48 {
|
unweightedHealthContribution(healthType: HealthType | undefined): I80F48 {
|
||||||
function orderExecutionCase(
|
function orderExecutionCase(
|
||||||
pi: PerpInfo,
|
pi: PerpInfo,
|
||||||
ordersBaseLots: BN,
|
ordersBaseLots: BN,
|
||||||
|
@ -1510,18 +1521,18 @@ export class PerpInfo {
|
||||||
let weight, basePrice;
|
let weight, basePrice;
|
||||||
if (healthType == HealthType.init) {
|
if (healthType == HealthType.init) {
|
||||||
if (netBaseNative.isNeg()) {
|
if (netBaseNative.isNeg()) {
|
||||||
weight = pi.initLiabWeight;
|
weight = pi.initBaseLiabWeight;
|
||||||
basePrice = pi.prices.liab(healthType);
|
basePrice = pi.prices.liab(healthType);
|
||||||
} else {
|
} else {
|
||||||
weight = pi.initAssetWeight;
|
weight = pi.initBaseAssetWeight;
|
||||||
basePrice = pi.prices.asset(healthType);
|
basePrice = pi.prices.asset(healthType);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (netBaseNative.isNeg()) {
|
if (netBaseNative.isNeg()) {
|
||||||
weight = pi.maintLiabWeight;
|
weight = pi.maintBaseLiabWeight;
|
||||||
basePrice = pi.prices.liab(healthType);
|
basePrice = pi.prices.liab(healthType);
|
||||||
} else {
|
} else {
|
||||||
weight = pi.maintAssetWeight;
|
weight = pi.maintBaseAssetWeight;
|
||||||
basePrice = pi.prices.asset(healthType);
|
basePrice = pi.prices.asset(healthType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1557,10 +1568,12 @@ export class PerpInfo {
|
||||||
static emptyFromPerpMarket(perpMarket: PerpMarket): PerpInfo {
|
static emptyFromPerpMarket(perpMarket: PerpMarket): PerpInfo {
|
||||||
return new PerpInfo(
|
return new PerpInfo(
|
||||||
perpMarket.perpMarketIndex,
|
perpMarket.perpMarketIndex,
|
||||||
perpMarket.maintAssetWeight,
|
perpMarket.maintBaseAssetWeight,
|
||||||
perpMarket.initAssetWeight,
|
perpMarket.initBaseAssetWeight,
|
||||||
perpMarket.maintLiabWeight,
|
perpMarket.maintBaseLiabWeight,
|
||||||
perpMarket.initLiabWeight,
|
perpMarket.initBaseLiabWeight,
|
||||||
|
perpMarket.maintPnlAssetWeight,
|
||||||
|
perpMarket.initPnlAssetWeight,
|
||||||
perpMarket.baseLotSize,
|
perpMarket.baseLotSize,
|
||||||
new BN(0),
|
new BN(0),
|
||||||
new BN(0),
|
new BN(0),
|
||||||
|
@ -1571,7 +1584,6 @@ export class PerpInfo {
|
||||||
I80F48.fromNumber(perpMarket.stablePriceModel.stablePrice),
|
I80F48.fromNumber(perpMarket.stablePriceModel.stablePrice),
|
||||||
),
|
),
|
||||||
false,
|
false,
|
||||||
perpMarket.trustedMarket,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1580,7 +1592,7 @@ export class PerpInfo {
|
||||||
this.baseLots
|
this.baseLots
|
||||||
}, quote: ${this.quote}, oraclePrice: ${
|
}, quote: ${this.quote}, oraclePrice: ${
|
||||||
this.prices.oracle
|
this.prices.oracle
|
||||||
}, uncapped health contribution ${this.uncappedHealthContribution(
|
}, uncapped health contribution ${this.unweightedHealthContribution(
|
||||||
HealthType.init,
|
HealthType.init,
|
||||||
)}`;
|
)}`;
|
||||||
}
|
}
|
||||||
|
@ -1641,10 +1653,12 @@ export class Serum3InfoDto {
|
||||||
|
|
||||||
export class PerpInfoDto {
|
export class PerpInfoDto {
|
||||||
perpMarketIndex: number;
|
perpMarketIndex: number;
|
||||||
maintAssetWeight: I80F48Dto;
|
maintBaseAssetWeight: I80F48Dto;
|
||||||
initAssetWeight: I80F48Dto;
|
initBaseAssetWeight: I80F48Dto;
|
||||||
maintLiabWeight: I80F48Dto;
|
maintBaseLiabWeight: I80F48Dto;
|
||||||
initLiabWeight: I80F48Dto;
|
initBaseLiabWeight: I80F48Dto;
|
||||||
|
maintPnlAssetWeight: I80F48Dto;
|
||||||
|
initPnlAssetWeight: I80F48Dto;
|
||||||
public baseLotSize: BN;
|
public baseLotSize: BN;
|
||||||
public baseLots: BN;
|
public baseLots: BN;
|
||||||
public bidsBaseLots: BN;
|
public bidsBaseLots: BN;
|
||||||
|
@ -1652,5 +1666,4 @@ export class PerpInfoDto {
|
||||||
quote: I80F48Dto;
|
quote: I80F48Dto;
|
||||||
prices: { oracle: I80F48Dto; stable: I80F48Dto };
|
prices: { oracle: I80F48Dto; stable: I80F48Dto };
|
||||||
hasOpenOrders: boolean;
|
hasOpenOrders: boolean;
|
||||||
trustedMarket: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,10 +30,10 @@ export type ParsedFillEvent = Modify<
|
||||||
export class PerpMarket {
|
export class PerpMarket {
|
||||||
public name: string;
|
public name: string;
|
||||||
public oracleConfig: OracleConfig;
|
public oracleConfig: OracleConfig;
|
||||||
public maintAssetWeight: I80F48;
|
public maintBaseAssetWeight: I80F48;
|
||||||
public initAssetWeight: I80F48;
|
public initBaseAssetWeight: I80F48;
|
||||||
public maintLiabWeight: I80F48;
|
public maintBaseLiabWeight: I80F48;
|
||||||
public initLiabWeight: I80F48;
|
public initBaseLiabWeight: I80F48;
|
||||||
public liquidationFee: I80F48;
|
public liquidationFee: I80F48;
|
||||||
public makerFee: I80F48;
|
public makerFee: I80F48;
|
||||||
public takerFee: I80F48;
|
public takerFee: I80F48;
|
||||||
|
@ -43,6 +43,9 @@ export class PerpMarket {
|
||||||
public shortFunding: I80F48;
|
public shortFunding: I80F48;
|
||||||
public feesAccrued: I80F48;
|
public feesAccrued: I80F48;
|
||||||
public feesSettled: I80F48;
|
public feesSettled: I80F48;
|
||||||
|
public maintPnlAssetWeight: I80F48;
|
||||||
|
public initPnlAssetWeight: I80F48;
|
||||||
|
|
||||||
public _price: I80F48;
|
public _price: I80F48;
|
||||||
public _uiPrice: number;
|
public _uiPrice: number;
|
||||||
|
|
||||||
|
@ -59,7 +62,6 @@ export class PerpMarket {
|
||||||
group: PublicKey;
|
group: PublicKey;
|
||||||
settleTokenIndex: number;
|
settleTokenIndex: number;
|
||||||
perpMarketIndex: number;
|
perpMarketIndex: number;
|
||||||
trustedMarket: number;
|
|
||||||
groupInsuranceFund: number;
|
groupInsuranceFund: number;
|
||||||
baseDecimals: number;
|
baseDecimals: number;
|
||||||
name: number[];
|
name: number[];
|
||||||
|
@ -71,10 +73,10 @@ export class PerpMarket {
|
||||||
stablePriceModel: StablePriceModel;
|
stablePriceModel: StablePriceModel;
|
||||||
quoteLotSize: BN;
|
quoteLotSize: BN;
|
||||||
baseLotSize: BN;
|
baseLotSize: BN;
|
||||||
maintAssetWeight: I80F48Dto;
|
maintBaseAssetWeight: I80F48Dto;
|
||||||
initAssetWeight: I80F48Dto;
|
initBaseAssetWeight: I80F48Dto;
|
||||||
maintLiabWeight: I80F48Dto;
|
maintBaseLiabWeight: I80F48Dto;
|
||||||
initLiabWeight: I80F48Dto;
|
initBaseLiabWeight: I80F48Dto;
|
||||||
openInterest: BN;
|
openInterest: BN;
|
||||||
seqNum: BN;
|
seqNum: BN;
|
||||||
registrationTime: BN;
|
registrationTime: BN;
|
||||||
|
@ -96,6 +98,8 @@ export class PerpMarket {
|
||||||
settlePnlLimitFactor: number;
|
settlePnlLimitFactor: number;
|
||||||
settlePnlLimitWindowSizeTs: BN;
|
settlePnlLimitWindowSizeTs: BN;
|
||||||
reduceOnly: number;
|
reduceOnly: number;
|
||||||
|
maintPnlAssetWeight: I80F48Dto;
|
||||||
|
initPnlAssetWeight: I80F48Dto;
|
||||||
},
|
},
|
||||||
): PerpMarket {
|
): PerpMarket {
|
||||||
return new PerpMarket(
|
return new PerpMarket(
|
||||||
|
@ -103,7 +107,6 @@ export class PerpMarket {
|
||||||
obj.group,
|
obj.group,
|
||||||
obj.settleTokenIndex as TokenIndex,
|
obj.settleTokenIndex as TokenIndex,
|
||||||
obj.perpMarketIndex as PerpMarketIndex,
|
obj.perpMarketIndex as PerpMarketIndex,
|
||||||
obj.trustedMarket == 1,
|
|
||||||
obj.groupInsuranceFund == 1,
|
obj.groupInsuranceFund == 1,
|
||||||
obj.baseDecimals,
|
obj.baseDecimals,
|
||||||
obj.name,
|
obj.name,
|
||||||
|
@ -115,10 +118,10 @@ export class PerpMarket {
|
||||||
obj.stablePriceModel,
|
obj.stablePriceModel,
|
||||||
obj.quoteLotSize,
|
obj.quoteLotSize,
|
||||||
obj.baseLotSize,
|
obj.baseLotSize,
|
||||||
obj.maintAssetWeight,
|
obj.maintBaseAssetWeight,
|
||||||
obj.initAssetWeight,
|
obj.initBaseAssetWeight,
|
||||||
obj.maintLiabWeight,
|
obj.maintBaseLiabWeight,
|
||||||
obj.initLiabWeight,
|
obj.initBaseLiabWeight,
|
||||||
obj.openInterest,
|
obj.openInterest,
|
||||||
obj.seqNum,
|
obj.seqNum,
|
||||||
obj.registrationTime,
|
obj.registrationTime,
|
||||||
|
@ -140,6 +143,8 @@ export class PerpMarket {
|
||||||
obj.settlePnlLimitFactor,
|
obj.settlePnlLimitFactor,
|
||||||
obj.settlePnlLimitWindowSizeTs,
|
obj.settlePnlLimitWindowSizeTs,
|
||||||
obj.reduceOnly == 1,
|
obj.reduceOnly == 1,
|
||||||
|
obj.maintPnlAssetWeight,
|
||||||
|
obj.initPnlAssetWeight,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +153,6 @@ export class PerpMarket {
|
||||||
public group: PublicKey,
|
public group: PublicKey,
|
||||||
public settleTokenIndex: TokenIndex,
|
public settleTokenIndex: TokenIndex,
|
||||||
public perpMarketIndex: PerpMarketIndex, // TODO rename to marketIndex?
|
public perpMarketIndex: PerpMarketIndex, // TODO rename to marketIndex?
|
||||||
public trustedMarket: boolean,
|
|
||||||
public groupInsuranceFund: boolean,
|
public groupInsuranceFund: boolean,
|
||||||
public baseDecimals: number,
|
public baseDecimals: number,
|
||||||
name: number[],
|
name: number[],
|
||||||
|
@ -160,10 +164,10 @@ export class PerpMarket {
|
||||||
public stablePriceModel: StablePriceModel,
|
public stablePriceModel: StablePriceModel,
|
||||||
public quoteLotSize: BN,
|
public quoteLotSize: BN,
|
||||||
public baseLotSize: BN,
|
public baseLotSize: BN,
|
||||||
maintAssetWeight: I80F48Dto,
|
maintBaseAssetWeight: I80F48Dto,
|
||||||
initAssetWeight: I80F48Dto,
|
initBaseAssetWeight: I80F48Dto,
|
||||||
maintLiabWeight: I80F48Dto,
|
maintBaseLiabWeight: I80F48Dto,
|
||||||
initLiabWeight: I80F48Dto,
|
initBaseLiabWeight: I80F48Dto,
|
||||||
public openInterest: BN,
|
public openInterest: BN,
|
||||||
public seqNum: BN,
|
public seqNum: BN,
|
||||||
public registrationTime: BN,
|
public registrationTime: BN,
|
||||||
|
@ -185,16 +189,18 @@ export class PerpMarket {
|
||||||
public settlePnlLimitFactor: number,
|
public settlePnlLimitFactor: number,
|
||||||
public settlePnlLimitWindowSizeTs: BN,
|
public settlePnlLimitWindowSizeTs: BN,
|
||||||
public reduceOnly: boolean,
|
public reduceOnly: boolean,
|
||||||
|
maintPnlAssetWeight: I80F48Dto,
|
||||||
|
initPnlAssetWeight: I80F48Dto,
|
||||||
) {
|
) {
|
||||||
this.name = utf8.decode(new Uint8Array(name)).split('\x00')[0];
|
this.name = utf8.decode(new Uint8Array(name)).split('\x00')[0];
|
||||||
this.oracleConfig = {
|
this.oracleConfig = {
|
||||||
confFilter: I80F48.from(oracleConfig.confFilter),
|
confFilter: I80F48.from(oracleConfig.confFilter),
|
||||||
maxStalenessSlots: oracleConfig.maxStalenessSlots,
|
maxStalenessSlots: oracleConfig.maxStalenessSlots,
|
||||||
} as OracleConfig;
|
} as OracleConfig;
|
||||||
this.maintAssetWeight = I80F48.from(maintAssetWeight);
|
this.maintBaseAssetWeight = I80F48.from(maintBaseAssetWeight);
|
||||||
this.initAssetWeight = I80F48.from(initAssetWeight);
|
this.initBaseAssetWeight = I80F48.from(initBaseAssetWeight);
|
||||||
this.maintLiabWeight = I80F48.from(maintLiabWeight);
|
this.maintBaseLiabWeight = I80F48.from(maintBaseLiabWeight);
|
||||||
this.initLiabWeight = I80F48.from(initLiabWeight);
|
this.initBaseLiabWeight = I80F48.from(initBaseLiabWeight);
|
||||||
this.liquidationFee = I80F48.from(liquidationFee);
|
this.liquidationFee = I80F48.from(liquidationFee);
|
||||||
this.makerFee = I80F48.from(makerFee);
|
this.makerFee = I80F48.from(makerFee);
|
||||||
this.takerFee = I80F48.from(takerFee);
|
this.takerFee = I80F48.from(takerFee);
|
||||||
|
@ -204,6 +210,8 @@ export class PerpMarket {
|
||||||
this.shortFunding = I80F48.from(shortFunding);
|
this.shortFunding = I80F48.from(shortFunding);
|
||||||
this.feesAccrued = I80F48.from(feesAccrued);
|
this.feesAccrued = I80F48.from(feesAccrued);
|
||||||
this.feesSettled = I80F48.from(feesSettled);
|
this.feesSettled = I80F48.from(feesSettled);
|
||||||
|
this.maintPnlAssetWeight = I80F48.from(maintPnlAssetWeight);
|
||||||
|
this.initPnlAssetWeight = I80F48.from(initPnlAssetWeight);
|
||||||
|
|
||||||
this.priceLotsToUiConverter = new Big(10)
|
this.priceLotsToUiConverter = new Big(10)
|
||||||
.pow(baseDecimals - QUOTE_DECIMALS)
|
.pow(baseDecimals - QUOTE_DECIMALS)
|
||||||
|
@ -249,9 +257,9 @@ export class PerpMarket {
|
||||||
insidePriceLimit(side: PerpOrderSide, orderPrice: number): boolean {
|
insidePriceLimit(side: PerpOrderSide, orderPrice: number): boolean {
|
||||||
return (
|
return (
|
||||||
(side === PerpOrderSide.bid &&
|
(side === PerpOrderSide.bid &&
|
||||||
orderPrice <= this.maintLiabWeight.toNumber() * this.uiPrice) ||
|
orderPrice <= this.maintBaseLiabWeight.toNumber() * this.uiPrice) ||
|
||||||
(side === PerpOrderSide.ask &&
|
(side === PerpOrderSide.ask &&
|
||||||
orderPrice >= this.maintAssetWeight.toNumber() * this.uiPrice)
|
orderPrice >= this.maintBaseAssetWeight.toNumber() * this.uiPrice)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,13 +494,13 @@ export class PerpMarket {
|
||||||
'\n perpMarketIndex -' +
|
'\n perpMarketIndex -' +
|
||||||
this.perpMarketIndex +
|
this.perpMarketIndex +
|
||||||
'\n maintAssetWeight -' +
|
'\n maintAssetWeight -' +
|
||||||
this.maintAssetWeight.toString() +
|
this.maintBaseAssetWeight.toString() +
|
||||||
'\n initAssetWeight -' +
|
'\n initAssetWeight -' +
|
||||||
this.initAssetWeight.toString() +
|
this.initBaseAssetWeight.toString() +
|
||||||
'\n maintLiabWeight -' +
|
'\n maintLiabWeight -' +
|
||||||
this.maintLiabWeight.toString() +
|
this.maintBaseLiabWeight.toString() +
|
||||||
'\n initLiabWeight -' +
|
'\n initLiabWeight -' +
|
||||||
this.initLiabWeight.toString() +
|
this.initBaseLiabWeight.toString() +
|
||||||
'\n liquidationFee -' +
|
'\n liquidationFee -' +
|
||||||
this.liquidationFee.toString() +
|
this.liquidationFee.toString() +
|
||||||
'\n makerFee -' +
|
'\n makerFee -' +
|
||||||
|
|
|
@ -1521,10 +1521,12 @@ export class MangoClient {
|
||||||
baseDecimals: number,
|
baseDecimals: number,
|
||||||
quoteLotSize: number,
|
quoteLotSize: number,
|
||||||
baseLotSize: number,
|
baseLotSize: number,
|
||||||
maintAssetWeight: number,
|
maintBaseAssetWeight: number,
|
||||||
initAssetWeight: number,
|
initBaseAssetWeight: number,
|
||||||
maintLiabWeight: number,
|
maintBaseLiabWeight: number,
|
||||||
initLiabWeight: number,
|
initBaseLiabWeight: number,
|
||||||
|
maintPnlAssetWeight: number,
|
||||||
|
initPnlAssetWeight: number,
|
||||||
liquidationFee: number,
|
liquidationFee: number,
|
||||||
makerFee: number,
|
makerFee: number,
|
||||||
takerFee: number,
|
takerFee: number,
|
||||||
|
@ -1533,7 +1535,6 @@ export class MangoClient {
|
||||||
maxFunding: number,
|
maxFunding: number,
|
||||||
impactQuantity: number,
|
impactQuantity: number,
|
||||||
groupInsuranceFund: boolean,
|
groupInsuranceFund: boolean,
|
||||||
trustedMarket: boolean,
|
|
||||||
settleFeeFlat: number,
|
settleFeeFlat: number,
|
||||||
settleFeeAmountThreshold: number,
|
settleFeeAmountThreshold: number,
|
||||||
settleFeeFractionLowHealth: number,
|
settleFeeFractionLowHealth: number,
|
||||||
|
@ -1560,10 +1561,12 @@ export class MangoClient {
|
||||||
baseDecimals,
|
baseDecimals,
|
||||||
new BN(quoteLotSize),
|
new BN(quoteLotSize),
|
||||||
new BN(baseLotSize),
|
new BN(baseLotSize),
|
||||||
maintAssetWeight,
|
maintBaseAssetWeight,
|
||||||
initAssetWeight,
|
initBaseAssetWeight,
|
||||||
maintLiabWeight,
|
maintBaseLiabWeight,
|
||||||
initLiabWeight,
|
initBaseLiabWeight,
|
||||||
|
maintPnlAssetWeight,
|
||||||
|
initPnlAssetWeight,
|
||||||
liquidationFee,
|
liquidationFee,
|
||||||
makerFee,
|
makerFee,
|
||||||
takerFee,
|
takerFee,
|
||||||
|
@ -1571,7 +1574,6 @@ export class MangoClient {
|
||||||
maxFunding,
|
maxFunding,
|
||||||
new BN(impactQuantity),
|
new BN(impactQuantity),
|
||||||
groupInsuranceFund,
|
groupInsuranceFund,
|
||||||
trustedMarket,
|
|
||||||
feePenalty,
|
feePenalty,
|
||||||
settleFeeFlat,
|
settleFeeFlat,
|
||||||
settleFeeAmountThreshold,
|
settleFeeAmountThreshold,
|
||||||
|
@ -1642,10 +1644,12 @@ export class MangoClient {
|
||||||
params.oracle,
|
params.oracle,
|
||||||
params.oracleConfig,
|
params.oracleConfig,
|
||||||
params.baseDecimals,
|
params.baseDecimals,
|
||||||
params.maintAssetWeight,
|
params.maintBaseAssetWeight,
|
||||||
params.initAssetWeight,
|
params.initBaseAssetWeight,
|
||||||
params.maintLiabWeight,
|
params.maintBaseLiabWeight,
|
||||||
params.initLiabWeight,
|
params.initBaseLiabWeight,
|
||||||
|
params.maintPnlAssetWeight,
|
||||||
|
params.initPnlAssetWeight,
|
||||||
params.liquidationFee,
|
params.liquidationFee,
|
||||||
params.makerFee,
|
params.makerFee,
|
||||||
params.takerFee,
|
params.takerFee,
|
||||||
|
@ -1653,7 +1657,6 @@ export class MangoClient {
|
||||||
params.maxFunding,
|
params.maxFunding,
|
||||||
params.impactQuantity !== null ? new BN(params.impactQuantity) : null,
|
params.impactQuantity !== null ? new BN(params.impactQuantity) : null,
|
||||||
params.groupInsuranceFund,
|
params.groupInsuranceFund,
|
||||||
params.trustedMarket,
|
|
||||||
params.feePenalty,
|
params.feePenalty,
|
||||||
params.settleFeeFlat,
|
params.settleFeeFlat,
|
||||||
params.settleFeeAmountThreshold,
|
params.settleFeeAmountThreshold,
|
||||||
|
|
|
@ -55,10 +55,12 @@ export interface PerpEditParams {
|
||||||
oracle: PublicKey | null;
|
oracle: PublicKey | null;
|
||||||
oracleConfig: OracleConfigParams | null;
|
oracleConfig: OracleConfigParams | null;
|
||||||
baseDecimals: number | null;
|
baseDecimals: number | null;
|
||||||
maintAssetWeight: number | null;
|
maintBaseAssetWeight: number | null;
|
||||||
initAssetWeight: number | null;
|
initBaseAssetWeight: number | null;
|
||||||
maintLiabWeight: number | null;
|
maintBaseLiabWeight: number | null;
|
||||||
initLiabWeight: number | null;
|
initBaseLiabWeight: number | null;
|
||||||
|
maintPnlAssetWeight: number | null;
|
||||||
|
initPnlAssetWeight: number | null;
|
||||||
liquidationFee: number | null;
|
liquidationFee: number | null;
|
||||||
makerFee: number | null;
|
makerFee: number | null;
|
||||||
takerFee: number | null;
|
takerFee: number | null;
|
||||||
|
@ -67,7 +69,6 @@ export interface PerpEditParams {
|
||||||
maxFunding: number | null;
|
maxFunding: number | null;
|
||||||
impactQuantity: number | null;
|
impactQuantity: number | null;
|
||||||
groupInsuranceFund: boolean | null;
|
groupInsuranceFund: boolean | null;
|
||||||
trustedMarket: boolean | null;
|
|
||||||
settleFeeFlat: number | null;
|
settleFeeFlat: number | null;
|
||||||
settleFeeAmountThreshold: number | null;
|
settleFeeAmountThreshold: number | null;
|
||||||
settleFeeFractionLowHealth: number | null;
|
settleFeeFractionLowHealth: number | null;
|
||||||
|
@ -83,10 +84,12 @@ export const NullPerpEditParams: PerpEditParams = {
|
||||||
oracle: null,
|
oracle: null,
|
||||||
oracleConfig: null,
|
oracleConfig: null,
|
||||||
baseDecimals: null,
|
baseDecimals: null,
|
||||||
maintAssetWeight: null,
|
maintBaseAssetWeight: null,
|
||||||
initAssetWeight: null,
|
initBaseAssetWeight: null,
|
||||||
maintLiabWeight: null,
|
maintBaseLiabWeight: null,
|
||||||
initLiabWeight: null,
|
initBaseLiabWeight: null,
|
||||||
|
maintPnlAssetWeight: null,
|
||||||
|
initPnlAssetWeight: null,
|
||||||
liquidationFee: null,
|
liquidationFee: null,
|
||||||
makerFee: null,
|
makerFee: null,
|
||||||
takerFee: null,
|
takerFee: null,
|
||||||
|
@ -95,7 +98,6 @@ export const NullPerpEditParams: PerpEditParams = {
|
||||||
maxFunding: null,
|
maxFunding: null,
|
||||||
impactQuantity: null,
|
impactQuantity: null,
|
||||||
groupInsuranceFund: null,
|
groupInsuranceFund: null,
|
||||||
trustedMarket: null,
|
|
||||||
settleFeeFlat: null,
|
settleFeeFlat: null,
|
||||||
settleFeeAmountThreshold: null,
|
settleFeeAmountThreshold: null,
|
||||||
settleFeeFractionLowHealth: null,
|
settleFeeFractionLowHealth: null,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export type MangoV4 = {
|
export type MangoV4 = {
|
||||||
"version": "0.2.0",
|
"version": "0.3.0",
|
||||||
"name": "mango_v4",
|
"name": "mango_v4",
|
||||||
"instructions": [
|
"instructions": [
|
||||||
{
|
{
|
||||||
|
@ -2508,19 +2508,27 @@ export type MangoV4 = {
|
||||||
"type": "i64"
|
"type": "i64"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "maintAssetWeight",
|
"name": "maintBaseAssetWeight",
|
||||||
"type": "f32"
|
"type": "f32"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "initAssetWeight",
|
"name": "initBaseAssetWeight",
|
||||||
"type": "f32"
|
"type": "f32"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "maintLiabWeight",
|
"name": "maintBaseLiabWeight",
|
||||||
"type": "f32"
|
"type": "f32"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "initLiabWeight",
|
"name": "initBaseLiabWeight",
|
||||||
|
"type": "f32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "maintPnlAssetWeight",
|
||||||
|
"type": "f32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "initPnlAssetWeight",
|
||||||
"type": "f32"
|
"type": "f32"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2551,10 +2559,6 @@ export type MangoV4 = {
|
||||||
"name": "groupInsuranceFund",
|
"name": "groupInsuranceFund",
|
||||||
"type": "bool"
|
"type": "bool"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "trustedMarket",
|
|
||||||
"type": "bool"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "feePenalty",
|
"name": "feePenalty",
|
||||||
"type": "f32"
|
"type": "f32"
|
||||||
|
@ -2631,25 +2635,37 @@ export type MangoV4 = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "maintAssetWeightOpt",
|
"name": "maintBaseAssetWeightOpt",
|
||||||
"type": {
|
"type": {
|
||||||
"option": "f32"
|
"option": "f32"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "initAssetWeightOpt",
|
"name": "initBaseAssetWeightOpt",
|
||||||
"type": {
|
"type": {
|
||||||
"option": "f32"
|
"option": "f32"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "maintLiabWeightOpt",
|
"name": "maintBaseLiabWeightOpt",
|
||||||
"type": {
|
"type": {
|
||||||
"option": "f32"
|
"option": "f32"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "initLiabWeightOpt",
|
"name": "initBaseLiabWeightOpt",
|
||||||
|
"type": {
|
||||||
|
"option": "f32"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "maintPnlAssetWeightOpt",
|
||||||
|
"type": {
|
||||||
|
"option": "f32"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "initPnlAssetWeightOpt",
|
||||||
"type": {
|
"type": {
|
||||||
"option": "f32"
|
"option": "f32"
|
||||||
}
|
}
|
||||||
|
@ -2696,12 +2712,6 @@ export type MangoV4 = {
|
||||||
"option": "bool"
|
"option": "bool"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "trustedMarketOpt",
|
|
||||||
"type": {
|
|
||||||
"option": "bool"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "feePenaltyOpt",
|
"name": "feePenaltyOpt",
|
||||||
"type": {
|
"type": {
|
||||||
|
@ -4308,10 +4318,7 @@ export type MangoV4 = {
|
||||||
"type": "u16"
|
"type": "u16"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "trustedMarket",
|
"name": "blocked1",
|
||||||
"docs": [
|
|
||||||
"May this market contribute positive values to health?"
|
|
||||||
],
|
|
||||||
"type": "u8"
|
"type": "u8"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -4386,25 +4393,25 @@ export type MangoV4 = {
|
||||||
"type": "i64"
|
"type": "i64"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "maintAssetWeight",
|
"name": "maintBaseAssetWeight",
|
||||||
"type": {
|
"type": {
|
||||||
"defined": "I80F48"
|
"defined": "I80F48"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "initAssetWeight",
|
"name": "initBaseAssetWeight",
|
||||||
"type": {
|
"type": {
|
||||||
"defined": "I80F48"
|
"defined": "I80F48"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "maintLiabWeight",
|
"name": "maintBaseLiabWeight",
|
||||||
"type": {
|
"type": {
|
||||||
"defined": "I80F48"
|
"defined": "I80F48"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "initLiabWeight",
|
"name": "initBaseLiabWeight",
|
||||||
"type": {
|
"type": {
|
||||||
"defined": "I80F48"
|
"defined": "I80F48"
|
||||||
}
|
}
|
||||||
|
@ -4564,12 +4571,33 @@ export type MangoV4 = {
|
||||||
"name": "reduceOnly",
|
"name": "reduceOnly",
|
||||||
"type": "u8"
|
"type": "u8"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "padding4",
|
||||||
|
"type": {
|
||||||
|
"array": [
|
||||||
|
"u8",
|
||||||
|
7
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "maintPnlAssetWeight",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "initPnlAssetWeight",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "reserved",
|
"name": "reserved",
|
||||||
"type": {
|
"type": {
|
||||||
"array": [
|
"array": [
|
||||||
"u8",
|
"u8",
|
||||||
1943
|
1904
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4869,25 +4897,37 @@ export type MangoV4 = {
|
||||||
"type": "u16"
|
"type": "u16"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "maintAssetWeight",
|
"name": "maintBaseAssetWeight",
|
||||||
"type": {
|
"type": {
|
||||||
"defined": "I80F48"
|
"defined": "I80F48"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "initAssetWeight",
|
"name": "initBaseAssetWeight",
|
||||||
"type": {
|
"type": {
|
||||||
"defined": "I80F48"
|
"defined": "I80F48"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "maintLiabWeight",
|
"name": "maintBaseLiabWeight",
|
||||||
"type": {
|
"type": {
|
||||||
"defined": "I80F48"
|
"defined": "I80F48"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "initLiabWeight",
|
"name": "initBaseLiabWeight",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "maintPnlAssetWeight",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "initPnlAssetWeight",
|
||||||
"type": {
|
"type": {
|
||||||
"defined": "I80F48"
|
"defined": "I80F48"
|
||||||
}
|
}
|
||||||
|
@ -4923,10 +4963,6 @@ export type MangoV4 = {
|
||||||
{
|
{
|
||||||
"name": "hasOpenOrders",
|
"name": "hasOpenOrders",
|
||||||
"type": "bool"
|
"type": "bool"
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "trustedMarket",
|
|
||||||
"type": "bool"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -7717,7 +7753,7 @@ export type MangoV4 = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const IDL: MangoV4 = {
|
export const IDL: MangoV4 = {
|
||||||
"version": "0.2.0",
|
"version": "0.3.0",
|
||||||
"name": "mango_v4",
|
"name": "mango_v4",
|
||||||
"instructions": [
|
"instructions": [
|
||||||
{
|
{
|
||||||
|
@ -10226,19 +10262,27 @@ export const IDL: MangoV4 = {
|
||||||
"type": "i64"
|
"type": "i64"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "maintAssetWeight",
|
"name": "maintBaseAssetWeight",
|
||||||
"type": "f32"
|
"type": "f32"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "initAssetWeight",
|
"name": "initBaseAssetWeight",
|
||||||
"type": "f32"
|
"type": "f32"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "maintLiabWeight",
|
"name": "maintBaseLiabWeight",
|
||||||
"type": "f32"
|
"type": "f32"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "initLiabWeight",
|
"name": "initBaseLiabWeight",
|
||||||
|
"type": "f32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "maintPnlAssetWeight",
|
||||||
|
"type": "f32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "initPnlAssetWeight",
|
||||||
"type": "f32"
|
"type": "f32"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -10269,10 +10313,6 @@ export const IDL: MangoV4 = {
|
||||||
"name": "groupInsuranceFund",
|
"name": "groupInsuranceFund",
|
||||||
"type": "bool"
|
"type": "bool"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "trustedMarket",
|
|
||||||
"type": "bool"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "feePenalty",
|
"name": "feePenalty",
|
||||||
"type": "f32"
|
"type": "f32"
|
||||||
|
@ -10349,25 +10389,37 @@ export const IDL: MangoV4 = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "maintAssetWeightOpt",
|
"name": "maintBaseAssetWeightOpt",
|
||||||
"type": {
|
"type": {
|
||||||
"option": "f32"
|
"option": "f32"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "initAssetWeightOpt",
|
"name": "initBaseAssetWeightOpt",
|
||||||
"type": {
|
"type": {
|
||||||
"option": "f32"
|
"option": "f32"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "maintLiabWeightOpt",
|
"name": "maintBaseLiabWeightOpt",
|
||||||
"type": {
|
"type": {
|
||||||
"option": "f32"
|
"option": "f32"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "initLiabWeightOpt",
|
"name": "initBaseLiabWeightOpt",
|
||||||
|
"type": {
|
||||||
|
"option": "f32"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "maintPnlAssetWeightOpt",
|
||||||
|
"type": {
|
||||||
|
"option": "f32"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "initPnlAssetWeightOpt",
|
||||||
"type": {
|
"type": {
|
||||||
"option": "f32"
|
"option": "f32"
|
||||||
}
|
}
|
||||||
|
@ -10414,12 +10466,6 @@ export const IDL: MangoV4 = {
|
||||||
"option": "bool"
|
"option": "bool"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "trustedMarketOpt",
|
|
||||||
"type": {
|
|
||||||
"option": "bool"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "feePenaltyOpt",
|
"name": "feePenaltyOpt",
|
||||||
"type": {
|
"type": {
|
||||||
|
@ -12026,10 +12072,7 @@ export const IDL: MangoV4 = {
|
||||||
"type": "u16"
|
"type": "u16"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "trustedMarket",
|
"name": "blocked1",
|
||||||
"docs": [
|
|
||||||
"May this market contribute positive values to health?"
|
|
||||||
],
|
|
||||||
"type": "u8"
|
"type": "u8"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -12104,25 +12147,25 @@ export const IDL: MangoV4 = {
|
||||||
"type": "i64"
|
"type": "i64"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "maintAssetWeight",
|
"name": "maintBaseAssetWeight",
|
||||||
"type": {
|
"type": {
|
||||||
"defined": "I80F48"
|
"defined": "I80F48"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "initAssetWeight",
|
"name": "initBaseAssetWeight",
|
||||||
"type": {
|
"type": {
|
||||||
"defined": "I80F48"
|
"defined": "I80F48"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "maintLiabWeight",
|
"name": "maintBaseLiabWeight",
|
||||||
"type": {
|
"type": {
|
||||||
"defined": "I80F48"
|
"defined": "I80F48"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "initLiabWeight",
|
"name": "initBaseLiabWeight",
|
||||||
"type": {
|
"type": {
|
||||||
"defined": "I80F48"
|
"defined": "I80F48"
|
||||||
}
|
}
|
||||||
|
@ -12282,12 +12325,33 @@ export const IDL: MangoV4 = {
|
||||||
"name": "reduceOnly",
|
"name": "reduceOnly",
|
||||||
"type": "u8"
|
"type": "u8"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "padding4",
|
||||||
|
"type": {
|
||||||
|
"array": [
|
||||||
|
"u8",
|
||||||
|
7
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "maintPnlAssetWeight",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "initPnlAssetWeight",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "reserved",
|
"name": "reserved",
|
||||||
"type": {
|
"type": {
|
||||||
"array": [
|
"array": [
|
||||||
"u8",
|
"u8",
|
||||||
1943
|
1904
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12587,25 +12651,37 @@ export const IDL: MangoV4 = {
|
||||||
"type": "u16"
|
"type": "u16"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "maintAssetWeight",
|
"name": "maintBaseAssetWeight",
|
||||||
"type": {
|
"type": {
|
||||||
"defined": "I80F48"
|
"defined": "I80F48"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "initAssetWeight",
|
"name": "initBaseAssetWeight",
|
||||||
"type": {
|
"type": {
|
||||||
"defined": "I80F48"
|
"defined": "I80F48"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "maintLiabWeight",
|
"name": "maintBaseLiabWeight",
|
||||||
"type": {
|
"type": {
|
||||||
"defined": "I80F48"
|
"defined": "I80F48"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "initLiabWeight",
|
"name": "initBaseLiabWeight",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "maintPnlAssetWeight",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "initPnlAssetWeight",
|
||||||
"type": {
|
"type": {
|
||||||
"defined": "I80F48"
|
"defined": "I80F48"
|
||||||
}
|
}
|
||||||
|
@ -12641,10 +12717,6 @@ export const IDL: MangoV4 = {
|
||||||
{
|
{
|
||||||
"name": "hasOpenOrders",
|
"name": "hasOpenOrders",
|
||||||
"type": "bool"
|
"type": "bool"
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "trustedMarket",
|
|
||||||
"type": "bool"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -245,13 +245,14 @@ async function main() {
|
||||||
1.05,
|
1.05,
|
||||||
0.012,
|
0.012,
|
||||||
0.0002,
|
0.0002,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
0.0,
|
0.0,
|
||||||
0,
|
0,
|
||||||
0.05,
|
0.05,
|
||||||
0.05,
|
0.05,
|
||||||
100,
|
100,
|
||||||
true,
|
true,
|
||||||
true,
|
|
||||||
1000,
|
1000,
|
||||||
1000000,
|
1000000,
|
||||||
0.05,
|
0.05,
|
||||||
|
|
|
@ -424,6 +424,8 @@ async function registerPerpMarkets() {
|
||||||
0.95,
|
0.95,
|
||||||
1.025,
|
1.025,
|
||||||
1.05,
|
1.05,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
0.0125,
|
0.0125,
|
||||||
-0.0001,
|
-0.0001,
|
||||||
0.0004,
|
0.0004,
|
||||||
|
@ -432,7 +434,6 @@ async function registerPerpMarkets() {
|
||||||
0.05,
|
0.05,
|
||||||
100, // if btc is at 20k, this is 200$
|
100, // if btc is at 20k, this is 200$
|
||||||
true,
|
true,
|
||||||
true,
|
|
||||||
1000, // solana tx fee is currently 50 native quote at a sol price of 10$
|
1000, // solana tx fee is currently 50 native quote at a sol price of 10$
|
||||||
1000000,
|
1000000,
|
||||||
0.01, // less than liquidationFee
|
0.01, // less than liquidationFee
|
||||||
|
@ -454,6 +455,8 @@ async function registerPerpMarkets() {
|
||||||
0.99, // 100x leverage
|
0.99, // 100x leverage
|
||||||
1.005,
|
1.005,
|
||||||
1.01,
|
1.01,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
0.0025,
|
0.0025,
|
||||||
-0.0001,
|
-0.0001,
|
||||||
0.0004,
|
0.0004,
|
||||||
|
@ -462,7 +465,6 @@ async function registerPerpMarkets() {
|
||||||
0.05,
|
0.05,
|
||||||
1000, // if mngo price 1 cent, this is 10$
|
1000, // if mngo price 1 cent, this is 10$
|
||||||
false,
|
false,
|
||||||
false,
|
|
||||||
1000,
|
1000,
|
||||||
1000000,
|
1000000,
|
||||||
0.001, // less than liquidationFee
|
0.001, // less than liquidationFee
|
||||||
|
@ -487,21 +489,6 @@ async function makePerpMarketReduceOnly() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function makePerpMarketUntrusted() {
|
|
||||||
const result = await buildAdminClient();
|
|
||||||
const client = result[0];
|
|
||||||
const admin = result[1];
|
|
||||||
const creator = result[2];
|
|
||||||
|
|
||||||
const group = await client.getGroupForCreator(creator.publicKey, GROUP_NUM);
|
|
||||||
const perpMarket = group.getPerpMarketByName('BTC-PERP');
|
|
||||||
await client.perpEditMarket(
|
|
||||||
group,
|
|
||||||
perpMarket.perpMarketIndex,
|
|
||||||
Builder(NullPerpEditParams).trustedMarket(false).build(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createAndPopulateAlt() {
|
async function createAndPopulateAlt() {
|
||||||
const result = await buildAdminClient();
|
const result = await buildAdminClient();
|
||||||
const client = result[0];
|
const client = result[0];
|
||||||
|
@ -662,7 +649,6 @@ async function main() {
|
||||||
try {
|
try {
|
||||||
// await registerPerpMarkets();
|
// await registerPerpMarkets();
|
||||||
// await makePerpMarketReduceOnly();
|
// await makePerpMarketReduceOnly();
|
||||||
// await makePerpMarketUntrusted();
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -228,6 +228,8 @@ async function main() {
|
||||||
0.8,
|
0.8,
|
||||||
1.1,
|
1.1,
|
||||||
1.2,
|
1.2,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
0.05,
|
0.05,
|
||||||
-0.001,
|
-0.001,
|
||||||
0.002,
|
0.002,
|
||||||
|
@ -236,7 +238,6 @@ async function main() {
|
||||||
0.1,
|
0.1,
|
||||||
10,
|
10,
|
||||||
false,
|
false,
|
||||||
false,
|
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
|
Loading…
Reference in New Issue