Flat 001a es un sistema de especulación diseñado para el gráfico horario del EURUSD. Escanea las velas de tres horas más recientes y mide la distancia entre el máximo más alto y el mínimo más bajo. Cuando el rango de esta ventana de tres velas se mantiene dentro de un número configurable de puntos, la estrategia anticipa que el precio permanecerá atrapado dentro del piso. Luego intenta limitar las incursiones breves en el cuarto superior o inferior del canal y emite inmediatamente órdenes de protección.
El asesor experto original MQL4 negoció solo EURUSD en el primer semestre y rechazó la negociación si el símbolo o el período de tiempo eran incorrectos. Este puerto mantiene los mismos valores predeterminados (EURUSD, velas de 60 minutos) y reproduce todos los cálculos de entrada, stop-loss, take-profit y trailing-stop en StockSharp.
Indicadores y datos
Los indicadores Highest y Lowest (período = 3) rastrean la parte superior e inferior de las últimas tres velas terminadas.
Un parámetro de marco de tiempo tiene como valor predeterminado velas de 60 minutos para reflejar el requisito H1 del código fuente.
No se utilizan osciladores adicionales ni filtros de suavizado, por lo que la estrategia reacciona únicamente a los precios extremos.
Lógica de entrada
Espere a que se cierre la vela de suscripción. Sólo se procesan velas terminadas.
Verifique que el código de seguridad actual coincida con el código configurado (predeterminado: EURUSD). Si no es así, la estrategia queda inactiva.
Evalúe la ventana de negociación opcional. De forma predeterminada, se permiten entradas durante las dos horas que comienzan a la medianoche, hora de la plataforma (horas 0 y 1). El filtro se puede desactivar.
Calcule el rango de tres velas range = highest - lowest y tradúzcalo a puntos mediante el instrumento PriceStep.
Continúe solo si el número de puntos se encuentra entre DiffMinPoints y DiffMaxPoints.
Si el precio de cierre se encuentra dentro del cuarto más bajo del rango y no hay ninguna posición abierta, inicie una operación larga.
Si el precio de cierre se encuentra dentro del cuarto más alto del rango y no hay ninguna posición abierta, ingrese una operación corta.
Gestión de pedidos
Stop-loss inicial
Operaciones largas: lowest - range / 3.
Operaciones cortas: highest + range / 3.
Take-profit
Operaciones largas: precio de entrada + TakeProfitPoints * PriceStep.
Operaciones cortas: precio de entrada - TakeProfitPoints * PriceStep.
Parada de seguimiento
Una vez que el beneficio no realizado supera TrailingStopPoints * PriceStep, el stop-loss se sigue vela por vela.
Las operaciones largas mueven el stop a closePrice - TrailingDistance si es más alto que el stop actual.
Las operaciones cortas mueven el tope a closePrice + TrailingDistance si es inferior al tope actual.
Todas las salidas se ejecutan con órdenes de mercado. La estrategia cierra la posición completa cuando la vela siguiente toca el nivel de stop-loss o take-profit.
Parámetros
grupo
Nombre
Descripción
Predeterminado
generales
CandleType
Tipo de vela utilizada para los cálculos. Debe establecerse en un período de tiempo de 60 minutos para que coincida con el sistema original.
TimeFrame(60m)
generales
SecurityCode
Código de seguridad esperado. Déjelo vacío para operar con cualquier instrumento.
EURUSD
Filtro de rango
DiffMinPoints
Rango mínimo de tres velas en puntos necesarios para operar.
18
Filtro de rango
DiffMaxPoints
Rango máximo de tres velas en puntos permitidos para operar.
28
Ventana de negociación
EnableTimeFilter
Activa o desactiva el filtro horario.
true
Ventana de negociación
OpenHour
Hora de inicio (0–23) de la ventana de negociación. La estrategia también permite la próxima hora inmediata.
0
Gestión de riesgos
TakeProfitPoints
Distancia de toma de ganancias expresada en puntos. Establezca en cero para desactivar.
8
Gestión de riesgos
TrailingStopPoints
Distancia del trailing stop expresada en puntos. Establezca en cero para desactivar el seguimiento.
6
Notas practicas
La propiedad StockSharp Strategy.Volume controla el tamaño del pedido. Ajústelo según el tamaño del contrato de su corredor.
Asegúrese de que el instrumento seleccionado exponga un PriceStep válido. Si falta PriceStep, la estrategia vuelve a 1 y registra una advertencia.
El asesor experto MQL4 ofreció administración de dinero opcional escalando lotes según el saldo de la cuenta. La muestra de StockSharp mantiene constante el tamaño de la posición; puede programar su propia gestión de volumen si es necesario.
Pruebe siempre la estrategia en simulación antes de ejecutarla en vivo. La lógica de seguimiento supone que el corredor ejecutará órdenes de protección cuando los extremos de las velas crucen el nivel; En los mercados rápidos, el deslizamiento puede aumentar el riesgo realizado.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Flat 001a: RSI reversal with EMA filter and ATR stops.
/// </summary>
public class Flat001aStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _atrLength;
private decimal _prevRsi;
private decimal _entryPrice;
public Flat001aStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_rsiLength = Param(nameof(RsiLength), 14)
.SetDisplay("RSI Length", "RSI period.", "Indicators");
_emaLength = Param(nameof(EmaLength), 20)
.SetDisplay("EMA Length", "Trend filter.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period.", "Indicators");
}
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int RsiLength { get => _rsiLength.Value; set => _rsiLength.Value = value; }
public int EmaLength { get => _emaLength.Value; set => _emaLength.Value = value; }
public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevRsi = 0; _entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevRsi = 0; _entryPrice = 0;
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var ema = new ExponentialMovingAverage { Length = EmaLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(rsi, ema, atr, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, ema); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal rsiVal, decimal emaVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished) return;
if (_prevRsi == 0 || atrVal <= 0) { _prevRsi = rsiVal; return; }
var close = candle.ClosePrice;
if (Position > 0)
{
if (close >= _entryPrice + atrVal * 2.5m || close <= _entryPrice - atrVal * 1.5m || rsiVal > 70) { SellMarket(); _entryPrice = 0; }
}
else if (Position < 0)
{
if (close <= _entryPrice - atrVal * 2.5m || close >= _entryPrice + atrVal * 1.5m || rsiVal < 30) { BuyMarket(); _entryPrice = 0; }
}
if (Position == 0)
{
if (rsiVal > 55 && _prevRsi <= 55 && close > emaVal) { _entryPrice = close; BuyMarket(); }
else if (rsiVal < 45 && _prevRsi >= 45 && close < emaVal) { _entryPrice = close; SellMarket(); }
}
_prevRsi = rsiVal;
}
}
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.Strategies import Strategy
from StockSharp.Algo.Indicators import RelativeStrengthIndex, ExponentialMovingAverage, AverageTrueRange
class flat001a_strategy(Strategy):
def __init__(self):
super(flat001a_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe.", "General")
self._rsi_length = self.Param("RsiLength", 14) \
.SetDisplay("RSI Length", "RSI period.", "Indicators")
self._ema_length = self.Param("EmaLength", 20) \
.SetDisplay("EMA Length", "Trend filter.", "Indicators")
self._atr_length = self.Param("AtrLength", 14) \
.SetDisplay("ATR Length", "ATR period.", "Indicators")
self._prev_rsi = 0.0
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@property
def RsiLength(self):
return self._rsi_length.Value
@property
def EmaLength(self):
return self._ema_length.Value
@property
def AtrLength(self):
return self._atr_length.Value
def OnStarted2(self, time):
super(flat001a_strategy, self).OnStarted2(time)
self._prev_rsi = 0.0
self._entry_price = 0.0
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.RsiLength
self._ema = ExponentialMovingAverage()
self._ema.Length = self.EmaLength
self._atr = AverageTrueRange()
self._atr.Length = self.AtrLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._rsi, self._ema, self._atr, self.ProcessCandle).Start()
def ProcessCandle(self, candle, rsi_val, ema_val, atr_val):
if candle.State != CandleStates.Finished:
return
rv = float(rsi_val)
ev = float(ema_val)
av = float(atr_val)
if self._prev_rsi == 0 or av <= 0:
self._prev_rsi = rv
return
close = float(candle.ClosePrice)
if self.Position > 0:
if close >= self._entry_price + av * 2.5 or close <= self._entry_price - av * 1.5 or rv > 70:
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0:
if close <= self._entry_price - av * 2.5 or close >= self._entry_price + av * 1.5 or rv < 30:
self.BuyMarket()
self._entry_price = 0.0
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_rsi = rv
return
if self.Position == 0:
if rv > 55 and self._prev_rsi <= 55 and close > ev:
self._entry_price = close
self.BuyMarket()
elif rv < 45 and self._prev_rsi >= 45 and close < ev:
self._entry_price = close
self.SellMarket()
self._prev_rsi = rv
def OnReseted(self):
super(flat001a_strategy, self).OnReseted()
self._prev_rsi = 0.0
self._entry_price = 0.0
def CreateClone(self):
return flat001a_strategy()