GitHub で見る
XRSI DeMarker ヒストグラム戦略
概要
この戦略はエキスパートアドバイザー Exp_XRSIDeMarker_Histogram を再現します。相対強度指数(RSI)とDeMarkerインジケーターを組み合わせ、結果を平滑化するカスタムオシレーターで検出された反転を取引します。システムはロングとショートのトレードを独立して開閉でき、価格ステップで表現されたオプションの保護ストップをサポートします。
インジケーターの構成
- 適用価格 – RSIは設定された期間を使用して選択された入力(終値、始値、高値、安値、中値、典型的または加重価格)で計算されます。
- DeMarkerコンポーネント – 完成した各ローソク足について、戦略は上昇(
deMax)と下降(deMin)圧力を測定します:
deMax = max(High_t - High_{t-1}, 0)
deMin = max(Low_{t-1} - Low_t, 0)
両方のシリーズはRSI期間と同じ長さの単純移動平均で平滑化されます。
DeMarker = deMaxAvg / (deMaxAvg + deMinAvg)(0–100の範囲にスケーリング)。
- 複合オシレーター – 最終値は
(RSI + 100 * DeMarker) / 2です。
- 平滑化 – 複合オシレーターはサポートされている移動平均(SMA、EMA、SMMA、LWMA、またはJurik)の1つを通過します。オリジナルMQLバージョンからサポートされていない平滑化モードが選択された場合、インジケーターは要求された長さのEMAにフォールバックします。Jurikオプションはフェーズパラメーターも考慮します。
- シグナル履歴 – 戦略は履歴値を保存し、
SignalBarで定義されたバーのシグナルを評価します。これは取引前に次のローソク足を待つオリジナルEAを模倣します。
トレードロジック
- 強気の反転
- 条件:
SignalBar+1の値がSignalBar+2より低く(下降傾向)、SignalBarの値が再び上昇(>=)。
- アクション:
CloseShortOnLongSignalが真の場合、既存のショートトレードを閉じます。
AllowBuyEntriesが有効な場合、TradeVolumeで新しいロングトレードを開きます(ショートからの反転に必要な数量を加算)。
- 弱気の反転
- 条件:
SignalBar+1の値がSignalBar+2より高く(上昇傾向)、SignalBarの値が下降(<=)。
- アクション:
CloseLongOnShortSignalが真の場合、既存のロングトレードを閉じます。
AllowSellEntriesが有効な場合、新しいショートトレードを開きます。
- インジケーターとDeMarkerコンポーネントが完全に形成されるまでシグナルは無視され、戦略がオンラインでトレードが許可されている場合のみ注文が置かれます。
リスク管理
StopLossTicksとTakeProfitTicksは価格ステップの距離を表します。戦略はこれらの値をSecurity.PriceStepで掛けます(インストゥルメントステップが不明な場合は1にフォールバック)、ローソク足の範囲内で距離に達したときにポジションを閉じます。
0を渡すと対応する保護が無効になります。
TradeVolumeパラメーターはデフォルトの注文サイズとして使用され、反転の計算にも使われます(反対のポジションが新しいポジションを開く前に閉じられます)。
パラメーター
| パラメーター |
説明 |
デフォルト値 |
TradeVolume |
新しいポジションを開く際のボリューム。 |
0.1 |
StopLossTicks |
価格ステップでの保護ストップ。 |
1000 |
TakeProfitTicks |
価格ステップでの利益目標。 |
2000 |
AllowBuyEntries |
ロングトレードの有効化/無効化。 |
true |
AllowSellEntries |
ショートトレードの有効化/無効化。 |
true |
CloseLongOnShortSignal |
ショートシグナルが表示されたときにロングを閉じる。 |
true |
CloseShortOnLongSignal |
ロングシグナルが表示されたときにショートを閉じる。 |
true |
CandleType |
分析に使用するタイムフレーム(デフォルト4時間ローソク足)。 |
H4 |
IndicatorPeriod |
RSIとDeMarkerコンポーネントのルックバック。 |
14 |
AppliedPriceSelection |
RSI計算で使用される適用価格。 |
Close |
SmoothingMethodSelection |
平滑化に使用する移動平均(SMA/EMA/SMMA/LWMA/Jurik/Adaptive)。 |
Sma |
SmoothingLength |
平滑化平均の期間。 |
5 |
SmoothingPhase |
Jurik平滑化に渡されるフェーズ引数。 |
15 |
SignalBar |
シグナル評価に使用される閉じたバーの数。 |
1 |
オリジナルEAとの相違点
- MQLバージョンの資金管理モード(残高ベース、フリーマージンベースなど)は直接の
TradeVolumeパラメーターに置き換えられます。
- StockSharpは成行注文を使用するため、注文スリッページ(
Deviation)は不要です。
- 高度な平滑化アルゴリズム(放物線MA、T3、VIDYA、AMA)はStockSharpでは利用できず、
Adaptiveオプションを介してEMAにマッピングされます。
- C#ソースコードのすべてのコメントは英語で書かれており、ロジックはオリジナルの実装と同様に完成したローソク足のみで実行されます。
namespace StockSharp.Samples.Strategies;
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// XRSI DeMarker Histogram strategy (simplified).
/// Uses RSI combined with momentum to detect reversals.
/// Buys on RSI reversal from oversold, sells on reversal from overbought.
/// </summary>
public class XrsidDeMarkerHistogramStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _smaPeriod;
private decimal _prevRsi;
private decimal _prevPrevRsi;
private bool _initialized;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
public int SmaPeriod
{
get => _smaPeriod.Value;
set => _smaPeriod.Value = value;
}
public XrsidDeMarkerHistogramStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Source candles", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI indicator period", "Indicators");
_smaPeriod = Param(nameof(SmaPeriod), 5)
.SetGreaterThanZero()
.SetDisplay("SMA Period", "Smoothing period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevRsi = 0m;
_prevPrevRsi = 0m;
_initialized = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevRsi = 0;
_prevPrevRsi = 0;
_initialized = false;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var sma = new SimpleMovingAverage { Length = SmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, sma, (ICandleMessage candle, decimal rsiValue, decimal smaValue) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!_initialized)
{
_prevPrevRsi = rsiValue;
_prevRsi = rsiValue;
_initialized = true;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevPrevRsi = _prevRsi;
_prevRsi = rsiValue;
return;
}
// Buy on RSI reversal from oversold (V-bottom)
var buySignal = _prevPrevRsi > _prevRsi && rsiValue >= _prevRsi && _prevRsi < 35m;
// Sell on RSI reversal from overbought (inverse V)
var sellSignal = _prevPrevRsi < _prevRsi && rsiValue <= _prevRsi && _prevRsi > 65m;
if (buySignal && Position <= 0)
{
BuyMarket();
}
else if (sellSignal && Position >= 0)
{
SellMarket();
}
_prevPrevRsi = _prevRsi;
_prevRsi = rsiValue;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, rsi);
DrawIndicator(area, sma);
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, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class xrsid_de_marker_histogram_strategy(Strategy):
def __init__(self):
super(xrsid_de_marker_histogram_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Source candles", "General")
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI indicator period", "Indicators")
self._sma_period = self.Param("SmaPeriod", 5) \
.SetDisplay("SMA Period", "Smoothing period", "Indicators")
self._prev_rsi = 0.0
self._prev_prev_rsi = 0.0
self._initialized = False
@property
def CandleType(self):
return self._candle_type.Value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@property
def SmaPeriod(self):
return self._sma_period.Value
def OnReseted(self):
super(xrsid_de_marker_histogram_strategy, self).OnReseted()
self._prev_rsi = 0.0
self._prev_prev_rsi = 0.0
self._initialized = False
def OnStarted2(self, time):
super(xrsid_de_marker_histogram_strategy, self).OnStarted2(time)
self._prev_rsi = 0.0
self._prev_prev_rsi = 0.0
self._initialized = False
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
sma = SimpleMovingAverage()
sma.Length = self.SmaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription \
.Bind(rsi, sma, self._on_process) \
.Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, rsi)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def _on_process(self, candle, rsi_value, sma_value):
if candle.State != CandleStates.Finished:
return
rv = float(rsi_value)
if not self._initialized:
self._prev_prev_rsi = rv
self._prev_rsi = rv
self._initialized = True
return
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_prev_rsi = self._prev_rsi
self._prev_rsi = rv
return
buy_signal = self._prev_prev_rsi > self._prev_rsi and rv >= self._prev_rsi and self._prev_rsi < 35.0
sell_signal = self._prev_prev_rsi < self._prev_rsi and rv <= self._prev_rsi and self._prev_rsi > 65.0
if buy_signal and self.Position <= 0:
self.BuyMarket()
elif sell_signal and self.Position >= 0:
self.SellMarket()
self._prev_prev_rsi = self._prev_rsi
self._prev_rsi = rv
def CreateClone(self):
return xrsid_de_marker_histogram_strategy()