GitHub で見る
RSI デュアル戦略の RSI MA
概要
RSI デュアル戦略の RSI MA は、StockSharp 内に MetaTrader エキスパート アドバイザー「RSI_MAonRSI_Dual」を再作成します。ルックバック期間が異なる 2 つの相対強度インデックスを監視し、各 RSI ストリームに共通の移動平均を適用します。平滑化された RSI ラインが構成可能な中立レベルの同じ側に留まりながら互いに交差するときに、取引の決定が下されます。
変換では、時間フィルタリングや取引方向を制限したり信号ロジックを反転したりする機能など、元のロボットの動作が維持されます。
インジケーター
- Fast RSI – 設定可能な期間を持つ相対強度インデックス。
- Slow RSI – 独自の周期を持つ相対強度指数。
- RSI の移動平均 – 各 RSI 値ストリームに基づいて計算された単純移動平均。どちらの RSI も同じスムージング長を使用します。
3 つのインジケーターはすべて同じ適用価格 (デフォルトでは終値) を共有します。 2 本の平滑化された RSI 線が、監視用の専用チャート パネルに描画されます。
エントリールール
- 両方の平滑化された RSI 値が現在の完成バーに形成されるまで待ちます。
- 長いセットアップ
- 高速平滑化された RSI は、低速平滑化された RSI の 上 と交差しています (上が現在の値、下が前の値)。
- 平滑化された RSI は両方ともニュートラル レベル (デフォルトでは 50) を下 にしています。
- 簡単なセットアップ
- 高速平滑化された RSI は、低速平滑化された RSI を下で交差します (現在値が下、前回の値が上)。
- 平滑化された RSI は両方ともニュートラル レベルを 上 にあります。
- 必要に応じて、
ReverseSignals パラメータを使用して信号の方向を反転します。
- 同じバーで生成された信号は無視されます (バーごとに 1 つのエントリ)。
ポジション管理
AllowLong と AllowShort は、戦略が各方向にポジションをオープンできるかどうかを制御します。
CloseOpposite は、反対側に入る前に既存のポジションを決済し、元の EA ロジックを複製します。
OnlyOnePosition は、ポジションがすでにアクティブな場合に新しいポジションを開くことを禁止します。
- 成行注文は戦略
Volume で発行されます。
時間フィルター
UseTimeFilter を使用して取引セッション フィルターを有効または無効にします。有効にすると、SessionStart と SessionEnd の間でのみ取引が許可されます。真夜中を超えるセッションはサポートされています。タイムスタンプは、受信キャンドル メッセージによって提供される交換タイム ゾーンで評価されます。
パラメーター
| 名前 |
説明 |
CandleType |
戦略別に分析したキャンドルシリーズ。 |
FastRsiPeriod |
高速の RSI の期間。 |
SlowRsiPeriod |
遅い RSI の期間。 |
MaPeriod |
両方の RSI ストリームを平滑化するために使用される移動平均の長さ。 |
AppliedPrice |
RSI の計算に転送される価格タイプ。 |
NeutralLevel |
RSI は強気ゾーンと弱気ゾーンを分けるしきい値です。 |
AllowLong / AllowShort |
取引方向を有効または無効にします。 |
ReverseSignals |
長い信号と短い信号を交換します。 |
CloseOpposite |
新しいポジションに入る前に、反対のポジションを閉じます。 |
OnlyOnePosition |
オープンポジションは最大 1 つまで許可します。 |
UseTimeFilter |
取引セッションフィルターを有効にします。 |
SessionStart / SessionEnd |
取引ウィンドウの境界。 |
オリジナルの EA との違い
- 元の MQL5 コードの資金管理、ストップロス、トレーリングストップのブロックは再現されません。 StockSharp 戦略は、戦略に設定された固定の
Volume を使用して成行注文を出します。
- すべてのログ記録と診断アラートが削除されました。必要に応じて、代わりに StockSharp ログを使用する必要があります。
- プラットフォーム固有のトランザクション追跡は、StockSharp 注文状態イベントに置き換えられます。
これらの違いにもかかわらず、コアのエントリ ロジックと方向フィルターはソースの Expert Advisor と一致します。
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>
/// Dual moving averages calculated on top of RSI values.
/// Fast RSI MA crossing slow RSI MA generates entry signals.
/// </summary>
public class RsiMaOnRsiDualStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastRsiPeriod;
private readonly StrategyParam<int> _slowRsiPeriod;
private readonly StrategyParam<int> _maPeriod;
private RelativeStrengthIndex _fastRsi;
private RelativeStrengthIndex _slowRsi;
private readonly Queue<decimal> _fastRsiHistory = new();
private readonly Queue<decimal> _slowRsiHistory = new();
private decimal? _previousFastMa;
private decimal? _previousSlowMa;
public RsiMaOnRsiDualStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle type", "Candles processed by the strategy.", "General");
_fastRsiPeriod = Param(nameof(FastRsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Fast RSI period", "Length of the fast RSI smoothing window.", "Indicators");
_slowRsiPeriod = Param(nameof(SlowRsiPeriod), 28)
.SetGreaterThanZero()
.SetDisplay("Slow RSI period", "Length of the slow RSI smoothing window.", "Indicators");
_maPeriod = Param(nameof(MaPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("MA period", "Number of RSI values averaged by the smoothing moving average.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastRsiPeriod
{
get => _fastRsiPeriod.Value;
set => _fastRsiPeriod.Value = value;
}
public int SlowRsiPeriod
{
get => _slowRsiPeriod.Value;
set => _slowRsiPeriod.Value = value;
}
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_previousFastMa = null;
_previousSlowMa = null;
_fastRsiHistory.Clear();
_slowRsiHistory.Clear();
_fastRsi = null!;
_slowRsi = null!;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_previousFastMa = null;
_previousSlowMa = null;
_fastRsiHistory.Clear();
_slowRsiHistory.Clear();
_fastRsi = new RelativeStrengthIndex { Length = FastRsiPeriod };
_slowRsi = new RelativeStrengthIndex { Length = SlowRsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_fastRsi, _slowRsi, ProcessCandle)
.Start();
var priceArea = CreateChartArea();
if (priceArea != null)
{
DrawCandles(priceArea, subscription);
DrawOwnTrades(priceArea);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastRsiValue, decimal slowRsiValue)
{
if (candle.State != CandleStates.Finished)
return;
_fastRsiHistory.Enqueue(fastRsiValue);
_slowRsiHistory.Enqueue(slowRsiValue);
while (_fastRsiHistory.Count > MaPeriod)
_fastRsiHistory.Dequeue();
while (_slowRsiHistory.Count > MaPeriod)
_slowRsiHistory.Dequeue();
if (!_fastRsi.IsFormed || !_slowRsi.IsFormed)
return;
if (_fastRsiHistory.Count < MaPeriod || _slowRsiHistory.Count < MaPeriod)
return;
// Calculate SMA of each RSI
var fastSum = 0m;
var fastHistory = _fastRsiHistory.ToArray();
foreach (var v in fastHistory)
fastSum += v;
var fastMa = fastSum / MaPeriod;
var slowSum = 0m;
var slowHistory = _slowRsiHistory.ToArray();
foreach (var v in slowHistory)
slowSum += v;
var slowMa = slowSum / MaPeriod;
if (_previousFastMa is null || _previousSlowMa is null)
{
_previousFastMa = fastMa;
_previousSlowMa = slowMa;
return;
}
var crossUp = _previousFastMa < _previousSlowMa && fastMa > slowMa;
var crossDown = _previousFastMa > _previousSlowMa && fastMa < slowMa;
var volume = Volume;
if (volume <= 0)
volume = 1;
if (crossUp)
{
if (Position <= 0)
BuyMarket(volume);
}
else if (crossDown)
{
if (Position >= 0)
SellMarket(volume);
}
_previousFastMa = fastMa;
_previousSlowMa = slowMa;
}
}
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 RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class rsi_ma_on_rsi_dual_strategy(Strategy):
def __init__(self):
super(rsi_ma_on_rsi_dual_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._fast_rsi_period = self.Param("FastRsiPeriod", 14)
self._slow_rsi_period = self.Param("SlowRsiPeriod", 28)
self._ma_period = self.Param("MaPeriod", 12)
self._fast_rsi_history = []
self._slow_rsi_history = []
self._prev_fast_ma = 0.0
self._prev_slow_ma = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def FastRsiPeriod(self):
return self._fast_rsi_period.Value
@FastRsiPeriod.setter
def FastRsiPeriod(self, value):
self._fast_rsi_period.Value = value
@property
def SlowRsiPeriod(self):
return self._slow_rsi_period.Value
@SlowRsiPeriod.setter
def SlowRsiPeriod(self, value):
self._slow_rsi_period.Value = value
@property
def MaPeriod(self):
return self._ma_period.Value
@MaPeriod.setter
def MaPeriod(self, value):
self._ma_period.Value = value
def OnReseted(self):
super(rsi_ma_on_rsi_dual_strategy, self).OnReseted()
self._fast_rsi_history = []
self._slow_rsi_history = []
self._prev_fast_ma = 0.0
self._prev_slow_ma = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(rsi_ma_on_rsi_dual_strategy, self).OnStarted2(time)
self._fast_rsi_history = []
self._slow_rsi_history = []
self._prev_fast_ma = 0.0
self._prev_slow_ma = 0.0
self._has_prev = False
fast_rsi = RelativeStrengthIndex()
fast_rsi.Length = self.FastRsiPeriod
slow_rsi = RelativeStrengthIndex()
slow_rsi.Length = self.SlowRsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast_rsi, slow_rsi, self._process_candle).Start()
def _process_candle(self, candle, fast_rsi_value, slow_rsi_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_rsi_value)
slow_val = float(slow_rsi_value)
ma_len = self.MaPeriod
self._fast_rsi_history.append(fast_val)
self._slow_rsi_history.append(slow_val)
while len(self._fast_rsi_history) > ma_len:
self._fast_rsi_history.pop(0)
while len(self._slow_rsi_history) > ma_len:
self._slow_rsi_history.pop(0)
if len(self._fast_rsi_history) < ma_len or len(self._slow_rsi_history) < ma_len:
return
fast_ma = sum(self._fast_rsi_history) / ma_len
slow_ma = sum(self._slow_rsi_history) / ma_len
if self._has_prev:
cross_up = self._prev_fast_ma < self._prev_slow_ma and fast_ma > slow_ma
cross_down = self._prev_fast_ma > self._prev_slow_ma and fast_ma < slow_ma
if cross_up and self.Position <= 0:
self.BuyMarket()
elif cross_down and self.Position >= 0:
self.SellMarket()
self._prev_fast_ma = fast_ma
self._prev_slow_ma = slow_ma
self._has_prev = True
def CreateClone(self):
return rsi_ma_on_rsi_dual_strategy()