Die Conditional Position Opener Strategy reproduziert das Verhalten des ursprünglichen MetaTrader-Skripts „Eine Kaufposition eröffnen, wenn keine offene Position vorhanden ist“. Die Logik ist bewusst einfach: Wenn manuelle Schalter die Long- oder Short-Seite aktivieren, sendet die Strategie nur dann eine Marktorder, wenn in dieser Richtung kein offenes Exposure besteht. Dies verhindert doppelte Einträge und hält die Position an der ausgewählten Seite ausgerichtet.
Der StockSharp-Port sorgt dafür, dass der Implementierungsmakler neutral bleibt, indem er sich auf das High-Level-Candle-Abonnement und den integrierten Schutzhelfer des Frameworks verlässt. Stop-Loss- und Take-Profit-Abstände werden in Pip-Einheiten (Preisschritten) angegeben, sodass sie an jedes Instrument angepasst werden können.
Strategielogik
Abonnieren Sie die konfigurierte Kerzenserie, um als Timing-Herzschlag zu fungieren.
Überprüfen Sie bei jeder fertigen Kerze die aktuelle Nettoposition.
Wenn der Long-Schalter aktiviert ist und die Position flach oder short ist, senden Sie eine Kauf-Market-Order.
Wenn der Short-Schalter aktiviert ist und die Position flach oder long ist, senden Sie eine Marktverkaufsorder.
Schutzaufträge werden automatisch über StartProtection verwaltet, das die Pip-Abstände in tatsächliche Preisversätze umwandelt.
Da StockSharp Nettopositionen verwendet, wird durch die gleichzeitige Aktivierung beider Seiten zuerst der Long-Trade und dann, wenn er nach der Füllung immer noch flach ist, der Short-Trade eröffnet. Dies spiegelt die Absicht des MQL-Codes wider, der mehrere Bestellungen pro Richtung vermeidet.
Parameter
Name
Standard
Beschreibung
Volume
1
Ordergröße für jeden Markteintritt.
StopLossPips
100
Stop-Loss-Distanz ausgedrückt in Preisschritten. Zum Deaktivieren auf Null setzen.
TakeProfitPips
200
Take-Profit-Distanz, ausgedrückt in Preisschritten. Zum Deaktivieren auf Null setzen.
EnableBuy
false
Bei true kann die Strategie Long-Positionen eröffnen, wenn kein Long-Engagement besteht.
EnableSell
false
Bei true kann die Strategie Short-Positionen eröffnen, wenn kein Short-Engagement besteht.
CandleType
1 minute timeframe
Kerzenreihe, die die periodische Auswertung vorantreibt.
Notizen
Entfernungen werden mithilfe des PriceStep des Instruments in tatsächliche Preiserhöhungen umgerechnet. Wenn die Börse dies nicht meldet, wird der rohe Pip-Wert als absoluter Offset verwendet.
StartProtection fügt nach jeder Ausführung automatisch Stop-Loss- und Take-Profit-Orders hinzu, sodass keine manuelle Orderverwaltung erforderlich ist.
Die Strategie konzentriert sich auf die manuelle Auslösung und ist als Vorlage für die diskretionäre Ausführung über Parameter gedacht.
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simplified from "Conditional Position Opener" MetaTrader expert.
/// Uses Momentum indicator to conditionally open long or short positions.
/// Opens long when momentum is positive, short when negative.
/// </summary>
public class ConditionalPositionOpenerStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _momentumPeriod;
private Momentum _momentum;
private decimal? _prevMomentum;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int MomentumPeriod
{
get => _momentumPeriod.Value;
set => _momentumPeriod.Value = value;
}
public ConditionalPositionOpenerStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for signal generation", "General");
_momentumPeriod = Param(nameof(MomentumPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Momentum Period", "Momentum indicator period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevMomentum = null;
_momentum = new Momentum { Length = MomentumPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_momentum, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal momentumValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_momentum.IsFormed)
{
_prevMomentum = momentumValue;
return;
}
if (_prevMomentum is null)
{
_prevMomentum = momentumValue;
return;
}
var volume = Volume;
if (volume <= 0)
volume = 1;
// Cross above 101 (positive momentum)
var crossUp = _prevMomentum.Value <= 101m && momentumValue > 101m;
// Cross below 99 (negative momentum)
var crossDown = _prevMomentum.Value >= 99m && momentumValue < 99m;
if (crossUp)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
else if (crossDown)
{
if (Position >= 0)
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
_prevMomentum = momentumValue;
}
/// <inheritdoc />
protected override void OnReseted()
{
_momentum = null;
_prevMomentum = null;
base.OnReseted();
}
}