GitHub で見る
トップス ボトムス トレンド RSI 戦略
概要
この戦略は、MetaTrader エキスパート アドバイザー「Tops Bottoms Trend and RSI EA」の StockSharp 移植です。選択した時間枠の終了したローソク足を監視し、設定可能なルックバック ウィンドウ内で新たなトレンドの天井または底を検索し、相対強度指数 (RSI) フィルターで各機会を確認します。基準が満たされると、この戦略は単一の成行注文を開き、ピップベースの距離から導出された保護的なストップロスとテイクプロフィットレベルを即座に割り当てます。
取引ロジック
- データ ソース – アルゴリズムは構成されたローソク タイプをサブスクライブし、不完全なデータの使用を避けるために完成したローソクのみを評価します。
- 底値検出 (ロングセットアップ) – 最新のローソク足の終値は、
BuyTrendCandles バー前のローソク足の高値より少なくとも BuyTrendPips ピップス下である必要があります。すべての中間安値は現在の終値を上回っている必要があり、品質フィルター (BuyTrendQuality) では、最近の高値が基準高値から大きく乖離していないことが必要です。この構造が形成され、前のローソク足の RSI の値が BuyRsiThreshold を下回っている場合、この戦略はボリューム BuyVolume のロング ポジションをオープンします。
- 上値検出 (ショートセットアップ) – 最新のローソク足の終値は、
SellTrendCandles バー前のローソク足の安値より少なくとも SellTrendPips ピップス上である必要があります。品質フィルター (SellTrendQuality) が最近の安値を基準値付近に維持する一方で、中間高値は現在の終値を下回らないようにする必要があります。前のローソク足の RSI の値が SellRsiThreshold を超える場合、この戦略は出来高 SellVolume のショート ポジションをオープンします。
- リスク管理 – 各エントリーの後、ストラテジーは約定価格を保存し、ピップベースの保護レベルを計算します。ストップロス オフセットには、
BuyStopLossPips または SellStopLossPips を使用します。テイクプロフィット距離は主に、BuyTakeProfitPercentOfStop または SellTakeProfitPercentOfStop 経由のストップから導出されます。ロングテイクプロフィットパーセンテージが無効になっている場合 (0)、代わりに固定の BuyTakeProfitPips 距離が使用されます。後続のローソク足が対応するストップまたはテイクプロフィットレベルに達すると、ポジションは成行注文でクローズされます。
- 位置制御 – システムは最大 1 つの開いた位置を維持します。ポジションまたはアクティブな注文が存在する間は、新しいシグナルは無視されます。 RSI の確認は常に前のローソク足 (1 バー シフト) に依存し、元の EA を反映します。
パラメーター
| 名前 |
説明 |
デフォルト |
BuyVolume |
ロングポジションに使用される注文量。 |
0.01 |
BuyStopLossPips |
ロングトレードのストップロス距離 (pips)。 |
20 |
BuyTakeProfitPips |
パーセンテージモードが無効な場合のロングのテイクプロフィット距離をピップ単位で修正しました。 |
5 |
BuyTakeProfitPercentOfStop |
長いストップロス距離に対するテイクプロフィットの割合。 |
100 |
SellVolume |
ショートポジションに使用される注文量。 |
0.01 |
SellStopLossPips |
ショートトレードのストップロス距離 (pips)。 |
20 |
SellTakeProfitPercentOfStop |
短いストップロス距離に対するテイクプロフィットの割合。 |
100 |
SellTrendCandles |
新しいトップを検索するときに検査されるローソクの数。 |
10 |
SellTrendPips |
短いセットアップに必要な基準低値を上回る最小前進量 (pips)。 |
20 |
SellTrendQuality |
短いセットアップ用のトレンド品質フィルター (1 ~ 9 の範囲に固定)。 |
5 |
BuyTrendCandles |
新しい底値を検索するときに検査されるキャンドルの数。 |
10 |
BuyTrendPips |
長いセットアップに必要な基準高値を下回る最小の下落 (pips)。 |
20 |
BuyTrendQuality |
長いセットアップ用のトレンド品質フィルター (1 ~ 9 の範囲に固定)。 |
5 |
BuyRsiPeriod |
RSI 期間は長い確認に使用されます。 |
14 |
BuyRsiThreshold |
ロングエントリーを有効にするには、RSI の売られ過ぎのしきい値を上から超える必要があります。 |
40 |
SellRsiPeriod |
RSI の期間は短い確認に使用されます。 |
14 |
SellRsiThreshold |
RSI の買われすぎのしきい値。ショートエントリーを有効にするには、これを下回る必要があります。 |
60 |
CandleType |
戦略によって処理されるローソク足のタイムフレーム。 |
30-minute time frame |
注意事項
- ピップ距離は、証券の
PriceStep を使用して価格に変換されます。 5 桁および小数ピップの外国為替相場は、元の EA からの変換ルールを複製して、従来のピップ サイズに正規化されます。
- RSI 確認では前のローソク足 (シフト = 1) が使用されるため、ストラテジーでは取引する前に完全に形成された RSI 値が少なくとも 1 つ必要です。したがって、起動後の最初の数本のキャンドルは無視されます。
- このロジックはポジションが完全にクローズされるたびにすべての保護レベルをキャンセルし、次のエントリーが新しいリスクパラメーターで開始されることを保証します。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Tops Bottoms Trend RSI strategy: RSI trend direction with EMA filter.
/// Buys when RSI above 50 and close above EMA, sells when RSI below 50 and close below EMA.
/// </summary>
public class TopsBottomsTrendRsiStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _emaPeriod;
private decimal _prevRsi;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public TopsBottomsTrendRsiStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 21)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period", "Indicators");
_emaPeriod = Param(nameof(EmaPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "EMA trend filter period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevRsi = 0;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevRsi = 0;
_hasPrev = false;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(rsi, ema, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue, decimal emaValue)
{
if (candle.State != CandleStates.Finished) return;
if (_hasPrev)
{
if (_prevRsi <= 45 && rsiValue > 45 && candle.ClosePrice > emaValue && Position <= 0)
BuyMarket();
else if (_prevRsi >= 55 && rsiValue < 55 && candle.ClosePrice < emaValue && Position >= 0)
SellMarket();
}
_prevRsi = rsiValue;
_hasPrev = true;
}
}
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, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class tops_bottoms_trend_rsi_strategy(Strategy):
def __init__(self):
super(tops_bottoms_trend_rsi_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._rsi_period = self.Param("RsiPeriod", 21)
self._ema_period = self.Param("EmaPeriod", 50)
self._prev_rsi = 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 RsiPeriod(self):
return self._rsi_period.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsi_period.Value = value
@property
def EmaPeriod(self):
return self._ema_period.Value
@EmaPeriod.setter
def EmaPeriod(self, value):
self._ema_period.Value = value
def OnReseted(self):
super(tops_bottoms_trend_rsi_strategy, self).OnReseted()
self._prev_rsi = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(tops_bottoms_trend_rsi_strategy, self).OnStarted2(time)
self._prev_rsi = 0.0
self._has_prev = False
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
ema = ExponentialMovingAverage()
ema.Length = self.EmaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(rsi, ema, self._process_candle).Start()
def _process_candle(self, candle, rsi_value, ema_value):
if candle.State != CandleStates.Finished:
return
rsi_val = float(rsi_value)
ema_val = float(ema_value)
close = float(candle.ClosePrice)
if self._has_prev:
if self._prev_rsi <= 45 and rsi_val > 45 and close > ema_val and self.Position <= 0:
self.BuyMarket()
elif self._prev_rsi >= 55 and rsi_val < 55 and close < ema_val and self.Position >= 0:
self.SellMarket()
self._prev_rsi = rsi_val
self._has_prev = True
def CreateClone(self):
return tops_bottoms_trend_rsi_strategy()