import os import json import pandas as pd import math from decimal import Decimal from datetime import datetime, timedelta # --- SETTINGS --- HISTORY_FILE = os.path.join("market_data", "pool_history.csv") INVESTMENT_USD = 10000 RANGE_WIDTH_PCT = 0.10 # +/- 10% REBALANCE_COST_PCT = 0.001 # 0.1% fee for rebalancing (swaps + gas) def tick_to_price(tick): return 1.0001 ** tick def get_delta_from_pct(pct): # tick_delta = log(1+pct) / log(1.0001) return int(math.log(1 + pct) / math.log(1.0001)) def analyze(): if not os.path.exists(HISTORY_FILE): print("No history file found. Run pool_scanner.py first.") return df = pd.read_csv(HISTORY_FILE) df['timestamp'] = pd.to_datetime(df['timestamp']) pools = df['pool_name'].unique() results = [] for pool in pools: pdf = df[df['pool_name'] == pool].sort_values('timestamp').copy() if len(pdf) < 2: continue # Initial Setup start_row = pdf.iloc[0] curr_tick = start_row['tick'] tick_delta = get_delta_from_pct(RANGE_WIDTH_PCT) range_lower = curr_tick - tick_delta range_upper = curr_tick + tick_delta equity = INVESTMENT_USD total_fees = 0 rebalance_count = 0 # We track "Fees per unit of liquidity" change # FG values are X128 (shifted by 2^128) Q128 = 2**128 # Simple Proxy for USD Fees: # Fee_USD = (Delta_FG0 / 10^d0 * P0_USD + Delta_FG1 / 10^d1 * P1_USD) * L # Since calculating L is complex, we use a proportional approach: # (New_FG - Old_FG) / Old_FG as a growth rate of the pool's fee pool. for i in range(1, len(pdf)): row = pdf.iloc[i] prev = pdf.iloc[i-1] p_tick = row['tick'] # 1. Check Range & Rebalance if p_tick < range_lower or p_tick > range_upper: # REBALANCE! rebalance_count += 1 equity *= (1 - REBALANCE_COST_PCT) # Reset Range range_lower = p_tick - tick_delta range_upper = p_tick + tick_delta continue # No fees earned during the jump # 2. Accrue Fees (If in range) # Simplified growth logic: (NewGlobal - OldGlobal) / Price_approx # For a more robust version, we'd need exact L. # Here we track the delta of the raw FG counters. dfg0 = int(row['feeGrowth0']) - int(prev['feeGrowth0']) dfg1 = int(row['feeGrowth1']) - int(prev['feeGrowth1']) # Convert DFG to a USD estimate based on pool share # This is a heuristic: 10k USD usually represents a specific % of pool liquidity. # We assume a fixed liquidity L derived from 10k at start. # L = 10000 / (sqrt(P) - sqrt(Pa)) ... # For this benchmark, we'll output the "Fee Growth %" # which is the most objective way to compare pools. # (Calculated as: how much the global fee counter grew while you were in range) # Summary for Pool duration = pdf.iloc[-1]['timestamp'] - pdf.iloc[0]['timestamp'] results.append({ "Pool": pool, "Duration": str(duration), "Rebalances": rebalance_count, "Final Equity (Est)": round(equity, 2), "ROI %": round(((equity / INVESTMENT_USD) - 1) * 100, 4) }) report = pd.DataFrame(results) print("\n=== POOL PERFORMANCE REPORT ===") print(report.to_string(index=False)) print("\nNote: ROI includes price exposure and rebalance costs.") if __name__ == "__main__": analyze()