Um sistema contrário semanal convertido do consultor especialista MQL "Contrarian_trade_MA" original. A estratégia analisa os extremos semanais das velas juntamente com uma média móvel simples para atenuar os movimentos esticados no início de uma nova semana.
Lógica de negociação
Fonte de dados: velas semanais fornecidas pelo parâmetro CandleType (o padrão é um período de 7 dias).
Extremos históricos: os indicadores Highest e Lowest rastreiam a máxima e a mínima das CalcPeriod semanas anteriores concluídas, excluindo a vela atualmente avaliada.
Filtro de média móvel: uma média móvel simples de comprimento MaPeriod aplicada a fechamentos semanais atua como um filtro direcional.
Regras de inscrição:
Compre quando o fechamento da semana anterior for superior à máxima monitorada (highest < previousClose) ou quando a média móvel estiver acima da abertura semanal atual.
Venda quando o fechamento da semana anterior for inferior ao mínimo monitorado (lowest > previousClose) ou quando a média móvel estiver abaixo da abertura semanal atual.
Apenas uma posição pode ser aberta por vez; sinais opostos são ignorados até que a negociação existente seja fechada.
Regras de saída:
A posição é fechada após ser mantida por sete dias (604.800 segundos), independentemente da direção.
Uma parada protetora é avaliada em cada vela semanal concluída. A distância de parada é calculada a partir de StopLossPoints * PriceStep (volta para 1 se os metadados do instrumento não especificarem uma etapa).
Parâmetros
Nome
Padrão
Descrição
CalcPeriod
4
Número de semanas completas usadas para calcular o máximo mais alto e o mínimo mais baixo.
MaPeriod
7
Período da média móvel simples aplicada aos fechamentos semanais.
StopLossPoints
300
Distância do preço de entrada ao stop loss, medida em etapas de preço. Defina como 0 para desativar a parada.
Volume
0.5
Tamanho do pedido em lotes enviado por BuyMarket/SellMarket.
CandleType
7 days
Prazo para as velas que conduzem todos os cálculos.
Notas adicionais
A estratégia recupera automaticamente a etapa de preço de Security.PriceStep. Forneça esse valor nos metadados do instrumento para um posicionamento preciso do stop loss.
StartProtection() está habilitado para rastrear mudanças de posição inesperadas realizadas fora da estratégia.
Como a lógica opera em velas semanais concluídas, os preenchimentos são simulados no fechamento semanal da barra de sinal durante a execução no modo de teste.
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>
/// Contrarian MA strategy - mean reversion around SMA.
/// Buys when price crosses below SMA (contrarian dip buy).
/// Sells when price crosses above SMA (contrarian top sell).
/// Uses Highest/Lowest as extreme confirmation.
/// </summary>
public class ContrarianTradeMaWeeklyStrategy : Strategy
{
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<int> _channelPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevClose;
private decimal _prevSma;
private bool _hasPrev;
public int MaPeriod { get => _maPeriod.Value; set => _maPeriod.Value = value; }
public int ChannelPeriod { get => _channelPeriod.Value; set => _channelPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ContrarianTradeMaWeeklyStrategy()
{
_maPeriod = Param(nameof(MaPeriod), 14)
.SetDisplay("SMA Period", "SMA period", "Indicators");
_channelPeriod = Param(nameof(ChannelPeriod), 10)
.SetDisplay("Channel Period", "Highest/Lowest lookback", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
protected override void OnReseted() { base.OnReseted(); _prevClose = 0m; _prevSma = 0m; _hasPrev = false; }
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var sma = new SimpleMovingAverage { Length = MaPeriod };
var highest = new Highest { Length = ChannelPeriod };
var lowest = new Lowest { Length = ChannelPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, highest, lowest, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal sma, decimal highest, decimal lowest)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
if (!_hasPrev)
{
_prevClose = close;
_prevSma = sma;
_hasPrev = true;
return;
}
var mid = (highest + lowest) / 2;
// Contrarian buy: price crosses below SMA and is near the low
if (_prevClose >= _prevSma && close < sma && close < mid && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Contrarian sell: price crosses above SMA and is near the high
else if (_prevClose <= _prevSma && close > sma && close > mid && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevClose = close;
_prevSma = sma;
}
}
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, Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class contrarian_trade_ma_weekly_strategy(Strategy):
def __init__(self):
super(contrarian_trade_ma_weekly_strategy, self).__init__()
self._ma_period = self.Param("MaPeriod", 14) \
.SetDisplay("SMA Period", "SMA period", "Indicators")
self._channel_period = self.Param("ChannelPeriod", 10) \
.SetDisplay("Channel Period", "Highest/Lowest lookback", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_close = 0.0
self._prev_sma = 0.0
self._has_prev = False
@property
def ma_period(self):
return self._ma_period.Value
@property
def channel_period(self):
return self._channel_period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(contrarian_trade_ma_weekly_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_sma = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(contrarian_trade_ma_weekly_strategy, self).OnStarted2(time)
self._has_prev = False
sma = SimpleMovingAverage()
sma.Length = self.ma_period
highest = Highest()
highest.Length = self.channel_period
lowest = Lowest()
lowest.Length = self.channel_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sma, highest, lowest, self.process_candle).Start()
def process_candle(self, candle, sma, highest, lowest):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
sma_val = float(sma)
high_val = float(highest)
low_val = float(lowest)
if not self._has_prev:
self._prev_close = close
self._prev_sma = sma_val
self._has_prev = True
return
mid = (high_val + low_val) / 2.0
if self._prev_close >= self._prev_sma and close < sma_val and close < mid and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_close <= self._prev_sma and close > sma_val and close > mid and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_close = close
self._prev_sma = sma_val
def CreateClone(self):
return contrarian_trade_ma_weekly_strategy()