A estratégia Day Trading PAMXA reproduz o consultor especialista do MetaTrader 5 que combina reversões de momentum do Awesome Oscillator de Bill Williams com um filtro estocástico. O port para StockSharp mantém o design multi-período original:
O loop de decisão principal é executado no período de Velas de Sinal (padrão 1 hora).
O Awesome Oscillator é avaliado em um período separado de Velas AO (padrão 1 dia) para obter momentum de período superior.
O oscilador estocástico usa seu próprio período de Velas Estocásticas (padrão 1 hora) para que os níveis %K/%D estejam alinhados com as configurações originais.
A estratégia mantém no máximo uma posição por vez. Quando aparece uma configuração altista, primeiro cobre quaisquer posições vendidas ativas antes de entrar comprado, e vice-versa para configurações baixistas.
Lógica de Entrada
Calcular os valores terminados mais recentes do Awesome Oscillator no período AO.
Calcular os valores terminados mais recentes de %K e %D do oscilador estocástico no período estocástico.
Em cada vela de sinal terminada:
Configuração altista: acionada quando a barra AO anterior estava abaixo de zero e a última barra fechou acima de zero (reversão de momentum) enquanto %K ou %D estiver abaixo do limiar Nível estocástico baixo (condição de sobrevenda). Qualquer posição vendida aberta é coberta e uma nova posição comprada é aberta se não restar posição.
Configuração baixista: acionada quando a barra AO anterior estava acima de zero e a última barra fechou abaixo de zero enquanto %K ou %D estiver acima do limiar Nível estocástico alto (condição de sobrecompra). Qualquer posição comprada aberta é fechada e, se flat, uma nova posição vendida é aberta.
Saída e Gestão de Risco
Um stop-loss e take-profit baseados em pips são anexados na entrada. Quando a mínima da vela (para comprados) ou a máxima (para vendidos) viola o nível de stop, a posição é liquidada imediatamente. A mesma lógica se aplica ao alvo de lucro.
Um trailing stop opcional ativa quando o preço avançou Trailing Stop + Trailing Step pips a favor da posição. Para comprados o stop segue a máxima mais alta menos a distância de trailing; para vendidos segue a mínima mais baixa mais a distância de trailing. O ajuste de trailing ocorre somente quando o movimento excede o passo de trailing.
A gestão monetária pode operar em dois modos:
FixedVolume: usa o parâmetro Order Volume diretamente.
RiskPercent: calcula o volume de modo que o percentual configurado do valor do portfólio seria perdido se o stop-loss for atingido.
A estratégia nunca piramida – uma vez que existe uma posição, o próximo sinal oposto irá achatá-la antes de qualquer nova entrada ser considerada.
Parâmetros
Parâmetro
Descrição
Stop Loss
Distância de stop-loss em pips. Zero desativa o stop protetor.
Take Profit
Distância de take-profit em pips. Zero desativa o alvo de lucro.
Trailing Stop
Distância de ativação do trailing stop em pips. Zero desativa o trailing.
Trailing Step
Pips adicionais necessários antes que o trailing stop avance. Deve ser positivo quando o trailing está habilitado.
Money Mode
Seleciona entre dimensionamento FixedVolume e RiskPercent.
Money Value
Interpretado como tamanho de lote com volume fixo, ou como percentual de risco com dimensionamento baseado em risco.
Order Volume
Volume base usado quando Money Mode é FixedVolume.
Stochastic %K
Comprimento do cálculo estocástico %K.
Stochastic %D
Comprimento de suavização para a linha estocástica %D.
Stochastic Slow
Fator de suavização final aplicado ao oscilador estocástico.
Level Up
Limiar estocástico superior que habilita entradas vendidas.
Level Down
Limiar estocástico inferior que habilita entradas compradas.
Signal Candles
Período que impulsiona o loop principal de negociação.
Stochastic Candles
Período que alimenta o oscilador estocástico.
AO Candles
Período que alimenta o Awesome Oscillator.
AO Fast / AO Slow
Períodos para as médias móveis internas do Awesome Oscillator.
Notas de Implementação
O cálculo do valor do pip emula a lógica do MetaTrader: quando o instrumento usa 3 ou 5 casas decimais, um pip equivale a dez passos de preço; caso contrário equivale a um passo de preço.
O oscilador estocástico do StockSharp não expõe uma seleção dedicada de "campo de preço"; o port usa o cálculo padrão baseado em fechamento, mantendo os parâmetros de suavização configuráveis.
O tratamento do trailing stop é implementado como uma verificação virtual nas máximas/mínimas das velas, replicando os ajustes de stop do lado servidor realizados no MetaTrader sem registrar ordens de stop explícitas.
O código assina todos os períodos de velas necessários através de GetWorkingSecurities.
Comentários em inglês documentam as decisões de fluxo de controle mais importantes.
Dicas de Uso
Alinhe o período de Signal Candles com o período em que planeja fazer backtesting ou negociar. Mantenha Stochastic Candles e AO Candles iguais aos padrões originais quando quiser replicar exatamente o especialista MQL5.
Ao mudar para dimensionamento RiskPercent, certifique-se de que a distância de stop-loss seja diferente de zero; caso contrário a estratégia recorre a Order Volume.
A configuração de trailing padrão reflete o EA original (trailing stop de 25 pips com passo de 5 pips). Defina Trailing Stop como zero se preferir um stop-loss estático.
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>
/// Day Trading PAMXA strategy using EMA crossover.
/// Buys when fast EMA crosses above slow EMA, sells on reverse.
/// </summary>
public class DayTradingPamxaStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public DayTradingPamxaStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { 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;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class day_trading_pamxa_strategy(Strategy):
def __init__(self):
super(day_trading_pamxa_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(day_trading_pamxa_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(day_trading_pamxa_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
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 = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
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 = 100
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 = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return day_trading_pamxa_strategy()