La Estrategia de panel de intercambio de símbolos es una conversión StockSharp del panel MQL "Panel de intercambio de símbolos". El experto original actuó como un widget de gráfico que permitía a los operadores escribir un símbolo, cambiar el gráfico activo a ese símbolo y monitorear información de mercado en tiempo real, como valores OHLC, volumen de ticks y spread. La estrategia convertida recrea el mismo flujo de trabajo en el entorno StockSharp. Se puede iniciar con cualquier valor y proporciona un cambio manual para saltar a otro instrumento mientras registra continuamente las métricas de mercado más relevantes.
Comportamiento central
Se suscribe a datos de velas y cotizaciones de nivel uno para el valor activo.
Registra cada vela completa con apertura, máximo, mínimo, cierre, volumen total y el último diferencial calculado.
Almacena cotizaciones de oferta/demanda y obtiene un margen actualizado que refleja la lectura del panel MQL.
Reacciona a solicitudes de intercambio manuales y reemplaza la seguridad monitoreada con el identificador elegido sin necesidad de reiniciar la estrategia.
Mantiene la seguridad previamente seleccionada para que se ignoren los intercambios redundantes y las activaciones dobles accidentales no interrumpan las suscripciones.
Parámetros
Nombre
Tipo
Descripción
TargetSecurityId
string
Identificador de seguridad que debe activarse cuando se activa la solicitud de intercambio. Las cadenas vacías se ignoran con una advertencia.
CandleType
DataType
Agregación de velas para actualizaciones periódicas (el valor predeterminado es velas de 1 hora, replicando el período de tiempo del panel MQL.
SwapRequested
bool
Marcador manual que solicita un cambio inmediato a TargetSecurityId. Se restablece a false después de que se procesa el intento de intercambio.
Suscripciones de datos
Suscripción de vela creada con CandleType para la seguridad actualmente activa.
Suscripción de nivel uno utilizada para realizar un seguimiento de las cotizaciones de oferta y demanda y calcular un valor de diferencial en vivo.
Las suscripciones se reinician de forma segura cada vez que cambia la seguridad, lo que garantiza que no se dejen en ejecución flujos de datos obsoletos.
Flujo de trabajo
Cuando la estrategia comienza resuelve la seguridad inicial desde Strategy.Security o, si falta, desde TargetSecurityId.
Se abren suscripciones de vela y de nivel uno para ese instrumento.
Cada vela completa activa un mensaje de registro detallado que refleja el texto que se muestra en las etiquetas originales del panel.
Las actualizaciones entrantes de nivel uno actualizan los valores de oferta/demanda almacenados en caché.
Configurar SwapRequested en true y proporcionar un TargetSecurityId válido cambia inmediatamente la seguridad monitoreada y reinicia las suscripciones.
Notas de uso
La estrategia está diseñada para seguimiento manual y no realiza pedidos.
El diferencial solo se informa cuando los valores de oferta y demanda están presentes y son positivos.
Cuando se proporciona un símbolo no válido o desconocido, se registra una advertencia y la solicitud se descarta sin interrumpir las suscripciones en ejecución.
Debido a que la herramienta original actualizaba la interfaz de usuario una vez por segundo, puede reducir el período de tiempo de la vela si necesita actualizaciones de registro más frecuentes.
Se conservan las características originales de MQL
Cambio manual de símbolo a través de un identificador textual.
Visualización en tiempo real de valores, volumen y extensión de OHLC para el símbolo elegido.
Protege contra entradas vacías y adiciones fallidas de Market Watch (traducidas a advertencias StockSharp.
Diferencias con la implementación MQL
La estrategia StockSharp utiliza mensajes de registro en lugar de etiquetas en pantalla. Esto coincide con el flujo de trabajo típico dentro de StockSharp y al mismo tiempo expone la misma información.
El cambio de gráfico se implementa reasignando la seguridad de la estrategia y recreando las suscripciones en lugar de alterar la ventana del gráfico del terminal.
La lógica de actualización basada en temporizador se reemplaza por eventos de finalización de velas para mantenerse alineado con las API StockSharp de alto nivel.
Requisitos
Conector StockSharp con acceso a los valores deseados.
Alimentación de datos de nivel uno para obtener cotizaciones de oferta y demanda para el cálculo del diferencial.
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>
/// Price monitoring strategy that logs OHLC metrics and trades on candle patterns.
/// Simplified from the "Symbol Swap Panel" MQL display widget.
/// </summary>
public class SymbolSwapPanelStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _maPeriod;
private SimpleMovingAverage _sma;
private decimal _entryPrice;
private decimal _prevClose;
/// <summary>
/// Candle type for monitoring.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Moving average period for trend signals.
/// </summary>
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
/// <summary>
/// Initializes strategy parameters.
/// </summary>
public SymbolSwapPanelStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle series for monitoring and signals", "General");
_maPeriod = Param(nameof(MaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("MA Period", "Moving average period for entry signals", "Indicators");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, CandleType);
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_sma = null;
_entryPrice = 0m;
_prevClose = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_sma = new SimpleMovingAverage { Length = MaPeriod };
SubscribeCandles(CandleType)
.Bind(_sma, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
var price = candle.ClosePrice;
var high = candle.HighPrice;
var low = candle.LowPrice;
// Log price info
LogInfo(
$"Time: {candle.CloseTime:O}, O: {candle.OpenPrice}, H: {high}, L: {low}, C: {price}, " +
$"Vol: {candle.TotalVolume}, SMA: {smaValue:F5}");
// Exit: reversal or profit target
if (Position != 0 && _entryPrice > 0m)
{
var pnl = Position > 0
? price - _entryPrice
: _entryPrice - price;
// Exit on trend reversal
if ((Position > 0 && price < smaValue) ||
(Position < 0 && price > smaValue))
{
if (Position > 0)
SellMarket(Math.Abs(Position));
else
BuyMarket(Math.Abs(Position));
_entryPrice = 0m;
_prevClose = price;
return;
}
}
// Entry: follow MA trend with momentum confirmation
if (Position == 0 && _prevClose > 0m)
{
if (price > smaValue && _prevClose <= smaValue)
{
BuyMarket();
_entryPrice = price;
}
else if (price < smaValue && _prevClose >= smaValue)
{
SellMarket();
_entryPrice = price;
}
}
_prevClose = 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_panel_strategy(Strategy):
def __init__(self):
super(symbol_swap_panel_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Candle series for monitoring and signals", "General")
self._ma_period = self.Param("MaPeriod", 20) \
.SetGreaterThanZero() \
.SetDisplay("MA Period", "Moving average period for entry signals", "Indicators")
self._entry_price = 0.0
self._prev_close = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def MaPeriod(self):
return self._ma_period.Value
@MaPeriod.setter
def MaPeriod(self, value):
self._ma_period.Value = value
def OnReseted(self):
super(symbol_swap_panel_strategy, self).OnReseted()
self._entry_price = 0.0
self._prev_close = 0.0
def OnStarted2(self, time):
super(symbol_swap_panel_strategy, self).OnStarted2(time)
sma = SimpleMovingAverage()
sma.Length = self.MaPeriod
self.SubscribeCandles(self.CandleType) \
.Bind(sma, self._process_candle) \
.Start()
def _process_candle(self, candle, sma_value):
if candle.State != CandleStates.Finished:
return
price = float(candle.ClosePrice)
sma_v = float(sma_value)
# Exit: reversal against trend
if self.Position != 0 and self._entry_price > 0:
if (self.Position > 0 and price < sma_v) or \
(self.Position < 0 and price > sma_v):
if self.Position > 0:
self.SellMarket(abs(self.Position))
else:
self.BuyMarket(abs(self.Position))
self._entry_price = 0.0
self._prev_close = price
return
# Entry: follow MA trend with momentum confirmation
if self.Position == 0 and self._prev_close > 0:
if price > sma_v and self._prev_close <= sma_v:
self.BuyMarket()
self._entry_price = price
elif price < sma_v and self._prev_close >= sma_v:
self.SellMarket()
self._entry_price = price
self._prev_close = price
def CreateClone(self):
return symbol_swap_panel_strategy()