135 lines
5.5 KiB
Python
135 lines
5.5 KiB
Python
import os
|
|
import csv
|
|
import time
|
|
import logging
|
|
from decimal import Decimal
|
|
from typing import Dict, Optional
|
|
|
|
# Setup Logger
|
|
logger = logging.getLogger("KPI_TRACKER")
|
|
logger.setLevel(logging.INFO)
|
|
# Basic handler if not already handled by parent
|
|
if not logger.handlers:
|
|
ch = logging.StreamHandler()
|
|
formatter = logging.Formatter('%(asctime)s - KPI - %(message)s')
|
|
ch.setFormatter(formatter)
|
|
logger.addHandler(ch)
|
|
|
|
KPI_FILE = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'logs', 'kpi_history.csv')
|
|
|
|
def initialize_kpi_csv():
|
|
"""Creates the CSV with headers if it doesn't exist."""
|
|
if not os.path.exists(os.path.dirname(KPI_FILE)):
|
|
os.makedirs(os.path.dirname(KPI_FILE))
|
|
|
|
if not os.path.exists(KPI_FILE):
|
|
with open(KPI_FILE, 'w', newline='') as f:
|
|
writer = csv.writer(f)
|
|
writer.writerow([
|
|
"Timestamp",
|
|
"Date",
|
|
"NAV_Total_USD",
|
|
"Benchmark_HODL_USD",
|
|
"Alpha_USD",
|
|
"Uniswap_Val_USD",
|
|
"Uniswap_Fees_Claimed_USD",
|
|
"Uniswap_Fees_Unclaimed_USD",
|
|
"Hedge_Equity_USD",
|
|
"Hedge_PnL_Realized_USD",
|
|
"Hedge_Fees_Paid_USD",
|
|
"ETH_Price",
|
|
"Fee_Coverage_Ratio"
|
|
])
|
|
|
|
def calculate_hodl_benchmark(initial_eth: Decimal, initial_usdc: Decimal, initial_hedge_usdc: Decimal, current_eth_price: Decimal) -> Decimal:
|
|
"""Calculates value if assets were just held (Wallet Assets + Hedge Account Cash)."""
|
|
return (initial_eth * current_eth_price) + initial_usdc + initial_hedge_usdc
|
|
|
|
def log_kpi_snapshot(
|
|
snapshot_data: Dict[str, float]
|
|
):
|
|
"""
|
|
Logs a KPI snapshot to CSV.
|
|
Expected keys in snapshot_data:
|
|
- initial_eth, initial_usdc, initial_hedge_usdc
|
|
- current_eth_price
|
|
- uniswap_pos_value_usd
|
|
- uniswap_fees_claimed_usd
|
|
- uniswap_fees_unclaimed_usd
|
|
- hedge_equity_usd
|
|
- hedge_pnl_realized_usd
|
|
- hedge_fees_paid_usd
|
|
- wallet_eth_bal, wallet_usdc_bal (Optional, for full NAV)
|
|
"""
|
|
try:
|
|
initialize_kpi_csv()
|
|
|
|
# Convert all inputs to Decimal for precision
|
|
price = Decimal(str(snapshot_data.get('current_eth_price', 0)))
|
|
|
|
# 1. Benchmark (HODL)
|
|
init_eth = Decimal(str(snapshot_data.get('initial_eth', 0)))
|
|
init_usdc = Decimal(str(snapshot_data.get('initial_usdc', 0)))
|
|
init_hedge = Decimal(str(snapshot_data.get('initial_hedge_usdc', 0)))
|
|
benchmark_val = calculate_hodl_benchmark(init_eth, init_usdc, init_hedge, price)
|
|
|
|
# 2. Strategy NAV (Net Asset Value)
|
|
# NAV = Uni Pos + Uni Fees (Claimed+Unclaimed) + Hedge Equity + (Wallet Surplus - Initial Wallet Surplus?)
|
|
# For simplicity, we focus on the Strategy PnL components:
|
|
# Strategy Val = (Current Uni Pos) + (Claimed Fees) + (Unclaimed Fees) + (Hedge PnL Realized) + (Hedge Unrealized?)
|
|
# Note: Hedge Equity usually includes margin. We strictly want "Value Generated".
|
|
|
|
uni_val = Decimal(str(snapshot_data.get('uniswap_pos_value_usd', 0)))
|
|
uni_fees_claimed = Decimal(str(snapshot_data.get('uniswap_fees_claimed_usd', 0)))
|
|
uni_fees_unclaimed = Decimal(str(snapshot_data.get('uniswap_fees_unclaimed_usd', 0)))
|
|
|
|
# Hedge PnL (Realized + Unrealized) is better than Equity for PnL tracking,
|
|
# but Equity represents actual redeemable cash. Let's use Equity if provided, or PnL components.
|
|
hedge_equity = Decimal(str(snapshot_data.get('hedge_equity_usd', 0)))
|
|
hedge_fees = Decimal(str(snapshot_data.get('hedge_fees_paid_usd', 0)))
|
|
|
|
# Simplified NAV for Strategy Comparison:
|
|
# We assume 'hedge_equity' is the Liquidation Value of the hedge account.
|
|
# But if we want strictly "Strategy Performance", we usually do:
|
|
# Current Value = Uni_Val + Unclaimed + Hedge_Equity
|
|
# (Assuming Hedge_Equity started at 0 or we track delta? No, usually Hedge Account has deposit).
|
|
|
|
# Let's define NAV as Total Current Liquidation Value of Strategy Components
|
|
current_nav = uni_val + uni_fees_unclaimed + uni_fees_claimed + hedge_equity
|
|
|
|
# Alpha
|
|
alpha = current_nav - benchmark_val
|
|
|
|
# Coverage Ratio
|
|
total_hedge_cost = abs(hedge_fees) # + funding if available
|
|
total_uni_earnings = uni_fees_claimed + uni_fees_unclaimed
|
|
|
|
if total_hedge_cost > 0:
|
|
coverage_ratio = total_uni_earnings / total_hedge_cost
|
|
else:
|
|
coverage_ratio = Decimal("999.0") # Infinite/Good
|
|
|
|
# Write
|
|
with open(KPI_FILE, 'a', newline='') as f:
|
|
writer = csv.writer(f)
|
|
writer.writerow([
|
|
int(time.time()),
|
|
time.strftime('%Y-%m-%d %H:%M:%S'),
|
|
f"{current_nav:.2f}",
|
|
f"{benchmark_val:.2f}",
|
|
f"{alpha:.2f}",
|
|
f"{uni_val:.2f}",
|
|
f"{uni_fees_claimed:.2f}",
|
|
f"{uni_fees_unclaimed:.2f}",
|
|
f"{hedge_equity:.2f}",
|
|
f"{snapshot_data.get('hedge_pnl_realized_usd', 0):.2f}",
|
|
f"{hedge_fees:.2f}",
|
|
f"{price:.2f}",
|
|
f"{coverage_ratio:.2f}"
|
|
])
|
|
|
|
logger.info(f"📊 KPI Logged | NAV: ${current_nav:.2f} | Benchmark: ${benchmark_val:.2f} | Alpha: ${alpha:.2f}")
|
|
|
|
except Exception as e:
|
|
logger.error(f"Failed to log KPI: {e}")
|