- Complete MVP for tracking Fidelity brokerage account performance - Transaction import from CSV with deduplication - Automatic FIFO position tracking with options support - Real-time P&L calculations with market data caching - Dashboard with timeframe filtering (30/90/180 days, 1 year, YTD, all time) - Docker-based deployment with PostgreSQL backend - React/TypeScript frontend with TailwindCSS - FastAPI backend with SQLAlchemy ORM Features: - Multi-account support - Import via CSV upload or filesystem - Open and closed position tracking - Balance history charting - Performance analytics and metrics - Top trades analysis - Responsive UI design Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
158 lines
4.5 KiB
Python
Executable File
158 lines
4.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Apply patches for rate limiting fix.
|
|
This Python script works across all platforms.
|
|
"""
|
|
import os
|
|
import sys
|
|
import shutil
|
|
from pathlib import Path
|
|
|
|
|
|
def backup_file(filepath):
|
|
"""Create backup of file."""
|
|
backup_path = f"{filepath}.backup"
|
|
shutil.copy2(filepath, backup_path)
|
|
print(f"✓ Backed up {filepath} to {backup_path}")
|
|
return backup_path
|
|
|
|
|
|
def patch_main_py():
|
|
"""Patch backend/app/main.py to use analytics_v2."""
|
|
filepath = Path("backend/app/main.py")
|
|
|
|
if not filepath.exists():
|
|
print(f"❌ Error: {filepath} not found")
|
|
return False
|
|
|
|
print(f"\n[1/2] Patching {filepath}...")
|
|
|
|
# Backup
|
|
backup_file(filepath)
|
|
|
|
# Read file
|
|
with open(filepath, 'r') as f:
|
|
content = f.read()
|
|
|
|
# Check if already patched
|
|
if 'analytics_v2 as analytics' in content or 'import analytics_v2' in content:
|
|
print("✓ Backend already patched (analytics_v2 found)")
|
|
return True
|
|
|
|
# Apply patch
|
|
old_import = "from app.api.endpoints import accounts, transactions, positions, analytics"
|
|
new_import = "from app.api.endpoints import accounts, transactions, positions, analytics_v2 as analytics"
|
|
|
|
if old_import in content:
|
|
content = content.replace(old_import, new_import)
|
|
|
|
# Write back
|
|
with open(filepath, 'w') as f:
|
|
f.write(content)
|
|
|
|
print("✓ Backend patched successfully")
|
|
return True
|
|
else:
|
|
print("❌ Could not find expected import line")
|
|
print("\nLooking for:")
|
|
print(f" {old_import}")
|
|
print("\nPlease manually edit backend/app/main.py")
|
|
return False
|
|
|
|
|
|
def patch_app_tsx():
|
|
"""Patch frontend/src/App.tsx to use DashboardV2."""
|
|
filepath = Path("frontend/src/App.tsx")
|
|
|
|
if not filepath.exists():
|
|
print(f"❌ Error: {filepath} not found")
|
|
return False
|
|
|
|
print(f"\n[2/2] Patching {filepath}...")
|
|
|
|
# Backup
|
|
backup_file(filepath)
|
|
|
|
# Read file
|
|
with open(filepath, 'r') as f:
|
|
content = f.read()
|
|
|
|
# Check if already patched
|
|
if 'DashboardV2' in content or "components/DashboardV2" in content:
|
|
print("✓ Frontend already patched (DashboardV2 found)")
|
|
return True
|
|
|
|
# Apply patch - handle both single and double quotes
|
|
old_import1 = "import Dashboard from './components/Dashboard'"
|
|
new_import1 = "import Dashboard from './components/DashboardV2'"
|
|
old_import2 = 'import Dashboard from "./components/Dashboard"'
|
|
new_import2 = 'import Dashboard from "./components/DashboardV2"'
|
|
|
|
changed = False
|
|
if old_import1 in content:
|
|
content = content.replace(old_import1, new_import1)
|
|
changed = True
|
|
if old_import2 in content:
|
|
content = content.replace(old_import2, new_import2)
|
|
changed = True
|
|
|
|
if changed:
|
|
# Write back
|
|
with open(filepath, 'w') as f:
|
|
f.write(content)
|
|
|
|
print("✓ Frontend patched successfully")
|
|
return True
|
|
else:
|
|
print("❌ Could not find expected import line")
|
|
print("\nLooking for:")
|
|
print(f" {old_import1}")
|
|
print(f" or {old_import2}")
|
|
print("\nPlease manually edit frontend/src/App.tsx")
|
|
return False
|
|
|
|
|
|
def main():
|
|
print("=" * 60)
|
|
print("Applying Rate Limiting Fix Patches (Python)")
|
|
print("=" * 60)
|
|
|
|
# Check we're in the right directory
|
|
if not Path("docker-compose.yml").exists():
|
|
print("\n❌ Error: docker-compose.yml not found")
|
|
print("Please run this script from the fidelity project directory")
|
|
sys.exit(1)
|
|
|
|
# Apply patches
|
|
backend_ok = patch_main_py()
|
|
frontend_ok = patch_app_tsx()
|
|
|
|
print("\n" + "=" * 60)
|
|
|
|
if backend_ok and frontend_ok:
|
|
print("✅ All patches applied successfully!")
|
|
print("=" * 60)
|
|
print("\nNext steps:")
|
|
print("")
|
|
print("1. Rebuild containers:")
|
|
print(" docker compose down")
|
|
print(" docker compose build --no-cache backend frontend")
|
|
print(" docker compose up -d")
|
|
print("")
|
|
print("2. Run migration:")
|
|
print(" sleep 30")
|
|
print(" docker compose exec backend alembic upgrade head")
|
|
print("")
|
|
print("3. Test:")
|
|
print(" curl http://localhost:8000/api/analytics/overview/1?refresh_prices=false")
|
|
print("")
|
|
sys.exit(0)
|
|
else:
|
|
print("⚠️ Some patches failed - see manual instructions above")
|
|
print("=" * 60)
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|