EMA RSIトレンドリバーサル戦略
RSI確認によるEMAクロスオーバーでロングエントリーし、RSIがレベルを下回った状態での逆クロスオーバー発生時にエグジットする戦略。パーセントベースのテイクプロフィットとストップロスを使用します。
詳細
- エントリー条件:
- ロング:
FastEMA crosses above SlowEMA && RSI > RsiLevel
- ロング:
- ロング/ショート: ロングのみ
- ストップ: パーセンテージベースのテイクプロフィットとストップロス
- デフォルト値:
FastLength= 9SlowLength= 21RsiLength= 14RsiLevel= 50mTakeProfitPercent= 2mStopLossPercent= 1mCandleType= TimeSpan.FromMinutes(5).TimeFrame()
- フィルター:
- カテゴリ: トレンド
- 方向: ロングのみ
- インジケーター: EMA, RSI
- ストップ: はい
- 複雑さ: 初心者
- 時間軸: 中期
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
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>
/// EMA RSI trend reversal strategy.
/// Long only: buys when the fast EMA crosses above the slow EMA with RSI above RsiLevel and closes the long when the fast EMA
/// crosses below the slow EMA with RSI below RsiLevel. Percent take profit and stop loss protect the position.
/// </summary>
public class EmaRsiTrendReversalStrategy : Strategy
{
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<decimal> _rsiLevel;
private readonly StrategyParam<decimal> _takeProfitPercent;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevFast;
private decimal? _prevSlow;
/// <summary>
/// Fast EMA length.
/// </summary>
public int FastLength
{
get => _fastLength.Value;
set => _fastLength.Value = value;
}
/// <summary>
/// Slow EMA length.
/// </summary>
public int SlowLength
{
get => _slowLength.Value;
set => _slowLength.Value = value;
}
/// <summary>
/// RSI length.
/// </summary>
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
/// <summary>
/// RSI level that confirms entries and exits.
/// </summary>
public decimal RsiLevel
{
get => _rsiLevel.Value;
set => _rsiLevel.Value = value;
}
/// <summary>
/// Take profit percentage from entry price.
/// </summary>
public decimal TakeProfitPercent
{
get => _takeProfitPercent.Value;
set => _takeProfitPercent.Value = value;
}
/// <summary>
/// Stop loss percentage from entry price.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public EmaRsiTrendReversalStrategy()
{
_fastLength = Param(nameof(FastLength), 9)
.SetGreaterThanZero()
.SetDisplay("Fast EMA", "Fast EMA length", "Indicators");
_slowLength = Param(nameof(SlowLength), 21)
.SetGreaterThanZero()
.SetDisplay("Slow EMA", "Slow EMA length", "Indicators");
_rsiLength = Param(nameof(RsiLength), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "RSI length", "Indicators");
_rsiLevel = Param(nameof(RsiLevel), 50m)
.SetDisplay("RSI Level", "RSI level that confirms entries and exits", "Indicators");
_takeProfitPercent = Param(nameof(TakeProfitPercent), 2m)
.SetNotNegative()
.SetDisplay("Take Profit %", "Take profit percentage from entry price", "Risk");
_stopLossPercent = Param(nameof(StopLossPercent), 1m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).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();
_prevFast = null;
_prevSlow = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = null;
_prevSlow = null;
var fast = new ExponentialMovingAverage { Length = FastLength };
var slow = new ExponentialMovingAverage { Length = SlowLength };
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, rsi, ProcessCandle)
.Start();
StartProtection(
TakeProfitPercent > 0m ? new Unit(TakeProfitPercent, UnitTypes.Percent) : new Unit(),
StopLossPercent > 0m ? new Unit(StopLossPercent, UnitTypes.Percent) : new Unit(),
useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
DrawOwnTrades(area);
var oscillators = CreateChartArea();
if (oscillators != null)
DrawIndicator(oscillators, rsi);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow, decimal rsi)
{
if (candle.State != CandleStates.Finished)
return;
var prevFast = _prevFast;
var prevSlow = _prevSlow;
_prevFast = fast;
_prevSlow = slow;
if (prevFast is not decimal pf || prevSlow is not decimal ps)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (Position == 0 && pf <= ps && fast > slow && rsi > RsiLevel)
BuyMarket(Volume);
else if (Position > 0 && pf >= ps && fast < slow && rsi < RsiLevel)
SellMarket(Position);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import ExponentialMovingAverage, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class ema_rsi_trend_reversal_strategy(Strategy):
"""
EMA RSI trend reversal strategy.
Long only: buys when the fast EMA crosses above the slow EMA with RSI above RsiLevel and closes the long when the fast EMA
crosses below the slow EMA with RSI below RsiLevel. Percent take profit and stop loss protect the position.
"""
def __init__(self):
super(ema_rsi_trend_reversal_strategy, self).__init__()
self._fast_length = self.Param("FastLength", 9).SetGreaterThanZero().SetDisplay("Fast EMA", "Fast EMA length", "Indicators")
self._slow_length = self.Param("SlowLength", 21).SetGreaterThanZero().SetDisplay("Slow EMA", "Slow EMA length", "Indicators")
self._rsi_length = self.Param("RsiLength", 14).SetGreaterThanZero().SetDisplay("RSI Length", "RSI length", "Indicators")
self._rsi_level = self.Param("RsiLevel", 50.0).SetDisplay("RSI Level", "RSI level that confirms entries and exits", "Indicators")
self._take_profit_percent = self.Param("TakeProfitPercent", 2.0).SetNotNegative().SetDisplay("Take Profit %", "Take profit percentage from entry price", "Risk")
self._stop_loss_percent = self.Param("StopLossPercent", 1.0).SetNotNegative().SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._prev_fast = None
self._prev_slow = None
def OnReseted(self):
super(ema_rsi_trend_reversal_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(ema_rsi_trend_reversal_strategy, self).OnStarted2(time)
self._reset_state()
fast = ExponentialMovingAverage()
fast.Length = self._fast_length.Value
slow = ExponentialMovingAverage()
slow.Length = self._slow_length.Value
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast, slow, rsi, self._process_candle).Start()
take = float(self._take_profit_percent.Value)
stop = float(self._stop_loss_percent.Value)
self.StartProtection(
Unit(Decimal(take), UnitTypes.Percent) if take > 0 else Unit(),
Unit(Decimal(stop), UnitTypes.Percent) if stop > 0 else Unit(),
useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
oscillators = self.CreateChartArea()
if oscillators is not None:
self.DrawIndicator(oscillators, rsi)
def _process_candle(self, candle, fast_value, slow_value, rsi_value):
if candle.State != CandleStates.Finished:
return
fast = float(fast_value)
slow = float(slow_value)
rsi = float(rsi_value)
prev_fast = self._prev_fast
prev_slow = self._prev_slow
self._prev_fast = fast
self._prev_slow = slow
if prev_fast is None or prev_slow is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
level = float(self._rsi_level.Value)
if self.Position == 0 and prev_fast <= prev_slow and fast > slow and rsi > level:
self.BuyMarket(self.Volume)
elif self.Position > 0 and prev_fast >= prev_slow and fast < slow and rsi < level:
self.SellMarket(self.Position)
def CreateClone(self):
return ema_rsi_trend_reversal_strategy()