Boring EA2 Alert bildet die Benachrichtigungslogik des MetaTrader-4-Expert-Advisors boring-ea2 nach. Die Strategie hört auf abgeschlossene Kerzen, berechnet drei einfache gleitende Durchschnitte (SMA 3, SMA 20, SMA 150) und gibt informative Logs aus, wenn ein Crossover zwischen den Durchschnitten auftritt. Die Implementierung vermeidet bewusst Orderplatzierung: Ziel ist es, Tradern rechtzeitige Alarme zu geben, die sie mit diskretionärer Ausführung oder anderen automatisierten Strategien kombinieren können.
Strategielogik
Verfolgung gleitender Durchschnitte
Kurzfristiger Bias: Eine 3-Perioden-SMA reagiert auf unmittelbare Preisänderungen.
Mittlerer Trend: Eine 20-Perioden-SMA glättet den Preis über den kurzfristigen Swing-Horizont.
Langer Trend: Eine 150-Perioden-SMA repräsentiert den dominanten Hintergrundtrend.
Crossover-Erkennung
SMA3 vs SMA20: meldet "crossed up", wenn SMA3 über SMA20 steigt, und "crossed down", wenn sie darunter fällt. Interne Flags stellen sicher, dass jeder Übergang einmal gemeldet wird.
SMA3 vs SMA150: spiegelt dieselbe Logik gegenüber dem langfristigen Durchschnitt, um Momentum-Schübe oder Umkehrungen gegen den vorherrschenden Trend zu erkennen.
SMA20 vs SMA150: fügt eine mittel-/langfristige Bestätigungsebene hinzu, sodass Verschiebungen in der höheren Zeitrahmenstruktur eigene Alarme auslösen.
Initialisierungsschutz: Die erste abgeschlossene Kerze setzt nur den Anfangszustand. Alarme beginnen mit der zweiten abgeschlossenen Kerze, sobald eine echte Beziehungsänderung beobachtet wird.
Benachrichtigungsformat
Alarme spiegeln die ursprüngliche EA-Nachricht: Alert!!! - SYMBOL - TF - description.
Der Zeitrahmencode wird aus dem konfigurierten Kerzentyp abgeleitet. Standard-Labels im MetaTrader-Stil (M1, M5, H1 usw.) werden verwendet, wenn verfügbar; andere Zeitrahmen fallen auf kompakte Notation zurück (z. B. M45 oder D2).
Nachrichten werden mit AddInfoLog geschrieben und können an Log-Viewer, Skripte oder GUI-Dashboards weitergeleitet werden.
Parameter
Short SMA Length: Anzahl Perioden für den schnellen gleitenden Durchschnitt (Standard 3).
Medium SMA Length: Anzahl Perioden für den mittleren gleitenden Durchschnitt (Standard 20).
Long SMA Length: Anzahl Perioden für den langsamen gleitenden Durchschnitt (Standard 150).
Candle Type: Zeitrahmen zur Berechnung der gleitenden Durchschnitte. Standard sind 1-Minuten-Kerzen, passend zu den tickbasierten Prüfungen des EA mit hoher Reaktivität.
Zusätzliche Hinweise
Die Strategie sendet, ändert oder storniert keine Orders. Sie ist rein informativ.
Da Bind finalisierte Werte liefert, wird jedes Crossover auf abgeschlossenen Kerzen bewertet. Dies vermeidet die lauten Intrabar-Wechsel, die der ursprüngliche EA durch Tick-Zählung abmilderte.
Logging-basierte Benachrichtigungen können mit eigenen Handlern integriert werden, indem innerhalb einer Host-Anwendung Strategie-Logereignisse abonniert werden.
Derzeit wird keine Python-Übersetzung bereitgestellt; nur die C#-Version ist im API-Paket enthalten.
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Boring EA2 strategy: Triple SMA crossover.
/// Buys when fast crosses above medium while medium above slow.
/// Sells when fast crosses below medium while medium below slow.
/// </summary>
public class BoringEa2Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public BoringEa2Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new SimpleMovingAverage { Length = 10 };
var med = new SimpleMovingAverage { Length = 20 };
var slow = new SimpleMovingAverage { Length = 40 };
decimal? prevFast = null;
decimal? prevMed = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, med, slow, (candle, fastVal, medVal, slowVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (prevFast.HasValue && prevMed.HasValue)
{
var fastCrossUp = prevFast.Value <= prevMed.Value && fastVal > medVal;
var fastCrossDown = prevFast.Value >= prevMed.Value && fastVal < medVal;
if (fastCrossUp && medVal > slowVal && Position <= 0)
BuyMarket();
else if (fastCrossDown && medVal < slowVal && Position >= 0)
SellMarket();
}
prevFast = fastVal;
prevMed = medVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, med);
DrawIndicator(area, slow);
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class boring_ea2_strategy(Strategy):
def __init__(self):
super(boring_ea2_strategy, self).__init__()
self._fast = None
self._med = None
self._slow = None
self._prev_fast = None
self._prev_med = None
def OnReseted(self):
super(boring_ea2_strategy, self).OnReseted()
self._fast = None
self._med = None
self._slow = None
self._prev_fast = None
self._prev_med = None
def OnStarted2(self, time):
super(boring_ea2_strategy, self).OnStarted2(time)
self._fast = SimpleMovingAverage()
self._fast.Length = 10
self._med = SimpleMovingAverage()
self._med.Length = 20
self._slow = SimpleMovingAverage()
self._slow.Length = 40
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(15)))
subscription.Bind(self._fast, self._med, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, med_value, slow_value):
if candle.State != CandleStates.Finished:
return
if not self._fast.IsFormed or not self._med.IsFormed or not self._slow.IsFormed:
return
fast_val = float(fast_value)
med_val = float(med_value)
slow_val = float(slow_value)
if self._prev_fast is not None and self._prev_med is not None:
fast_cross_up = self._prev_fast <= self._prev_med and fast_val > med_val
fast_cross_down = self._prev_fast >= self._prev_med and fast_val < med_val
if fast_cross_up and med_val > slow_val and self.Position <= 0:
self.BuyMarket()
elif fast_cross_down and med_val < slow_val and self.Position >= 0:
self.SellMarket()
self._prev_fast = fast_val
self._prev_med = med_val
def CreateClone(self):
return boring_ea2_strategy()