A Aussie Surfer Ltd Strategy é uma versão StockSharp de alto nível API do MetaTrader 5 consultor especialista "Aussie Surfer Ltd" (MQL pasta 43278). A estratégia combina reversões rápidas de banda Bollinger com um filtro de tendência Alligator para automatizar a configuração discricionária usada no EA original. As negociações são realizadas no instrumento primário configurado para a estratégia e avaliadas em uma série de velas de 15 minutos por padrão.
Indicadores e Dados
Bollinger Bandas (preço de fechamento, comprimento padrão 5, largura 2,5) – detecta quando o mercado se estende temporariamente para fora das bandas e volta para dentro.
Média móvel suavizada (comprimento 21) – reproduz a linha de "dentes" Alligator para avaliar a desaceleração da tendência.
Preço mediano de cada vela ((High + Low) / 2) – alimenta o cálculo Alligator para que a inclinação corresponda à implementação original.
A estratégia assina um único fluxo de velas. Os valores dos indicadores são impulsionados apenas por velas finalizadas, garantindo que os sinais sejam gerados em dados confirmados.
Lógica de negociação
Configuração de entrada
Quando a vela anterior abriu acima da banda Bollinger inferior e a vela atual abriu abaixo do valor da banda observado há duas barras, uma posição longa é aberta (após achatar qualquer exposição curta). Isso recria a lógica EA em que o preço ultrapassa a banda inferior e imediatamente volta para dentro.
Quando a vela anterior abriu abaixo da banda Bollinger superior e a vela atual abriu acima do valor da banda observado há duas barras, uma posição curta é aberta (após achatar qualquer exposição longa).
Saída baseada em Alligator
A linha dos dentes Alligator é monitorada uma e duas barras atrás. Uma posição longa é liquidada sempre que a inclinação diminui (o valor de duas barras atrás é maior que o valor de uma barra atrás). Uma posição curta fecha quando a inclinação sobe.
Camadas de risco
Um stop-loss e um take-profit fixos em pip são aplicados na entrada. Ambos são opcionais e podem ser desativados definindo a distância do pip como zero.
Um trailing stop opcional realinha o stop-loss com a máxima (para posições compradas) ou mínima (para posições vendidas) da vela anteriormente concluída menos/mais a distância do pip configurada. A lógica móvel só estará ativa se o stop-loss estiver ativado e EnableTrailingStop estiver definido como true.
Gestão de risco
Stop-loss – converte a distância do pip configurada em unidades de preço usando a etapa de preço do título.
Take-profit – calculado uma vez na entrada e mantido estático até ser alcançado ou a posição ser fechada por outra regra.
Trailing stop – avança o stop loss quando uma máxima mais favorável (para posições compradas) ou mínima (para posições vendidas) aparece na vela anterior.
Tratamento de reversão – caso chegue um sinal enquanto uma posição oposta estiver aberta, a estratégia envia uma ordem de mercado dimensionada para reverter totalmente e estabelecer a nova exposição em uma única transação.
Parâmetros
Parâmetro
Descrição
Padrão
OrderVolume
Tamanho base da negociação em lotes ou contratos.
0.30
StopLossPips
Distância de parada protetora em pips. 0 desativa a parada.
46
TakeProfitPips
Distância alvo de lucro em pips. 0 desativa o alvo.
0
EnableTrailingStop
Permite o rastreamento baseado em pip quando um stop loss está ativo.
true
BollingerPeriod
Comprimento da janela Bollinger Bandas.
5
BollingerDeviation
Multiplicador de desvio padrão para as bandas.
2.5
TeethPeriod
Comprimento médio móvel suavizado para a linha dos dentes Alligator.
21
CandleType
Série de velas usada para cálculos (período de 15 minutos por padrão).
15m velas
Todos os parâmetros numéricos incluem metadados de otimização para que possam ser ajustados através do Strategy Analyzer.
Notas de implementação
Somente velas concluídas são processadas; dados inacabados são ignorados para imitar a execução orientada por temporizador MetaTrader executada no início de cada nova barra.
A lógica móvel requer uma distância de stop-loss positiva. Uma exceção será lançada durante a inicialização se a opção final estiver habilitada sem parar.
As instâncias do indicador são desenhadas automaticamente quando uma área do gráfico está disponível, ajudando a validar se a porta StockSharp corresponde ao modelo MetaTrader.
Uso
Carregue a estratégia em um terminal StockSharp ou ambiente de backtesting.
Configure o título de negociação e ajuste os parâmetros (especialmente as distâncias do pip) para corresponder às especificações do contrato da corretora.
Comece a estratégia. Ele assinará a série de velas configuradas, avaliará as entradas em cada vela finalizada e gerenciará a posição usando as regras descritas.
Para negociação ao vivo, certifique-se de que a corretora oferece suporte a ordens de mercado e que o símbolo PriceStep esteja disponível para que as conversões de pip sejam precisas.
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simplified from "Aussie Surfer Ltd" MetaTrader expert.
/// Uses Bollinger Band reversals with an SMA slope filter for entries.
/// </summary>
public class AussieSurferLtdStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _bollingerPeriod;
private readonly StrategyParam<decimal> _bollingerWidth;
private readonly StrategyParam<int> _smaPeriod;
private ExponentialMovingAverage _bandEma;
private ExponentialMovingAverage _slopeEma;
private decimal? _prevSma;
private decimal? _prevClose;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int BollingerPeriod
{
get => _bollingerPeriod.Value;
set => _bollingerPeriod.Value = value;
}
public decimal BollingerWidth
{
get => _bollingerWidth.Value;
set => _bollingerWidth.Value = value;
}
public int SmaPeriod
{
get => _smaPeriod.Value;
set => _smaPeriod.Value = value;
}
public AussieSurferLtdStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(120).TimeFrame())
.SetDisplay("Candle Type", "Primary timeframe", "General");
_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Bollinger Period", "Bollinger Bands window", "Indicators");
_bollingerWidth = Param(nameof(BollingerWidth), 2.5m)
.SetGreaterThanZero()
.SetDisplay("Bollinger Width", "Standard deviation multiplier", "Indicators");
_smaPeriod = Param(nameof(SmaPeriod), 21)
.SetGreaterThanZero()
.SetDisplay("SMA Period", "SMA period for slope filter", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_bandEma = new ExponentialMovingAverage { Length = BollingerPeriod };
_slopeEma = new ExponentialMovingAverage { Length = SmaPeriod };
_prevSma = null;
_prevClose = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_bandEma, _slopeEma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _bandEma);
DrawIndicator(area, _slopeEma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal bandValue, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_bandEma.IsFormed || !_slopeEma.IsFormed)
{
_prevClose = candle.ClosePrice;
_prevSma = smaValue;
return;
}
var close = candle.ClosePrice;
var bandOffset = bandValue * (BollingerWidth / 100m);
var upperBand = bandValue + bandOffset;
var lowerBand = bandValue - bandOffset;
if (_prevSma is null || _prevClose is null)
{
_prevSma = smaValue;
_prevClose = close;
return;
}
var volume = Volume;
if (volume <= 0)
volume = 1;
// SMA slope (uptrend or downtrend)
var smaRising = smaValue > _prevSma.Value;
var smaFalling = smaValue < _prevSma.Value;
// Long: price was below lower band and crosses back above, SMA falling (reversal)
var longSignal = _prevClose.Value < lowerBand && close >= lowerBand && smaFalling;
// Short: price was above upper band and crosses back below, SMA rising (reversal)
var shortSignal = _prevClose.Value > upperBand && close <= upperBand && smaRising;
if (longSignal)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
else if (shortSignal)
{
if (Position >= 0)
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
// Exit at opposite band or SMA reversal
if (Position > 0 && (close >= upperBand || (smaFalling && _prevSma.Value > smaValue)))
{
SellMarket(Position);
}
else if (Position < 0 && (close <= lowerBand || (smaRising && _prevSma.Value < smaValue)))
{
BuyMarket(Math.Abs(Position));
}
_prevSma = smaValue;
_prevClose = close;
}
/// <inheritdoc />
protected override void OnReseted()
{
_bandEma = null;
_slopeEma = null;
_prevSma = null;
_prevClose = null;
base.OnReseted();
}
}
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 aussie_surfer_ltd_strategy(Strategy):
def __init__(self):
super(aussie_surfer_ltd_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(120)))
self._bollinger_period = self.Param("BollingerPeriod", 20)
self._bollinger_width = self.Param("BollingerWidth", 2.5)
self._sma_period = self.Param("SmaPeriod", 21)
self._prev_sma = None
self._prev_close = None
@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
@BollingerPeriod.setter
def BollingerPeriod(self, value):
self._bollinger_period.Value = value
@property
def BollingerWidth(self):
return self._bollinger_width.Value
@BollingerWidth.setter
def BollingerWidth(self, value):
self._bollinger_width.Value = value
@property
def SmaPeriod(self):
return self._sma_period.Value
@SmaPeriod.setter
def SmaPeriod(self, value):
self._sma_period.Value = value
def OnReseted(self):
super(aussie_surfer_ltd_strategy, self).OnReseted()
self._prev_sma = None
self._prev_close = None
def OnStarted2(self, time):
super(aussie_surfer_ltd_strategy, self).OnStarted2(time)
self._prev_sma = None
self._prev_close = None
band_ema = ExponentialMovingAverage()
band_ema.Length = self.BollingerPeriod
slope_ema = ExponentialMovingAverage()
slope_ema.Length = self.SmaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(band_ema, slope_ema, self._process_candle).Start()
def _process_candle(self, candle, band_value, sma_value):
if candle.State != CandleStates.Finished:
return
band_val = float(band_value)
sma_val = float(sma_value)
close = float(candle.ClosePrice)
band_offset = band_val * (float(self.BollingerWidth) / 100.0)
upper_band = band_val + band_offset
lower_band = band_val - band_offset
if self._prev_sma is None or self._prev_close is None:
self._prev_sma = sma_val
self._prev_close = close
return
sma_rising = sma_val > self._prev_sma
sma_falling = sma_val < self._prev_sma
# Long: price was below lower band and crosses back above, SMA falling (reversal)
long_signal = self._prev_close < lower_band and close >= lower_band and sma_falling
# Short: price was above upper band and crosses back below, SMA rising (reversal)
short_signal = self._prev_close > upper_band and close <= upper_band and sma_rising
if long_signal:
if self.Position <= 0:
self.BuyMarket()
elif short_signal:
if self.Position >= 0:
self.SellMarket()
# Exit at opposite band or SMA reversal
if self.Position > 0 and (close >= upper_band or (sma_falling and self._prev_sma > sma_val)):
self.SellMarket()
elif self.Position < 0 and (close <= lower_band or (sma_rising and self._prev_sma < sma_val)):
self.BuyMarket()
self._prev_sma = sma_val
self._prev_close = close
def CreateClone(self):
return aussie_surfer_ltd_strategy()