A Python-based simulator for analyzing LP profitability with rehypothecation when Trevee provides one-sided liquidity (plUSD only) in a constant-product AMM, with all trade flow being plUSD → USDT0.
NEW: Interactive web dashboard available!
# Install web dependencies
pip install -r requirements-web.txt
# Launch web interface
streamlit run app.pyAccess at http://localhost:8501
Deploy to cloud: See DEPLOYMENT.md for Streamlit Cloud, Railway, or Render deployment.
This simulator models the economics of:
- One-sided LP provision (plUSD deposit, USDT0 borrowed)
- Directional trade flow (all swaps are plUSD → USDT0)
- Multiple yield sources: underlying yield, rehypothecation yield
- Borrowing costs for USDT0
- Operational costs
- Impermanent loss tracking
- Liquidation risk monitoring
- AMM Type: Constant-product (x · y = k)
- Fee Model: Configurable basis points per trade (default: 7 bps)
- Reserves: Two-asset pool (plUSD, USDT0)
- Initial Setup: Trevee deposits plUSD only
- USDT0 Provision: Borrowed to balance pool liquidity
- Rehypothecation: Fraction of plUSD (default 60%) is rehypothecated for additional yield
- Trade Flow: All trades are plUSD → USDT0, gradually reducing borrowed position
| Component | Formula | Description |
|---|---|---|
| Fees | Σ(volume × fee_bps) | Trading fees earned proportional to LP share |
| Underlying Yield | plUSD_balance × underlying_yield_apr | Base yield on plUSD holdings |
| Rehyp Yield | rehyp_fraction × plUSD_balance × rehyp_yield_apr | Additional yield from rehypothecated assets |
| Borrow Cost | borrowed_USDT0 × borrow_cost_apr | Interest on borrowed USDT0 |
| IL | vs holding plUSD | Impermanent loss from AMM rebalancing |
| Ops Cost | ops_cost_usd_per_day × t | Fixed operational expenses |
| Net P&L | fees + yields - borrow_cost - IL - ops_cost | Total profitability |
Each time step executes:
- Generate trade flow (deterministic or stochastic)
- Execute swap (plUSD → USDT0)
- Calculate and accrue LP fees
- Accrue yields (underlying + rehyp)
- Accrue borrow costs
- Update LP position (USDT0 received reduces debt)
- Calculate NAV and P&L
- Check liquidation risk (LTV ratio)
# Clone repository
git clone <repo-url>
cd eulerswap-simulator
# Install dependencies
pip install -r requirements.txtnumpy>=1.24.0
matplotlib>=3.7.0
pyyaml>=6.0
pytest>=7.3.0
python -m sim.run --config sim/config.yamlpython -m sim.run --config sim/config.yaml --plot# Export to CSV
python -m sim.run --config sim/config.yaml --output results.csv
# Export to JSON
python -m sim.run --config sim/config.yaml --output results.jsonEdit sim/config.yaml:
horizon_days: 180 # Simulation duration
steps_per_day: 24 # Time granularity
amm:
fee_bps: 7 # 0.07% trading fee
initial_state:
plusd_reserve: 5_000_000
usdt0_reserve: 5_000_000
trevee_deposit_plusd: 1_000_000
rehyp_fraction: 0.6 # 60% rehypothecated
yields:
underlying_yield_apr: 0.06 # 6% base yield
rehyp_yield_apr: 0.12 # 12% rehyp yield
borrow_cost_apr: 0.08 # 8% borrow cost
flow:
model: "deterministic"
deterministic_schedule_bps_of_pool: 20 # 0.2% daily flowhorizon_days: Total simulation durationsteps_per_day: Number of steps per day (higher = more granular)seed: Random seed for reproducibility
amm.type: AMM curve type (currently "constant_product")amm.fee_bps: Trading fee in basis points
plusd_reserve: Initial plUSD in poolusdt0_reserve: Initial USDT0 in pooltrevee_deposit_plusd: Trevee's plUSD depositrehyp_fraction: Fraction of plUSD to rehypothecate (0.0 to 1.0)
underlying_yield_apr: Annual yield on plUSD (decimal, e.g., 0.06 = 6%)rehyp_yield_apr: Annual yield on rehypothecated plUSDborrow_cost_apr: Annual interest on borrowed USDT0ops_cost_usd_per_day: Daily operational costs
flow.model: "deterministic" or "stochastic"deterministic_schedule_bps_of_pool: Daily flow as % of pool (deterministic)stochastic.mu_daily: Mean daily drift (stochastic)stochastic.sigma_daily: Daily volatility (stochastic)
max_borrow_multiple: Maximum LTV ratio before liquidationpeg_deviation_std_bps: Standard deviation of price noise (optional)
mark_to_market_price_plusd: MTM price for plUSD (default: 1.0)mark_to_market_price_usdt0: MTM price for USDT0 (default: 1.0)
============================================================
SIMULATION SUMMARY
============================================================
Time Horizon: 180 days
Initial Capital: $1,000,000.00
Final NAV: $1,089,456.23
------------------------------------------------------------
P&L BREAKDOWN
------------------------------------------------------------
Total Fees Earned: $42,350.12
Total Yields: $124,678.90
Total Borrow Cost: -$98,234.56
Total Ops Cost: -$27,000.00
Impermanent Loss: -2.34%
------------------------------------------------------------
Net P&L: $89,456.23
------------------------------------------------------------
RETURNS
------------------------------------------------------------
Total Return: 8.95%
Annualized Return: 18.23%
Max Drawdown: 3.45%
------------------------------------------------------------
RISK METRICS
------------------------------------------------------------
Final Borrowed USDT0: $3,456,789.01
Final LTV: 34.57%
Generated plots include:
- LP NAV Over Time: Shows equity growth/drawdown
- P&L Component Breakdown: Stacked area chart of all P&L sources
- Borrowed USDT0: Debt position over time
- LTV Ratio: Liquidation risk monitoring
- P&L Components (Cumulative): Individual component tracking
- Impermanent Loss: IL percentage over time
Exported data includes per-step metrics:
- Time and step number
- Reserve balances
- LP position (plUSD, USDT0)
- Borrowed amounts
- Trade flow and output
- Fee and yield accruals
- NAV and P&L
- Risk metrics (LTV)
# Run all tests
pytest tests/ -v
# Run specific test file
pytest tests/test_models.py -v
# Run with coverage
pytest tests/ --cov=sim --cov-report=htmlTests verify:
- ✓ AMM swap mechanics (constant product, fees)
- ✓ Continuous compounding accruals
- ✓ Impermanent loss calculations
- ✓ Liquidation risk assessment
- ✓ Zero-fee/zero-flow scenarios (yields only)
- ✓ Fee impact on profitability
- ✓ Borrow cost effects
- Implement new swap function in
sim/models.py:
def swap_stableswap(x_reserve, y_reserve, x_in, fee_bps, A):
"""StableSwap invariant: A * sum(x_i) + product(x_i) = constant"""
# Implementation here
pass- Update
execute_swap()insim/core.py:
if self.params.amm_type == "stableswap":
usdt0_out, new_plusd, new_usdt0 = swap_stableswap(...)- Add
Aparameter to config:
amm:
type: "stableswap"
fee_bps: 4
amplification: 100- Extend
generate_trade_flow()insim/core.py:
elif self.params.flow_model == "seasonal":
# Implement seasonal patterns
day_of_year = (step / self.params.steps_per_day) % 365
seasonal_factor = 1 + 0.3 * math.sin(2 * math.pi * day_of_year / 365)
return base_flow * seasonal_factor- Add parameters to
SimulationParams:
@dataclass
class SimulationParams:
# ...
seasonal_amplitude: float = 0.3
seasonal_period_days: int = 365Add new metrics to StepResult dataclass in sim/core.py:
@dataclass
class StepResult:
# Existing fields...
sharpe_ratio: float = 0.0
volatility: float = 0.0Then calculate in step_simulation():
result = StepResult(
# ...
sharpe_ratio=self._calculate_sharpe(),
volatility=self._calculate_volatility()
)- Constant prices: Assumes plUSD and USDT0 maintain 1:1 peg
- No cross-asset volatility: Doesn't model depegging scenarios
- Unidirectional flow: All trades are plUSD → USDT0
- No liquidity depth: Price impact calculated but no order book
- No external arbitrage: LP is the only liquidity provider
- Continuous time: Uses discrete time steps with continuous compounding approximation
- High trade volume: Can drain USDT0 reserve, causing slippage
- Liquidation: Simulator doesn't force-close positions at max LTV
- Negative IL: Can occur when receiving more assets than HODL
- Rehyp fraction > 1: Not validated, would be over-leveraged
Determine if LP strategy is viable given:
- Expected trade volume
- Yield rates
- Borrowing costs
Find optimal:
- Fee tier (3, 7, 30 bps)
- Rehypothecation fraction
- Initial capital allocation
Evaluate:
- Maximum drawdown scenarios
- Liquidation risk under stress
- Sensitivity to borrow cost changes
Model different market conditions:
- High/low trading volume
- Rate environment changes
- Operational cost variations
initial_state:
trevee_deposit_plusd: 500_000
rehyp_fraction: 0.3 # Low rehyp
yields:
borrow_cost_apr: 0.06 # Low borrow cost
flow:
deterministic_schedule_bps_of_pool: 10 # Moderate flowinitial_state:
trevee_deposit_plusd: 2_000_000
rehyp_fraction: 0.8 # High rehyp
yields:
rehyp_yield_apr: 0.18 # High rehyp yield
borrow_cost_apr: 0.10 # Higher borrow cost
flow:
deterministic_schedule_bps_of_pool: 30 # High flowCause: Borrow costs exceed fee + yield income
Solution: Reduce borrow_cost_apr or increase fee_bps
Cause: LTV ratio exceeds max_borrow_multiple
Solution: Increase initial usdt0_reserve or reduce trade flow
Cause: Insufficient trade volume or low LP share
Solution: Increase deterministic_schedule_bps or trevee_deposit_plusd
Cause: Large reserve imbalances from one-sided flow Solution: Expected behavior - monitor that fees + yields exceed IL
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure
pytest -qpasses - Submit a pull request
MIT License - see LICENSE file for details
- Uniswap V2 Whitepaper - Constant product AMM
- Impermanent Loss Calculator
- Continuous Compounding
For questions or support, please open an issue on GitHub.
Built for Trevee Earn | Version 0.1.0