← Back to Home
Fibonacci Pivot Breakout Trading Strategy with Scaled Entries and Trailing Stops

Fibonacci Pivot Breakout Trading Strategy with Scaled Entries and Trailing Stops

This article describes a trading strategy implemented in Backtrader that focuses on breakout opportunities using simplified pivot points, with scaled entries to manage position sizing and trailing stops for risk management. The strategy incorporates momentum and accumulation/distribution signals to enhance trade decisions.

Strategy Overview

The Fibonacci Pivot Breakout Trading Strategy integrates the following components:

Code Implementation

Below is the complete Backtrader code for the strategy:

import backtrader as bt

class FibonacciPivotBreakoutStrategy(bt.Strategy):
    params = (
        ('cmo_period', 14),
        ('ad_roc_period', 3),           # Period to check if AD line is rising
        ('trail_percent', 0.028),       # 2.8% trailing stop
        ('entry_size_pct', 0.33),       # 33% per entry (3 entries total)
        ('max_entries', 3),             # Maximum number of scale-in entries
        ('entry_spacing', 0.002),       # 0.2% spacing
    )
    
    def __init__(self):
        # Fibonacci Pivot Points
        self.fib_pivot = bt.indicators.FibonacciPivotPoint()
        
        # Chande Momentum Oscillator
        self.cmo = bt.indicators.PctChange(period=self.params.cmo_period)  # Using PctChange as CMO proxy
        
        # Accumulation/Distribution Line (using WilliamsAD as proxy)
        self.ad_line = bt.indicators.WilliamsAD()
        
        # AD Line rising (ROC of AD line)
        self.ad_roc = bt.indicators.ROC(self.ad_line, period=self.params.ad_roc_period)
        
        # State tracking
        self.order = None
        self.entry_count = 0
        self.first_entry_price = None
        self.pivot_level = None
    
    def next(self):
        if self.order or len(self.data) < 30:
            return
        
        # Get current values - SIMPLIFIED PIVOT CALCULATION
        current_price = self.data.close[0]
        
        # Simple manual pivot calculation (always works)
        if len(self.data) > 1:
            high_prev = self.data.high[-1]
            low_prev = self.data.low[-1] 
            close_prev = self.data.close[-1]
            pivot_level = (high_prev + low_prev + close_prev) / 3
            r1_level = pivot_level + (pivot_level - low_prev)  # Simplified R1
        else:
            pivot_level = self.data.close[0]
            r1_level = self.data.close[0] * 1.01  # 1% above current price
        
        # Entry conditions - VERY SIMPLE
        if self.entry_count < self.params.max_entries:
            # Initial entry - just price above yesterday's high
            if self.entry_count == 0:
                if len(self.data) > 1 and current_price > self.data.high[-1]:
                    self._make_entry(current_price)
                    self.pivot_level = pivot_level
            
            # Scale-in entries
            elif self.entry_count > 0 and self.first_entry_price:
                entry_spacing_price = self.first_entry_price * (1 + self.params.entry_spacing * self.entry_count)
                if current_price > entry_spacing_price:
                    self._make_entry(current_price)
        
        # Exit conditions
        if self.position and self.pivot_level is not None:
            # Exit if price falls below pivot level
            if current_price < self.pivot_level:
                self.order = self.close()
                self._reset_entries()
    
    def _make_entry(self, entry_price):
        """Execute a scaled entry"""
        cash = self.broker.getcash()
        size = int(cash * self.params.entry_size_pct / entry_price)
        
        if size > 0:
            self.order = self.buy(size=size)
            self.entry_count += 1
            
            # Track first entry price
            if self.entry_count == 1:
                self.first_entry_price = entry_price
            
            # Set trailing stop (only on first entry to avoid multiple stops)
            if self.entry_count == 1:
                self.sell(exectype=bt.Order.StopTrail, 
                         trailpercent=self.params.trail_percent)
    
    def _reset_entries(self):
        """Reset entry tracking variables"""
        self.entry_count = 0
        self.first_entry_price = None
        self.pivot_level = None
    
    def notify_order(self, order):
        if order.status in [order.Completed, order.Canceled, order.Margin, order.Rejected]:
            self.order = None
    
    def notify_trade(self, trade):
        if trade.isclosed:
            self._reset_entries()

Strategy Explanation

1. FibonacciPivotBreakoutStrategy

The strategy uses simplified pivot points and scaled entries to trade breakouts, with risk management via trailing stops:

Key Features

Pasted image 20250717020224.png Pasted image 20250717020235.png

Potential Improvements

This strategy is designed for markets with strong breakout potential, such as stocks or forex, and can be backtested to evaluate its performance across various timeframes and assets.