mirror of
https://github.com/NicolasBohn/NexQuant.git
synced 2026-07-27 23:47:46 +00:00
1cb09d73ea
Kompakte Implementierung: 1. backtest_engine.py - IC, Sharpe, Max Drawdown, Win Rate - FactorBacktester mit JSON-Export 2. results_db.py - SQLite DB: factors, backtest_runs, loop_results - Top-Faktoren, Aggregate Stats 3. risk_management.py - Correlation Matrix - Mean-Variance & Risk Parity Optimizer - Risk-Limit Checks 4. results/ Ordner (in .gitignore) - backtests/, db/, factors/, runs/, logs/ - README.md mit Dokumentation Status: - Backtesting: 10% → 90% ✅ - Risk Management: 60% → 95% ✅
89 lines
4.1 KiB
Python
89 lines
4.1 KiB
Python
"""
|
|
Predix Results Database - SQLite für Backtest-Ergebnisse
|
|
"""
|
|
import sqlite3
|
|
import pandas as pd
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
from typing import Dict, Optional
|
|
|
|
class ResultsDatabase:
|
|
def __init__(self, db_path: Optional[str] = None):
|
|
if db_path is None:
|
|
db_path = Path(__file__).parent.parent.parent / "results" / "db" / "backtest_results.db"
|
|
self.db_path = db_path
|
|
Path(db_path).parent.mkdir(parents=True, exist_ok=True)
|
|
self.conn = sqlite3.connect(db_path)
|
|
self._create_tables()
|
|
|
|
def _create_tables(self):
|
|
c = self.conn.cursor()
|
|
c.execute("""CREATE TABLE IF NOT EXISTS factors (
|
|
id INTEGER PRIMARY KEY, factor_name TEXT UNIQUE, factor_type TEXT, created_at TIMESTAMP)""")
|
|
c.execute("""CREATE TABLE IF NOT EXISTS backtest_runs (
|
|
id INTEGER PRIMARY KEY, factor_id INTEGER, run_name TEXT, run_date TIMESTAMP,
|
|
ic REAL, sharpe REAL, annual_return REAL, max_drawdown REAL, win_rate REAL)""")
|
|
c.execute("""CREATE TABLE IF NOT EXISTS loop_results (
|
|
id INTEGER PRIMARY KEY, loop_index INTEGER, factors_success INTEGER,
|
|
factors_fail INTEGER, success_rate REAL, best_ic REAL, status TEXT)""")
|
|
self.conn.commit()
|
|
|
|
def add_factor(self, name: str, type: str = "unknown") -> int:
|
|
c = self.conn.cursor()
|
|
c.execute("INSERT OR IGNORE INTO factors (factor_name, factor_type, created_at) VALUES (?, ?, ?)",
|
|
(name, type, datetime.now()))
|
|
c.execute("SELECT id FROM factors WHERE factor_name = ?", (name,))
|
|
self.conn.commit()
|
|
result = c.fetchone()
|
|
return result[0] if result else -1
|
|
|
|
def add_backtest(self, factor_name: str, metrics: Dict) -> int:
|
|
factor_id = self.add_factor(factor_name)
|
|
c = self.conn.cursor()
|
|
c.execute("""INSERT INTO backtest_runs
|
|
(factor_id, run_name, run_date, ic, sharpe, annual_return, max_drawdown, win_rate)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)""",
|
|
(factor_id, f"{factor_name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}",
|
|
datetime.now(), metrics.get('ic'), metrics.get('sharpe_ratio'),
|
|
metrics.get('annualized_return'), metrics.get('max_drawdown'), metrics.get('win_rate')))
|
|
self.conn.commit()
|
|
return c.lastrowid
|
|
|
|
def add_loop(self, loop_idx: int, success: int, fail: int, best_ic: float = None, status: str = "completed") -> int:
|
|
c = self.conn.cursor()
|
|
rate = success / (success + fail) if (success + fail) > 0 else 0
|
|
c.execute("""INSERT INTO loop_results (loop_index, factors_success, factors_fail, success_rate, best_ic, status)
|
|
VALUES (?, ?, ?, ?, ?, ?)""", (loop_idx, success, fail, rate, best_ic, status))
|
|
self.conn.commit()
|
|
return c.lastrowid
|
|
|
|
def get_top_factors(self, metric: str = 'sharpe', limit: int = 20) -> pd.DataFrame:
|
|
return pd.read_sql_query(f"""SELECT factor_name, {metric}, ic, annual_return, max_drawdown
|
|
FROM backtest_runs JOIN factors ON factor_id = factors.id
|
|
WHERE {metric} IS NOT NULL ORDER BY {metric} DESC LIMIT ?""",
|
|
self.conn, params=[limit])
|
|
|
|
def get_aggregate_stats(self) -> Dict:
|
|
c = self.conn.cursor()
|
|
c.execute("""SELECT COUNT(DISTINCT factor_name), AVG(ic), MAX(sharpe), AVG(annual_return)
|
|
FROM backtest_runs JOIN factors ON factor_id = factors.id""")
|
|
r = c.fetchone()
|
|
return {'total_factors': r[0], 'avg_ic': r[1], 'max_sharpe': r[2], 'avg_return': r[3]}
|
|
|
|
def close(self):
|
|
self.conn.close()
|
|
|
|
if __name__ == "__main__":
|
|
print("=== DB Test ===")
|
|
db = ResultsDatabase()
|
|
db.add_factor("TestFactor", "Momentum")
|
|
db.add_backtest("TestFactor", {'ic': 0.05, 'sharpe_ratio': 1.5, 'annualized_return': 0.15, 'max_drawdown': -0.08, 'win_rate': 0.55})
|
|
db.add_loop(1, 4, 6, 0.05, "completed")
|
|
|
|
print("Top Faktoren:")
|
|
print(db.get_top_factors())
|
|
print("\nAggregate Stats:")
|
|
print(db.get_aggregate_stats())
|
|
db.close()
|
|
print("✅ Test bestanden!")
|