diff --git a/notebooks/strat_supertrend_initial_backtest.ipynb b/notebooks/strat_supertrend_initial_backtest.ipynb new file mode 100644 index 0000000..3878d71 --- /dev/null +++ b/notebooks/strat_supertrend_initial_backtest.ipynb @@ -0,0 +1,209 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "247ae640", + "metadata": {}, + "outputs": [], + "source": [ + "# %%\n", + "# filename: strat_supertrend_initial_backtest.ipynb\n", + "\n", + "# --- 1. Imports and Setup ---\n", + "import os\n", + "import pandas as pd\n", + "import pandas_ta as ta\n", + "import vectorbt as vbt\n", + "import plotly.graph_objects as go" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7486f4f9", + "metadata": {}, + "outputs": [], + "source": [ + "# %%\n", + "# --- 2. Configuration and Data Loading ---\n", + "\n", + "# --- Path Configuration ---\n", + "project_root = os.path.abspath(os.path.join(os.getcwd(), \"..\"))\n", + "data_dir = os.path.join(project_root, \"data\", \"parquet\")\n", + "# Make sure this filename matches the file you copied into the data/parquet directory\n", + "DATA_FILENAME = \"EURUSD_M15_2024-09-14_to_2025-09-14.parquet\"\n", + "file_path = os.path.join(data_dir, DATA_FILENAME)\n", + "\n", + "# --- Strategy Parameters ---\n", + "SUPERTREND_PERIOD = 7\n", + "SUPERTREND_MULTIPLIER = 3.0\n", + "\n", + "# --- Data Loading ---\n", + "print(f\"Loading data from: {file_path}\")\n", + "try:\n", + " price_data = pd.read_parquet(file_path)\n", + " price_data.set_index('Time', inplace=True)\n", + " print(\"Data loaded successfully and index set.\")\n", + "except FileNotFoundError:\n", + " print(f\"ERROR: File not found at '{file_path}'.\")\n", + " # Stop execution if data is not found\n", + " exit()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ed3dcc21", + "metadata": {}, + "outputs": [], + "source": [ + "# %%\n", + "# --- 3. Indicator Calculation ---\n", + "print(f\"Calculating Supertrend with period={SUPERTREND_PERIOD} and multiplier={SUPERTREND_MULTIPLIER}...\")\n", + "\n", + "# Use pandas-ta to calculate the Supertrend indicator\n", + "# It conveniently returns multiple columns, including the trend direction and the line itself.\n", + "price_data.ta.supertrend(\n", + " length=SUPERTREND_PERIOD,\n", + " multiplier=SUPERTREND_MULTIPLIER,\n", + " append=True\n", + ")\n", + "\n", + "# For clarity, let's rename the supertrend line column\n", + "# The default name is SUPERT_7_3.0\n", + "supertrend_col_name = f\"SUPERT_{SUPERTREND_PERIOD}_{SUPERTREND_MULTIPLIER}\"\n", + "price_data.rename(columns={supertrend_col_name: 'supertrend_line'}, inplace=True)\n", + "\n", + "print(\"Supertrend calculation complete.\")\n", + "print(price_data.tail())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "778fdcaa", + "metadata": {}, + "outputs": [], + "source": [ + "# %%\n", + "# --- 4. Strategy Logic & Signal Generation ---\n", + "print(\"Generating trading signals...\")\n", + "\n", + "# The signal is when the Close price crosses the Supertrend line.\n", + "# We use vectorbt's built-in signal functions for this.\n", + "entries = price_data['Close'].vbt.crossed_above(price_data['supertrend_line'])\n", + "exits = price_data['Close'].vbt.crossed_below(price_data['supertrend_line'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "895de355", + "metadata": {}, + "outputs": [], + "source": [ + "# %%\n", + "# --- 5. Backtesting and Analysis ---\n", + "print(\"Running backtest with vectorbt...\")\n", + "\n", + "# Create the portfolio from the generated signals\n", + "portfolio = vbt.Portfolio.from_signals(\n", + " price_data['Close'],\n", + " entries,\n", + " exits,\n", + " freq='15min', # Set the frequency of the data (15 minutes)\n", + " init_cash=10000,\n", + " fees=0.0001, # Example fee: 0.01%\n", + " slippage=0.0001 # Example slippage: 0.01%\n", + ")\n", + "\n", + "# Print the performance statistics\n", + "print(\"\\n--- Backtest Results ---\")\n", + "print(portfolio.stats())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "04ff5766", + "metadata": {}, + "outputs": [], + "source": [ + "# %%\n", + "# --- 6. Visualization (Optimized and Corrected) ---\n", + "print(\"\\nGenerating plot...\")\n", + "\n", + "# --- Performance Optimization for Plotting ---\n", + "# To avoid browser slowdowns, we will only plot the last 3 months of data.\n", + "# We use the modern `.loc` slicing method instead of the deprecated `.last()`.\n", + "print(\"Selecting the last 3 months of data for visualization...\")\n", + "end_date = price_data.index[-1]\n", + "start_date_plot = end_date - pd.DateOffset(months=3)\n", + "plot_data = price_data.loc[start_date_plot:]\n", + "\n", + "# --- Re-run Backtest on the Sliced Data for Clean Plotting ---\n", + "# This is the most robust way to get a portfolio object that matches the plot data.\n", + "# It's extremely fast, so there's no significant performance cost.\n", + "print(\"Running a quick backtest on the sliced data for plotting...\")\n", + "plot_entries = entries.loc[plot_data.index]\n", + "plot_exits = exits.loc[plot_data.index]\n", + "\n", + "plot_portfolio = vbt.Portfolio.from_signals(\n", + " plot_data['Close'],\n", + " plot_entries,\n", + " plot_exits,\n", + " freq='15min', # Use the corrected frequency string\n", + " init_cash=10000,\n", + " fees=0.0001,\n", + " slippage=0.0001\n", + ")\n", + "\n", + "# --- Layered Plotting ---\n", + "# Step 1: Create the base candlestick chart from the SLICED data\n", + "fig = plot_data.vbt.ohlc.plot(\n", + " title_text=f'Supertrend Strategy on {DATA_FILENAME} (Last 3 Months)',\n", + " template='plotly_dark'\n", + ")\n", + "\n", + "# Step 2: Add the Supertrend line from the SLICED data\n", + "fig.add_trace(\n", + " go.Scatter(\n", + " x=plot_data.index,\n", + " y=plot_data['supertrend_line'],\n", + " mode='lines',\n", + " name='Supertrend Line',\n", + " line=dict(color='yellow', width=1.5)\n", + " )\n", + ")\n", + "\n", + "# Step 3: Add the trade markers from the NEWLY created plot_portfolio\n", + "plot_portfolio.trades.plot(fig=fig)\n", + "\n", + "# Step 4: Show the final, combined figure\n", + "fig.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "strategy-optimizer_env", + "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.12.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}