GitHub で見る
DeMarker ポジション獲得ボリューム 2 戦略
この戦略は、StockSharp のハイレベル API を使用して、MetaTrader 5 エキスパート アドバイザー 「DeMarker のポジション獲得ボリューム 2」 を再現します。 DeMarker オシレーターを使用して設定可能なローソク足シリーズを分析し、値が極端なゾーンに入ると反応します。この実装では、固定ロット サイズ設定、オプションのシグナル反転、組み込みのストップロス/テイクプロフィット処理、オプションの取引セッション フィルターなど、元の資金管理の特徴が維持されています。
専門家の本来の動作
- プラットフォーム: MetaTrader 5.
- インジケーター: クラシック DeMarker オシレーター (
DEM)、デフォルト期間 14。
- エントリー: DeMarker が下限しきい値を下回るとロングがオープンし、上限しきい値を上回るとショートがオープンします。
- リスクコントロール: ポイントで表現される固定ストップロス/テイクプロフィット、オプションのステップ付きトレーリングストップ、オプションの時間枠。
- ポジション管理: バーごとに 1 つのトレードのみを保証し、方向を反転する前に反対側をクローズします。
StockSharp 変換も同じ原則に従います。プロテクション注文は StartProtection で実装されるため、ポジションがオープンされるとストップロス、テイクプロフィット、トレーリングが自動的に管理されます。
取引ロジック
- 構成されたローソク足タイプ (
CandleType、デフォルトでは 5 分足ローソク足) をサブスクライブし、選択した期間 (DeMarkerPeriod) で DeMarker 値を計算します。
- ローソク足が閉じたら、オシレーターを評価します。
ReverseSignals が false の場合 (デフォルト):
- 長いセットアップ –
DeMarker <= LowerLevel。
- 簡単なセットアップ –
DeMarker >= UpperLevel。
ReverseSignals が true の場合、ロング/ショート ルールが入れ替わります。
UseTimeFilter が有効な場合は、SessionStart/SessionEnd で定義されたオプションのセッション ウィンドウ内でのみ取引します。夜間のセッションもサポートされています。
- キャンドルごとに最大 1 つの新しいエントリを実行します。新しいポジションを開く前に、この戦略は MT5 ロジックを反映するために反対の保有をすべて閉じます。
- 音量は
TradeVolume パラメータによって固定されます。戦略がすでに部分的に望ましい方向に進んでいる場合は、要求されたボリュームまで補充されます。
リスク管理
StopLossPoints と TakeProfitPoints (価格ステップ内) は、エキスパートのポイントベースのストップ距離とテイクプロフィット距離にマッピングされます。
EnableTrailing を有効にすると、停止距離が TrailingStopPoints に切り替わり、調整ステップとして TrailingStepPoints を使用して内蔵のトレーリング エンジンが有効になります。
StartProtection は useMarketOrders = true で構成されているため、MT5 の取引終了動作と同様に、保護注文がすぐに実行されます。
パラメーター
| パラメータ |
説明 |
DeMarkerPeriod |
DeMarker インジケーターの平均期間。 |
UpperLevel / LowerLevel |
買われすぎ/売られすぎの閾値によりショート/ロングが引き起こされます。 |
ReverseSignals |
ロング条件とショート条件を入れ替えます。 |
StopLossPoints |
価格ステップで測定される初期保護停止距離。 |
TakeProfitPoints |
価格ステップで測定される利食い距離。 |
EnableTrailing |
トレーリングストップブロックを有効にします。 |
TrailingStopPoints |
トレーリングがアクティブになった後のトレーリング ストップの距離。 |
TrailingStepPoints |
トレーリングストップが前進する前の最小限の有利な動き。 |
UseTimeFilter |
取引を SessionStart~SessionEnd ウィンドウに制限します。 |
SessionStart / SessionEnd |
包括的/排他的セッション境界 (ラップアラウンドをサポート)。 |
TradeVolume |
各成行注文で送信する数量。 |
CandleType |
分析するローソク足シリーズ (デフォルトは 5 分)。 |
実装メモ
- MT5 エキスパートには、「トレーリング アクティベーション」のしきい値が含まれていました。 StockSharp の標準のトレーリング保護は同じパラメータを公開しないため、
EnableTrailing が true の場合、トレーリングはすぐにアクティブになります。
- 無効なロットサイズ、凍結レベル、入札/売値更新ロジックのエラー処理は、StockSharp のインフラストラクチャによって処理されるため、変換から省略されます。
- ロギングは、基本クラス
Strategy を介して実行されます (追加のトレースが必要な場合は、LogInfo/LogError を呼び出します)。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// Strategy converted from "DeMarker gaining position volume 2" expert advisor.
/// Uses DeMarker oscillator thresholds for entry signals.
/// </summary>
public class DeMarkerGainingPositionVolume2Strategy : Strategy
{
private readonly StrategyParam<int> _deMarkerPeriod;
private readonly StrategyParam<decimal> _upperLevel;
private readonly StrategyParam<decimal> _lowerLevel;
private readonly StrategyParam<DataType> _candleType;
private RelativeStrengthIndex _rsi;
private decimal? _prevOscillator;
/// <summary>
/// DeMarker averaging period.
/// </summary>
public int DeMarkerPeriod
{
get => _deMarkerPeriod.Value;
set => _deMarkerPeriod.Value = value;
}
/// <summary>
/// Upper DeMarker threshold.
/// </summary>
public decimal UpperLevel
{
get => _upperLevel.Value;
set => _upperLevel.Value = value;
}
/// <summary>
/// Lower DeMarker threshold.
/// </summary>
public decimal LowerLevel
{
get => _lowerLevel.Value;
set => _lowerLevel.Value = value;
}
/// <summary>
/// Candle type for DeMarker calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public DeMarkerGainingPositionVolume2Strategy()
{
_deMarkerPeriod = Param(nameof(DeMarkerPeriod), 14)
.SetDisplay("DeMarker Period", "Number of bars used by the oscillator.", "Indicator");
_upperLevel = Param(nameof(UpperLevel), 0.7m)
.SetDisplay("Upper Level", "Overbought threshold.", "Indicator");
_lowerLevel = Param(nameof(LowerLevel), 0.3m)
.SetDisplay("Lower Level", "Oversold threshold.", "Indicator");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for calculations.", "Data");
}
/// <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;
}
var oscillatorValue = rsiValue / 100m;
var volume = Volume;
if (volume <= 0)
volume = 1;
// Cross below lower level => oversold => buy
if (_prevOscillator is decimal prev)
{
var crossBelow = prev >= LowerLevel && oscillatorValue < LowerLevel;
var crossAbove = prev <= UpperLevel && oscillatorValue > UpperLevel;
if (crossBelow)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
else if (crossAbove)
{
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_gaining_position_volume2_strategy(Strategy):
def __init__(self):
super(de_marker_gaining_position_volume2_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._demarker_period = self.Param("DeMarkerPeriod", 14)
self._upper_level = self.Param("UpperLevel", 0.7)
self._lower_level = self.Param("LowerLevel", 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 UpperLevel(self):
return self._upper_level.Value
@UpperLevel.setter
def UpperLevel(self, value):
self._upper_level.Value = value
@property
def LowerLevel(self):
return self._lower_level.Value
@LowerLevel.setter
def LowerLevel(self, value):
self._lower_level.Value = value
def OnReseted(self):
super(de_marker_gaining_position_volume2_strategy, self).OnReseted()
self._prev_osc = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(de_marker_gaining_position_volume2_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.UpperLevel)
lower = float(self.LowerLevel)
if self._has_prev:
# Cross below lower => oversold => buy
cross_below = self._prev_osc >= lower and osc_val < lower
# Cross above upper => overbought => sell
cross_above = self._prev_osc <= upper and osc_val > upper
if cross_below and self.Position <= 0:
self.BuyMarket()
elif cross_above and self.Position >= 0:
self.SellMarket()
self._prev_osc = osc_val
self._has_prev = True
def CreateClone(self):
return de_marker_gaining_position_volume2_strategy()