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}")