Esta estrategia utiliza la dirección de la pendiente de una Media Móvil Jurik (JMA) para generar operaciones. La JMA aproxima el indicador "ColorJFatl_Digit" del experto MQL5 original. Se abre una posición larga cuando la JMA se vuelve ascendente, mientras que se abre una posición corta cuando la JMA se vuelve descendente. Las posiciones opuestas se cierran cuando la pendiente se revierte.
El sistema opera en ambas direcciones y no emplea stops duros por defecto. Es adecuado para instrumentos donde los cambios de tendencia pueden capturarse con una media móvil adaptativa suavizada.
Detalles
Criterios de entrada:
Largo: La pendiente de la JMA cambia de negativa a positiva.
Corto: La pendiente de la JMA cambia de positiva a negativa.
Largo/Corto: Ambos lados.
Criterios de salida:
Largo: La pendiente de la JMA se vuelve negativa.
Corto: La pendiente de la JMA se vuelve positiva.
Stops: Ninguno por defecto.
Valores predeterminados:
JMA Length = 5
Timeframe = 4 horas
Filtros:
Categoría: Seguimiento de tendencia
Dirección: Ambos
Indicadores: Único
Stops: No
Complejidad: Simple
Marco temporal: Medio plazo
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>
/// Strategy based on the slope changes of Jurik Moving Average (JMA).
/// Opens long when JMA turns up, opens short when JMA turns down.
/// </summary>
public class ColorJFatlDigitStrategy : Strategy
{
private readonly StrategyParam<int> _jmaLength;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevJma;
private decimal? _prevSlope;
public int JmaLength { get => _jmaLength.Value; set => _jmaLength.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ColorJFatlDigitStrategy()
{
_jmaLength = Param(nameof(JmaLength), 5)
.SetGreaterThanZero()
.SetDisplay("JMA Length", "Period for Jurik Moving Average", "Parameters");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe of indicator", "Parameters");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevJma = null;
_prevSlope = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevJma = null;
_prevSlope = null;
var jma = new JurikMovingAverage { Length = JmaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(jma, Process)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, jma);
DrawOwnTrades(area);
}
}
private void Process(ICandleMessage candle, decimal jmaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var slope = _prevJma is decimal prev ? jmaValue - prev : (decimal?)null;
if (slope is decimal s && _prevSlope is decimal ps)
{
// JMA slope turns positive -> buy
if (ps <= 0m && s > 0m && Position <= 0)
BuyMarket();
// JMA slope turns negative -> sell
else if (ps >= 0m && s < 0m && Position >= 0)
SellMarket();
}
_prevSlope = slope;
_prevJma = jmaValue;
}
}
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 JurikMovingAverage
from StockSharp.Algo.Strategies import Strategy
class color_j_fatl_digit_strategy(Strategy):
def __init__(self):
super(color_j_fatl_digit_strategy, self).__init__()
self._jma_length = self.Param("JmaLength", 5) \
.SetDisplay("JMA Length", "Period for Jurik Moving Average", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe of indicator", "Parameters")
self._prev_jma = None
self._prev_slope = None
@property
def jma_length(self):
return self._jma_length.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(color_j_fatl_digit_strategy, self).OnReseted()
self._prev_jma = None
self._prev_slope = None
def OnStarted2(self, time):
super(color_j_fatl_digit_strategy, self).OnStarted2(time)
self._prev_jma = None
self._prev_slope = None
jma = JurikMovingAverage()
jma.Length = self.jma_length
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(jma, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, jma)
self.DrawOwnTrades(area)
def process_candle(self, candle, jma_value):
if candle.State != CandleStates.Finished:
return
jma_value = float(jma_value)
slope = None
if self._prev_jma is not None:
slope = jma_value - self._prev_jma
if slope is not None and self._prev_slope is not None:
if self._prev_slope <= 0 and slope > 0 and self.Position <= 0:
self.BuyMarket()
elif self._prev_slope >= 0 and slope < 0 and self.Position >= 0:
self.SellMarket()
self._prev_slope = slope
self._prev_jma = jma_value
def CreateClone(self):
return color_j_fatl_digit_strategy()