Skip to content

Commit

Permalink
calculate 15 day trailing rv on portfolio and asset
Browse files Browse the repository at this point in the history
  • Loading branch information
kinrezC committed Oct 10, 2023
1 parent 415db02 commit f25c5c9
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 92 deletions.
139 changes: 48 additions & 91 deletions box-simulation/src/agents/rebalancer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use box_core::math::ComputeReturns;
use ethers::utils::format_ether;
use std::collections::VecDeque;
use std::ops::Div;

use super::*;
Expand All @@ -10,14 +9,10 @@ pub struct Rebalancer {
pub g3m: G3M<RevmMiddleware>,
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<f64>,
pub asset_prices: Vec<f64>,
pub portfolio_returns: VecDeque<f64>,
pub asset_returns: VecDeque<f64>,
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 {
Expand All @@ -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(),
})
}

Expand All @@ -68,91 +59,57 @@ impl Rebalancer {
let asset_price_float = format_ether(asset_price).parse::<f64>().unwrap();
let portfolio_price_float = format_ether(portfolio_price).parse::<f64>().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::<Vec<f64>>();

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::<Vec<f64>>();
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<Swap> {
// 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::<Vec<f64>>();

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::<Vec<f64>>();
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<U256> {
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<U256> {
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(())
}
}
2 changes: 1 addition & 1 deletion box-simulation/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}

0 comments on commit f25c5c9

Please sign in to comment.