Estrategia de rompimiento convertida del script MetaTrader binario_31. El algoritmo construye dos medias móviles exponenciales de 144 períodos calculadas sobre los precios máximos y mínimos de las velas, creando un canal dinámico. Mientras el precio permanece dentro del canal, la estrategia prepara órdenes de stop de entrada:
una compra stop colocada por encima de la EMA-alta más un desplazamiento configurable;
una venta stop colocada por debajo de la EMA-baja menos el mismo desplazamiento.
Cuando el precio rompe uno de estos niveles, se abre una posición en la dirección del rompimiento. Se coloca un stop de protección en el lado opuesto del canal y se calcula un objetivo de take profit relativo a la entrada. Se puede activar un trailing stop opcional para proteger las ganancias.
Parámetros
EMA Length – período para ambas EMA de máximos y mínimos.
Pip Difference – distancia desde el nivel de la EMA hasta la entrada de rompimiento en pasos de precio.
Take Profit – distancia desde la entrada hasta el take profit en pasos de precio.
Trailing Stop – distancia del trailing stop en pasos de precio. Establecer en cero para desactivar.
Volume – volumen de la orden.
Candle Type – tipo de velas a las que se suscribe la estrategia.
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>
/// EMA channel breakout strategy.
/// Buys when price breaks above EMA + offset, sells when below EMA - offset.
/// Uses trailing stop and take profit for exits.
/// </summary>
public class Binario31Strategy : Strategy
{
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<decimal> _channelOffset;
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<DataType> _candleType;
private decimal _entryPrice;
public int EmaLength { get => _emaLength.Value; set => _emaLength.Value = value; }
public decimal ChannelOffset { get => _channelOffset.Value; set => _channelOffset.Value = value; }
public decimal TakeProfit { get => _takeProfit.Value; set => _takeProfit.Value = value; }
public decimal StopLossVal { get => _stopLoss.Value; set => _stopLoss.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Binario31Strategy()
{
_emaLength = Param(nameof(EmaLength), 20)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "EMA period", "Indicator");
_channelOffset = Param(nameof(ChannelOffset), 50m)
.SetDisplay("Channel Offset", "Distance from EMA for channel", "Indicator");
_takeProfit = Param(nameof(TakeProfit), 2000m)
.SetDisplay("Take Profit", "Take profit distance", "Risk");
_stopLoss = Param(nameof(StopLossVal), 1500m)
.SetDisplay("Stop Loss", "Stop loss distance", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_entryPrice = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ema = new ExponentialMovingAverage { Length = EmaLength };
SubscribeCandles(CandleType)
.Bind(ema, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal emaValue)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
var upperBand = emaValue + ChannelOffset;
var lowerBand = emaValue - ChannelOffset;
// Exit management
if (Position > 0)
{
var profit = close - _entryPrice;
if ((TakeProfit > 0 && profit >= TakeProfit) || (StopLossVal > 0 && -profit >= StopLossVal))
{
SellMarket();
return;
}
}
else if (Position < 0)
{
var profit = _entryPrice - close;
if ((TakeProfit > 0 && profit >= TakeProfit) || (StopLossVal > 0 && -profit >= StopLossVal))
{
BuyMarket();
return;
}
}
// Entry: channel breakout
if (Position == 0)
{
if (close > upperBand)
{
BuyMarket();
_entryPrice = close;
}
else if (close < lowerBand)
{
SellMarket();
_entryPrice = close;
}
}
}
}
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
class binario31_strategy(Strategy):
def __init__(self):
super(binario31_strategy, self).__init__()
self._ema_length = self.Param("EmaLength", 20) \
.SetDisplay("EMA Length", "EMA period", "Indicator")
self._channel_offset = self.Param("ChannelOffset", 50.0) \
.SetDisplay("Channel Offset", "Distance from EMA for channel", "Indicator")
self._take_profit = self.Param("TakeProfit", 2000.0) \
.SetDisplay("Take Profit", "Take profit distance", "Risk")
self._stop_loss = self.Param("StopLossVal", 1500.0) \
.SetDisplay("Stop Loss", "Stop loss distance", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle type", "General")
self._entry_price = 0.0
@property
def EmaLength(self):
return self._ema_length.Value
@EmaLength.setter
def EmaLength(self, value):
self._ema_length.Value = value
@property
def ChannelOffset(self):
return self._channel_offset.Value
@ChannelOffset.setter
def ChannelOffset(self, value):
self._channel_offset.Value = value
@property
def TakeProfit(self):
return self._take_profit.Value
@TakeProfit.setter
def TakeProfit(self, value):
self._take_profit.Value = value
@property
def StopLossVal(self):
return self._stop_loss.Value
@StopLossVal.setter
def StopLossVal(self, value):
self._stop_loss.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(binario31_strategy, self).OnStarted2(time)
ema = ExponentialMovingAverage()
ema.Length = self.EmaLength
self.SubscribeCandles(self.CandleType) \
.Bind(ema, self.ProcessCandle) \
.Start()
def ProcessCandle(self, candle, ema_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
ema_val = float(ema_value)
offset = float(self.ChannelOffset)
tp = float(self.TakeProfit)
sl = float(self.StopLossVal)
upper_band = ema_val + offset
lower_band = ema_val - offset
if self.Position > 0:
profit = close - self._entry_price
if (tp > 0 and profit >= tp) or (sl > 0 and -profit >= sl):
self.SellMarket()
return
elif self.Position < 0:
profit = self._entry_price - close
if (tp > 0 and profit >= tp) or (sl > 0 and -profit >= sl):
self.BuyMarket()
return
if self.Position == 0:
if close > upper_band:
self.BuyMarket()
self._entry_price = close
elif close < lower_band:
self.SellMarket()
self._entry_price = close
def OnReseted(self):
super(binario31_strategy, self).OnReseted()
self._entry_price = 0.0
def CreateClone(self):
return binario31_strategy()