Die Exp XPVT-Strategie ist eine Konvertierung des MetaTrader 5-Expertenberaters Exp_XPVT. Das System handelt Kreuzungen zwischen dem Price and Volume Trend (PVT)-Indikator und einem konfigurierbaren gleitenden Durchschnitt, der auf die PVT-Serie angewendet wird. Wenn die rohe PVT-Linie unter ihre geglättete Variante fällt, öffnet die Strategie Long-Positionen, während Aufwärtskreuzungen Short-Einstiege auslösen. Optionale Stop-Loss- und Take-Profit-Abstände emulieren das Verhalten des ursprünglichen Expertenberaters.
Indikatorlogik
Der Price and Volume Trend akkumuliert volumengewichtete prozentuale Preisänderungen mithilfe des ausgewählten angewendeten Preises (Schlusskurs, Eröffnung, Median usw.).
Ein Glättungsfilter (SMA, EMA, geglätteter MA, LWMA, Jurik, T3, VIDYA-Näherung oder Kaufman AMA) erzeugt die Signallinie.
Ein historischer Versatz (Signal Bar) recreiert die MT5-Logik: Die Strategie vergleicht geglättete und rohe Werte von einer und zwei Bars zurück, um Kreuzungen und Ausstiegsbedingungen zu erkennen.
Tick- oder reales Volumen kann für die Gewichtung verwendet werden. Wenn der angeforderte Volumentyp nicht verfügbar ist, wechselt die Strategie automatisch zur anderen Quelle.
Handelsregeln
Bei jeder abgeschlossenen Kerze den PVT-Wert aus dem konfigurierten angewendeten Preis und Volumentyp berechnen.
Den Glättungsindikator aktualisieren und die neuesten Werte gemäß Signal Bar speichern.
Wenn die vorherige Bar PVT über der Signallinie zeigte, jede Short-Position schließen. Wenn zusätzlich der zuletzt gespeicherte PVT unter oder gleich der Signallinie ist, eine Long-Position öffnen (wenn Long-Einstiege aktiviert sind).
Wenn die vorherige Bar PVT unter der Signallinie zeigte, jede Long-Position schließen. Wenn zusätzlich der zuletzt gespeicherte PVT über oder gleich der Signallinie ist, eine Short-Position öffnen (wenn Short-Einstiege aktiviert sind).
Nach dem Einstieg in einen Trade werden optionale Stop-Loss- und Take-Profit-Orders mit den konfigurierten Abständen (in Preisschritten) angehängt.
Das Geldmanagement imitiert den ursprünglichen Expertenberater: Neue Orders verwenden das konfigurierte Basis-Order Volume und schließen das entgegengesetzte Exposure ein, um beim Richtungswechsel vollständig umzukehren.
Parameter
Order Volume – Basisvolumen für neue Orders und Umkehrungen.
Stop Loss – Abstand in Preisschritten für den Schutz-Stop (0 deaktiviert ihn).
Take Profit – Abstand in Preisschritten für das Gewinnziel (0 deaktiviert es).
Candle Type – Zeitrahmen für Indikatorberechnungen.
Volume Source – Tick- oder reales Volumen für PVT-Gewichtung wählen.
Smoothing Method / Length / Phase – Gleitender Durchschnitt angewendet auf die PVT-Linie. Der Phase-Parameter wird nur von Jurik-artigen Methoden verwendet.
Applied Price – Preisformel für den PVT (Schlusskurs, Eröffnung, Trendfolge, DeMark usw.).
Signal Bar – Historischer Versatz (in Bars) für die Kreuzungsbewertung, der die MT5-Implementierung reproduziert.
Hinweise
Die Strategie verarbeitet nur abgeschlossene Kerzen, um die Indikatorstabilität zu gewährleisten.
Jurik-artiges Glätten verwendet Reflexion, um den Phase-Parameter weiterzuleiten, wenn der Indikator ihn freigibt.
Wenn weder Tick- noch reales Volumen verfügbar ist, fällt die Strategie auf Nullvolumen zurück, um fehlerhafte Akkumulationen zu verhindern.
Der optionale StartProtection-Aufruf aktiviert das integrierte Positionsmonitoring von StockSharp, entsprechend der einzelnen Aufruf im ursprünglichen Expertenberater.
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;
public class ExpXpvtStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public ExpXpvtStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_prevFast = fastValue; _prevSlow = slowValue;
}
}
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.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class exp_xpvt_strategy(Strategy):
def __init__(self):
super(exp_xpvt_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(exp_xpvt_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(exp_xpvt_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return exp_xpvt_strategy()