アダプティブ SMI エルゴディック戦略
アダプティブ SMI エルゴディック戦略は、EMA シグナルラインを持つ True Strength Index (TSI) オシレーターを使用して、買われすぎまたは売られすぎの極端な状態からのリバーサルを検出します。TSI が売られすぎしきい値を上抜けし、シグナルラインを上回っているときにロングポジションが建てられます。TSI が買われすぎしきい値を下抜けし、シグナルラインを下回っているときにショートポジションが建てられます。
詳細
- エントリー条件:
- TSI が売られすぎを上抜けし、TSI > シグナル (ロング)。
- TSI が買われすぎを下抜けし、TSI < シグナル (ショート)。
- ロング/ショート: 両方。
- エグジット条件:
- 逆シグナルが反対方向のトレードを引き起こす。
- ストップ: なし。
- デフォルト値:
LongLength= 12ShortLength= 5SignalLength= 5OversoldThreshold= -0.4OverboughtThreshold= 0.4
- フィルター:
- カテゴリ: モメンタムオシレーター
- 方向: ロング/ショート
- インジケーター: True Strength Index, EMA
- ストップ: いいえ
- 複雑さ: 低
- 時間軸: 任意
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 低
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>
/// Adaptive SMI Ergodic strategy.
/// The True Strength Index (long smoothing LongLength, short smoothing ShortLength) is compared with its EMA signal line. A long opens
/// when TSI crosses above OversoldThreshold while above the signal line, a short when it crosses below OverboughtThreshold while below
/// the signal line; the opposite signal reverses the position. Thresholds are on the -1..1 ergodic scale.
/// </summary>
public class AdaptiveSmiErgodicStrategy : Strategy
{
private readonly StrategyParam<int> _longLength;
private readonly StrategyParam<int> _shortLength;
private readonly StrategyParam<int> _signalLength;
private readonly StrategyParam<decimal> _oversoldThreshold;
private readonly StrategyParam<decimal> _overboughtThreshold;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevTsi;
/// <summary>
/// Long smoothing length of TSI.
/// </summary>
public int LongLength
{
get => _longLength.Value;
set => _longLength.Value = value;
}
/// <summary>
/// Short smoothing length of TSI.
/// </summary>
public int ShortLength
{
get => _shortLength.Value;
set => _shortLength.Value = value;
}
/// <summary>
/// EMA length of the signal line.
/// </summary>
public int SignalLength
{
get => _signalLength.Value;
set => _signalLength.Value = value;
}
/// <summary>
/// Oversold level on the -1..1 scale.
/// </summary>
public decimal OversoldThreshold
{
get => _oversoldThreshold.Value;
set => _oversoldThreshold.Value = value;
}
/// <summary>
/// Overbought level on the -1..1 scale.
/// </summary>
public decimal OverboughtThreshold
{
get => _overboughtThreshold.Value;
set => _overboughtThreshold.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public AdaptiveSmiErgodicStrategy()
{
_longLength = Param(nameof(LongLength), 12)
.SetGreaterThanZero()
.SetDisplay("Long Length", "Long smoothing length of TSI", "TSI");
_shortLength = Param(nameof(ShortLength), 5)
.SetGreaterThanZero()
.SetDisplay("Short Length", "Short smoothing length of TSI", "TSI");
_signalLength = Param(nameof(SignalLength), 5)
.SetGreaterThanZero()
.SetDisplay("Signal Length", "EMA length of the signal line", "TSI");
_oversoldThreshold = Param(nameof(OversoldThreshold), -0.4m)
.SetDisplay("Oversold Threshold", "Oversold level on the -1..1 scale", "Levels");
_overboughtThreshold = Param(nameof(OverboughtThreshold), 0.4m)
.SetDisplay("Overbought Threshold", "Overbought level on the -1..1 scale", "Levels");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevTsi = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevTsi = null;
var tsi = new TrueStrengthIndex
{
FirstLength = LongLength,
SecondLength = ShortLength,
SignalLength = SignalLength,
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(tsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
var oscillators = CreateChartArea();
if (oscillators != null)
DrawIndicator(oscillators, tsi);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue tsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (tsiValue is not ITrueStrengthIndexValue { Tsi: decimal rawTsi, Signal: decimal rawSignal })
return;
// The indicator reports TSI in percent; the thresholds use the -1..1 ergodic scale.
var tsi = rawTsi / 100m;
var signal = rawSignal / 100m;
var prevTsi = _prevTsi;
_prevTsi = tsi;
if (prevTsi is not decimal prev || !IsFormedAndOnlineAndAllowTrading())
return;
var crossAboveOversold = prev <= OversoldThreshold && tsi > OversoldThreshold;
var crossBelowOverbought = prev >= OverboughtThreshold && tsi < OverboughtThreshold;
if (crossAboveOversold && tsi > signal && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (crossBelowOverbought && tsi < signal && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import TrueStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class adaptive_smi_ergodic_strategy(Strategy):
"""
Adaptive SMI Ergodic strategy.
The True Strength Index (long smoothing LongLength, short smoothing ShortLength) is compared with its EMA signal line. A long opens
when TSI crosses above OversoldThreshold while above the signal line, a short when it crosses below OverboughtThreshold while below
the signal line; the opposite signal reverses the position. Thresholds are on the -1..1 ergodic scale.
"""
def __init__(self):
super(adaptive_smi_ergodic_strategy, self).__init__()
self._long_length = self.Param("LongLength", 12).SetGreaterThanZero().SetDisplay("Long Length", "Long smoothing length of TSI", "TSI")
self._short_length = self.Param("ShortLength", 5).SetGreaterThanZero().SetDisplay("Short Length", "Short smoothing length of TSI", "TSI")
self._signal_length = self.Param("SignalLength", 5).SetGreaterThanZero().SetDisplay("Signal Length", "EMA length of the signal line", "TSI")
self._oversold_threshold = self.Param("OversoldThreshold", -0.4).SetDisplay("Oversold Threshold", "Oversold level on the -1..1 scale", "Levels")
self._overbought_threshold = self.Param("OverboughtThreshold", 0.4).SetDisplay("Overbought Threshold", "Overbought level on the -1..1 scale", "Levels")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_tsi = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(adaptive_smi_ergodic_strategy, self).OnReseted()
self._prev_tsi = None
def OnStarted2(self, time):
super(adaptive_smi_ergodic_strategy, self).OnStarted2(time)
self._prev_tsi = None
tsi = TrueStrengthIndex()
tsi.FirstLength = self._long_length.Value
tsi.SecondLength = self._short_length.Value
tsi.SignalLength = self._signal_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(tsi, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
oscillators = self.CreateChartArea()
if oscillators is not None:
self.DrawIndicator(oscillators, tsi)
def _process_candle(self, candle, tsi_value):
if candle.State != CandleStates.Finished:
return
if tsi_value.Tsi is None or tsi_value.Signal is None:
return
# The indicator reports TSI in percent; the thresholds use the -1..1 ergodic scale.
tsi = tsi_value.Tsi / Decimal(100)
signal = tsi_value.Signal / Decimal(100)
prev = self._prev_tsi
self._prev_tsi = tsi
if prev is None or not self.IsFormedAndOnlineAndAllowTrading():
return
oversold = Decimal(self._oversold_threshold.Value)
overbought = Decimal(self._overbought_threshold.Value)
cross_above_oversold = prev <= oversold and tsi > oversold
cross_below_overbought = prev >= overbought and tsi < overbought
if cross_above_oversold and tsi > signal and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif cross_below_overbought and tsi < signal and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
def CreateClone(self):
return adaptive_smi_ergodic_strategy()