The Bollinger Band breakout strategy is a classic approach to capturing market trends and momentum using a statistical representation of price volatility. In this blog post, we implement and simulate this strategy using Python and MetaTrader 5, applying it to historical data for AAPL (Apple Inc.) from April 2024 to the present.
Overview of the Bollinger Band Breakout Strategy
Bollinger Bands consist of three lines:
- SMA (Simple Moving Average): The middle band, representing the average price over a specific period.
- Upper Band: Two standard deviations above the SMA.
- Lower Band: Two standard deviations below the SMA.
The strategy uses these bands to identify breakout opportunities:
- Buy Signal: When the price remains near the upper band for two consecutive days.
- Sell Signal: When the price remains near the lower band for two consecutive days.
- Exit Criteria: Exit a trade:
- Within four days if a profit is realized.
- After four days if a loss exceeds 50 cents.
- Do not exit on the first day even if the loss is 50 cents or more.
Simulation Rules and Implementation
- Trade Setup:
- Start with an initial balance of $10,000.
- Each trade involves a fixed investment of $1.
- Entry and Exit Points:
- Trades are placed after consecutive signals near the upper or lower band.
- Exit trades within the defined criteria, accounting for both profit and loss conditions.
- Performance Tracking:
- The program calculates and records the profit or loss of each trade.
- It computes the final balance after simulating the entire historical dataset.
Python Implementation
Below is a concise description of the program:
- Data Retrieval: Historical price data for AAPL is fetched using MetaTrader 5.
- Bollinger Band Calculation: The bands are computed using a 20-day SMA and standard deviation.
- Trade Simulation: The program simulates trades based on the Bollinger Band breakout strategy, tracking performance over time.
- Visualization: The results are plotted to illustrate trades on the price chart.
Key Results
The program evaluates the performance of this strategy over the given period. Each trade entry and exit point, along with its profit or loss, is displayed. Here's an example of the output:
1 2 3 4 5 6 | Initial Balance: 10000.00 USD Final Balance: 10032.75 USD Trade Results: Buy | Entry: 185.43 | Exit: 186.89 | Profit: 1.46 USD | Entry Date: 2024-01-31 | Exit Date: 2024-02-02 Sell | Entry: 183.21 | Exit: 182.71 | Profit: 0.50 USD | Entry Date: 2024-02-10 | Exit Date: 2024-02-14 |
Chart Visualization
The chart includes:
- Price movements with Bollinger Bands (upper, lower, and middle).
- Entry and exit points for each trade marked on the chart.
Here’s an example of what the visualization looks like:
- Blue Line: Closing prices.
- Green Line: Upper Band.
- Red Line: Lower Band.
- Orange Line: SMA (Middle Band).
- Trade Points: Green dots for Buy entries and red dots for Sell entries, with exit points marked as crosses.
Insights
This simulation demonstrates how the Bollinger Band breakout strategy can be used to identify potential trading opportunities. While the strategy does not guarantee profits, it offers a systematic approach to trend-following and momentum trading.
Next Steps
You can further refine this strategy by:
- Adjusting the Bollinger Band parameters (e.g., SMA length or standard deviation multiplier).
- Incorporating additional indicators for confirmation.
- Exploring advanced position-sizing methods to optimize returns.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | import MetaTrader5 as mt5 import pandas as pd import matplotlib.pyplot as plt from datetime import datetime # Initialize and connect to MetaTrader 5 account = nnnn # Replace with your account number password = "xxxx" # Replace with your password server = "MetaQuotes-Demo" # Replace with your server # Simulated starting balance initial_balance = 10000 # Starting balance in USD trade_amount = 1 # Trade size in USD current_balance = initial_balance if not mt5.initialize(login=account, password=password, server=server): print(f"Failed to initialize MT5: {mt5.last_error()}") quit() # Symbol and timeframe SYMBOL = "AAPL" TIMEFRAME = mt5.TIMEFRAME_D1 # Daily timeframe # Get historical data from 2024/04/01 to present start_date = datetime(2024, 4, 1) end_date = datetime.now() rates = mt5.copy_rates_range(SYMBOL, TIMEFRAME, start_date, end_date) if rates is None: print(f"Failed to retrieve data for {SYMBOL}") mt5.shutdown() quit() # Convert to DataFrame data = pd.DataFrame(rates) data['time'] = pd.to_datetime(data['time'], unit='s') data.set_index('time', inplace=True) # Calculate Bollinger Bands window = 20 # 20-day moving average data['SMA'] = data['close'].rolling(window=window).mean() data['STD'] = data['close'].rolling(window=window).std() data['Upper Band'] = data['SMA'] + 2 * data['STD'] data['Lower Band'] = data['SMA'] - 2 * data['STD'] # Identify proximity to Bollinger Bands threshold = 0.15 # Define "near" as within 1% of the band data['Near Upper Band'] = abs(data['close'] - data['Upper Band']) / data['Upper Band'] < threshold data['Near Lower Band'] = abs(data['close'] - data['Lower Band']) / data['Lower Band'] < threshold # Simulate trades open_trade = None # Track the current open trade trade_results = [] # Store trade outcomes for i in range(len(data)): row = data.iloc[i] if open_trade is None: # Check for entry signals if ( row['Near Upper Band'] and data.iloc[i - 1]['Near Upper Band'] ): open_trade = { 'type': 'Buy', 'entry_price': row['close'], 'entry_date': row.name, 'days_held': 0 } elif ( row['Near Lower Band'] and data.iloc[i - 1]['Near Lower Band'] ): open_trade = { 'type': 'Sell', 'entry_price': row['close'], 'entry_date': row.name, 'days_held': 0 } else: # Update trade duration open_trade['days_held'] += 1 # Calculate profit/loss if open_trade['type'] == 'Buy': profit = trade_amount * ((row['close'] - open_trade['entry_price']) ) else: # Sell trade profit = trade_amount * ((open_trade['entry_price'] - row['close'])) # Check exit conditions if profit > 0 and open_trade['days_held'] <= 4: # Exit with profit within 4 days current_balance += profit trade_results.append({ 'type': open_trade['type'], 'entry_price': open_trade['entry_price'], 'exit_price': row['close'], 'profit': profit, 'entry_date': open_trade['entry_date'], 'exit_date': row.name }) open_trade = None elif open_trade['days_held'] > 3 and profit <= -0.5: # Exit if loss exceeds 50 cents after 4 days current_balance += profit trade_results.append({ 'type': open_trade['type'], 'entry_price': open_trade['entry_price'], 'exit_price': row['close'], 'profit': profit, 'entry_date': open_trade['entry_date'], 'exit_date': row.name }) open_trade = None # Display trade results print(f"Initial Balance: {initial_balance:.2f} USD") print(f"Final Balance: {current_balance:.2f} USD") print("\nTrade Results:") for trade in trade_results: print(f"{trade['type']} | Entry: {trade['entry_price']:.2f} | Exit: {trade['exit_price']:.2f} | " f"Profit: {trade['profit']:.2f} USD | " f"Entry Date: {trade['entry_date']} | Exit Date: {trade['exit_date']}") # Plot the chart with trades plt.figure(figsize=(15, 8)) plt.plot(data.index, data['close'], label="Close Price", color="blue") plt.plot(data.index, data['Upper Band'], label="Upper Band", color="green", alpha=0.5) plt.plot(data.index, data['Lower Band'], label="Lower Band", color="red", alpha=0.5) plt.plot(data.index, data['SMA'], label="Middle Band (SMA)", color="orange") # Plot trade entry/exit points for trade in trade_results: color = "green" if trade['type'] == 'Buy' else "red" marker = "o" if trade['type'] == 'Buy' else "x" plt.scatter(trade['entry_date'], trade['entry_price'], color="green", marker="o", zorder=5) plt.scatter(trade['exit_date'], trade['exit_price'], color="red", marker="x", zorder=5) # Add a single entry and exit symbol to the legend plt.scatter([], [], color="green", marker="o", label="Entry") plt.scatter([], [], color="red", marker="x", label="Exit") # Plot settings plt.title(f"Bollinger Bands Strategy Simulation with Trade Rules") plt.xlabel("Date") plt.ylabel("Price") plt.legend(loc="best") plt.grid(True) # Display the chart plt.show() # Shutdown MT5 mt5.shutdown() |