GitHub で見る
初日の開始 MACD ヒストグラム戦略
概要
この戦略は、MetaTrader のエキスパート「2 1000 1 0.7% 0.5 500lev st」を再現するもので、新しい取引日の開始時に取引を入力し、MACD ヒストグラムの傾きで方向をフィルタリングします。このシステムは時間足ローソク足用に設計されており、元の MQL 設定から変換された固定資金管理パラメータに依存しています。
取引ロジック
- この戦略は、時間ごとのローソク足を監視し、新しい日ごとに最初のローソク足を検出します。
- 前日の最も最近完了した 2 つのローソク足の MACD ヒストグラムを評価します。
- ヒストグラムがこれら 2 本のバーの間で下落した場合、システムは新しい日の最初のローソク足でロングポジションをオープンします。
- ヒストグラムが増加した場合は、代わりにショートポジションをオープンします。
- 一度にアクティブにできるポジションは 1 つだけです。反対のシグナルは、新しい方向を開始する前に現在の取引を終了します。
リスク管理
- 初期ストップロス距離: 875 ポイント (商品価格ステップを乗算して価格に換算)。
- テイクプロフィットディスタンス:510ポイント。
- トレーリングストップ距離: 2172 ポイント。ストップはエントリー以降に到達した最高値(ロング)または最低(ショート)価格に従い、値が厳しくなると最初のストップを上書きします。
- 元の損益分岐点オプションは無効になっていたため、ここでは省略されました。
パラメーター
| 名前 |
説明 |
デフォルト |
CandleType |
戦略で使用されるローソク足シリーズ (デフォルトでは時間ごと)。 |
1時間キャンドル |
MacdFastPeriod |
MACD の短い EMA 期間。 |
58 |
MacdSlowPeriod |
MACDのEMA期間が遅いです。 |
195 |
MacdSignalPeriod |
MACD の信号線期間。 |
183 |
StopLossPoints |
インスツルメントポイントで表されるストップロス距離。 |
875 |
TakeProfitPoints |
テイクプロフィット距離(ポイント単位)。 |
510 |
TrailingStopPoints |
トレーリングストップの距離 (ポイント単位)。 |
2172 |
注意事項
- この戦略は、ソースエキスパートの「前のバー値を使用」オプションを反映して、バー内先読みを回避するために完了したローソク足のみを使用します。
- トレーリングおよび固定エグジットは内部で処理されるため、ストップの二重処理を防ぐために追加のポートフォリオ保護は無効のままにしておく必要があります。
- このロジックでは、ブローカーが標準のポイント定義 (価格ステップ) を使用していることを前提としています。インストゥルメントが異なるティック サイズを使用する場合は、パラメータを調整します。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Day Opening MACD Histogram strategy: MACD histogram direction.
/// Buys when MACD histogram turns positive, sells when turns negative.
/// </summary>
public class DayOpeningMacdHistogramStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _signalPeriod;
private readonly StrategyParam<int> _signalCooldownCandles;
private decimal _prevHistogram;
private int _candlesSinceTrade;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int SignalPeriod { get => _signalPeriod.Value; set => _signalPeriod.Value = value; }
public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }
public DayOpeningMacdHistogramStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("MACD Fast", "MACD fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 26)
.SetGreaterThanZero()
.SetDisplay("MACD Slow", "MACD slow EMA period", "Indicators");
_signalPeriod = Param(nameof(SignalPeriod), 9)
.SetGreaterThanZero()
.SetDisplay("Signal Period", "MACD signal period", "Indicators");
_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 4)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevHistogram = 0;
_candlesSinceTrade = SignalCooldownCandles;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevHistogram = 0;
_candlesSinceTrade = SignalCooldownCandles;
_hasPrev = false;
var macd = new MovingAverageConvergenceDivergenceSignal
{
Macd = { ShortMa = { Length = FastPeriod }, LongMa = { Length = SlowPeriod } },
SignalMa = { Length = SignalPeriod }
};
var subscription = SubscribeCandles(CandleType);
subscription.BindEx(macd, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue)
{
if (candle.State != CandleStates.Finished) return;
if (!macdValue.IsFinal) return;
if (_candlesSinceTrade < SignalCooldownCandles)
_candlesSinceTrade++;
if (macdValue is not MovingAverageConvergenceDivergenceSignalValue typed) return;
if (typed.Macd is not decimal macdMain || typed.Signal is not decimal signal) return;
var histogram = macdMain - signal;
if (_hasPrev)
{
if (_prevHistogram <= 0 && histogram > 0 && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
BuyMarket();
_candlesSinceTrade = 0;
}
else if (_prevHistogram >= 0 && histogram < 0 && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
SellMarket();
_candlesSinceTrade = 0;
}
}
_prevHistogram = histogram;
_hasPrev = true;
}
}
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 MovingAverageConvergenceDivergenceSignal
from StockSharp.Algo.Strategies import Strategy
class day_opening_macd_histogram_strategy(Strategy):
def __init__(self):
super(day_opening_macd_histogram_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._fast_period = self.Param("FastPeriod", 12)
self._slow_period = self.Param("SlowPeriod", 26)
self._signal_period = self.Param("SignalPeriod", 9)
self._signal_cooldown_candles = self.Param("SignalCooldownCandles", 4)
self._prev_histogram = 0.0
self._candles_since_trade = 4
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 FastPeriod(self):
return self._fast_period.Value
@FastPeriod.setter
def FastPeriod(self, value):
self._fast_period.Value = value
@property
def SlowPeriod(self):
return self._slow_period.Value
@SlowPeriod.setter
def SlowPeriod(self, value):
self._slow_period.Value = value
@property
def SignalPeriod(self):
return self._signal_period.Value
@SignalPeriod.setter
def SignalPeriod(self, value):
self._signal_period.Value = value
@property
def SignalCooldownCandles(self):
return self._signal_cooldown_candles.Value
@SignalCooldownCandles.setter
def SignalCooldownCandles(self, value):
self._signal_cooldown_candles.Value = value
def OnReseted(self):
super(day_opening_macd_histogram_strategy, self).OnReseted()
self._prev_histogram = 0.0
self._candles_since_trade = self.SignalCooldownCandles
self._has_prev = False
def OnStarted2(self, time):
super(day_opening_macd_histogram_strategy, self).OnStarted2(time)
self._prev_histogram = 0.0
self._candles_since_trade = self.SignalCooldownCandles
self._has_prev = False
macd = MovingAverageConvergenceDivergenceSignal()
macd.Macd.ShortMa.Length = self.FastPeriod
macd.Macd.LongMa.Length = self.SlowPeriod
macd.SignalMa.Length = self.SignalPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.BindEx(macd, self._process_candle).Start()
def _process_candle(self, candle, macd_value):
if candle.State != CandleStates.Finished:
return
if not macd_value.IsFinal:
return
if self._candles_since_trade < self.SignalCooldownCandles:
self._candles_since_trade += 1
if macd_value.Macd is None or macd_value.Signal is None:
return
macd_main = float(macd_value.Macd)
signal = float(macd_value.Signal)
histogram = macd_main - signal
if self._has_prev:
if self._prev_histogram <= 0 and histogram > 0 and self.Position <= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.BuyMarket()
self._candles_since_trade = 0
elif self._prev_histogram >= 0 and histogram < 0 and self.Position >= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.SellMarket()
self._candles_since_trade = 0
self._prev_histogram = histogram
self._has_prev = True
def CreateClone(self):
return day_opening_macd_histogram_strategy()