AutoFib Breakout Strategy
This strategy draws a dynamic Fibonacci extension from recent swing high and low and goes long when price breaks above the 1.618 level during an uptrend defined by the 200 EMA. Risk is managed using ATR-based stop and target.
Details
- Entry Criteria: Close above 1.618 Fibonacci extension and above EMA200.
- Long/Short: Long only.
- Exit Criteria: ATR-based stop-loss or 3×ATR take profit.
- Stops: Yes, based on ATR.
- Default Values:
EmaLength= 200AtrLength= 14FibLevel= 1.618PivotPeriod= 10CandleType= 5 minute
- Filters:
- Category: Breakout
- Direction: Long
- Indicators: EMA, ATR, Highest, Lowest
- Stops: Yes
- Complexity: Basic
- Timeframe: Intraday
- Seasonality: No
- Neural networks: No
- Divergence: No
- Risk level: Medium
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// AutoFib breakout strategy.
/// Uses Highest/Lowest channel with EMA trend filter.
/// Buys on breakout above channel high in uptrend, sells on break below in downtrend.
/// </summary>
public class AutoFibBreakoutStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _channelLength;
private readonly StrategyParam<int> _cooldownBars;
private decimal _prevHighest;
private decimal _prevLowest;
private int _barIndex;
private int _lastTradeBar;
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// EMA period.
/// </summary>
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
/// <summary>
/// Channel lookback period.
/// </summary>
public int ChannelLength
{
get => _channelLength.Value;
set => _channelLength.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public AutoFibBreakoutStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
_emaLength = Param(nameof(EmaLength), 50)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "EMA trend filter period", "Indicators");
_channelLength = Param(nameof(ChannelLength), 20)
.SetGreaterThanZero()
.SetDisplay("Channel Length", "Highest/Lowest lookback", "Indicators");
_cooldownBars = Param(nameof(CooldownBars), 350)
.SetDisplay("Cooldown Bars", "Bars between trades", "Trading");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevHighest = 0;
_prevLowest = 0;
_barIndex = 0;
_lastTradeBar = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ema = new ExponentialMovingAverage { Length = EmaLength };
var highest = new Highest { Length = ChannelLength };
var lowest = new Lowest { Length = ChannelLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ema, highest, lowest, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal emaValue, decimal highestValue, decimal lowestValue)
{
if (candle.State != CandleStates.Finished)
return;
_barIndex++;
var cooldownOk = _barIndex - _lastTradeBar > CooldownBars;
// Breakout above previous highest with uptrend confirmation
var breakUp = _prevHighest > 0 && candle.ClosePrice > _prevHighest && candle.ClosePrice > emaValue;
// Breakdown below previous lowest with downtrend confirmation
var breakDown = _prevLowest > 0 && candle.ClosePrice < _prevLowest && candle.ClosePrice < emaValue;
if (breakUp && Position <= 0 && cooldownOk)
{
BuyMarket();
_lastTradeBar = _barIndex;
}
else if (breakDown && Position >= 0 && cooldownOk)
{
SellMarket();
_lastTradeBar = _barIndex;
}
_prevHighest = highestValue;
_prevLowest = lowestValue;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage, Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
class auto_fib_breakout_strategy(Strategy):
"""
AutoFib breakout strategy.
Uses Highest/Lowest channel with EMA trend filter.
Buys on breakout above channel high in uptrend, sells on break below in downtrend.
"""
def __init__(self):
super(auto_fib_breakout_strategy, self).__init__()
self._candle_type = self.Param("CandleType", tf(1)) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._ema_length = self.Param("EmaLength", 50) \
.SetGreaterThanZero() \
.SetDisplay("EMA Length", "EMA trend filter period", "Indicators")
self._channel_length = self.Param("ChannelLength", 20) \
.SetGreaterThanZero() \
.SetDisplay("Channel Length", "Highest/Lowest lookback", "Indicators")
self._cooldown_bars = self.Param("CooldownBars", 350) \
.SetDisplay("Cooldown Bars", "Bars between trades", "Trading")
self._prev_highest = 0.0
self._prev_lowest = 0.0
self._bar_index = 0
self._last_trade_bar = 0
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, v): self._candle_type.Value = v
@property
def EmaLength(self): return self._ema_length.Value
@EmaLength.setter
def EmaLength(self, v): self._ema_length.Value = v
@property
def ChannelLength(self): return self._channel_length.Value
@ChannelLength.setter
def ChannelLength(self, v): self._channel_length.Value = v
@property
def CooldownBars(self): return self._cooldown_bars.Value
@CooldownBars.setter
def CooldownBars(self, v): self._cooldown_bars.Value = v
def OnReseted(self):
super(auto_fib_breakout_strategy, self).OnReseted()
self._prev_highest = 0.0
self._prev_lowest = 0.0
self._bar_index = 0
self._last_trade_bar = 0
def OnStarted2(self, time):
super(auto_fib_breakout_strategy, self).OnStarted2(time)
ema = ExponentialMovingAverage()
ema.Length = self.EmaLength
highest = Highest()
highest.Length = self.ChannelLength
lowest = Lowest()
lowest.Length = self.ChannelLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema, highest, lowest, self.ProcessCandle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def ProcessCandle(self, candle, ema_value, highest_value, lowest_value):
if candle.State != CandleStates.Finished:
return
self._bar_index += 1
cooldown_ok = self._bar_index - self._last_trade_bar > self.CooldownBars
close = float(candle.ClosePrice)
break_up = self._prev_highest > 0 and close > self._prev_highest and close > ema_value
break_down = self._prev_lowest > 0 and close < self._prev_lowest and close < ema_value
if break_up and self.Position <= 0 and cooldown_ok:
self.BuyMarket()
self._last_trade_bar = self._bar_index
elif break_down and self.Position >= 0 and cooldown_ok:
self.SellMarket()
self._last_trade_bar = self._bar_index
self._prev_highest = highest_value
self._prev_lowest = lowest_value
def CreateClone(self):
"""!! REQUIRED!! Creates a new instance of the strategy."""
return auto_fib_breakout_strategy()