108 lines
3.7 KiB
Python
108 lines
3.7 KiB
Python
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()
|