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.
/// The swing low and high of the previous PivotPeriod candles span a Fibonacci extension at low + (high - low) * FibLevel. A
/// close above that level while the close is above the EMA opens a long. Each entry fixes a 1.5 ATR stop-loss and a 3 ATR
/// take-profit from the entry close. Long only.
/// </summary>
public class AutoFibBreakoutStrategy : Strategy
{
private const decimal _stopAtrMultiple = 1.5m;
private const decimal _takeAtrMultiple = 3m;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _atrLength;
private readonly StrategyParam<decimal> _fibLevel;
private readonly StrategyParam<int> _pivotPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevHigh;
private decimal? _prevLow;
private decimal _stopPrice;
private decimal _takePrice;
/// <summary>
/// Trend EMA period.
/// </summary>
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
/// <summary>
/// ATR period of the stop-loss and take-profit.
/// </summary>
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
/// <summary>
/// Fibonacci extension level of the breakout.
/// </summary>
public decimal FibLevel
{
get => _fibLevel.Value;
set => _fibLevel.Value = value;
}
/// <summary>
/// Candles that define the swing high and low.
/// </summary>
public int PivotPeriod
{
get => _pivotPeriod.Value;
set => _pivotPeriod.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public AutoFibBreakoutStrategy()
{
_emaLength = Param(nameof(EmaLength), 200)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "Trend EMA period", "Trend");
_atrLength = Param(nameof(AtrLength), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Length", "ATR period of the stop-loss and take-profit", "Risk");
_fibLevel = Param(nameof(FibLevel), 1.618m)
.SetGreaterThanZero()
.SetDisplay("Fib Level", "Fibonacci extension level of the breakout", "Fibonacci");
_pivotPeriod = Param(nameof(PivotPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Pivot Period", "Candles that define the swing high and low", "Fibonacci");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
ResetState();
}
private void ResetState()
{
_prevHigh = null;
_prevLow = null;
_stopPrice = 0m;
_takePrice = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetState();
var ema = new ExponentialMovingAverage { Length = EmaLength };
var atr = new AverageTrueRange { Length = AtrLength };
var highest = new Highest { Length = PivotPeriod };
var lowest = new Lowest { Length = PivotPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ema, atr, highest, lowest, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal ema, decimal atr, decimal highest, decimal lowest)
{
if (candle.State != CandleStates.Finished)
return;
// The swing range comes from the candles before this one.
var prevHigh = _prevHigh;
var prevLow = _prevLow;
_prevHigh = highest;
_prevLow = lowest;
if (prevHigh is not decimal swingHigh || prevLow is not decimal swingLow)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
if (Position > 0)
{
if (candle.LowPrice <= _stopPrice || candle.HighPrice >= _takePrice)
SellMarket(Position);
return;
}
var extension = swingLow + (swingHigh - swingLow) * FibLevel;
if (Position == 0 && close > extension && close > ema)
{
BuyMarket(Volume);
_stopPrice = close - _stopAtrMultiple * atr;
_takePrice = close + _takeAtrMultiple * atr;
}
}
}
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 DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage, AverageTrueRange, Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
STOP_ATR_MULTIPLE = 1.5
TAKE_ATR_MULTIPLE = 3.0
class auto_fib_breakout_strategy(Strategy):
"""
AutoFib breakout strategy.
The swing low and high of the previous PivotPeriod candles span a Fibonacci extension at low + (high - low) * FibLevel. A
close above that level while the close is above the EMA opens a long. Each entry fixes a 1.5 ATR stop-loss and a 3 ATR
take-profit from the entry close. Long only.
"""
def __init__(self):
super(auto_fib_breakout_strategy, self).__init__()
self._ema_length = self.Param("EmaLength", 200) \
.SetGreaterThanZero() \
.SetDisplay("EMA Length", "Trend EMA period", "Trend")
self._atr_length = self.Param("AtrLength", 14) \
.SetGreaterThanZero() \
.SetDisplay("ATR Length", "ATR period of the stop-loss and take-profit", "Risk")
self._fib_level = self.Param("FibLevel", 1.618) \
.SetGreaterThanZero() \
.SetDisplay("Fib Level", "Fibonacci extension level of the breakout", "Fibonacci")
self._pivot_period = self.Param("PivotPeriod", 10) \
.SetGreaterThanZero() \
.SetDisplay("Pivot Period", "Candles that define the swing high and low", "Fibonacci")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._reset_state()
@property
def CandleType(self):
return self._candle_type.Value
def GetWorkingSecurities(self):
return [(self.Security, self.CandleType)]
def _reset_state(self):
self._prev_high = None
self._prev_low = None
self._stop_price = 0.0
self._take_price = 0.0
def OnReseted(self):
super(auto_fib_breakout_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(auto_fib_breakout_strategy, self).OnStarted2(time)
self._reset_state()
ema = ExponentialMovingAverage()
ema.Length = self._ema_length.Value
atr = AverageTrueRange()
atr.Length = self._atr_length.Value
highest = Highest()
highest.Length = self._pivot_period.Value
lowest = Lowest()
lowest.Length = self._pivot_period.Value
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema, atr, highest, lowest, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def _process_candle(self, candle, ema_value, atr_value, highest_value, lowest_value):
if candle.State != CandleStates.Finished:
return
# The swing range comes from the candles before this one.
swing_high = self._prev_high
swing_low = self._prev_low
self._prev_high = float(highest_value)
self._prev_low = float(lowest_value)
if swing_high is None or swing_low is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
close = float(candle.ClosePrice)
if self.Position > 0:
if float(candle.LowPrice) <= self._stop_price or float(candle.HighPrice) >= self._take_price:
self.SellMarket(self.Position)
return
extension = swing_low + (swing_high - swing_low) * float(self._fib_level.Value)
atr = float(atr_value)
if self.Position == 0 and close > extension and close > float(ema_value):
self.BuyMarket(self.Volume)
self._stop_price = close - STOP_ATR_MULTIPLE * atr
self._take_price = close + TAKE_ATR_MULTIPLE * atr
def CreateClone(self):
return auto_fib_breakout_strategy()