Molly ETF EMA Crossover-Strategie
Die Strategie eröffnet eine Long-Position, wenn die schnelle EMA die langsame EMA von unten kreuzt, und schließt sie, wenn die schnelle EMA die langsame EMA von oben kreuzt. Sie enthält optionale Parameter zur Einschränkung des Handels auf einen bestimmten Datumsbereich.
Details
- Einstiegskriterien:
- Long: Die schnelle EMA kreuzt die langsame EMA nach oben innerhalb des Datumsbereichs.
- Long/Short: Nur Long.
- Ausstiegskriterien:
- Die schnelle EMA kreuzt die langsame EMA nach unten oder der Datumsbereich endet.
- Stops: Keine.
- Standardwerte:
Fast EMA= 10Slow EMA= 21Start Date= 2018-01-01End Date= 2023-09-07
- Filter:
- Kategorie: Trendfolge
- Richtung: Nur Long
- Indikatoren: EMA
- Stops: Nein
- Komplexität: Grundlegend
- Zeitrahmen: Beliebig
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Niedrig
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>
/// Molly ETF EMA crossover strategy.
/// Goes long when fast EMA crosses above slow EMA and exits on opposite cross.
/// Supports optional date range filter.
/// </summary>
public class MollyEtfEmaCrossoverStrategy : Strategy
{
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
private readonly StrategyParam<bool> _useDateFilter;
private readonly StrategyParam<DateTime> _startDate;
private readonly StrategyParam<DateTime> _endDate;
private readonly StrategyParam<DataType> _candleType;
/// <summary>
/// Fast EMA period length.
/// </summary>
public int FastLength
{
get => _fastLength.Value;
set => _fastLength.Value = value;
}
/// <summary>
/// Slow EMA period length.
/// </summary>
public int SlowLength
{
get => _slowLength.Value;
set => _slowLength.Value = value;
}
/// <summary>
/// Enable trading only within specified date range.
/// </summary>
public bool UseDateFilter
{
get => _useDateFilter.Value;
set => _useDateFilter.Value = value;
}
/// <summary>
/// Start date of allowed trading period.
/// </summary>
public DateTime StartDate
{
get => _startDate.Value;
set => _startDate.Value = value;
}
/// <summary>
/// End date of allowed trading period.
/// </summary>
public DateTime EndDate
{
get => _endDate.Value;
set => _endDate.Value = value;
}
/// <summary>
/// Candle type to use.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="MollyEtfEmaCrossoverStrategy"/> class.
/// </summary>
public MollyEtfEmaCrossoverStrategy()
{
_fastLength = Param(nameof(FastLength), 10)
.SetGreaterThanZero()
.SetDisplay("Fast EMA", "Length of the fast EMA", "Parameters");
_slowLength = Param(nameof(SlowLength), 21)
.SetGreaterThanZero()
.SetDisplay("Slow EMA", "Length of the slow EMA", "Parameters");
_useDateFilter = Param(nameof(UseDateFilter), false)
.SetDisplay("Use Date Filter", "Enable date range filtering", "Date Range");
_startDate = Param(nameof(StartDate), new DateTime(2018, 1, 1))
.SetDisplay("Start Date", "Beginning of trading period", "Date Range");
_endDate = Param(nameof(EndDate), new DateTime(2030, 1, 1))
.SetDisplay("End Date", "End of trading period", "Date Range");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastEma = new EMA { Length = FastLength };
var slowEma = new EMA { Length = SlowLength };
var subscription = SubscribeCandles(CandleType);
var wasFastAboveSlow = false;
var initialized = false;
var wasInTradeWindow = false;
subscription
.Bind(fastEma, slowEma, (candle, fastValue, slowValue) =>
{
if (candle.State != CandleStates.Finished)
return;
var candleTime = candle.OpenTime;
var inTradeWindow = !UseDateFilter || (candleTime >= StartDate && candleTime < EndDate);
if (!inTradeWindow && wasInTradeWindow)
{
CancelActiveOrders();
ClosePosition();
}
wasInTradeWindow = inTradeWindow;
if (!inTradeWindow)
return;
if (!initialized)
{
if (fastEma.IsFormed && slowEma.IsFormed)
{
wasFastAboveSlow = fastValue > slowValue;
initialized = true;
}
return;
}
var isFastAboveSlow = fastValue > slowValue;
var crossOver = !wasFastAboveSlow && isFastAboveSlow;
var crossUnder = wasFastAboveSlow && !isFastAboveSlow;
if (crossOver && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
if (crossUnder && Position > 0)
SellMarket(Math.Abs(Position));
wasFastAboveSlow = isFastAboveSlow;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastEma);
DrawIndicator(area, slowEma);
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
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class molly_etf_ema_crossover_strategy(Strategy):
"""
Molly ETF EMA crossover: long when fast EMA crosses above slow, exit on opposite cross.
"""
def __init__(self):
super(molly_etf_ema_crossover_strategy, self).__init__()
self._fast_length = self.Param("FastLength", 10).SetDisplay("Fast EMA", "Fast EMA length", "Parameters")
self._slow_length = self.Param("SlowLength", 21).SetDisplay("Slow EMA", "Slow EMA length", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))).SetDisplay("Candle Type", "Candles", "General")
self._was_fast_above = False
self._initialized = False
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(molly_etf_ema_crossover_strategy, self).OnReseted()
self._was_fast_above = False
self._initialized = False
def OnStarted2(self, time):
super(molly_etf_ema_crossover_strategy, self).OnStarted2(time)
fast = ExponentialMovingAverage()
fast.Length = self._fast_length.Value
slow = ExponentialMovingAverage()
slow.Length = self._slow_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast, slow, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def _process_candle(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
fast = float(fast_val)
slow = float(slow_val)
if not self._initialized:
self._was_fast_above = fast > slow
self._initialized = True
return
is_fast_above = fast > slow
cross_over = not self._was_fast_above and is_fast_above
cross_under = self._was_fast_above and not is_fast_above
if cross_over and self.Position <= 0:
self.BuyMarket()
if cross_under and self.Position > 0:
self.SellMarket()
self._was_fast_above = is_fast_above
def CreateClone(self):
return molly_etf_ema_crossover_strategy()