Conversão do MetaTrader 4 consultor especialista up3x1.mq4 localizado em MQL/8097.
Implementa o cruzamento triplo de média móvel simples com uma mudança positiva no gráfico exatamente como no script original.
Processa apenas velas concluídas para emular a guarda Volume[0] > 1 que forçou o especialista a avaliar uma vez por barra.
Os recursos de gerenciamento de risco incluem takeprofit, stop loss, redução dinâmica de lote após perdas em negociações e um trailing stop opcional.
Lógica de negociação
Indicadores
Três médias móveis simples com um deslocamento gráfico de 6 barras (rápido = 24, médio = 60, lento = 120 por padrão).
Entrada longa
Barra anterior: SMAfast₍t-1₎ < SMAmedium₍t-1₎ < SMAslow₍t-1₎.
Barra atual: SMAmedium₍t₎ < SMAfast₍t₎ < SMAslow₍t₎.
A condição replica ma1 < ma2 < ma3 && ma5 < ma4 < ma6 de MQL.
Entrada curta
Barra anterior: SMAfast₍t-1₎ > SMAmedium₍t-1₎ > SMAslow₍t-1₎.
Barra atual: SMAmedium₍t₎ > SMAfast₍t₎ > SMAslow₍t₎.
Regras de saída
Take Profit e Stop Loss respeitam a distância do ponto configurado multiplicada por Security.PriceStep (ou usado diretamente quando o passo é desconhecido).
O trailing stop bloqueia os lucros quando o preço avança mais de TrailingStopPoints e segue o extremo alcançado após a entrada.
Saída à prova de falhas quando as médias móveis mudam para a ordem oposta, espelhando a lógica OrderClose original.
Dimensionamento de posições
O volume padrão é igual a BaseVolume (0,1 lote) sempre que as métricas do portfólio não estiverem disponíveis.
Quando Portfolio.CurrentValue existe, a estratégia o multiplica por RiskFraction (padrão 0.00002, equivalente à fórmula MQL FreeMargin * 0.02 / 1000).
Após mais de uma saída perdida, o volume é reduzido em volume * losses / 3, exatamente como a rotina LotsOptimized.
O volume é arredondado para Security.VolumeStep e reduzido a zero se não puder satisfazer Security.MinVolume.
Parâmetros
Parâmetro
Padrão
Descrição
FastPeriod
24
Comprimento do deslocamento mais rápido SMA.
MediumPeriod
60
Comprimento do meio deslocado SMA.
SlowPeriod
120
Comprimento do deslocamento lento SMA.
TakeProfitPoints
150
Distância em pontos de preço entre o preço de entrada e o lucro.
StopLossPoints
100
Distância em pontos de preço entre o preço de entrada e o stop loss.
TrailingStopPoints
100
Distância de parada móvel opcional em pontos (definida como 0 para desabilitar).
BaseVolume
0,1
Tamanho da negociação de reserva e volume mínimo após reduções.
RiskFraction
0,00002
Fração do valor do portfólio utilizado para calcular o volume dinâmico.
CandleType
Período de 1 hora
Série de velas usadas para alimentar indicadores.
Notas de conversão
A estratégia usa o API de alto nível (SubscribeCandles + Bind) e evita buffers de histórico manuais.
Os valores do indicador são armazenados entre chamadas para imitar o parâmetro shift sem acesso direto ao índice.
As saídas protetoras são executadas com comandos de mercado no nível de preço detectado para permanecerem compatíveis com a abstração StockSharp.
Todos os comentários in-line são escritos em inglês, em conformidade com as diretrizes do projeto.
Uso
Anexe a estratégia a um título e portfólio no StockSharp Designer ou código.
Selecione uma série de velas (CandleType) que corresponda ao seu período MT4 (H1 por padrão).
Revise os parâmetros de risco baseados em pontos para alinhá-los com o tamanho do tick do instrumento (por exemplo, 0,0001 para a maioria dos pares Forex).
Defina TrailingStopPoints como zero quando o rastreamento não for necessário.
Monitore os registros em busca de mensagens como "Enter long" e "Exit short" que espelham o diagnóstico do MQL.
Estrutura do Repositório
API/3924/
├── CS/Up3x1ShiftedSmaStrategy.cs # Estratégia C# convertida com comentários em inglês
├── README.md # Documentação em inglês (este arquivo)
├── README_zh.md # Tradução chinesa
└── README_ru.md # Tradução russa
Isenção de responsabilidade
A negociação envolve riscos significativos. A estratégia é fornecida para fins educacionais e deve ser validada em dados históricos e simulados antes da negociação ao vivo.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class Up3x1ShiftedSmaStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Up3x1ShiftedSmaStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 8).SetDisplay("Fast WMA", "Fast WMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 24).SetDisplay("Slow WMA", "Slow WMA period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = default;
_prevSlow = default;
_hasPrev = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var fast = new SimpleMovingAverage { Length = FastPeriod };
var slow = new SimpleMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, slow, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) return;
if (!_hasPrev) { _prevFast = fast; _prevSlow = slow; _hasPrev = true; return; }
if (_cooldown > 0)
{
_cooldown--;
_prevFast = fast;
_prevSlow = slow;
return;
}
if (_prevFast <= _prevSlow && fast > slow && Position <= 0)
{
var volume = Volume + Math.Abs(Position);
BuyMarket(volume);
_cooldown = 2;
}
else if (_prevFast >= _prevSlow && fast < slow && Position >= 0)
{
var volume = Volume + Math.Abs(Position);
SellMarket(volume);
_cooldown = 2;
}
_prevFast = fast; _prevSlow = slow;
}
}
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
from datatype_extensions import *
from indicator_extensions import *
class up_3x1_shifted_sma_strategy(Strategy):
"""Simple SMA crossover (fast/slow) with cooldown between trades."""
def __init__(self):
super(up_3x1_shifted_sma_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 8).SetDisplay("Fast SMA", "Fast SMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 24).SetDisplay("Slow SMA", "Slow SMA period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))).SetDisplay("Candle Type", "Timeframe", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(up_3x1_shifted_sma_strategy, self).OnReseted()
self._prev_fast = 0
self._prev_slow = 0
self._has_prev = False
self._cooldown = 0
def OnStarted2(self, time):
super(up_3x1_shifted_sma_strategy, self).OnStarted2(time)
self._prev_fast = 0
self._prev_slow = 0
self._has_prev = False
self._cooldown = 0
fast = SimpleMovingAverage()
fast.Length = self._fast_period.Value
slow = SimpleMovingAverage()
slow.Length = self._slow_period.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(fast, slow, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def OnProcess(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
fv = float(fast_val)
sv = float(slow_val)
if not self._has_prev:
self._prev_fast = fv
self._prev_slow = sv
self._has_prev = True
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fv
self._prev_slow = sv
return
if self._prev_fast <= self._prev_slow and fv > sv and self.Position <= 0:
volume = self.Volume + abs(self.Position)
self.BuyMarket(volume)
self._cooldown = 2
elif self._prev_fast >= self._prev_slow and fv < sv and self.Position >= 0:
volume = self.Volume + abs(self.Position)
self.SellMarket(volume)
self._cooldown = 2
self._prev_fast = fv
self._prev_slow = sv
def CreateClone(self):
return up_3x1_shifted_sma_strategy()