Eine Rejection Candle bildet sich, wenn der Preis ein Niveau testet, aber nicht darüber hinaus halten kann, und dabei einen langen Docht und einen kleinen Körper hinterlässt.
Solche Kerzen zeigen an, dass ein Versuch, sich in eine Richtung zu bewegen, vom Markt entschieden abgelehnt wurde.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 49%. Die Strategie funktioniert am besten am Kryptomarkt.
Die Strategie tritt in die entgegengesetzte Richtung des Dochts ein, sobald die Kerze schließt, und erwartet, dass der Preis durch die Range zurückkehrt.
Stops werden außerhalb des abgelehnten Hochs oder Tiefs gesetzt, um das Risiko zu begrenzen, und Trades werden beendet, wenn der Impuls ausbleibt.
Details
Einstiegskriterien: Mustererkennung
Long/Short: Beide
Ausstiegskriterien: Stop-Loss oder entgegengesetztes Signal
Stops: Ja, prozentbasiert
Standardwerte:
CandleType = 15 minute
WickRatio = 1.5
StopLossPercent = 2
Eine Ablehnungskerze sticht unter das Tief (über das Hoch) der Vorkerze, schließt in die Gegenrichtung und hat einen Docht länger als WickRatio Körper. Der Stop liegt StopLossPercent jenseits des abgelehnten Tiefs oder Hochs, und ein Schluss dahinter schließt die Position.
Filter:
Kategorie: Muster
Richtung: Beide
Indikatoren: Candlestick
Stops: Ja
Komplexität: Mittel
Zeitrahmen: Intraday
Saisonalität: Nein
Neuronale Netze: Nein
Divergenz: Nein
Risikolevel: Mittel
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>
/// Rejection Candle strategy.
/// A bullish rejection probes below the previous candle's low, closes up, and has a lower wick longer than WickRatio bodies;
/// a bearish rejection mirrors it above the previous high. While flat the strategy trades against the wick.
/// The stop lies StopLossPercent beyond the rejected low or high, and a close beyond it closes the position.
/// </summary>
public class RejectionCandleStrategy : Strategy
{
private readonly StrategyParam<decimal> _wickRatio;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private ICandleMessage _prevCandle;
private decimal _stopPrice;
/// <summary>
/// How many bodies long the rejecting wick must be.
/// </summary>
public decimal WickRatio
{
get => _wickRatio.Value;
set => _wickRatio.Value = value;
}
/// <summary>
/// Distance of the stop beyond the rejected extreme, 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 RejectionCandleStrategy()
{
_wickRatio = Param(nameof(WickRatio), 1.5m)
.SetGreaterThanZero()
.SetDisplay("Wick Ratio", "How many bodies long the rejecting wick must be", "Pattern");
_stopLossPercent = Param(nameof(StopLossPercent), 2m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Distance of the stop beyond the rejected extreme, 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();
_prevCandle = null;
_stopPrice = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCandle = null;
_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;
var previous = _prevCandle;
_prevCandle = candle;
if (previous == null || !IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
if (Position > 0)
{
if (close <= _stopPrice)
SellMarket(Position);
return;
}
if (Position < 0)
{
if (close >= _stopPrice)
BuyMarket(-Position);
return;
}
var body = Math.Abs(close - candle.OpenPrice);
var upperWick = candle.HighPrice - Math.Max(candle.OpenPrice, close);
var lowerWick = Math.Min(candle.OpenPrice, close) - candle.LowPrice;
if (candle.LowPrice < previous.LowPrice && close > candle.OpenPrice && lowerWick > body * WickRatio)
{
BuyMarket(Volume);
_stopPrice = candle.LowPrice * (1 - StopLossPercent / 100m);
}
else if (candle.HighPrice > previous.HighPrice && close < candle.OpenPrice && upperWick > body * WickRatio)
{
SellMarket(Volume);
_stopPrice = candle.HighPrice * (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, Math, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class rejection_candle_strategy(Strategy):
"""
Rejection Candle strategy.
A bullish rejection probes below the previous candle's low, closes up, and has a lower wick longer than WickRatio bodies;
a bearish rejection mirrors it above the previous high. While flat the strategy trades against the wick.
The stop lies StopLossPercent beyond the rejected low or high, and a close beyond it closes the position.
"""
def __init__(self):
super(rejection_candle_strategy, self).__init__()
self._wick_ratio = self.Param("WickRatio", 1.5).SetGreaterThanZero().SetDisplay("Wick Ratio", "How many bodies long the rejecting wick must be", "Pattern")
self._stop_loss_percent = self.Param("StopLossPercent", 2.0).SetNotNegative().SetDisplay("Stop Loss %", "Distance of the stop beyond the rejected extreme, in percent", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_candle = None
self._stop_price = Decimal(0)
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(rejection_candle_strategy, self).OnReseted()
self._prev_candle = None
self._stop_price = Decimal(0)
def OnStarted2(self, time):
super(rejection_candle_strategy, self).OnStarted2(time)
self._prev_candle = None
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
previous = self._prev_candle
self._prev_candle = candle
if previous is None or 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:
if close >= self._stop_price:
self.BuyMarket(-self.Position)
return
body = Math.Abs(close - candle.OpenPrice)
upper_wick = candle.HighPrice - Math.Max(candle.OpenPrice, close)
lower_wick = Math.Min(candle.OpenPrice, close) - candle.LowPrice
ratio = Decimal(self._wick_ratio.Value)
percent = Decimal(self._stop_loss_percent.Value) / Decimal(100)
if candle.LowPrice < previous.LowPrice and close > candle.OpenPrice and lower_wick > body * ratio:
self.BuyMarket(self.Volume)
self._stop_price = candle.LowPrice * (Decimal(1) - percent)
elif candle.HighPrice > previous.HighPrice and close < candle.OpenPrice and upper_wick > body * ratio:
self.SellMarket(self.Volume)
self._stop_price = candle.HighPrice * (Decimal(1) + percent)
def CreateClone(self):
return rejection_candle_strategy()