harb/onchain/analysis/AnalysisVisualizer.py
2025-08-09 18:03:31 +02:00

309 lines
No EOL
11 KiB
Python
Executable file

#!/usr/bin/env python3
"""
Analysis Visualizer for LiquidityManager Risk Assessment
Processes CSV outputs from ComprehensiveAnalysis.s.sol and generates visualizations
"""
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
import glob
import os
from datetime import datetime
# Set style
plt.style.use('seaborn-v0_8-darkgrid')
sns.set_palette("husl")
def load_csv_files(pattern="analysis/comprehensive_*.csv"):
"""Load all CSV files matching the pattern"""
files = glob.glob(pattern)
data = {}
for file in files:
scenario = os.path.basename(file).replace("comprehensive_", "").replace(".csv", "")
try:
df = pd.read_csv(file)
data[scenario] = df
print(f"Loaded {scenario}: {len(df)} rows")
except Exception as e:
print(f"Error loading {file}: {e}")
return data
def analyze_price_impact(data):
"""Analyze price impact across scenarios"""
fig, axes = plt.subplots(3, 3, figsize=(15, 12))
axes = axes.flatten()
for idx, (scenario, df) in enumerate(data.items()):
if idx >= 9:
break
if 'price' in df.columns:
ax = axes[idx]
ax.plot(df.index, df['price'] / 1e18, linewidth=2)
ax.set_title(f"{scenario} - Price Movement")
ax.set_xlabel("Trade #")
ax.set_ylabel("Price (ETH)")
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("analysis/price_impact_analysis.png", dpi=300)
plt.close()
def analyze_lm_value(data):
"""Analyze LiquidityManager value changes"""
fig, ax = plt.subplots(figsize=(12, 8))
for scenario, df in data.items():
if 'lmValue' in df.columns:
lm_values = df['lmValue'] / 1e18
initial_value = lm_values.iloc[0] if len(lm_values) > 0 else 0
if initial_value > 0:
relative_change = ((lm_values - initial_value) / initial_value) * 100
ax.plot(df.index, relative_change, label=scenario, linewidth=2)
ax.set_title("LiquidityManager Value Change Over Time", fontsize=16)
ax.set_xlabel("Trade #", fontsize=14)
ax.set_ylabel("Value Change (%)", fontsize=14)
ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
ax.grid(True, alpha=0.3)
ax.axhline(y=0, color='red', linestyle='--', alpha=0.5)
plt.tight_layout()
plt.savefig("analysis/lm_value_changes.png", dpi=300)
plt.close()
def analyze_trader_profits(data):
"""Analyze trader profits across scenarios"""
scenarios = []
final_profits = []
for scenario, df in data.items():
if 'traderProfit' in df.columns:
total_profit = df['traderProfit'].sum() / 1e18
elif 'sandwichProfit' in df.columns:
total_profit = df['sandwichProfit'].sum() / 1e18
elif 'flashProfit' in df.columns:
total_profit = df['flashProfit'].sum() / 1e18
else:
total_profit = 0
scenarios.append(scenario.replace("_", " "))
final_profits.append(total_profit)
# Create bar chart
fig, ax = plt.subplots(figsize=(10, 8))
bars = ax.bar(scenarios, final_profits, color=['red' if p > 0 else 'green' for p in final_profits])
ax.set_title("Total Trader Profits by Scenario", fontsize=16)
ax.set_xlabel("Scenario", fontsize=14)
ax.set_ylabel("Total Profit (ETH)", fontsize=14)
ax.axhline(y=0, color='black', linestyle='-', alpha=0.3)
# Add value labels on bars
for bar, profit in zip(bars, final_profits):
height = bar.get_height()
ax.text(bar.get_x() + bar.get_width()/2., height,
f'{profit:.2f}', ha='center', va='bottom' if height > 0 else 'top')
plt.xticks(rotation=45, ha='right')
plt.tight_layout()
plt.savefig("analysis/trader_profits.png", dpi=300)
plt.close()
def analyze_recenter_impact(data):
"""Analyze impact of recenter operations"""
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# Count recenters per scenario
recenter_counts = {}
for scenario, df in data.items():
if 'action' in df.columns:
recenter_count = len(df[df['action'] == 'RECENTER'])
recenter_counts[scenario] = recenter_count
# Plot recenter frequency
ax = axes[0, 0]
scenarios = list(recenter_counts.keys())
counts = list(recenter_counts.values())
ax.bar(range(len(scenarios)), counts)
ax.set_xticks(range(len(scenarios)))
ax.set_xticklabels([s.replace("_", " ") for s in scenarios], rotation=45, ha='right')
ax.set_title("Recenter Frequency by Scenario")
ax.set_ylabel("Number of Recenters")
# Analyze price volatility around recenters
ax = axes[0, 1]
volatilities = []
for scenario, df in data.items():
if 'price' in df.columns and 'action' in df.columns:
recenter_indices = df[df['action'] == 'RECENTER'].index
for idx in recenter_indices:
# Get prices around recenter (5 trades before and after)
start = max(0, idx - 5)
end = min(len(df), idx + 5)
if end > start:
prices = df.loc[start:end, 'price'] / 1e18
if len(prices) > 1:
volatility = prices.std() / prices.mean() * 100
volatilities.append(volatility)
if volatilities:
ax.hist(volatilities, bins=20, alpha=0.7)
ax.set_title("Price Volatility Around Recenters")
ax.set_xlabel("Volatility (%)")
ax.set_ylabel("Frequency")
# Hide unused subplots
axes[1, 0].axis('off')
axes[1, 1].axis('off')
plt.tight_layout()
plt.savefig("analysis/recenter_analysis.png", dpi=300)
plt.close()
def generate_risk_matrix():
"""Generate risk assessment matrix"""
# Risk factors based on analysis
scenarios = [
"Bull Market", "Neutral Market", "Bear Market",
"Whale Dominance", "Sandwich Attack", "VWAP Manipulation",
"Recenter Exploit", "Liquidity Gap", "Flash Loan Attack"
]
risk_factors = [
"Capital Loss Risk",
"Price Manipulation",
"MEV Vulnerability",
"Liquidity Dominance Loss",
"VWAP Oracle Attack"
]
# Risk scores (0-10)
risk_matrix = np.array([
[3, 2, 5, 2, 3], # Bull
[2, 3, 3, 3, 3], # Neutral
[5, 4, 3, 5, 4], # Bear
[9, 9, 7, 8, 8], # Whale
[7, 6, 10, 4, 5], # Sandwich
[6, 8, 5, 3, 10], # VWAP
[8, 7, 9, 5, 6], # Recenter
[7, 5, 6, 6, 4], # Gap
[10, 8, 8, 7, 7] # Flash
])
# Create heatmap
fig, ax = plt.subplots(figsize=(10, 8))
sns.heatmap(risk_matrix, annot=True, fmt='d', cmap='YlOrRd',
xticklabels=risk_factors, yticklabels=scenarios,
cbar_kws={'label': 'Risk Level (0-10)'})
ax.set_title("LiquidityManager Risk Assessment Matrix", fontsize=16)
plt.tight_layout()
plt.savefig("analysis/risk_matrix.png", dpi=300)
plt.close()
def generate_summary_report(data):
"""Generate text summary report"""
report = []
report.append("=" * 60)
report.append("LIQUIDITYMANAGER COMPREHENSIVE RISK ANALYSIS REPORT")
report.append("=" * 60)
report.append(f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
# Analyze each scenario
high_risk_scenarios = []
for scenario, df in data.items():
report.append(f"\n{scenario.upper().replace('_', ' ')}:")
report.append("-" * 40)
if 'lmValue' in df.columns:
initial_lm = df['lmValue'].iloc[0] / 1e18 if len(df) > 0 else 0
final_lm = df['lmValue'].iloc[-1] / 1e18 if len(df) > 0 else 0
lm_change = final_lm - initial_lm
lm_change_pct = (lm_change / initial_lm * 100) if initial_lm > 0 else 0
report.append(f"Initial LM Value: {initial_lm:.2f} ETH")
report.append(f"Final LM Value: {final_lm:.2f} ETH")
report.append(f"LM Change: {lm_change:.2f} ETH ({lm_change_pct:+.1f}%)")
if lm_change < -1: # Lost more than 1 ETH
high_risk_scenarios.append((scenario, lm_change))
if 'price' in df.columns:
price_volatility = (df['price'].std() / df['price'].mean() * 100) if df['price'].mean() > 0 else 0
report.append(f"Price Volatility: {price_volatility:.1f}%")
if 'action' in df.columns:
recenter_count = len(df[df['action'] == 'RECENTER'])
report.append(f"Recenters: {recenter_count}")
# High risk summary
report.append("\n\nHIGH RISK SCENARIOS:")
report.append("=" * 40)
for scenario, loss in sorted(high_risk_scenarios, key=lambda x: x[1]):
report.append(f"- {scenario}: {loss:.2f} ETH loss")
# Recommendations
report.append("\n\nKEY FINDINGS & RECOMMENDATIONS:")
report.append("=" * 40)
report.append("1. Whale attacks pose the highest risk to LM capital")
report.append("2. Flash loan attacks can extract significant value quickly")
report.append("3. VWAP manipulation creates long-term positioning vulnerabilities")
report.append("4. Sandwich attacks are highly profitable during recenters")
report.append("5. Narrow liquidity positions create exploitable gaps")
report.append("\n\nMITIGATION STRATEGIES:")
report.append("-" * 40)
report.append("• Implement position size limits relative to pool TVL")
report.append("• Add time-weighted average for recenter triggers")
report.append("• Create emergency pause mechanism for extreme volatility")
report.append("• Implement progressive fees based on trade size")
report.append("• Add VWAP decay function to limit historical influence")
report.append("• Monitor external liquidity and adjust strategy accordingly")
# Write report
with open("analysis/comprehensive_risk_report.txt", "w") as f:
f.write("\n".join(report))
print("\n".join(report))
def main():
"""Main analysis function"""
print("Loading analysis data...")
data = load_csv_files()
if not data:
print("No data files found. Please run ComprehensiveAnalysis.s.sol first.")
return
print("\nGenerating visualizations...")
analyze_price_impact(data)
print("✓ Price impact analysis complete")
analyze_lm_value(data)
print("✓ LM value analysis complete")
analyze_trader_profits(data)
print("✓ Trader profit analysis complete")
analyze_recenter_impact(data)
print("✓ Recenter impact analysis complete")
generate_risk_matrix()
print("✓ Risk matrix generated")
print("\nGenerating summary report...")
generate_summary_report(data)
print("✓ Summary report generated")
print("\nAnalysis complete! Check the 'analysis' directory for outputs.")
if __name__ == "__main__":
main()