Estratégia de Cruzamento de Três EMA
A estratégia Three EMA Cross combina um clássico cruzamento de média móvel rápida/lenta com um filtro de tendência mais longo. Após a EMA rápida cruzar acima da EMA lenta, a estratégia aguarda um pullback para a média rápida enquanto o preço de fechamento permanece acima de uma EMA de tendência mais ampla. Esta configuração tenta capturar movimentos de continuação após uma breve correção dentro da tendência prevalente.
As posições são encerradas quando o momentum se esvai e a EMA rápida cai novamente abaixo da EMA lenta. Um stop loss baseado em porcentagem protege a posição se o preço se mover contra a operação. A técnica funciona bem em mercados com tendências persistentes e tende a evitar ranges laterais.
Detalhes
- Critérios de entrada:
- Cruzamento recente da EMA rápida acima da EMA lenta dentro das últimas N barras.
- Fechamento atual ≥ EMA rápida e mínimo de sessão ≤ EMA rápida.
- EMA de tendência ≤ fechamento atual.
- Comprado/Vendido: Somente comprado.
- Critérios de saída:
- EMA rápida cai abaixo da EMA lenta.
- Stops: Stop loss em
stop_loss_percentdo preço de entrada. - Valores padrão:
FastEmaLength= 10SlowEmaLength= 20TrendEmaLength= 100StopLossPercent= 2.0CrossBackBars= 10
- Filtros:
- Categoria: Seguidor de tendência
- Direção: Comprado
- Indicadores: EMA
- Stops: Sim
- Complexidade: Médio
- Período: Qualquer
- Sazonalidade: Não
- Redes neurais: Não
- Divergência: Não
- Nível de risco: Médio
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// Three EMA Cross Strategy.
/// Uses fast/slow EMA crossover with trend EMA filter.
/// Buys when fast EMA crosses above slow EMA while above trend EMA.
/// Sells when fast EMA crosses below slow EMA while below trend EMA.
/// </summary>
public class ThreeEmaCrossStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastEmaLength;
private readonly StrategyParam<int> _slowEmaLength;
private readonly StrategyParam<int> _trendEmaLength;
private readonly StrategyParam<int> _cooldownBars;
private ExponentialMovingAverage _fastEma;
private ExponentialMovingAverage _slowEma;
private ExponentialMovingAverage _trendEma;
private decimal _prevFastEma;
private decimal _prevSlowEma;
private int _cooldownRemaining;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastEmaLength
{
get => _fastEmaLength.Value;
set => _fastEmaLength.Value = value;
}
public int SlowEmaLength
{
get => _slowEmaLength.Value;
set => _slowEmaLength.Value = value;
}
public int TrendEmaLength
{
get => _trendEmaLength.Value;
set => _trendEmaLength.Value = value;
}
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
public ThreeEmaCrossStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_fastEmaLength = Param(nameof(FastEmaLength), 10)
.SetGreaterThanZero()
.SetDisplay("Fast EMA", "Fast EMA length", "Moving Averages");
_slowEmaLength = Param(nameof(SlowEmaLength), 20)
.SetGreaterThanZero()
.SetDisplay("Slow EMA", "Slow EMA length", "Moving Averages");
_trendEmaLength = Param(nameof(TrendEmaLength), 100)
.SetGreaterThanZero()
.SetDisplay("Trend EMA", "Trend EMA length", "Moving Averages");
_cooldownBars = Param(nameof(CooldownBars), 10)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_fastEma = null;
_slowEma = null;
_trendEma = null;
_prevFastEma = 0;
_prevSlowEma = 0;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fastEma = new ExponentialMovingAverage { Length = FastEmaLength };
_slowEma = new ExponentialMovingAverage { Length = SlowEmaLength };
_trendEma = new ExponentialMovingAverage { Length = TrendEmaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_fastEma, _slowEma, _trendEma, OnProcess)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _fastEma);
DrawIndicator(area, _slowEma);
DrawIndicator(area, _trendEma);
DrawOwnTrades(area);
}
}
private void OnProcess(ICandleMessage candle, decimal fastEma, decimal slowEma, decimal trendEma)
{
if (candle.State != CandleStates.Finished)
return;
if (!_fastEma.IsFormed || !_slowEma.IsFormed || !_trendEma.IsFormed)
{
_prevFastEma = fastEma;
_prevSlowEma = slowEma;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevFastEma = fastEma;
_prevSlowEma = slowEma;
return;
}
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevFastEma = fastEma;
_prevSlowEma = slowEma;
return;
}
if (_prevFastEma == 0 || _prevSlowEma == 0)
{
_prevFastEma = fastEma;
_prevSlowEma = slowEma;
return;
}
// EMA crossovers
var crossUp = fastEma > slowEma && _prevFastEma <= _prevSlowEma;
var crossDown = fastEma < slowEma && _prevFastEma >= _prevSlowEma;
// Buy: fast crosses above slow + price above trend EMA
if (crossUp && candle.ClosePrice > trendEma && Position <= 0)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
BuyMarket(Volume);
_cooldownRemaining = CooldownBars;
}
// Sell: fast crosses below slow + price below trend EMA
else if (crossDown && candle.ClosePrice < trendEma && Position >= 0)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
SellMarket(Volume);
_cooldownRemaining = CooldownBars;
}
// Exit long: fast crosses below slow
else if (Position > 0 && crossDown)
{
SellMarket(Math.Abs(Position));
_cooldownRemaining = CooldownBars;
}
// Exit short: fast crosses above slow
else if (Position < 0 && crossUp)
{
BuyMarket(Math.Abs(Position));
_cooldownRemaining = CooldownBars;
}
_prevFastEma = fastEma;
_prevSlowEma = slowEma;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class three_ema_cross_strategy(Strategy):
"""Three EMA Cross Strategy."""
def __init__(self):
super(three_ema_cross_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._fast_ema_length = self.Param("FastEmaLength", 10) \
.SetDisplay("Fast EMA", "Fast EMA length", "Moving Averages")
self._slow_ema_length = self.Param("SlowEmaLength", 20) \
.SetDisplay("Slow EMA", "Slow EMA length", "Moving Averages")
self._trend_ema_length = self.Param("TrendEmaLength", 100) \
.SetDisplay("Trend EMA", "Trend EMA length", "Moving Averages")
self._cooldown_bars = self.Param("CooldownBars", 10) \
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "Risk")
self._fast_ema = None
self._slow_ema = None
self._trend_ema = None
self._prev_fast_ema = 0.0
self._prev_slow_ema = 0.0
self._cooldown_remaining = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(three_ema_cross_strategy, self).OnReseted()
self._fast_ema = None
self._slow_ema = None
self._trend_ema = None
self._prev_fast_ema = 0.0
self._prev_slow_ema = 0.0
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(three_ema_cross_strategy, self).OnStarted2(time)
self._fast_ema = ExponentialMovingAverage()
self._fast_ema.Length = int(self._fast_ema_length.Value)
self._slow_ema = ExponentialMovingAverage()
self._slow_ema.Length = int(self._slow_ema_length.Value)
self._trend_ema = ExponentialMovingAverage()
self._trend_ema.Length = int(self._trend_ema_length.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._fast_ema, self._slow_ema, self._trend_ema, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._fast_ema)
self.DrawIndicator(area, self._slow_ema)
self.DrawIndicator(area, self._trend_ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_ema, slow_ema, trend_ema):
if candle.State != CandleStates.Finished:
return
if not self._fast_ema.IsFormed or not self._slow_ema.IsFormed or not self._trend_ema.IsFormed:
self._prev_fast_ema = float(fast_ema)
self._prev_slow_ema = float(slow_ema)
return
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_fast_ema = float(fast_ema)
self._prev_slow_ema = float(slow_ema)
return
fe = float(fast_ema)
se = float(slow_ema)
te = float(trend_ema)
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
self._prev_fast_ema = fe
self._prev_slow_ema = se
return
if self._prev_fast_ema == 0.0 or self._prev_slow_ema == 0.0:
self._prev_fast_ema = fe
self._prev_slow_ema = se
return
close = float(candle.ClosePrice)
cooldown = int(self._cooldown_bars.Value)
cross_up = fe > se and self._prev_fast_ema <= self._prev_slow_ema
cross_down = fe < se and self._prev_fast_ema >= self._prev_slow_ema
if cross_up and close > te and self.Position <= 0:
if self.Position < 0:
self.BuyMarket(Math.Abs(self.Position))
self.BuyMarket(self.Volume)
self._cooldown_remaining = cooldown
elif cross_down and close < te and self.Position >= 0:
if self.Position > 0:
self.SellMarket(Math.Abs(self.Position))
self.SellMarket(self.Volume)
self._cooldown_remaining = cooldown
elif self.Position > 0 and cross_down:
self.SellMarket(Math.Abs(self.Position))
self._cooldown_remaining = cooldown
elif self.Position < 0 and cross_up:
self.BuyMarket(Math.Abs(self.Position))
self._cooldown_remaining = cooldown
self._prev_fast_ema = fe
self._prev_slow_ema = se
def CreateClone(self):
return three_ema_cross_strategy()