Стратегия JMA Candle Sign
Стратегия использует две скользящие средние Jurik (JMA), рассчитанные по ценам открытия и закрытия свечи. Когда JMA по цене открытия пересекает JMA по цене закрытия снизу вверх, формируется сигнал на покупку. Если JMA по цене открытия пересекает JMA по цене закрытия сверху вниз, появляется сигнал на продажу.
По умолчанию используется таймфрейм H4 и период JMA равный 7. Уровни стоп-лосса и тейк-профита задаются в пунктах и применяются встроенной системой управления рисками. Стратегия работает только с завершёнными свечами и удерживает не более одной позиции.
Параметры
- JMA Length – период обеих JMA.
- Candle Type – таймфрейм обрабатываемых свечей.
- Take Profit – цель прибыли в пунктах.
- Stop Loss – максимально допустимый убыток в пунктах.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy using Jurik moving averages of open and close prices.
/// Goes long when JMA(close) crosses above JMA(open).
/// Goes short when JMA(close) crosses below JMA(open).
/// </summary>
public class JmaCandleSignStrategy : Strategy
{
private readonly StrategyParam<int> _jmaLength;
private readonly StrategyParam<DataType> _candleType;
private JurikMovingAverage _jmaOpen;
private JurikMovingAverage _jmaClose;
private decimal _prevOpenJma;
private decimal _prevCloseJma;
private bool _hasPrev;
public int JmaLength
{
get => _jmaLength.Value;
set => _jmaLength.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public JmaCandleSignStrategy()
{
_jmaLength = Param(nameof(JmaLength), 7)
.SetDisplay("JMA Length", "Period for Jurik moving averages", "Parameters");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for strategy", "Parameters");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_jmaOpen = default;
_jmaClose = default;
_prevOpenJma = 0;
_prevCloseJma = 0;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_jmaOpen = new JurikMovingAverage { Length = JmaLength };
_jmaClose = new JurikMovingAverage { Length = JmaLength };
_prevOpenJma = 0;
_prevCloseJma = 0;
_hasPrev = false;
Indicators.Add(_jmaOpen);
Indicators.Add(_jmaClose);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var openResult = _jmaOpen.Process(new DecimalIndicatorValue(_jmaOpen, candle.OpenPrice, candle.OpenTime) { IsFinal = true });
var closeResult = _jmaClose.Process(new DecimalIndicatorValue(_jmaClose, candle.ClosePrice, candle.OpenTime) { IsFinal = true });
if (!openResult.IsFormed || !closeResult.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var openJma = openResult.ToDecimal();
var closeJma = closeResult.ToDecimal();
if (!_hasPrev)
{
_prevOpenJma = openJma;
_prevCloseJma = closeJma;
_hasPrev = true;
return;
}
// JMA(close) crosses above JMA(open) - bullish
if (_prevCloseJma <= _prevOpenJma && closeJma > openJma && Position <= 0)
{
BuyMarket();
}
// JMA(close) crosses below JMA(open) - bearish
else if (_prevCloseJma >= _prevOpenJma && closeJma < openJma && Position >= 0)
{
SellMarket();
}
_prevOpenJma = openJma;
_prevCloseJma = closeJma;
}
}
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
from indicator_extensions import *
class jma_candle_sign_strategy(Strategy):
def __init__(self):
super(jma_candle_sign_strategy, self).__init__()
self._jma_length = self.Param("JmaLength", 7) \
.SetDisplay("JMA Length", "Period for Jurik moving averages", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for strategy", "Parameters")
self._jma_open = None
self._jma_close = None
self._prev_open_jma = 0.0
self._prev_close_jma = 0.0
self._has_prev = False
@property
def jma_length(self):
return self._jma_length.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(jma_candle_sign_strategy, self).OnReseted()
self._jma_open = None
self._jma_close = None
self._prev_open_jma = 0.0
self._prev_close_jma = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(jma_candle_sign_strategy, self).OnStarted2(time)
self._jma_open = JurikMovingAverage()
self._jma_open.Length = self.jma_length
self._jma_close = JurikMovingAverage()
self._jma_close.Length = self.jma_length
self._prev_open_jma = 0.0
self._prev_close_jma = 0.0
self._has_prev = False
self.Indicators.Add(self._jma_open)
self.Indicators.Add(self._jma_close)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
open_result = process_float(self._jma_open, candle.OpenPrice, candle.OpenTime, True)
close_result = process_float(self._jma_close, candle.ClosePrice, candle.OpenTime, True)
if not open_result.IsFormed or not close_result.IsFormed:
return
open_jma = float(open_result)
close_jma = float(close_result)
if not self._has_prev:
self._prev_open_jma = open_jma
self._prev_close_jma = close_jma
self._has_prev = True
return
# JMA(close) crosses above JMA(open) - bullish
if self._prev_close_jma <= self._prev_open_jma and close_jma > open_jma and self.Position <= 0:
self.BuyMarket()
# JMA(close) crosses below JMA(open) - bearish
elif self._prev_close_jma >= self._prev_open_jma and close_jma < open_jma and self.Position >= 0:
self.SellMarket()
self._prev_open_jma = open_jma
self._prev_close_jma = close_jma
def CreateClone(self):
return jma_candle_sign_strategy()