XDerivative-Strategie
Die XDerivative-Strategie verfolgt Verschiebungen im Preismomentum mithilfe einer geglätteten Änderungsrate. Der originale MQL-Experte kombiniert eine Änderungsraten-Berechnung mit Jurik-Glättung zur Erkennung von Wendepunkten. Die StockSharp-Version nutzt integrierte Indikatoren, um dasselbe Konzept umzusetzen.
Die Strategie berechnet die Änderungsrate über RocPeriod Balken und glättet sie mit einem Jurik Moving Average der Länge MaLength. Wenn die geglättete Ableitung ein Tal bildet (der vorherige Wert ist niedriger als sein Vorgänger und der aktuelle Wert steigt über den vorherigen), eröffnet die Strategie eine Long-Position oder wechselt dazu. Wenn ein Gipfel entsteht (der vorherige Wert ist höher als sein Vorgänger und der aktuelle fällt darunter), eröffnet die Strategie eine Short-Position oder wechselt dazu. Schutzstopps verwalten die Ausstiege.
Details
- Einstiegskriterien:
- Long: Geglättete Ableitung dreht nach oben nach einem lokalen Minimum.
- Short: Geglättete Ableitung dreht nach unten nach einem lokalen Maximum.
- Long/Short: Beide Richtungen.
- Ausstiegskriterien: Entgegengesetzter Ableitungswechsel oder Schutzstop.
- Stops: Ja, prozentuale Take-Profit und Stop-Loss.
- Standardwerte:
RocPeriod = 34
MaLength = 7
TakeProfitPercent = 2
StopLossPercent = 1
CandleType = TimeSpan.FromHours(4)
- Filter:
- Kategorie: Trendfolge
- Richtung: Beide
- Indikatoren: RateOfChange, JurikMovingAverage
- Stops: Ja
- Komplexität: Grundlegend
- Zeitrahmen: 4H
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
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>
/// XDerivative strategy based on smoothed rate of change.
/// Enters long when the smoothed derivative forms a trough and short when it forms a peak.
/// </summary>
public class XDerivativeStrategy : Strategy
{
private readonly StrategyParam<int> _rocPeriod;
private readonly StrategyParam<int> _maLength;
private readonly StrategyParam<decimal> _takeProfitPct;
private readonly StrategyParam<decimal> _stopLossPct;
private readonly StrategyParam<DataType> _candleType;
private JurikMovingAverage _jma;
private decimal? _prevValue;
private decimal? _prevPrevValue;
public int RocPeriod
{
get => _rocPeriod.Value;
set => _rocPeriod.Value = value;
}
public int MaLength
{
get => _maLength.Value;
set => _maLength.Value = value;
}
public decimal TakeProfitPct
{
get => _takeProfitPct.Value;
set => _takeProfitPct.Value = value;
}
public decimal StopLossPct
{
get => _stopLossPct.Value;
set => _stopLossPct.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public XDerivativeStrategy()
{
_rocPeriod = Param(nameof(RocPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ROC Period", "Period for rate of change", "Parameters");
_maLength = Param(nameof(MaLength), 7)
.SetGreaterThanZero()
.SetDisplay("JMA Length", "Period for Jurik MA smoothing", "Parameters");
_takeProfitPct = Param(nameof(TakeProfitPct), 3m)
.SetGreaterThanZero()
.SetDisplay("Take Profit %", "Take profit percentage", "Risk");
_stopLossPct = Param(nameof(StopLossPct), 2m)
.SetGreaterThanZero()
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "Parameters");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_jma = default;
_prevValue = null;
_prevPrevValue = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_jma = new JurikMovingAverage { Length = MaLength };
var roc = new RateOfChange { Length = RocPeriod };
Indicators.Add(_jma);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(roc, (candle, rocValue) =>
{
if (candle.State != CandleStates.Finished)
return;
var jmaResult = _jma.Process(rocValue, candle.OpenTime, true);
if (!jmaResult.IsFormed)
return;
var value = jmaResult.ToDecimal();
if (_prevValue is decimal prev && _prevPrevValue is decimal prev2)
{
var turnUp = prev < prev2 && value > prev;
var turnDown = prev > prev2 && value < prev;
if (turnUp && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (turnDown && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
}
_prevPrevValue = _prevValue;
_prevValue = value;
})
.Start();
StartProtection(
takeProfit: new Unit(TakeProfitPct, UnitTypes.Percent),
stopLoss: new Unit(StopLossPct, UnitTypes.Percent),
useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, roc);
DrawOwnTrades(area);
}
}
}
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 JurikMovingAverage, RateOfChange
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class x_derivative_strategy(Strategy):
def __init__(self):
super(x_derivative_strategy, self).__init__()
self._roc_period = self.Param("RocPeriod", 14) \
.SetDisplay("ROC Period", "Period for rate of change", "Parameters")
self._ma_length = self.Param("MaLength", 7) \
.SetDisplay("JMA Length", "Period for Jurik MA smoothing", "Parameters")
self._take_profit_pct = self.Param("TakeProfitPct", 3.0) \
.SetDisplay("Take Profit %", "Take profit percentage", "Risk")
self._stop_loss_pct = self.Param("StopLossPct", 2.0) \
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "Parameters")
self._jma = None
self._prev_value = None
self._prev_prev_value = None
@property
def roc_period(self):
return self._roc_period.Value
@property
def ma_length(self):
return self._ma_length.Value
@property
def take_profit_pct(self):
return self._take_profit_pct.Value
@property
def stop_loss_pct(self):
return self._stop_loss_pct.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(x_derivative_strategy, self).OnReseted()
self._jma = None
self._prev_value = None
self._prev_prev_value = None
def OnStarted2(self, time):
super(x_derivative_strategy, self).OnStarted2(time)
self._jma = JurikMovingAverage()
self._jma.Length = self.ma_length
roc = RateOfChange()
roc.Length = self.roc_period
self.Indicators.Add(self._jma)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(roc, self.on_candle).Start()
self.StartProtection(
takeProfit=Unit(self.take_profit_pct, UnitTypes.Percent),
stopLoss=Unit(self.stop_loss_pct, UnitTypes.Percent),
useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, roc)
self.DrawOwnTrades(area)
def on_candle(self, candle, roc_value):
if candle.State != CandleStates.Finished:
return
jma_result = process_float(self._jma, roc_value, candle.OpenTime, True)
if not jma_result.IsFormed:
return
value = float(jma_result)
if self._prev_value is not None and self._prev_prev_value is not None:
turn_up = self._prev_value < self._prev_prev_value and value > self._prev_value
turn_down = self._prev_value > self._prev_prev_value and value < self._prev_value
if turn_up and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif turn_down and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_prev_value = self._prev_value
self._prev_value = value
def CreateClone(self):
return x_derivative_strategy()