Diese Strategie ist ein High-Level-StockSharp-Port des öffentlichen "MultiTrader"-MQL-Panels (Codebasis #24786). Der ursprüngliche Expertenberater war ein diskretionäres Dashboard, das die relative Stärke der acht wichtigsten Währungen anzeigte, visuelle/akustische Alerts auslöste, wenn eine Währung extrem stark oder schwach wurde, und vorschlug, welches Forex-Paar gehandelt werden soll. Die StockSharp-Version automatisiert denselben analytischen Workflow und führt optional Trades auf dem stärksten-vs.-schwächsten Paar aus.
Die Logik berechnet eine prozentuale Position des Schlusskurses jedes Symbols innerhalb seiner aktuellen Kerzenspanne. Das Mitteln der relevanten Kreuze ergibt einen Stärkewert für AUD, CAD, CHF, EUR, GBP, JPY, NZD und USD. Wenn eine Währung über den konfigurierbaren Kaufschwellenwert steigt und eine andere unter den Verkaufsschwellenwert fällt, empfiehlt die Strategie das aus diesen Währungen gebildete Paar. Wenn das Paar im konfigurierten Universum vorhanden ist, kann die Strategie automatisch eine Market-Order in diese Richtung platzieren.
Währungsstärkemodell
Die Prozentwertung für ein Symbol wird berechnet als:
percent = 100 * (Close - Low) / (High - Low)
Die Stärke jeder Währung wird aus sieben Kreuzen abgeleitet, was die MQL-Implementierung widerspiegelt. Eine 100 - percent-Inversion wird angewendet, wenn die Währung als Kurswährung im Paar erscheint:
Die Strategie speichert die letzte abgeschlossene Kerze pro Paar, behält den neuesten Prozentsatz und aktualisiert die Währungsstärken nach jeder Aktualisierung.
Handel und Alerts
Wenn alle acht Währungen gültige Daten haben, protokolliert die Strategie einen Snapshot (stärkste bis schwächste).
Wenn der stärkste Wert ≥ BuyLevel und der schwächste Wert ≤ SellLevel ist, wird ein Handelsvorschlag generiert.
Die Strategie versucht, das direkte Paar zu finden (starke Währung als Basis, schwache Währung als Kurs). Wenn es nicht existiert, prüft sie die inverse Orientierung und greift schließlich auf Paare mit USD zurück.
Das erkannte Paar und die Richtung werden protokolliert. Wenn EnableAutoTradingtrue ist und OrderVolume positiv ist, gibt die Strategie eine Market-Order in die vorgeschlagene Richtung aus. Entgegengesetzte Positionen werden automatisch durch Erhöhung der Auftragsgröße geflacht.
Signale werden durch Merken des zuletzt vorgeschlagenen Paares und der Seite gedrosselt, was doppelte Alerts verhindert, bis der Markt die Schwellenwertzone verlässt.
Parameter
Name
Beschreibung
Standard
Universe
Liste von Security-Objekten, die die FX-Paare repräsentieren (28 Hauptpaare empfohlen).
Erforderlich
CandleType
Kerzenspezifikation für Berechnungen (Täglich, Wöchentlich, Monatlich, etc.).
Tageskerzen
BuyLevel
Schwellenwert, über dem eine Währung als überkauft gilt.
90
SellLevel
Schwellenwert, unter dem eine Währung als überverkauft gilt.
10
EnableAutoTrading
Aktiviert oder deaktiviert automatische Orderplatzierung.
false
OrderVolume
Volumen für Market-Orders bei aktiviertem Auto-Trading.
1
SymbolPrefix
Optionales Präfix vom Broker/Exchange (z.B. m.).
""
SymbolSuffix
Optionales Suffix vom Broker/Exchange (z.B. .FX).
""
Konfigurationsschritte
Universum-Setup. Fügen Sie die 28 wichtigsten Forex-Kreuze zum Strategieuniversum hinzu. Codes sollten den kanonischen Parnamen entsprechen (z.B. EURUSD). Verwenden Sie SymbolPrefix/SymbolSuffix, wenn Ihr Broker Dekorationen hinzufügt.
Zeitrahmenauswahl. Wählen Sie den gewünschten CandleType. Tages-, Wochen- und Monatskerzen reproduzieren die ursprünglichen Panel-Modi.
Schwellenwert-Anpassung. Passen Sie BuyLevel/SellLevel an, um zu steuern, wie extrem die Stärke sein muss, bevor ein Signal generiert wird.
Auto-Trading (optional). Setzen Sie EnableAutoTrading auf true und definieren Sie OrderVolume. Lassen Sie das Flag auf false, um nur Informationsprotokolle zu empfangen.
Migrationshinweise
Die gesamte GUI-Schicht des ursprünglichen MQL-Panels wird bewusst weggelassen. Alle Ausgaben sind über das Strategieprotokoll verfügbar.
Alerts werden als LogInfo-Einträge ausgegeben; Push-/E-Mail-/Desktop-Benachrichtigungen wurden nicht portiert.
Automatische Stop-Loss-/Zielberechnungen der MQL-Version werden nicht unterstützt; Trader sollten das Risiko über StockSharp-Schutzmodule oder externe Risikokontrollen verwalten.
Der DES-basierte Lizenz-Helper im MQL-Skript wurde entfernt.
Empfohlene Verwendung
Setzen Sie die Strategie in einer Connector-Sitzung ein, die Echtzeit- und historische Kerzen für alle relevanten Paare liefert.
Kombinieren Sie sie mit einem Chart-Widget, um das vorgeschlagene Paar zu visualisieren und die zugrunde liegenden Kerzenserien zu überwachen.
Verwenden Sie StockSharp-StartProtection-Parameter oder separate Risikostrategien für globale Stops/Ziele.
Testüberlegungen
Stellen Sie sicher, dass Ihre Datenquelle abgeschlossene Kerzen für den ausgewählten Zeitrahmen liefert; die Strategie ignoriert unfertige Kerzen.
Wenn einige Paare im Universum fehlen, kann die entsprechende Währung nicht berechnet werden und es wird kein Signal erzeugt.
Stellen Sie beim Bewerten der historischen Leistung sicher, dass das Universum während des gesamten Backtests statisch bleibt, um Stärkelücken zu vermeiden.
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;
public class MultiTraderStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public MultiTraderStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_prevFast = fastValue; _prevSlow = slowValue;
}
}
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 multi_trader_strategy(Strategy):
def __init__(self):
super(multi_trader_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(multi_trader_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(multi_trader_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return multi_trader_strategy()