ColorJMomentum-Strategie
Die ColorJMomentum-Strategie handelt basierend auf Richtungsänderungen eines mit Jurik geglätteten Momentum-Indikators. Der Ansatz leitet sich vom ursprünglichen MQL5-Expertenberater Exp_ColorJMomentum ab und wird mithilfe der StockSharp-High-Level-API reproduziert.
Konzept
- Den Standard-Momentum der ausgewählten Preisserie berechnen.
- Die Momentum-Werte mit dem Jurik Moving Average (JMA) glätten.
- Die letzten zwei Werte des geglätteten Momentums überwachen:
- Wenn der Indikator rückläufig war und sich nach oben dreht, wird eine Long-Position eröffnet.
- Wenn der Indikator steigend war und sich nach unten dreht, wird eine Short-Position eröffnet.
- Der Positionsschutz erfolgt durch optionalen Stop Loss und Take Profit in Prozentangaben.
Die Strategie liest historische Indikatorwerte nicht direkt. Stattdessen reagiert sie nur auf neue Kerzenabschlüsse und speichert vorherige Werte intern.
Parameter
- Momentum Length – Periode für die Momentum-Berechnung.
- JMA Length – Glättungsperiode des auf Momentum angewandten Jurik Moving Average.
- Candle Type – Zeitrahmen für Kerzenabonnements.
- Stop Loss % – Prozentsatz für optionalen Stop Loss.
- Enable Stop Loss – ob Stop Loss aktiviert wird.
- Take Profit % – Prozentsatz für Take Profit.
- Enable Long – Long-Positionen eröffnen erlauben.
- Enable Short – Short-Positionen eröffnen erlauben.
Alle Parameter werden mit StrategyParam erstellt, damit sie in Designer optimiert werden können.
Verwendung
- Strategie an das gewünschte Wertpapier anhängen.
- Parameter konfigurieren oder Standardwerte belassen (8-Perioden-Momentum und 8-Perioden-JMA auf 8‑Stunden-Kerzen).
- Strategie ausführen. Orders werden über
BuyMarket und SellMarket ausgegeben, wenn sich die Momentum-Richtung umkehrt.
Hinweise
- Die Strategie verarbeitet nur abgeschlossene Kerzen.
- Für Indikatoren werden keine expliziten Farben gesetzt – Designer wählt sie automatisch aus.
- Der Algorithmus vermeidet jegliches LINQ oder benutzerdefinierte Sammlungen gemäß den Projektrichtlinien.
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;
/// <summary>
/// Strategy based on smoothed momentum direction changes.
/// Opens long when momentum turns up, short when momentum turns down.
/// </summary>
public class ColorJMomentumStrategy : Strategy
{
private readonly StrategyParam<int> _momentumLength;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<decimal> _takeProfitPercent;
private readonly StrategyParam<bool> _enableLong;
private readonly StrategyParam<bool> _enableShort;
private decimal _prevMom;
private decimal _prevPrevMom;
private int _count;
public int MomentumLength { get => _momentumLength.Value; set => _momentumLength.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public decimal StopLossPercent { get => _stopLossPercent.Value; set => _stopLossPercent.Value = value; }
public decimal TakeProfitPercent { get => _takeProfitPercent.Value; set => _takeProfitPercent.Value = value; }
public bool EnableLong { get => _enableLong.Value; set => _enableLong.Value = value; }
public bool EnableShort { get => _enableShort.Value; set => _enableShort.Value = value; }
public ColorJMomentumStrategy()
{
_momentumLength = Param(nameof(MomentumLength), 8)
.SetGreaterThanZero()
.SetDisplay("Momentum Length", "Period for momentum", "Parameters");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for candles", "Parameters");
_stopLossPercent = Param(nameof(StopLossPercent), 1m)
.SetGreaterThanZero()
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk management");
_takeProfitPercent = Param(nameof(TakeProfitPercent), 2m)
.SetGreaterThanZero()
.SetDisplay("Take Profit %", "Take profit percentage", "Risk management");
_enableLong = Param(nameof(EnableLong), true)
.SetDisplay("Enable Long", "Allow long entries", "General");
_enableShort = Param(nameof(EnableShort), true)
.SetDisplay("Enable Short", "Allow short entries", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMom = 0;
_prevPrevMom = 0;
_count = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var momentum = new Momentum { Length = MomentumLength };
SubscribeCandles(CandleType)
.Bind(momentum, ProcessCandle)
.Start();
StartProtection(
takeProfit: new Unit(TakeProfitPercent, UnitTypes.Percent),
stopLoss: new Unit(StopLossPercent, UnitTypes.Percent)
);
}
private void ProcessCandle(ICandleMessage candle, decimal momValue)
{
if (candle.State != CandleStates.Finished)
return;
_count++;
if (_count < 3)
{
_prevPrevMom = _prevMom;
_prevMom = momValue;
return;
}
var wasDecreasing = _prevMom < _prevPrevMom;
var nowIncreasing = momValue > _prevMom;
var wasIncreasing = _prevMom > _prevPrevMom;
var nowDecreasing = momValue < _prevMom;
// Momentum turns up - go long
if (wasDecreasing && nowIncreasing && EnableLong && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
// Momentum turns down - go short
else if (wasIncreasing && nowDecreasing && EnableShort && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevPrevMom = _prevMom;
_prevMom = momValue;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import Momentum
from StockSharp.Algo.Strategies import Strategy
class color_j_momentum_strategy(Strategy):
"""
Strategy based on smoothed momentum direction changes.
Opens long when momentum turns up, short when momentum turns down.
"""
def __init__(self):
super(color_j_momentum_strategy, self).__init__()
self._momentum_length = self.Param("MomentumLength", 8) \
.SetDisplay("Momentum Length", "Period for momentum", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for candles", "Parameters")
self._stop_loss_percent = self.Param("StopLossPercent", 1.0) \
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk management")
self._take_profit_percent = self.Param("TakeProfitPercent", 2.0) \
.SetDisplay("Take Profit %", "Take profit percentage", "Risk management")
self._enable_long = self.Param("EnableLong", True) \
.SetDisplay("Enable Long", "Allow long entries", "General")
self._enable_short = self.Param("EnableShort", True) \
.SetDisplay("Enable Short", "Allow short entries", "General")
self._prev_mom = 0.0
self._prev_prev_mom = 0.0
self._count = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(color_j_momentum_strategy, self).OnReseted()
self._prev_mom = 0.0
self._prev_prev_mom = 0.0
self._count = 0
def OnStarted2(self, time):
super(color_j_momentum_strategy, self).OnStarted2(time)
momentum = Momentum()
momentum.Length = self._momentum_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(momentum, self.on_process).Start()
self.StartProtection(
takeProfit=Unit(self._take_profit_percent.Value, UnitTypes.Percent),
stopLoss=Unit(self._stop_loss_percent.Value, UnitTypes.Percent)
)
def on_process(self, candle, mom_val):
if candle.State != CandleStates.Finished:
return
self._count += 1
if self._count < 3:
self._prev_prev_mom = self._prev_mom
self._prev_mom = mom_val
return
was_decreasing = self._prev_mom < self._prev_prev_mom
now_increasing = mom_val > self._prev_mom
was_increasing = self._prev_mom > self._prev_prev_mom
now_decreasing = mom_val < self._prev_mom
if was_decreasing and now_increasing and self._enable_long.Value and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif was_increasing and now_decreasing and self._enable_short.Value and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_prev_mom = self._prev_mom
self._prev_mom = mom_val
def CreateClone(self):
return color_j_momentum_strategy()