Skip to content

Commit 88b10c5

Browse files
0xbigzcrispheaney
andauthored
program: auction-order-params-on-slow-fast-twap-divergence (#1882)
* program: auction-order-params-on-slow-fast-twap-divergence * change tests * rm dlog * CHANGELOG * cargo fmt -- --------- Co-authored-by: Chris Heaney <[email protected]>
1 parent 6cce7e5 commit 88b10c5

File tree

3 files changed

+82
-56
lines changed

3 files changed

+82
-56
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Features
1111

12+
- program: auction order params account for twap divergence ([#1882](https://github.com/drift-labs/protocol-v2/pull/1882))
1213
- program: add delegate stake if ([#1859](https://github.com/drift-labs/protocol-v2/pull/1859))
1314

1415
### Fixes

programs/drift/src/state/order_params.rs

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -702,13 +702,6 @@ impl OrderParams {
702702
}
703703
.cast::<i64>()?;
704704

705-
let baseline_start_price_offset_slow = mark_twap_slow.safe_sub(
706-
perp_market
707-
.amm
708-
.historical_oracle_data
709-
.last_oracle_price_twap,
710-
)?;
711-
712705
let baseline_start_price_offset_fast = perp_market
713706
.amm
714707
.last_mark_price_twap_5min
@@ -720,27 +713,42 @@ impl OrderParams {
720713
.last_oracle_price_twap_5min,
721714
)?;
722715

723-
let frac_of_long_spread_in_price: i64 = perp_market
724-
.amm
725-
.long_spread
726-
.cast::<i64>()?
727-
.safe_mul(mark_twap_slow)?
728-
.safe_div(PRICE_PRECISION_I64 * 10)?;
716+
let baseline_start_price_offset_slow = mark_twap_slow.safe_sub(
717+
perp_market
718+
.amm
719+
.historical_oracle_data
720+
.last_oracle_price_twap,
721+
)?;
729722

730-
let frac_of_short_spread_in_price: i64 = perp_market
731-
.amm
732-
.short_spread
733-
.cast::<i64>()?
734-
.safe_mul(mark_twap_slow)?
735-
.safe_div(PRICE_PRECISION_I64 * 10)?;
736-
737-
let baseline_start_price_offset = match direction {
738-
PositionDirection::Long => baseline_start_price_offset_slow
739-
.safe_add(frac_of_long_spread_in_price)?
740-
.min(baseline_start_price_offset_fast.safe_sub(frac_of_short_spread_in_price)?),
741-
PositionDirection::Short => baseline_start_price_offset_slow
742-
.safe_sub(frac_of_short_spread_in_price)?
743-
.max(baseline_start_price_offset_fast.safe_add(frac_of_long_spread_in_price)?),
723+
let baseline_start_price_offset = if baseline_start_price_offset_slow
724+
.abs_diff(baseline_start_price_offset_fast)
725+
<= perp_market.amm.last_mark_price_twap_5min / 200
726+
{
727+
let frac_of_long_spread_in_price: i64 = perp_market
728+
.amm
729+
.long_spread
730+
.cast::<i64>()?
731+
.safe_mul(mark_twap_slow)?
732+
.safe_div(PRICE_PRECISION_I64 * 10)?;
733+
734+
let frac_of_short_spread_in_price: i64 = perp_market
735+
.amm
736+
.short_spread
737+
.cast::<i64>()?
738+
.safe_mul(mark_twap_slow)?
739+
.safe_div(PRICE_PRECISION_I64 * 10)?;
740+
741+
match direction {
742+
PositionDirection::Long => baseline_start_price_offset_slow
743+
.safe_add(frac_of_long_spread_in_price)?
744+
.min(baseline_start_price_offset_fast.safe_sub(frac_of_short_spread_in_price)?),
745+
PositionDirection::Short => baseline_start_price_offset_slow
746+
.safe_sub(frac_of_short_spread_in_price)?
747+
.max(baseline_start_price_offset_fast.safe_add(frac_of_long_spread_in_price)?),
748+
}
749+
} else {
750+
// more than 50bps different of fast/slow twap, use fast only
751+
baseline_start_price_offset_fast
744752
};
745753

746754
Ok(baseline_start_price_offset)
@@ -891,15 +899,15 @@ fn get_auction_duration(
891899
) -> DriftResult<u8> {
892900
let percent_diff = price_diff.safe_mul(PERCENTAGE_PRECISION_U64)?.div(price);
893901

894-
let slots_per_bp = if contract_tier.is_as_safe_as_contract(&ContractTier::B) {
902+
let slots_per_pct = if contract_tier.is_as_safe_as_contract(&ContractTier::B) {
895903
100
896904
} else {
897905
60
898906
};
899907

900908
Ok(percent_diff
901-
.safe_mul(slots_per_bp)?
902-
.safe_div_ceil(PERCENTAGE_PRECISION_U64 / 100)? // 1% = 60 slots
909+
.safe_mul(slots_per_pct)?
910+
.safe_div_ceil(PERCENTAGE_PRECISION_U64 / 100)? // 1% = 40 slots
903911
.clamp(1, 180) as u8) // 180 slots max
904912
}
905913

programs/drift/src/state/order_params/tests.rs

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -409,10 +409,11 @@ mod update_perp_auction_params {
409409
..AMM::default()
410410
};
411411
amm.last_bid_price_twap = (oracle_price * 15 / 10 - 192988) as u64;
412-
amm.last_mark_price_twap_5min = (oracle_price * 16 / 10) as u64;
412+
amm.last_mark_price_twap_5min = (oracle_price * 155 / 100) as u64;
413413
amm.last_ask_price_twap = (oracle_price * 16 / 10 + 192988) as u64;
414414
amm.historical_oracle_data.last_oracle_price_twap = oracle_price;
415415
amm.historical_oracle_data.last_oracle_price_twap_5min = oracle_price;
416+
amm.last_mark_price_twap_5min = (amm.last_ask_price_twap + amm.last_bid_price_twap) / 2;
416417

417418
amm.historical_oracle_data.last_oracle_price = oracle_price;
418419
let perp_market = PerpMarket {
@@ -436,7 +437,7 @@ mod update_perp_auction_params {
436437
.update_perp_auction_params(&perp_market, oracle_price, false)
437438
.unwrap();
438439

439-
assert_eq!(order_params_after.auction_start_price, Some(72_524_319));
440+
assert_eq!(order_params_after.auction_start_price, Some(79_750_000));
440441
assert_eq!(order_params_after.auction_end_price, Some(90_092_988));
441442
assert_eq!(order_params_after.auction_duration, Some(180));
442443
}
@@ -456,13 +457,13 @@ mod update_perp_auction_params {
456457
..AMM::default()
457458
};
458459
amm.last_bid_price_twap = (oracle_price * 99 / 100) as u64;
459-
amm.last_mark_price_twap_5min = oracle_price as u64;
460460
amm.last_ask_price_twap = (oracle_price * 101 / 100) as u64;
461461
amm.historical_oracle_data.last_oracle_price_twap = oracle_price;
462462
amm.historical_oracle_data.last_oracle_price_twap_5min = oracle_price;
463+
amm.last_mark_price_twap_5min = (amm.last_ask_price_twap + amm.last_bid_price_twap) / 2;
463464

464465
amm.historical_oracle_data.last_oracle_price = oracle_price;
465-
let perp_market = PerpMarket {
466+
let mut perp_market = PerpMarket {
466467
amm,
467468
..PerpMarket::default()
468469
};
@@ -563,10 +564,10 @@ mod update_perp_auction_params {
563564
.update_perp_auction_params(&perp_market, oracle_price, false)
564565
.unwrap();
565566
assert_ne!(order_params_before, order_params_after);
566-
assert_eq!(order_params_after.auction_duration, Some(175));
567+
assert_eq!(order_params_after.auction_duration, Some(120));
567568
assert_eq!(
568569
order_params_after.auction_start_price,
569-
Some(100 * PRICE_PRECISION_I64 - 901000)
570+
Some(100 * PRICE_PRECISION_I64)
570571
);
571572
assert_eq!(
572573
order_params_after.auction_end_price,
@@ -599,20 +600,24 @@ mod update_perp_auction_params {
599600
direction: PositionDirection::Short,
600601
..OrderParams::default()
601602
};
603+
604+
// tighten bid/ask to mark twap 5min to activate buffer
605+
perp_market.amm.last_bid_price_twap = amm.last_mark_price_twap_5min - 100000;
606+
perp_market.amm.last_ask_price_twap = amm.last_mark_price_twap_5min + 100000;
602607
let mut order_params_after = order_params_before;
603608
order_params_after
604609
.update_perp_auction_params(&perp_market, oracle_price, false)
605610
.unwrap();
606611
assert_ne!(order_params_before, order_params_after);
607-
assert_eq!(order_params_after.auction_duration, Some(174));
608612
assert_eq!(
609613
order_params_after.auction_start_price,
610-
Some(100 * PRICE_PRECISION_I64 + 899000) // %1 / 10 = 10 bps aggression
614+
Some(100 * PRICE_PRECISION_I64 + 100100) // a bit more passive than mid
611615
);
612616
assert_eq!(
613617
order_params_after.auction_end_price,
614618
Some(98 * PRICE_PRECISION_I64)
615619
);
620+
assert_eq!(order_params_after.auction_duration, Some(127));
616621
}
617622

618623
#[test]
@@ -786,10 +791,12 @@ mod update_perp_auction_params {
786791
};
787792
amm.historical_oracle_data.last_oracle_price = oracle_price;
788793
amm.historical_oracle_data.last_oracle_price_twap = oracle_price - 97238;
794+
amm.historical_oracle_data.last_oracle_price_twap_5min = oracle_price - 97238;
789795
amm.last_ask_price_twap =
790796
(amm.historical_oracle_data.last_oracle_price_twap as u64) + 217999;
791797
amm.last_bid_price_twap =
792798
(amm.historical_oracle_data.last_oracle_price_twap as u64) + 17238;
799+
amm.last_mark_price_twap_5min = (amm.last_ask_price_twap + amm.last_bid_price_twap) / 2;
793800

794801
let mut perp_market = PerpMarket {
795802
amm,
@@ -812,7 +819,7 @@ mod update_perp_auction_params {
812819
.update_perp_auction_params(&perp_market, oracle_price, false)
813820
.unwrap();
814821
assert_ne!(order_params_before, order_params_after);
815-
assert_eq!(order_params_after.auction_start_price.unwrap(), 98901080);
822+
assert_eq!(order_params_after.auction_start_price.unwrap(), 99018698);
816823
let amm_bid_price = amm.bid_price(amm.reserve_price().unwrap()).unwrap();
817824
assert_eq!(amm_bid_price, 98010000);
818825
assert!(order_params_after.auction_start_price.unwrap() as u64 > amm_bid_price);
@@ -832,7 +839,7 @@ mod update_perp_auction_params {
832839
.update_perp_auction_params(&perp_market, oracle_price, false)
833840
.unwrap();
834841
assert_ne!(order_params_before, order_params_after);
835-
assert_eq!(order_params_after.auction_start_price.unwrap(), 99118879);
842+
assert_eq!(order_params_after.auction_start_price.unwrap(), 99216738);
836843

837844
// skip for prelaunch oracle
838845
perp_market.amm.oracle_source = OracleSource::Prelaunch;
@@ -893,12 +900,13 @@ mod update_perp_auction_params {
893900
..AMM::default()
894901
};
895902
amm.historical_oracle_data.last_oracle_price = oracle_price;
903+
amm.historical_oracle_data.last_oracle_price_twap_5min = oracle_price - 97238;
896904
amm.historical_oracle_data.last_oracle_price_twap = oracle_price - 97238;
897905
amm.last_ask_price_twap =
898906
(amm.historical_oracle_data.last_oracle_price_twap as u64) + 217999;
899907
amm.last_bid_price_twap =
900908
(amm.historical_oracle_data.last_oracle_price_twap as u64) + 17238;
901-
909+
amm.last_mark_price_twap_5min = (amm.last_ask_price_twap + amm.last_bid_price_twap) / 2;
902910
let perp_market = PerpMarket {
903911
amm,
904912
contract_tier: ContractTier::B,
@@ -920,7 +928,8 @@ mod update_perp_auction_params {
920928
.update_perp_auction_params(&perp_market, oracle_price, false)
921929
.unwrap();
922930
assert_ne!(order_params_before, order_params_after);
923-
assert_eq!(order_params_after.auction_start_price.unwrap(), -98920);
931+
assert_eq!(order_params_after.auction_start_price.unwrap(), 18698);
932+
assert_eq!(order_params_after.auction_end_price.unwrap(), 2196053);
924933

925934
let order_params_before = OrderParams {
926935
order_type: OrderType::Oracle,
@@ -985,10 +994,12 @@ mod update_perp_auction_params {
985994
};
986995
amm.historical_oracle_data.last_oracle_price = oracle_price;
987996
amm.historical_oracle_data.last_oracle_price_twap = oracle_price - 97238;
997+
amm.historical_oracle_data.last_oracle_price_twap_5min = oracle_price - 97238;
988998
amm.last_ask_price_twap =
989999
(amm.historical_oracle_data.last_oracle_price_twap as u64) + 217999;
9901000
amm.last_bid_price_twap =
9911001
(amm.historical_oracle_data.last_oracle_price_twap as u64) + 17238;
1002+
amm.last_mark_price_twap_5min = (amm.last_ask_price_twap + amm.last_bid_price_twap) / 2;
9921003

9931004
let perp_market = PerpMarket {
9941005
amm,
@@ -1011,7 +1022,7 @@ mod update_perp_auction_params {
10111022
.update_perp_auction_params(&perp_market, oracle_price, false)
10121023
.unwrap();
10131024
assert_ne!(order_params_before, order_params_after);
1014-
assert_eq!(order_params_after.auction_start_price.unwrap(), 98653580);
1025+
assert_eq!(order_params_after.auction_start_price.unwrap(), 98771198);
10151026

10161027
let order_params_before = OrderParams {
10171028
order_type: OrderType::Market,
@@ -1030,7 +1041,7 @@ mod update_perp_auction_params {
10301041
assert_ne!(order_params_before, order_params_after);
10311042
assert_eq!(
10321043
order_params_after.auction_start_price.unwrap(),
1033-
(99 * PRICE_PRECISION_I64 - oracle_price / 400) - 98920 // approx equal with some noise
1044+
(99 * PRICE_PRECISION_I64 - oracle_price / 400 + 18698) // approx equal with some noise
10341045
);
10351046

10361047
let order_params_before = OrderParams {
@@ -1049,7 +1060,7 @@ mod update_perp_auction_params {
10491060
.unwrap();
10501061
assert_eq!(
10511062
order_params_after.auction_start_price.unwrap(),
1052-
99118879 + oracle_price / 400
1063+
99118879 + oracle_price / 400 + 97859
10531064
);
10541065

10551066
let order_params_before = OrderParams {
@@ -1069,7 +1080,7 @@ mod update_perp_auction_params {
10691080
assert_ne!(order_params_before, order_params_after);
10701081
assert_eq!(
10711082
order_params_after.auction_start_price.unwrap(),
1072-
(99 * PRICE_PRECISION_U64 + 100000) as i64 + oracle_price / 400 + 18879 // use limit price and oracle buffer with some noise
1083+
(99 * PRICE_PRECISION_U64 + 100000) as i64 + oracle_price / 400 + 116738 // use limit price and oracle buffer with some noise
10731084
);
10741085

10751086
let order_params_before = OrderParams {
@@ -1088,11 +1099,11 @@ mod update_perp_auction_params {
10881099
.unwrap();
10891100
assert_eq!(
10901101
order_params_after.auction_start_price.unwrap(),
1091-
99118879 + oracle_price / 400
1102+
99118879 + oracle_price / 400 + 97859
10921103
);
10931104
assert_eq!(order_params_after.auction_end_price.unwrap(), 98028211);
10941105

1095-
assert_eq!(order_params_after.auction_duration, Some(82));
1106+
assert_eq!(order_params_after.auction_duration, Some(88));
10961107

10971108
let order_params_before = OrderParams {
10981109
order_type: OrderType::Market,
@@ -1110,11 +1121,11 @@ mod update_perp_auction_params {
11101121
.unwrap();
11111122
assert_eq!(
11121123
order_params_after.auction_start_price.unwrap(),
1113-
98901080 - oracle_price / 400
1124+
98901080 - oracle_price / 400 + 117618
11141125
);
11151126
assert_eq!(order_params_after.auction_end_price.unwrap(), 100207026);
11161127

1117-
assert_eq!(order_params_after.auction_duration, Some(95));
1128+
assert_eq!(order_params_after.auction_duration, Some(88));
11181129
}
11191130

11201131
#[test]
@@ -1325,8 +1336,11 @@ mod get_close_perp_params {
13251336
let amm = AMM {
13261337
last_ask_price_twap: 101 * PRICE_PRECISION_U64,
13271338
last_bid_price_twap: 99 * PRICE_PRECISION_U64,
1339+
last_mark_price_twap_5min: 99 * PRICE_PRECISION_U64,
13281340
historical_oracle_data: HistoricalOracleData {
13291341
last_oracle_price_twap: 100 * PRICE_PRECISION_I64,
1342+
last_oracle_price_twap_5min: 100 * PRICE_PRECISION_I64,
1343+
13301344
..HistoricalOracleData::default()
13311345
},
13321346
mark_std: PRICE_PRECISION_U64,
@@ -1385,7 +1399,7 @@ mod get_close_perp_params {
13851399
let auction_start_price = params.auction_start_price.unwrap();
13861400
let auction_end_price = params.auction_end_price.unwrap();
13871401
let oracle_price_offset = params.oracle_price_offset.unwrap();
1388-
assert_eq!(auction_start_price, PRICE_PRECISION_I64);
1402+
assert_eq!(auction_start_price, 2 * PRICE_PRECISION_I64);
13891403
assert_eq!(auction_end_price, 4 * PRICE_PRECISION_I64);
13901404
assert_eq!(oracle_price_offset, 4 * PRICE_PRECISION_I64 as i32);
13911405

@@ -1420,7 +1434,7 @@ mod get_close_perp_params {
14201434
let auction_start_price = params.auction_start_price.unwrap();
14211435
let auction_end_price = params.auction_end_price.unwrap();
14221436
let oracle_price_offset = params.oracle_price_offset.unwrap();
1423-
assert_eq!(auction_start_price, -3 * PRICE_PRECISION_I64);
1437+
assert_eq!(auction_start_price, -2 * PRICE_PRECISION_I64);
14241438
assert_eq!(auction_end_price, 0);
14251439
assert_eq!(oracle_price_offset, 0);
14261440

@@ -1436,8 +1450,11 @@ mod get_close_perp_params {
14361450
let amm = AMM {
14371451
last_ask_price_twap: 101 * PRICE_PRECISION_U64,
14381452
last_bid_price_twap: 99 * PRICE_PRECISION_U64,
1453+
last_mark_price_twap_5min: 100 * PRICE_PRECISION_U64,
1454+
14391455
historical_oracle_data: HistoricalOracleData {
14401456
last_oracle_price_twap: 100 * PRICE_PRECISION_I64,
1457+
last_oracle_price_twap_5min: 100 * PRICE_PRECISION_I64,
14411458
..HistoricalOracleData::default()
14421459
},
14431460
mark_std: PRICE_PRECISION_U64,
@@ -1462,7 +1479,7 @@ mod get_close_perp_params {
14621479
let auction_start_price = params.auction_start_price.unwrap();
14631480
let auction_end_price = params.auction_end_price.unwrap();
14641481
let oracle_price_offset = params.oracle_price_offset.unwrap();
1465-
assert_eq!(auction_start_price, 1000000);
1482+
assert_eq!(auction_start_price, 0);
14661483
assert_eq!(auction_end_price, -2 * PRICE_PRECISION_I64);
14671484
assert_eq!(oracle_price_offset, -2 * PRICE_PRECISION_I64 as i32);
14681485

@@ -1498,7 +1515,7 @@ mod get_close_perp_params {
14981515
let auction_start_price = params.auction_start_price.unwrap();
14991516
let auction_end_price = params.auction_end_price.unwrap();
15001517
let oracle_price_offset = params.oracle_price_offset.unwrap();
1501-
assert_eq!(auction_start_price, 3 * PRICE_PRECISION_I64);
1518+
assert_eq!(auction_start_price, 2 * PRICE_PRECISION_I64);
15021519
assert_eq!(auction_end_price, 0);
15031520
assert_eq!(oracle_price_offset, 0);
15041521

@@ -1536,7 +1553,7 @@ mod get_close_perp_params {
15361553
let auction_start_price = params.auction_start_price.unwrap();
15371554
let auction_end_price = params.auction_end_price.unwrap();
15381555
let oracle_price_offset = params.oracle_price_offset.unwrap();
1539-
assert_eq!(auction_start_price, -PRICE_PRECISION_I64);
1556+
assert_eq!(auction_start_price, -2 * PRICE_PRECISION_I64);
15401557
assert_eq!(auction_end_price, -4 * PRICE_PRECISION_I64);
15411558
assert_eq!(oracle_price_offset, -4 * PRICE_PRECISION_I64 as i32);
15421559

@@ -1613,7 +1630,7 @@ mod get_close_perp_params {
16131630
let auction_start_price = params.auction_start_price.unwrap();
16141631
let auction_end_price = params.auction_end_price.unwrap();
16151632
let oracle_price_offset = params.oracle_price_offset.unwrap();
1616-
assert_eq!(auction_start_price, 641);
1633+
assert_eq!(auction_start_price, 284);
16171634
assert_eq!(auction_end_price, -1021);
16181635
assert_eq!(oracle_price_offset, -1021);
16191636

0 commit comments

Comments
 (0)