Color J2JMA StdDev-Strategie
Diese Strategie berechnet die Steigung eines Jurik Moving Average (JMA) und vergleicht sie mit der Standardabweichung der jüngsten Steigungen. Die Idee ist, starke gerichtete Bewegungen zu erfassen, wenn die Steigung ein Vielfaches ihrer jüngsten Volatilität überschreitet.
Eine neue Long-Position wird eröffnet, wenn die JMA-Steigung über den hohen Schwellenwert steigt (K2 × Standardabweichung). Eine neue Short-Position wird eröffnet, wenn die Steigung unter den negativen hohen Schwellenwert fällt. Bestehende Positionen werden geschlossen, wenn die Steigung den entgegengesetzten niedrigen Schwellenwert kreuzt (K1 × Standardabweichung). Stop-Loss- und Take-Profit-Niveaus werden in Punkten vom Einstiegspreis angewendet.
Parameter:
- JMA Length – Periode des Jurik Moving Average.
- StdDev Period – Anzahl der jüngsten Steigungen für die Standardabweichung.
- K1 – Multiplikator für den niedrigen Schwellenwert zum Schließen von Positionen.
- K2 – Multiplikator für den hohen Schwellenwert zum Öffnen von Positionen.
- Candle Type – Zeitrahmen der Kerzen für Berechnungen.
- Stop Loss – Schutz-Stop in Punkten.
- Take Profit – Gewinnziel in Punkten.
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 of Jurik moving average and its standard deviation.
/// Opens a long position when the JMA slope rises above the high threshold.
/// Opens a short position when the JMA slope falls below the negative high threshold.
/// Existing positions are closed when the slope crosses the opposite low threshold.
/// </summary>
public class ColorJ2JmaStdDevStrategy : Strategy
{
private readonly StrategyParam<int> _jmaLength;
private readonly StrategyParam<int> _stdDevPeriod;
private readonly StrategyParam<decimal> _k1;
private readonly StrategyParam<decimal> _k2;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevJma;
private StandardDeviation _stdDev;
public int JmaLength
{
get => _jmaLength.Value;
set => _jmaLength.Value = value;
}
public int StdDevPeriod
{
get => _stdDevPeriod.Value;
set => _stdDevPeriod.Value = value;
}
public decimal K1
{
get => _k1.Value;
set => _k1.Value = value;
}
public decimal K2
{
get => _k2.Value;
set => _k2.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public ColorJ2JmaStdDevStrategy()
{
_jmaLength = Param(nameof(JmaLength), 5)
.SetDisplay("JMA Length", "Period of JMA", "Parameters")
.SetOptimize(3, 20, 1);
_stdDevPeriod = Param(nameof(StdDevPeriod), 9)
.SetDisplay("StdDev Period", "Period of standard deviation", "Parameters")
.SetOptimize(5, 20, 1);
_k1 = Param(nameof(K1), 0.5m)
.SetDisplay("K1", "First threshold multiplier (close)", "Parameters")
.SetOptimize(0.3m, 2m, 0.3m);
_k2 = Param(nameof(K2), 1.0m)
.SetDisplay("K2", "Second threshold multiplier (entry)", "Parameters")
.SetOptimize(0.5m, 3m, 0.5m);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "Parameters");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevJma = null;
_stdDev = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevJma = null;
var jma = new JurikMovingAverage { Length = JmaLength };
_stdDev = new StandardDeviation { Length = StdDevPeriod };
Indicators.Add(_stdDev);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(jma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, jma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal jmaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevJma is not decimal prev)
{
_prevJma = jmaValue;
return;
}
var diff = jmaValue - prev;
_prevJma = jmaValue;
// Process diff through StdDev manually with IsFinal = true
var stdResult = _stdDev.Process(new DecimalIndicatorValue(_stdDev, diff, candle.ServerTime) { IsFinal = true });
if (!_stdDev.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var stDev = stdResult.GetValue<decimal>();
if (stDev == 0)
return;
var lowThreshold = K1 * stDev;
var highThreshold = K2 * stDev;
// Close existing long when slope turns strongly down
if (Position > 0 && diff < -lowThreshold)
{
SellMarket();
return;
}
// Close existing short when slope turns strongly up
if (Position < 0 && diff > lowThreshold)
{
BuyMarket();
return;
}
// Open new long on strong positive slope
if (Position <= 0 && diff > highThreshold)
{
BuyMarket();
}
// Open new short on strong negative slope
else if (Position >= 0 && diff < -highThreshold)
{
SellMarket();
}
}
}
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, StandardDeviation
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class color_j2_jma_std_dev_strategy(Strategy):
def __init__(self):
super(color_j2_jma_std_dev_strategy, self).__init__()
self._jma_length = self.Param("JmaLength", 5) \
.SetDisplay("JMA Length", "Period of JMA", "Parameters")
self._std_dev_period = self.Param("StdDevPeriod", 9) \
.SetDisplay("StdDev Period", "Period of standard deviation", "Parameters")
self._k1 = self.Param("K1", 0.5) \
.SetDisplay("K1", "First threshold multiplier (close)", "Parameters")
self._k2 = self.Param("K2", 1.0) \
.SetDisplay("K2", "Second threshold multiplier (entry)", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe", "Parameters")
self._prev_jma = None
self._std_dev = None
@property
def jma_length(self):
return self._jma_length.Value
@property
def std_dev_period(self):
return self._std_dev_period.Value
@property
def k1(self):
return self._k1.Value
@property
def k2(self):
return self._k2.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(color_j2_jma_std_dev_strategy, self).OnReseted()
self._prev_jma = None
self._std_dev = None
def OnStarted2(self, time):
super(color_j2_jma_std_dev_strategy, self).OnStarted2(time)
self._prev_jma = None
jma = JurikMovingAverage()
jma.Length = self.jma_length
self._std_dev = StandardDeviation()
self._std_dev.Length = self.std_dev_period
self.Indicators.Add(self._std_dev)
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)
if self._prev_jma is None:
self._prev_jma = jma_value
return
diff = jma_value - self._prev_jma
self._prev_jma = jma_value
std_result = process_float(self._std_dev, diff, candle.ServerTime, True)
if not self._std_dev.IsFormed:
return
st_dev = float(std_result)
if st_dev == 0:
return
k1_val = float(self.k1)
k2_val = float(self.k2)
low_threshold = k1_val * st_dev
high_threshold = k2_val * st_dev
if self.Position > 0 and diff < -low_threshold:
self.SellMarket()
return
if self.Position < 0 and diff > low_threshold:
self.BuyMarket()
return
if self.Position <= 0 and diff > high_threshold:
self.BuyMarket()
elif self.Position >= 0 and diff < -high_threshold:
self.SellMarket()
def CreateClone(self):
return color_j2_jma_std_dev_strategy()