Esta estrategia es un puerto StockSharp del robot MetaTrader TimerEA. Se centra en abrir y cerrar operaciones en fechas y horas programadas.
con órdenes pendientes opcionales, protección de seguimiento y manejo de equilibrio.
Lógica de trading
Horario
OpenTime activa la colocación de pedidos una vez que la primera vela terminada alcanza el minuto configurado.
CloseTime fuerza la liquidación de posiciones y, opcionalmente, cancela las órdenes pendientes restantes.
Modos de pedido
Se pueden seleccionar entradas de mercado, stop o límite. Las órdenes pendientes se colocan a una distancia configurable (en pasos de precio) y pueden
caducan después del número de minutos especificado.
Control de dirección
Los interruptores separados permiten habilitar operaciones largas y/o cortas. Cada lado envía una orden por ejecución.
Gestión de riesgos
El volumen fijo o el tamaño basado en el equilibrio (usando RiskFactor) imita la selección de lote original.
Las distancias de stop-loss y take-profit se expresan en incrementos de precio y se recrean después de cada entrada.
La lógica de trailing stop mantiene el stop en un desplazamiento constante una vez que las ganancias exceden el buffer BreakEvenSteps. El sendero se activa
sólo cuando la parada ya está más allá del desplazamiento inicial más el TrailingStep.
Protecciones
El requisito de equilibrio opcional evita el retraso hasta que se alcanza el umbral mínimo de beneficio.
Las órdenes pendientes que sobreviven a su vencimiento se cancelan automáticamente.
Parámetros predeterminados
Modo de pedido: Mercado.
Abierto compra/venta: deshabilitado.
Take Profit / Stop Loss: 10 pasos cada uno.
Trailing stop y punto de equilibrio: desactivados.
Distancia pendiente: 10 pasos con 60 minutos de vencimiento.
Tamaño del lote: Volumen manual = 1,0 (factor de riesgo = 1,0 para el modo de equilibrio).
Tipo de vela: intervalo de tiempo de 1 minuto.
Notas
La estrategia opera con velas terminadas y, por lo tanto, reacciona con hasta una barra de latencia.
StockSharp utiliza un modelo de posición neta, por lo que no se admite la exposición larga y corta simultánea incluso si ambas alternancias están activadas.
habilitado.
Los incrementos de precios se calculan con Security.PriceStep. Los instrumentos sin un paso configurado tratarán las distancias como precio bruto
puntos.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Timer EA strategy: SMA crossover with time-of-day filter.
/// Trades only during active session hours.
/// </summary>
public class TimerEaStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public TimerEaStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast SMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow SMA period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new SimpleMovingAverage { Length = FastPeriod };
var slow = new SimpleMovingAverage { Length = SlowPeriod };
decimal? prevFast = null;
decimal? prevSlow = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, (candle, fastVal, slowVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (prevFast.HasValue && prevSlow.HasValue)
{
if (prevFast.Value <= prevSlow.Value && fastVal > slowVal && Position <= 0)
BuyMarket();
else if (prevFast.Value >= prevSlow.Value && fastVal < slowVal && Position >= 0)
SellMarket();
}
prevFast = fastVal;
prevSlow = slowVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class timer_ea_strategy(Strategy):
def __init__(self):
super(timer_ea_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._fast_period = self.Param("FastPeriod", 10) \
.SetGreaterThanZero() \
.SetDisplay("Fast Period", "Fast SMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 30) \
.SetGreaterThanZero() \
.SetDisplay("Slow Period", "Slow SMA period", "Indicators")
self._prev_fast = None
self._prev_slow = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(timer_ea_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(timer_ea_strategy, self).OnStarted2(time)
self._fast_ind = SimpleMovingAverage()
self._fast_ind.Length = self._fast_period.Value
self._slow_ind = SimpleMovingAverage()
self._slow_ind.Length = self._slow_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._fast_ind, self._slow_ind, self._process_candle).Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if self._prev_fast is not None and self._prev_slow is not None:
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return timer_ea_strategy()