Risikoüberwachungsstrategie
Überblick
Risk Monitor Strategy ist eine Portierung des MetaTrader 4 Expert Advisors risk.mq4. Das Originalskript eröffnete nie Trades; stattdessen es
ermittelte anhand des Kontostands und eines benutzerdefinierten Risikoprozentsatzes, wie viele Lots der Händler sicher einsetzen konnte. Dies
Die StockSharp-Version behält den gleichen Geist bei: Sie führt eine kontinuierliche Kontodiagnose durch, berechnet empfohlene Handelsgrößen und überwacht
variable und realisierte Gewinne und veröffentlicht die Ergebnisse direkt im Strategiekommentar für eine schnelle Entscheidungsfindung.
Im Gegensatz zu herkömmlichen Strategien versendet die Risk Monitor Strategy keine Aufträge automatisch. Seine Rolle ist die Aufsicht: Es gibt die
Händler eine Momentaufnahme des aktuellen Engagements, der verfügbaren Kapazität gemäß dem gewählten Risikobudget und der Rentabilität der geschlossenen Geschäfte
Positionen. Die Kommentarzeile wird jedes Mal aktualisiert, wenn sich Positionen, PnL oder Trades ändern, sodass die Informationen immer auf dem neuesten Stand sind
Portfoliostatus.
Berechnungen
Die Strategie leitet die im Kommentar angezeigten Zahlen aus drei Datengruppen ab:
- Grundlosgröße – berechnet als
AccountBalance / 1000 und abgestimmt auf den Sicherheitsvolumenschritt. Dies spiegelt das Original wider
MT4-Logik, bei der alle 1000 Guthabeneinheiten einem Standardlos entsprechen.
- Risikolosgröße – multipliziert die Basislose mit
Risk % / 100, richtet das Ergebnis auf den Volumenschritt aus und gibt an, wie viele
Lose können unter Einhaltung des konfigurierten Risikobudgets eröffnet werden.
- Offene Lots & Differenz – vergleicht die absolute Nettoposition mit der Risikolosgröße. Liegt der Händler unter dem Schwellenwert,
Die Differenz zeigt an, wie viele Lose noch verfügbar sind, bevor das Limit erreicht wird. Eine winzige negative Differenz, die kleiner ist als
Der Lautstärkeschritt wird auf Null gerundet, um verwirrendes Rauschen zu vermeiden.
Bei Gewinnen unterscheidet die Strategie zwischen variablen und realisierten Werten:
- Floating PnL – aus der Strategieeigenschaft
PnL gelesen und sowohl in Preiseinheiten als auch als Prozentsatz des aktuellen Wertes ausgedrückt
Portfoliowert.
- Realisierter Gewinn – angesammelt aus eigenen Geschäften. Die Komponente teilt jede abschließende Füllung in positive und negative Teile auf,
wendet die gemeldete Provision an und führt eine laufende Summe. Die endgültige Zahl wird auch in einen Prozentsatz des Eigenkapitals umgerechnet
mit der MT4-Anzeige übereinstimmen.
Parameter
- Risiko % – Teil des Kontostands, der für neue Positionen reserviert werden kann. Standard:
10. Der Parameter ist verfügbar für
Optimierung, sodass unterschiedliche Risikobudgets schnell rückgetestet werden können.
Die Strategie aktualisiert den Kommentar mit drei Zeilen:
Base lots, Risk lots, Open lots, Lots to adjust – Schnellansicht der Positionsgrößenmetriken.
Risk, Floating PnL – Risikoeinstellung, variabler Gewinn in Währungseinheiten und variabler Gewinn in Prozent des Saldos.
Realized profit – kumulierter geschlossener Gewinn und sein Prozentsatz.
Alle Werte werden ähnlich wie beim MT4-Skript gerundet, wobei der Sicherheitslosschritt berücksichtigt und zwei Dezimalstellen für den Geldwert verwendet werden
Zahlen. Da sich die Ausgabe im Kommentar befindet, ist sie sofort im Diagramm oder im Strategieraster sichtbar, ohne dass sie geöffnet werden muss
zusätzliche Panels.
Nutzungshinweise
- Hängen Sie die Strategie an das Instrument an, dessen Balance und Position Sie überwachen möchten. Es funktioniert mit Nettopositionen (kein MT4-Stil).
Absicherung) genau wie StockSharp selbst.
- Die Strategie toleriert den manuellen Handel: Sie reagiert auf alle Handelsbestätigungen, um die Statistiken synchron zu halten.
- Der Kommentar wird automatisch gelöscht, wenn die Strategie beendet oder zurückgesetzt wird, wodurch verhindert wird, dass veraltete Werte über Sitzungen hinweg bestehen bleiben.
- Es wird keine Python-Implementierung bereitgestellt. Das Paket API enthält nur die C#-Version.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Risk-aware EMA crossover strategy inspired by the original MT4 Risk Monitor script.
/// Uses a risk percentage of account balance to size positions, combined with EMA crossover signals.
/// Tracks realized gains/losses and adjusts lot sizing accordingly.
/// </summary>
public class RiskMonitorStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _riskPercent;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<decimal> _takeProfitPoints;
private readonly StrategyParam<decimal> _stopLossPoints;
private ExponentialMovingAverage _fastEma;
private ExponentialMovingAverage _slowEma;
private decimal? _prevFast;
private decimal? _prevSlow;
/// <summary>
/// Candle type used for signal detection.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Percentage of the account balance allocated to new positions.
/// </summary>
public decimal RiskPercent
{
get => _riskPercent.Value;
set => _riskPercent.Value = value;
}
/// <summary>
/// Fast EMA period.
/// </summary>
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
/// <summary>
/// Slow EMA period.
/// </summary>
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
/// <summary>
/// Take profit distance in absolute points.
/// </summary>
public decimal TakeProfitPoints
{
get => _takeProfitPoints.Value;
set => _takeProfitPoints.Value = value;
}
/// <summary>
/// Stop loss distance in absolute points.
/// </summary>
public decimal StopLossPoints
{
get => _stopLossPoints.Value;
set => _stopLossPoints.Value = value;
}
/// <summary>
/// Initializes a new instance of <see cref="RiskMonitorStrategy"/>.
/// </summary>
public RiskMonitorStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle series used for calculations", "General");
_riskPercent = Param(nameof(RiskPercent), 10m)
.SetGreaterThanZero()
.SetDisplay("Risk %", "Portion of balance used to size positions", "Risk Management")
.SetOptimize(5m, 30m, 5m);
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
.SetOptimize(5, 30, 5);
_slowPeriod = Param(nameof(SlowPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
.SetOptimize(20, 80, 10);
_takeProfitPoints = Param(nameof(TakeProfitPoints), 500m)
.SetNotNegative()
.SetDisplay("Take Profit", "Absolute take profit distance", "Risk");
_stopLossPoints = Param(nameof(StopLossPoints), 500m)
.SetNotNegative()
.SetDisplay("Stop Loss", "Absolute stop loss distance", "Risk");
Volume = 1;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_fastEma = null;
_slowEma = null;
_prevFast = null;
_prevSlow = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
_fastEma = new ExponentialMovingAverage { Length = FastPeriod };
_slowEma = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_fastEma, _slowEma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _fastEma);
DrawIndicator(area, _slowEma);
DrawOwnTrades(area);
}
if (TakeProfitPoints > 0 || StopLossPoints > 0)
{
var tp = TakeProfitPoints > 0 ? new Unit(TakeProfitPoints, UnitTypes.Absolute) : null;
var sl = StopLossPoints > 0 ? new Unit(StopLossPoints, UnitTypes.Absolute) : null;
StartProtection(tp, sl);
}
base.OnStarted2(time);
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished)
return;
var pf = _prevFast;
var ps = _prevSlow;
_prevFast = fastValue;
_prevSlow = slowValue;
if (pf == null || ps == null)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Detect crossover
var prevDiff = pf.Value - ps.Value;
var currDiff = fastValue - slowValue;
if (prevDiff <= 0 && currDiff > 0)
{
// Bullish crossover
if (Position < 0)
BuyMarket(Math.Abs(Position));
if (Position == 0)
BuyMarket(Volume);
}
else if (prevDiff >= 0 && currDiff < 0)
{
// Bearish crossover
if (Position > 0)
SellMarket(Position);
if (Position == 0)
SellMarket(Volume);
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates, UnitTypes, Unit
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class risk_monitor_strategy(Strategy):
def __init__(self):
super(risk_monitor_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 10).SetGreaterThanZero().SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 30).SetGreaterThanZero().SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._tp_points = self.Param("TakeProfitPoints", 500.0).SetNotNegative().SetDisplay("Take Profit", "TP distance", "Risk")
self._sl_points = self.Param("StopLossPoints", 500.0).SetNotNegative().SetDisplay("Stop Loss", "SL distance", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candle timeframe", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(risk_monitor_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
self._entry_price = 0
def OnStarted2(self, time):
super(risk_monitor_strategy, self).OnStarted2(time)
self._prev_fast = None
self._prev_slow = None
self._entry_price = 0
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self._fast_period.Value
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self._slow_period.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(fast_ema, slow_ema, self.OnProcess).Start()
tp_val = float(self._tp_points.Value)
sl_val = float(self._sl_points.Value)
tp = Unit(tp_val, UnitTypes.Absolute) if tp_val > 0 else None
sl = Unit(sl_val, UnitTypes.Absolute) if sl_val > 0 else None
self.StartProtection(tp, sl)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, fast_ema)
self.DrawIndicator(area, slow_ema)
self.DrawOwnTrades(area)
def OnProcess(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
pf = self._prev_fast
ps = self._prev_slow
self._prev_fast = fast_val
self._prev_slow = slow_val
if pf is None or ps is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
prev_diff = pf - ps
curr_diff = fast_val - slow_val
if prev_diff <= 0 and curr_diff > 0:
if self.Position < 0:
self.BuyMarket(abs(self.Position))
if self.Position == 0:
self.BuyMarket(self.Volume)
elif prev_diff >= 0 and curr_diff < 0:
if self.Position > 0:
self.SellMarket(self.Position)
if self.Position == 0:
self.SellMarket(self.Volume)
def CreateClone(self):
return risk_monitor_strategy()