Omar MMR-Strategie
Momentum-basierte Methode, die RSI, drei exponentielle gleitende Durchschnitte und eine MACD-Kreuzung kombiniert. Long-Trades entstehen, wenn der Kurs über der langsamen EMA liegt, die schnelle EMA die mittlere EMA übersteigt, MACD bullisch kreuzt und RSI in einer neutralen Zone zwischen 29 und 70 liegt.
Take-Profit- und Stop-Loss-Prozentsätze werden über das Schutzmodul des Motors angewendet. Das Setup konzentriert sich auf die Ausrichtung von Momentum und Trend und vermeidet dabei überdehnte RSI-Werte.
Details
- Einstiegskriterien:
- Long: Schluss über EMA C, EMA A > EMA B, MACD-Linie kreuzt über das Signal, RSI zwischen 29 und 70.
- Ausstiegskriterien:
- Verwaltung über Take-Profit oder Stop-Loss; kein expliziter Indikator-Ausstieg.
- Indikatoren:
- RSI (Länge 14)
- EMA A/B/C (Perioden 20/50/200)
- MACD (12,26,9)
- Stops: Prozentbasierter Take-Profit 1,5% und Stop-Loss 2% standardmäßig.
- Standardwerte:
RsiLength= 14EmaALength= 20EmaBLength= 50EmaCLength= 200MacdFastLength= 12MacdSlowLength= 26MacdSignalLength= 9TakeProfitPercent= 1.5StopLossPercent= 2.0
- Filter:
- Trendfortsetzung
- Einzelner Zeitrahmen
- Indikatoren: RSI, EMA, MACD
- Stops: Ja
- Komplexität: Moderat
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// Omar MMR Strategy.
/// Uses RSI, triple EMA alignment, and MACD signal crossover for entries.
/// Buys when price > EMA C, EMA A > EMA B, MACD crosses above signal, RSI in range.
/// Sells when EMA alignment reverses or MACD crosses below signal.
/// </summary>
public class OmarMmrStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleTypeParam;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<int> _emaALength;
private readonly StrategyParam<int> _emaBLength;
private readonly StrategyParam<int> _emaCLength;
private readonly StrategyParam<int> _cooldownBars;
private RelativeStrengthIndex _rsi;
private ExponentialMovingAverage _emaA;
private ExponentialMovingAverage _emaB;
private ExponentialMovingAverage _emaC;
private decimal _prevEmaA;
private decimal _prevEmaB;
private int _cooldownRemaining;
public OmarMmrStrategy()
{
_candleTypeParam = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle type", "Candle type for strategy calculation.", "General");
_rsiLength = Param(nameof(RsiLength), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "RSI period", "RSI");
_emaALength = Param(nameof(EmaALength), 20)
.SetGreaterThanZero()
.SetDisplay("EMA A Length", "Fast EMA period", "Moving Averages");
_emaBLength = Param(nameof(EmaBLength), 50)
.SetGreaterThanZero()
.SetDisplay("EMA B Length", "Medium EMA period", "Moving Averages");
_emaCLength = Param(nameof(EmaCLength), 200)
.SetGreaterThanZero()
.SetDisplay("EMA C Length", "Slow EMA period", "Moving Averages");
_cooldownBars = Param(nameof(CooldownBars), 15)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "Risk");
}
public DataType CandleType
{
get => _candleTypeParam.Value;
set => _candleTypeParam.Value = value;
}
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
public int EmaALength
{
get => _emaALength.Value;
set => _emaALength.Value = value;
}
public int EmaBLength
{
get => _emaBLength.Value;
set => _emaBLength.Value = value;
}
public int EmaCLength
{
get => _emaCLength.Value;
set => _emaCLength.Value = value;
}
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_rsi = null;
_emaA = null;
_emaB = null;
_emaC = null;
_prevEmaA = 0;
_prevEmaB = 0;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_rsi = new RelativeStrengthIndex { Length = RsiLength };
_emaA = new ExponentialMovingAverage { Length = EmaALength };
_emaB = new ExponentialMovingAverage { Length = EmaBLength };
_emaC = new ExponentialMovingAverage { Length = EmaCLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_rsi, _emaA, _emaB, _emaC, OnProcess)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _emaA);
DrawIndicator(area, _emaB);
DrawIndicator(area, _emaC);
DrawOwnTrades(area);
}
}
private void OnProcess(ICandleMessage candle, decimal rsiVal, decimal emaA, decimal emaB, decimal emaC)
{
if (candle.State != CandleStates.Finished)
return;
if (!_rsi.IsFormed || !_emaA.IsFormed || !_emaB.IsFormed || !_emaC.IsFormed)
{
_prevEmaA = emaA;
_prevEmaB = emaB;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevEmaA = emaA;
_prevEmaB = emaB;
return;
}
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevEmaA = emaA;
_prevEmaB = emaB;
return;
}
if (_prevEmaA == 0 || _prevEmaB == 0)
{
_prevEmaA = emaA;
_prevEmaB = emaB;
return;
}
// EMA alignment
var bullishAlignment = emaA > emaB && candle.ClosePrice > emaC;
var bearishAlignment = emaA < emaB && candle.ClosePrice < emaC;
// EMA A/B crossover
var emaCrossUp = emaA > emaB && _prevEmaA <= _prevEmaB;
var emaCrossDown = emaA < emaB && _prevEmaA >= _prevEmaB;
// RSI filter
var rsiInBuyRange = rsiVal > 30 && rsiVal < 70;
var rsiInSellRange = rsiVal > 30 && rsiVal < 70;
// Buy: bullish EMA alignment + EMA cross up + RSI in range
if (bullishAlignment && emaCrossUp && rsiInBuyRange && Position <= 0)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
BuyMarket(Volume);
_cooldownRemaining = CooldownBars;
}
// Sell: bearish EMA alignment + EMA cross down + RSI in range
else if (bearishAlignment && emaCrossDown && rsiInSellRange && Position >= 0)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
SellMarket(Volume);
_cooldownRemaining = CooldownBars;
}
// Exit long: EMA A crosses below EMA B
else if (Position > 0 && emaCrossDown)
{
SellMarket(Math.Abs(Position));
_cooldownRemaining = CooldownBars;
}
// Exit short: EMA A crosses above EMA B
else if (Position < 0 && emaCrossUp)
{
BuyMarket(Math.Abs(Position));
_cooldownRemaining = CooldownBars;
}
_prevEmaA = emaA;
_prevEmaB = emaB;
}
}
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
from StockSharp.Algo.Indicators import RelativeStrengthIndex, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class omar_mmr_strategy(Strategy):
"""Omar MMR Strategy."""
def __init__(self):
super(omar_mmr_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle type", "Candle type for strategy calculation.", "General")
self._rsi_length = self.Param("RsiLength", 14) \
.SetDisplay("RSI Length", "RSI period", "RSI")
self._ema_a_length = self.Param("EmaALength", 20) \
.SetDisplay("EMA A Length", "Fast EMA period", "Moving Averages")
self._ema_b_length = self.Param("EmaBLength", 50) \
.SetDisplay("EMA B Length", "Medium EMA period", "Moving Averages")
self._ema_c_length = self.Param("EmaCLength", 200) \
.SetDisplay("EMA C Length", "Slow EMA period", "Moving Averages")
self._cooldown_bars = self.Param("CooldownBars", 15) \
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "Risk")
self._rsi = None
self._ema_a = None
self._ema_b = None
self._ema_c = None
self._prev_ema_a = 0.0
self._prev_ema_b = 0.0
self._cooldown_remaining = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(omar_mmr_strategy, self).OnReseted()
self._rsi = None
self._ema_a = None
self._ema_b = None
self._ema_c = None
self._prev_ema_a = 0.0
self._prev_ema_b = 0.0
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(omar_mmr_strategy, self).OnStarted2(time)
self._rsi = RelativeStrengthIndex()
self._rsi.Length = int(self._rsi_length.Value)
self._ema_a = ExponentialMovingAverage()
self._ema_a.Length = int(self._ema_a_length.Value)
self._ema_b = ExponentialMovingAverage()
self._ema_b.Length = int(self._ema_b_length.Value)
self._ema_c = ExponentialMovingAverage()
self._ema_c.Length = int(self._ema_c_length.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._rsi, self._ema_a, self._ema_b, self._ema_c, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._ema_a)
self.DrawIndicator(area, self._ema_b)
self.DrawIndicator(area, self._ema_c)
self.DrawOwnTrades(area)
def _on_process(self, candle, rsi_val, ema_a_val, ema_b_val, ema_c_val):
if candle.State != CandleStates.Finished:
return
if not self._rsi.IsFormed or not self._ema_a.IsFormed or not self._ema_b.IsFormed or not self._ema_c.IsFormed:
self._prev_ema_a = float(ema_a_val)
self._prev_ema_b = float(ema_b_val)
return
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_ema_a = float(ema_a_val)
self._prev_ema_b = float(ema_b_val)
return
ema_a = float(ema_a_val)
ema_b = float(ema_b_val)
ema_c = float(ema_c_val)
rsi = float(rsi_val)
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
self._prev_ema_a = ema_a
self._prev_ema_b = ema_b
return
if self._prev_ema_a == 0.0 or self._prev_ema_b == 0.0:
self._prev_ema_a = ema_a
self._prev_ema_b = ema_b
return
close = float(candle.ClosePrice)
cooldown = int(self._cooldown_bars.Value)
bullish_alignment = ema_a > ema_b and close > ema_c
bearish_alignment = ema_a < ema_b and close < ema_c
ema_cross_up = ema_a > ema_b and self._prev_ema_a <= self._prev_ema_b
ema_cross_down = ema_a < ema_b and self._prev_ema_a >= self._prev_ema_b
rsi_in_buy_range = rsi > 30 and rsi < 70
rsi_in_sell_range = rsi > 30 and rsi < 70
if bullish_alignment and ema_cross_up and rsi_in_buy_range and self.Position <= 0:
if self.Position < 0:
self.BuyMarket(Math.Abs(self.Position))
self.BuyMarket(self.Volume)
self._cooldown_remaining = cooldown
elif bearish_alignment and ema_cross_down and rsi_in_sell_range and self.Position >= 0:
if self.Position > 0:
self.SellMarket(Math.Abs(self.Position))
self.SellMarket(self.Volume)
self._cooldown_remaining = cooldown
elif self.Position > 0 and ema_cross_down:
self.SellMarket(Math.Abs(self.Position))
self._cooldown_remaining = cooldown
elif self.Position < 0 and ema_cross_up:
self.BuyMarket(Math.Abs(self.Position))
self._cooldown_remaining = cooldown
self._prev_ema_a = ema_a
self._prev_ema_b = ema_b
def CreateClone(self):
return omar_mmr_strategy()