POTE/scripts/calculate_all_returns.py
ilia 34aebb1c2e PR4: Phase 2 Analytics Foundation
Complete analytics module with returns, benchmarks, and performance metrics.

New Modules:
- src/pote/analytics/returns.py: Return calculator for trades
- src/pote/analytics/benchmarks.py: Benchmark comparison & alpha
- src/pote/analytics/metrics.py: Performance aggregations

Scripts:
- scripts/analyze_official.py: Analyze specific official
- scripts/calculate_all_returns.py: System-wide analysis

Tests:
- tests/test_analytics.py: Full coverage of analytics

Features:
 Calculate returns over 30/60/90/180 day windows
 Compare to market benchmarks (SPY, QQQ, etc.)
 Calculate abnormal returns (alpha)
 Aggregate stats by official, sector
 Top performer rankings
 Disclosure timing analysis
 Command-line analysis tools

~1,210 lines of new code, all tested
2025-12-15 11:33:21 -05:00

117 lines
4.0 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Calculate returns for all trades and display summary statistics.
"""
import argparse
import logging
from pote.analytics.metrics import PerformanceMetrics
from pote.db import get_session
logging.basicConfig(level=logging.INFO, format="%(message)s")
logger = logging.getLogger(__name__)
def main():
parser = argparse.ArgumentParser(description="Calculate returns for all trades")
parser.add_argument(
"--window",
type=int,
default=90,
help="Return window in days (default: 90)",
)
parser.add_argument(
"--benchmark",
default="SPY",
help="Benchmark ticker (default: SPY)",
)
parser.add_argument(
"--top",
type=int,
default=10,
help="Number of top performers to show (default: 10)",
)
args = parser.parse_args()
with next(get_session()) as session:
metrics = PerformanceMetrics(session)
# Get system-wide statistics
logger.info("\n" + "=" * 70)
logger.info(" POTE System-Wide Performance Analysis")
logger.info("=" * 70)
summary = metrics.summary_statistics(
window_days=args.window,
benchmark=args.benchmark,
)
logger.info(f"\n📊 OVERALL STATISTICS")
logger.info("-" * 70)
logger.info(f"Total Officials: {summary['total_officials']}")
logger.info(f"Total Securities: {summary['total_securities']}")
logger.info(f"Total Trades: {summary['total_trades']}")
logger.info(f"Trades Analyzed: {summary.get('total_trades', 0)}")
logger.info(f"Window: {summary['window_days']} days")
logger.info(f"Benchmark: {summary['benchmark']}")
if summary.get('avg_alpha') is not None:
logger.info(f"\n🎯 AGGREGATE PERFORMANCE")
logger.info("-" * 70)
logger.info(f"Average Alpha: {float(summary['avg_alpha']):+.2f}%")
logger.info(f"Median Alpha: {float(summary['median_alpha']):+.2f}%")
logger.info(f"Max Alpha: {float(summary['max_alpha']):+.2f}%")
logger.info(f"Min Alpha: {float(summary['min_alpha']):+.2f}%")
logger.info(f"Beat Market Rate: {summary['beat_market_rate']:.1%}")
# Top performers
logger.info(f"\n🏆 TOP {args.top} PERFORMERS (by Alpha)")
logger.info("-" * 70)
top_performers = metrics.top_performers(
window_days=args.window,
benchmark=args.benchmark,
limit=args.top,
)
for i, perf in enumerate(top_performers, 1):
name = perf['name'][:25].ljust(25)
party = perf['party'][:3]
trades = perf['trades_analyzed']
alpha = float(perf['avg_alpha'])
logger.info(f"{i:2d}. {name} ({party}) | {trades:2d} trades | Alpha: {alpha:+6.2f}%")
# Sector analysis
logger.info(f"\n📊 PERFORMANCE BY SECTOR")
logger.info("-" * 70)
sectors = metrics.sector_analysis(
window_days=args.window,
benchmark=args.benchmark,
)
for sector_data in sectors:
sector = sector_data['sector'][:20].ljust(20)
count = sector_data['trade_count']
alpha = float(sector_data['avg_alpha'])
win_rate = sector_data['win_rate']
logger.info(f"{sector} | {count:3d} trades | Alpha: {alpha:+6.2f}% | Win: {win_rate:.1%}")
# Timing analysis
logger.info(f"\n⏱️ DISCLOSURE TIMING")
logger.info("-" * 70)
timing = metrics.timing_analysis()
if 'error' not in timing:
logger.info(f"Average Disclosure Lag: {timing['avg_disclosure_lag_days']:.1f} days")
logger.info(f"Median Disclosure Lag: {timing['median_disclosure_lag_days']} days")
logger.info(f"Max Disclosure Lag: {timing['max_disclosure_lag_days']} days")
logger.info("\n" + "=" * 70 + "\n")
if __name__ == "__main__":
main()