Monday, December 9, 2024

Trading the Bollinger Band Breakout Strategy with AAPL

 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

  1. Trade Setup:
    • Start with an initial balance of $10,000.
    • Each trade involves a fixed investment of $1.
  2. 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.
  3. 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:

  1. Data Retrieval: Historical price data for AAPL is fetched using MetaTrader 5.
  2. Bollinger Band Calculation: The bands are computed using a 20-day SMA and standard deviation.
  3. Trade Simulation: The program simulates trades based on the Bollinger Band breakout strategy, tracking performance over time.
  4. 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

Actual result:
With the trading rules implemented, The current balance was 10046.60 USD. if I adjust the trade amount from $1 to $5, I still get 10233.00 USD!

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:

  1. Adjusting the Bollinger Band parameters (e.g., SMA length or standard deviation multiplier).
  2. Incorporating additional indicators for confirmation.
  3. Exploring advanced position-sizing methods to optimize returns.
Here is the complete program listing:
  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()

No comments:

Post a Comment

Managing Trading Risks by Knowing Calendar Events That Affect Market Volatility

  Introduction to Trading Risks In Forex and other financial markets, risk management is one of the most critical aspects of successful trad...