GitHub で見る
HarVesteR MACD トレンド戦略
概要
HarVesteR 戦略は、元の MetaTrader アドバイザーから変換されたトレンド追跡システムです。これは、MACD の勢いの確認と、トレンドの方向を定義し、後続の出口を管理する 2 つの単純な移動平均を組み合わせたものです。オプションの ADX フィルターを使用すると、取引アクティビティが強い方向性の動きに集中し続けます。
デフォルト設定は、公開されているエキスパートアドバイザー MACD(12, 24, 9)、50 期間管理 SMA、100 期間トレンド フィルター SMA、および価格が初期リスクの 2 倍になったらポジションを半分にする段階的テイクプロフィットを反映しています。
取引ロジック
- トレンド バイアス – 100 期間 SMA は方向性ゲートとして機能します。価格がそれを下回るとロングセットアップが準備され、その上で閉じるとショートセットアップが準備されます。取引が成立すると、価格が反対側に戻るまでフラグがリセットされ、引き戻しなしに連続エントリーすることができなくなります。
- MACD 確認 – シグナルは、MACD ラインがゼロの予想される側にあり、最後の 確認バー ローソク足内で少なくとも 1 回反対側にあった場合にのみ有効です。これは、スライディング ウィンドウ内の符号の変化を検索する元のループを複製します。
- エントリー条件 – ロング取引では、ローソク足終値と設定されたオフセット (価格ポイント) が両方の SMA を上回り、MACD がプラスで、(有効な場合) ADX が 50 を超える必要があります。ショート取引では、マイナスの MACD と価格が両方の SMA を下回るミラー ロジックが使用されます。
- 初期ストップ – ストップロスは、最後に ストップ バー で完了したローソク足の最低価格 (ロングの場合) または最高価格 (ショートの場合) に固定され、MQL
iLowest/iHighest のコールを 1 バーのシフトと一致させます。
- ポジション管理 – 価格が初期リスクの リスク乗数 倍に等しい距離を移動すると、ポジションの半分がクローズされ、ストップが損益分岐点に移動します。残りの半分は、50期間SMAがオフセット調整後の終値の上(ロング)または下(ショート)に達するほど価格が後退したときに終了します。
- 保護出口 – 保存されているストップ価格を突破するローソク足は、ポジション全体を即座にクローズします。
パラメーター
| 名前 |
説明 |
デフォルト |
Fast EMA |
MACD 計算内で使用される短い EMA 期間。 |
12 |
Slow EMA |
MACD の計算内で長い EMA 期間が使用されています。 |
24 |
Signal EMA |
MACD 信号線の平滑化期間。 |
9 |
MACD Confirmation Bars |
新しいエントリの前に、反対側の MACD 測定値間のローソク足の最大数が必要です。 |
6 |
Trend SMA |
後続の出口を保護する管理の長さ SMA。 |
50 |
Filter SMA |
ロング/ショートセットアップを準備するために使用される方向性 SMA の長さ。 |
100 |
Offset (points) |
価格を SMA と比較するときに追加または減算されるオフセット (商品ポイント単位)。 |
10 |
Stop Bars |
最初のストップを設定するときに考慮される過去のローソク足の数。 |
6 |
Risk Multiplier |
部分的なテイクプロフィットをトリガーするために初期リスクディスタンスに適用される乗数。 |
2.0 |
Use ADX |
ADX>50 トレンド強度フィルターを有効にします。 |
障害者 |
ADX Period |
フィルタがアクティブな場合に使用される ADX ルックバック。 |
14 |
Candle Type |
インジケーターに提供されるローソク足シリーズ (デフォルトは 1 時間足)。 |
1Hの時間枠 |
実装メモ
- 価格オフセットは、
Security.Step (または利用可能な場合は Security.PriceStep) を介して絶対価格に変換されます。セキュリティがステップを公開しない場合、戦略は 0.0001 にフォールバックし、元の FX に重点を置いたアドバイザーの動作と一致します。
- 部分的なエグジットでは、現在のポジションの半分のサイズの成行注文が使用され、ソースの MQL 実装で実行されたロット削減が反映されます。
StartProtection() を有効にすると、新しい取引が行われる前に組み込みのポジション ガードが確実にアクティブになります。
- ADX フィルタはオプションです。無効にすると、アルゴリズムは、ADX を人為的な値 60 に置き換えることで、過去のスクリプトとまったく同じように動作します。
使用のヒント
- 戦略を開始する前に、
Volume プロパティを設定します。これは、エントリー時および部分的なエグジット時に使用される基本注文サイズを定義します。
Candle Type を希望の時間枠に合わせます。元の戦略は 1 時間ごとのデータに基づいて調整されましたが、パラメーターの最適化によってより短いフレームを調査できます。
- 通常、
MACD Confirmation Bars、Offset (points)、および Risk Multiplier の最適化は、勝率と取引頻度に最も大きな影響を与えます。
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class HarVesteRMacdTrendStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast; private decimal _prevSlow; private bool _hasPrev;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public HarVesteRMacdTrendStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 12).SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 26).SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = default;
_prevSlow = default;
_hasPrev = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, slow, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) return;
if (!_hasPrev) { _prevFast = fast; _prevSlow = slow; _hasPrev = true; return; }
if (_cooldown > 0)
{
_cooldown--;
_prevFast = fast; _prevSlow = slow;
return;
}
if (_prevFast <= _prevSlow && fast > slow && Position <= 0)
{
var volume = Volume + Math.Abs(Position);
BuyMarket(volume);
_cooldown = 2;
}
else if (_prevFast >= _prevSlow && fast < slow && Position >= 0)
{
var volume = Volume + Math.Abs(Position);
SellMarket(volume);
_cooldown = 2;
}
_prevFast = fast; _prevSlow = slow;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class har_veste_r_macd_trend_strategy(Strategy):
def __init__(self):
super(har_veste_r_macd_trend_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 12).SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 26).SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))).SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_fast = 0.0; self._prev_slow = 0.0; self._has_prev = False; self._cooldown = 0
@property
def fast_period(self): return self._fast_period.Value
@property
def slow_period(self): return self._slow_period.Value
@property
def candle_type(self): return self._candle_type.Value
def OnReseted(self):
super(har_veste_r_macd_trend_strategy, self).OnReseted()
self._prev_fast = 0.0; self._prev_slow = 0.0; self._has_prev = False; self._cooldown = 0
def OnStarted2(self, time):
super(har_veste_r_macd_trend_strategy, self).OnStarted2(time)
self._has_prev = False; self._cooldown = 0
fast = ExponentialMovingAverage(); fast.Length = self.fast_period
slow = ExponentialMovingAverage(); slow.Length = self.slow_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast, slow, self.process_candle).Start()
def process_candle(self, candle, fast, slow):
if candle.State != CandleStates.Finished: return
if not self.IsFormedAndOnlineAndAllowTrading(): return
fast_val = float(fast); slow_val = float(slow)
if not self._has_prev:
self._prev_fast = fast_val; self._prev_slow = slow_val; self._has_prev = True; return
if self._cooldown > 0:
self._cooldown -= 1; self._prev_fast = fast_val; self._prev_slow = slow_val; return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
volume = self.Volume + abs(self.Position)
self.BuyMarket(volume); self._cooldown = 2
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
volume = self.Volume + abs(self.Position)
self.SellMarket(volume); self._cooldown = 2
self._prev_fast = fast_val; self._prev_slow = slow_val
def CreateClone(self): return har_veste_r_macd_trend_strategy()