A estratégia MA Price Cross é uma conversão direta do MetaTrader 4 consultor especialista "MA Price Cross" para o StockSharp API de alto nível. Ele espera que a média móvel selecionada cruze o preço atual enquanto a negociação é permitida dentro de uma janela de tempo configurável. Quando o cruzamento acontece por baixo, o algoritmo abre uma posição comprada; quando o cruzamento acontece por cima, abre uma posição curta. As distâncias protetoras de stop-loss e take-profit são definidas em MetaTrader pontos e convertidas automaticamente em compensações de preço absoluto usando o PriceStep do instrumento.
Ao contrário da implementação original MQL, que reage a cada tick, a versão StockSharp funciona com velas finalizadas e usa a assinatura de alto nível SubscribeCandles. Isso garante que as decisões de negociação sejam executadas uma vez por barra e permaneçam compatíveis com o pipeline de vinculação do indicador. A média móvel pode ser configurada para corresponder a todos os quatro modos MetaTrader e aceita diferentes fontes de preços (fechamento, abertura, máximo, mínimo, mediano, típico, ponderado).
Lógica de negociação
Aguarde até que o horário atual caia na janela de negociação [StartTime, StopTime). As janelas noturnas são suportadas por volta da meia-noite.
Processe apenas velas concluídas. Alimente a média móvel configurada com o preço aplicado escolhido.
Armazene o valor da média móvel anterior para emular a lógica de deslocamento iMA usada em MetaTrader.
Quando a média anterior estiver abaixo do preço mais recente e a nova média estiver acima do preço, abra (ou inverta) uma posição longa.
Quando a média anterior estiver acima do preço mais recente e a nova média estiver abaixo do preço, abra (ou inverta) uma posição curta.
Antes de abrir uma nova posição no lado oposto, nivele qualquer exposição existente para espelhar a restrição OrdersTotal() == 0 do código original.
Inicie um stop-loss e um take-profit virtuais com distâncias expressas em MetaTrader pontos multiplicados pelo instrumento atual PriceStep.
Parâmetros padrão
Parâmetro
Padrão
Descrição
CandleType
TimeFrame(1m)
Série de velas que orienta todos os cálculos.
MaPeriod
160
Número de barras utilizadas pela média móvel.
MaMethod
Simple
Tipo de média móvel: Simples, Exponencial, Suavizada ou LinearWeighted.
PriceType
Close
Fonte de preço encaminhada para média móvel (fechamento/abertura/máxima/mínima/mediana/típica/ponderada).
StartTime
01:00
Hora do dia em que a negociação se torna ativa.
StopTime
22:00
Hora do dia em que novas entradas são interrompidas.
StopLossPoints
200
MetaTrader pontos convertidos em uma distância de parada de proteção absoluta.
TakeProfitPoints
600
MetaTrader pontos convertidos em uma distância alvo de lucro absoluto.
OrderVolume
0.1
Volume padrão enviado com ordens de mercado.
Notas
Se StartTime for igual a StopTime, o filtro de horário será desativado e a negociação será permitida o dia todo.
Quando StopLossPoints ou TakeProfitPoints é igual a zero, o nível de proteção correspondente não é registrado.
O filtro de tempo usa o tempo de fechamento da vela (candle.CloseTime.TimeOfDay) para se adaptar ao fuso horário de troca fornecido pelo MarketDataConnector.
Se a segurança não expor PriceStep, as distâncias baseadas em pontos serão usadas diretamente, sem escala.
Referência de estratégia original
Fonte: MQL/44133/MA Price Cross.mq4
Autor: JBlanked (2023)
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 "MA Price Cross" MetaTrader expert.
/// Enters when SMA crosses above/below the current close price.
/// </summary>
public class MaPriceCrossStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _maPeriod;
private ExponentialMovingAverage _sma;
private decimal? _prevAverage;
private decimal? _prevClose;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
public MaPriceCrossStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for MA cross detection", "General");
_maPeriod = Param(nameof(MaPeriod), 100)
.SetGreaterThanZero()
.SetDisplay("MA Period", "SMA period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_sma = new ExponentialMovingAverage { Length = MaPeriod };
_prevAverage = null;
_prevClose = null;
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 smaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_sma.IsFormed)
{
_prevAverage = smaValue;
_prevClose = candle.ClosePrice;
return;
}
if (_prevAverage is null || _prevClose is null)
{
_prevAverage = smaValue;
_prevClose = candle.ClosePrice;
return;
}
var close = candle.ClosePrice;
var volume = Volume;
if (volume <= 0)
volume = 1;
// MA was below price, now crosses above -> sell signal (price goes under MA)
var sellSignal = _prevClose.Value >= _prevAverage.Value && close < smaValue;
// MA was above price, now crosses below -> buy signal (price goes above MA)
var buySignal = _prevClose.Value <= _prevAverage.Value && close > smaValue;
if (buySignal)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
else if (sellSignal)
{
if (Position >= 0)
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
_prevAverage = smaValue;
_prevClose = close;
}
/// <inheritdoc />
protected override void OnReseted()
{
_sma = null;
_prevAverage = 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 ma_price_cross_strategy(Strategy):
def __init__(self):
super(ma_price_cross_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._ma_period = self.Param("MaPeriod", 100)
self._prev_average = 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 MaPeriod(self):
return self._ma_period.Value
@MaPeriod.setter
def MaPeriod(self, value):
self._ma_period.Value = value
def OnReseted(self):
super(ma_price_cross_strategy, self).OnReseted()
self._prev_average = None
self._prev_close = None
def OnStarted2(self, time):
super(ma_price_cross_strategy, self).OnStarted2(time)
self._prev_average = None
self._prev_close = None
sma = ExponentialMovingAverage()
sma.Length = self.MaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(sma, self._process_candle).Start()
def _process_candle(self, candle, sma_value):
if candle.State != CandleStates.Finished:
return
sma_val = float(sma_value)
close = float(candle.ClosePrice)
if self._prev_average is None or self._prev_close is None:
self._prev_average = sma_val
self._prev_close = close
return
# Price crosses above MA -> buy
buy_signal = self._prev_close <= self._prev_average and close > sma_val
# Price crosses below MA -> sell
sell_signal = self._prev_close >= self._prev_average and close < sma_val
if buy_signal:
if self.Position <= 0:
self.BuyMarket()
elif sell_signal:
if self.Position >= 0:
self.SellMarket()
self._prev_average = sma_val
self._prev_close = close
def CreateClone(self):
return ma_price_cross_strategy()