Diese Strategie implementiert ein konträres System aus gleitenden Durchschnitts-Kreuzungen, das ursprünglich in MQL als X trader geschrieben wurde.
Es verwendet zwei einfache gleitende Durchschnitte und eröffnet Positionen entgegen der Kreuzungsrichtung. Das Risiko wird
mithilfe fester Take-Profit- und Stop-Loss-Werte in absoluten Punkten über StartProtection verwaltet.
Funktionsweise
Kerzdaten des angegebenen Zeitrahmens abonnieren.
Zwei gleitende Durchschnitte mit konfigurierbaren Perioden berechnen.
Die letzten zwei Werte jedes Durchschnitts verfolgen, um eine Kreuzung zu erkennen.
Wenn der schnelle Durchschnitt den langsamen von unten kreuzt und zwei Balken lang darüber bleibt, während er vor zwei Balken darunter war,
wird eine Short-Position eröffnet.
Wenn der schnelle Durchschnitt den langsamen von oben kreuzt und zwei Balken lang darunter bleibt, während er vor zwei Balken darüber war,
wird eine Long-Position eröffnet.
Es kann jeweils nur eine Position offen sein. Der Schutz schließt Trades automatisch, wenn sich der Preis um den
konfigurierten Take-Profit- oder Stop-Loss-Betrag bewegt.
Parameter
CandleType – zu verwendende Kerzenserie.
Ma1Period – Periode des ersten gleitenden Durchschnitts.
Ma2Period – Periode des zweiten gleitenden Durchschnitts.
TakeProfitPoints – Gewinnziel in Preispunkten.
StopLossPoints – Verlustlimit in Preispunkten.
Indikator
SimpleMovingAverage – zweimal mit unterschiedlichen Perioden verwendet.
Risikomanagement
StartProtection wird in OnStarted aktiviert und wendet die Take-Profit- und Stop-Loss-Werte auf alle Positionen an.
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>
/// X Trader Strategy - contrarian moving average cross.
/// </summary>
public class XTraderStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _ma1Period;
private readonly StrategyParam<int> _ma2Period;
private decimal _ma1Prev;
private decimal _ma1Prev2;
private decimal _ma2Prev;
private decimal _ma2Prev2;
private bool _hasPrev2;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int Ma1Period { get => _ma1Period.Value; set => _ma1Period.Value = value; }
public int Ma2Period { get => _ma2Period.Value; set => _ma2Period.Value = value; }
public XTraderStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_ma1Period = Param(nameof(Ma1Period), 16)
.SetGreaterThanZero()
.SetDisplay("MA1 Period", "Period of the first moving average", "Parameters");
_ma2Period = Param(nameof(Ma2Period), 10)
.SetGreaterThanZero()
.SetDisplay("MA2 Period", "Period of the second moving average", "Parameters");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_ma1Prev = 0;
_ma1Prev2 = 0;
_ma2Prev = 0;
_ma2Prev2 = 0;
_hasPrev2 = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ma1 = new ExponentialMovingAverage { Length = Ma1Period };
var ma2 = new ExponentialMovingAverage { Length = Ma2Period };
SubscribeCandles(CandleType)
.Bind(ma1, ma2, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal ma1Value, decimal ma2Value)
{
if (candle.State != CandleStates.Finished) return;
if (_ma1Prev == 0)
{
_ma1Prev = ma1Value;
_ma2Prev = ma2Value;
return;
}
if (!_hasPrev2)
{
_ma1Prev2 = _ma1Prev;
_ma2Prev2 = _ma2Prev;
_ma1Prev = ma1Value;
_ma2Prev = ma2Value;
_hasPrev2 = true;
return;
}
// Contrarian: sell when MA1 crosses above MA2, buy when MA1 crosses below
var sellSignal = ma1Value > ma2Value && _ma1Prev > _ma2Prev && _ma1Prev2 < _ma2Prev2;
var buySignal = ma1Value < ma2Value && _ma1Prev < _ma2Prev && _ma1Prev2 > _ma2Prev2;
if (sellSignal && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
else if (buySignal && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
_ma1Prev2 = _ma1Prev;
_ma2Prev2 = _ma2Prev;
_ma1Prev = ma1Value;
_ma2Prev = ma2Value;
}
}
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 x_trader_strategy(Strategy):
def __init__(self):
super(x_trader_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._ma1_period = self.Param("Ma1Period", 16) \
.SetDisplay("MA1 Period", "Period of the first moving average", "Parameters")
self._ma2_period = self.Param("Ma2Period", 10) \
.SetDisplay("MA2 Period", "Period of the second moving average", "Parameters")
self._ma1_prev = 0.0
self._ma1_prev2 = 0.0
self._ma2_prev = 0.0
self._ma2_prev2 = 0.0
self._has_prev2 = False
@property
def candle_type(self):
return self._candle_type.Value
@property
def ma1_period(self):
return self._ma1_period.Value
@property
def ma2_period(self):
return self._ma2_period.Value
def OnReseted(self):
super(x_trader_strategy, self).OnReseted()
self._ma1_prev = 0.0
self._ma1_prev2 = 0.0
self._ma2_prev = 0.0
self._ma2_prev2 = 0.0
self._has_prev2 = False
def OnStarted2(self, time):
super(x_trader_strategy, self).OnStarted2(time)
ma1 = ExponentialMovingAverage()
ma1.Length = self.ma1_period
ma2 = ExponentialMovingAverage()
ma2.Length = self.ma2_period
self.SubscribeCandles(self.candle_type).Bind(ma1, ma2, self.process_candle).Start()
def process_candle(self, candle, ma1_value, ma2_value):
if candle.State != CandleStates.Finished:
return
m1 = float(ma1_value)
m2 = float(ma2_value)
if self._ma1_prev == 0.0:
self._ma1_prev = m1
self._ma2_prev = m2
return
if not self._has_prev2:
self._ma1_prev2 = self._ma1_prev
self._ma2_prev2 = self._ma2_prev
self._ma1_prev = m1
self._ma2_prev = m2
self._has_prev2 = True
return
sell_signal = m1 > m2 and self._ma1_prev > self._ma2_prev and self._ma1_prev2 < self._ma2_prev2
buy_signal = m1 < m2 and self._ma1_prev < self._ma2_prev and self._ma1_prev2 > self._ma2_prev2
if sell_signal and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
elif buy_signal and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._ma1_prev2 = self._ma1_prev
self._ma2_prev2 = self._ma2_prev
self._ma1_prev = m1
self._ma2_prev = m2
def CreateClone(self):
return x_trader_strategy()