Die Lavika100-Strategie ist eine getreue Portierung des MetaTrader-5 Expert Advisors "Lavika cent". Das System kombiniert einen einstündigen (H1) und einen vierstündigen (H4) RAVI-Momentum-Filter, um zu entscheiden, wann Trades eröffnet werden. Es behält die ursprünglichen Money-Management-Optionen (fester Lot oder Risikoprozentsatz), Ein-Positions-Disziplin, optionale Signalumkehr und automatische Stop-Verwaltung bei. Die StockSharp-Version hält sich an die High-Level-API-Richtlinien: Kerzenabonnements treiben den Ablauf, Indikatoren werden über Binder angesprochen und Schutzorders werden mit StartProtection konfiguriert.
Ablauf
Datenabonnements - die Strategie abonniert H1-Kerzen für den Ausführungszeitrahmen und H4-Kerzen für den Trendfilter. Der SimpleMovingAverage-Indikator wird auf die Eröffnungspreise angewendet, um die MT5-Aufrufe iMA(..., PRICE_OPEN) nachzubilden.
RAVI-Momentum - zwei gleitende Durchschnitte auf jedem Zeitrahmen (schnell/langsam) erzeugen einen "RAVI"-Prozentsatz: (fast - slow) / slow * 100. Der H1-Wert muss positiv sein, bevor ein Trade in Betracht gezogen wird.
Erkennung des Trendmusters - die vier jüngsten RAVI-Werte auf H4 werden geprüft:
Eine steigende Sequenz (r0 > r1, r1 < r2, r2 < r3) löst ein Long-Signal aus.
Eine fallende Sequenz (r0 < r1, r1 > r2, r2 > r3) löst ein Short-Signal aus. Dies spiegelt das Verhalten des ursprünglichen Codes, obwohl der Expert Advisor die Richtung nur über das Reverse-Flag wechselte.
Signalumkehr und Glattstellung - je nach den Parametern ReverseSignals und CloseOpposite eröffnet der Algorithmus in der erkannten Richtung oder kehrt sie um und schließt zuvor jede Gegenposition.
Money Management - das Volumen stammt aus FixedVolume oder wird über die Methode RiskPercent nach Risiko skaliert (Portfoliowert * Prozentsatz / Stop-Distanz).
Schutz - Stop-Loss, Take-Profit, Trailing Stop und Trailing-Schritt werden über StartProtection aktiviert, sobald die Strategie startet und die Parameter ungleich null sind.
Handelsregeln
Long-Einstieg - H1 RAVI ist positiv und die H4-Reihe zeigt ein steigendes Muster. Die Strategie schließt vor dem Kauf eine bestehende Short-Position, wenn CloseOpposite=true ist.
Short-Einstieg - H1 RAVI ist positiv und die H4-Reihe zeigt ein fallendes Muster. Wenn ReverseSignals=true ist, werden die Richtungen getauscht, passend zum MT5-Schalter "Reverse".
Einzelposition - mit OnlyOnePosition=true blockiert jede nicht flache Exposure zusätzliche Einstiege, bis die Position geschlossen ist.
Volumenbestimmung - der Risikoprozentsatzmodus verwendet das PriceStep/StepPrice-Paar des Instruments, um die Preisdistanz in einen Geldwert umzuwandeln, und berücksichtigt VolumeStep, VolumeMin und VolumeMax.
Parameter
Name
Beschreibung
H1CandleType
Zeitrahmen für die Ausführungslogik (Standard 1 Stunde).
H4CandleType
Höherer Zeitrahmen für den Trendfilter (Standard 4 Stunden).
H1FastPeriod / H1SlowPeriod
Längen der gleitenden Durchschnitte für H1 RAVI.
H4FastPeriod / H4SlowPeriod
Längen der gleitenden Durchschnitte für H4 RAVI.
StopLossPoints
Stop-Loss-Distanz in pipbasierten Punkten.
TakeProfitPoints
Take-Profit-Distanz in pipbasierten Punkten.
TrailingStopPoints
Trailing-Stop-Distanz. Auf null setzen, um Trailing zu deaktivieren.
TrailingStepPoints
Mindestschritt für Trailing-Aktualisierungen. Muss positiv sein, wenn Trailing aktiviert ist.
FixedVolume
Lotgröße im festen Modus.
RiskPercent
Prozentsatz des Portfoliowerts, der riskiert wird, wenn MoneyMode gleich RiskPercent ist.
MoneyMode
Schaltet zwischen FixedLot und RiskPercent um.
OnlyOnePosition
Erlaubt nur eine einzelne offene Position.
ReverseSignals
Kehrt Long-/Short-Aktionen um (Standard true, um zur EA-Einstellung zu passen).
CloseOpposite
Schließt eine Gegenposition, bevor eine neue Order platziert wird.
Hinweise zur Umrechnung
Die Pip-Umrechnung imitiert den MT5-Expert: Drei- und fünfstellige Kurse multiplizieren PriceStep mit zehn, um eine pipgroße Schrittweite zu erhalten.
Die RAVI-Historie wird ohne benutzerdefinierte Collections gespeichert - nur vier nullable Felder - und respektiert damit die Repository-Beschränkungen gegen manuelle Buffer.
Money Management vermeidet Indikator-GetValue-Aufrufe und nutzt StockSharp-Marktdaten, um prozentuales Risiko auf Volumen abzubilden.
StartProtection wird nur aufgerufen, wenn mindestens eine der Schutzdistanzen positiv ist, was eine sichere Ausführung in Backtests und im Live-Handel gewährleistet.
Nutzungstipps
Stellen Sie ein Forex-ähnliches Instrument mit korrekt konfiguriertem PriceStep, StepPrice, VolumeStep, VolumeMin und VolumeMax bereit.
Definieren Sie bei risikobasierter Größenbestimmung einen von null verschiedenen StopLossPoints; andernfalls ist das berechnete Volumen null.
Da der ursprüngliche EA eine logische Eigenheit enthielt, bei der beide Muster das Kauf-Flag setzten, behalten Sie ReverseSignals=true bei, wenn Sie seine exakten Trades reproduzieren müssen.
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 Lavika100Strategy : 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 Lavika100Strategy()
{
_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 lavika100_strategy(Strategy):
def __init__(self):
super(lavika100_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(lavika100_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(lavika100_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 lavika100_strategy()