GitHub で見る
DeMarker 保留中の戦略
概要
この StockSharp 戦略は、MetaTrader エキスパート アドバイザー「DeMarker Pending 2.5」の動作を再現します。ボットは、設定可能な時間枠で DeMarker オシレーターを評価し、極端なレベルを超えると、ブレイクアウト方向に指値注文を出します。注文は、固定ポイント数でオフセットされたストップ注文または指値注文のいずれかになります。オプションの取引ウィンドウのフィルタリングと自動有効期限により、未決注文を元のエキスパートの行動に合わせた状態に保つことができます。
取引ロジック
- 選択したローソク足シリーズをサブスクライブし、期間
DemarkerPeriod で DeMarker インジケーターを計算します。
- 現在および以前の終了ローソク足の値を使用して、下限 (
DemarkerLowerLevel) と上限 (DemarkerUpperLevel) のしきい値のクロスオーバーを検出します。
- 下のレベルが上にクロスすると、長いセットアップをキューに入れます。上のレベルが下にクロスしたら、短いセットアップをキューに入れます。
Modeに応じて、ブレークアウトモードの逆指値注文またはプルバックエントリーの指値注文を使用して、セットアップを価格Close ± PendingIndentPoints * PriceStepの未決注文に変換します。
- エントリー価格を
StopLossPoints ポイントと TakeProfitPoints ポイントオフセットすることで、ストップロスとテイクプロフィットのレベルを未決注文に付加します。
- 新しい保留中の注文を登録する前に、
ReplacePreviousPending と SinglePendingOnly に従って古い保留中の注文をキャンセルまたは再利用してください。
PendingExpirationMinutes の有効期間が経過すると、保留中の注文が自動的に削除されます。
UseTimeWindow が有効な場合、日中ウィンドウ外のシグナルを無視します。すべてのバーは 1 回だけ処理されるため、バーおよび方向ごとに最大 1 つの新しい未決注文が作成されます。
注文管理
- すべてのエントリは未決注文として作成されます (
BuyStop、SellStop、BuyLimit、SellLimit)。
- 各未決注文には独自のストップロス価格とテイクプロフィット価格が設定されているため、アクティブ化直後にポジションが保護されます。
- 保留中の注文は、有効期限が切れたとき、新しい設定に置き換えられたとき、または注文の状態が非アクティブなステータス (約定、キャンセル、拒否) に変化したときにキャンセルされます。
パラメーター
| パラメータ |
説明 |
Volume |
ロット単位での注文量。 |
StopLossPoints |
エントリー価格とストップロスの間の距離(ポイント単位)。 |
TakeProfitPoints |
エントリー価格とテイクプロフィットの間の距離(ポイント単位)。 |
PendingIndentPoints |
市場価格と未決注文の間のオフセット。 |
PendingExpirationMinutes |
各未決注文の存続期間 (分単位) (0 は有効期限を無効にします)。 |
Mode |
未決注文のタイプ (ブレイクアウトの場合はストップ、プルバックの場合はリミット)。 |
SinglePendingOnly |
有効にすると、複数のアクティブな未決注文を発注できなくなります。 |
ReplacePreviousPending |
新しい注文を発行する前に、アクティブな未決注文をキャンセルします。 |
DemarkerPeriod |
DeMarker オシレーターのルックバック期間。 |
DemarkerUpperLevel |
売り設定をトリガーする DeMarker しきい値。 |
DemarkerLowerLevel |
購入セットアップをトリガーする DeMarker しきい値。 |
CandleType |
ローソク足のサブスクリプションとインジケーターの評価に使用される時間枠。 |
UseTimeWindow |
日中の時間フィルタリングを有効にします。 |
StartTime |
日中取引ウィンドウの開始。 |
EndTime |
日中取引ウィンドウの終了。 |
注意事項
- オリジナルのエキスパートには、洗練された資金管理とトレーリングストップルーチンが含まれています。このポートはシグナル生成と未決注文の処理を維持しますが、ポジションのサイジングを単一の固定
Volume パラメーターに簡素化します。
- StockSharp は注文登録時にストップロス価格とテイクプロフィット価格を付加します。ブローカーによっては、ストップ注文と指値注文がこれらの保護レベルをサポートしているかどうかを確認する必要がある場合があります。
- ポイントベースの距離が取引シンボルの
PriceStep と互換性があることを常に確認してください。 PendingIndentPoints、StopLossPoints、および TakeProfitPoints をブローカーの最小距離要件を満たす値に設定します。
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simplified from the "DeMarker Pending 2.5" MetaTrader expert.
/// Uses DeMarker indicator level crossovers to generate buy/sell market signals.
/// Original used pending orders; this version uses market orders.
/// </summary>
public class DeMarkerPendingStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _demarkerPeriod;
private readonly StrategyParam<decimal> _demarkerUpper;
private readonly StrategyParam<decimal> _demarkerLower;
private RelativeStrengthIndex _rsi;
private decimal? _prevOscillator;
/// <summary>
/// Candle type used for signal evaluation.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// DeMarker indicator period.
/// </summary>
public int DemarkerPeriod
{
get => _demarkerPeriod.Value;
set => _demarkerPeriod.Value = value;
}
/// <summary>
/// Upper DeMarker threshold that triggers sell signals.
/// </summary>
public decimal DemarkerUpperLevel
{
get => _demarkerUpper.Value;
set => _demarkerUpper.Value = value;
}
/// <summary>
/// Lower DeMarker threshold that triggers buy signals.
/// </summary>
public decimal DemarkerLowerLevel
{
get => _demarkerLower.Value;
set => _demarkerLower.Value = value;
}
public DeMarkerPendingStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Timeframe used for signal evaluation", "General");
_demarkerPeriod = Param(nameof(DemarkerPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("DeMarker Period", "Averaging period for DeMarker indicator", "Indicator");
_demarkerUpper = Param(nameof(DemarkerUpperLevel), 0.7m)
.SetDisplay("Upper Level", "DeMarker value that triggers sell setup", "Indicator");
_demarkerLower = Param(nameof(DemarkerLowerLevel), 0.3m)
.SetDisplay("Lower Level", "DeMarker value that triggers buy setup", "Indicator");
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevOscillator = null;
_rsi = new RelativeStrengthIndex { Length = DemarkerPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_rsi.IsFormed)
{
_prevOscillator = rsiValue / 100m;
return;
}
if (_prevOscillator is null)
{
_prevOscillator = rsiValue / 100m;
return;
}
var oscillatorValue = rsiValue / 100m;
var volume = Volume;
if (volume <= 0)
volume = 1;
// DeMarker crosses below lower level -> buy signal
var crossDown = _prevOscillator.Value > DemarkerLowerLevel && oscillatorValue <= DemarkerLowerLevel;
// DeMarker crosses above upper level -> sell signal
var crossUp = _prevOscillator.Value < DemarkerUpperLevel && oscillatorValue >= DemarkerUpperLevel;
if (crossDown)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
else if (crossUp)
{
if (Position >= 0)
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
_prevOscillator = oscillatorValue;
}
/// <inheritdoc />
protected override void OnReseted()
{
_rsi = null;
_prevOscillator = null;
base.OnReseted();
}
}
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 de_marker_pending_strategy(Strategy):
def __init__(self):
super(de_marker_pending_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._demarker_period = self.Param("DemarkerPeriod", 14)
self._demarker_upper = self.Param("DemarkerUpperLevel", 0.7)
self._demarker_lower = self.Param("DemarkerLowerLevel", 0.3)
self._prev_osc = 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 DemarkerPeriod(self):
return self._demarker_period.Value
@DemarkerPeriod.setter
def DemarkerPeriod(self, value):
self._demarker_period.Value = value
@property
def DemarkerUpperLevel(self):
return self._demarker_upper.Value
@DemarkerUpperLevel.setter
def DemarkerUpperLevel(self, value):
self._demarker_upper.Value = value
@property
def DemarkerLowerLevel(self):
return self._demarker_lower.Value
@DemarkerLowerLevel.setter
def DemarkerLowerLevel(self, value):
self._demarker_lower.Value = value
def OnReseted(self):
super(de_marker_pending_strategy, self).OnReseted()
self._prev_osc = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(de_marker_pending_strategy, self).OnStarted2(time)
self._prev_osc = 0.0
self._has_prev = False
rsi = RelativeStrengthIndex()
rsi.Length = self.DemarkerPeriod
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
osc_val = float(rsi_value) / 100.0
upper = float(self.DemarkerUpperLevel)
lower = float(self.DemarkerLowerLevel)
if self._has_prev:
# Cross below lower level => buy
if self._prev_osc > lower and osc_val <= lower and self.Position <= 0:
self.BuyMarket()
# Cross above upper level => sell
elif self._prev_osc < upper and osc_val >= upper and self.Position >= 0:
self.SellMarket()
self._prev_osc = osc_val
self._has_prev = True
def CreateClone(self):
return de_marker_pending_strategy()