A estratégia replica o consultor especialista "55 MA" do MetaTrader 5, comparando dois pontos de uma média móvel de 55 períodos e negociando sempre que sua diferença excede um limite configurável. Todos os cálculos são realizados em velas completadas dentro de uma sessão intradiária definida pelo usuário, e a direção da operação pode ser opcionalmente invertida. O algoritmo preserva o comportamento original onde uma posição vendida é aberta sempre que nenhuma condição de alta é atendida.
Lógica de trading
Inscrever-se na série de velas selecionada e calcular uma média móvel com o comprimento, método e preço aplicado escolhidos.
Manter os valores mais recentes da média móvel em um buffer para que os valores nos índices de barra BarA e BarB possam ser acessados mesmo quando um deslocamento horizontal de MA é utilizado.
Quando uma vela finalizada chega dentro da janela [StartHour, EndHour):
Recuperar o valor de MA em BarA + MaShift e BarB + MaShift.
Se o valor em BarA excede o valor em BarB em mais de DifferenceThreshold, abrir uma posição comprada a menos que ReverseSignals esteja habilitado.
Se o valor em BarA é menor que o valor em BarB em mais de DifferenceThreshold, abrir uma posição vendida (ou uma posição comprada quando ReverseSignals está habilitado).
Caso contrário, a estratégia mantém o comportamento original do EA e aciona uma entrada vendida.
As ordens são sempre enviadas a mercado usando o Volume da estratégia. Quando CloseOppositePositions está habilitado, o tamanho solicitado é aumentado para neutralizar qualquer exposição oposta antes de estabelecer a nova posição.
Proteções opcionais de stop-loss e take-profit são anexadas através de StartProtection. As distâncias são expressas em pips, onde um pip equivale a PriceStep multiplicado por 10 para instrumentos cotados com 3 ou 5 dígitos decimais.
Entradas
Nome
Tipo
Padrão
Descrição
CandleType
DataType
Período de 1 minuto
Série de velas utilizada para cálculos e sinais.
StopLossPips
int
30
Distância do stop-loss em pips. Definir como 0 para desabilitar.
TakeProfitPips
int
50
Distância do take-profit em pips. Definir como 0 para desabilitar.
StartHour
int
8
Hora inclusiva (0-23) que marca o início da sessão de negociação.
EndHour
int
21
Hora exclusiva (0-23) que marca o fim da sessão de negociação. Deve ser maior que StartHour.
DifferenceThreshold
decimal
0.0001
Diferença absoluta mínima entre os valores de MA comparados que aciona um sinal direcional.
BarA
int
0
Índice da primeira barra usada para a comparação de MA (0 = vela atual).
BarB
int
1
Índice da segunda barra usada para a comparação de MA.
ReverseSignals
bool
false
Inverte as condições de alta e baixa.
CloseOppositePositions
bool
false
Se habilitado, aumenta o tamanho da ordem para fechar qualquer posição na direção oposta antes de abrir o novo trade.
MaShift
int
0
Deslocamento horizontal aplicado à linha da média móvel. Valores positivos acessam pontos de MA mais antigos.
MaLength
int
55
Período da média móvel.
MaMethod
MovingAverageMethods
Exponential
Método de suavização (Simple, Exponential, Smoothed, Weighted).
AppliedPrice
AppliedPriceTypes
Median
Preço usado como entrada de MA (Close, Open, High, Low, Median, Typical, Weighted).
Gestão de posições
Definir o Volume da estratégia para controlar o tamanho base da operação. É combinado com a posição atual quando CloseOppositePositions está ativo.
As proteções de stop-loss e take-profit são opcionais. Elas são anexadas apenas quando a respectiva distância em pips é maior que zero.
Notas
A janela de negociação funciona no tempo do instrumento; sinais fora de [StartHour, EndHour) são ignorados.
Quando MaShift produz índices negativos, a estratégia aguarda até que histórico suficiente seja acumulado, espelhando o comportamento original do EA onde buffers deslocados podem retornar EMPTY_VALUE.
Como o especialista original sempre tem como padrão uma ordem de venda quando o limite de diferença não é atingido, a estratégia convertida mantém a mesma lógica para plena fidelidade. Ajustar DifferenceThreshold se esse comportamento for indesejável.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// 55 MA bar comparison strategy. Compares candle body with MA direction.
/// </summary>
public class FiftyFiveMaBarComparisonStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _maPeriod;
private decimal? _prevMa;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
public FiftyFiveMaBarComparisonStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_maPeriod = Param(nameof(MaPeriod), 55)
.SetGreaterThanZero()
.SetDisplay("MA Period", "Moving average period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMa = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevMa = null;
var sma = new SimpleMovingAverage { Length = MaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal maVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevMa = maVal;
return;
}
if (_prevMa == null)
{
_prevMa = maVal;
return;
}
var close = candle.ClosePrice;
var bullishBar = candle.ClosePrice > candle.OpenPrice;
var bearishBar = candle.ClosePrice < candle.OpenPrice;
var maRising = maVal > _prevMa.Value;
var maFalling = maVal < _prevMa.Value;
_prevMa = maVal;
// Bullish bar + rising MA + close above MA → buy
if (bullishBar && maRising && close > maVal && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Bearish bar + falling MA + close below MA → sell
else if (bearishBar && maFalling && close < maVal && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
}
}
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class fifty_five_ma_bar_comparison_strategy(Strategy):
def __init__(self):
super(fifty_five_ma_bar_comparison_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._ma_period = self.Param("MaPeriod", 55) \
.SetDisplay("MA Period", "Moving average period", "Indicators")
self._prev_ma = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def MaPeriod(self):
return self._ma_period.Value
def OnReseted(self):
super(fifty_five_ma_bar_comparison_strategy, self).OnReseted()
self._prev_ma = None
def OnStarted2(self, time):
super(fifty_five_ma_bar_comparison_strategy, self).OnStarted2(time)
self._prev_ma = None
sma = SimpleMovingAverage()
sma.Length = self.MaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(sma, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def _on_process(self, candle, ma_value):
if candle.State != CandleStates.Finished:
return
mv = float(ma_value)
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_ma = mv
return
if self._prev_ma is None:
self._prev_ma = mv
return
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
bullish_bar = close > open_price
bearish_bar = close < open_price
ma_rising = mv > self._prev_ma
ma_falling = mv < self._prev_ma
self._prev_ma = mv
# Bullish bar + rising MA + close above MA
if bullish_bar and ma_rising and close > mv and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Bearish bar + falling MA + close below MA
elif bearish_bar and ma_falling and close < mv and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return fifty_five_ma_bar_comparison_strategy()