Esta estrategia porta el experto de MetaTrader Starter.mq5 a la API de alto nivel de StockSharp. Sincroniza tres osciladores stochastic (rápido, normal, lento) con medias móviles coincidentes calculadas en diferentes marcos temporales. Un trade se permite solo cuando todos los filtros confirman la misma dirección y el precio opera en el lado correcto de cada media móvil desplazada.
Lógica de trading
La estrategia se suscribe a tres flujos de velas:
Marco temporal rápido (por defecto M5).
Marco temporal normal (por defecto M30).
Marco temporal lento (por defecto H2).
Para cada flujo construye una media móvil (método configurable, longitud y precio aplicado) y un oscilador stochastic con los mismos parámetros %K, %D y slowdown.
El marco temporal lento impulsa la ejecución. Cuando una vela lenta cierra, se comparan los últimos valores de todos los marcos temporales:
Configuración larga: cada línea stochastic tiene %K > %D, todos los valores %K están por debajo de 50, y el precio está por debajo de cada media móvil desplazada.
Configuración corta: cada línea stochastic tiene %K < %D, todos los valores %K están por encima de 50, y el precio está por encima de cada media móvil desplazada.
Las señales pueden invertirse opcionalmente a través de ReverseSignals. Cuando se toma una entrada, la estrategia invierte la exposición existente (si CloseOppositePositions = true) o ignora la señal hasta que el posición opuesta esté cerrada.
Después de un llenado, los niveles de stop-loss y take-profit se simulan en el espacio de precio. Un trailing stop replica la lógica MQL original requiriendo TrailingStopPips + TrailingStepPips de ganancia antes de mover el stop por TrailingStopPips.
El dimensionamiento de posición basado en riesgo refleja el interruptor lot/risk de MetaTrader. Cuando el modo es RiskPercent, el volumen del trade se deriva del valor de la cuenta, el porcentaje de riesgo y la distancia de stop-loss en pips.
Parámetros
Nombre
Predeterminado
Descripción
StopLossPips
45
Distancia protectora de stop en pips. Establecer en 0 para deshabilitar el stop fijo.
TakeProfitPips
105
Distancia de take-profit en pips. Establecer en 0 para deshabilitar el objetivo.
TrailingStopPips
5
Offset de trailing stop aplicado después del avance mínimo.
TrailingStepPips
5
Avance mínimo de ganancia (en pips) requerido antes de que el trailing stop se mueva.
MoneyMode
RiskPercent
Selecciona entre dimensionamiento de lote fijo y riesgo porcentual por trade.
MoneyValue
3
Tamaño de lote cuando se usa FixedLot, o porcentaje de riesgo cuando se usa RiskPercent.
FastCandleType
M5
Tipo de vela para el conjunto de indicadores rápido.
NormalCandleType
M30
Tipo de vela para el conjunto de indicadores intermedio.
SlowCandleType
H2
Tipo de vela que desencadena la evaluación de señales y órdenes.
MaPeriod
20
Longitud de todas las medias móviles.
MaShift
1
Desplazamiento horizontal aplicado a cada media móvil (barras atrás).
MaMethod
Simple
Suavizado de media móvil: Simple, Exponential, Smoothed, o Weighted.
MaPriceType
Close
Precio aplicado para alimentar las medias móviles.
StochasticKPeriod
5
Longitud %K para todos los osciladores stochastic.
StochasticDPeriod
3
Longitud de suavizado %D.
StochasticSlowing
3
Factor de slowdown final para %K.
ReverseSignals
false
Intercambia las condiciones larga y corta.
CloseOppositePositions
false
Si es true, revierte la posición en una única orden cuando aparece una señal en la dirección opuesta.
Gestión monetaria
MoneyMode = FixedLot envía cada orden con el volumen exacto de MoneyValue.
MoneyMode = RiskPercent reproduce el comportamiento original: el efectivo arriesgado equivale a AccountValue * MoneyValue / 100. El tamaño del trade se calcula como efectivo arriesgado / (StopLossPips * tamaño del pip). Si StopLossPips es cero o el valor de la cartera no está disponible, la estrategia se niega a operar.
Protección y trailing
Los niveles de stop-loss y take-profit se rastrean internamente y se comparan con los máximos/mínimos de las velas, emulando las órdenes protectoras de MetaTrader.
El trailing stop se activa solo después de que la ganancia no realizada supere TrailingStopPips + TrailingStepPips pips, cumpliendo el requisito original de que tanto un offset inicial como un paso mínimo deben satisfacerse antes de mover el stop.
Alineación multitemporal
Todos los indicadores se recalculan en cada vela cerrada de su respectivo marco temporal. El marco temporal lento espera a que las tres medias móviles y los stochastics formen y utiliza los valores más recientes de la media móvil desplazada, imitando el parámetro de desplazamiento iMA de MetaTrader. Esto asegura que el port de StockSharp dispara trades en la misma barra que el experto MQL original.
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 StarterTripleStochasticStrategy : 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 StarterTripleStochasticStrategy()
{
_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 starter_triple_stochastic_strategy(Strategy):
def __init__(self):
super(starter_triple_stochastic_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(starter_triple_stochastic_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(starter_triple_stochastic_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 starter_triple_stochastic_strategy()