X2MA JFatl Crossover-Strategie
Diese Strategie ist eine StockSharp-Adaption des MetaTrader-Experten Exp_X2MA_JFatl. Sie kombiniert einen schnellen Simple Moving Average (SMA) mit einem langsamen Jurik Moving Average (JMA) und einem zusätzlichen Jurik-Filter zur Bestätigung der Trendrichtung. Trades werden eröffnet, wenn der schnelle Durchschnitt den langsamen kreuzt und der Preis auf derselben Seite des Filters liegt. Positionen werden geschlossen, wenn der Preis gegen den Filter läuft oder ein entgegengesetzter Crossover auftritt.
Details
- Einstiegskriterien:
- Long:
SMA_fastkreuzt überJMA_slowundClose>JMA_filter. - Short:
SMA_fastkreuzt unterJMA_slowundClose<JMA_filter.
- Long:
- Ausstiegskriterien:
- Preis bewegt sich auf die entgegengesetzte Seite des Filters.
- Entgegengesetzter Crossover der Durchschnitte.
- Long/Short: Beide Seiten.
- Stops: Standardmäßig nicht verwendet.
- Standardwerte:
Fast MA Length= 5.Slow MA Length= 12.Filter Length= 20.
- Filter:
- Kategorie: Trendfolge
- Richtung: Beide
- Indikatoren: Mehrere (SMA, JMA)
- Stops: Nein
- Komplexität: Moderat
- Zeitrahmen: Kurzfristig
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
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>
/// X2MA with JFATL filter strategy.
/// Opens long when the fast SMA crosses above the slow Jurik MA and price is above the filter.
/// Opens short when the fast SMA crosses below the slow Jurik MA and price is below the filter.
/// </summary>
public class X2MaJfatlStrategy : Strategy
{
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
private readonly StrategyParam<int> _filterLength;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevDiff;
private bool _isInitialized;
private int _barsSinceTrade;
/// <summary>
/// Fast moving average length.
/// </summary>
public int FastLength
{
get => _fastLength.Value;
set => _fastLength.Value = value;
}
/// <summary>
/// Slow Jurik moving average length.
/// </summary>
public int SlowLength
{
get => _slowLength.Value;
set => _slowLength.Value = value;
}
/// <summary>
/// Jurik filter length.
/// </summary>
public int FilterLength
{
get => _filterLength.Value;
set => _filterLength.Value = value;
}
/// <summary>
/// Candle type used for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes strategy parameters.
/// </summary>
public X2MaJfatlStrategy()
{
_fastLength = Param(nameof(FastLength), 5)
.SetGreaterThanZero()
.SetDisplay("Fast MA Length", "Length of the fast moving average", "Parameters")
.SetOptimize(5, 20, 1);
_slowLength = Param(nameof(SlowLength), 13)
.SetGreaterThanZero()
.SetDisplay("Slow MA Length", "Length of the slow Jurik MA", "Parameters")
.SetOptimize(10, 40, 2);
_filterLength = Param(nameof(FilterLength), 21)
.SetGreaterThanZero()
.SetDisplay("Filter Length", "Length of the Jurik filter", "Parameters")
.SetOptimize(10, 60, 5);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Type of candles for calculation", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevDiff = 0m;
_isInitialized = false;
_barsSinceTrade = 10;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevDiff = 0m;
_isInitialized = false;
_barsSinceTrade = 10;
var fastMa = new SMA { Length = FastLength };
var slowMa = new JurikMovingAverage { Length = SlowLength };
var filterMa = new JurikMovingAverage { Length = FilterLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastMa, slowMa, filterMa, Process)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastMa);
DrawIndicator(area, slowMa);
DrawIndicator(area, filterMa);
DrawOwnTrades(area);
}
}
private void Process(ICandleMessage candle, decimal fastValue, decimal slowValue, decimal filterValue)
{
if (candle.State != CandleStates.Finished)
return;
_barsSinceTrade++;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (!_isInitialized)
{
_prevDiff = fastValue - slowValue;
_isInitialized = true;
return;
}
var diff = fastValue - slowValue;
// Exit if price moves against the filter
if (Position > 0 && candle.ClosePrice < filterValue)
{
SellMarket();
_barsSinceTrade = 0;
}
else if (Position < 0 && candle.ClosePrice > filterValue)
{
BuyMarket();
_barsSinceTrade = 0;
}
// Crossover entries
if (_barsSinceTrade >= 5 && _prevDiff <= 0m && diff > 0m && candle.ClosePrice > filterValue && Position <= 0)
{
BuyMarket();
_barsSinceTrade = 0;
}
else if (_barsSinceTrade >= 5 && _prevDiff >= 0m && diff < 0m && candle.ClosePrice < filterValue && Position >= 0)
{
SellMarket();
_barsSinceTrade = 0;
}
_prevDiff = diff;
}
}
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 SimpleMovingAverage, JurikMovingAverage
from StockSharp.Algo.Strategies import Strategy
class x2_ma_j_fatl_strategy(Strategy):
def __init__(self):
super(x2_ma_j_fatl_strategy, self).__init__()
self._fast_length = self.Param("FastLength", 5) \
.SetDisplay("Fast MA Length", "Length of the fast moving average", "Parameters")
self._slow_length = self.Param("SlowLength", 13) \
.SetDisplay("Slow MA Length", "Length of the slow Jurik MA", "Parameters")
self._filter_length = self.Param("FilterLength", 21) \
.SetDisplay("Filter Length", "Length of the Jurik filter", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))) \
.SetDisplay("Candle Type", "Type of candles for calculation", "General")
self._prev_diff = 0.0
self._is_initialized = False
self._bars_since_trade = 10
@property
def fast_length(self):
return self._fast_length.Value
@property
def slow_length(self):
return self._slow_length.Value
@property
def filter_length(self):
return self._filter_length.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(x2_ma_j_fatl_strategy, self).OnReseted()
self._prev_diff = 0.0
self._is_initialized = False
self._bars_since_trade = 10
def OnStarted2(self, time):
super(x2_ma_j_fatl_strategy, self).OnStarted2(time)
self._prev_diff = 0.0
self._is_initialized = False
self._bars_since_trade = 10
fast_ma = SimpleMovingAverage()
fast_ma.Length = int(self.fast_length)
slow_ma = JurikMovingAverage()
slow_ma.Length = int(self.slow_length)
filter_ma = JurikMovingAverage()
filter_ma.Length = int(self.filter_length)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast_ma, slow_ma, filter_ma, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_ma)
self.DrawIndicator(area, slow_ma)
self.DrawIndicator(area, filter_ma)
self.DrawOwnTrades(area)
def process_candle(self, candle, fast_value, slow_value, filter_value):
if candle.State != CandleStates.Finished:
return
fast_value = float(fast_value)
slow_value = float(slow_value)
filter_value = float(filter_value)
self._bars_since_trade += 1
if not self._is_initialized:
self._prev_diff = fast_value - slow_value
self._is_initialized = True
return
diff = fast_value - slow_value
close = float(candle.ClosePrice)
if self.Position > 0 and close < filter_value:
self.SellMarket()
self._bars_since_trade = 0
elif self.Position < 0 and close > filter_value:
self.BuyMarket()
self._bars_since_trade = 0
if self._bars_since_trade >= 5 and self._prev_diff <= 0 and diff > 0 and close > filter_value and self.Position <= 0:
self.BuyMarket()
self._bars_since_trade = 0
elif self._bars_since_trade >= 5 and self._prev_diff >= 0 and diff < 0 and close < filter_value and self.Position >= 0:
self.SellMarket()
self._bars_since_trade = 0
self._prev_diff = diff
def CreateClone(self):
return x2_ma_j_fatl_strategy()