Estratégia de Pullback Fibonacci Adaptativo
A estratégia calcula a média de três linhas SuperTrend construídas com multiplicadores de Fibonacci (0.618, 1.618, 2.618) e suaviza o resultado com uma EMA. As operações seguem pullbacks para essa tendência adaptativa, enquanto uma linha média baseada em AMA e um filtro RSI opcional confirmam a direção.
Detalhes
- Critérios de entrada:
- Mínimo abaixo do SuperTrend médio e fechamento acima do seu valor suavizado.
- O fechamento anterior em relação à linha média AMA define o pullback.
- Comprado: fechamento acima da linha média e RSI > limiar.
- Vendido: fechamento abaixo da linha média e RSI < limiar.
- Comprado/Vendido: Ambos os lados.
- Critérios de saída:
- Fechamento cruzando o SuperTrend suavizado na direção oposta.
- Stops: Stop loss e take profit percentuais via
StartProtection. - Valores padrão:
AtrPeriod= 8SmoothLength= 21AmaLength= 55RsiLength= 7RsiBuy= 70RsiSell= 30TakeProfitPercent= 5StopLossPercent= 0.75
- Filtros:
- Categoria: Pullback de tendência
- Direção: Ambos
- Indicadores: SuperTrend, EMA, AMA, RSI
- Stops: Sim
- Complexidade: Moderado
- Período: Qualquer
- Sazonalidade: Não
- Redes neurais: Não
- Divergência: Não
- Nível de risco: Médio
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>
/// Adaptive Fibonacci Pullback strategy.
/// Three SuperTrend lines with Fibonacci multipliers are averaged and the average is smoothed by an EMA. A long needs the low to dip
/// below the average while the close stays above the smoothed line, the previous and current close above the Kaufman AMA midline and
/// RSI above RsiBuy; a short mirrors this with RSI below RsiSell. Positions close when the close crosses the smoothed line against them,
/// and percent take profit and stop loss protect every trade.
/// </summary>
public class AdaptiveFibonacciPullbackStrategy : Strategy
{
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _factor1;
private readonly StrategyParam<decimal> _factor2;
private readonly StrategyParam<decimal> _factor3;
private readonly StrategyParam<int> _smoothLength;
private readonly StrategyParam<int> _amaLength;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<decimal> _rsiBuy;
private readonly StrategyParam<decimal> _rsiSell;
private readonly StrategyParam<decimal> _takeProfitPercent;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _smooth;
private decimal? _prevClose;
private decimal? _prevSmooth;
/// <summary>
/// ATR period of the SuperTrends.
/// </summary>
public int AtrPeriod
{
get => _atrPeriod.Value;
set => _atrPeriod.Value = value;
}
/// <summary>
/// Multiplier of the first SuperTrend.
/// </summary>
public decimal Factor1
{
get => _factor1.Value;
set => _factor1.Value = value;
}
/// <summary>
/// Multiplier of the second SuperTrend.
/// </summary>
public decimal Factor2
{
get => _factor2.Value;
set => _factor2.Value = value;
}
/// <summary>
/// Multiplier of the third SuperTrend.
/// </summary>
public decimal Factor3
{
get => _factor3.Value;
set => _factor3.Value = value;
}
/// <summary>
/// EMA length that smooths the SuperTrend average.
/// </summary>
public int SmoothLength
{
get => _smoothLength.Value;
set => _smoothLength.Value = value;
}
/// <summary>
/// Period of the AMA midline.
/// </summary>
public int AmaLength
{
get => _amaLength.Value;
set => _amaLength.Value = value;
}
/// <summary>
/// Period of RSI.
/// </summary>
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
/// <summary>
/// RSI level a long requires to exceed.
/// </summary>
public decimal RsiBuy
{
get => _rsiBuy.Value;
set => _rsiBuy.Value = value;
}
/// <summary>
/// RSI level a short requires to stay below.
/// </summary>
public decimal RsiSell
{
get => _rsiSell.Value;
set => _rsiSell.Value = value;
}
/// <summary>
/// Take profit percentage.
/// </summary>
public decimal TakeProfitPercent
{
get => _takeProfitPercent.Value;
set => _takeProfitPercent.Value = value;
}
/// <summary>
/// Stop loss percentage.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public AdaptiveFibonacciPullbackStrategy()
{
_atrPeriod = Param(nameof(AtrPeriod), 8)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "ATR period of the SuperTrends", "SuperTrend");
_factor1 = Param(nameof(Factor1), 0.618m)
.SetGreaterThanZero()
.SetDisplay("Factor 1", "Multiplier of the first SuperTrend", "SuperTrend");
_factor2 = Param(nameof(Factor2), 1.618m)
.SetGreaterThanZero()
.SetDisplay("Factor 2", "Multiplier of the second SuperTrend", "SuperTrend");
_factor3 = Param(nameof(Factor3), 2.618m)
.SetGreaterThanZero()
.SetDisplay("Factor 3", "Multiplier of the third SuperTrend", "SuperTrend");
_smoothLength = Param(nameof(SmoothLength), 21)
.SetGreaterThanZero()
.SetDisplay("Smooth Length", "EMA length that smooths the SuperTrend average", "SuperTrend");
_amaLength = Param(nameof(AmaLength), 55)
.SetGreaterThanZero()
.SetDisplay("AMA Length", "Period of the AMA midline", "AMA");
_rsiLength = Param(nameof(RsiLength), 7)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "Period of RSI", "RSI");
_rsiBuy = Param(nameof(RsiBuy), 70m)
.SetDisplay("RSI Buy", "RSI level a long requires to exceed", "RSI");
_rsiSell = Param(nameof(RsiSell), 30m)
.SetDisplay("RSI Sell", "RSI level a short requires to stay below", "RSI");
_takeProfitPercent = Param(nameof(TakeProfitPercent), 5m)
.SetNotNegative()
.SetDisplay("Take Profit %", "Take profit percentage", "Risk");
_stopLossPercent = Param(nameof(StopLossPercent), 0.75m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).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();
_smooth = null;
_prevClose = null;
_prevSmooth = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevClose = null;
_prevSmooth = null;
var st1 = new SuperTrend { Length = AtrPeriod, Multiplier = Factor1 };
var st2 = new SuperTrend { Length = AtrPeriod, Multiplier = Factor2 };
var st3 = new SuperTrend { Length = AtrPeriod, Multiplier = Factor3 };
var ama = new KaufmanAdaptiveMovingAverage { Length = AmaLength };
var rsi = new RelativeStrengthIndex { Length = RsiLength };
_smooth = new ExponentialMovingAverage { Length = SmoothLength };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx([st1, st2, st3, ama, rsi], ProcessCandle)
.Start();
StartProtection(new Unit(TakeProfitPercent, UnitTypes.Percent), new Unit(StopLossPercent, UnitTypes.Percent), useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ama);
DrawOwnTrades(area);
var oscillators = CreateChartArea();
if (oscillators != null)
DrawIndicator(oscillators, rsi);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue[] values)
{
if (candle.State != CandleStates.Finished)
return;
foreach (var value in values)
{
if (!value.IsFormed)
return;
}
var average = (values[0].ToDecimal() + values[1].ToDecimal() + values[2].ToDecimal()) / 3m;
var mid = values[3].ToDecimal();
var rsi = values[4].ToDecimal();
var smoothValue = _smooth.Process(average, candle.ServerTime, true);
if (!_smooth.IsFormed)
return;
var smooth = smoothValue.ToDecimal();
var close = candle.ClosePrice;
var prevClose = _prevClose;
var prevSmooth = _prevSmooth;
_prevClose = close;
_prevSmooth = smooth;
if (prevClose is not decimal pc || prevSmooth is not decimal ps)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var longEntry = candle.LowPrice < average && close > smooth && pc > mid && close > mid && rsi > RsiBuy;
var shortEntry = candle.HighPrice > average && close < smooth && pc < mid && close < mid && rsi < RsiSell;
if (longEntry && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (shortEntry && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
else if (Position > 0 && pc >= ps && close < smooth)
SellMarket(Position);
else if (Position < 0 && pc <= ps && close > smooth)
BuyMarket(-Position);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan, Decimal, Array
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import IIndicator, SuperTrend, ExponentialMovingAverage, KaufmanAdaptiveMovingAverage, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class adaptive_fibonacci_pullback_strategy(Strategy):
"""
Adaptive Fibonacci Pullback strategy.
Three SuperTrend lines with Fibonacci multipliers are averaged and the average is smoothed by an EMA. A long needs the low to dip
below the average while the close stays above the smoothed line, the previous and current close above the Kaufman AMA midline and
RSI above RsiBuy; a short mirrors this with RSI below RsiSell. Positions close when the close crosses the smoothed line against them,
and percent take profit and stop loss protect every trade.
"""
def __init__(self):
super(adaptive_fibonacci_pullback_strategy, self).__init__()
self._atr_period = self.Param("AtrPeriod", 8).SetGreaterThanZero().SetDisplay("ATR Period", "ATR period of the SuperTrends", "SuperTrend")
self._factor1 = self.Param("Factor1", 0.618).SetGreaterThanZero().SetDisplay("Factor 1", "Multiplier of the first SuperTrend", "SuperTrend")
self._factor2 = self.Param("Factor2", 1.618).SetGreaterThanZero().SetDisplay("Factor 2", "Multiplier of the second SuperTrend", "SuperTrend")
self._factor3 = self.Param("Factor3", 2.618).SetGreaterThanZero().SetDisplay("Factor 3", "Multiplier of the third SuperTrend", "SuperTrend")
self._smooth_length = self.Param("SmoothLength", 21).SetGreaterThanZero().SetDisplay("Smooth Length", "EMA length that smooths the SuperTrend average", "SuperTrend")
self._ama_length = self.Param("AmaLength", 55).SetGreaterThanZero().SetDisplay("AMA Length", "Period of the AMA midline", "AMA")
self._rsi_length = self.Param("RsiLength", 7).SetGreaterThanZero().SetDisplay("RSI Length", "Period of RSI", "RSI")
self._rsi_buy = self.Param("RsiBuy", 70.0).SetDisplay("RSI Buy", "RSI level a long requires to exceed", "RSI")
self._rsi_sell = self.Param("RsiSell", 30.0).SetDisplay("RSI Sell", "RSI level a short requires to stay below", "RSI")
self._take_profit_percent = self.Param("TakeProfitPercent", 5.0).SetNotNegative().SetDisplay("Take Profit %", "Take profit percentage", "Risk")
self._stop_loss_percent = self.Param("StopLossPercent", 0.75).SetNotNegative().SetDisplay("Stop Loss %", "Stop loss percentage", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._smooth = None
self._prev_close = None
self._prev_smooth = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(adaptive_fibonacci_pullback_strategy, self).OnReseted()
self._smooth = None
self._prev_close = None
self._prev_smooth = None
def OnStarted2(self, time):
super(adaptive_fibonacci_pullback_strategy, self).OnStarted2(time)
self._prev_close = None
self._prev_smooth = None
st1 = SuperTrend()
st1.Length = self._atr_period.Value
st1.Multiplier = Decimal(self._factor1.Value)
st2 = SuperTrend()
st2.Length = self._atr_period.Value
st2.Multiplier = Decimal(self._factor2.Value)
st3 = SuperTrend()
st3.Length = self._atr_period.Value
st3.Multiplier = Decimal(self._factor3.Value)
ama = KaufmanAdaptiveMovingAverage()
ama.Length = self._ama_length.Value
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_length.Value
self._smooth = ExponentialMovingAverage()
self._smooth.Length = self._smooth_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(Array[IIndicator]([st1, st2, st3, ama, rsi]), self._process_candle).Start()
self.StartProtection(Unit(Decimal(self._take_profit_percent.Value), UnitTypes.Percent), Unit(Decimal(self._stop_loss_percent.Value), UnitTypes.Percent), useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ama)
self.DrawOwnTrades(area)
oscillators = self.CreateChartArea()
if oscillators is not None:
self.DrawIndicator(oscillators, rsi)
def _process_candle(self, candle, values):
if candle.State != CandleStates.Finished:
return
for value in values:
if not value.IsFormed:
return
average = (values[0].GetValue[Decimal](None) + values[1].GetValue[Decimal](None) + values[2].GetValue[Decimal](None)) / Decimal(3)
mid = values[3].GetValue[Decimal](None)
rsi = values[4].GetValue[Decimal](None)
smooth_value = process_value(self._smooth, average, candle.ServerTime, True)
if not self._smooth.IsFormed:
return
smooth = smooth_value.GetValue[Decimal](None)
close = candle.ClosePrice
prev_close = self._prev_close
prev_smooth = self._prev_smooth
self._prev_close = close
self._prev_smooth = smooth
if prev_close is None or prev_smooth is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
long_entry = candle.LowPrice < average and close > smooth and prev_close > mid and close > mid and rsi > Decimal(self._rsi_buy.Value)
short_entry = candle.HighPrice > average and close < smooth and prev_close < mid and close < mid and rsi < Decimal(self._rsi_sell.Value)
if long_entry and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif short_entry and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
elif self.Position > 0 and prev_close >= prev_smooth and close < smooth:
self.SellMarket(self.Position)
elif self.Position < 0 and prev_close <= prev_smooth and close > smooth:
self.BuyMarket(-self.Position)
def CreateClone(self):
return adaptive_fibonacci_pullback_strategy()