Estrategia Neon de Ondas de Momentum
La estrategia Neon de Ondas de Momentum usa cruces del histograma MACD para operar en ambas direcciones. La estrategia va largo cuando el histograma cruza por encima del nivel de entrada (cero por defecto) y va corto cuando cruza por debajo. Las posiciones se cierran cuando el histograma alcanza los niveles de salida configurados.
Detalles
- Criterios de entrada: El histograma MACD cruza el nivel de entrada.
- Largo/Corto: Ambas direcciones.
- Criterios de salida: El histograma cruza los niveles de salida de largo/corto.
- Stops: No.
- Valores predeterminados:
FastLength= 12SlowLength= 26SignalLength= 20EntryLevel= 0LongExitLevel= 11ShortExitLevel= -9CandleType= 1 minute
- Filtros:
- Categoría: Momentum
- Dirección: Ambos
- Indicadores: MACD
- Stops: No
- Complejidad: Básico
- Marco temporal: Intradía (1m)
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
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>
/// Neon Momentum Waves strategy based on MACD histogram levels.
/// </summary>
public class NeonMomentumWavesStrategy : Strategy
{
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
private readonly StrategyParam<int> _signalLength;
private readonly StrategyParam<decimal> _entryLevel;
private readonly StrategyParam<decimal> _longExitLevel;
private readonly StrategyParam<decimal> _shortExitLevel;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevHist;
private DateTimeOffset _lastSignal = DateTimeOffset.MinValue;
/// <summary>
/// MACD fast EMA length.
/// </summary>
public int FastLength
{
get => _fastLength.Value;
set => _fastLength.Value = value;
}
/// <summary>
/// MACD slow EMA length.
/// </summary>
public int SlowLength
{
get => _slowLength.Value;
set => _slowLength.Value = value;
}
/// <summary>
/// MACD signal smoothing length.
/// </summary>
public int SignalLength
{
get => _signalLength.Value;
set => _signalLength.Value = value;
}
/// <summary>
/// Histogram entry level.
/// </summary>
public decimal EntryLevel
{
get => _entryLevel.Value;
set => _entryLevel.Value = value;
}
/// <summary>
/// Histogram level to exit long position.
/// </summary>
public decimal LongExitLevel
{
get => _longExitLevel.Value;
set => _longExitLevel.Value = value;
}
/// <summary>
/// Histogram level to exit short position.
/// </summary>
public decimal ShortExitLevel
{
get => _shortExitLevel.Value;
set => _shortExitLevel.Value = value;
}
/// <summary>
/// Candle type parameter.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of <see cref="NeonMomentumWavesStrategy"/>.
/// </summary>
public NeonMomentumWavesStrategy()
{
_fastLength = Param(nameof(FastLength), 12)
.SetDisplay("Fast Length", "MACD fast EMA length", "MACD")
;
_slowLength = Param(nameof(SlowLength), 26)
.SetDisplay("Slow Length", "MACD slow EMA length", "MACD")
;
_signalLength = Param(nameof(SignalLength), 20)
.SetDisplay("Signal Length", "MACD signal smoothing", "MACD")
;
_entryLevel = Param(nameof(EntryLevel), 0m)
.SetDisplay("Entry Level", "Histogram entry threshold", "Parameters");
_longExitLevel = Param(nameof(LongExitLevel), 11m)
.SetDisplay("Long Exit Level", "Histogram level to exit longs", "Parameters");
_shortExitLevel = Param(nameof(ShortExitLevel), -9m)
.SetDisplay("Short Exit Level", "Histogram level to exit shorts", "Parameters");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevHist = null;
_lastSignal = DateTimeOffset.MinValue;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var macd = new MovingAverageConvergenceDivergenceSignal
{
Macd =
{
ShortMa = { Length = FastLength },
LongMa = { Length = SlowLength },
},
SignalMa = { Length = SignalLength }
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(macd, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, macd);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var typed = (MovingAverageConvergenceDivergenceSignalValue)macdValue;
if (typed.Macd is not decimal macdLine || typed.Signal is not decimal signal)
return;
var hist = macdLine - signal;
if (_prevHist is null)
{
_prevHist = hist;
return;
}
var prev = _prevHist.Value;
var cooldown = TimeSpan.FromMinutes(360);
if (candle.OpenTime - _lastSignal >= cooldown)
{
if (prev <= EntryLevel && hist > EntryLevel && Position <= 0)
{
BuyMarket();
_lastSignal = candle.OpenTime;
}
else if (prev >= EntryLevel && hist < EntryLevel && Position > 0)
{
SellMarket();
_lastSignal = candle.OpenTime;
}
}
_prevHist = hist;
}
}
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 MovingAverageConvergenceDivergenceSignal
from StockSharp.Algo.Strategies import Strategy
class neon_momentum_waves_strategy(Strategy):
def __init__(self):
super(neon_momentum_waves_strategy, self).__init__()
self._fast_length = self.Param("FastLength", 12) \
.SetDisplay("Fast Length", "MACD fast EMA length", "MACD")
self._slow_length = self.Param("SlowLength", 26) \
.SetDisplay("Slow Length", "MACD slow EMA length", "MACD")
self._signal_length = self.Param("SignalLength", 20) \
.SetDisplay("Signal Length", "MACD signal smoothing", "MACD")
self._entry_level = self.Param("EntryLevel", 0.0) \
.SetDisplay("Entry Level", "Histogram entry threshold", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._prev_hist = None
self._last_signal_ticks = 0
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(neon_momentum_waves_strategy, self).OnReseted()
self._prev_hist = None
self._last_signal_ticks = 0
def OnStarted2(self, time):
super(neon_momentum_waves_strategy, self).OnStarted2(time)
self._prev_hist = None
self._last_signal_ticks = 0
self._macd = MovingAverageConvergenceDivergenceSignal()
self._macd.Macd.ShortMa.Length = self._fast_length.Value
self._macd.Macd.LongMa.Length = self._slow_length.Value
self._macd.SignalMa.Length = self._signal_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(self._macd, self.OnProcess).Start()
def OnProcess(self, candle, macd_value):
if candle.State != CandleStates.Finished:
return
if not self._macd.IsFormed:
return
macd_line = macd_value.Macd
signal_line = macd_value.Signal
if macd_line is None or signal_line is None:
return
hist = float(macd_line) - float(signal_line)
if self._prev_hist is None:
self._prev_hist = hist
return
entry = float(self._entry_level.Value)
cooldown_ticks = TimeSpan.FromMinutes(360).Ticks
current_ticks = candle.OpenTime.Ticks
if current_ticks - self._last_signal_ticks >= cooldown_ticks:
if self._prev_hist <= entry and hist > entry and self.Position <= 0:
self.BuyMarket()
self._last_signal_ticks = current_ticks
elif self._prev_hist >= entry and hist < entry and self.Position > 0:
self.SellMarket()
self._last_signal_ticks = current_ticks
self._prev_hist = hist
def CreateClone(self):
return neon_momentum_waves_strategy()