working version, before optimalization
This commit is contained in:
107
tools/analyze_pool_data.py
Normal file
107
tools/analyze_pool_data.py
Normal file
@ -0,0 +1,107 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user