Estrategia de Reversión en Retroceso de Fibonacci
Los mercados frecuentemente retroceden una parte de un movimiento anterior antes de reanudar la tendencia. Esta estrategia identifica los máximos y mínimos recientes del swing y vigila que el precio pruebe los niveles de retroceso del 61.8% o el 78.6%. Estas áreas frecuentemente marcan puntos de agotamiento.
Las pruebas indican un rendimiento anual promedio de aproximadamente el 115%. Funciona mejor en el mercado de acciones.
El algoritmo rastrea los swings en una ventana deslizante y calcula los niveles de Fibonacci entre ellos. Cuando el precio se acerca a un retroceso clave y forma una vela en la dirección de la tendencia original, se abre una operación con un stop colocado a un porcentaje fijo. Los objetivos se sitúan alrededor del punto medio del 50% del swing.
Al centrarse en retrocesos profundos dentro de una tendencia existente, el método busca capturar las etapas iniciales de un movimiento de continuación después de que vendedores o compradores hayan tomado el control brevemente.
Detalles
- Criterios de entrada: El precio prueba el retroceso del 61.8% o el 78.6% e imprime una vela de confirmación.
- Largo/Corto: Ambos dependiendo de la tendencia.
- Criterios de salida: Precio alcanzando el nivel del 50% o stop-loss.
- Stops: Sí, basados en porcentaje.
- Valores predeterminados:
SwingLookbackPeriod= 20FibLevelBuffer= 0.5 Un cierre a menos de este porcentaje de un nivel de retroceso cuenta como prueba del nivel.CandleType= 5 minuteStopLossPercent= 2
- Filtros:
- Categoría: Seguimiento de tendencia
- Dirección: Ambos
- Indicadores: Fibonacci levels
- Stops: Sí
- Complejidad: Avanzado
- Marco temporal: Intradía
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
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()