Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix two resize bugs #2412

Merged
merged 2 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 11 additions & 44 deletions coordinator/src/trade/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use crate::payout_curve;
use crate::position::models::NewPosition;
use crate::position::models::Position;
use crate::position::models::PositionState;
use crate::trade::models::NewTrade;
use anyhow::anyhow;
use anyhow::bail;
use anyhow::ensure;
Expand Down Expand Up @@ -735,26 +734,6 @@ impl TradeExecutor {
order_matching_fee,
)?;

// We add the trade before it is complete so that we can insert the PNL now. Otherwise the
// information is lost.
db::trades::insert(
conn,
NewTrade {
position_id: position.id,
contract_symbol: position.contract_symbol,
trader_pubkey: position.trader,
quantity: trade_params.quantity,
trader_leverage: position.trader_leverage,
trader_direction: trade_params.direction,
average_price: trade_params
.average_execution_price()
.to_f32()
.expect("to fit"),
order_matching_fee,
trader_realized_pnl_sat: realized_pnl.map(SignedAmount::to_sat),
},
)?;

Ok(())
}

Expand Down Expand Up @@ -1207,29 +1186,17 @@ fn apply_resize_to_position(
let coordinator_liquidation_price =
Decimal::try_from(position.coordinator_liquidation_price).expect("to fit");

let margin_coordinator = {
let margin_reduction = Amount::from_sat(calculate_margin(
order_average_execution_price,
order_contracts.to_f32().expect("to fit"),
position.coordinator_leverage,
));

Amount::from_sat(position.coordinator_margin as u64)
.checked_sub(margin_reduction)
.context("Coordinator margin below zero after resize")?
};

let margin_trader = {
let margin_reduction = Amount::from_sat(calculate_margin(
order_average_execution_price,
order_contracts.to_f32().expect("to fit"),
position.trader_leverage,
));
let margin_coordinator = Amount::from_sat(calculate_margin(
position_average_execution_price,
total_contracts.to_f32().expect("to fit"),
position.coordinator_leverage,
));

Amount::from_sat(position.trader_margin as u64)
.checked_sub(margin_reduction)
.context("Trader margin below zero after resize")?
};
let margin_trader = Amount::from_sat(calculate_margin(
position_average_execution_price,
total_contracts.to_f32().expect("to fit"),
position.trader_leverage,
));

let (original_margin_long, original_margin_short) = match position.trader_direction {
Direction::Long => (
Expand Down Expand Up @@ -1390,7 +1357,7 @@ fn apply_resize_to_position(
.expect("to fit");

let closed_margin = SignedAmount::from_sat(calculate_margin(
order_average_execution_price,
position_average_execution_price,
position.quantity,
position.trader_leverage,
) as i64);
Expand Down
4 changes: 2 additions & 2 deletions ...nator/src/trade/snapshots/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ ResizedPosition {
trader_liquidation_price: 33333.333333333333333333333333,
margin_coordinator: Amount(0.00250000 BTC),
margin_trader: Amount(0.00250000 BTC),
collateral_reserve_coordinator: Amount(0.00321214 BTC),
collateral_reserve_trader: Amount(0.00180968 BTC),
collateral_reserve_coordinator: Amount(0.00389336 BTC),
collateral_reserve_trader: Amount(0.00112846 BTC),
realized_pnl: Some(
SignedAmount(-0.00136245 BTC),
),
Expand Down
8 changes: 4 additions & 4 deletions coordinator/src/trade/snapshots/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ ResizedPosition {
average_execution_price: 27491,
coordinator_liquidation_price: 45818.33,
trader_liquidation_price: 19636.43,
margin_coordinator: Amount(0.00056878 BTC),
margin_trader: Amount(0.00056878 BTC),
collateral_reserve_coordinator: Amount(0.00514335 BTC),
collateral_reserve_trader: Amount(0.00374091 BTC),
margin_coordinator: Amount(0.00090939 BTC),
margin_trader: Amount(0.00090939 BTC),
collateral_reserve_coordinator: Amount(0.00480274 BTC),
collateral_reserve_trader: Amount(0.00340030 BTC),
realized_pnl: Some(
SignedAmount(-0.00068122 BTC),
),
Expand Down
4 changes: 2 additions & 2 deletions ...inator/src/trade/snapshots/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ ResizedPosition {
trader_liquidation_price: 33333.333333333333333333333333,
margin_coordinator: Amount(0.00250000 BTC),
margin_trader: Amount(0.00250000 BTC),
collateral_reserve_coordinator: Amount(0.00196213 BTC),
collateral_reserve_trader: Amount(0.00124091 BTC),
collateral_reserve_coordinator: Amount(0.00230274 BTC),
collateral_reserve_trader: Amount(0.00090030 BTC),
realized_pnl: Some(
SignedAmount(-0.00068122 BTC),
),
Expand Down
30 changes: 15 additions & 15 deletions crates/tests-e2e/tests/e2e_resize_position.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ async fn can_resize_position() {
//
// 250_005 [extra margin] = 250 [order contracts] / (49_999 [price] * 2 [leverage])
//
// 1_500 [fee] = 250 [order contracts] * (/ 1 49_999 [price]) * 0.0030 [fee coefficient]
// 1_500 [fee] = 250 [order contracts] * (1 / 49_999 [price]) * 0.0030 [fee coefficient]
//
// 748_495 [new reserve] = 1_000_000 [reserve] - 250_005 [extra margin] - 1_500 [fee]
let expected_off_chain_balance = 748_495;
Expand Down Expand Up @@ -93,27 +93,27 @@ async fn can_resize_position() {

// To decrease the position, we must decrease the margin (and increase the reserve).
//
// 399_992 [margin reduction] = 400 [order contracts] / (50_001 [closing price] * 2 [leverage])
// 400_008 [margin reduction] = 400 [order contracts] / (49_999 [opening price] * 2 [leverage])
//
// 2_400 [fee] = 400 [order contracts] * (/ 1 50_001 [closing price]) * 0.0030 [fee coefficient]
// 2_400 [fee] = 400 [order contracts] * (1 / 50_001 [closing price]) * 0.0030 [fee coefficient]
//
// -32 [pnl] = (400 [order contracts] / 50_001 [closing price]) - (400 [order contracts] /
// 49_999 [opening price])
//
// 1_146_055 [new reserve] = 748_495 [reserve] + 399_992 [margin reduction] - 2_400 [fee] - 32
// 1_146_071 [new reserve] = 748_495 [reserve] + 400_008 [margin reduction] - 2_400 [fee] - 32
// [pnl]
let expected_off_chain_balance = 1_146_055;
let expected_off_chain_balance = 1_146_071;
wait_until_balance_equals(&test, expected_off_chain_balance).await;

// 397_560 [trade amount] = 399_992 [margin reduction] - 2_400 [fee] - 32 [pnl]
// 397_576 [trade amount] = 400_008 [margin reduction] - 2_400 [fee] - 32 [pnl]
check_trade(
&test,
&order_id,
Direction::Long,
400,
Some(-32),
2_400,
397_560,
397_576,
);

tracing::info!(
Expand All @@ -136,35 +136,35 @@ async fn can_resize_position() {
// To change direction, we must decrease the margin to 0 and then increase it. The total effect
// depends on the specific order executed.
//
// 99_998 [closed margin] = 100 [close contracts] / (50_001 [closing price] * 2 [leverage])
// 100_002 [closed margin] = 100 [close contracts] / (49_999 [opening price] * 2 [leverage])
//
// -8 [pnl] = (100 [close contracts] / 50_001 [closing price]) - (100 [order contracts] / 49_999
// -8 [pnl] = (100 [close contracts] / 50_001 [closing price]) - (100 [close contracts] / 49_999
// [opening price])
//
// 199_996 [new margin] = 200 [remaining contracts] / (50_001 [price] * 2 [leverage])
//
// 1_800 [fee] = 300 [total contracts] * (/ 1 50_001 [closing price]) * 0.0030 [fee
// 1_800 [fee] = 300 [total contracts] * (1 / 50_001 [closing price]) * 0.0030 [fee
// coefficient]
//
// 1_044_249 [new reserve] = 1_146_055 [reserve] + 99_998 [closed margin] - 199_996 [new margin]
// - 1_800 [fee] - 8 [pnl]
let expected_off_chain_balance = 1_044_249;
// 1_044_269 [new reserve] = 1_146_071 [reserve] + 100_002 [closed margin] - 199_996 [new
// margin] - 1_800 [fee] - 8 [pnl]
let expected_off_chain_balance = 1_044_269;
wait_until_balance_equals(&test, expected_off_chain_balance).await;

// The direction changing order is split into two trades: one to close the short position and
// another to open the long position.

// Close short position.
//
// 99_390 [1st trade amount] = 99_998 [closed margin] - 600 [fee] - 8 [pnl]
// 99_394 [1st trade amount] = 100_002 [closed margin] - 600 [fee] - 8 [pnl]
check_trade(
&test,
&order_id,
Direction::Long,
100,
Some(-8),
600,
99_390,
99_394,
);

// Open long position, threfore no PNL.
Expand Down
32 changes: 14 additions & 18 deletions mobile/native/src/trade/position/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,30 +295,26 @@ impl Position {
compute_relative_contracts(order.quantity, order.direction);

let (new_collateral, closed_collateral) = {
let original_collateral_btc = starting_contracts
/ (starting_leverage * starting_average_execution_price);

let original_before_btc = original_collateral_btc
let contract_diff = Decimal::try_from(contract_diff).expect("to fit");
let new_collateral_btc =
contract_diff / (starting_leverage * starting_average_execution_price);
let new_collateral_btc = new_collateral_btc
.round_dp_with_strategy(8, RoundingStrategy::MidpointAwayFromZero)
.to_f64()
.expect("margin to fit into f64");

let original_collateral = Amount::from_btc(original_before_btc)
.expect("margin diff to fit into SignedAmount");

let closed_collateral_btc =
order_contracts / (starting_leverage * order_execution_price);
.expect("to fit");
let new_collateral = Amount::from_btc(new_collateral_btc).expect("to fit");

let closed_collateral_btc = order_contracts
/ (starting_leverage * starting_average_execution_price);
let closed_collateral_btc = closed_collateral_btc
.abs()
.round_dp_with_strategy(8, RoundingStrategy::MidpointAwayFromZero)
.to_f64()
.expect("collateral to fit into f64");

let closed_collateral = Amount::from_btc(closed_collateral_btc)
.expect("collateral to fit into Amount");

(original_collateral - closed_collateral, closed_collateral)
(new_collateral, closed_collateral)
};

let position = Position {
Expand Down Expand Up @@ -396,8 +392,8 @@ impl Position {
};

let closed_collateral = {
let closed_collateral_btc =
starting_contracts / (starting_leverage * order_execution_price);
let closed_collateral_btc = starting_contracts
/ (starting_leverage * starting_average_execution_price);

let closed_collateral_btc = closed_collateral_btc
.abs()
Expand Down Expand Up @@ -825,7 +821,7 @@ mod tests {
position.liquidation_price
);
assert_eq!(updated_position.position_state, PositionState::Open);
assert_eq!(updated_position.collateral, 6_842);
assert_eq!(updated_position.collateral, 6_855);
assert!(!updated_position.stable);

let trade = match trades.as_slice() {
Expand All @@ -837,7 +833,7 @@ mod tests {
assert_eq!(trade.contract_symbol, order.contract_symbol);
assert_eq!(trade.contracts, dec!(5));
assert_eq!(trade.direction, order.direction);
assert_eq!(trade.trade_cost, SignedAmount::from_sat(-5_842));
assert_eq!(trade.trade_cost, SignedAmount::from_sat(-5_829));
assert_eq!(trade.fee, Amount::from_sat(1_000));
assert_eq!(trade.pnl, Some(SignedAmount::from_sat(-26)));
assert_eq!(
Expand Down Expand Up @@ -905,7 +901,7 @@ mod tests {
assert_eq!(closing_trade.contract_symbol, order.contract_symbol);
assert_eq!(closing_trade.contracts, Decimal::TEN);
assert_eq!(closing_trade.direction, order.direction);
assert_eq!(closing_trade.trade_cost, SignedAmount::from_sat(-13_185));
assert_eq!(closing_trade.trade_cost, SignedAmount::from_sat(-13_159));
assert_eq!(closing_trade.fee, Amount::from_sat(500));
assert_eq!(closing_trade.pnl, Some(SignedAmount::from_sat(-51)));
assert_eq!(
Expand Down
Loading