Esta estratégia porta o consultor especialista 1 MINUTE SCALPER do MetaTrader 4 para a API de alto nível do StockSharp.
Mantém a confirmação de tendência multicamadas, o momentum multi-temporal e o filtro MACD de longo prazo do robô original
enquanto adapta os controles de risco ao modelo centrado em posições do StockSharp.
Lógica Central
Pilha de Tendência – treze médias móveis lineares ponderadas (LWMA 3/5/8/10/12/15/30/35/40/45/50/55/200) devem estar
alinhadas em ordem estrita. Operações compradas requerem que cada média mais curta esteja acima da próxima, enquanto as
vendidas invertem a condição.
Portão de Tendência Principal – uma LWMA rápida adicional (padrão 6) deve permanecer acima da LWMA lenta (padrão 85)
para comprados e abaixo para vendidos, espelhando a verificação rápido-vs-lento do EA.
Estrutura de Candle – entradas só são acionadas quando os padrões de sobreposição do script estão presentes: para
comprados o mínimo de duas barras atrás deve estar abaixo do máximo anterior; para vendidos o mínimo anterior deve cair
abaixo do máximo de duas barras atrás.
Filtro de Momentum – um indicador de momentum de 14 períodos calculado em um período superior (padrão candles de 15
minutos) deve se desviar de 100 pelo menos nos limiares configurados em qualquer um dos últimos três valores. Isso reproduz
as comparações MomLevelB/MomLevelS.
Viés MACD Mensal – um MACD construído no período MACD selecionado (padrão candles de 30 dias como proxy para dados
mensais) deve mostrar a linha principal acima do sinal para comprados ou abaixo para vendidos.
Gestão de Operações
Proteção Inicial – as distâncias de stop-loss e take-profit são expressas em passos do instrumento (pontos). Quando uma
posição abre, a estratégia converte essas contagens de passos para preços absolutos usando Security.PriceStep.
Movimento de Ponto de Equilíbrio – após o preço mover BreakEvenTriggerSteps a favor, o stop é movido para a entrada
mais BreakEvenOffsetSteps (para vendidos a lógica espelhada se aplica). O indicador é acionado uma vez por posição.
Trailing por Passos – quando TrailingStopSteps é positivo, o stop segue o preço mais alto (ou mais baixo) desde a
entrada pelo número especificado de passos.
Trailing Monetário – uma vez que o lucro flutuante exceda MoneyTrailTarget (moeda), a estratégia rastreia o PnL
flutuante máximo e fecha a posição se o recuo for igual a MoneyTrailStop.
Alvos Monetários/Percentuais – alvos de take-profit absolutos ou opcionais fecham toda a exposição quando o PnL flutuante
cruza os limiares configurados. O alvo percentual usa o valor inicial do portfólio capturado quando a estratégia começa.
Stop de Capital – a estratégia monitora o capital máximo (valor do portfólio mais PnL aberto). Se o drawdown desse pico
exceder EquityRiskPercent, todas as posições são fechadas, replicando a salvaguarda AccountEquityHigh() do EA.
Parâmetros
Parâmetro
Descrição
Volume
Volume de ordem para novas entradas. Adicionado à posição atual absoluta para que as reversões mudem a exposição imediatamente.
FastMaPeriod / SlowMaPeriod
Comprimentos de LWMA para o filtro de tendência principal.
MomentumPeriod
Comprimento do indicador de momentum no período superior.
MomentumBuyThreshold / MomentumSellThreshold
Desvio absoluto mínimo de 100 necessário para confirmação de momentum comprado/vendido.
Configurar a lógica de trailing do lucro flutuante.
UseEquityStop, EquityRiskPercent
Habilitar o stop de drawdown e definir o percentual máximo de drawdown.
CandleType
Candles de trabalho principais (padrão 1 minuto).
MomentumCandleType
Candles de período superior para o indicador de momentum (padrão 15 minutos).
MacdCandleType
Candles usadas para o filtro de tendência MACD (padrão 30 dias ≈ mensal).
Diferenças vs. o Expert do MT4
StockSharp usa posições líquidas, então a estratégia sempre mantém uma única posição agregada em vez de múltiplos tickets até
Max_Trades. Reversões fecham a exposição existente antes de abrir na direção oposta.
PercentTakeProfit referencia o valor do portfólio capturado no início em vez do AccountBalance() em constante mudança
usado pelo MetaTrader, o que evita alvos ruidosos quando operações externas modificam o saldo.
A lógica de saída baseada em dinheiro (Take_Profit_In_Money e TRAIL_PROFIT_IN_MONEY2) opera sobre o PnL flutuante em tempo
real calculado a partir do preço de entrada médio da estratégia. Isso corresponde ao comportamento do EA mas dentro do
framework de proteção do StockSharp.
A plataforma deve fornecer feeds de candles para os períodos selecionados (CandleType, MomentumCandleType,
MacdCandleType). Certifique-se de que os adaptadores que você usa suportam as resoluções solicitadas.
Ajuste os limiares para adequar ao seu instrumento e sessão. Pares com spreads estreitos ou altamente voláteis podem exigir
distâncias de passos maiores ou limiares de momentum maiores para reduzir o ruído.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// One-minute scalper strategy using fast/slow WMA crossover.
/// Buys on bullish crossover, sells on bearish crossover.
/// </summary>
public class OneMinuteScalperStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private WeightedMovingAverage _fast;
private WeightedMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
/// <summary>
/// Fast WMA period.
/// </summary>
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
/// <summary>
/// Slow WMA period.
/// </summary>
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
/// <summary>
/// Stop-loss distance in price steps.
/// </summary>
public int StopLossPoints
{
get => _stopLossPoints.Value;
set => _stopLossPoints.Value = value;
}
/// <summary>
/// Take-profit distance in price steps.
/// </summary>
public int TakeProfitPoints
{
get => _takeProfitPoints.Value;
set => _takeProfitPoints.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="OneMinuteScalperStrategy"/> class.
/// </summary>
public OneMinuteScalperStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast WMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 85)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow WMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200)
.SetNotNegative()
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 500)
.SetNotNegative()
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_fast = null;
_slow = null;
_prevFast = 0;
_prevSlow = 0;
_entryPrice = 0;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new WeightedMovingAverage { Length = FastPeriod };
_slow = new WeightedMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_fast.IsFormed || !_slow.IsFormed)
{
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
// Check SL/TP
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step)
{
SellMarket();
_entryPrice = 0;
_cooldown = 60;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step)
{
SellMarket();
_entryPrice = 0;
_cooldown = 60;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step)
{
BuyMarket();
_entryPrice = 0;
_cooldown = 60;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step)
{
BuyMarket();
_entryPrice = 0;
_cooldown = 60;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
}
// WMA crossover
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
_entryPrice = close;
_cooldown = 60;
}
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
_entryPrice = close;
_cooldown = 60;
}
_prevFast = fastValue;
_prevSlow = slowValue;
}
}
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 WeightedMovingAverage
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
from indicator_extensions import *
class one_minute_scalper_strategy(Strategy):
def __init__(self):
super(one_minute_scalper_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 20).SetGreaterThanZero().SetDisplay("Fast Period", "Fast WMA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 85).SetGreaterThanZero().SetDisplay("Slow Period", "Slow WMA period", "Indicator")
self._sl_points = self.Param("StopLossPoints", 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._tp_points = self.Param("TakeProfitPoints", 500).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
def OnReseted(self):
super(one_minute_scalper_strategy, self).OnReseted()
self._prev_fast = 0
self._prev_slow = 0
self._entry_price = 0
self._cooldown = 0
def OnStarted2(self, time):
super(one_minute_scalper_strategy, self).OnStarted2(time)
self._prev_fast = 0
self._prev_slow = 0
self._entry_price = 0
self._cooldown = 0
self._fast = WeightedMovingAverage()
self._fast.Length = self._fast_period.Value
self._slow = WeightedMovingAverage()
self._slow.Length = self._slow_period.Value
sub = self.SubscribeCandles(tf(5))
sub.Bind(self._fast, self._slow, self.OnProcess).Start()
def OnProcess(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = candle.ClosePrice
step = 1.0
if self.Security is not None and self.Security.PriceStep is not None and self.Security.PriceStep > 0:
step = float(self.Security.PriceStep)
# Check SL/TP
if self.Position > 0 and self._entry_price > 0:
if self._sl_points.Value > 0 and close <= self._entry_price - self._sl_points.Value * step:
self.SellMarket()
self._entry_price = 0
self._cooldown = 60
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._tp_points.Value > 0 and close >= self._entry_price + self._tp_points.Value * step:
self.SellMarket()
self._entry_price = 0
self._cooldown = 60
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self._sl_points.Value > 0 and close >= self._entry_price + self._sl_points.Value * step:
self.BuyMarket()
self._entry_price = 0
self._cooldown = 60
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._tp_points.Value > 0 and close <= self._entry_price - self._tp_points.Value * step:
self.BuyMarket()
self._entry_price = 0
self._cooldown = 60
self._prev_fast = fast_val
self._prev_slow = slow_val
return
# WMA crossover
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 60
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 60
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return one_minute_scalper_strategy()