Diese Strategie ist eine direkte Portierung des Expertenberaters Universal Investor MetaTrader 4. Es kombiniert einen exponentiellen gleitenden Durchschnitt (EMA) und einen linear gewichteten gleitenden Durchschnitt (LWMA), um die kurzfristige Trendrichtung zu bestätigen, und führt den Handel mit einer Position mit adaptiver Positionsgröße durch.
Handelslogik
Abonnieren Sie den konfigurierten CandleType und berechnen Sie sowohl EMA als auch den LWMA mit dem durch MovingPeriod definierten Zeitraum.
Speichern Sie die beiden neuesten Werte jedes gleitenden Durchschnitts, damit die Logik die iMA(..., shift = 1/2)-Aufrufe des ursprünglichen EA nachahmt.
Erzeugen Sie ein Kaufsignal, wenn der vorherige LWMA über dem vorherigen EMA liegt, beide Durchschnittswerte gestiegen sind und es kein entgegengesetztes Signal für dieselbe Kerze gibt.
Erzeugen Sie ein Verkaufssignal, wenn der vorherige LWMA unter dem vorherigen EMA liegt, beide Durchschnittswerte gefallen sind und es kein entgegengesetztes Signal für dieselbe Kerze gibt.
Schließen Sie eine offene Long-Position, sobald der LWMA unter EMA fällt (Spiegellogik für Shorts).
Berechnen Sie das Handelsvolumen anhand des Strategieparameters Volume, erhöhen Sie es, um die MaximumRisk-Anforderung zu erfüllen, wenn der Portfoliowert groß genug ist, und reduzieren Sie es nach aufeinanderfolgenden Verlustgeschäften gemäß DecreaseFactor.
Senden Sie Marktaufträge mit BuyMarket/SellMarket und behalten Sie den Einstiegspreis im Auge, um gewinnende oder verlierende Ausstiege zu erkennen.
Die Strategie hält jeweils nur eine Position offen und kehrt sich erst nach einem vollständigen Schließen sofort um, wodurch das Verhalten des ursprünglichen MetaTrader-Skripts reproduziert wird.
Parameter
Name
Beschreibung
CandleType
Für Berechnungen verwendete Kerzenreihe.
MovingPeriod
Zeitraum sowohl für EMA als auch für LWMA.
MaximumRisk
Anteil des Eigenkapitals (0,05 = 5 %), der zur Berechnung des Mindestpositionsvolumens verwendet wird.
DecreaseFactor
Reduziert das Volumen nach aufeinanderfolgenden Verlustgeschäften (0 deaktiviert die Funktion).
Volume
Basisvertragsvolumen an BuyMarket/SellMarket übergeben.
Indikatoren
ExponentialMovingAverage
LinearWeightedMovingAverage
Notizen
Aufträge werden nur für geschlossene Kerzen erteilt, die mit EA übereinstimmen, das auf Time[0]-Prüfungen basiert.
Die Logik der Positionsgröße spiegelt die Funktion MetaTrader LotsOptimized wider, einschließlich der risikobasierten Komponente und des Verluststreak-Multiplikators.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class UniversalInvestor3920Strategy : 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;
private int _cooldown;
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 UniversalInvestor3920Strategy()
{
_fastPeriod = Param(nameof(FastPeriod), 12).SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 26).SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = default;
_prevSlow = default;
_hasPrev = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, slow, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) return;
if (!_hasPrev) { _prevFast = fast; _prevSlow = slow; _hasPrev = true; return; }
if (_cooldown > 0)
{
_cooldown--;
_prevFast = fast;
_prevSlow = slow;
return;
}
if (_prevFast <= _prevSlow && fast > slow && Position <= 0)
{
var volume = Volume + Math.Abs(Position);
BuyMarket(volume);
_cooldown = 2;
}
else if (_prevFast >= _prevSlow && fast < slow && Position >= 0)
{
var volume = Volume + Math.Abs(Position);
SellMarket(volume);
_cooldown = 2;
}
_prevFast = fast; _prevSlow = slow;
}
}