A Estratégia de Random Hedg é uma portagem de alto nível do StockSharp do expert advisor MetaTrader "Random Hedg". O EA original abre simultaneamente uma ordem de compra a mercado e uma de venda a mercado, gerenciando ambas as posições com uma mistura de stop loss fixo, take profit, ponto de equilíbrio e lógica de trailing. A conversão mantém esse comportamento central enquanto expõe cada configuração como parâmetro de estratégia para que o bot possa ser ajustado ou otimizado diretamente no StockSharp Designer.
Lógica de negociação
Hedge inicial – quando a estratégia não tem posição, envia imediatamente duas ordens a mercado (compra e venda) usando o mesmo volume configurável. Ambas as posições recebem um stop loss e um take profit expressos em pips.
Proteção de ponto de equilíbrio – após o preço mover-se favoravelmente a uma posição pelo número configurado de pips, o nível de stop é deslocado para o ponto de equilíbrio mais um offset opcional (posições compradas) ou menos o offset (posições vendidas). Isso replica o interruptor "mover para sem perda" do EA.
Trailing stop – quando o lucro supera a distância de trailing, o stop acompanha o preço. Para posições compradas, o stop segue o preço mais alto menos a distância de trailing; para vendidas, segue o preço mais baixo mais a distância.
Saídas protetoras – cada posição é fechada quando seu take profit ou stop loss é tocado. Opcionalmente, a estratégia pode liquidar ambas as posições se uma vela fechar abaixo da Banda de Bollinger inferior, recriando o filtro de saída do código original.
Reinício de ciclo – após ambas as posições serem fechadas, a estratégia redefine seus rastreadores internos e aguarda a próxima vela para abrir um novo par coberto.
Parâmetros
HedgeVolume – volume utilizado para abrir ambas as posições de hedge (padrão 0,1 contratos).
StopLossPips – distância do stop loss protetor (padrão 200 pips).
TakeProfitPips – distância do take profit (padrão 200 pips).
TrailingStopPips – passo de trailing aplicado quando uma posição se torna lucrativa (padrão 40 pips).
BreakEvenTriggerPips – lucro necessário antes de mover o stop para o ponto de equilíbrio (padrão 10 pips).
BreakEvenOffsetPips – lucro adicional garantido quando ocorre o deslocamento para o ponto de equilíbrio (padrão 5 pips).
EnableTrailing – ativa ou desativa o gerenciamento do trailing stop.
EnableBreakEven – ativa ou desativa a função de ponto de equilíbrio.
EnableExitStrategy – ativa o filtro de liquidação baseado nas Bandas de Bollinger.
BollingerPeriod – período das Bandas de Bollinger usadas para a saída opcional (padrão 20 velas).
BollingerWidth – multiplicador de largura das Bandas de Bollinger (padrão 2).
CandleType – série de dados de velas usada para executar a lógica (padrão período de 30 minutos).
Notas de implementação
A conversão usa a API de alto nível Strategy com assinaturas de velas e o mecanismo BindEx para calcular as Bandas de Bollinger dinamicamente.
O estado interno rastreia o preço de entrada, volume e níveis protetores dinâmicos para cada posição. Isso permite que a versão C# imite os auxiliares de gestão monetária do EA original sem depender de identificadores de ordem específicos da plataforma.
Os volumes de ordens pendentes são rastreados separadamente para que as execuções possam ser classificadas como entradas ou saídas mesmo quando operações de compra e venda ocorrem consecutivamente.
A estratégia espera uma conta com capacidade de hedge pois mantém exposição comprada e vendida ao mesmo tempo, assim como o expert advisor original.
Funções de trailing baseado em dinheiro e take profit por percentual do código MQL são intencionalmente omitidas. Dependem de dados de saldo específicos do corretor e raramente eram usadas na prática; a versão StockSharp foca no gerenciamento central de ação do preço.
Arquivos
CS/RandomHedgStrategy.cs – implementação principal em C# com comentários inline detalhados em inglês.
README.md – esta documentação (inglês).
README_ru.md – tradução para o russo.
README_zh.md – tradução para o chinês simplificado.
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;
public class RandomHedgStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public RandomHedgStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_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
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class random_hedg_strategy(Strategy):
def __init__(self):
super(random_hedg_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(random_hedg_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(random_hedg_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return random_hedg_strategy()