A estratégia opera com base em um Average Directional Index (ADX) de suavização dupla. Compara as linhas +DI e -DI suavizadas para detectar mudanças de tendência. Quando a linha +DI suavizada cruza acima da linha -DI suavizada, a estratégia entra em uma posição comprada. Quando a linha +DI suavizada cruza abaixo da linha -DI suavizada, abre uma posição vendida.
Como Funciona
Utiliza um indicador ADX com período configurável.
Aplica duas passagens de suavização exponencial controladas pelos parâmetros Alpha1 e Alpha2.
Um sinal de compra ocorre quando o +DI suavizado anterior estava abaixo do -DI suavizado e o +DI suavizado atual está acima.
Um sinal de venda ocorre no cruzamento oposto.
Parâmetros opcionais permitem desabilitar operações compradas ou vendidas e controlar se as posições existentes podem ser fechadas quando um sinal oposto aparece.
O gerenciamento de risco integrado define níveis de stop-loss e take-profit em pontos.
Parâmetros
Nome
Descrição
AdxPeriod
Período para o cálculo do ADX.
Alpha1
Primeiro coeficiente de suavização (0-1).
Alpha2
Segundo coeficiente de suavização (0-1).
StopLoss
Stop-loss em pontos.
TakeProfit
Take-profit em pontos.
AllowBuy
Habilitar entradas compradas.
AllowSell
Habilitar entradas vendidas.
AllowCloseBuy
Permitir fechar posições compradas em sinais de venda.
AllowCloseSell
Permitir fechar posições vendidas em sinais de compra.
CandleType
Período utilizado para o indicador.
Notas
Apenas velas finalizadas são processadas.
A estratégia usa a API de alto nível com vinculação de indicadores.
Stop-loss e take-profit são gerenciados via StartProtection.
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>
/// Smoothed EMA crossover strategy (ADX-inspired directional cross concept).
/// Buys when fast EMA crosses above slow EMA, sells when below.
/// </summary>
public class AdxSmoothedCrossStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevFast;
private decimal? _prevSlow;
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 AdxSmoothedCrossStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 25)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = null;
_prevSlow = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
SubscribeCandles(CandleType)
.Bind(fast, slow, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevFast is null || _prevSlow is null)
{
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
var crossUp = _prevFast <= _prevSlow && fastValue > slowValue;
var crossDown = _prevFast >= _prevSlow && fastValue < slowValue;
if (crossUp && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (crossDown && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_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, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class adx_smoothed_cross_strategy(Strategy):
def __init__(self):
super(adx_smoothed_cross_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 10) \
.SetDisplay("Fast Period", "Fast EMA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 25) \
.SetDisplay("Slow Period", "Slow EMA period", "Indicator")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle type", "General")
self._prev_fast = None
self._prev_slow = None
@property
def FastPeriod(self):
return self._fast_period.Value
@FastPeriod.setter
def FastPeriod(self, value):
self._fast_period.Value = value
@property
def SlowPeriod(self):
return self._slow_period.Value
@SlowPeriod.setter
def SlowPeriod(self, value):
self._slow_period.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(adx_smoothed_cross_strategy, self).OnStarted2(time)
fast = ExponentialMovingAverage()
fast.Length = self.FastPeriod
slow = ExponentialMovingAverage()
slow.Length = self.SlowPeriod
self.SubscribeCandles(self.CandleType) \
.Bind(fast, slow, self.ProcessCandle) \
.Start()
def ProcessCandle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
cross_up = self._prev_fast <= self._prev_slow and fast_val > slow_val
cross_down = self._prev_fast >= self._prev_slow and fast_val < slow_val
if cross_up and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif cross_down and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def OnReseted(self):
super(adx_smoothed_cross_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def CreateClone(self):
return adx_smoothed_cross_strategy()