GitHub で見る
AMS ES RSI 戦略
概要
AMS ES RSI 戦略は、StockSharp 内の MetaTrader エキスパート Expert_AMS_ES_RSI の動作を再現します。朝/宵の明星ローソク足形成と相対強度指数 (RSI) 確認フィルターを組み合わせます。ロング取引は、RSI が売られ過ぎの状況を示している間に強気の明けの明星が現れたときに開始されます。短期取引は、買われすぎた RSI に弱気の宵の明星が形成されたときに行われます。 RSI が設定可能なしきい値レベルを通過すると、ポジションはクローズされます。
市場の仮定
- 通常の OHLC キャンドルを生成するあらゆる機器で動作します。スポット FX と指数先物は、MQL エキスパートの当初のターゲットでした。
- この戦略は、日本のローソク足パターンが意味のあるスムーズな価格変動を期待します。非常にノイズの多いティック チャートでは、信頼できるシグナルが生成されない可能性があります。
エントリーロジック
- 設定された時間枠 (デフォルト: 1 時間) を購読し、3 つの完全に閉じたローソク足を待ちます。
- 最後の BodyAveragePeriod キャンドル全体の平均ボディ サイズを計算します (デフォルト: 3)。
- 次の場合に 明けの明星 を検出します。
- ローソク足 3 は非常に弱気です (平均体サイズよりも
Open - Close 大きい)。
- ローソク足 2 には小さな実体 (平均の半分未満) とローソク足 3 の下にギャップがあります。
- ローソク足 1 はローソク足 3 の中点より上で終了します。
- 対称的な弱気条件で Evening Star を検出します。
- 現在の RSI 値が LongEntryRsi (デフォルト: 40) を下回っている場合、長いエントリを確認します。 RSI が ShortEntryRsi (デフォルト: 60) を超えている場合、短いエントリを確認します。
- 戦略
Volume を使用して成行注文を実行します。
終了ロジック
- RSI が UpperExitRsi (デフォルト: 70) または LowerExitRsi (デフォルト: 30) を下方向にクロスすると、ロングポジションを閉じます。
- RSI が同じレベルを上向きにクロスしたら、ショート ポジションを閉じます。
- ハードストップロスやテイクプロフィットは適用されません。リスク管理は外部から、またはしきい値を調整することによって処理する必要があります。
パラメーター
| 名前 |
説明 |
デフォルト |
範囲 |
CandleType |
サブスクライブするローソク足シリーズを表すデータ型。 |
1時間枠 |
サポートされているキャンドルの種類 |
RsiPeriod |
RSI の計算長。 |
47 |
最適化可能 (10 ~ 70) |
BodyAveragePeriod |
パターンの検証に必要な平均体のサイズを計算するために使用されるキャンドルの数。 |
3 |
最適化可能 (2 ~ 6) |
LongEntryRsi |
長いエントリを許可する最大 RSI 値。 |
40 |
最適化可能 (20 ~ 50) |
ShortEntryRsi |
短いエントリを許可する最小の RSI 値。 |
60 |
最適化可能 (50 ~ 80) |
LowerExitRsi |
上方に越えたときに出口をトリガーする下限境界。 |
30 |
最適化可能 (20 ~ 40) |
UpperExitRsi |
下方に通過したときに終了をトリガーする上限。 |
70 |
最適化可能 (60 ~ 80) |
実装メモ
- 自動キャンドル サブスクリプションで StockSharp の高レベルの API を使用します。
Bind によって提供されるインジケーター値のみに依存し、プロジェクト ガイドラインに従って手動の GetValue 呼び出しを回避します。
- パターン検証のために最小限のメモリ内履歴 (最近の 3 つのキャンドル) のみを維持します。
- この戦略は、起動時に自動的に
StartProtection() を呼び出し、組み込みの安全メカニズムを有効にします。
使用のヒント
- ストラテジーを商品/ポートフォリオのペアにアタッチし、ローソク足シリーズがコネクタから利用可能であることを確認します。
- 資産のボラティリティに応じて RSI レベルを調整します。しきい値を広くすると取引数は減りますが、確認の品質は向上します。
- 外部のポジションサイジングモジュール(リスクベースのボリュームなど)と組み合わせて、元の EA の固定ロットの動作をエミュレートします。
- バックテストを行うときは、スター パターンを正しく識別できるように、ローソク足のデータにギャップが含まれていることを確認してください。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Morning/Evening Star + RSI strategy.
/// Buys on morning star with low RSI, sells on evening star with high RSI.
/// </summary>
public class AmsEsRsiStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _rsiLow;
private readonly StrategyParam<decimal> _rsiHigh;
private ICandleMessage _prevCandle;
private ICandleMessage _prevPrevCandle;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public decimal RsiLow { get => _rsiLow.Value; set => _rsiLow.Value = value; }
public decimal RsiHigh { get => _rsiHigh.Value; set => _rsiHigh.Value = value; }
public AmsEsRsiStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period", "Indicators");
_rsiLow = Param(nameof(RsiLow), 40m)
.SetDisplay("RSI Low", "RSI oversold threshold", "Signals");
_rsiHigh = Param(nameof(RsiHigh), 60m)
.SetDisplay("RSI High", "RSI overbought threshold", "Signals");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevCandle = null;
_prevPrevCandle = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCandle = null;
_prevPrevCandle = null;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(rsi, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished) return;
if (_prevCandle != null && _prevPrevCandle != null)
{
var prevBody = Math.Abs(_prevCandle.ClosePrice - _prevCandle.OpenPrice);
var prevRange = _prevCandle.HighPrice - _prevCandle.LowPrice;
var isSmallBody = prevRange > 0 && prevBody < prevRange * 0.3m;
var firstBearish = _prevPrevCandle.OpenPrice > _prevPrevCandle.ClosePrice;
var currBullish = candle.ClosePrice > candle.OpenPrice;
var isMorningStar = firstBearish && isSmallBody && currBullish;
var firstBullish = _prevPrevCandle.ClosePrice > _prevPrevCandle.OpenPrice;
var currBearish = candle.OpenPrice > candle.ClosePrice;
var isEveningStar = firstBullish && isSmallBody && currBearish;
if (isMorningStar && rsiValue < RsiLow && Position <= 0)
BuyMarket();
else if (isEveningStar && rsiValue > RsiHigh && Position >= 0)
SellMarket();
}
_prevPrevCandle = _prevCandle;
_prevCandle = candle;
}
}
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 ams_es_rsi_strategy(Strategy):
def __init__(self):
super(ams_es_rsi_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._rsi_period = self.Param("RsiPeriod", 14)
self._rsi_low = self.Param("RsiLow", 40.0)
self._rsi_high = self.Param("RsiHigh", 60.0)
self._prev_candle = None
self._prev_prev_candle = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsi_period.Value = value
@property
def RsiLow(self):
return self._rsi_low.Value
@RsiLow.setter
def RsiLow(self, value):
self._rsi_low.Value = value
@property
def RsiHigh(self):
return self._rsi_high.Value
@RsiHigh.setter
def RsiHigh(self, value):
self._rsi_high.Value = value
def OnReseted(self):
super(ams_es_rsi_strategy, self).OnReseted()
self._prev_candle = None
self._prev_prev_candle = None
def OnStarted2(self, time):
super(ams_es_rsi_strategy, self).OnStarted2(time)
self._prev_candle = None
self._prev_prev_candle = None
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(rsi, self._process_candle).Start()
def _process_candle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
rsi_val = float(rsi_value)
if self._prev_candle is not None and self._prev_prev_candle is not None:
prev_body = abs(float(self._prev_candle.ClosePrice) - float(self._prev_candle.OpenPrice))
prev_range = float(self._prev_candle.HighPrice) - float(self._prev_candle.LowPrice)
is_small_body = prev_range > 0 and prev_body < prev_range * 0.3
first_bearish = float(self._prev_prev_candle.OpenPrice) > float(self._prev_prev_candle.ClosePrice)
curr_bullish = float(candle.ClosePrice) > float(candle.OpenPrice)
is_morning_star = first_bearish and is_small_body and curr_bullish
first_bullish = float(self._prev_prev_candle.ClosePrice) > float(self._prev_prev_candle.OpenPrice)
curr_bearish = float(candle.OpenPrice) > float(candle.ClosePrice)
is_evening_star = first_bullish and is_small_body and curr_bearish
if is_morning_star and rsi_val < self.RsiLow and self.Position <= 0:
self.BuyMarket()
elif is_evening_star and rsi_val > self.RsiHigh and self.Position >= 0:
self.SellMarket()
self._prev_prev_candle = self._prev_candle
self._prev_candle = candle
def CreateClone(self):
return ams_es_rsi_strategy()