Diese Strategie portiert den MetaTrader-Experten Vortex Indicator System.mq4 in die StockSharp-Hochebene API. Die ursprüngliche Idee war
ist in Technical Analysis of Stocks & Commodities (Januar 2010) veröffentlicht und basiert auf dem Vortex-Indikator-Crossover zum Armbre
Erteilen Sie Aufträge zum Hoch/Tief der Crossover-Kerze. Die StockSharp-Version behält den gleichen Entscheidungsfluss bei: Ein Crossover schließt die
Die entgegengesetzte Position aktiviert einen Ausbruchsauslöser am Extrempunkt des Crossover-Balkens und die nächste Kerze, die dieses Niveau durchbricht, führt den aus
Marktordnung.
Wie es funktioniert
Ein einzelnes Kerzenabonnement wird gemäß CandleType eröffnet. Der resultierende Stream ist an ein VortexIndicator Insta gebunden
Sobald Bind verwendet wird, erhält die Strategie immer synchronisierte VI+- und VI--Werte für die fertigen Kerzen.
Wenn das Aufwärmen des Indikators abgeschlossen ist, verfolgt der Algorithmus die vorherigen VI-Werte, um die gleichen Übergangsbedingungen u zu erkennen
sed im MQL-Experten: VI+ Kreuzung über VI- oder umgekehrt zwischen den letzten beiden geschlossenen Kerzen.
Setup-Phase – Sobald ein bullischer Crossover erkannt wird, wird jede offene Short-Position sofort geschlossen und das Hoch von th
Die Crossover-Kerze wird zum ausstehenden Long-Trigger. Der entgegengesetzte Crossover schließt eine bestehende Long-Position und speichert das Tief
dieses Balkens als Short-Trigger.
Triggerphase – bei jeder weiteren abgeschlossenen Kerze prüft die Strategie, ob der aufgezeichnete Triggerpreis berührt wurde („Hi
ghPrice≥ long trigger orLowPrice≤ kurzer Trigger). Wenn dies der Fall ist, übermittelt es eine Marktorder, die so dimensioniert ist, dass beide den verbleibenden Gegner glätten Site-Präsenz (falls die vorherige Bestellung noch nicht abgeschlossen wurde) und eröffnen Sie eine neue Position mitTradeVolume`.
Sobald ein Auftrag ausgelöst wird, wird der entsprechende Auslöser gelöscht. Wenn kein Ausbruch erfolgt, bleibt das Setup bis zu einem neuen Crossove aktiv
r überschreibt es.
Ausgänge basieren ausschließlich auf der Crossover-Logik: Das entgegengesetzte Signal glättet sofort die aktuelle Position und aktiviert ein neues b
Reakout-Trigger, der die MetaTrader-Implementierung widerspiegelt.
Signale
Bullisches Setup – tritt auf, wenn VI+ bei der vorherigen geschlossenen Kerze unter oder gleich VI- war und am längsten darüber steigt
Neustes. Der Long-Trigger ist auf das Hoch dieser Kerze eingestellt.
Bullische Ausführung – die nächste Kerze, deren Hoch den Auslöser erreicht, sendet eine Marktkauforder mit TradeVolume (plus etwaiger Vo
(die zum Schließen einer ausstehenden Short-Position erforderliche Leuchtkraft).
Bearisches Setup – tritt auf, wenn VI- bei der vorherigen geschlossenen Kerze unter oder gleich VI+ war und am längsten darüber steigt
Neustes. Der Short-Trigger ist auf das Tief dieser Kerze eingestellt.
Bearische Ausführung – die nächste Kerze, deren Tief den Auslöser berührt, sendet einen Marktverkaufsauftrag mit TradeVolume (plus dem Vo
erforderliche Lichtstärke, um eine offene Long-Position abzuflachen).
Parameter
Parameter
Standard
Beschreibung
VortexLength
14
Auf den Vortex-Indikator angewendeter Zeitraum.
CandleType
1 Stunde
Zeitrahmen für Kerzen und Indikatoraktualisierungen.
TradeVolume
1
Market-Order-Größe, die für Neuzugänge verwendet wird.
Hinweise zur Implementierung
Die Strategie reagiert nur auf fertige Kerzen, um den Konvertierungsrichtlinien zu entsprechen. Intrabar-Ausbrüche werden erkannt
Sobald eine Kerze mit einem Hoch/Tief über dem gespeicherten Auslöser schließt.
Ausstehende Trigger werden am OnStopped gelöscht, sodass die Instanz sauber und ohne verbleibenden Status neu gestartet werden kann.
Bei der Ausführung einer Breakout-Order erhöht der Algorithmus das Volumen, wenn er immer noch eine entgegengesetzte Position hält, und erreicht so das gleiche, z
Wirkung als MetaTrader-Experte, der die aktive Bestellung schloss, bevor die neue geöffnet wurde.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Vortex Indicator Breakout: Dual EMA crossover breakout with ATR stops.
/// </summary>
public class VortexIndicatorBreakoutStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastEmaLength;
private readonly StrategyParam<int> _slowEmaLength;
private readonly StrategyParam<int> _atrLength;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
public VortexIndicatorBreakoutStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(2).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_fastEmaLength = Param(nameof(FastEmaLength), 14)
.SetDisplay("Fast EMA", "Fast EMA period.", "Indicators");
_slowEmaLength = Param(nameof(SlowEmaLength), 28)
.SetDisplay("Slow EMA", "Slow EMA period.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastEmaLength
{
get => _fastEmaLength.Value;
set => _fastEmaLength.Value = value;
}
public int SlowEmaLength
{
get => _slowEmaLength.Value;
set => _slowEmaLength.Value = value;
}
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0;
_prevSlow = 0;
_entryPrice = 0;
var fastEma = new ExponentialMovingAverage { Length = FastEmaLength };
var slowEma = new ExponentialMovingAverage { Length = SlowEmaLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastEma, slowEma, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastEma);
DrawIndicator(area, slowEma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevFast == 0 || _prevSlow == 0 || atrVal <= 0)
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
var close = candle.ClosePrice;
if (Position > 0)
{
if (fastVal < slowVal && _prevFast >= _prevSlow)
{
SellMarket();
_entryPrice = 0;
}
else if (close <= _entryPrice - atrVal * 2m)
{
SellMarket();
_entryPrice = 0;
}
}
else if (Position < 0)
{
if (fastVal > slowVal && _prevFast <= _prevSlow)
{
BuyMarket();
_entryPrice = 0;
}
else if (close >= _entryPrice + atrVal * 2m)
{
BuyMarket();
_entryPrice = 0;
}
}
if (Position == 0)
{
if (fastVal > slowVal && _prevFast <= _prevSlow)
{
_entryPrice = close;
BuyMarket();
}
else if (fastVal < slowVal && _prevFast >= _prevSlow)
{
_entryPrice = close;
SellMarket();
}
}
_prevFast = fastVal;
_prevSlow = slowVal;
}
}
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
from StockSharp.Algo.Indicators import ExponentialMovingAverage, AverageTrueRange
class vortex_indicator_breakout_strategy(Strategy):
def __init__(self):
super(vortex_indicator_breakout_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(2))) \
.SetDisplay("Candle Type", "Timeframe.", "General")
self._fast_ema_length = self.Param("FastEmaLength", 14) \
.SetDisplay("Fast EMA", "Fast EMA period.", "Indicators")
self._slow_ema_length = self.Param("SlowEmaLength", 28) \
.SetDisplay("Slow EMA", "Slow EMA period.", "Indicators")
self._atr_length = self.Param("AtrLength", 14) \
.SetDisplay("ATR Length", "ATR period.", "Indicators")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastEmaLength(self):
return self._fast_ema_length.Value
@property
def SlowEmaLength(self):
return self._slow_ema_length.Value
@property
def AtrLength(self):
return self._atr_length.Value
def OnStarted2(self, time):
super(vortex_indicator_breakout_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._fast_ema = ExponentialMovingAverage()
self._fast_ema.Length = self.FastEmaLength
self._slow_ema = ExponentialMovingAverage()
self._slow_ema.Length = self.SlowEmaLength
self._atr = AverageTrueRange()
self._atr.Length = self.AtrLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._fast_ema, self._slow_ema, self._atr, self.ProcessCandle).Start()
def ProcessCandle(self, candle, fast_val, slow_val, atr_val):
if candle.State != CandleStates.Finished:
return
fv = float(fast_val)
sv = float(slow_val)
av = float(atr_val)
if self._prev_fast == 0 or self._prev_slow == 0 or av <= 0:
self._prev_fast = fv
self._prev_slow = sv
return
close = float(candle.ClosePrice)
if self.Position > 0:
if fv < sv and self._prev_fast >= self._prev_slow:
self.SellMarket()
self._entry_price = 0.0
elif close <= self._entry_price - av * 2.0:
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0:
if fv > sv and self._prev_fast <= self._prev_slow:
self.BuyMarket()
self._entry_price = 0.0
elif close >= self._entry_price + av * 2.0:
self.BuyMarket()
self._entry_price = 0.0
if self.Position == 0:
if fv > sv and self._prev_fast <= self._prev_slow:
self._entry_price = close
self.BuyMarket()
elif fv < sv and self._prev_fast >= self._prev_slow:
self._entry_price = close
self.SellMarket()
self._prev_fast = fv
self._prev_slow = sv
def OnReseted(self):
super(vortex_indicator_breakout_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
def CreateClone(self):
return vortex_indicator_breakout_strategy()