Flat Trend EA Strategy es un puerto de StockSharp del asesor experto MQL5 "Flat Trend EA". El algoritmo combina el indicador Parabolic SAR con el Índice de Dirección Promedio (ADX) para detectar cuatro estados de mercado: tendencia alcista, tendencia bajista, fin de compra y fin de venta. La estrategia reacciona solo a velas completadas del marco temporal configurado y refleja la lógica original de cerrar posiciones opuestas antes de abrir una nueva.
Lógica de trading
Señal de compra: el punto del Parabolic SAR se imprime por debajo del precio de cierre y la línea +DI del ADX está por encima de la línea -DI. Cualquier exposición corta se cierra inmediatamente, y se abre un nuevo largo cuando no hay posición activa.
Señal de venta: el punto del Parabolic SAR se imprime por encima del precio de cierre y +DI es menor o igual a -DI. Cualquier exposición larga se cierra antes de abrir una operación corta.
Filtros de fin de tendencia: cuando el SAR está por encima del precio mientras +DI es mayor que -DI, la estrategia marca el fin de una tendencia corta; cuando el SAR está por debajo del precio mientras +DI es menor o igual a -DI, marca el fin de una tendencia larga. Ambos eventos fuerzan el cierre de las posiciones existentes sin abrir una nueva operación.
Ventana de trading: filtros de sesión opcionales restringen las entradas al intervalo [StartHour, EndHour). Las señales fuera de la sesión aún pueden cerrar operaciones, pero las nuevas entradas se omiten.
Gestión de riesgos
Las distancias de stop-loss y take-profit se miden en pips (escaladas automáticamente para instrumentos de tres y cinco dígitos). Los precios se normalizan al paso del instrumento.
El trailing stop se activa después de que la posición gana más que TrailingStopPips + TrailingStepPips. Las posiciones largas siguen por debajo del último cierre, los cortos por encima. Cuando el trailing está deshabilitado, el nivel de stop permanece fijo.
Salidas de protección: en cada vela finalizada la estrategia comprueba los precios bajos/altos contra los niveles de stop-loss, take-profit y trailing. Cualquier brecha cierra la posición y restablece el seguimiento de riesgo.
Parámetros
StopLossPips – distancia al stop de protección en pips.
TakeProfitPips – distancia al objetivo en pips.
TrailingStopPips – distancia de trailing stop en pips (establecer en 0 para deshabilitar el trailing).
TrailingStepPips – progreso adicional requerido antes de que el trailing stop se mueva; debe ser positivo cuando el trailing está habilitado.
UseTradingHours – habilita el filtro de ventana de trading.
StartHour / EndHour – hora de inicio inclusiva y hora de fin exclusiva para entradas (hora del exchange).
AdxPeriod – período de suavizado para el ADX, que controla la sensibilidad de +DI y -DI.
SarStart, SarIncrement, SarMaximum – configuraciones de aceleración del Parabolic SAR que coinciden con el indicador original (0.02 / 0.02 / 0.2 por defecto).
CandleType – marco temporal utilizado para las suscripciones de velas y los cálculos del indicador.
Volume – heredado de Strategy, representa el tamaño de la orden utilizado al entrar en nuevas posiciones.
Indicadores
Índice de Dirección Promedio (ADX) proporciona los componentes +DI y -DI utilizados para determinar la dirección actual de la tendencia.
Parabolic SAR define si la estructura del mercado es alcista o bajista y proporciona el nivel del punto para la lógica de trailing.
Notas adicionales
El tamaño del pip se calcula a partir de la configuración del instrumento: para instrumentos con tres y cinco decimales, el paso de precio se multiplica por diez para coincidir con la definición MQL de un pip.
La estrategia siempre cierra las posiciones existentes cuando aparecen señales opuestas o de fin antes de evaluar nuevas entradas, reproduciendo el flujo de trabajo original del EA.
Solo se proporciona la implementación en C#; no se crea ninguna versión ni carpeta de Python, según lo solicitado.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Flat Trend EA strategy. Uses DEMA crossover to distinguish flat from trend.
/// </summary>
public class FlatTrendEaStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal? _prevFast;
private decimal? _prevSlow;
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 FlatTrendEaStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast DEMA", "Fast DEMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Slow DEMA", "Slow DEMA period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = null;
_prevSlow = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = null;
_prevSlow = null;
var fast = new DoubleExponentialMovingAverage { Length = FastPeriod };
var slow = new DoubleExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
if (_prevFast == null || _prevSlow == null)
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
var prevAbove = _prevFast.Value > _prevSlow.Value;
var currAbove = fastVal > slowVal;
_prevFast = fastVal;
_prevSlow = slowVal;
if (!prevAbove && currAbove && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (prevAbove && !currAbove && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
}
}
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 DoubleExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class flat_trend_ea_strategy(Strategy):
def __init__(self):
super(flat_trend_ea_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._fast_period = self.Param("FastPeriod", 10) \
.SetDisplay("Fast DEMA", "Fast DEMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 30) \
.SetDisplay("Slow DEMA", "Slow DEMA period", "Indicators")
self._prev_fast = None
self._prev_slow = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
def OnReseted(self):
super(flat_trend_ea_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(flat_trend_ea_strategy, self).OnStarted2(time)
self._prev_fast = None
self._prev_slow = None
fast = DoubleExponentialMovingAverage()
fast.Length = self.FastPeriod
slow = DoubleExponentialMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, slow, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
if self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fv
self._prev_slow = sv
return
prev_above = self._prev_fast > self._prev_slow
curr_above = fv > sv
self._prev_fast = fv
self._prev_slow = sv
if not prev_above and curr_above and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif prev_above and not curr_above and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return flat_trend_ea_strategy()