Skip to content

Commit d59683e

Browse files
committed
debugging
1 parent 283fc45 commit d59683e

File tree

1 file changed

+52
-46
lines changed
  • crates/hyperdrive-math/src/short

1 file changed

+52
-46
lines changed

crates/hyperdrive-math/src/short/max.rs

Lines changed: 52 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ impl State {
6060
Ok(spot_price * (fixed!(1e18) - weight) + min_price * weight)
6161
}
6262

63+
/// Use SGD with rate reduction to find the amount of bonds shorted for a
64+
/// given base deposit amount.
6365
pub fn calculate_short_bonds_given_deposit(
6466
&self,
6567
base_deposit_amount: FixedPoint<U256>,
@@ -71,21 +73,24 @@ impl State {
7173
let mut learning_rate = fixed!(1e18);
7274
let max_iterations = maybe_max_iterations.unwrap_or(1_000);
7375
let tolerance = maybe_tolerance.unwrap_or(fixed!(1e5));
76+
let min_learning_rate = fixed!(1e2);
77+
7478
// Start with a conservative estimate of the bonds shorted & base paid.
79+
// Assuming the LP short principal is equal to some relized price times
80+
// the bond amount, we can calculate a lower bound using a conservative
81+
// price.
7582
let conservative_price = self.calculate_conservative_short_price(base_deposit_amount)?;
76-
// let close_vault_share_price = open_vault_share_price.max(self.vault_share_price());
77-
// We ignore the short principal so that we have a closed-form inversion
78-
// of the short deposit equation.
79-
// let mut last_good_bond_amount = base_deposit_amount
80-
// / (((fixed!(1e18) / self.vault_share_price())
81-
// * (close_vault_share_price / open_vault_share_price)
82-
// + self.flat_fee())
83-
// + self.curve_fee() * (fixed!(1e18) - conservative_price));
84-
let mut last_good_bond_amount = self.minimum_transaction_amount();
83+
println!("conservative_price = {:#?}", conservative_price);
84+
let close_vault_share_price = open_vault_share_price.max(self.vault_share_price());
85+
let mut last_good_bond_amount = base_deposit_amount
86+
/ ((close_vault_share_price / open_vault_share_price)
87+
+ self.flat_fee()
88+
+ (self.curve_fee() * (fixed!(1e18) - self.calculate_spot_price()?))
89+
- conservative_price);
90+
8591
let mut last_good_base_amount =
8692
self.calculate_open_short(last_good_bond_amount, open_vault_share_price)?;
8793
println!("base_deposit_amount = {:#?}", base_deposit_amount);
88-
println!("conservative_price = {:#?}", conservative_price);
8994
println!("last_good_bond_amount = {:#?}", last_good_bond_amount);
9095
println!("last_good_base_amount = {:#?}", last_good_base_amount);
9196
println!(
@@ -103,71 +108,68 @@ impl State {
103108
// Short circuit if we somehow hit it with the guess.
104109
else if (base_deposit_amount - last_good_base_amount) <= tolerance {
105110
// Within tolerance, but bond amount must be >= 0.
106-
return Ok(last_good_bond_amount.max(fixed!(0)).change_type::<U256>()?);
111+
return Ok(last_good_bond_amount.max(fixed!(0)));
107112
}
108113
// Run Stochastic Gradient Descent to adjust the bond amount.
109114
for iter in 0..max_iterations {
110115
println!("\n----\niter {:#?}", iter);
111-
println!("learning_rate {:#?}", learning_rate);
116+
println!("learning_rate={:#?}", learning_rate);
112117
// Calculate the current deposit.
113118
let base_amount =
114119
self.calculate_open_short(last_good_bond_amount, open_vault_share_price)?;
115-
// Calculate the current gradient.
116-
let base_amount_derivative = self.calculate_open_short_derivative(
117-
last_good_bond_amount,
118-
open_vault_share_price,
119-
Some(self.calculate_spot_price()?),
120-
)?;
121-
// If we overshot here, we set the error to zero and then the
122-
// new_bond_amount = last_good_bond_amount.
120+
// If we overshot here, we throw an error.
123121
println!("last_good_bond_amount={:#?}", last_good_bond_amount);
124122
println!("base_amount={:#?}", base_amount);
125123
println!("base_deposit_amount={:#?}", base_deposit_amount);
126124
let error = if base_amount < base_deposit_amount {
127125
base_deposit_amount - base_amount
128126
} else {
129-
fixed!(0)
127+
return Err(eyre!("Overshot target."));
130128
};
131129
println!("error={:#?}", error);
130+
// Calculate the current gradient.
131+
let base_amount_derivative = self.calculate_open_short_derivative(
132+
last_good_bond_amount,
133+
open_vault_share_price,
134+
Some(self.calculate_spot_price()?),
135+
)?;
136+
println!("base_amount_derivative={:#?}", base_amount_derivative);
132137
// Calculate the new bond amount.
138+
// FIXME: swap x & y so it's bonds & base
133139
// The update rule is: x_1 = x_0 - \eta * L(y,y_t) * dL(y,y_t)/dx,
134-
// where \eta is the learning rate, L is the error, y is
135-
// open_short(x), and y_t is the target deposit. The derivative of
136-
// L(y,y_t) wrt x is -base_amount_derivative. So we add here instead
137-
// of subtracting a negative.
140+
// where x is the deposit in base, \eta is the learning rate, y is
141+
// open_short(x), y_t is the target deposit, and L is (y_t - y).
142+
// The derivative of L(y,y_t) wrt x is -base_amount_derivative,
143+
// so we add here instead of subtracting a negative.
138144
let new_bond_amount =
139145
last_good_bond_amount + learning_rate * error * base_amount_derivative;
146+
println!("new_bond_amount={:#?}", new_bond_amount);
140147
// If we overshot, lower the learning rate and try again.
141148
// Otherwise, check convergence to either return or continue.
142149
match self.calculate_open_short(new_bond_amount, open_vault_share_price) {
143150
Ok(new_base_amount) => {
144-
println!(
145-
"new_base_amount={:#?}; base_deposit_amount={:#?}",
146-
new_base_amount, base_deposit_amount
147-
);
148-
if new_base_amount > base_deposit_amount {
149-
let error_magnitude = new_base_amount / base_deposit_amount;
150-
println!("error_magnitude={:#?}", error_magnitude);
151-
// If the values are too close then the error magnitude
152-
// will round to 1.0 and the rate will not change.
153-
learning_rate = if error_magnitude <= fixed!(1e18) {
154-
(learning_rate / fixed!(2e18)).max(fixed!(1))
155-
} else {
156-
(learning_rate / error_magnitude).max(fixed!(1))
157-
};
158-
} else {
159-
last_good_bond_amount = new_bond_amount;
151+
println!("new_base_amount={:#?}", new_base_amount);
152+
if new_base_amount <= base_deposit_amount {
160153
last_good_base_amount = new_base_amount;
154+
last_good_bond_amount = new_bond_amount;
161155
// Check for convergence.
162156
if (base_deposit_amount - last_good_base_amount) <= tolerance {
163157
// Within tolerance, but bond amount must be >= 0.
164158
return Ok(last_good_bond_amount.max(fixed!(0)));
165159
}
166-
// Amount was good but we did not converge; keep going.
160+
// else, amount was good but we did not converge; keep going.
161+
} else {
162+
// Scale the learning rate reduction by the error.
163+
// If the values are too close then the error magnitude
164+
// will be small and the rate will not change enough.
165+
let error_magnitude =
166+
(new_base_amount / base_deposit_amount).max(fixed!(1.0001e18));
167+
println!("error_magnitude={:#?}", error_magnitude);
168+
learning_rate = (learning_rate / error_magnitude).max(min_learning_rate);
167169
}
168170
}
169171
Err(_) => {
170-
learning_rate = (learning_rate / fixed!(10e18)).max(fixed!(1));
172+
learning_rate = (learning_rate / fixed!(1.0001e18)).max(min_learning_rate);
171173
}
172174
}
173175
}
@@ -720,10 +722,11 @@ mod tests {
720722

721723
#[tokio::test]
722724
async fn fuzz_calculate_short_bonds_given_deposit() -> Result<()> {
723-
let test_tolerance = fixed!(1e6);
725+
let test_tolerance = fixed!(1e9);
724726
let max_iterations = 10_000;
725727
let mut rng = thread_rng();
726-
for _ in 0..*SLOW_FUZZ_RUNS {
728+
for fuzz_iter in 0..*SLOW_FUZZ_RUNS {
729+
println!("fuzz_iter {:#?}", fuzz_iter);
727730
let state = rng.gen::<State>();
728731
let open_vault_share_price = rng.gen_range(fixed!(0)..=state.vault_share_price());
729732
let checkpoint_exposure = {
@@ -734,7 +737,10 @@ mod tests {
734737
I256::try_from(value)?
735738
}
736739
};
737-
let max_short_trade = get_max_short(state.clone(), checkpoint_exposure, None)?;
740+
let max_short_trade = match get_max_short(state.clone(), checkpoint_exposure, None) {
741+
Ok(max_short_trade) => max_short_trade,
742+
Err(_) => continue,
743+
};
738744
let target_base_amount =
739745
rng.gen_range(state.minimum_transaction_amount()..=max_short_trade);
740746
let bond_amount = state.calculate_short_bonds_given_deposit(

0 commit comments

Comments
 (0)