Virtual Profit Close repliziert das Verhalten des MetaTrader 4 Expertenberaters Virtual_Profit_Close.mq4. Die Strategie beobachtet die
aktuelle Position des konfigurierten Wertpapiers und beendet sich, sobald ein virtuelles Gewinnziel erreicht ist. Im Gegensatz zu einer regulären Take-Profit-Order
Das Exit-Level wird intern ausgewertet, sodass keine Gewinnaufträge mehr im Auftragsbuch verbleiben. Ein konfigurierbarer Trailing Stop kann den Ausgang verschieben
Der Preis nähert sich dem Markt an, wenn der Handel Gewinne erwirtschaftet. Im Testmodus kann die Strategie automatisch Probenpositionen öffnen
um seine Logik zu demonstrieren.
Konvertierungshinweise
Tick-Ereignisse werden durch SubscribeTrades().Bind(ProcessTrade).Start() verbraucht, um die ursprüngliche OnTick-Routine nachzuahmen.
MetaTrader „Punkte“ werden in Pips umgewandelt, indem Security.PriceStep überprüft und für 3/5-stellige Symbole angepasst wird.
Virtuelle Gewinn- und Trailing-Berechnungen verwenden den aktuellen Geldkurs für Long-Positionen und den Briefkurs für Short-Positionen, passend zu MQL.
Implementierung, die auf Bid- und Ask-Preisen beruhte.
Die Trailing-Stop-Logik wird nach der konfigurierten Gewinnschwelle aktiviert und hält den Stop in einem festen Abstand zum Markt
Preis, ähnlich dem wiederholten Aufruf von OrderModify in MQL.
Ein Demonstrationsmodus ersetzt den ursprünglichen Strategietester-Helfer (SendTest), indem er Marktaufträge entsprechend der Auswahl öffnet
Richtung und Lautstärke. Optionale Schutzstopps werden mit SetStopLoss platziert.
Parameter
Parameter
Beschreibung
ProfitPips
Virtuelles Take-Profit-Niveau, ausgedrückt in MetaTrader Pips. Die Strategie schließt die Position, sobald der Gewinn diese Distanz überschreitet.
UseTrailingStop
Aktiviert das Nachlaufverhalten, wenn es auf true eingestellt ist.
TrailingOffsetPips
Abstand zwischen dem aktuellen Preis und dem Trailing Stop, sobald dieser aktiv ist.
TrailingActivationPips
Mindestgewinn in Pips erforderlich, bevor der Trailing Stop aktiviert wird.
EnableDemoMode
Öffnet jedes Mal automatisch Demonstrationsaufträge, wenn die Position flach wird. Nützlich für Backtests.
DemoOrderDirection
Richtung der Demo-Bestellungen (Buy oder Sell).
DemoOrderVolume
Für Demobestellungen eingereichtes Volumen.
DemoStopPips
Optionaler Schutzstopp für Demo-Orders, ausgedrückt in Pips.
Verhalten
Wenn die Strategie startet, berechnet sie die Pip-Größe und die Abstände für Gewinn-, Trailing- und Demo-Stops.
Jeder über ProcessTrade empfangene Tick wertet die aktuelle Position aus:
Long-Positionen werden geschlossen, wenn der Geldkurs den konfigurierten virtuellen Gewinn liefert.
Short-Positionen werden geschlossen, wenn der Briefkurs die gleiche Distanz in die entgegengesetzte Richtung zurücklegt.
Wenn Trailing aktiviert ist und der Aktivierungsschwellenwert erreicht ist, bewegt sich der Trailing Stop zusammen mit der günstigen Preisbewegung. Einmal
Wenn der Markt das nachlaufende Niveau überschreitet, sendet die Strategie einen Marktauftrag zum Ausstieg.
Der Demomodus kann automatisch eine neue Position eröffnen, wenn die Strategie flach wird, und stellt so die Nur-Tester-Funktion von wieder her
ursprünglicher Experte.
Anforderungen
Die Strategie benötigt Marktdaten auf Tick-Ebene, um präzise auf Preisänderungen reagieren zu können.
Der Strategieinstanz sollte nur ein Symbol zugewiesen werden. Mehrere gleichzeitige Symbole werden nicht unterstützt und entsprechen dem Original
MQL-Implementierung, die das aktuelle Diagrammsymbol überwacht.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Virtual Profit Close strategy: EMA crossover with profit target management.
/// Enters on EMA crossover, closes when profit target is hit.
/// </summary>
public class VirtualProfitCloseStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
private decimal _entryPrice;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public VirtualProfitCloseStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0m;
_prevSlow = 0m;
_hasPrev = false;
_entryPrice = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
_entryPrice = 0;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, slow, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
if (_hasPrev)
{
if (_prevFast <= _prevSlow && fast > slow && Position <= 0)
{
BuyMarket();
_entryPrice = close;
}
else if (_prevFast >= _prevSlow && fast < slow && Position >= 0)
{
SellMarket();
_entryPrice = close;
}
}
_prevFast = fast;
_prevSlow = slow;
_hasPrev = true;
}
}
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 virtual_profit_close_strategy(Strategy):
def __init__(self):
super(virtual_profit_close_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 20) \
.SetDisplay("Fast Period", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow EMA period", "Indicators")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
self._entry_price = 0.0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
def OnReseted(self):
super(virtual_profit_close_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
self._entry_price = 0.0
def OnStarted2(self, time):
super(virtual_profit_close_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
self._has_prev = False
self._entry_price = 0.0
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(15)))
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
if not self._fast.IsFormed or not self._slow.IsFormed:
return
close = float(candle.ClosePrice)
fast_val = float(fast_value)
slow_val = float(slow_value)
if self._has_prev:
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
self.BuyMarket()
self._entry_price = close
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
self.SellMarket()
self._entry_price = close
self._prev_fast = fast_val
self._prev_slow = slow_val
self._has_prev = True
def CreateClone(self):
return virtual_profit_close_strategy()