Diese Strategie ist eine StockSharp-Portierung des Expertenberaters Milestone 22.5. Sie handelt Rücksetzer innerhalb eines Trends, indem sie zwei geglättete gleitende Durchschnitte mit einem Volatilitäts- und Spike-Filter kombiniert. Wenn eine Kerze das Extrem der vorherigen Kerze durchbricht und der schnelle Durchschnitt die Bewegung bestätigt, wird eine Position in Richtung des dominanten Trends eröffnet. ATR verhindert den Handel in ruhigen Märkten und große Kerzenkörper werden als Spikes behandelt.
Backtests der ursprünglichen MQL-Version zeigen gute Leistung bei wichtigen Forex-Paaren. Die C#-Übersetzung legt Wert auf Klarheit und verwendet nur Marktorders für Ein- und Ausstiege.
Details
Einstiegskriterien:
Trendstärke zwischen MinTrend und MaxTrend.
Kerze durchbricht vorheriges Hoch oder Tief und schnelle SMA bestätigt.
ATR über MinRange und Kerzenkörper unter CandleSpike.
Long/Short: Beide Richtungen.
Ausstiegskriterien: Entgegengesetztes Signal schließt die Position.
Stops: Nicht implementiert; entgegengesetztes Signal fungiert als Stop.
Standardwerte:
SlowMaPeriod = 120
FastMaPeriod = 30
AtrPeriod = 14
MinTrend = 10
MaxTrend = 100
MinRange = 5
CandleSpike = 10
CandleType = TimeSpan.FromMinutes(1)
Filter:
Kategorie: Trendfolge
Richtung: Beide
Indikatoren: SMA, ATR
Stops: Nein
Komplexität: Mittel
Zeitrahmen: Intraday
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>
/// Milestone trend strategy using EMA crossover with trend confirmation.
/// </summary>
public class MilestoneTrendStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public MilestoneTrendStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "General");
_slowPeriod = Param(nameof(SlowPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type", "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 fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
SubscribeCandles(CandleType)
.Bind(fast, slow, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal)
{
if (candle.State != CandleStates.Finished) return;
if (!_hasPrev)
{
_prevFast = fastVal;
_prevSlow = slowVal;
_hasPrev = true;
return;
}
var crossUp = _prevFast <= _prevSlow && fastVal > slowVal;
var crossDown = _prevFast >= _prevSlow && fastVal < slowVal;
if (crossUp && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (crossDown && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevFast = fastVal;
_prevSlow = slowVal;
}
}