Conversión del MetaTrader 4 asesor experto up3x1.mq4 ubicado en MQL/8097.
Implementa el cruce triple de media móvil simple con un cambio positivo en el gráfico exactamente como en el guión original.
Los procesos solo completaron velas para emular la guardia Volume[0] > 1 que obligó al experto a evaluar una vez por barra.
Las funciones de gestión de riesgos incluyen toma de ganancias, stop loss, reducción dinámica de lotes después de perder operaciones y un trailing stop opcional.
Lógica de trading
Indicadores
Tres medias móviles simples con un desplazamiento del gráfico de 6 barras (rápida = 24, media = 60, lenta = 120 por defecto).
Entrada larga
Barra anterior: SMAfast₍t-1₎ < SMAmedium₍t-1₎ < SMAslow₍t-1₎.
Barra actual: SMAmedium₍t₎ < SMAfast₍t₎ < SMAslow₍t₎.
La condición replica ma1 < ma2 < ma3 && ma5 < ma4 < ma6 de MQL.
Entrada corta
Barra anterior: SMAfast₍t-1₎ > SMAmedium₍t-1₎ > SMAslow₍t-1₎.
Barra actual: SMAmedium₍t₎ > SMAfast₍t₎ > SMAslow₍t₎.
Reglas de salida
Take Profit y Stop Loss respetan la distancia de puntos configurada multiplicada por Security.PriceStep (o se usa directamente cuando se desconoce el paso).
El trailing stop bloquea las ganancias una vez que el precio avanza más de TrailingStopPoints y sigue el extremo alcanzado después de la entrada.
Salida a prueba de fallos cuando las medias móviles cambian al orden opuesto, reflejando la lógica OrderClose original.
Dimensionamiento de posiciones
El volumen predeterminado es igual a BaseVolume (0,1 lote) siempre que las métricas de la cartera no estén disponibles.
Cuando existe Portfolio.CurrentValue, la estrategia lo multiplica por RiskFraction (por defecto 0.00002, equivalente a la fórmula MQL FreeMargin * 0.02 / 1000).
Después de más de una salida perdedora, el volumen se reduce en volume * losses / 3, exactamente como en la rutina LotsOptimized.
El volumen se redondea a la baja a Security.VolumeStep y se reduce a cero si no puede satisfacer Security.MinVolume.
Parámetros
Parámetro
Predeterminado
Descripción
FastPeriod
24
Longitud del desplazamiento más rápido SMA.
MediumPeriod
60
Longitud del medio desplazada SMA.
SlowPeriod
120
Duración del cambio lento SMA.
TakeProfitPoints
150
Distancia en puntos de precio entre el precio de entrada y la toma de ganancias.
StopLossPoints
100
Distancia en puntos de precio entre el precio de entrada y el stop loss.
TrailingStopPoints
100
Distancia de trailing stop opcional en puntos (establecido en 0 para desactivarlo).
BaseVolume
0.1
Tamaño del comercio alternativo y volumen mínimo después de las reducciones.
RiskFraction
0.00002
Fracción del valor de la cartera utilizada para calcular el volumen dinámico.
CandleType
plazo de 1 hora
Serie de velas utilizadas para alimentar indicadores.
Notas de conversión
La estrategia utiliza el nivel alto API (SubscribeCandles + Bind) y evita los buffers de historial manuales.
Los valores del indicador se almacenan entre llamadas para imitar el parámetro shift sin acceso directo al índice.
Las salidas protectoras se ejecutan con comandos de mercado en el nivel de precio detectado para seguir siendo compatibles con la abstracción StockSharp.
Todos los comentarios en línea están escritos en inglés y cumplen con las pautas del proyecto.
Uso
Adjunte la estrategia a un valor y una cartera en StockSharp Designer o código.
Seleccione una serie de velas (CandleType) que coincida con su período de tiempo MT4 (H1 de forma predeterminada).
Revise los parámetros de riesgo basados en puntos para alinearlos con el tamaño del tick del instrumento (por ejemplo, 0,0001 para la mayoría de los pares de Forex).
Establezca TrailingStopPoints en cero cuando no sea necesario el seguimiento.
Supervise los registros en busca de mensajes como "Introducir largo" y "Salir breve" que reflejan los diagnósticos MQL.
Estructura del repositorio
API/3924/
├── CS/Up3x1ShiftedSmaStrategy.cs # Estrategia C# convertida con comentarios en inglés
├── README.md # Documentación en inglés (este archivo)
├── README_zh.md # traducción al chino
└── README_ru.md # traducción al ruso
Descargo de responsabilidad
El comercio implica un riesgo significativo. La estrategia se proporciona con fines educativos y debe validarse con datos históricos y simulados antes de operar en vivo.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class Up3x1ShiftedSmaStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Up3x1ShiftedSmaStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 8).SetDisplay("Fast WMA", "Fast WMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 24).SetDisplay("Slow WMA", "Slow WMA period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = default;
_prevSlow = default;
_hasPrev = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var fast = new SimpleMovingAverage { Length = FastPeriod };
var slow = new SimpleMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, slow, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) return;
if (!_hasPrev) { _prevFast = fast; _prevSlow = slow; _hasPrev = true; return; }
if (_cooldown > 0)
{
_cooldown--;
_prevFast = fast;
_prevSlow = slow;
return;
}
if (_prevFast <= _prevSlow && fast > slow && Position <= 0)
{
var volume = Volume + Math.Abs(Position);
BuyMarket(volume);
_cooldown = 2;
}
else if (_prevFast >= _prevSlow && fast < slow && Position >= 0)
{
var volume = Volume + Math.Abs(Position);
SellMarket(volume);
_cooldown = 2;
}
_prevFast = fast; _prevSlow = slow;
}
}
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
from datatype_extensions import *
from indicator_extensions import *
class up_3x1_shifted_sma_strategy(Strategy):
"""Simple SMA crossover (fast/slow) with cooldown between trades."""
def __init__(self):
super(up_3x1_shifted_sma_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 8).SetDisplay("Fast SMA", "Fast SMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 24).SetDisplay("Slow SMA", "Slow SMA period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))).SetDisplay("Candle Type", "Timeframe", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(up_3x1_shifted_sma_strategy, self).OnReseted()
self._prev_fast = 0
self._prev_slow = 0
self._has_prev = False
self._cooldown = 0
def OnStarted2(self, time):
super(up_3x1_shifted_sma_strategy, self).OnStarted2(time)
self._prev_fast = 0
self._prev_slow = 0
self._has_prev = False
self._cooldown = 0
fast = SimpleMovingAverage()
fast.Length = self._fast_period.Value
slow = SimpleMovingAverage()
slow.Length = self._slow_period.Value
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 not self.IsFormedAndOnlineAndAllowTrading():
return
fv = float(fast_val)
sv = float(slow_val)
if not self._has_prev:
self._prev_fast = fv
self._prev_slow = sv
self._has_prev = True
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fv
self._prev_slow = sv
return
if self._prev_fast <= self._prev_slow and fv > sv and self.Position <= 0:
volume = self.Volume + abs(self.Position)
self.BuyMarket(volume)
self._cooldown = 2
elif self._prev_fast >= self._prev_slow and fv < sv and self.Position >= 0:
volume = self.Volume + abs(self.Position)
self.SellMarket(volume)
self._cooldown = 2
self._prev_fast = fv
self._prev_slow = sv
def CreateClone(self):
return up_3x1_shifted_sma_strategy()