Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 152 additions & 0 deletions notebooks/optim_backtestingpy_sma_with_sl_tp.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "7712680a",
"metadata": {},
"outputs": [],
"source": [
"# %%\n",
"# filename: optim_backtestingpy_sma_with_sl_tp.ipynb\n",
"\n",
"# --- 1. Imports and Setup ---\n",
"import numpy as np\n",
"import pandas as pd\n",
"import pandas_ta as ta\n",
"from backtesting import Backtest, Strategy\n",
"from backtesting.lib import crossover\n",
"from backtesting.test import EURUSD\n",
"\n",
"# --- 2. Load Sample Data ---\n",
"print(\"Loading built-in EURUSD sample data...\")\n",
"data = EURUSD.copy()\n",
"print(\"Data loaded successfully.\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0fd6f9be",
"metadata": {},
"outputs": [],
"source": [
"# %%\n",
"# --- 3. The Parameterized Strategy with SL/TP ---\n",
"\n",
"class SmaCrossSLTP(Strategy):\n",
" # --- Parameters for Optimization ---\n",
" fast_period = 10\n",
" slow_period = 40\n",
"\n",
" # New parameters for Stop-Loss and Take-Profit (as percentages)\n",
" # Note: We express them as decimals, e.g., 1.5% SL is 0.015\n",
" sl_percent = 1.5\n",
" tp_percent = 3.0\n",
"\n",
" def init(self):\n",
" # Calculate indicators internally for optimization\n",
" self.fast_sma = self.I(ta.sma, pd.Series(self.data.Close), length=self.fast_period)\n",
" self.slow_sma = self.I(ta.sma, pd.Series(self.data.Close), length=self.slow_period)\n",
"\n",
" def next(self):\n",
" # Define SL and TP prices based on the current close\n",
" sl_price = self.data.Close[-1] * (1 - self.sl_percent / 100)\n",
" tp_price = self.data.Close[-1] * (1 + self.tp_percent / 100)\n",
"\n",
" # Entry logic\n",
" if crossover(self.fast_sma, self.slow_sma):\n",
" if not self.position:\n",
" # When buying, provide the sl and tp prices\n",
" self.buy(sl=sl_price, tp=tp_price)\n",
"\n",
" # The exit signal from the crossover is still valid\n",
" elif crossover(self.slow_sma, self.fast_sma):\n",
" self.position.close()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9572ae93",
"metadata": {},
"outputs": [],
"source": [
"# %%\n",
"# --- 4. Running the Optimization (FINAL, DEFINITIVE VERSION) ---\n",
"print(\"\\n--- Starting Grid Search Optimization with SL/TP ---\")\n",
"\n",
"bt = Backtest(data, SmaCrossSLTP, cash=10000, commission=.002)\n",
"\n",
"# Helper function to generate a range of floats\n",
"def frange(start, stop, step):\n",
" return np.arange(start, stop, step).tolist()\n",
"\n",
"# CORRECTED: The optimize() method with return_heatmap=True returns a TUPLE\n",
"# containing (stats_series, heatmap_data). We unpack this tuple into two variables.\n",
"stats, heatmap = bt.optimize(\n",
" fast_period=range(10, 31, 10),\n",
" slow_period=range(40, 61, 10),\n",
" sl_percent=frange(0.5, 2.1, 0.5),\n",
" tp_percent=frange(2.0, 5.1, 1.0),\n",
"\n",
" maximize='SQN',\n",
" constraint=lambda p: p.fast_period < p.slow_period,\n",
" return_heatmap=True # This is crucial for getting the tuple back\n",
")\n",
"\n",
"print(\"\\n--- Optimization Results ---\")\n",
"print(\"Best stats found:\")\n",
"# The 'stats' variable now correctly holds the results Series\n",
"print(stats)\n",
"\n",
"print(\"\\nBest parameters found:\")\n",
"# The strategy object is an attribute of the stats Series\n",
"print(stats._strategy)\n",
"\n",
"# The 'heatmap' variable now correctly holds the heatmap data for the next cell"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b7cac03e",
"metadata": {},
"outputs": [],
"source": [
"# %%\n",
"# --- 5. Visualizing the Best Run and Heatmaps ---\n",
"from backtesting.lib import plot_heatmaps\n",
"\n",
"print(\"\\n--- Plotting the Best Strategy Run ---\")\n",
"# The .plot() method will automatically show the SL/TP levels on the chart\n",
"bt.plot()\n",
"\n",
"print(\"\\n--- Plotting Optimization Heatmap ---\")\n",
"# This will generate a heatmap for each pair of optimized parameters\n",
"plot_heatmaps(heatmap, agg='mean')"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "strategy-optimizer_env_bck",
"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
}