GitHub で見る
基本的な RSI EA テンプレート戦略
基本的な RSI EA テンプレート戦略 は、MetaTrader 4 エキスパート アドバイザー「Basic Rsi EA Template.mq4」(MQL/26750) を複製します。選択したローソク足シリーズの相対強度指数 (RSI) を監視し、設定可能な買われすぎゾーンまたは売られすぎゾーンに勢いが広がったときに反応します。 StockSharp 変換は、高レベルのサブスクリプション API を採用しながら、シンプルな 1 ポジション ワークフローと元のロボットの保護停止/テイク ロジックを維持します。
戦略ロジック
インジケーター
- 相対強度指数 (RSI) は、選択したローソクの種類に基づいて計算された構成可能な期間を持ちます。
エントリー条件
- 長いセットアップ: RSI が
OversoldLevel を下回り、ストラテジーにオープン ポジションがない場合、設定された OrderVolume の成行買い注文が送信されます。
- 簡単なセットアップ: RSI が
OverboughtLevel を超えて上昇し、ストラテジーにオープン ポジションがない場合、設定された OrderVolume の成行売り注文が送信されます。
このアルゴリズムはネッティング モードで動作します。つまり、一度に存在できるポジションは 1 つだけです。ロング ポジションがアクティブな場合、ストラテジーはショート エントリーの前にポジションが決済されるのを待ちます (逆も同様です)。
終了条件
- プロテクトストップ:
StopLossPips は、商品ティックサイズを使用して絶対価格距離に変換されます。価格がその金額だけリトレースすると、内蔵の保護エンジンがポジションを閉じます。
- 利益確定:
TakeProfitPips も同様に処理されます。設定された距離だけ価格が有利に動くと、ポジションは利益を得るためにクローズされます。
追加のトレーリングまたはシグナルベースの終了はありません。この戦略は純粋に保護距離または取引を終了するための手動介入に依存しており、元のテンプレートのミニマリストなデザインを反映しています。
リスクとボリュームの処理
OrderVolume は、すべての成行注文で送信される固定金額を定義します (デフォルトは 0.01 ロット、MQL サンプルと一致します)。
- この戦略はピラミッド型でもヘッジ型でもありません。保護的なストップまたは利益確定によってアクティブな取引が終了すると、アルゴリズムはフラットになり、次の RSI トリガーを待ちます。
パラメーター
CandleType: シグナル生成に使用されるローソク足シリーズ (デフォルト: 1 分の時間枠)。
RsiPeriod: RSI ウィンドウ内のバーの数 (デフォルト: 14)。
OverboughtLevel: 短いエントリを許可する RSI のしきい値 (デフォルト: 70)。
OversoldLevel: 長いエントリを許可する RSI のしきい値 (デフォルト: 30)。
StopLossPips: 絶対価格単位に変換されたピップ単位のストップ距離 (デフォルト: 30 ピップ)。
TakeProfitPips: 絶対価格単位に変換されたピップ単位の利益目標 (デフォルト: 20 ピップ)。
OrderVolume: 成行注文の固定数量 (デフォルト: 0.01)。
実装メモ
SubscribeCandles(...).Bind(rsi, ProcessCandle) を使用するため、手動のバッファー管理を行わずにインジケーター値が処理メソッドに直接流れます。
CreateProtectionUnit は、MQL のピップ処理を再作成します。小数点以下 3 桁または 5 桁の商品は、10 倍の乗数を使用してピップを価格ステップにマッピングします。
- すべてのインジケーターのチェックは、同じ足での複数の注文を避けるために、完成したローソク足で実行されます。
- この変換は、MetaTrader のヘッジ モードとは異なり、ネッティング アカウントを前提としています。その結果、反対の取引は複数のチケットを作成するのではなく、現在のポジションを決済します。
- インライン コメントとログは、将来のメンテナンスに役立つように英語で表示されます。
使用のヒント
- 取引したい商品と時間枠に合わせて
CandleType を調整します(たとえば、スイング設定の場合は時間足ローソク足に切り替えます)。
StopLossPips と TakeProfitPips を調整して、金融商品のボラティリティに一致させます。防護距離はリスク管理に不可欠です。
- テンプレート ロジックを超えた高度な資金管理が必要な場合は、戦略を StockSharp ポートフォリオまたはリスク モジュールと組み合わせます。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Basic RSI template: buys when RSI is oversold, sells when RSI is overbought.
/// </summary>
public class BasicRsiEaTemplateStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _overboughtLevel;
private readonly StrategyParam<decimal> _oversoldLevel;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
public decimal OverboughtLevel
{
get => _overboughtLevel.Value;
set => _overboughtLevel.Value = value;
}
public decimal OversoldLevel
{
get => _oversoldLevel.Value;
set => _oversoldLevel.Value = value;
}
public BasicRsiEaTemplateStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI calculation period", "Indicators");
_overboughtLevel = Param(nameof(OverboughtLevel), 70m)
.SetDisplay("Overbought Level", "RSI overbought threshold", "Indicators");
_oversoldLevel = Param(nameof(OversoldLevel), 30m)
.SetDisplay("Oversold Level", "RSI oversold threshold", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
decimal? prevRsi = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, (candle, rsiValue) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (prevRsi.HasValue)
{
var crossBelowOversold = prevRsi.Value >= OversoldLevel && rsiValue < OversoldLevel;
var crossAboveOverbought = prevRsi.Value <= OverboughtLevel && rsiValue > OverboughtLevel;
if (crossBelowOversold && Position <= 0)
BuyMarket();
else if (crossAboveOverbought && Position >= 0)
SellMarket();
}
prevRsi = rsiValue;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, rsi);
DrawOwnTrades(area);
}
}
}
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 basic_rsi_ea_template_strategy(Strategy):
def __init__(self):
super(basic_rsi_ea_template_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI calculation period", "Indicators")
self._overbought_level = self.Param("OverboughtLevel", 70.0) \
.SetDisplay("Overbought Level", "RSI overbought threshold", "Indicators")
self._oversold_level = self.Param("OversoldLevel", 30.0) \
.SetDisplay("Oversold Level", "RSI oversold threshold", "Indicators")
self._rsi = None
self._prev_rsi = None
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def overbought_level(self):
return self._overbought_level.Value
@property
def oversold_level(self):
return self._oversold_level.Value
def OnReseted(self):
super(basic_rsi_ea_template_strategy, self).OnReseted()
self._rsi = None
self._prev_rsi = None
def OnStarted2(self, time):
super(basic_rsi_ea_template_strategy, self).OnStarted2(time)
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.rsi_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(30)))
subscription.Bind(self._rsi, self._process_candle)
subscription.Start()
def _process_candle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
if not self._rsi.IsFormed:
return
rsi = float(rsi_value)
if self._prev_rsi is not None:
cross_below_oversold = self._prev_rsi >= self.oversold_level and rsi < self.oversold_level
cross_above_overbought = self._prev_rsi <= self.overbought_level and rsi > self.overbought_level
if cross_below_oversold and self.Position <= 0:
self.BuyMarket()
elif cross_above_overbought and self.Position >= 0:
self.SellMarket()
self._prev_rsi = rsi
def CreateClone(self):
return basic_rsi_ea_template_strategy()