La Estrategia de Temporizador de Stop Global es una capa de gestión de riesgo convertida del experto de MetaTrader Exp_GStop_Tm.
Vigila continuamente el valor del portafolio en cada vela terminada y detiene el trading una vez que se alcanza un objetivo de ganancia global
o un límite de pérdida. Además, puede restringir el trading a una ventana de tiempo definida por el usuario y forzar el cierre de todas las posiciones abiertas
siempre que la ventana esté cerrada.
Cómo funciona
Cuando la estrategia inicia, registra el saldo inicial del portafolio como punto de referencia.
Cada vez que la serie de velas suscrita se cierra, la estrategia lee el valor actual del portafolio y calcula la
diferencia respecto al saldo inicial.
Dependiendo del StopCalculationMode seleccionado, la diferencia se convierte a porcentaje o se deja como moneda.
Si la pérdida supera StopLoss o la ganancia supera TakeProfit, la estrategia entra en estado detenido, registra el
evento y envía órdenes de mercado para cerrar cualquier posición restante.
Cuando la ventana de trading opcional está habilitada y el tiempo actual sale de la ventana, la estrategia también intenta
aplanar la posición. Una vez que el tamaño de la posición se convierte en cero, el indicador de stop se reinicia, permitiendo que el trading se reanude dentro
de la siguiente ventana válida.
La estrategia nunca abre nuevas posiciones por sí sola. Está diseñada para supervisar otras estrategias o trades manuales y para
proteger la cuenta de una caída excesiva o para asegurar las ganancias de toda la cuenta.
Lógica de la ventana de trading
La ventana de trading replica la lógica original del experto:
Si la hora de inicio es menor que la hora de fin, el trading se permite entre el minuto de inicio (inclusive) y el minuto de fin (exclusivo) en el mismo día.
Si la hora de inicio y fin son iguales, el trading se permite solo cuando el minuto actual está entre StartMinute
(inclusive) y EndMinute (exclusivo).
Si la hora de inicio es mayor que la hora de fin, la sesión se extiende pasada la medianoche. El trading se habilita desde el inicio
hasta la medianoche y se reanuda desde la medianoche hasta el fin al día siguiente.
Parámetros
StopCalculationMode – elegir entre stops globales basados en porcentaje o en moneda.
StopLoss – umbral de pérdida global. Tratado como porcentaje cuando el modo porcentual está activo, de lo contrario como moneda de la cuenta.
TakeProfit – objetivo de ganancia global. Usa la misma unidad que StopLoss.
UseTradingWindow – habilitar o deshabilitar el filtro de sesión.
StartHour / StartMinute – hora de inicio de la ventana de trading permitida.
EndHour / EndMinute – hora de cierre de la ventana de trading permitida.
CandleType – serie de velas que define con qué frecuencia se evalúa el estado de la cuenta.
Notas
Dado que las verificaciones de stop ocurren al cierre de la vela, usar un marco temporal pequeño (por ejemplo, un minuto) cuando se requiere reacción rápida.
La estrategia cierra solo la posición gestionada por esta instancia de estrategia. Ejecutar instancias separadas si múltiples
valores necesitan supervisión individual.
Usar junto a otras estrategias de trading adjuntándola como estrategia padre o ejecutándola en el mismo instrumento para
proporcionar protección a nivel de cuenta.
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;
/// <summary>
/// Global Stop Timer strategy (simplified). Trades momentum with
/// time-based position management using EMA trend filter.
/// </summary>
public class GlobalStopTimerStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _momentumLength;
private readonly StrategyParam<int> _emaLength;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int MomentumLength
{
get => _momentumLength.Value;
set => _momentumLength.Value = value;
}
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
public GlobalStopTimerStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candles", "General");
_momentumLength = Param(nameof(MomentumLength), 10)
.SetGreaterThanZero()
.SetDisplay("Momentum Length", "Momentum period", "Indicators");
_emaLength = Param(nameof(EmaLength), 20)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "EMA period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var momentum = new Momentum { Length = MomentumLength };
var ema = new ExponentialMovingAverage { Length = EmaLength };
decimal prevMomentum = 100m;
var hasPrev = false;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(momentum, ema, (ICandleMessage candle, decimal momVal, decimal emaVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!hasPrev)
{
prevMomentum = momVal;
hasPrev = true;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
prevMomentum = momVal;
return;
}
var close = candle.ClosePrice;
var bullishCross = prevMomentum <= 100m && momVal > 100m;
var bearishCross = prevMomentum >= 100m && momVal < 100m;
if (bullishCross && close > emaVal && Position <= 0)
BuyMarket();
else if (bearishCross && close < emaVal && Position >= 0)
SellMarket();
prevMomentum = momVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
}
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 Momentum, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class global_stop_timer_strategy(Strategy):
def __init__(self):
super(global_stop_timer_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candles", "General")
self._momentum_length = self.Param("MomentumLength", 10) \
.SetDisplay("Momentum Length", "Momentum period", "Indicators")
self._ema_length = self.Param("EmaLength", 20) \
.SetDisplay("EMA Length", "EMA period", "Indicators")
self._prev_momentum = 100.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@property
def MomentumLength(self):
return self._momentum_length.Value
@property
def EmaLength(self):
return self._ema_length.Value
def OnReseted(self):
super(global_stop_timer_strategy, self).OnReseted()
self._prev_momentum = 100.0
self._has_prev = False
def OnStarted2(self, time):
super(global_stop_timer_strategy, self).OnStarted2(time)
self._prev_momentum = 100.0
self._has_prev = False
momentum = Momentum()
momentum.Length = self.MomentumLength
ema = ExponentialMovingAverage()
ema.Length = self.EmaLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(momentum, ema, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, mom_value, ema_value):
if candle.State != CandleStates.Finished:
return
mv = float(mom_value)
if not self._has_prev:
self._prev_momentum = mv
self._has_prev = True
return
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_momentum = mv
return
close = float(candle.ClosePrice)
ev = float(ema_value)
bullish_cross = self._prev_momentum <= 100 and mv > 100
bearish_cross = self._prev_momentum >= 100 and mv < 100
if bullish_cross and close > ev and self.Position <= 0:
self.BuyMarket()
elif bearish_cross and close < ev and self.Position >= 0:
self.SellMarket()
self._prev_momentum = mv
def CreateClone(self):
return global_stop_timer_strategy()