Estrategia de MultiTrader Currency Strength (3253)
Descripción general
Esta estrategia es un puerto de alto nivel de StockSharp del panel público "MultiTrader" de MQL (código base #24786). El Asesor Experto original era un panel discrecional que mostraba la fortaleza relativa de las ocho divisas principales, activaba alertas visuales/auditivas cuando una divisa se volvía extremadamente fuerte o débil, y sugería qué par de Forex operar. La versión de StockSharp automatiza el mismo flujo de trabajo analítico y opcionalmente ejecuta trades en el par más fuerte vs. más débil.
La lógica calcula la posición porcentual del cierre de cada símbolo dentro de su rango de vela actual. Promediar los cruces relevantes produce una puntuación de fortaleza para AUD, CAD, CHF, EUR, GBP, JPY, NZD y USD. Cuando una divisa sube por encima del umbral de compra configurable y otra cae por debajo del umbral de venta, la estrategia recomienda el par construido a partir de esas divisas. Si el par existe en el universo configurado, la estrategia puede colocar automáticamente una orden de mercado en esa dirección.
Modelo de fortaleza de divisas
La puntuación porcentual de un símbolo se calcula como:
percent = 100 * (Close - Low) / (High - Low)
La fortaleza de cada divisa se deriva de siete cruces, reflejando la implementación de MQL. Se aplica una inversión 100 - percent cuando la divisa aparece como divisa cotizada en el par:
La estrategia almacena la última vela completada por par, mantiene el porcentaje más reciente y actualiza las fortalezas de las divisas después de cada actualización.
Trading y alertas
Cuando las ocho divisas tienen datos válidos, la estrategia registra una instantánea (de la más fuerte a la más débil).
Si el valor más fuerte es ≥ BuyLevel y el valor más débil es ≤ SellLevel, se genera una sugerencia de trading.
La estrategia intenta encontrar el par directo (divisa fuerte como base, divisa débil como cotización). Si no existe, verifica la orientación inversa y finalmente recurre a pares que involucran USD.
El par detectado y la dirección se registran. Si EnableAutoTrading es true y OrderVolume es positivo, la estrategia emite una orden de mercado en la dirección sugerida. Las posiciones opuestas se aplanan automáticamente aumentando el tamaño de la orden.
Las señales se limitan recordando el último par sugerido y el lado, evitando alertas duplicadas hasta que el mercado salga de la zona de umbral.
Parámetros
Nombre
Descripción
Predeterminado
Universe
Lista de objetos Security que representan los pares de FX (se recomiendan 28 principales).
Requerido
CandleType
Especificación de vela utilizada para los cálculos (Diario, Semanal, Mensual, etc.).
Velas diarias
BuyLevel
Umbral por encima del cual una divisa se trata como sobrecomprada.
90
SellLevel
Umbral por debajo del cual una divisa se trata como sobrevendida.
10
EnableAutoTrading
Habilita o deshabilita la colocación automática de órdenes.
false
OrderVolume
Volumen para enviar con órdenes de mercado cuando el trading automático está habilitado.
1
SymbolPrefix
Prefijo opcional utilizado por el broker/exchange (p.ej., m.).
""
SymbolSuffix
Sufijo opcional utilizado por el broker/exchange (p.ej., .FX).
""
Pasos de configuración
Configuración del universo. Añada los 28 cruces de Forex principales al universo de la estrategia. Los códigos deben coincidir con los nombres canónicos de los pares (p.ej., EURUSD). Use SymbolPrefix/SymbolSuffix si su broker añade decoraciones.
Selección de temporalidad. Elija el CandleType deseado. Las velas diarias, semanales y mensuales reproducen los modos del panel original.
Ajuste de umbrales. Ajuste BuyLevel/SellLevel para controlar cuán extrema debe ser la fortaleza antes de generar una señal.
Trading automático (opcional). Establezca EnableAutoTrading en true y defina OrderVolume. Deje la bandera en false para recibir solo registros informativos.
Notas de migración
La capa GUI completa del panel MQL original se omite intencionalmente. Toda la salida está disponible a través del registro de la estrategia.
Las alertas se emiten como entradas LogInfo; las notificaciones push/email/escritorio no fueron portadas.
Los cálculos automáticos de stop-loss/objetivo de la versión MQL no son compatibles; los traders deben gestionar el riesgo usando los módulos de protección de StockSharp o controles de riesgo externos.
El helper de licencias basado en DES incrustado en el script MQL fue eliminado.
Uso recomendado
Despliegue la estrategia dentro de una sesión de conector que proporcione velas en tiempo real e históricas para todos los pares relevantes.
Combine con un widget de gráfico para visualizar el par sugerido y monitorear las series de velas subyacentes.
Use los parámetros StartProtection de StockSharp o estrategias de riesgo separadas para hacer cumplir stops/objetivos globales.
Consideraciones de prueba
Verifique que su fuente de datos entregue velas completadas para la temporalidad seleccionada; la estrategia ignora las barras no terminadas.
Si algunos pares faltan en el universo, la divisa correspondiente no puede calcularse y no se producirá ninguna señal.
Al evaluar el rendimiento histórico, asegúrese de que el universo permanezca estático durante todo el backtest para evitar brechas de fortaleza.
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()