La Estrategia de intercambio de símbolos es el puerto StockSharp de la utilidad MetaTrader 5 "Symbol Swap". El programa MQL5 original abre un panel donde un operador puede ingresar cualquier ticker, cambiar inmediatamente el gráfico actual a ese símbolo y monitorear una ventana de datos compacta con la última hora, precios de OHLC, volumen de ticks y spread. Esta conversión de C# mantiene las mismas responsabilidades y depende exclusivamente de la suscripción de alto nivel de StockSharp API.
Comportamiento
Al inicio, la estrategia resuelve el instrumento a observar. Primero intenta WatchedSecurityId; si el campo está vacío, vuelve a Strategy.Security que está configurado en el iniciador.
Los datos de la vela del CandleType elegido se transmiten a través de SubscribeCandles(...). Las barras terminadas brindan el volumen de apertura, máximo, mínimo, cierre y tick que puebla el panel.
Los mejores valores de oferta/demanda en tiempo real llegan a través de SubscribeLevel1(...). El diferencial se recalcula en cada actualización de cotización para reflejar la ventana de datos MQL.
El bloque formateado se escribe en el registro de estrategia (OutputMode = Log) o se representa en un gráfico (OutputMode = Chart) con DrawText(...), recreando el panel flotante de MetaTrader.
Llamar a SwapSecurity("TICKER") durante la ejecución resuelve la nueva seguridad a través de SecurityProvider.LookupById y vuelve a suscribir sin problemas tanto la vela como los feeds de Nivel 1 al instrumento solicitado.
La estrategia es sólo informativa; no realiza pedidos. Puede ejecutarse de forma independiente como un panel de mercado o junto con otros robots comerciales.
Parámetros
Nombre
Descripción
Predeterminado
CandleType
Marco de tiempo que define la suscripción de vela utilizada para generar OHLC y datos de volumen de ticks.
TimeFrame(1 minute)
WatchedSecurityId
Identificador de instrumento opcional. Déjelo vacío para usar Strategy.Security.
vacío
OutputMode
Destino de renderizado del bloque de información. Elija entre Chart (superposición cerca del precio) o Log (registro de estrategia).
Chart
Métodos públicos
Método
Descripción
SwapSecurity(string securityId)
Resuelve el ticker proporcionado a través del SecurityProvider activo e inmediatamente cambia el panel a ese símbolo. El método se puede llamar varias veces; cada llamada borra las suscripciones anteriores de vela/Nivel 1 antes de agregar las nuevas fuentes.
Notas de uso
Asegúrese de que el conector exponga el identificador solicitado; de lo contrario, SecurityProvider.LookupById genera una excepción.
Cuando OutputMode = Chart, la estrategia crea automáticamente un área de gráfico, dibuja las velas suscritas y superpone el bloque de estado. Para el modo de registro sólo se producen las actualizaciones textuales.
El volumen de ticks es igual al TotalVolume de la vela, que es como MetaTrader informa su recuento de ticks por barra.
El diferencial se muestra solo cuando están disponibles tanto la mejor oferta como la mejor demanda. De lo contrario, el campo muestra n/a.
Detalles de conversión
El bucle del temporizador MetaTrader se reemplaza con suscripciones StockSharp. Las velas se activan una vez por barra terminada y las cotizaciones de Nivel 1 actualizan el diferencial en tiempo real.
Las etiquetas del panel MQL están representadas por un único bloque de texto de varias líneas. El texto utiliza el orden exacto de la herramienta original: tiempo, período, símbolo, cierre, apertura, máximo, mínimo, volumen de tick, extensión.
Los intercambios de símbolos en tiempo de ejecución ya no necesitan una gestión manual de Market Watch: la estrategia resuelve los instrumentos directamente a través del proveedor de seguridad StockSharp.
Solo se utilizan llamadas API de alto nivel (SubscribeCandles, SubscribeLevel1, DrawText, AddInfo). No hay cálculos manuales de indicadores ni manipulaciones directas del conector, lo que satisface las reglas de codificación del repositorio.
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>
/// Market monitoring strategy that tracks price metrics and trades on significant
/// spread changes. Simplified from the MetaTrader "Symbol Swap" display panel.
/// </summary>
public class SymbolSwapStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _smaPeriod;
private readonly StrategyParam<decimal> _spreadThreshold;
private SimpleMovingAverage _sma;
private decimal _entryPrice;
/// <summary>
/// Candle type for monitoring.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// SMA period for trend detection.
/// </summary>
public int SmaPeriod
{
get => _smaPeriod.Value;
set => _smaPeriod.Value = value;
}
/// <summary>
/// Price deviation threshold for entry signals.
/// </summary>
public decimal SpreadThreshold
{
get => _spreadThreshold.Value;
set => _spreadThreshold.Value = value;
}
/// <summary>
/// Initializes strategy parameters.
/// </summary>
public SymbolSwapStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candle series for signals", "General");
_smaPeriod = Param(nameof(SmaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("SMA Period", "Moving average period", "Indicators");
_spreadThreshold = Param(nameof(SpreadThreshold), 3m)
.SetGreaterThanZero()
.SetDisplay("Spread Threshold", "Price deviation from SMA to trigger entry", "Signals");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, CandleType);
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_sma = null;
_entryPrice = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_sma = new SimpleMovingAverage { Length = SmaPeriod };
SubscribeCandles(CandleType)
.Bind(_sma, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormed)
return;
var price = candle.ClosePrice;
// Exit on mean reversion
if (Position != 0 && _entryPrice > 0m)
{
var pnl = Position > 0
? price - _entryPrice
: _entryPrice - price;
// Exit on profit or loss threshold
if (pnl >= SpreadThreshold || pnl <= -SpreadThreshold * 2m)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
else
BuyMarket(Math.Abs(Position));
_entryPrice = 0m;
return;
}
}
// Entry on deviation
if (Position == 0)
{
var deviation = price - smaValue;
if (deviation > SpreadThreshold)
{
SellMarket();
_entryPrice = price;
}
else if (deviation < -SpreadThreshold)
{
BuyMarket();
_entryPrice = price;
}
}
}
}
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_swap_strategy(Strategy):
def __init__(self):
super(symbol_swap_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candle series for signals", "General")
self._sma_period = self.Param("SmaPeriod", 20) \
.SetGreaterThanZero() \
.SetDisplay("SMA Period", "Moving average period", "Indicators")
self._spread_threshold = self.Param("SpreadThreshold", 3.0) \
.SetGreaterThanZero() \
.SetDisplay("Spread Threshold", "Price deviation from SMA to trigger entry", "Signals")
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def SmaPeriod(self):
return self._sma_period.Value
@SmaPeriod.setter
def SmaPeriod(self, value):
self._sma_period.Value = value
@property
def SpreadThreshold(self):
return self._spread_threshold.Value
@SpreadThreshold.setter
def SpreadThreshold(self, value):
self._spread_threshold.Value = value
def OnReseted(self):
super(symbol_swap_strategy, self).OnReseted()
self._entry_price = 0.0
def OnStarted2(self, time):
super(symbol_swap_strategy, self).OnStarted2(time)
sma = SimpleMovingAverage()
sma.Length = self.SmaPeriod
self.SubscribeCandles(self.CandleType) \
.Bind(sma, self._process_candle) \
.Start()
def _process_candle(self, candle, sma_value):
if candle.State != CandleStates.Finished:
return
if not self.IsFormed:
return
price = float(candle.ClosePrice)
sma_v = float(sma_value)
threshold = float(self.SpreadThreshold)
# Exit on mean reversion
if self.Position != 0 and self._entry_price > 0:
pnl = price - self._entry_price if self.Position > 0 else self._entry_price - price
if pnl >= threshold or pnl <= -threshold * 2:
if self.Position > 0:
self.SellMarket(abs(self.Position))
else:
self.BuyMarket(abs(self.Position))
self._entry_price = 0.0
return
# Entry on deviation
if self.Position == 0:
deviation = price - sma_v
if deviation > threshold:
self.SellMarket()
self._entry_price = price
elif deviation < -threshold:
self.BuyMarket()
self._entry_price = price
def CreateClone(self):
return symbol_swap_strategy()