From f25c5c9445744a3ca7c7fd79becf427a7e3c07bd Mon Sep 17 00:00:00 2001 From: Kinrezc Date: Tue, 10 Oct 2023 15:19:08 -0400 Subject: [PATCH] calculate 15 day trailing rv on portfolio and asset --- box-simulation/src/agents/rebalancer.rs | 139 ++++++++---------------- box-simulation/src/main.rs | 2 +- 2 files changed, 49 insertions(+), 92 deletions(-) diff --git a/box-simulation/src/agents/rebalancer.rs b/box-simulation/src/agents/rebalancer.rs index 9f541a6c6..1f882c768 100644 --- a/box-simulation/src/agents/rebalancer.rs +++ b/box-simulation/src/agents/rebalancer.rs @@ -1,6 +1,5 @@ use box_core::math::ComputeReturns; use ethers::utils::format_ether; -use std::collections::VecDeque; use std::ops::Div; use super::*; @@ -10,14 +9,10 @@ pub struct Rebalancer { pub g3m: G3M, pub next_update_timestamp: u64, pub target_volatility: f64, - pub asset_vol: U256, - pub portfolio_vol: U256, - pub last_asset_value: f64, - pub last_portfolio_value: f64, - pub portfolio_prices: Vec, - pub asset_prices: Vec, - pub portfolio_returns: VecDeque, - pub asset_returns: VecDeque, + pub portfolio_prices: Vec<(f64, u64)>, + pub asset_prices: Vec<(f64, u64)>, + pub portfolio_rv: Vec<(f64, u64)>, + pub asset_rv: Vec<(f64, u64)>, } impl Rebalancer { @@ -37,14 +32,10 @@ impl Rebalancer { g3m, target_volatility, next_update_timestamp: 0, - asset_vol: U256::from(0), - portfolio_vol: U256::from(0), - last_asset_value: 0.0, - last_portfolio_value: 0.0, portfolio_prices: Vec::new(), asset_prices: Vec::new(), - portfolio_returns: VecDeque::new(), - asset_returns: VecDeque::new(), + portfolio_rv: Vec::new(), + asset_rv: Vec::new(), }) } @@ -68,91 +59,57 @@ impl Rebalancer { let asset_price_float = format_ether(asset_price).parse::().unwrap(); let portfolio_price_float = format_ether(portfolio_price).parse::().unwrap(); - self.append_asset_return(asset_price_float)?; - self.append_portfolio_return(portfolio_price_float)?; + self.asset_prices.push((asset_price_float, timestamp)); + self.portfolio_prices + .push((portfolio_price_float, timestamp)); } Ok(()) } - pub fn append_asset_return(&mut self, asset_price: f64) -> Result<()> { - if self.asset_returns.len() == 15 { - self.asset_returns.pop_front(); - } - if self.last_asset_value == 0.0 { - self.asset_returns.push_back(0.0); + pub fn calculate_rv(&mut self) -> Result<()> { + // if self.asset_prices.len() > 15 then only calcualte for the last 15 elements + if self.asset_prices.len() > 15 { + let asset_prices = self + .asset_prices + .iter() + .skip(self.asset_prices.len() - 15) + .map(|(price, _)| price.clone()) + .collect::>(); + + let asset_rv = asset_prices.compute_realized_volatility(); + self.asset_rv.push((asset_rv, self.next_update_timestamp)); } else { + let asset_prices = self + .asset_prices + .iter() + .map(|(price, _)| price.clone()) + .collect::>(); + let asset_rv = asset_prices.compute_realized_volatility(); + self.asset_rv.push((asset_rv, self.next_update_timestamp)); } - self.asset_returns.push_back(new_asset_return); - - Ok(()) - } - - pub fn append_portfolio_return(&mut self, portfolio_price: f64) -> Result<()> { - if self.portfolio_returns.len() == 15 { - self.portfolio_returns.pop_front(); - } - self.portfolio_returns.push_back(new_portfolio_return); - - Ok(()) - } - /// Detects if there is an arbitrage opportunity. - /// Returns the direction of the swap `XtoY` or `YtoX` if there is an - /// arbitrage opportunity. Returns `None` if there is no arbitrage - /// opportunity. - async fn detect_arbitrage(&mut self) -> Result { - // Update the prices the for the arbitrageur. - let liquid_exchange_price_wad = self.liquid_exchange.price().call().await?; - let g3m_price_wad = self.g3m.get_spot_price().call().await?; - - let gamma_wad = WAD - self.g3m.swap_fee().call().await?; - - // Compute the no-arbitrage bounds. - let upper_arb_bound = WAD * g3m_price_wad / gamma_wad; - let lower_arb_bound = g3m_price_wad * gamma_wad / WAD; - - // Check if we have an arbitrage opportunity by comparing against the bounds and - // current price. - // If these conditions are not satisfied, there cannot be a profitable - // arbitrage. See: [An Analysis of Uniswap Markets](https://arxiv.org/pdf/1911.03380.pdf) Eq. 3, for example. - if liquid_exchange_price_wad > upper_arb_bound && liquid_exchange_price_wad > g3m_price_wad - { - // Raise the portfolio price by selling asset for quote - Ok(Swap::RaiseExchangePrice(liquid_exchange_price_wad)) - } else if liquid_exchange_price_wad < lower_arb_bound - && liquid_exchange_price_wad < g3m_price_wad - { - // Lower the exchange price by selling asset for quote - Ok(Swap::LowerExchangePrice(liquid_exchange_price_wad)) + if self.portfolio_prices.len() > 15 { + let portfolio_prices = self + .portfolio_prices + .iter() + .skip(self.portfolio_prices.len() - 15) + .map(|(price, _)| price.clone()) + .collect::>(); + + let portfolio_rv = portfolio_prices.compute_realized_volatility(); + self.portfolio_rv + .push((portfolio_rv, self.next_update_timestamp)); } else { - // Prices are within the no-arbitrage bounds, so we don't have an arbitrage. - Ok(Swap::None) + let portfolio_prices = self + .portfolio_prices + .iter() + .map(|(price, _)| price.clone()) + .collect::>(); + let portfolio_rv = portfolio_prices.compute_realized_volatility(); + self.portfolio_rv + .push((portfolio_rv, self.next_update_timestamp)); } - } - - async fn get_x_input(&mut self, target_price_wad: U256) -> Result { - let weight_x = self.g3m.weight_x().call().await?; - let weight_y = self.g3m.weight_y().call().await?; - let reserve_y = self.g3m.reserve_y().call().await?; - let invariant = self.g3m.get_invariant().call().await?; - Ok(weight_y - * U256::from(1) - .div(target_price_wad * invariant.pow(U256::from(1).div(weight_x))) - .pow(U256::from(1) + weight_y.div(weight_x)) - - reserve_y) - } - - async fn get_y_input(&mut self, target_price_wad: U256) -> Result { - let weight_x = self.g3m.weight_x().call().await?; - let weight_y = self.g3m.weight_y().call().await?; - let reserve_x = self.g3m.reserve_x().call().await?; - let invariant = self.g3m.get_invariant().call().await?; - - Ok(weight_x - * target_price_wad - .div(invariant.pow(U256::from(1).div(weight_y))) - .pow(U256::from(1) + weight_x.div(weight_y)) - - reserve_x) + Ok(()) } } diff --git a/box-simulation/src/main.rs b/box-simulation/src/main.rs index dca75dfe8..d80a9264e 100644 --- a/box-simulation/src/main.rs +++ b/box-simulation/src/main.rs @@ -36,7 +36,7 @@ async fn main() -> Result<()> { setup::init::init(&contracts, &config).await; - let init = setup::init::init(&contracts).await?; + let init = setup::init::init(&contracts, &config).await?; Ok(()) }