Skip to content

Dca/swapper agent #152

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

Merged
merged 13 commits into from
Nov 14, 2023
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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ ui = { path = "./ui", version = "0.1.0" }
analysis = { path = "./analysis", version = "0.1.0" }

# External
arbiter-core = { version = "0.7.4", features = ["contracts"] }
arbiter-core = { version = "0.8.0", features = ["contracts"] }
ethers = { version = "2.0.10", features = ["ws"] }

## Config and parsing
Expand Down
207 changes: 151 additions & 56 deletions analysis/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use super::*;
use crate::{
reader::SimulationData,
visualize::{
plots::{line::LinePlot, statistical::StatisticalPlot, PlotSettings},
plots::{statistical::StatisticalPlot, PlotSettings},
Figure,
},
};
Expand Down Expand Up @@ -44,75 +44,170 @@ fn read_in_and_plot_statistical() {
#[test]
#[ignore]
fn plot_dca_weights() {
let file1 = "dca/static/1.json";
let data1 = SimulationData::new(file1).unwrap();
let weight_filter = data1.get_vectorized_events::<g3m::LogSyncingWeightFilter>("g3m");
let indices: Vec<f64> = weight_filter
.iter()
.enumerate()
.map(|(index, _)| index as f64)
.collect();
let mut weights_statistical = (vec![], vec![]);
let mut reserves_statistical = (vec![], vec![]);
let mut prices_statistical = (vec![], vec![]);
let mut portfolio_value_statistical = (vec![], vec![]);
let mut swapper_reserves_statistical = (vec![], vec![]);
let mut swapper_portfolio_value_statistical = (vec![], vec![]);

for idx in 0..10 {
// Chose the file and get the data
let file = format!("dca/static/{}.json", idx);
let data = SimulationData::new(&file).unwrap();

// Get the weights and indices for the plots
let weight_filter = data.get_vectorized_events::<g3m::LogSyncingWeightFilter>("g3m");
let indices: Vec<f64> = weight_filter
.iter()
.enumerate()
.map(|(index, _)| index as f64)
.collect();
if idx == 0 {
weights_statistical.0 = indices.clone();
}
weights_statistical.1.push(
weight_filter
.iter()
.map(|event| wad_to_float(event.weight_x))
.collect::<Vec<f64>>(),
);

// Get the reserves
let reserves = data.get_vectorized_events::<g3m::LogReservesFilter>("g3m");
if idx == 0 {
reserves_statistical.0 = indices.clone();
}
reserves_statistical.1.push(
reserves
.iter()
.map(|event| wad_to_float(event.reserve_x))
.collect::<Vec<f64>>(),
);

// Get the prices
let swap_filter = data.get_vectorized_events::<g3m::LogPricesFilter>("g3m");
if idx == 0 {
prices_statistical.0 = indices.clone();
}
prices_statistical.1.push(
swap_filter
.iter()
.map(|event| wad_to_float(event.spot_price))
.collect::<Vec<f64>>(),
);

// Get the portfolio values
let portfolio_value = reserves
.iter()
.zip(swap_filter)
.map(|(event, price_event)| {
let reserve_x = wad_to_float(event.reserve_x);
let reserve_y = wad_to_float(event.reserve_y);
let price = wad_to_float(price_event.spot_price);
reserve_x * price + reserve_y
});
if idx == 0 {
portfolio_value_statistical.0 = indices.clone();
}
portfolio_value_statistical
.1
.push(portfolio_value.collect::<Vec<f64>>());

// Get the swapper's reserves
let swapper_portfolio = data
.get_vectorized_events::<portfolio_tracker::LogPortfolioFilter>("portfolio_tracker");
if idx == 0 {
swapper_reserves_statistical.0 = indices.clone();
}
swapper_reserves_statistical.1.push(
swapper_portfolio
.iter()
.map(|event| wad_to_float(event.token_x_balance))
.collect::<Vec<f64>>(),
);

// Get the swapper's portfolio
let price_change_filter =
data.get_vectorized_events::<liquid_exchange::PriceChangeFilter>("lex");

let swapper_portfolio_value_plot = swapper_portfolio
.iter()
.zip(price_change_filter)
.map(|(event, price_change_event)| {
let x_balance = wad_to_float(event.token_x_balance);
let y_balance = wad_to_float(event.token_y_balance);
let price = wad_to_float(price_change_event.price);
// println!(
// "SWAPPER reserve_x: {}, reserve_y: {}, price: {}",
// x_balance, y_balance, price
// );
x_balance * price + y_balance
})
.collect::<Vec<f64>>();
if idx == 0 {
swapper_portfolio_value_statistical.0 = indices.clone();
}
swapper_portfolio_value_statistical
.1
.push(swapper_portfolio_value_plot);
}
// Create the figure
let mut figure = Figure::new("plot_dca_weights", Some((2000, 2000)));

// Plot the prices
let plot_settings = PlotSettings::new().title("Prices").labels("Index", "Price");
let prices_plot =
StatisticalPlot::new(prices_statistical.0, prices_statistical.1).settings(plot_settings);
figure.add_plot(prices_plot);

// Plot the weights
let plot_settings = PlotSettings::new()
.title("DCA Weights")
.title("LP DCA Weights")
.labels("Index", "Weight X");

let line_plot = LinePlot::new(
indices.clone(),
weight_filter
.iter()
.map(|event| wad_to_float(event.weight_x))
.collect(),
)
.settings(plot_settings);
let weights_plot =
StatisticalPlot::new(weights_statistical.0, weights_statistical.1).settings(plot_settings);
figure.add_plot(weights_plot);

// Plot the reserves
let plot_settings = PlotSettings::new()
.title("Reserves")
.title("LP Reserves")
.labels("Index", "Reserve X");
let reserves = data1.get_vectorized_events::<g3m::LogReservesFilter>("g3m");
let reserves_plot = LinePlot::new(
indices.clone(),
reserves
.iter()
.map(|event| wad_to_float(event.reserve_x))
.collect(),
)
.settings(plot_settings);

// Plot the prices
let plot_settings = PlotSettings::new().title("Prices").labels("Index", "Price");
let swap_filter = data1.get_vectorized_events::<g3m::SwapFilter>("g3m");
let prices_plot = LinePlot::new(
indices.clone(),
swap_filter
.iter()
.map(|event| wad_to_float(event.new_price))
.collect(),
)
.settings(plot_settings);
let reserves_plot = StatisticalPlot::new(reserves_statistical.0, reserves_statistical.1)
.settings(plot_settings);
figure.add_plot(reserves_plot);

// Plot the portfolio value
let plot_settings = PlotSettings::new()
.title("Portfolio Value")
.title("LP Portfolio Value")
.labels("Index", "Portfolio Value");
let portfolio_value = reserves
.iter()
.zip(swap_filter)
.map(|(event, price_event)| {
let reserve_x = wad_to_float(event.reserve_x);
let reserve_y = wad_to_float(event.reserve_y);
let price = wad_to_float(price_event.new_price);
reserve_x * price + reserve_y
});
let portfolio_value_plot =
LinePlot::new(indices, portfolio_value.collect()).settings(plot_settings);

let mut figure = Figure::new("plot_dca_weights", Some((1920, 1080)));
figure.add_plot(line_plot);
figure.add_plot(reserves_plot);
figure.add_plot(prices_plot);
StatisticalPlot::new(portfolio_value_statistical.0, portfolio_value_statistical.1)
.settings(plot_settings);
figure.add_plot(portfolio_value_plot);

// Plot the swapper reserves
let plot_settings = PlotSettings::new()
.title("Swapper Reserves")
.labels("Index", "Swapper Reserve X");
let swapper_reserves_plot = StatisticalPlot::new(
swapper_reserves_statistical.0,
swapper_reserves_statistical.1,
)
.settings(plot_settings);
figure.add_plot(swapper_reserves_plot);

// Plot the swapper portfolio value
let plot_settings = PlotSettings::new()
.title("Swapper Portfolio Value")
.labels("Index", "Swapper Portfolio Value");
let swapper_portfolio_value_plot = StatisticalPlot::new(
swapper_portfolio_value_statistical.0,
swapper_portfolio_value_statistical.1,
)
.settings(plot_settings);
figure.add_plot(swapper_portfolio_value_plot);

figure.create().unwrap();
}
3 changes: 2 additions & 1 deletion analysis/src/visualize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ impl Figure {
}

pub fn create(&self) -> Result<()> {
let drawing_area = BitMapBackend::new(&self.file_name, (800, 600)).into_drawing_area();
let dimensions = self.dimensions.unwrap_or((1920, 1080));
let drawing_area = BitMapBackend::new(&self.file_name, dimensions).into_drawing_area();
drawing_area.fill(&WHITE)?;

// Partition the main drawing area into subplots
Expand Down
9 changes: 7 additions & 2 deletions box-contracts/src/G3M.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import "./IStrategy.sol";
* @notice Geometric Mean Market Maker.
*/
contract G3M is IG3M, IStrategy {
event LogPrices(uint256 spotPrice, uint256 blockTimestamp);
//! ======== PROTOTYPE FUNCTIONS ======== !//
function instantiate(uint256 initial_x, uint256 initial_price) public {
// y = x * (1 - w_x) / (price * w_y)
Expand Down Expand Up @@ -411,8 +412,6 @@ contract G3M is IG3M, IStrategy {
uint256 new_price =
computeSpotPrice(reserveX, currentWeightX, reserveY, currentWeightY);
emit Swap(msg.sender, swapDirection, amountIn, amountOut, new_price);
emit LogSyncingWeight(weightX(), weightY(), block.timestamp);
emit LogReserves(reserveX, reserveY, block.timestamp);

return exactIn ? amountOut : amountIn;
}
Expand Down Expand Up @@ -471,4 +470,10 @@ contract G3M is IG3M, IStrategy {
function liquidityWithoutPrecision() public view returns (uint256) {
return convert(totalLiquidity);
}

function logData() external {
emit LogPrices(getSpotPrice(), block.timestamp);
emit LogReserves(UD60x18.unwrap(reserveX), UD60x18.unwrap(reserveY), block.timestamp);
emit LogSyncingWeight(weightX(), weightY(), block.timestamp);
}
}
1 change: 0 additions & 1 deletion box-contracts/src/IG3M.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ interface IG3M {
);

event LogSyncingWeight(UD60x18 weightX, UD60x18 weightY, uint256 blockTimestamp);
event LogReserves(UD60x18 reserveX, UD60x18 reserveY, uint256 blockTimestamp);

event LogWeights(uint256 blockTimestamp, UD60x18 weightX);

Expand Down
3 changes: 3 additions & 0 deletions box-contracts/src/IStrategy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ interface IStrategy {
function getReserveY() external view returns (uint256);
function getInvariant() external view returns (int256);
function getStrategyData() external view returns (bytes memory);
function logData() external;

event AddLiquidity(
address indexed sender,
Expand All @@ -38,4 +39,6 @@ interface IStrategy {
uint256 output,
uint256 newPrice
);

event LogReserves(uint256 reserveX, uint256 reserveY, uint256 blockTimestamp);
}
15 changes: 15 additions & 0 deletions box-contracts/src/PortfolioTracker.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
pragma solidity ^0.8.14;

interface TokenLike {
function balanceOf(address) external view returns (uint256);
}

contract PortfolioTracker {
event LogPortfolio(uint256 tokenXBalance, uint256 tokenYBalance, uint256 blockTimestamp);
event GhostEvent(bool ghosted);
function logPortfolio(address tokenX, address tokenY) external {
uint256 tokenXBalance = TokenLike(tokenX).balanceOf(msg.sender);
uint256 tokenYBalance = TokenLike(tokenY).balanceOf(msg.sender);
emit LogPortfolio(tokenXBalance, tokenYBalance, block.timestamp);
}
}
7 changes: 7 additions & 0 deletions box-contracts/src/RMM.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import "./IStrategy.sol";
import "./lib/RMMMath.sol";

contract RMM is IStrategy {
event LogParameters(uint256 sigma, uint256 strikePrice, uint256 tau, uint256 blockTimestamp);

ERC20 public tokenX;
ERC20 public tokenY;

Expand Down Expand Up @@ -316,4 +318,9 @@ contract RMM is IStrategy {
}

function getStrategyData() external view returns (bytes memory data) { }

function logData() external {
emit LogReserves(reserveX, reserveY, block.timestamp);
emit LogParameters(sigma, strikePrice, tau, block.timestamp);
}
}
20 changes: 14 additions & 6 deletions configs/dca/static.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ decimals = 18
# The seed to use (optional)
seed = 1
# The number of steps in the process
num_steps = 36500
num_steps = 1000
# The number of distinct paths to use
num_paths = 5
num_paths = 10
# The initial price of the asset
initial_price.fixed = 1.0
# The start time of the process
t_0.fixed = 0.0
# The end time of the process
t_n.fixed = 1.0
t_n.fixed = 0.1
## Parameters for the type of process to use.
# The drift for GBM
process.GBM.drift.fixed = 0.1
Expand All @@ -45,11 +45,19 @@ fee.fixed = 30
# The final weight to reach
specialty.DollarCostAveraging.end_weight = 0.99
# The amount of time to reach the final weight (in seconds)
specialty.DollarCostAveraging.end_timestamp = 547485 # One before very end
specialty.DollarCostAveraging.end_timestamp = 14985 # One before very end

# Liquidity provider settings
[agent.lp.LiquidityProvider]
# The amount of `token_x` to provide in ether
x_liquidity.fixed = 1
x_liquidity.fixed = 0.01 # SINCE WE ARE SETTINGS THE WEIGHT TO 0.01 AT THE START THIS WILL BE 1 ETH TOTAL LIQUIDITY
# The initial price of the pair
initial_price.fixed = 1.0
initial_price.fixed = 1.0

# Swapper settings
[agent.swapper.Swapper]
num_swaps.fixed = 12
start_timestamp = 15
end_timestamp = 15000
initial_balance = 1.0
swap_direction = false
3 changes: 2 additions & 1 deletion simulation/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ config.workspace = true
unit-conversions = "0.1.13"
itertools = "0.11.0"
rand = "0.8.5"
RustQuant = { version = "0.0.37", features = ["seedable"] }
linked-hash-map = "0.5.6"
RustQuant = { version = "0.0.37", features = ["seedable"] }
Loading