GitHub で見る
Trickerless RHMP 戦略 (StockSharp ポート)
この戦略は、MetaTrader エキスパート アドバイザー Trickerless RHMP を StockSharp の高レベル API に移植します。多段階を維持します
オリジナルロボットのエントリーロジック - 平均方向指数確認、平滑化移動平均構造、および
ボラティリティ主導のポジション管理 - AGENTS.md に記載されているフレームワーク規則に従います。
取引ロジック
指標
- 平均トゥルー レンジ (ATR) とボラティリティ サイズの設定可能な期間。
- トレンドの強さを評価するための完全な +DI/-DI コンポーネントを含む平均方向性インデックス (ADX)。
- 高速トレンド フィルターと低速トレンド フィルターを表す 2 つの平滑移動平均 (SMMA)。
トレンド評価
- 遅い SMMA の傾きは、
MinSlopePips…MaxSlopePips コリドー内にある必要があります (機器ピップで測定)。
- ADX は
AdxThreshold を超え、前のローソク足と比較して上昇する必要があります。
- 混雑を避けるために、料金は高速 SMMA から少なくとも
TrendSpacePips 離れた場所にある必要があります。
- 強気バイアスには、低速 SMMA を上回る高速 SMMA、+DI ≧ -DI、および高速平均の上昇が必要です。弱気バイアスはこれらを反映しています
小切手。
一次エントリ
- 強気 (または弱気) バイアスが有効な場合、戦略は、次の条件を考慮して、ボリューム
OrderVolume でロング (またはショート) 注文をオープンします。
MaxNetPositions し、エントリ間は少なくとも SleepInterval 待機します。
- 逆のネット ポジションが存在する場合は、ヘッジを無効のままにするために、最初にフラット化されます。
スパイクエントリー
- 現在のローソク足の範囲が前の範囲の
CandleSpikeMultiplier 倍を超えている場合、戦略は補助的なローソク足を発動できます。
ADX コンポーネントが一致すると、キャンドル本体の方向の位置が決まります。位置には OrderVolume * SpikeVolumeMultiplier が使用されます。
リスク管理
- ATR ベースのストップロス、テイクプロフィット、およびオプションのトレーリングストップ (
StopLossAtrMultiplier、TakeProfitAtrMultiplier、TrailingAtrMultiplier)。
- セッション全体の保護: 実現された損益が
DailyProfitTarget (開始資本の一部) に達すると、新しいエントリーはブロックされます。
- グローバル緊急スイッチ
EmergencyExit は、切り替えるとすぐにすべてのポジションを閉じます。
パラメーター
| 名前 |
説明 |
デフォルト |
CandleType |
すべての計算に使用される時間枠。 |
5分キャンドル |
OrderVolume |
各エントリの基本ボリューム。 |
0.03 |
AtrPeriod |
ATR ルックバックの長さ。 |
14 |
AdxPeriod |
ADX ルックバックの長さ。 |
14 |
AdxThreshold |
取引を可能にする最小の ADX 値。 |
10 |
FastMaPeriod |
高速平滑移動平均期間。 |
60 |
SlowMaPeriod |
ゆっくりとした平滑化移動平均期間。 |
120 |
MinSlopePips / MaxSlopePips |
低速 SMMA に許可されたスロープコリドー。 |
2/9 |
TrendSpacePips |
高速 SMMA からの最小価格距離 (ピップ単位)。 |
5 |
CandleSpikeMultiplier |
スパイクエントリーをトリガーするには、ローソク足の範囲がどのくらい大きくなければならないか。 |
7 |
TakeProfitAtrMultiplier |
利食いの場合は ATR 倍です。 |
1.0 |
StopLossAtrMultiplier |
ストップロスの倍数は ATR です。 |
1.5 |
TrailingAtrMultiplier |
トレーリングストップの ATR の倍数 (0 は無効になります)。 |
0 |
MaxNetPositions |
同時ネットポジションユニットの最大数。 |
1 |
SleepInterval |
連続するエントリ間の最小時間。 |
24分 |
DailyProfitTarget |
初期資本のうち、到達すると取引をブロックする割合。 |
0.045 |
AllowNewEntries |
エントリを有効/無効にするマスタースイッチ。 |
本当の |
SpikeVolumeMultiplier |
スパイクエントリーのボリューム乗数。 |
1.0 |
EmergencyExit |
true の場合、すべてのポジションを即座にクローズします。 |
偽 |
注意事項
- StockSharp ポートは、MetaTrader によるチケットごとのマイクロ管理ではなく、クリーンな高レベルの API に重点を置いています。すべて
資金管理ロジックは、
Volume および ATR ベースのレベルを通じて実装されます。
- 元の EA には、残高と証拠金のチェックがいくつかありました。これらは、
DailyProfitTarget、MaxNetPositions で近似されます。
および ATR のサイズ変更パラメータにより、MT4 アカウントを直接呼び出さなくても動作の調整が維持されます。
- この戦略では平滑化された平均が使用されるため、取引を評価する前に十分なウォームアップ期間があることを確認してください。
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 "Trickerless RHMP" MetaTrader expert.
/// Uses fast/slow EMA crossover for entries.
/// Fast EMA above slow = buy, below = sell.
/// </summary>
public class TrickerlessRhmpStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastMaPeriod;
private readonly StrategyParam<int> _slowMaPeriod;
private ExponentialMovingAverage _fastMa;
private ExponentialMovingAverage _slowMa;
private decimal? _prevFast;
private decimal? _prevSlow;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastMaPeriod
{
get => _fastMaPeriod.Value;
set => _fastMaPeriod.Value = value;
}
public int SlowMaPeriod
{
get => _slowMaPeriod.Value;
set => _slowMaPeriod.Value = value;
}
public TrickerlessRhmpStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Primary timeframe", "General");
_fastMaPeriod = Param(nameof(FastMaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Fast MA", "Fast EMA period", "Indicators");
_slowMaPeriod = Param(nameof(SlowMaPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("Slow MA", "Slow SMA period (computed manually)", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = null;
_prevSlow = null;
_fastMa = new ExponentialMovingAverage { Length = FastMaPeriod };
_slowMa = new ExponentialMovingAverage { Length = SlowMaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_fastMa, _slowMa, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _fastMa);
DrawIndicator(area, _slowMa);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_fastMa.IsFormed || !_slowMa.IsFormed)
{
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
if (_prevFast is null || _prevSlow is null)
{
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
var volume = Volume;
if (volume <= 0)
volume = 1;
var crossUp = _prevFast.Value <= _prevSlow.Value && fastValue > slowValue;
var crossDown = _prevFast.Value >= _prevSlow.Value && fastValue < slowValue;
if (crossUp)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
else if (crossDown)
{
if (Position >= 0)
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
_prevFast = fastValue;
_prevSlow = slowValue;
}
/// <inheritdoc />
protected override void OnReseted()
{
_fastMa = null;
_slowMa = null;
_prevFast = null;
_prevSlow = 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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class trickerless_rhmp_strategy(Strategy):
def __init__(self):
super(trickerless_rhmp_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._fast_ma_period = self.Param("FastMaPeriod", 20)
self._slow_ma_period = self.Param("SlowMaPeriod", 50)
self._prev_fast = 0.0
self._prev_slow = 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 FastMaPeriod(self):
return self._fast_ma_period.Value
@FastMaPeriod.setter
def FastMaPeriod(self, value):
self._fast_ma_period.Value = value
@property
def SlowMaPeriod(self):
return self._slow_ma_period.Value
@SlowMaPeriod.setter
def SlowMaPeriod(self, value):
self._slow_ma_period.Value = value
def OnReseted(self):
super(trickerless_rhmp_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(trickerless_rhmp_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
fast_ma = ExponentialMovingAverage()
fast_ma.Length = self.FastMaPeriod
slow_ma = ExponentialMovingAverage()
slow_ma.Length = self.SlowMaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast_ma, slow_ma, self._process_candle).Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if self._has_prev:
cross_up = self._prev_fast <= self._prev_slow and fast_val > slow_val
cross_down = self._prev_fast >= self._prev_slow and fast_val < slow_val
if cross_up and self.Position <= 0:
self.BuyMarket()
elif cross_down and self.Position >= 0:
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
self._has_prev = True
def CreateClone(self):
return trickerless_rhmp_strategy()