ゴールドRSIダイバージェンス戦略
ゴールドRSIダイバージェンス戦略は、価格と相対力指数(RSI)の間の強気・弱気ダイバージェンスを識別することで、ゴールドをスキャルピングします。 価格が新しい安値を付けながらRSIがより高い安値を示すとき、戦略は買いを探します。 逆に、価格が新しい高値を付けながらRSIがより低い高値を示すとき、戦略は売ります。 両方のセットアップは、設定可能なバー範囲内に2つのピボットが発生した場合にのみ確認されます。
詳細
- エントリー条件:
- ロング: 価格が低い安値、RSIが高い安値、RSI < 40。
- ショート: 価格が高い高値、RSIが低い高値、RSI > 60。
- ロング/ショート: 両方。
- エグジット条件:
- ストップロスとテイクプロフィットを使用。
- ストップ: pipsでの固定ストップロスとテイクプロフィット。
- デフォルト値:
RsiLength= 60StopLossPips= 11TakeProfitPips= 33
- フィルター:
- カテゴリ: ダイバージェンス
- 方向: 両方
- インジケーター: 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>
/// Gold RSI Divergence strategy.
/// RSI pivots are confirmed LookbackLeft bars before and LookbackRight bars after them. A pivot low whose RSI is higher than the
/// previous pivot low while price made a lower low, within RangeLower..RangeUpper bars of it and with RSI below 40, buys; the mirrored
/// bearish divergence with RSI above 60 sells. Positions are closed by a fixed stop loss and take profit in pips.
/// </summary>
public class GoldRsiDivergenceStrategy : Strategy
{
private const decimal _longRsiLimit = 40m;
private const decimal _shortRsiLimit = 60m;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<int> _lookbackLeft;
private readonly StrategyParam<int> _lookbackRight;
private readonly StrategyParam<int> _rangeLower;
private readonly StrategyParam<int> _rangeUpper;
private readonly StrategyParam<decimal> _stopLossPips;
private readonly StrategyParam<decimal> _takeProfitPips;
private readonly StrategyParam<DataType> _candleType;
private readonly List<(decimal rsi, decimal low, decimal high)> _window = [];
private int _barIndex;
private (decimal rsi, decimal low, int bar)? _lastPivotLow;
private (decimal rsi, decimal high, int bar)? _lastPivotHigh;
/// <summary>
/// RSI period.
/// </summary>
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
/// <summary>
/// Bars to the left of a pivot.
/// </summary>
public int LookbackLeft
{
get => _lookbackLeft.Value;
set => _lookbackLeft.Value = value;
}
/// <summary>
/// Bars to the right of a pivot.
/// </summary>
public int LookbackRight
{
get => _lookbackRight.Value;
set => _lookbackRight.Value = value;
}
/// <summary>
/// Minimum bars between two pivots.
/// </summary>
public int RangeLower
{
get => _rangeLower.Value;
set => _rangeLower.Value = value;
}
/// <summary>
/// Maximum bars between two pivots.
/// </summary>
public int RangeUpper
{
get => _rangeUpper.Value;
set => _rangeUpper.Value = value;
}
/// <summary>
/// Stop loss in pips (price steps).
/// </summary>
public decimal StopLossPips
{
get => _stopLossPips.Value;
set => _stopLossPips.Value = value;
}
/// <summary>
/// Take profit in pips (price steps).
/// </summary>
public decimal TakeProfitPips
{
get => _takeProfitPips.Value;
set => _takeProfitPips.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public GoldRsiDivergenceStrategy()
{
_rsiLength = Param(nameof(RsiLength), 60)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "RSI period", "RSI");
_lookbackLeft = Param(nameof(LookbackLeft), 5)
.SetGreaterThanZero()
.SetDisplay("Lookback Left", "Bars to the left of a pivot", "Divergence");
_lookbackRight = Param(nameof(LookbackRight), 5)
.SetGreaterThanZero()
.SetDisplay("Lookback Right", "Bars to the right of a pivot", "Divergence");
_rangeLower = Param(nameof(RangeLower), 5)
.SetNotNegative()
.SetDisplay("Range Lower", "Minimum bars between two pivots", "Divergence");
_rangeUpper = Param(nameof(RangeUpper), 60)
.SetGreaterThanZero()
.SetDisplay("Range Upper", "Maximum bars between two pivots", "Divergence");
_stopLossPips = Param(nameof(StopLossPips), 11m)
.SetNotNegative()
.SetDisplay("Stop Loss Pips", "Stop loss in pips (price steps)", "Risk");
_takeProfitPips = Param(nameof(TakeProfitPips), 33m)
.SetNotNegative()
.SetDisplay("Take Profit Pips", "Take profit in pips (price steps)", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).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();
ResetState();
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetState();
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(rsi, ProcessCandle)
.Start();
var step = Security.PriceStep ?? 1m;
StartProtection(new Unit(TakeProfitPips * step, UnitTypes.Absolute), new Unit(StopLossPips * step, UnitTypes.Absolute), useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
var oscillators = CreateChartArea();
if (oscillators != null)
DrawIndicator(oscillators, rsi);
}
}
private void ResetState()
{
_window.Clear();
_barIndex = 0;
_lastPivotLow = null;
_lastPivotHigh = null;
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!rsiValue.IsFormed)
return;
var rsi = rsiValue.ToDecimal();
_barIndex++;
_window.Add((rsi, candle.LowPrice, candle.HighPrice));
var size = LookbackLeft + LookbackRight + 1;
if (_window.Count > size)
_window.RemoveAt(0);
if (_window.Count < size)
return;
var pivot = _window[LookbackLeft];
var pivotBar = _barIndex - LookbackRight;
var isPivotLow = true;
var isPivotHigh = true;
for (var i = 0; i < size; i++)
{
if (i == LookbackLeft)
continue;
if (_window[i].rsi <= pivot.rsi)
isPivotLow = false;
if (_window[i].rsi >= pivot.rsi)
isPivotHigh = false;
}
var canTrade = IsFormedAndOnlineAndAllowTrading();
if (isPivotLow)
{
var bullish = _lastPivotLow is { } prev
&& InRange(pivotBar - prev.bar)
&& pivot.rsi > prev.rsi
&& pivot.low < prev.low;
if (canTrade && bullish && rsi < _longRsiLimit && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
_lastPivotLow = (pivot.rsi, pivot.low, pivotBar);
}
if (isPivotHigh)
{
var bearish = _lastPivotHigh is { } prev
&& InRange(pivotBar - prev.bar)
&& pivot.rsi < prev.rsi
&& pivot.high > prev.high;
if (canTrade && bearish && rsi > _shortRsiLimit && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
_lastPivotHigh = (pivot.rsi, pivot.high, pivotBar);
}
}
private bool InRange(int bars) => bars >= RangeLower && bars <= RangeUpper;
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
LONG_RSI_LIMIT = 40
SHORT_RSI_LIMIT = 60
class gold_rsi_divergence_strategy(Strategy):
"""
Gold RSI Divergence strategy.
RSI pivots are confirmed LookbackLeft bars before and LookbackRight bars after them. A pivot low whose RSI is higher than the
previous pivot low while price made a lower low, within RangeLower..RangeUpper bars of it and with RSI below 40, buys; the mirrored
bearish divergence with RSI above 60 sells. Positions are closed by a fixed stop loss and take profit in pips.
"""
def __init__(self):
super(gold_rsi_divergence_strategy, self).__init__()
self._rsi_length = self.Param("RsiLength", 60).SetGreaterThanZero().SetDisplay("RSI Length", "RSI period", "RSI")
self._lookback_left = self.Param("LookbackLeft", 5).SetGreaterThanZero().SetDisplay("Lookback Left", "Bars to the left of a pivot", "Divergence")
self._lookback_right = self.Param("LookbackRight", 5).SetGreaterThanZero().SetDisplay("Lookback Right", "Bars to the right of a pivot", "Divergence")
self._range_lower = self.Param("RangeLower", 5).SetNotNegative().SetDisplay("Range Lower", "Minimum bars between two pivots", "Divergence")
self._range_upper = self.Param("RangeUpper", 60).SetGreaterThanZero().SetDisplay("Range Upper", "Maximum bars between two pivots", "Divergence")
self._stop_loss_pips = self.Param("StopLossPips", 11.0).SetNotNegative().SetDisplay("Stop Loss Pips", "Stop loss in pips (price steps)", "Risk")
self._take_profit_pips = self.Param("TakeProfitPips", 33.0).SetNotNegative().SetDisplay("Take Profit Pips", "Take profit in pips (price steps)", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))).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._window = []
self._bar_index = 0
self._last_pivot_low = None
self._last_pivot_high = None
def OnReseted(self):
super(gold_rsi_divergence_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(gold_rsi_divergence_strategy, self).OnStarted2(time)
self._reset_state()
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(rsi, self._process_candle).Start()
step = self.Security.PriceStep if self.Security.PriceStep is not None else Decimal(1)
take = Decimal(self._take_profit_pips.Value) * step
stop = Decimal(self._stop_loss_pips.Value) * step
self.StartProtection(Unit(take, UnitTypes.Absolute), Unit(stop, UnitTypes.Absolute), useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
oscillators = self.CreateChartArea()
if oscillators is not None:
self.DrawIndicator(oscillators, rsi)
def _in_range(self, bars):
return self._range_lower.Value <= bars <= self._range_upper.Value
def _process_candle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
if not rsi_value.IsFormed:
return
rsi = rsi_value.GetValue[Decimal](None)
self._bar_index += 1
left = self._lookback_left.Value
right = self._lookback_right.Value
size = left + right + 1
self._window.append((rsi, candle.LowPrice, candle.HighPrice))
if len(self._window) > size:
self._window.pop(0)
if len(self._window) < size:
return
pivot_rsi, pivot_low, pivot_high = self._window[left]
pivot_bar = self._bar_index - right
is_pivot_low = True
is_pivot_high = True
for i in range(size):
if i == left:
continue
if self._window[i][0] <= pivot_rsi:
is_pivot_low = False
if self._window[i][0] >= pivot_rsi:
is_pivot_high = False
can_trade = self.IsFormedAndOnlineAndAllowTrading()
if is_pivot_low:
prev = self._last_pivot_low
bullish = (prev is not None and self._in_range(pivot_bar - prev[2])
and pivot_rsi > prev[0] and pivot_low < prev[1])
if can_trade and bullish and rsi < LONG_RSI_LIMIT and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
self._last_pivot_low = (pivot_rsi, pivot_low, pivot_bar)
if is_pivot_high:
prev = self._last_pivot_high
bearish = (prev is not None and self._in_range(pivot_bar - prev[2])
and pivot_rsi < prev[0] and pivot_high > prev[1])
if can_trade and bearish and rsi > SHORT_RSI_LIMIT and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
self._last_pivot_high = (pivot_rsi, pivot_high, pivot_bar)
def CreateClone(self):
return gold_rsi_divergence_strategy()