A estratégia Back Kick é um sistema de rompimento com hedge convertido do consultor especialista MetaTrader 5 Back kick.mq5. Mantém continuamente uma exposição de dois lados abrindo tanto uma posição comprada quanto uma vendida ao fechar de cada barra. Cada perna é protegida com distâncias simétricas de stop-loss e take-profit expressas em pips. O port StockSharp mantém as posições emparelhadas independentes rastreando seu estado manualmente em vez de depender da posição líquida agregada.
Lógica de trading
Subscrever às velas do período configurado. Quando uma vela fecha e não há pernas com hedge ativas, solicitar um novo par de entradas.
Enviar imediatamente uma ordem de compra e uma de venda de mercado usando o mesmo volume. Cada perna mantém seus próprios deslocamentos de stop-loss e take-profit convertidos de distâncias em pips.
Monitorar os melhores preços de oferta/demanda a partir de dados de Nível 1. Se uma perna atingir seu preço de proteção, ela é fechada com uma ordem de mercado, enquanto a perna oposta permanece ativa até que sua própria saída seja acionada.
Após ambas as pernas estarem flat, a estratégia aguarda a próxima vela concluída antes de recriar o hedge.
Este comportamento espelha o especialista original, que reentra constantemente em ambas as direções para capturar "impulsos" abruptos de preço.
Parâmetros
Nome
Descrição
Padrão
Notas
OrderVolume
Volume usado para cada perna de hedge.
0.1
Normalizado para o VolumeStep do instrumento, deve respeitar MinVolume/MaxVolume.
StopLossPips
Distância do stop-loss em pips.
50
Definir como 0 para desabilitar o stop de proteção para ambas as pernas.
TakeProfitPips
Distância do take-profit em pips.
140
Definir como 0 para desabilitar o take-profit de proteção.
CandleType
Período que aciona novos pares com hedge.
15m
Aceita qualquer TimeFrame suportado pelo ativo selecionado.
LogDiagnostics
Habilita log detalhado sobre entradas e saídas.
false
Útil para depurar sequências de preenchimento.
Notas de implementação
Conversão de pip – O EA original ajusta o tamanho do pip para símbolos de 3/5 dígitos. O port StockSharp replica isso multiplicando o passo de preço por 10 quando necessário.
Modelo de hedge manual – StockSharp usa posições líquidas, por isso a estratégia mantém o estado por perna (PositionState) e despacha ordens de mercado explícitas para saídas. Isso permite que o comportamento se assemelhe ao modo de conta com hedge do MT5.
Gestão de risco – Níveis de stop-loss e take-profit são opcionais. Se qualquer um estiver desabilitado, essa perna só fechará quando o nível de proteção oposto for atingido ou via gerenciamento externo.
Serviço de proteção – StartProtection() ainda é invocado para que o framework monitore desconexões inesperadas, mesmo que lógica de saída personalizada esteja implementada.
Uso
Anexar a estratégia a um ativo com dados confiáveis de Nível 1 (oferta/demanda) e as velas do período desejado.
Configurar as distâncias de pip e o volume de negociação de acordo com seu perfil de risco.
Iniciar a estratégia; ela aguardará o próximo fechamento de vela antes de enviar o par com hedge.
Monitorar os logs ou o gráfico para observar como cada perna sai independentemente.
Diferenças da versão MT5
O gerenciamento de dinheiro baseado em percentual de risco não é transferido; use OrderVolume para controlar o tamanho da negociação.
Como o StockSharp agrega posições de portfólio, a estratégia emula hedging através de contabilidade interna. Isso garante um comportamento próximo ao especialista original, mantendo compatibilidade com corretoras que netam posições.
Verificações de nível de congelamento/stop específicas do corretor são omitidas. Em vez disso, a rotina de normalização de volume lança exceções descritivas se os limites da bolsa forem violados.
Arquivos
CS/BackKickStrategy.cs – Implementação da estratégia usando a API de alto nível do StockSharp.
README.md – Documentação em inglês (este arquivo).
README_ru.md – Documentação em russo.
README_zh.md – Documentação em chinês.
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 BackKickStrategy : 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 BackKickStrategy()
{
_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 back_kick_strategy(Strategy):
def __init__(self):
super(back_kick_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(back_kick_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(back_kick_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 back_kick_strategy()