Estrategia de Canal de Rango XMA
Estrategia que construye un canal superior e inferior a partir de medias móviles de los precios máximos y mínimos. Una ruptura por encima de la banda superior activa una entrada larga, mientras que una ruptura por debajo de la banda inferior activa una entrada corta. El modelo replica el comportamiento del experto MQL original "XMA Range Channel".
Detalles
- Criterios de entrada:
- Largo:
Close > UpperChannel - Corto:
Close < LowerChannel
- Largo:
- Largo/Corto: Ambos
- Criterios de salida: Señal opuesta
- Stops: No
- Valores predeterminados:
CandleType= TimeSpan.FromHours(4).TimeFrame()Length= 7
- Filtros:
- Categoría: Ruptura de canal
- Dirección: Ambos
- Indicadores: SMA en High/Low
- Stops: No
- Complejidad: Básico
- Marco temporal: Swing
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy that trades breakouts of a moving average channel built from highs and lows.
/// </summary>
public class XmaRangeChannelStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _length;
private ExponentialMovingAverage _highMa = null!;
private ExponentialMovingAverage _lowMa = null!;
/// <summary>
/// Candle type for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Moving average period for channel construction.
/// </summary>
public int Length
{
get => _length.Value;
set => _length.Value = value;
}
/// <summary>
/// Initializes a new instance of the strategy.
/// </summary>
public XmaRangeChannelStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe used for analysis", "General");
_length = Param(nameof(Length), 7)
.SetGreaterThanZero()
.SetDisplay("Channel Length", "Period for high and low moving averages", "Indicator")
;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_highMa = default;
_lowMa = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_highMa = new ExponentialMovingAverage { Length = Length };
_lowMa = new ExponentialMovingAverage { Length = Length };
Indicators.Add(_highMa);
Indicators.Add(_lowMa);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
StartProtection(null, null);
}
private void ProcessCandle(ICandleMessage candle)
{
// Only finished candles are used.
if (candle.State != CandleStates.Finished)
return;
// Update moving averages with high and low prices.
var upper = _highMa.Process(new DecimalIndicatorValue(_highMa, candle.HighPrice, candle.OpenTime) { IsFinal = true }).ToDecimal();
var lower = _lowMa.Process(new DecimalIndicatorValue(_lowMa, candle.LowPrice, candle.OpenTime) { IsFinal = true }).ToDecimal();
if (!_highMa.IsFormed || !_lowMa.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Breakout above the upper band - go long.
if (candle.ClosePrice > upper && Position <= 0)
{
BuyMarket();
}
// Breakout below the lower band - go short.
else if (candle.ClosePrice < lower && Position >= 0)
{
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class xma_range_channel_strategy(Strategy):
def __init__(self):
super(xma_range_channel_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe used for analysis", "General")
self._length = self.Param("Length", 7) \
.SetDisplay("Channel Length", "Period for high and low moving averages", "Indicator")
self._high_ma = None
self._low_ma = None
@property
def candle_type(self):
return self._candle_type.Value
@property
def length(self):
return self._length.Value
def OnReseted(self):
super(xma_range_channel_strategy, self).OnReseted()
self._high_ma = None
self._low_ma = None
def OnStarted2(self, time):
super(xma_range_channel_strategy, self).OnStarted2(time)
self._high_ma = ExponentialMovingAverage()
self._high_ma.Length = self.length
self._low_ma = ExponentialMovingAverage()
self._low_ma.Length = self.length
self.Indicators.Add(self._high_ma)
self.Indicators.Add(self._low_ma)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.process_candle).Start()
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
upper_result = process_float(self._high_ma, candle.HighPrice, candle.OpenTime, True)
lower_result = process_float(self._low_ma, candle.LowPrice, candle.OpenTime, True)
if not self._high_ma.IsFormed or not self._low_ma.IsFormed:
return
upper = float(upper_result)
lower = float(lower_result)
close = float(candle.ClosePrice)
# Breakout above upper band - go long
if close > upper and self.Position <= 0:
self.BuyMarket()
# Breakout below lower band - go short
elif close < lower and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return xma_range_channel_strategy()