Cobertura EES (avanzada)
Descripción general
La estrategia refleja el comportamiento del clásico asesor experto MetaTrader "EES Hedger". Cada vez que un operador externo, un operador discrecional u otro sistema automatizado abre una posición en la misma cuenta, la estrategia crea inmediatamente una cobertura opuesta utilizando un volumen configurable. Luego gestiona la cobertura con reglas de límite de pérdidas, toma de ganancias, punto de equilibrio y límite dinámico para neutralizar la exposición mientras se protegen las ganancias de la cobertura.
A diferencia de las estrategias tradicionales basadas en señales, este módulo supone que las entradas se producen en otro lugar. Su única responsabilidad es observar las operaciones de la cuenta, reaccionar a los tickets coincidentes y proteger la posición de cobertura hasta que se cierre mediante órdenes de protección o manualmente.
Lógica comercial
- Detección de transacciones externas: se monitorea el flujo del conector de las transacciones de la cuenta. Las operaciones cuyo comentario coincida con
OriginalOrderComment (o todas las operaciones cuando el campo esté vacío) se tratan como la fuente que debe cubrirse. Las operaciones producidas por la propia estrategia se filtran almacenando sus identificadores de transacción.
- Órdenes reflejadas: una vez que se recibe una operación calificada, la estrategia envía una orden de mercado inmediata en la dirección opuesta con un volumen
HedgeVolume. Un HedgerOrderComment opcional ayuda a las herramientas administrativas a separar las órdenes de cobertura de otras actividades.
- Gestión de riesgos: una vez completada la cobertura, la estrategia coloca órdenes de limitación de pérdidas y toma de ganancias a distancias definidas por los parámetros de pip. Cuando se cumplen las condiciones de equilibrio, el stop se mueve al precio de entrada más un pip. Si el seguimiento está habilitado, el stop avanza aún más a medida que el mercado continúa moviéndose a favor de la cobertura.
- Limpieza del estado: cuando la posición llega a cero (por ejemplo, después de un cierre manual), todas las órdenes de protección se cancelan y los indicadores internos se restablecen para que la siguiente operación externa pueda cubrirse desde cero.
Parámetros
| Parámetro |
Descripción |
HedgeVolume |
Volumen utilizado para abrir la posición de cobertura opuesta. |
StopLossPips |
Distancia desde el precio de entrada hasta la orden protectora de stop-loss. |
TakeProfitPips |
Distancia desde el precio de entrada hasta la orden de toma de beneficios. |
TrailingStopPips |
Distancia mantenida por el trailing stop una vez superado el umbral de activación. Establezca en cero para desactivar el seguimiento. |
TrailingActivationPips |
Beneficio mínimo (en pips) requerido antes de que el trailing stop comience a moverse. |
BreakEvenPips |
Umbral de beneficio (en pips) tras el cual el stop-loss se mueve al precio de entrada más un pip. |
OriginalOrderComment |
Filtro de comentarios opcional que selecciona qué operaciones externas deben cubrirse. Déjelo vacío para cubrir todas las operaciones con el instrumento. |
HedgerOrderComment |
Comentario adjunto a las órdenes de cobertura y stop de protección generados por la estrategia. |
Notas practicas
- Asigne la misma cartera/cuenta a la estrategia que el operador externo. Todas las posiciones creadas en esa cuenta serán visibles para el conector y, por lo tanto, podrán cubrirse.
- Cuando se utiliza con puentes MetaTrader, configure el asesor experto o el puente para copiar el comentario del pedido original para que el filtrado funcione como se esperaba.
- El tamaño del pip se deriva del paso del precio del instrumento. Para símbolos FX de cinco dígitos, la distancia traduce automáticamente los valores de pip especificados en compensaciones de precios correctas.
- La lógica de equilibrio y de seguimiento nunca aleja el stop más del precio de entrada. Solo se aplican mejoras, garantizando que una vez que se alcanza el punto de equilibrio, el stop nunca vuelva a un nivel de pérdidas.
- La estrategia no gestiona la posición original. Cerrarlo o modificarlo sigue siendo responsabilidad del sistema de comercio primario.
Flujo de trabajo de uso
- Configura los parámetros de la estrategia, prestando especial atención a los filtros de comentarios y al volumen de la cobertura.
- Inicie la estrategia y confirme que esté conectada al feed del corredor. Permanecerá inactivo hasta que llegue un comercio exterior.
- Tan pronto como aparezca una operación calificada, observe cómo se crea la orden de cobertura y cómo se colocan las órdenes de protección en el DOM.
- Supervise el comportamiento de equilibrio y seguimiento para garantizar que las distancias de pips configuradas coincidan con las especificaciones del contrato del corredor.
- Detenga la estrategia cuando ya no sea necesaria la cobertura. Todas las órdenes de protección de trabajo se cancelan durante el cierre.
Limitaciones
- El módulo asume acceso al flujo comercial de la cuenta. No puede cubrir operaciones que sean completamente invisibles para el conector.
- Las reglas de redondeo de volumen son específicas de cada corredor. Asegúrese de que el
HedgeVolume configurado sea compatible con el paso de lote del instrumento.
- Debido a que la estrategia coloca órdenes de mercado inmediatamente, el deslizamiento en los mercados rápidos puede resultar en coberturas imperfectas. Aumente las distancias de stop-loss para tener en cuenta esto cuando sea necesario.
using System;
using System.Linq;
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>
/// Adapted from the MetaTrader "EES Hedger" expert advisor.
/// Uses EMA crossover signals with break-even and trailing stop risk management.
/// </summary>
public class EesHedgerAdvancedStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPips;
private readonly StrategyParam<int> _takeProfitPips;
private readonly StrategyParam<DataType> _candleType;
/// <summary>
/// Fast EMA period.
/// </summary>
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
/// <summary>
/// Slow EMA period.
/// </summary>
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
/// <summary>
/// Stop-loss distance in price steps.
/// </summary>
public int StopLossPips
{
get => _stopLossPips.Value;
set => _stopLossPips.Value = value;
}
/// <summary>
/// Take-profit distance in price steps.
/// </summary>
public int TakeProfitPips
{
get => _takeProfitPips.Value;
set => _takeProfitPips.Value = value;
}
/// <summary>
/// Candle type used by the strategy.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes default parameters.
/// </summary>
public EesHedgerAdvancedStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
_stopLossPips = Param(nameof(StopLossPips), 500)
.SetDisplay("Stop Loss", "Stop-loss distance", "Risk Management");
_takeProfitPips = Param(nameof(TakeProfitPips), 500)
.SetDisplay("Take Profit", "Take-profit distance", "Risk Management");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candles used for calculations", "Market Data");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return new[] { (Security, CandleType) };
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
var fastEma = new EMA { Length = FastPeriod };
var slowEma = new EMA { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastEma, slowEma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastEma);
DrawIndicator(area, slowEma);
DrawOwnTrades(area);
}
// Use StartProtection for SL/TP
var tp = TakeProfitPips > 0 ? new Unit(TakeProfitPips, UnitTypes.Absolute) : null;
var sl = StopLossPips > 0 ? new Unit(StopLossPips, UnitTypes.Absolute) : null;
StartProtection(tp, sl);
base.OnStarted2(time);
}
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevFast = fastValue;
_prevSlow = slowValue;
_hasPrev = true;
return;
}
if (!_hasPrev)
{
_prevFast = fastValue;
_prevSlow = slowValue;
_hasPrev = true;
return;
}
// EMA crossover detection
var crossedUp = _prevFast <= _prevSlow && fastValue > slowValue;
var crossedDown = _prevFast >= _prevSlow && fastValue < slowValue;
if (crossedUp)
{
// Close short if any, then go long
if (Position < 0)
BuyMarket(Math.Abs(Position));
if (Position <= 0)
BuyMarket(Volume);
}
else if (crossedDown)
{
// Close long if any, then go short
if (Position > 0)
SellMarket(Position);
if (Position >= 0)
SellMarket(Volume);
}
_prevFast = fastValue;
_prevSlow = slowValue;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates, UnitTypes, Unit
from StockSharp.Algo.Strategies import Strategy
from StockSharp.Algo.Indicators import ExponentialMovingAverage
class ees_hedger_advanced_strategy(Strategy):
def __init__(self):
super(ees_hedger_advanced_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 10) \
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 30) \
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._stop_loss_pips = self.Param("StopLossPips", 500) \
.SetDisplay("Stop Loss", "Stop-loss distance", "Risk Management")
self._take_profit_pips = self.Param("TakeProfitPips", 500) \
.SetDisplay("Take Profit", "Take-profit distance", "Risk Management")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candles used for calculations", "Market Data")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
@property
def StopLossPips(self):
return self._stop_loss_pips.Value
@property
def TakeProfitPips(self):
return self._take_profit_pips.Value
@property
def CandleType(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(ees_hedger_advanced_strategy, self).OnStarted2(time)
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self.FastPeriod
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast_ema, slow_ema, self.ProcessCandle).Start()
tp = Unit(self.TakeProfitPips, UnitTypes.Absolute) if self.TakeProfitPips > 0 else None
sl = Unit(self.StopLossPips, UnitTypes.Absolute) if self.StopLossPips > 0 else None
self.StartProtection(tp, sl)
def ProcessCandle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_value = float(fast_value)
slow_value = float(slow_value)
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_fast = fast_value
self._prev_slow = slow_value
self._has_prev = True
return
if not self._has_prev:
self._prev_fast = fast_value
self._prev_slow = slow_value
self._has_prev = True
return
crossed_up = self._prev_fast <= self._prev_slow and fast_value > slow_value
crossed_down = self._prev_fast >= self._prev_slow and fast_value < slow_value
if crossed_up:
if self.Position < 0:
self.BuyMarket(abs(self.Position))
if self.Position <= 0:
self.BuyMarket(self.Volume)
elif crossed_down:
if self.Position > 0:
self.SellMarket(self.Position)
if self.Position >= 0:
self.SellMarket(self.Volume)
self._prev_fast = fast_value
self._prev_slow = slow_value
def OnReseted(self):
super(ees_hedger_advanced_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
def CreateClone(self):
return ees_hedger_advanced_strategy()