Diese Strategie erzeugt Trades, wenn ein schneller und ein langsamer einfacher gleitender
Durchschnitt, berechnet auf dem Median-Preis, sich kreuzen. Die Logik spiegelt das
ursprüngliche MQL-Skript X_trail.mq4 wider, das bei solchen Kreuzungen Alarme auslöste.
Eine Long-Position wird eröffnet, wenn der schnelle MA auf der aktuellen und der vorherigen
Kerze über dem langsamen MA liegt, während er zwei Kerzen zuvor darunter lag. Das
umgekehrte Muster löst eine Short-Position aus. Positionen werden bei jedem neuen Signal umgekehrt.
Details
Einstiegskriterien:
Long: Schneller MA > langsamer MA auf den letzten zwei abgeschlossenen Kerzen und schneller MA lag zwei Kerzen zuvor unter dem langsamen MA.
Short: Schneller MA < langsamer MA auf den letzten zwei abgeschlossenen Kerzen und schneller MA lag zwei Kerzen zuvor über dem langsamen MA.
Long/Short: Beide.
Ausstiegskriterien:
Gegenläufige Kreuzung (Positionsumkehr).
Stops: Keine.
Indikatoren:
Zwei einfache gleitende Durchschnitte, berechnet auf dem Median-Preis.
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>
/// Moving average crossover strategy based on median price.
/// Enters long when fast MA crosses above slow MA.
/// Enters short when fast MA crosses below slow MA.
/// </summary>
public class XTrailStrategy : Strategy
{
private readonly StrategyParam<int> _ma1Length;
private readonly StrategyParam<int> _ma2Length;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
public int Ma1Length
{
get => _ma1Length.Value;
set => _ma1Length.Value = value;
}
public int Ma2Length
{
get => _ma2Length.Value;
set => _ma2Length.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public XTrailStrategy()
{
_ma1Length = Param(nameof(Ma1Length), 10)
.SetGreaterThanZero()
.SetDisplay("Fast MA Length", "Length of the fast moving average", "General");
_ma2Length = Param(nameof(Ma2Length), 30)
.SetGreaterThanZero()
.SetDisplay("Slow MA Length", "Length of the slow moving average", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ma1 = new SimpleMovingAverage { Length = Ma1Length };
var ma2 = new SimpleMovingAverage { Length = Ma2Length };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ma1, ma2, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ma1);
DrawIndicator(area, ma2);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
if (_hasPrev)
{
var crossUp = _prevFast <= _prevSlow && fast > slow;
var crossDown = _prevFast >= _prevSlow && fast < slow;
if (crossUp && Position <= 0)
BuyMarket();
else if (crossDown && Position >= 0)
SellMarket();
}
_prevFast = fast;
_prevSlow = slow;
_hasPrev = true;
}
}
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
from StockSharp.Algo.Strategies import Strategy
class x_trail_strategy(Strategy):
def __init__(self):
super(x_trail_strategy, self).__init__()
self._ma1_length = self.Param("Ma1Length", 10) \
.SetDisplay("Fast MA Length", "Length of the fast moving average", "General")
self._ma2_length = self.Param("Ma2Length", 30) \
.SetDisplay("Slow MA Length", "Length of the slow moving average", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
@property
def ma1_length(self):
return self._ma1_length.Value
@property
def ma2_length(self):
return self._ma2_length.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(x_trail_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(x_trail_strategy, self).OnStarted2(time)
ma1 = SimpleMovingAverage()
ma1.Length = self.ma1_length
ma2 = SimpleMovingAverage()
ma2.Length = self.ma2_length
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ma1, ma2, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ma1)
self.DrawIndicator(area, ma2)
self.DrawOwnTrades(area)
def on_process(self, candle, fast, slow):
if candle.State != CandleStates.Finished:
return
if self._has_prev:
cross_up = self._prev_fast <= self._prev_slow and fast > slow
cross_down = self._prev_fast >= self._prev_slow and fast < slow
if cross_up and self.Position <= 0:
self.BuyMarket()
elif cross_down and self.Position >= 0:
self.SellMarket()
self._prev_fast = fast
self._prev_slow = slow
self._has_prev = True
def CreateClone(self):
return x_trail_strategy()