Стратегия ColorJFatl StDev
Стратегия представляет собой перенос советника ColorJFatl_StDev из MQL5 на StockSharp API. В ней используется усреднение Jurik (JMA) и каналы стандартного отклонения для формирования торговых сигналов.
Логика стратегии
- Расчёт JMA по ценам закрытия.
- Вычисление стандартного отклонения за заданный период.
- Построение двух наборов динамических каналов с коэффициентами
K1иK2:upper1 = JMA + K1 * StdDevupper2 = JMA + K2 * StdDevlower1 = JMA - K1 * StdDevlower2 = JMA - K2 * StdDev
- В зависимости от выбранного режима сигнала осуществляется открытие или закрытие позиций:
- Point – срабатывает при пересечении ценой каналов.
- Direct – основан на точках разворота линии JMA.
- Without – отключает соответствующий сигнал.
Параметры
| Имя | Описание |
|---|---|
CandleTimeFrame |
Таймфрейм свечей |
JmaLength |
Период JMA |
JmaPhase |
Фаза JMA |
StdPeriod |
Период стандартного отклонения |
K1 |
Первый множитель отклонения |
K2 |
Второй множитель отклонения |
BuyOpenMode |
Режим открытия длинных позиций |
SellOpenMode |
Режим открытия коротких позиций |
BuyCloseMode |
Режим закрытия длинных позиций |
SellCloseMode |
Режим закрытия коротких позиций |
Использование
Стратегия подписывается на свечи выбранного таймфрейма, обрабатывает значения JMA и стандартного отклонения и автоматически подаёт рыночные заявки согласно заданным режимам. Реализация предназначена для демонстрационных целей и может быть расширена дополнительными механизмами управления рисками.
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 and standard deviation bands.
/// Opens and closes positions according to signal modes.
/// </summary>
public class ColorJFatlStDevStrategy : Strategy
{
public enum SignalModes
{
Point,
Direct,
Without
}
private readonly StrategyParam<int> _jmaLength;
private readonly StrategyParam<int> _jmaPhase;
private readonly StrategyParam<int> _stdPeriod;
private readonly StrategyParam<decimal> _k1;
private readonly StrategyParam<decimal> _k2;
private readonly StrategyParam<SignalModes> _buyOpenMode;
private readonly StrategyParam<SignalModes> _sellOpenMode;
private readonly StrategyParam<SignalModes> _buyCloseMode;
private readonly StrategyParam<SignalModes> _sellCloseMode;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevJma;
private decimal? _prevPrevJma;
public int JmaLength { get => _jmaLength.Value; set => _jmaLength.Value = value; }
public int JmaPhase { get => _jmaPhase.Value; set => _jmaPhase.Value = value; }
public int StdPeriod { get => _stdPeriod.Value; set => _stdPeriod.Value = value; }
public decimal K1 { get => _k1.Value; set => _k1.Value = value; }
public decimal K2 { get => _k2.Value; set => _k2.Value = value; }
public SignalModes BuyOpenMode { get => _buyOpenMode.Value; set => _buyOpenMode.Value = value; }
public SignalModes SellOpenMode { get => _sellOpenMode.Value; set => _sellOpenMode.Value = value; }
public SignalModes BuyCloseMode { get => _buyCloseMode.Value; set => _buyCloseMode.Value = value; }
public SignalModes SellCloseMode { get => _sellCloseMode.Value; set => _sellCloseMode.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ColorJFatlStDevStrategy()
{
_jmaLength = Param(nameof(JmaLength), 5)
.SetDisplay("JMA Length", "JMA period", "Indicators");
_jmaPhase = Param(nameof(JmaPhase), -100)
.SetDisplay("JMA Phase", "JMA phase", "Indicators");
_stdPeriod = Param(nameof(StdPeriod), 9)
.SetDisplay("Std Period", "Standard deviation period", "Indicators");
_k1 = Param(nameof(K1), 0.5m)
.SetDisplay("K1", "First deviation multiplier", "Parameters");
_k2 = Param(nameof(K2), 1.0m)
.SetDisplay("K2", "Second deviation multiplier", "Parameters");
_buyOpenMode = Param(nameof(BuyOpenMode), SignalModes.Point)
.SetDisplay("Buy Open", "Mode for opening long", "Signals");
_sellOpenMode = Param(nameof(SellOpenMode), SignalModes.Point)
.SetDisplay("Sell Open", "Mode for opening short", "Signals");
_buyCloseMode = Param(nameof(BuyCloseMode), SignalModes.Point)
.SetDisplay("Buy Close", "Mode for closing long", "Signals");
_sellCloseMode = Param(nameof(SellCloseMode), SignalModes.Point)
.SetDisplay("Sell Close", "Mode for closing short", "Signals");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevJma = null;
_prevPrevJma = null;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevJma = null;
_prevPrevJma = null;
var jma = new JurikMovingAverage { Length = JmaLength, Phase = JmaPhase };
var std = new StandardDeviation { Length = StdPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(jma, std, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, jma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal jmaValue, decimal stdValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_prevJma is null || _prevPrevJma is null)
{
_prevPrevJma = _prevJma;
_prevJma = jmaValue;
return;
}
if (stdValue == 0)
{
_prevPrevJma = _prevJma;
_prevJma = jmaValue;
return;
}
var upper1 = jmaValue + K1 * stdValue;
var upper2 = jmaValue + K2 * stdValue;
var lower1 = jmaValue - K1 * stdValue;
var lower2 = jmaValue - K2 * stdValue;
var buyOpen = false;
var sellOpen = false;
var buyClose = false;
var sellClose = false;
switch (BuyOpenMode)
{
case SignalModes.Point:
buyOpen = candle.ClosePrice > upper1 || candle.ClosePrice > upper2;
break;
case SignalModes.Direct:
buyOpen = jmaValue > _prevJma && _prevJma < _prevPrevJma;
break;
}
switch (SellOpenMode)
{
case SignalModes.Point:
sellOpen = candle.ClosePrice < lower1 || candle.ClosePrice < lower2;
break;
case SignalModes.Direct:
sellOpen = jmaValue < _prevJma && _prevJma > _prevPrevJma;
break;
}
switch (BuyCloseMode)
{
case SignalModes.Point:
buyClose = candle.ClosePrice < lower1 || candle.ClosePrice < lower2;
break;
case SignalModes.Direct:
buyClose = jmaValue > _prevJma;
break;
}
switch (SellCloseMode)
{
case SignalModes.Point:
sellClose = candle.ClosePrice > upper1 || candle.ClosePrice > upper2;
break;
case SignalModes.Direct:
sellClose = jmaValue < _prevJma;
break;
}
if (buyClose && Position > 0)
SellMarket();
else if (sellClose && Position < 0)
BuyMarket();
else if (buyOpen && Position <= 0)
BuyMarket();
else if (sellOpen && Position >= 0)
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, StandardDeviation
from StockSharp.Algo.Strategies import Strategy
SIGNAL_POINT = 0
SIGNAL_DIRECT = 1
SIGNAL_WITHOUT = 2
class color_j_fatl_st_dev_strategy(Strategy):
def __init__(self):
super(color_j_fatl_st_dev_strategy, self).__init__()
self._jma_length = self.Param("JmaLength", 5) \
.SetDisplay("JMA Length", "JMA period", "Indicators")
self._jma_phase = self.Param("JmaPhase", -100) \
.SetDisplay("JMA Phase", "JMA phase", "Indicators")
self._std_period = self.Param("StdPeriod", 9) \
.SetDisplay("Std Period", "Standard deviation period", "Indicators")
self._k1 = self.Param("K1", 0.5) \
.SetDisplay("K1", "First deviation multiplier", "Parameters")
self._k2 = self.Param("K2", 1.0) \
.SetDisplay("K2", "Second deviation multiplier", "Parameters")
self._buy_open_mode = self.Param("BuyOpenMode", SIGNAL_POINT) \
.SetDisplay("Buy Open", "Mode for opening long", "Signals")
self._sell_open_mode = self.Param("SellOpenMode", SIGNAL_POINT) \
.SetDisplay("Sell Open", "Mode for opening short", "Signals")
self._buy_close_mode = self.Param("BuyCloseMode", SIGNAL_POINT) \
.SetDisplay("Buy Close", "Mode for closing long", "Signals")
self._sell_close_mode = self.Param("SellCloseMode", SIGNAL_POINT) \
.SetDisplay("Sell Close", "Mode for closing short", "Signals")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._prev_jma = None
self._prev_prev_jma = None
@property
def jma_length(self):
return self._jma_length.Value
@property
def jma_phase(self):
return self._jma_phase.Value
@property
def std_period(self):
return self._std_period.Value
@property
def k1(self):
return self._k1.Value
@property
def k2(self):
return self._k2.Value
@property
def buy_open_mode(self):
return self._buy_open_mode.Value
@property
def sell_open_mode(self):
return self._sell_open_mode.Value
@property
def buy_close_mode(self):
return self._buy_close_mode.Value
@property
def sell_close_mode(self):
return self._sell_close_mode.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(color_j_fatl_st_dev_strategy, self).OnReseted()
self._prev_jma = None
self._prev_prev_jma = None
def OnStarted2(self, time):
super(color_j_fatl_st_dev_strategy, self).OnStarted2(time)
self._prev_jma = None
self._prev_prev_jma = None
jma = JurikMovingAverage()
jma.Length = self.jma_length
jma.Phase = self.jma_phase
std = StandardDeviation()
std.Length = self.std_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(jma, std, 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, std_value):
if candle.State != CandleStates.Finished:
return
jma_value = float(jma_value)
std_value = float(std_value)
if self._prev_jma is None or self._prev_prev_jma is None:
self._prev_prev_jma = self._prev_jma
self._prev_jma = jma_value
return
if std_value == 0:
self._prev_prev_jma = self._prev_jma
self._prev_jma = jma_value
return
k1_val = float(self.k1)
k2_val = float(self.k2)
upper1 = jma_value + k1_val * std_value
upper2 = jma_value + k2_val * std_value
lower1 = jma_value - k1_val * std_value
lower2 = jma_value - k2_val * std_value
close_price = float(candle.ClosePrice)
buy_open = False
sell_open = False
buy_close = False
sell_close = False
bom = int(self.buy_open_mode)
som = int(self.sell_open_mode)
bcm = int(self.buy_close_mode)
scm = int(self.sell_close_mode)
if bom == SIGNAL_POINT:
buy_open = close_price > upper1 or close_price > upper2
elif bom == SIGNAL_DIRECT:
buy_open = jma_value > self._prev_jma and self._prev_jma < self._prev_prev_jma
if som == SIGNAL_POINT:
sell_open = close_price < lower1 or close_price < lower2
elif som == SIGNAL_DIRECT:
sell_open = jma_value < self._prev_jma and self._prev_jma > self._prev_prev_jma
if bcm == SIGNAL_POINT:
buy_close = close_price < lower1 or close_price < lower2
elif bcm == SIGNAL_DIRECT:
buy_close = jma_value > self._prev_jma
if scm == SIGNAL_POINT:
sell_close = close_price > upper1 or close_price > upper2
elif scm == SIGNAL_DIRECT:
sell_close = jma_value < self._prev_jma
if buy_close and self.Position > 0:
self.SellMarket()
elif sell_close and self.Position < 0:
self.BuyMarket()
elif buy_open and self.Position <= 0:
self.BuyMarket()
elif sell_open and self.Position >= 0:
self.SellMarket()
self._prev_prev_jma = self._prev_jma
self._prev_jma = jma_value
def CreateClone(self):
return color_j_fatl_st_dev_strategy()