Estratégia de Reversão em Retração de Fibonacci
Os mercados frequentemente retraem uma parte de um movimento anterior antes de retomar a tendência. Esta estratégia identifica máximas e mínimas recentes de swing e observa o preço testar os níveis de retração de 61.8% ou 78.6%. Essas áreas frequentemente marcam pontos de esgotamento.
Os testes indicam um retorno anual médio de aproximadamente 115%. Funciona melhor no mercado de ações.
O algoritmo rastreia swings em uma janela deslizante e calcula os níveis de Fibonacci entre eles. Quando o preço se aproxima de uma retração chave e forma uma vela na direção da tendência original, uma operação é aberta com um stop colocado a um percentual fixo. Os alvos ficam em torno do ponto médio de 50% do swing.
Ao focar em retrações profundas dentro de uma tendência existente, o método busca capturar os estágios iniciais de um movimento de continuação após vendedores ou compradores terem assumido o controle brevemente.
Detalhes
- Critérios de entrada: O preço testa a retração de 61.8% ou 78.6% e imprime uma vela de confirmação.
- Comprado/Vendido: Ambos dependendo da tendência.
- Critérios de saída: Preço atingindo o nível de 50% ou stop-loss.
- Stops: Sim, baseados em percentual.
- Valores padrão:
SwingLookbackPeriod= 20FibLevelBuffer= 0.5 Um fechamento a no máximo essa porcentagem de um nível de retração conta como teste do nível.CandleType= 5 minuteStopLossPercent= 2
- Filtros:
- Categoria: Seguidor de tendência
- Direção: Ambos
- Indicadores: Fibonacci levels
- Stops: Sim
- Complexidade: Avançado
- Período: Intradiário
- Sazonalidade: Não
- Redes neurais: Não
- Divergência: Não
- Nível de risco: Médio
using System;
using System.Collections.Generic;
using System.Linq;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Fibonacci Retracement Reversal strategy.
/// The swing is the highest high and lowest low of the previous SwingLookbackPeriod candles; it rose when the low came first.
/// In a rising swing a bullish candle closing within FibLevelBuffer percent of the 61.8% or 78.6% retracement buys,
/// in a falling swing a bearish candle near those levels sells. The target is the swing's 50% level, and a percent stop protects the trade.
/// </summary>
public class FibonacciRetracementReversalStrategy : Strategy
{
private readonly StrategyParam<int> _swingLookbackPeriod;
private readonly StrategyParam<decimal> _fibLevelBuffer;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private readonly List<(decimal High, decimal Low)> _candles = [];
private decimal _target;
/// <summary>
/// Number of previous candles that form the swing.
/// </summary>
public int SwingLookbackPeriod
{
get => _swingLookbackPeriod.Value;
set => _swingLookbackPeriod.Value = value;
}
/// <summary>
/// How close to a retracement level the close must be, in percent of the level.
/// </summary>
public decimal FibLevelBuffer
{
get => _fibLevelBuffer.Value;
set => _fibLevelBuffer.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 FibonacciRetracementReversalStrategy()
{
_swingLookbackPeriod = Param(nameof(SwingLookbackPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Swing Lookback", "Previous candles that form the swing", "Indicators");
_fibLevelBuffer = Param(nameof(FibLevelBuffer), 0.5m)
.SetNotNegative()
.SetDisplay("Level Buffer %", "Distance from a retracement level that counts as a test, in percent", "Indicators");
_stopLossPercent = Param(nameof(StopLossPercent), 2m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk");
_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();
_candles.Clear();
_target = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_candles.Clear();
_target = 0;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
StartProtection(new Unit(), new Unit(StopLossPercent, UnitTypes.Percent), useMarketOrders: true, isLocalStop: true);
// The stop has to see prices between candles, not only at their close.
foreach (var field in new[] { Level1Fields.BestBidPrice, Level1Fields.BestAskPrice })
{
var quotes = new Subscription(DataType.Level1, Security);
quotes.MarketData.BuildField = field;
SubscribeLevel1(quotes).Bind(ObserveProtectionQuote).Start();
}
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ObserveProtectionQuote(Level1ChangeMessage quote)
{
// The high-level handler activates native protection before this callback, also between signal bars.
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
// The swing is formed by the candles before this one.
var swing = _candles.ToArray();
_candles.Add((candle.HighPrice, candle.LowPrice));
if (_candles.Count > SwingLookbackPeriod)
_candles.RemoveAt(0);
if (swing.Length < SwingLookbackPeriod || !IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
if (Position > 0)
{
if (close >= _target)
SellMarket(Position);
return;
}
if (Position < 0)
{
if (close <= _target)
BuyMarket(-Position);
return;
}
var highIndex = Array.FindIndex(swing, c => c.High == swing.Max(x => x.High));
var lowIndex = Array.FindIndex(swing, c => c.Low == swing.Min(x => x.Low));
var high = swing[highIndex].High;
var low = swing[lowIndex].Low;
var range = high - low;
if (range <= 0)
return;
var middle = low + range / 2m;
bool Near(decimal level) => Math.Abs(close - level) <= level * FibLevelBuffer / 100m;
if (lowIndex < highIndex)
{
// Rising swing: buy a bullish candle at a deep pullback.
if (close > candle.OpenPrice && close < middle && (Near(high - range * 0.618m) || Near(high - range * 0.786m)))
{
BuyMarket(Volume);
_target = middle;
}
}
else if (highIndex < lowIndex)
{
// Falling swing: sell a bearish candle at a deep rebound.
if (close < candle.OpenPrice && close > middle && (Near(low + range * 0.618m) || Near(low + range * 0.786m)))
{
SellMarket(Volume);
_target = middle;
}
}
}
}
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, Math, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes, Level1Fields
from StockSharp.BusinessEntities import Subscription
from StockSharp.Algo.Strategies import Strategy
class fibonacci_retracement_reversal_strategy(Strategy):
"""
Fibonacci Retracement Reversal strategy.
The swing is the highest high and lowest low of the previous SwingLookbackPeriod candles; it rose when the low came first.
In a rising swing a bullish candle closing within FibLevelBuffer percent of the 61.8% or 78.6% retracement buys,
in a falling swing a bearish candle near those levels sells. The target is the swing's 50% level, and a percent stop protects the trade.
"""
def __init__(self):
super(fibonacci_retracement_reversal_strategy, self).__init__()
self._swing_lookback_period = self.Param("SwingLookbackPeriod", 20).SetGreaterThanZero().SetDisplay("Swing Lookback", "Previous candles that form the swing", "Indicators")
self._fib_level_buffer = self.Param("FibLevelBuffer", 0.5).SetNotNegative().SetDisplay("Level Buffer %", "Distance from a retracement level that counts as a test, in percent", "Indicators")
self._stop_loss_percent = self.Param("StopLossPercent", 2.0).SetNotNegative().SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._candles = []
self._target = Decimal(0)
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(fibonacci_retracement_reversal_strategy, self).OnReseted()
self._candles = []
self._target = Decimal(0)
def OnStarted2(self, time):
super(fibonacci_retracement_reversal_strategy, self).OnStarted2(time)
self._candles = []
self._target = Decimal(0)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._process_candle).Start()
self.StartProtection(Unit(), Unit(Decimal(self._stop_loss_percent.Value), UnitTypes.Percent), useMarketOrders=True, isLocalStop=True)
# The stop has to see prices between candles, not only at their close.
for field in (Level1Fields.BestBidPrice, Level1Fields.BestAskPrice):
quotes = Subscription(DataType.Level1, self.Security)
quotes.MarketData.BuildField = field
self.SubscribeLevel1(quotes).Bind(self._observe_protection_quote).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _observe_protection_quote(self, quote):
# The high-level handler activates native protection before the callback, including between bars.
pass
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
# The swing is formed by the candles before this one.
period = self._swing_lookback_period.Value
swing = list(self._candles)
self._candles.append((candle.HighPrice, candle.LowPrice))
if len(self._candles) > period:
self._candles.pop(0)
if len(swing) < period or not self.IsFormedAndOnlineAndAllowTrading():
return
close = candle.ClosePrice
if self.Position > 0:
if close >= self._target:
self.SellMarket(self.Position)
return
if self.Position < 0:
if close <= self._target:
self.BuyMarket(-self.Position)
return
high = max(c[0] for c in swing)
low = min(c[1] for c in swing)
high_index = next(i for i, c in enumerate(swing) if c[0] == high)
low_index = next(i for i, c in enumerate(swing) if c[1] == low)
price_range = high - low
if price_range <= 0:
return
middle = low + price_range / Decimal(2)
buffer = Decimal(self._fib_level_buffer.Value) / Decimal(100)
def near(level):
return Math.Abs(close - level) <= level * buffer
if low_index < high_index:
# Rising swing: buy a bullish candle at a deep pullback.
if close > candle.OpenPrice and close < middle and (near(high - price_range * Decimal(0.618)) or near(high - price_range * Decimal(0.786))):
self.BuyMarket(self.Volume)
self._target = middle
elif high_index < low_index:
# Falling swing: sell a bearish candle at a deep rebound.
if close < candle.OpenPrice and close > middle and (near(low + price_range * Decimal(0.618)) or near(low + price_range * Decimal(0.786))):
self.SellMarket(self.Volume)
self._target = middle
def CreateClone(self):
return fibonacci_retracement_reversal_strategy()