Die N-Candles-Strategie scannt den Markt nach aufeinanderfolgenden Kerzen, die alle in dieselbe Richtung schließen. Sobald eine konfigurierbare Anzahl bullischer oder bärischer Kerzen erschienen ist, geht die Strategie in Richtung der Sequenz ein. Die Implementierung ist eine direkte Konvertierung des MetaTrader "N Candles v4" Expert Advisors und bewahrt seine Risikokontrollen, Pip-basierte Konfiguration und optionales Trailing-Stop-Verhalten innerhalb der High-Level-API von StockSharp.
Einstiegsbedingungen
Jede abgeschlossene Kerze wird einmal ausgewertet.
Kerzen, die nach oben schließen, werden als bullisch gezählt, Kerzen, die nach unten schließen, als bärisch, und Doji-Kerzen setzen die Sequenz zurück.
Wenn ConsecutiveCandles bullische (oder bärische) Kerzen in einer Reihe erscheinen, sendet die Strategie eine Market-Order in Richtung der Bewegung.
Hedging-ähnliches Stapeln oder Netting-ähnliche Exposure-Obergrenzen werden je nach gewähltem AccountingMode angewendet.
Exit-Management
StopLossPips und TakeProfitPips definieren statische Exit-Niveaus, gemessen in Pips vom durchschnittlichen Einstiegspreis der aktiven Position.
Wenn TrailingStopPips größer als null ist, folgt das Stop-Niveau dem günstigsten Preis:
Wenn kein fester Stop vorhanden ist (beispielsweise wenn StopLossPips null ist), wartet die Strategie, bis der Preis sich um TrailingStopPips zugunsten des Trades bewegt, bevor ein Break-Even-Stop gesetzt wird.
Sobald ein Stop gesetzt ist, bewegt er sich in Richtung Markt, wenn der Abstand zwischen Preis und Stop TrailingStopPips + TrailingStepPips überschreitet.
Schutz-Niveaus werden neu berechnet, wenn sich die Positionsgröße ändert, und gegen jede abgeschlossene Kerze geprüft, was garantiert, dass jedes Stop-Loss- oder Take-Profit-Ereignis den Trade sofort schließt.
Parameter
Name
Beschreibung
Standard
ConsecutiveCandles
Anzahl identischer Kerzen, die zum Auslösen eines Einstiegs erforderlich sind.
3
TakeProfitPips
Take-Profit-Abstand in Pips. Null zur Deaktivierung des Ziels verwenden.
50
StopLossPips
Stop-Loss-Abstand in Pips. Null zur Deaktivierung des Stops verwenden.
50
TrailingStopPips
Trailing-Stop-Abstand in Pips. Null deaktiviert Trailing.
10
TrailingStepPips
Zusätzliche Bewegung, die erforderlich ist, bevor der Trailing-Stop vorrückt.
4
MaxPositionsPerDirection
Maximale Anzahl gestapelter Einstiege pro Richtung beim Hedging.
2
MaxNetVolume
Maximale absolute Netto-Positionsgröße bei Netting-Modus.
2
AccountingMode
Wechsel zwischen Netting (Volumen-Obergrenze) und Hedging (Einstiegsanzahl-Obergrenze).
Netting
CandleType
Kerzen-Aggregation für die Mustererkennung.
1-Minuten-Kerzen
Alle Pip-basierten Parameter werden anhand der Tick-Größe des Instruments in Preisoffsets umgerechnet. Wenn das Instrument 3 oder 5 Dezimalstellen hat, wird die Pip-Größe um den Faktor zehn skaliert, um die MetaTrader-Definition zu spiegeln.
Implementierungshinweise
Die Strategie basiert auf dem StockSharp High-Level-Kerzenabonnement (SubscribeCandles) und vermeidet manuelle Verlaufspuffer.
Die Schutzlogik verfolgt den höchsten (für Longs) oder niedrigsten (für Shorts) Preis seit dem Einstieg, um das ursprüngliche Trailing-Verhalten zu emulieren.
Positionslimits passen sich automatisch an das Basis-Volume der Strategie an. Eine Erhöhung des Volume erweitert Stop- und Take-Profit-Ordergrößen proportional.
Protokollmeldungen werden ausgegeben, wenn ein Schutz-Exit (Stop oder Take-Profit) eine Position schließt, was Klarheit während Backtests bietet.
Verwendungstipps
Hedging-Modus wählen, wenn Plattformen simuliert werden, die mehrere Tickets pro Richtung erlauben, oder bei Netting bleiben, um Einzel-Positions-Konten zu spiegeln.
TrailingStepPips auf null setzen für einen klassischen Trailing-Stop, der sich immer bewegt, wenn der Markt um TrailingStopPips vorrückt.
Da Exits auf abgeschlossenen Kerzen ausgewertet werden, ein kürzeres Kerzenintervall in Betracht ziehen, wenn Intrabar-Präzision entscheidend ist.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy that opens positions after detecting N identical candles in a row.
/// Enters in the direction of the candle streak.
/// </summary>
public class NCandlesSequenceStrategy : Strategy
{
private readonly StrategyParam<int> _consecutiveCandles;
private readonly StrategyParam<DataType> _candleType;
private int _consecutiveDirection;
private int _consecutiveCount;
/// <summary>
/// Number of identical candles required before entering a trade.
/// </summary>
public int ConsecutiveCandles
{
get => _consecutiveCandles.Value;
set => _consecutiveCandles.Value = value;
}
/// <summary>
/// Candle type used for pattern detection.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of the strategy.
/// </summary>
public NCandlesSequenceStrategy()
{
_consecutiveCandles = Param(nameof(ConsecutiveCandles), 3)
.SetGreaterThanZero()
.SetDisplay("Consecutive Candles", "Number of identical candles in a row", "Entry")
.SetOptimize(2, 6, 1);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to analyze", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_consecutiveDirection = 0;
_consecutiveCount = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_consecutiveDirection = 0;
_consecutiveCount = 0;
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 direction = GetCandleDirection(candle);
if (direction == 0)
{
_consecutiveDirection = 0;
_consecutiveCount = 0;
return;
}
if (direction == _consecutiveDirection)
{
_consecutiveCount++;
}
else
{
_consecutiveDirection = direction;
_consecutiveCount = 1;
}
if (_consecutiveCount < ConsecutiveCandles)
return;
if (direction > 0 && Position <= 0)
{
BuyMarket();
}
else if (direction < 0 && Position >= 0)
{
SellMarket();
}
}
private static int GetCandleDirection(ICandleMessage candle)
{
if (candle.ClosePrice > candle.OpenPrice)
return 1;
if (candle.ClosePrice < candle.OpenPrice)
return -1;
return 0;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class n_candles_sequence_strategy(Strategy):
"""Opens positions after detecting N identical-direction candles in a row."""
def __init__(self):
super(n_candles_sequence_strategy, self).__init__()
self._consecutive = self.Param("ConsecutiveCandles", 3) \
.SetGreaterThanZero() \
.SetDisplay("Consecutive Candles", "Number of identical candles in a row", "Entry")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Type of candles to analyze", "General")
self._direction = 0
self._count = 0
@property
def ConsecutiveCandles(self):
return self._consecutive.Value
@property
def CandleType(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(n_candles_sequence_strategy, self).OnStarted2(time)
self._direction = 0
self._count = 0
subscription = self.SubscribeCandles(self.CandleType)
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
d = 0
if float(candle.ClosePrice) > float(candle.OpenPrice):
d = 1
elif float(candle.ClosePrice) < float(candle.OpenPrice):
d = -1
if d == 0:
self._direction = 0
self._count = 0
return
if d == self._direction:
self._count += 1
else:
self._direction = d
self._count = 1
if self._count < self.ConsecutiveCandles:
return
if d > 0 and self.Position <= 0:
self.BuyMarket()
elif d < 0 and self.Position >= 0:
self.SellMarket()
def OnReseted(self):
super(n_candles_sequence_strategy, self).OnReseted()
self._direction = 0
self._count = 0
def CreateClone(self):
return n_candles_sequence_strategy()