Fibonacci-Retracement Umkehrstrategie
Märkte retracieren häufig einen Teil einer vorherigen Bewegung, bevor sie den Trend fortsetzen. Diese Strategie identifiziert jüngste Swing-Hochs und -Tiefs und beobachtet, wie der Kurs die Retracement-Niveaus von 61.8% oder 78.6% testet. Diese Bereiche markieren häufig Erschöpfungspunkte.
Tests zeigen eine durchschnittliche Jahresrendite von etwa 115%. Die Strategie eignet sich am besten für den Aktienmarkt.
Der Algorithmus verfolgt Swings über ein rollendes Fenster und berechnet Fibonacci-Niveaus zwischen ihnen. Wenn der Kurs sich einem wichtigen Retracement nähert und eine Kerze in Richtung des ursprünglichen Trends bildet, wird ein Trade mit einem in festem Prozentabstand platzierten Stop eröffnet. Ziele liegen um den 50%-Mittelpunkt des Swings.
Indem der Fokus auf tiefen Pullbacks innerhalb eines bestehenden Trends liegt, zielt die Methode darauf ab, die frühen Phasen einer Fortsetzungsbewegung zu erfassen, nachdem Verkäufer oder Käufer kurzzeitig die Kontrolle übernommen haben.
Details
- Einstiegskriterien: Kurs testet 61.8%- oder 78.6%-Retracement und bildet eine bestätigende Kerze.
- Long/Short: Beide abhängig vom Trend.
- Ausstiegskriterien: Kurs erreicht das 50%-Niveau oder Stop-Loss.
- Stops: Ja, prozentbasiert.
- Standardwerte:
SwingLookbackPeriod= 20FibLevelBuffer= 0.5 Ein Schlusskurs höchstens so viele Prozent von einem Retracement-Niveau entfernt gilt als Test dieses Niveaus.CandleType= 5 minuteStopLossPercent= 2
- Filter:
- Kategorie: Trendfolge
- Richtung: Beide
- Indikatoren: Fibonacci levels
- Stops: Ja
- Komplexität: Fortgeschritten
- Zeitrahmen: Intraday
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
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()