Die Symbol-Synchronisierungsstrategie repliziert das MetaTrader-Dienstprogramm SymbolSyncEA innerhalb der StockSharp-Umgebung. Die Strategie synchronisiert das Hauptstrategiesymbol und alle registrierten verknüpften Strategien. Immer wenn sich das primäre Symbol ändert, überträgt die Strategie die neue Sicherheit automatisch auf jede verknüpfte Strategie und stellt so sicher, dass der gesamte Arbeitsbereich ohne manuelle Eingriffe demselben Instrument folgt.
Kernideen
Erfassen Sie die anfängliche Strategiesicherheit beim Start und verwenden Sie sie als Fallback-Option wieder.
Führen Sie eine konfigurierbare Liste verknüpfter Strategien, die immer die Hauptsicherheit widerspiegeln sollten.
Symboländerungen zulassen, die entweder durch eine direkte Security-Zuweisung oder durch Angabe einer neuen Sicherheitskennung ausgelöst werden.
Stellen Sie manuelle Synchronisierungs- und Rücksetzvorgänge bereit, um dem ursprünglichen Verhalten des Expert Advisors zu entsprechen.
Parameter
Name
Beschreibung
Standard
ChartLimit
Maximale Anzahl verknüpfter Strategien, die synchronisiert werden können. Verhindert versehentliche Massenaktualisierungen.
10
SyncSecurityId
Bezeichner der Sicherheit, die an verknüpfte Strategien weitergegeben wird. Ein leerer Wert fällt auf die Strategiesicherheit zurück.
""
Öffentliche Methoden
RegisterLinkedStrategy(Strategy strategy) – fügt eine Strategieinstanz zur Synchronisierungsliste hinzu. Gibt bei erfolgreicher Registrierung true zurück.
UnregisterLinkedStrategy(Strategy strategy) – entfernt eine Strategie aus der Liste.
ChangeSyncSecurity(Security security) – wechselt zur bereitgestellten Sicherheitsinstanz und gibt sie an jede verknüpfte Strategie weiter.
ChangeSyncSecurity(string securityId) – löst die Kennung durch den aktuellen SecurityProvider auf und ruft ChangeSyncSecurity(Security) auf.
ResetToInitialSecurity() – stellt das beim Start erfasste Symbol wieder her.
SyncSymbols() – erzwingt eine manuelle Neusynchronisierung, ohne die gespeicherte Kennung zu ändern.
Nutzungsworkflow
Instanziieren Sie SymbolSyncStrategy und legen Sie den primären Security fest oder weisen Sie SyncSecurityId zu, bevor Sie mit der Strategie beginnen.
Rufen Sie RegisterLinkedStrategy für jede untergeordnete Strategie auf, die das aktive Symbol widerspiegeln muss (z. B. unterschiedliche Zeitrahmen oder Dashboards).
Wenn sich das Hauptsymbol ändern sollte, rufen Sie ChangeSyncSecurity(Security) oder ChangeSyncSecurity(string) auf.
Rufen Sie optional SyncSymbols() auf, um die Weitergabe zu erzwingen, wenn eine externe Komponente eine verknüpfte Strategie geändert hat.
Unterschiede zur MQL-Version
Funktioniert mit StockSharp Strategy Instanzen anstelle von MetaTrader Diagrammfenstern.
Verwendet die SecurityProvider-Abstraktion, um Bezeichner aufzulösen.
Fügt defensive Protokollierung und ein konfigurierbares Limit für synchronisierte Strategien hinzu.
Bietet explizite Reset- und manuelle Synchronisierungsmethoden für erweiterte Automatisierungsszenarien.
Notizen
Die Strategie erteilt keine Marktaufträge; Es fungiert als Infrastrukturhelfer.
Alle Codekommentare werden auf Englisch gehalten, um den Projektanforderungen zu entsprechen.
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>
/// Strategy that synchronizes the security of linked strategies whenever the main symbol changes.
/// </summary>
public class SymbolSyncStrategy : Strategy
{
private readonly StrategyParam<int> _chartLimit;
private readonly StrategyParam<string> _syncSecurityId;
private readonly List<Strategy> _linkedStrategies = new();
private Security _initialSecurity;
public SymbolSyncStrategy()
{
_chartLimit = Param(nameof(ChartLimit), 10)
.SetNotNegative()
.SetDisplay("Chart limit", "Maximum number of linked strategies that can be synchronized.", "General")
;
_syncSecurityId = Param(nameof(SyncSecurityId), string.Empty)
.SetDisplay("Sync security ID", "Identifier of the security propagated to linked strategies.", "General")
;
}
/// <summary>
/// Maximum number of linked strategies that can follow the symbol changes.
/// </summary>
public int ChartLimit
{
get => _chartLimit.Value;
set => _chartLimit.Value = value;
}
/// <summary>
/// Identifier of the security that must be mirrored by linked strategies.
/// </summary>
public string SyncSecurityId
{
get => _syncSecurityId.Value;
set => _syncSecurityId.Value = value ?? string.Empty;
}
private SimpleMovingAverage _smaFast;
private SimpleMovingAverage _smaSlow;
private int _candleCount;
private int _lastTradeCandle;
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_linkedStrategies.Clear();
_initialSecurity = default;
_smaFast = default;
_smaSlow = default;
_candleCount = default;
_lastTradeCandle = default;
_syncSecurityId.Value = string.Empty;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_initialSecurity = Security;
if (SyncSecurityId.IsEmpty() && Security != null)
SyncSecurityId = Security.Id;
_smaFast = new SimpleMovingAverage { Length = 10 };
_smaSlow = new SimpleMovingAverage { Length = 30 };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription
.Bind(_smaFast, _smaSlow, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
_candleCount++;
if (_candleCount - _lastTradeCandle < 200)
return;
if (fast > slow && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
_lastTradeCandle = _candleCount;
}
else if (fast < slow && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
_lastTradeCandle = _candleCount;
}
}
/// <inheritdoc />
protected override void OnStopped()
{
base.OnStopped();
_initialSecurity = null;
}
/// <summary>
/// Registers an additional strategy that must mirror the current security.
/// </summary>
/// <param name="strategy">Strategy that will receive symbol updates.</param>
/// <returns><c>true</c> when the strategy is registered; otherwise <c>false</c>.</returns>
public bool RegisterLinkedStrategy(Strategy strategy)
{
if (strategy == null)
throw new ArgumentNullException(nameof(strategy));
if (_linkedStrategies.Contains(strategy))
return false;
var limit = Math.Max(ChartLimit, 0);
if (_linkedStrategies.Count >= limit)
{
LogWarning($"Chart limit of {limit} reached. Strategy '{strategy.Name}' cannot be synchronized.");
return false;
}
_linkedStrategies.Add(strategy);
ApplySymbol(strategy);
return true;
}
/// <summary>
/// Removes a strategy from the synchronization list.
/// </summary>
/// <param name="strategy">Strategy previously added with <see cref="RegisterLinkedStrategy"/>.</param>
/// <returns><c>true</c> when the strategy was removed.</returns>
public bool UnregisterLinkedStrategy(Strategy strategy)
{
if (strategy == null)
throw new ArgumentNullException(nameof(strategy));
return _linkedStrategies.Remove(strategy);
}
/// <summary>
/// Restores the initial security captured when the strategy started.
/// </summary>
public void ResetToInitialSecurity()
{
if (_initialSecurity == null)
return;
ChangeSyncSecurity(_initialSecurity);
}
/// <summary>
/// Changes the synchronization security using a resolved <see cref="Security"/> instance.
/// </summary>
/// <param name="security">Security that should be mirrored by linked strategies.</param>
/// <returns><c>true</c> when the identifier changed.</returns>
public bool ChangeSyncSecurity(Security security)
{
if (security == null)
throw new ArgumentNullException(nameof(security));
if (Security != security)
Security = security;
if (SyncSecurityId.EqualsIgnoreCase(security.Id))
{
SyncSymbols();
return false;
}
SyncSecurityId = security.Id;
SyncSymbols();
return true;
}
/// <summary>
/// Changes the synchronization security by resolving the identifier through <see cref="Strategy.Connector"/>.
/// </summary>
/// <param name="securityId">Identifier of the security to use for synchronization.</param>
/// <returns><c>true</c> when the identifier resolved to a new security.</returns>
public bool ChangeSyncSecurity(string securityId)
{
if (securityId.IsEmpty())
throw new ArgumentNullException(nameof(securityId));
if (Connector != null)
{
var resolved = Connector.LookupById(securityId);
if (resolved != null)
return ChangeSyncSecurity(resolved);
LogWarning($"Security '{securityId}' not found by the security provider.");
}
SyncSecurityId = securityId;
SyncSymbols();
return false;
}
/// <summary>
/// Synchronizes the security across every registered strategy.
/// </summary>
/// <returns><c>true</c> when a security was resolved and propagated.</returns>
public bool SyncSymbols()
{
var security = ResolveSecurity();
if (security == null)
{
LogWarning("No synchronization security resolved. Linked strategies keep their current assignments.");
return false;
}
if (Security != security)
Security = security;
foreach (var strategy in _linkedStrategies)
ApplySymbol(strategy);
return true;
}
private void ApplySymbol(Strategy strategy)
{
if (strategy == null)
return;
var security = ResolveSecurity();
if (security == null)
return;
if (strategy.Security == security)
return;
strategy.Security = security;
}
private Security ResolveSecurity()
{
if (Security != null && (SyncSecurityId.IsEmpty() || SyncSecurityId.EqualsIgnoreCase(Security.Id)))
return Security;
if (!SyncSecurityId.IsEmpty() && Connector != null)
{
var resolved = Connector.LookupById(SyncSecurityId);
if (resolved != null)
return resolved;
}
return Security;
}
}
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 symbol_sync_strategy(Strategy):
"""Fast/slow SMA crossover (10/30) on 5-min candles."""
def __init__(self):
super(symbol_sync_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candle timeframe", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnStarted2(self, time):
super(symbol_sync_strategy, self).OnStarted2(time)
fast = SimpleMovingAverage()
fast.Length = 10
slow = SimpleMovingAverage()
slow.Length = 30
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(fast, slow, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def OnProcess(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
if fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return symbol_sync_strategy()