Color J Variation Strategy
Strategy replicating the ColorJVariation Expert Advisor using Jurik Moving Average. It tracks the JMA slope and enters when the direction changes. The strategy supports absolute stop loss and take profit levels.
Details
- Entry Criteria:
- Long:
PrevSlopeDown && JMA turns up - Short:
PrevSlopeUp && JMA turns down
- Long:
- Long/Short: Both
- Exit Criteria:
- Opposite reversal signal
- Stops: Absolute via
StopLossandTakeProfit - Default Values:
JmaPeriod= 12JmaPhase= 100StopLoss= 1000TakeProfit= 2000CandleType= TimeSpan.FromHours(1).TimeFrame()
- Filters:
- Category: Trend reversal
- Direction: Both
- Indicators: Jurik Moving Average
- Stops: Yes
- Complexity: Basic
- Timeframe: Mid-term
- Seasonality: No
- Neural Networks: No
- Divergence: No
- Risk Level: Medium
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 Jurik moving average slope reversals.
/// Buys when JMA turns up, sells when JMA turns down.
/// </summary>
public class ColorJVariationStrategy : Strategy
{
private readonly StrategyParam<int> _jmaPeriod;
private readonly StrategyParam<int> _jmaPhase;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevJma;
private decimal _prevPrevJma;
private int _count;
public int JmaPeriod { get => _jmaPeriod.Value; set => _jmaPeriod.Value = value; }
public int JmaPhase { get => _jmaPhase.Value; set => _jmaPhase.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ColorJVariationStrategy()
{
_jmaPeriod = Param(nameof(JmaPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("JMA Period", "JMA averaging period", "Indicator");
_jmaPhase = Param(nameof(JmaPhase), 100)
.SetDisplay("JMA Phase", "Phase for JMA", "Indicator");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for analysis", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevJma = 0;
_prevPrevJma = 0;
_count = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var jma = new JurikMovingAverage
{
Length = JmaPeriod,
Phase = JmaPhase
};
SubscribeCandles(CandleType)
.Bind(jma, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal jmaValue)
{
if (candle.State != CandleStates.Finished)
return;
_count++;
if (_count < 3)
{
_prevPrevJma = _prevJma;
_prevJma = jmaValue;
return;
}
var turnUp = _prevJma < _prevPrevJma && jmaValue > _prevJma;
var turnDown = _prevJma > _prevPrevJma && jmaValue < _prevJma;
if (turnUp && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (turnDown && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevPrevJma = _prevJma;
_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_variation_strategy(Strategy):
"""
Strategy based on Jurik moving average slope reversals.
Buys when JMA turns up, sells when JMA turns down.
"""
def __init__(self):
super(color_j_variation_strategy, self).__init__()
self._jma_period = self.Param("JmaPeriod", 12) \
.SetDisplay("JMA Period", "JMA averaging period", "Indicator")
self._jma_phase = self.Param("JmaPhase", 100) \
.SetDisplay("JMA Phase", "Phase for JMA", "Indicator")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for analysis", "General")
self._prev_jma = 0.0
self._prev_prev_jma = 0.0
self._count = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(color_j_variation_strategy, self).OnReseted()
self._prev_jma = 0.0
self._prev_prev_jma = 0.0
self._count = 0
def OnStarted2(self, time):
super(color_j_variation_strategy, self).OnStarted2(time)
jma = JurikMovingAverage()
jma.Length = self._jma_period.Value
jma.Phase = self._jma_phase.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(jma, self.on_process).Start()
def on_process(self, candle, jma_val):
if candle.State != CandleStates.Finished:
return
self._count += 1
if self._count < 3:
self._prev_prev_jma = self._prev_jma
self._prev_jma = jma_val
return
turn_up = self._prev_jma < self._prev_prev_jma and jma_val > self._prev_jma
turn_down = self._prev_jma > self._prev_prev_jma and jma_val < self._prev_jma
if turn_up and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif turn_down and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_prev_jma = self._prev_jma
self._prev_jma = jma_val
def CreateClone(self):
return color_j_variation_strategy()