{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# PREDIX Quickstart Tutorial\n",
    "\n",
    "Willkommen zu PREDIX – deiner Plattform für algorithmisches EUR/USD Trading!\n",
    "\n",
    "In diesem Notebook lernst du:\n",
    "1. **Daten laden** – EUR/USD 1-Minute Daten vorbereiten\n",
    "2. **Faktoren generieren** – Einfache Trading-Faktoren berechnen\n",
    "3. **Strategie kombinieren** – Mehrere Faktoren zu einer Strategie verbinden\n",
    "4. **Backtest durchführen** – Historische Performance testen\n",
    "5. **Ergebnisse visualisieren** – Equity Curve und Metriken\n",
    "\n",
    "## Voraussetzungen\n",
    "\n",
    "```bash\n",
    "pip install -e \".[all]\"\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Setup & Daten laden\n",
    "\n",
    "Zuerst importieren wir die benötigten Bibliotheken und laden die EUR/USD Daten."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import warnings\n",
    "warnings.filterwarnings('ignore')\n",
    "\n",
    "# Plotly für interaktive Charts (optional)\n",
    "try:\n",
    "    import plotly.graph_objects as go\n",
    "    from plotly.subplots import make_subplots\n",
    "    HAS_PLOTLY = True\n",
    "except ImportError:\n",
    "    HAS_PLOTLY = False\n",
    "\n",
    "print(\"✓ Imports erfolgreich!\")\n",
    "print(f\"  Pandas: {pd.__version__}\")\n",
    "print(f\"  NumPy: {np.__version__}\")\n",
    "print(f\"  Plotly: {'ja' if HAS_PLOTLY else 'nein (pip install plotly)'}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Daten-Simulation\n",
    "\n",
    "Für dieses Tutorial simulieren wir EUR/USD Daten (in Produktion: Echte Daten aus Qlib)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Simuliere EUR/USD 1-Minute Daten (1 Jahr)\n",
    "np.random.seed(42)\n",
    "n_bars = 525600  # 525600 Minuten pro Jahr\n",
    "\n",
    "# Datetime-Index (24/7 Trading)\n",
    "dates = pd.date_range('2024-01-01', periods=n_bars, freq='min')\n",
    "\n",
    "# Simulierte Preise (Geometric Brownian Motion)\n",
    "dt = 1/525600\n",
    "mu = 0.00002  # Drift\n",
    "sigma = 0.0003  # Volatilität\n",
    "returns = np.random.normal(mu, sigma, n_bars)\n",
    "prices = 1.0850 * np.exp(np.cumsum(returns))  # Start bei 1.0850\n",
    "\n",
    # OHLCV erstellen\n",
    "df = pd.DataFrame({\n",
    "    'open': prices + np.random.normal(0, 0.0001, n_bars),\n",
    "    'high': prices + np.abs(np.random.normal(0, 0.0002, n_bars)),\n",
    "    'low': prices - np.abs(np.random.normal(0, 0.0002, n_bars)),\n",
    "    'close': prices,\n",
    "    'volume': np.random.exponential(100, n_bars).astype(int)\n",
    "}, index=dates)\n",
    "\n",
    "print(f\"✓ Daten generiert: {len(df)} Bars\")\n",
    "print(f\"  Zeitraum: {df.index[0]} bis {df.index[-1]}\")\n",
    "print(f\"\\nErste 5 Zeilen:\")\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Trading-Faktoren berechnen\n",
    "\n",
    "Jetzt berechnen wir verschiedene Trading-Faktoren:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def calculate_momentum(close: pd.Series, window: int) -> pd.Series:\n",
    "    \"\"\"Momentum-Faktor: Prozentuale Veränderung über window Bars.\"\"\"\n",
    "    return close.pct_change(window)\n",
    "\n",
    "def calculate_rsi(close: pd.Series, period: int = 14) -> pd.Series:\n",
    "    \"\"\"RSI (Relative Strength Index).\"\"\"\n",
    "    delta = close.diff()\n",
    "    gain = delta.where(delta > 0, 0).rolling(period).mean()\n",
    "    loss = (-delta.where(delta < 0, 0)).rolling(period).mean()\n",
    "    rs = gain / (loss + 1e-8)\n",
    "    return 100 - (100 / (1 + rs))\n",
    "\n",
    "def calculate_hl_range(high: pd.Series, low: pd.Series, close: pd.Series) -> pd.Series:\n",
    "    \"\"\"High-Low Range als Volatilitäts-Proxy.\"\"\"\n",
    "    return (high - low) / close\n",
    "\n",
    "def calculate_session_flag(index: pd.DatetimeIndex, session: str) -> pd.Series:\n",
    "    \"\"\"Session-Filter (London, NY, Asian).\"\"\"\n",
    "    hour = index.hour\n",
    "    if session == 'london':\n",
    "        return ((hour >= 8) & (hour < 16)).astype(float)\n",
    "    elif session == 'ny':\n",
    "        return ((hour >= 13) & (hour < 21)).astype(float)\n",
    "    elif session == 'overlap':\n",
    "        return ((hour >= 13) & (hour < 16)).astype(float)\n",
    "    return pd.Series(1, index=index)\n",
    "\n",
    "# Faktoren berechnen\n",
    "factors = pd.DataFrame(index=df.index)\n",
    "factors['momentum_16'] = calculate_momentum(df['close'], 16)\n",
    "factors['momentum_96'] = calculate_momentum(df['close'], 96)\n",
    "factors['rsi_14'] = calculate_rsi(df['close'], 14)\n",
    "factors['hl_range'] = calculate_hl_range(df['high'], df['low'], df['close'])\n",
    "factors['is_london'] = calculate_session_flag(df.index, 'london')\n",
    "factors['is_ny'] = calculate_session_flag(df.index, 'ny')\n",
    "\n",
    "# NaN entfernen\n",
    "factors = factors.dropna()\n",
    "\n",
    "print(f\"✓ {len(factors.columns)} Faktoren berechnet:\")\n",
    "for col in factors.columns:\n",
    "    print(f\"  - {col:15s} | Mean: {factors[col].mean():+.4f} | Std: {factors[col].std():.4f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Strategie kombinieren\n",
    "\n",
    "Wir kombinieren die Faktoren zu einer IC-weighted Strategie:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Simulierte IC-Werte (Information Coefficient)\n",
    "ic_values = {\n",
    "    'momentum_16': 0.074,      # Positiv: Trend-following\n",
    "    'momentum_96': 0.051,      # Positiv: Langfristiger Trend\n",
    "    'rsi_14': -0.045,          # Negativ: Mean-reversion\n",
    "    'hl_range': -0.032         # Negativ: Volatilitäts-Fade\n",
    "}\n",
    "\n",
    "# Z-Score Normalisierung\n",
    "z_scores = (factors[list(ic_values.keys())] - factors[list(ic_values.keys())].rolling(20).mean()) / (\n",
    "    factors[list(ic_values.keys())].rolling(20).std() + 1e-8\n",
    ")\n",
    "\n",
    "# IC-Weights (normalisieren)\n",
    "total_abs_ic = sum(abs(ic) for ic in ic_values.values())\n",
    "weights = {k: v / total_abs_ic for k, v in ic_values.items()}\n",
    "\n",
    "# Composite Signal\n",
    "composite = pd.Series(0.0, index=z_scores.index)\n",
    "for factor_name, weight in weights.items():\n",
    "    composite += weight * z_scores[factor_name]\n",
    "\n",
    "# Signale generieren (Thresholds)\n",
    "signal = pd.Series(0, index=composite.index)\n",
    "signal[composite > 0.5] = 1    # LONG\n",
    "signal[composite < -0.5] = -1  # SHORT\n",
    "\n",
    "print(f\"✓ Strategie generiert\")\n",
    "print(f\"\\nSignal-Verteilung:\")\n",
    "print(f\"  LONG:    {(signal == 1).sum():6d} ({(signal == 1).mean()*100:.1f}%)\")\n",
    "print(f\"  SHORT:   {(signal == -1).sum():6d} ({(signal == -1).mean()*100:.1f}%)\")\n",
    "print(f\"  NEUTRAL: {(signal == 0).sum():6d} ({(signal == 0).mean()*100:.1f}%)\")\n",
    "\n",
    "# IC-Weights anzeigen\n",
    "print(f\"\\nIC-Weights:\")\n",
    "for factor_name, weight in weights.items():\n",
    "    print(f\"  {factor_name:15s}: {weight:+.4f} (IC: {ic_values[factor_name]:+.4f})\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. Backtest\n",
    "\n",
    "Simulieren wir einen einfachen Backtest mit Spread-Kosten:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Backtest-Parameter\n",
    "spread_cost = 0.00015  # 1.5 bps\n",
    "initial_capital = 100000\n",
    "position_size = 0.1  # 10% des Kapitals pro Trade\n",
    "\n",
    "# Nur London/NY Session handeln\n",
    "active_mask = (factors['is_london'] == 1) | (factors['is_ny'] == 1)\n",
    "\n",
    "# Returns berechnen\n",
    "close = df.loc[signal.index, 'close']\n",
    "returns = close.pct_change()\n",
    "\n",
    "# Strategie-Returns\n",
    "strategy_returns = signal.shift(1) * returns  # Signal vom Vortag\n",
    "strategy_returns = strategy_returns[active_mask]\n",
    "\n",
    "# Spread-Kosten abziehen\n",
    "trade_costs = (signal.shift(1) != signal).astype(float) * spread_cost\n",
    "strategy_returns = strategy_returns - trade_costs\n",
    "\n",
    "# Kumulierte Returns\n",
    "equity = initial_capital * (1 + strategy_returns).cumprod()\n",
    "benchmark_equity = initial_capital * (1 + returns[active_mask]).cumprod()\n",
    "\n",
    "# Metriken berechnen\n",
    "total_return = (equity.iloc[-1] / initial_capital - 1) * 100\n",
    "years = len(strategy_returns) / 525600\n",
    "arr = ((equity.iloc[-1] / initial_capital) ** (1/max(years, 0.001)) - 1) * 100\n",
    "sharpe = strategy_returns.mean() / (strategy_returns.std() + 1e-8) * np.sqrt(525600)\n",
    "\n",
    "# Max Drawdown\n",
    "rolling_max = equity.cummax()\n",
    "drawdown = (equity - rolling_max) / rolling_max\n",
    "max_dd = drawdown.min() * 100\n",
    "\n",
    "print(f\"=\" * 50)\n",
    "print(f\"BACKTEST ERGEBNISSE\")\n",
    "print(f\"=\" * 50)\n",
    "print(f\"  Initial Capital:  ${initial_capital:,.0f}\")\n",
    "print(f\"  Final Capital:    ${equity.iloc[-1]:,.0f}\")\n",
    "print(f\"  Total Return:     {total_return:+.2f}%\")\n",
    "print(f\"  ARR:              {arr:+.2f}%\")\n",
    "print(f\"  Sharpe Ratio:     {sharpe:.2f}\")\n",
    "print(f\"  Max Drawdown:     {max_dd:.2f}%\")\n",
    "print(f\"  Trades:           {(signal.shift(1) != signal).sum()}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5. Visualisierung\n",
    "\n",
    "Jetzt visualisieren wir die Equity Curve und die Drawdowns."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if HAS_PLOTLY:\n",
    "    # Subplots: Equity + Drawdown\n",
    "    fig = make_subplots(\n",
    "        rows=2, cols=1,\n",
    "        shared_xaxes=True,\n",
    "        vertical_spacing=0.05,\n",
    "        row_heights=[0.7, 0.3],\n",
    "        subplot_titles=('Equity Curve', 'Drawdown')\n",
    "    )\n",
    "    \n",
    "    # Equity Curve\n",
    "    fig.add_trace(\n",
    "        go.Scatter(x=equity.index, y=equity.values, name='Strategy', line=dict(color='#2E86AB', width=2)),\n",
    "        row=1, col=1\n",
    "    )\n",
    "    fig.add_trace(\n",
    "        go.Scatter(x=benchmark_equity.index, y=benchmark_equity.values, name='Benchmark', line=dict(color='#A23B72', width=1, dash='dot')),\n",
    "        row=1, col=1\n",
    "    )\n",
    "    \n",
    "    # Drawdown\n",
    "    fig.add_trace(\n",
    "        go.Scatter(x=drawdown.index, y=drawdown.values*100, name='Drawdown',\n",
    "                   fill='tozeroy', line=dict(color='#F18F01', width=1)),\n",
    "        row=2, col=1\n",
    "    )\n",
    "    \n",
    "    fig.update_layout(\n",
    "        title='PREDIX Backtest - EUR/USD 1-Minute',\n",
    "        template='plotly_dark',\n",
    "        height=700,\n",
    "        showlegend=True\n",
    "    )\n",
    "    \n",
    "    fig.show()\n",
    "else:\n",
    "    # Matplotlib Fallback\n",
    "    fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(14, 8), sharex=True, gridspec_kw={'height_ratios': [3, 1]})\n",
    "    \n",
    "    ax1.plot(equity.index, equity.values, label='Strategy', color='#2E86AB', linewidth=2)\n",
    "    ax1.plot(benchmark_equity.index, benchmark_equity.values, label='Benchmark', color='#A23B72', linewidth=1, linestyle='--')\n",
    "    ax1.set_title('Equity Curve')\n",
    "    ax1.legend()\n",
    "    ax1.grid(True, alpha=0.3)\n",
    "    \n",
    "    ax2.fill_between(drawdown.index, drawdown.values*100, 0, color='#F18F01', alpha=0.5)\n",
    "    ax2.set_title('Drawdown')\n",
    "    ax2.grid(True, alpha=0.3)\n",
    "    \n",
    "    plt.tight_layout()\n",
    "    plt.savefig('equity_curve.png', dpi=150)\n",
    "    plt.show()\n",
    "    print(\"✓ Chart gespeichert: equity_curve.png\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6. Nächste Schritte\n",
    "\n",
    "🎉 Glückwunsch! Du hast deinen ersten PREDIX-Backtest durchgeführt.\n",
    "\n",
    "### Weiterführende Beispiele:\n",
    "\n",
    "| Beispiel | Beschreibung |\n",
    "|----------|-------------|\n",
    "| `01_factor_discovery.py` | Automatische Faktor-Generierung mit LLM |\n",
    "| `02_factor_evolution.py` | Faktor-Optimierung mit Session/Regime Filters |\n",
    "| `05_model_training.py` | ML-Modelle (LSTM/XGBoost) trainieren |\n",
    "| `06_rl_trading_agent.py` | Reinforcement Learning Agent |\n",
    "\n",
    "### CLI Commands:\n",
    "\n",
    "```bash\n",
    "# Alle Commands anzeigen\n",
    "rdagent --help\n",
    "\n",
    "# Faktor-Generierung starten\n",
    "rdagent quant --loop-n 10\n",
    "\n",
    "# Faktoren evaluieren\n",
    "rdagent evaluate\n",
    "\n",
    "# Top-Faktoren anzeigen\n",
    "rdagent top --n 10\n",
    "```\n",
    "\n",
    "### Ressourcen:\n",
    "\n",
    "- 📚 [Dokumentation](../docs/)\n",
    "- 💬 [GitHub Discussions](https://github.com/nico/NexQuant/discussions)\n",
    "- 🐛 [Issues melden](https://github.com/nico/NexQuant/issues)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
