Esta estratégia replica o Expert Advisor "iMA iSAR EA" do MetaTrader 5 usando a API de alto nível do StockSharp. Combina um filtro de tripla média móvel ponderada com dois trilhos de SAR Parabólico para identificar rompimentos de momentum. Uma posição comprada é aberta quando a média móvel ponderada mais rápida permanece acima das outras duas médias e ambos os trilhos SAR ficam abaixo do fechamento da vela. Uma condição espelhada gera entradas vendidas. Stops protetores, metas de lucro e um trailing stop opcional são gerenciados em pontos de preço (pips).
A implementação trabalha em uma única série de velas configurável através do parâmetro CandleType. Todos os indicadores são avaliados neste período. O expert do MetaTrader original usava múltiplos períodos para seus indicadores; no StockSharp esse comportamento é aproximado permitindo deslocamentos individuais das médias móveis que podem atrasar cada sinal por um número de barras concluídas.
Regras de trading
Indicadores
Três médias móveis ponderadas (Fast, Normal, Slow) calculadas no stream de velas configurado. Deslocamentos de barras opcionais emulam os buffers atrasados do código MQ5 original.
Dois indicadores SAR Parabólico (FastSAR, NormalSAR) compartilham o mesmo stream de velas mas têm parâmetros de aceleração e máximo independentes.
Condições de entrada
Comprado: a MA Fast está acima de Normal e Slow, enquanto ambos os valores SAR estão abaixo do fechamento da vela.
Vendido: a MA Fast está abaixo de Normal e Slow, enquanto ambos os valores SAR estão acima do fechamento da vela.
Quando um sinal de reversão aparece, a estratégia fecha qualquer exposição oposta e muda de direção em uma única ordem a mercado.
Controles de risco
Níveis fixos de stop-loss e take-profit são expressos em pips (múltiplos do passo de preço do instrumento). São avaliados em velas concluídas.
Trailing stop opcional: uma vez habilitado, o stop segue o preço de fechamento a uma distância configurável e avança apenas após mover-se pelo passo de trailing especificado.
Os volumes são ajustados às configurações VolumeStep, MinVolume e MaxVolume do instrumento antes de enviar as ordens.
Parâmetros
Nome
Tipo
Padrão
Descrição
Volume
decimal
0.1
Tamanho base da ordem. Automaticamente aumentado para cobrir uma posição oposta ao mudar de direção.
StopLossPips
decimal
50
Distância do stop protetor em pips. Definir como 0 para desabilitar.
TakeProfitPips
decimal
50
Distância da meta de lucro em pips. Definir como 0 para desabilitar.
UseTrailing
bool
true
Habilita o gerenciamento dinâmico de trailing stop.
TrailingStopPips
decimal
25
Distância entre o preço e o trailing stop, em pips.
TrailingStepPips
decimal
5
Movimento favorável mínimo (pips) antes do trailing stop avançar.
CandleType
DataType
TimeFrameCandle 15m
Série de velas usada para todos os cálculos.
FastMaPeriod
int
10
Período da média móvel ponderada rápida.
FastMaShift
int
0
Número de barras concluídas para deslocar a MA rápida para trás.
NormalMaPeriod
int
30
Período da média móvel ponderada normal.
NormalMaShift
int
3
Número de barras concluídas para deslocar a MA normal para trás.
SlowMaPeriod
int
60
Período da média móvel ponderada lenta.
SlowMaShift
int
6
Número de barras concluídas para deslocar a MA lenta para trás.
FastSarStep
decimal
0.02
Fator de aceleração para o SAR Parabólico rápido.
FastSarMax
decimal
0.2
Aceleração máxima para o SAR Parabólico rápido.
NormalSarStep
decimal
0.02
Fator de aceleração para o SAR Parabólico normal.
NormalSarMax
decimal
0.2
Aceleração máxima para o SAR Parabólico normal.
Notas
As verificações de trailing stop são realizadas no fechamento da vela. Se precisão intrabarra for necessária, combine a estratégia com um componente protetor no nível de tick.
O tamanho do pip equivale ao passo de preço do instrumento quando disponível. Caso contrário, um tick padrão de 0.0001 é assumido para pares FX.
Para consistência com a versão do MetaTrader, todos os sinais de indicadores operam em velas fechadas. Transações pendentes não são preparadas; cada sinal envia uma ordem a mercado imediata.
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;
public class ImaIsarEaStrategy : 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 ImaIsarEaStrategy()
{
_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 ima_isar_ea_strategy(Strategy):
def __init__(self):
super(ima_isar_ea_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(ima_isar_ea_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(ima_isar_ea_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 ima_isar_ea_strategy()