La estrategia replica el comportamiento del Asesor Experto original MostasHaR15 Pivot MQL5 utilizando la API de alto nivel de StockSharp. Combina cálculos clásicos de pivotes diarios de suelo con filtros de momentum del ADX, diferenciales de EMA y el histograma MACD (OsMA). La estrategia opera en un flujo de velas intradía (1 hora por defecto) y consume la vela diaria completada anterior para reconstruir el mapa de pivotes en cada barra.
Lógica de trading
Cuadrícula de pivote – los máximos, mínimos y cierres diarios anteriores se usan para calcular el pivote principal (P), tres niveles de resistencia (R1–R3), tres niveles de soporte (S1–S3) y seis puntos medios (M0–M5). El cierre de la vela actual se compara con esta escalera para identificar el segmento de soporte y resistencia circundante. Un caso especial heredado del EA mapea los precios entre M5 y R3 de vuelta al rango S3/M0.
Filtro de distancia – las operaciones solo se permiten cuando la distancia al nivel de take-profit más cercano es mayor que MinimumDistancePips (14 pips por defecto), que coincide con los filtros originales dif1/dif2.
Las entradas largas requieren todo lo siguiente:
La línea principal ADX supera AdxThreshold (20) y +DI está tanto subiendo como por encima de –DI.
La EMA de 5 períodos en los cierres de velas está al menos EmaSlopePips (5 pips) por encima de la EMA de 8 períodos en las aperturas de velas, y la barra anterior mostró el mismo ordenamiento alcista de EMA.
El histograma MACD (OsMA) aumentó en comparación con la barra anterior.
Las entradas cortas replican las condiciones largas con fuerza de –DI, spread EMA bajista y un histograma MACD cayendo.
Solo se permite una posición neta. Las órdenes se colocan con ejecución de mercado mediante BuyMarket()/SellMarket().
Gestión de posición
Stop-loss – opcional, ubicado StopLossPips por debajo/encima del precio de entrada. Establecer el parámetro en 0 deshabilita el stop inicial, como en el EA.
Take-profit – fijo en el límite de pivote más cercano que rodea el precio actual cuando se abre la posición.
Stop trailing – replica la lógica trailing original. Una vez que el precio avanza más de TrailingStopPips + TrailingStepPips desde la entrada, el stop se mueve para mantener una distancia trailing de TrailingStopPips. El trailing puede deshabilitarse estableciendo TrailingStopPips en 0.
Si el stop-loss, trailing stop o take-profit se alcanza durante una vela, la posición se liquida al cierre de esa vela.
Parámetros de estrategia
Parámetro
Descripción
Por defecto
CandleType
Serie de velas intradía usada para trading.
Marco temporal de 1 hora
DailyCandleType
Serie de velas diarias para cálculos de pivote.
Marco temporal de 1 día
StopLossPips
Distancia del stop-loss en pips. Establecer 0 para deshabilitar.
20
TrailingStopPips
Distancia del stop trailing en pips.
5
TrailingStepPips
Movimiento mínimo favorable antes de que el trailing se actualice. Debe ser >0 si el trailing está habilitado.
5
MinimumDistancePips
Distancia mínima en pips al límite de pivote más cercano antes de entrar a una operación.
14
EmaSlopePips
Separación requerida entre la EMA de cierre y la EMA de apertura.
5
AdxThreshold
Lectura mínima de ADX para operaciones largas y cortas.
20
AdxPeriod
Longitud del indicador ADX.
14
EmaClosePeriod
Período EMA aplicado a los cierres de velas.
5
EmaOpenPeriod
Período EMA aplicado a las aperturas de velas.
8
MacdFastPeriod
Período EMA rápida dentro del histograma MACD.
12
MacdSlowPeriod
Período EMA lenta dentro del histograma MACD.
26
MacdSignalPeriod
Período EMA de señal dentro del histograma MACD.
9
Notas de conversión
La estrategia mantiene el comportamiento inusual del EA donde el rango de precios entre el nivel medio M5 y la resistencia R3 se mapea de vuelta al par de soporte/resistencia S3/M0.
Todos los valores de indicadores se procesan solo en velas completadas. No se almacenan colecciones históricas; todo el estado se mantiene en campos escalares según las pautas del repositorio.
Los comentarios en la estrategia permanecen en inglés según las instrucciones del repositorio.
Consejos de uso
Ajuste CandleType y DailyCandleType al aplicar la estrategia a mercados con diferentes sesiones de trading.
Debido a que la lógica de stop-loss y trailing se evalúa en velas cerradas, puede aparecer slippage adicional en mercados rápidos en comparación con la ejecución a nivel de tick en el EA 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;
/// <summary>
/// MostasHar15 Pivot strategy (simplified).
/// Uses daily pivot levels with RSI filter for entries.
/// </summary>
public class MostasHar15PivotStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<DataType> _dailyCandleType;
private readonly StrategyParam<int> _rsiLength;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public DataType DailyCandleType
{
get => _dailyCandleType.Value;
set => _dailyCandleType.Value = value;
}
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
public MostasHar15PivotStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Trading candles", "General");
_dailyCandleType = Param(nameof(DailyCandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Daily Candle Type", "Higher timeframe for pivots", "General");
_rsiLength = Param(nameof(RsiLength), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "RSI period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiLength };
decimal pivotHigh = 0;
decimal pivotLow = 0;
decimal pivotMid = 0;
bool hasPivot = false;
// Subscribe to higher timeframe for pivot levels
var dailySub = SubscribeCandles(DailyCandleType);
dailySub
.Bind((ICandleMessage candle) =>
{
if (candle.State != CandleStates.Finished)
return;
pivotMid = (candle.HighPrice + candle.LowPrice + candle.ClosePrice) / 3m;
pivotHigh = 2m * pivotMid - candle.LowPrice;
pivotLow = 2m * pivotMid - candle.HighPrice;
hasPivot = true;
})
.Start();
// Subscribe to trading timeframe with RSI
var tradeSub = SubscribeCandles(CandleType);
tradeSub
.Bind(rsi, (ICandleMessage candle, decimal rsiVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (!hasPivot)
return;
var close = candle.ClosePrice;
// Long: price above pivot, RSI momentum confirms
if (close > pivotMid && rsiVal > 55 && Position <= 0)
BuyMarket();
// Short: price below pivot, RSI confirms weakness
else if (close < pivotMid && rsiVal < 45 && Position >= 0)
SellMarket();
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, tradeSub);
DrawIndicator(area, rsi);
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 RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class mostas_har15_pivot_strategy(Strategy):
def __init__(self):
super(mostas_har15_pivot_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Trading candles", "General")
self._daily_candle_type = self.Param("DailyCandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Daily Candle Type", "Higher timeframe for pivots", "General")
self._rsi_length = self.Param("RsiLength", 14) \
.SetDisplay("RSI Length", "RSI period", "Indicators")
self._pivot_mid = 0.0
self._has_pivot = False
@property
def CandleType(self):
return self._candle_type.Value
@property
def DailyCandleType(self):
return self._daily_candle_type.Value
@property
def RsiLength(self):
return self._rsi_length.Value
def OnReseted(self):
super(mostas_har15_pivot_strategy, self).OnReseted()
self._pivot_mid = 0.0
self._has_pivot = False
def OnStarted2(self, time):
super(mostas_har15_pivot_strategy, self).OnStarted2(time)
self._pivot_mid = 0.0
self._has_pivot = False
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiLength
daily_sub = self.SubscribeCandles(self.DailyCandleType)
daily_sub.Bind(self._on_daily_candle).Start()
trade_sub = self.SubscribeCandles(self.CandleType)
trade_sub.Bind(rsi, self._on_trade_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, trade_sub)
self.DrawOwnTrades(area)
def _on_daily_candle(self, candle):
if candle.State != CandleStates.Finished:
return
high = float(candle.HighPrice)
low = float(candle.LowPrice)
close = float(candle.ClosePrice)
self._pivot_mid = (high + low + close) / 3.0
self._has_pivot = True
def _on_trade_candle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
if not self._has_pivot:
return
close = float(candle.ClosePrice)
rv = float(rsi_value)
if close > self._pivot_mid and rv > 55 and self.Position <= 0:
self.BuyMarket()
elif close < self._pivot_mid and rv < 45 and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return mostas_har15_pivot_strategy()