Esta estratégia é uma versão StockSharp do consultor especialista Pedroxxmod MetaTrader 4. O EA original espera que o mercado mova um
alguns pips de distância de um preço de referência e então abre uma posição contrária. Os pedidos subsequentes são calculados na mesma direção
sempre que o preço retrocede por uma distância configurável. A implementação StockSharp mantém o comportamento intacto ao expor
parâmetros fortemente digitados por meio do Strategy API de alto nível.
Lógica de negociação
Assine as melhores cotações de compra/venda da Level1 e armazene em cache os valores mais recentes.
Quando nenhuma negociação estiver aberta, armazene o preço de venda atual como nível de entrada de referência. A negociação só é permitida entre
StartHour e EndHour, e de StartYear em diante.
Se a melhor venda subir Gap MetaTrader pips acima da referência, envie uma ordem de venda a mercado. Se cair Gap pips,
enviar uma ordem de compra de mercado. Os níveis protetores de stop-loss e take-profit são anexados automaticamente chamando
SetStopLoss / SetTakeProfit com as mesmas distâncias de pip que o consultor especialista.
Uma vez estabelecida uma direção de cesta, a estratégia mantém uma lista FIFO das posições sintéticas para emular o hedge.
estilo de MetaTrader. Contanto que o tamanho atual da cesta seja inferior a MaxTrades, a média dos pedidos será adicionada quando a melhor oferta
retorna dentro de ReEntryGap pips do último preço de entrada.
O gerenciamento de dinheiro pode usar o parâmetro fixo Lots ou alocar volume dinamicamente de acordo com a regra EA
floor(Equity / 20000), limitado por MaxLots. Todos os volumes são normalizados em relação à etapa/mín/máx do volume da segurança.
As atualizações fora do horário comercial redefinem as âncoras de entrada internas para evitar negociações falsas quando a próxima sessão começar.
Parâmetros
Nome
Descrição
Lots
Volume de pedidos fixo quando o gerenciamento de dinheiro está desativado.
StopLoss
Distância de parada protetora em MetaTrader pips. Defina como 0 para desativar a parada.
TakeProfit
Distância alvo de lucro em MetaTrader pips. Defina como 0 para desativar o alvo.
Gap
Distância em MetaTrader pips que o pedido deve se afastar da referência antes de abrir a primeira negociação.
MaxTrades
Número máximo de negociações abertas simultaneamente (tamanho da cesta).
ReEntryGap
Distância em MetaTrader pips que aciona a média dos pedidos na direção da cesta.
MoneyManagement
Ativa a regra de volume dinâmico floor(Equity / 20000) quando definida como true.
MaxLots
Limite superior para o volume calculado dinamicamente.
StartHour / EndHour
Janela de negociação no horário do servidor Exchange (inclusive).
StartYear
Ano civil a partir do qual a negociação é permitida. Os dados anteriores são ignorados.
Notas
A estratégia consome apenas dados do Nível 1 e não solicita velas. É, portanto, leve e reage imediatamente a
alterações de cotação, assim como o manipulador de ticks MT4 start().
Paradas e alvos dependem dos métodos auxiliares de Strategy para traduzir distâncias de MetaTrader pip em específicas do corretor
níveis de preços. Certifique-se de que o local conectado exponha os valores PriceStep, StepPrice e VolumeStep corretos.
O contador de cesta sintético permite que a estratégia imite contas de hedge, mesmo que StockSharp agregue a posição.
Preenchimentos parciais e ocorrências de parada são tratados por meio do retorno de chamada OnPositionChanged que mantém as filas FIFO.
A implementação do Python é omitida intencionalmente de acordo com as diretrizes do repositório.
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using StockSharp.Algo;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// Pedro Mod mean reversion strategy using Bollinger Bands.
/// Buy when price touches the lower band, sell when price touches the upper band.
/// </summary>
public class PedroModStrategy : Strategy
{
private readonly StrategyParam<int> _bollingerPeriod;
private readonly StrategyParam<decimal> _bollingerWidth;
private readonly StrategyParam<DataType> _candleType;
public int BollingerPeriod { get => _bollingerPeriod.Value; set => _bollingerPeriod.Value = value; }
public decimal BollingerWidth { get => _bollingerWidth.Value; set => _bollingerWidth.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public PedroModStrategy()
{
_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
.SetDisplay("Bollinger Period", "Bollinger Bands period", "Indicators");
_bollingerWidth = Param(nameof(BollingerWidth), 1.5m)
.SetDisplay("Bollinger Width", "Standard deviation multiplier", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var bb = new BollingerBands { Length = BollingerPeriod, Width = BollingerWidth };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bb, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue bbValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!bbValue.IsFinal)
return;
var bb = (BollingerBandsValue)bbValue;
if (bb.UpBand is not decimal upper || bb.LowBand is not decimal lower || bb.MovingAverage is not decimal middle)
return;
// Buy when price touches lower band (mean reversion)
if (Position <= 0 && candle.ClosePrice <= lower)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Sell when price touches upper band
else if (Position >= 0 && candle.ClosePrice >= upper)
{
if (Position > 0)
SellMarket();
SellMarket();
}
// Exit at middle band
else if (Position > 0 && candle.ClosePrice >= middle)
{
SellMarket();
}
else if (Position < 0 && candle.ClosePrice <= middle)
{
BuyMarket();
}
}
}
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
from StockSharp.Algo.Indicators import BollingerBands
from StockSharp.Algo.Strategies import Strategy
class pedro_mod_strategy(Strategy):
"""Pedro Mod mean reversion strategy using Bollinger Bands.
Buy when price touches the lower band, sell when price touches the upper band.
Exit at the middle band."""
def __init__(self):
super(pedro_mod_strategy, self).__init__()
self._bollinger_period = self.Param("BollingerPeriod", 20) \
.SetDisplay("Bollinger Period", "Bollinger Bands period", "Indicators")
self._bollinger_width = self.Param("BollingerWidth", 1.5) \
.SetDisplay("Bollinger Width", "Standard deviation multiplier", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def BollingerPeriod(self):
return self._bollinger_period.Value
@property
def BollingerWidth(self):
return self._bollinger_width.Value
def OnReseted(self):
super(pedro_mod_strategy, self).OnReseted()
def OnStarted2(self, time):
super(pedro_mod_strategy, self).OnStarted2(time)
bb = BollingerBands()
bb.Length = self.BollingerPeriod
bb.Width = self.BollingerWidth
subscription = self.SubscribeCandles(self.CandleType)
subscription.BindEx(bb, self._process_candle).Start()
def _process_candle(self, candle, bb_value):
if candle.State != CandleStates.Finished:
return
if not bb_value.IsFinal:
return
up_band = bb_value.UpBand if hasattr(bb_value, 'UpBand') else None
low_band = bb_value.LowBand if hasattr(bb_value, 'LowBand') else None
mid_band = bb_value.MovingAverage if hasattr(bb_value, 'MovingAverage') else None
if up_band is None or low_band is None or mid_band is None:
return
upper = float(up_band)
lower = float(low_band)
middle = float(mid_band)
close = float(candle.ClosePrice)
# Buy when price touches lower band (mean reversion)
if self.Position <= 0 and close <= lower:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Sell when price touches upper band
elif self.Position >= 0 and close >= upper:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
# Exit at middle band
elif self.Position > 0 and close >= middle:
self.SellMarket()
elif self.Position < 0 and close <= middle:
self.BuyMarket()
def CreateClone(self):
return pedro_mod_strategy()