Spring Reversal ist ein Wyckoff-Konzept, bei dem der Preis kurz unter den Support bricht und dann wieder darüber zurückspringt.
Dieser Ausschüttler fängt späte Verkäufer in der Falle und markiert oft den Beginn eines Aufwärtstrends.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 55%. Die Strategie funktioniert am besten am Aktienmarkt.
Die Strategie kauft, sobald der Preis das gebrochene Niveau zurückerobert, in Erwartung schneller Short-Eindeckungen und neuer Nachfrage.
Ein Stop knapp unter dem Spring-Tief begrenzt den Nachteil, und die Position wird geschlossen, wenn die Fortsetzung ausbleibt.
Details
Einstiegskriterien: Indikatorsignal
Long/Short: Beide
Ausstiegskriterien: Stop-Loss oder entgegengesetztes Signal
Stops: Ja, prozentbasiert
Standardwerte:
CandleType = 15 minute
LookbackPeriod = 20
StopLossPercent = 2
Die Unterstützung ist das tiefste Tief der vorherigen LookbackPeriod Kerzen. Die Strategie kauft nur: eine bullische Kerze, die die Unterstützung unterschreitet und wieder darüber schließt. Der Stop liegt StopLossPercent unter dem Spring-Tief, und die Position schließt, wenn eine Kerze darunter schließt.
Filter:
Kategorie: Umkehr
Richtung: Beide
Indikatoren: Wyckoff
Stops: Ja
Komplexität: Mittel
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>
/// Spring Reversal strategy.
/// Support is the lowest low of the previous LookbackPeriod candles. A bullish candle that breaks below support and closes back above it
/// is a spring and buys while flat. The stop lies StopLossPercent below the spring low, and a close below it closes the position.
/// </summary>
public class SpringReversalStrategy : Strategy
{
private readonly StrategyParam<int> _lookbackPeriod;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private readonly List<(decimal High, decimal Low)> _candles = [];
private decimal _stopPrice;
/// <summary>
/// Number of previous candles that form the level.
/// </summary>
public int LookbackPeriod
{
get => _lookbackPeriod.Value;
set => _lookbackPeriod.Value = value;
}
/// <summary>
/// Distance of the stop beyond the level, in percent.
/// </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 SpringReversalStrategy()
{
_lookbackPeriod = Param(nameof(LookbackPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("LookbackPeriod", "Number of previous candles that form the level", "Pattern");
_stopLossPercent = Param(nameof(StopLossPercent), 2m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Distance of the stop beyond the level, in percent", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).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();
_stopPrice = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_candles.Clear();
_stopPrice = default;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
// The level is formed by the candles before this one.
var ready = _candles.Count == LookbackPeriod;
var high = ready ? _candles.Max(c => c.High) : 0m;
var low = ready ? _candles.Min(c => c.Low) : 0m;
_candles.Add((candle.HighPrice, candle.LowPrice));
if (_candles.Count > LookbackPeriod)
_candles.RemoveAt(0);
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
if (Position > 0)
{
if (close <= _stopPrice)
SellMarket(Position);
return;
}
if (Position != 0 || !ready || !(candle.LowPrice < low && close > low && close > candle.OpenPrice))
return;
BuyMarket(Volume);
_stopPrice = candle.LowPrice * (1 - StopLossPercent / 100m);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class spring_reversal_strategy(Strategy):
"""
Spring Reversal strategy.
Support is the lowest low of the previous LookbackPeriod candles. A bullish candle that breaks below support and closes back above it
is a spring and buys while flat. The stop lies StopLossPercent below the spring low, and a close below it closes the position.
"""
def __init__(self):
super(spring_reversal_strategy, self).__init__()
self._lookback_period = self.Param("LookbackPeriod", 20).SetGreaterThanZero().SetDisplay("LookbackPeriod", "Number of previous candles that form the level", "Pattern")
self._stop_loss_percent = self.Param("StopLossPercent", 2.0).SetNotNegative().SetDisplay("Stop Loss %", "Distance of the stop beyond the level, in percent", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._candles = []
self._stop_price = Decimal(0)
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(spring_reversal_strategy, self).OnReseted()
self._candles = []
self._stop_price = Decimal(0)
def OnStarted2(self, time):
super(spring_reversal_strategy, self).OnStarted2(time)
self._candles = []
self._stop_price = Decimal(0)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
# The level is formed by the candles before this one.
period = self._lookback_period.Value
ready = len(self._candles) == period
high = max(c[0] for c in self._candles) if ready else Decimal(0)
low = min(c[1] for c in self._candles) if ready else Decimal(0)
self._candles.append((candle.HighPrice, candle.LowPrice))
if len(self._candles) > period:
self._candles.pop(0)
if not self.IsFormedAndOnlineAndAllowTrading():
return
close = candle.ClosePrice
if self.Position > 0:
if close <= self._stop_price:
self.SellMarket(self.Position)
return
if self.Position != 0 or not ready or not (candle.LowPrice < low and close > low and close > candle.OpenPrice):
return
percent = Decimal(self._stop_loss_percent.Value) / Decimal(100)
self.BuyMarket(self.Volume)
self._stop_price = candle.LowPrice * (Decimal(1) - percent)
def CreateClone(self):
return spring_reversal_strategy()