Color JLaguerre 戦略
色分けされたLaguerreオシレーターに基づく戦略です。
このインジケーターはJurikフィルターで価格動向を平滑化し、事前定義されたレベル内の位置に応じてラインを着色します。色の変化はトレンドの転換の可能性を示します。
戦略はオシレーターが中間レベルを上向きに越えたときにロングに入り、下向きに越えたときにショートに入ります。オシレーターが極端なレベルに達するか反対のシグナルが現れるとポジションがクローズされます。
詳細
- エントリー条件: 中間レベル付近でのLaguerreオシレーターの色の変化。
- ロング/ショート: 両方向。
- エグジット条件: 反対シグナルまたは極端なレベルへの到達。
- ストップ: はい。
- デフォルト値:
RsiLength= 14HighLevel= 85MiddleLevel= 50LowLevel= 15StopLossPercent= 2mCandleType= TimeSpan.FromHours(1)
- フィルター:
- カテゴリ: オシレーター
- 方向: 両方
- インジケーター: RSI
- ストップ: はい
- 複雑さ: 基本
- 時間軸: 時間足 (1h)
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
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>
/// RSI oscillator smoothed through Jurik MA. Middle-level reversals and
/// extreme-level exits are based on formed indicators and completed candles.
/// </summary>
public class ColorJLaguerreStrategy : Strategy
{
private readonly StrategyParam<int> _rsiLength, _jmaLength;
private readonly StrategyParam<decimal> _highLevel, _middleLevel, _lowLevel, _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private JurikMovingAverage _jma;
private decimal? _previous;
private Order _pending;
public int RsiLength { get => _rsiLength.Value; set => _rsiLength.Value = value; }
public int JmaLength { get => _jmaLength.Value; set => _jmaLength.Value = value; }
public decimal HighLevel { get => _highLevel.Value; set => _highLevel.Value = value; }
public decimal MiddleLevel { get => _middleLevel.Value; set => _middleLevel.Value = value; }
public decimal LowLevel { get => _lowLevel.Value; set => _lowLevel.Value = value; }
public decimal StopLossPercent { get => _stopLossPercent.Value; set => _stopLossPercent.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ColorJLaguerreStrategy()
{
_rsiLength = Param(nameof(RsiLength), 14).SetGreaterThanZero()
.SetDisplay("RSI Length", "RSI lookback period", "Indicator");
_jmaLength = Param(nameof(JmaLength), 14).SetGreaterThanZero()
.SetDisplay("JMA Length", "Jurik smoothing of RSI", "Indicator");
_highLevel = Param(nameof(HighLevel), 85m)
.SetDisplay("High Level", "Close long at this threshold", "Levels");
_middleLevel = Param(nameof(MiddleLevel), 50m)
.SetDisplay("Middle Level", "Entry crossover threshold", "Levels");
_lowLevel = Param(nameof(LowLevel), 15m)
.SetDisplay("Low Level", "Close short at this threshold", "Levels");
_stopLossPercent = Param(nameof(StopLossPercent), 2m).SetNotNegative()
.SetDisplay("Stop Loss %", "Native percent stop distance", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_jma = null;
_previous = null;
_pending = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_previous = null;
_pending = null;
var rsi = new RelativeStrengthIndex { Length = RsiLength };
_jma = new JurikMovingAverage { Length = JmaLength };
Indicators.Add(_jma);
SubscribeCandles(CandleType)
.Bind(rsi, (candle, value) =>
{
if (candle.State == CandleStates.Finished && rsi.IsFormed)
ProcessCandle(candle, value);
}).Start();
StartProtection(
takeProfit: new Unit(0m, UnitTypes.Percent),
stopLoss: new Unit(StopLossPercent, UnitTypes.Percent),
useMarketOrders: true);
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
var result = _jma.Process(rsiValue, candle.OpenTime, true);
if (!result.IsFormed)
return;
var value = result.ToDecimal();
var crossUp = _previous is decimal prior && prior <= MiddleLevel && value > MiddleLevel;
var crossDown = _previous is decimal before && before >= MiddleLevel && value < MiddleLevel;
_previous = value;
if (!IsFormedAndOnlineAndAllowTrading()
|| (_pending is not null && _pending.State is not (OrderStates.Done or OrderStates.Failed)))
return;
if (Position > 0m && value >= HighLevel)
{
_pending = SellMarket(Position);
return;
}
if (Position < 0m && value <= LowLevel)
{
_pending = BuyMarket(-Position);
return;
}
if (crossUp)
{
if (Position < 0m)
_pending = BuyMarket(-Position + Volume);
else if (Position == 0m)
_pending = BuyMarket(Volume);
}
else if (crossDown)
{
if (Position > 0m)
_pending = SellMarket(Position + Volume);
else if (Position == 0m)
_pending = SellMarket(Volume);
}
}
}
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, OrderStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import RelativeStrengthIndex, JurikMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import process_float
class color_j_laguerre_strategy(Strategy):
"""RSI-JMA oscillator crosses middle and exits at extreme levels on finished candles."""
def __init__(self):
super(color_j_laguerre_strategy, self).__init__()
self._rsi_length = self.Param("RsiLength", 14).SetGreaterThanZero() \
.SetDisplay("RSI Length", "RSI lookback", "Indicator")
self._jma_length = self.Param("JmaLength", 14).SetGreaterThanZero() \
.SetDisplay("JMA Length", "Jurik smoothing of RSI", "Indicator")
self._high_level = self.Param("HighLevel", 85.0) \
.SetDisplay("High Level", "Close long at upper threshold", "Levels")
self._middle_level = self.Param("MiddleLevel", 50.0) \
.SetDisplay("Middle Level", "Middle crossover threshold", "Levels")
self._low_level = self.Param("LowLevel", 15.0) \
.SetDisplay("Low Level", "Close short at lower threshold", "Levels")
self._stop_loss_percent = self.Param("StopLossPercent", 2.0).SetNotNegative() \
.SetDisplay("Stop Loss %", "Native percent stop", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._rsi = None
self._jma = None
self._previous = None
self._pending = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(color_j_laguerre_strategy, self).OnReseted()
self._rsi = self._jma = self._previous = self._pending = None
def OnStarted2(self, time):
super(color_j_laguerre_strategy, self).OnStarted2(time)
self._previous = self._pending = None
self._rsi = RelativeStrengthIndex()
self._rsi.Length = int(self._rsi_length.Value)
self._jma = JurikMovingAverage()
self._jma.Length = int(self._jma_length.Value)
self.Indicators.Add(self._jma)
self.SubscribeCandles(self.CandleType).Bind(self._rsi, self.ProcessCandle).Start()
self.StartProtection(
takeProfit=Unit(0.0, UnitTypes.Percent),
stopLoss=Unit(self._stop_loss_percent.Value, UnitTypes.Percent),
useMarketOrders=True)
def ProcessCandle(self, candle, rsi_value):
if candle.State != CandleStates.Finished or not self._rsi.IsFormed:
return
smooth = process_float(self._jma, rsi_value, candle.OpenTime, True)
if not smooth.IsFormed:
return
value = float(smooth)
middle = float(self._middle_level.Value)
up = self._previous is not None and self._previous <= middle and value > middle
down = self._previous is not None and self._previous >= middle and value < middle
self._previous = value
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self._pending is not None and self._pending.State not in (OrderStates.Done, OrderStates.Failed):
return
if self.Position > 0 and value >= float(self._high_level.Value):
self._pending = self.SellMarket(self.Position)
return
if self.Position < 0 and value <= float(self._low_level.Value):
self._pending = self.BuyMarket(-self.Position)
return
if up:
if self.Position < 0:
self._pending = self.BuyMarket(-self.Position + self.Volume)
elif self.Position == 0:
self._pending = self.BuyMarket(self.Volume)
elif down:
if self.Position > 0:
self._pending = self.SellMarket(self.Position + self.Volume)
elif self.Position == 0:
self._pending = self.SellMarket(self.Volume)
def CreateClone(self):
return color_j_laguerre_strategy()