ホーム
/
戦略のサンプル
GitHub で見る
MACD 4 色 2 Martingale 戦略
MACD 4 色 2 Martingale
この戦略では、「MACD Four Colors 2 Martingale」エキスパート アドバイザーを MetaTrader から StockSharp に移植します。 MACD の「色」解釈とマーチンゲール位置サイジング モデルを中心に構築された元のロジックが維持されています。
概要
基本的なインジケーターは、MACD ヒストグラムを 5 色でペイントします。デフォルトの「新しい」配色では、MACD の線がゼロ線の上または下にあるかどうかに応じて、ヒストグラムの色が変わります。エキスパートアドバイザーは、色が銀から黄色に変化するとき(負の MACD が再び下降する)、または赤から青に変化するとき(正の MACD が反転するとき)にポジションをオープンします。 StockSharp バージョンは、MACD の値から色を再構成することで、このシーケンスを再現します。
常に 1 方向の取引バスケットのみがアクティブになります。新しい取引は、その価格が現在のバスケットの平均エントリーを改善する場合にのみ許可されます(ロングの場合は価格が低く、ショートの場合は価格が高くなります)。新しいエントリごとに、最後に充填されたボリュームに設定可能なロット係数を乗算し、元の EA からのマーチンゲール平均を実装します。
取引ルール
インジケーター ロジック : クラシック 12/26/9 構成の MovingAverageConvergenceDivergenceSignal インジケーターは、MACD 値を生成します。
色の再構成 : この戦略では、最新の 2 つの MACD 値を比較します。負の立ち上がり MACD はカラー 1 (銀) にマッピングされ、正の立ち上がりはカラー 2 (赤) に、正の立ち下がりはカラー 3 (青) に、そして負の立ち下がりはカラー 4 (黄色) にマッピングされます。
ロングエントリ : 前のバーの MACD がゼロ未満のままで、再構成された色が 1 から 4 に移動するとトリガーされます。取引はショートエクスポージャーがなく、新しい価格が既存のロングエントリーよりも低い場合にのみ実行されます。
簡単なエントリ : 前のバーの MACD が 0 を超えている間に色が 2 から 3 に移動するとトリガーされます。ロングエクスポージャーがなく、新しい価格が既存のショートエントリーよりも高い場合にのみ取引が開始されます。
ボリューム管理 : 最初の注文では InitialVolume が使用されます。同じバスケット内の後続の注文はすべて、最後に実行された数量に LotCoefficient を掛けます。係数 ≤ 0 を設定すると、乗算器が無効になります。
損益管理 : 変動損益は完成したキャンドルごとに評価されます。 TargetProfit を押すと、すべてのポジションがクローズされ、マーチンゲール サイクルがリセットされます。 MaxDrawdown (損失しきい値として解釈される) に違反すると、すべてが閉じられ、サイクルが再開されます。元のコードと同様に、負のしきい値がサポートされます。
ポジションの出口 : 目標金額とは別に、自動停止はありません。リスクしきい値に達するか、ユーザーが手動で介入するまで、ポジションはオープンしたままになります。
パラメーター
CandleType (DataType、デフォルトは 1h) – MACD 計算の時間枠。
InitialVolume (10 進数、デフォルトは 1) – バスケット内の最初の注文の数量。
LotCoefficient (10 進数、デフォルト 2) – マーチンゲールがアクティブなときに前のボリュームに適用される乗数。
MaxDrawdown (10 進数、デフォルト 50) – 清算を強制する変動損失のしきい値 (金額)。正の値は -MaxDrawdown を監視し、負の値は正確な値を使用します。
TargetProfit (10 進数、デフォルトは 150) – バスケットをクローズする変動利益目標 (金額)。負の値は、MQL バージョンと同様に比較を反転します。
FastEmaPeriod (int、デフォルト 12) – MACD の高速 EMA の長さ。
SlowEmaPeriod (int、デフォルト 26) – MACD の低速 EMA の長さ。
SignalPeriod (int、デフォルトは 9) – MACD 平滑化のための信号 EMA の長さ。
使用上の注意
未実現損益は取引所の仕様から計算されるため、PriceStep と StepPrice を定義するあらゆる商品で機能します。
マーチンゲールサイジングにより、ポジションが急速に拡大する可能性があります。ライブ口座での取引を有効にする前に、リスク制限を検証してください。
視覚的な分析のために、戦略によって作成されたチャート領域を添付します。ローソク足、MACD インジケーター、および実行された取引をプロットします。
カタログフィルター
カテゴリ : トレンド/モメンタム平均化
方向 : 両方 (長いバスケットと短いバスケット)
インジケーター : MACD
停留所 : 金銭ベースの降車のみ
時間枠 : 設定可能 (デフォルトは 1 時間)
複雑さ : 中級
リスク : マーチンゲール法による高リスク
自動化 : 一度開始すると完全に自動化されます
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// MACD histogram crossover with martingale volume scaling.
/// Based on the MACD Four Colors 2 Martingale expert advisor.
/// </summary>
public class MacdFourColors2MartingaleStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastEmaPeriod;
private readonly StrategyParam<int> _slowEmaPeriod;
private readonly StrategyParam<int> _signalPeriod;
private readonly StrategyParam<decimal> _lotCoefficient;
private readonly StrategyParam<int> _maxMartingale;
private MovingAverageConvergenceDivergence _macd;
private readonly System.Collections.Generic.Queue<decimal> _macdHistory = new();
private decimal? _prevHistogram;
private decimal _currentVolume;
private int _consecutiveLosses;
private decimal _entryPrice;
/// <summary>
/// Type of candles used for MACD analysis.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Period of the fast EMA inside MACD.
/// </summary>
public int FastEmaPeriod
{
get => _fastEmaPeriod.Value;
set => _fastEmaPeriod.Value = value;
}
/// <summary>
/// Period of the slow EMA inside MACD.
/// </summary>
public int SlowEmaPeriod
{
get => _slowEmaPeriod.Value;
set => _slowEmaPeriod.Value = value;
}
/// <summary>
/// Period of the signal line.
/// </summary>
public int SignalPeriod
{
get => _signalPeriod.Value;
set => _signalPeriod.Value = value;
}
/// <summary>
/// Multiplier applied after a losing trade.
/// </summary>
public decimal LotCoefficient
{
get => _lotCoefficient.Value;
set => _lotCoefficient.Value = value;
}
/// <summary>
/// Maximum number of martingale steps before resetting.
/// </summary>
public int MaxMartingale
{
get => _maxMartingale.Value;
set => _maxMartingale.Value = value;
}
/// <summary>
/// Initialize strategy parameters.
/// </summary>
public MacdFourColors2MartingaleStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Type of candles for MACD analysis", "General");
_fastEmaPeriod = Param(nameof(FastEmaPeriod), 20)
.SetDisplay("Fast EMA", "Fast EMA period for MACD", "Indicators")
.SetGreaterThanZero();
_slowEmaPeriod = Param(nameof(SlowEmaPeriod), 50)
.SetDisplay("Slow EMA", "Slow EMA period for MACD", "Indicators")
.SetGreaterThanZero();
_signalPeriod = Param(nameof(SignalPeriod), 12)
.SetDisplay("Signal Period", "Signal line smoothing period", "Indicators")
.SetGreaterThanZero();
_lotCoefficient = Param(nameof(LotCoefficient), 1.5m)
.SetDisplay("Lot Coefficient", "Multiplier after a loss", "Money Management")
.SetGreaterThanZero();
_maxMartingale = Param(nameof(MaxMartingale), 5)
.SetDisplay("Max Martingale", "Maximum consecutive doublings", "Money Management")
.SetGreaterThanZero();
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevHistogram = null;
_currentVolume = Volume > 0 ? Volume : 1;
_consecutiveLosses = 0;
_entryPrice = 0;
_macdHistory.Clear();
_macd = new MovingAverageConvergenceDivergence
{
ShortMa = { Length = FastEmaPeriod },
LongMa = { Length = SlowEmaPeriod }
};
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_macd, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal macdValue)
{
if (candle.State != CandleStates.Finished)
return;
_macdHistory.Enqueue(macdValue);
while (_macdHistory.Count > SignalPeriod)
_macdHistory.Dequeue();
if (!_macd.IsFormed || _macdHistory.Count < SignalPeriod)
{
_prevHistogram = null;
return;
}
// Calculate signal line (SMA of MACD)
var sum = 0m;
var history = _macdHistory.ToArray();
foreach (var v in history)
sum += v;
var signalValue = sum / history.Length;
var histogram = macdValue - signalValue;
if (_prevHistogram is null)
{
_prevHistogram = histogram;
return;
}
var crossUp = _prevHistogram < 0 && histogram >= 0;
var crossDown = _prevHistogram >= 0 && histogram < 0;
if (crossUp)
{
// Check for loss on closing short
if (Position < 0)
{
var pnl = _entryPrice - candle.ClosePrice;
if (pnl < 0)
{
_consecutiveLosses++;
if (_consecutiveLosses <= MaxMartingale)
_currentVolume *= LotCoefficient;
}
else
{
_consecutiveLosses = 0;
_currentVolume = Volume > 0 ? Volume : 1;
}
BuyMarket(Math.Abs(Position) + _currentVolume);
_entryPrice = candle.ClosePrice;
}
else if (Position == 0)
{
BuyMarket(_currentVolume);
_entryPrice = candle.ClosePrice;
}
}
else if (crossDown)
{
// Check for loss on closing long
if (Position > 0)
{
var pnl = candle.ClosePrice - _entryPrice;
if (pnl < 0)
{
_consecutiveLosses++;
if (_consecutiveLosses <= MaxMartingale)
_currentVolume *= LotCoefficient;
}
else
{
_consecutiveLosses = 0;
_currentVolume = Volume > 0 ? Volume : 1;
}
SellMarket(Math.Abs(Position) + _currentVolume);
_entryPrice = candle.ClosePrice;
}
else if (Position == 0)
{
SellMarket(_currentVolume);
_entryPrice = candle.ClosePrice;
}
}
_prevHistogram = histogram;
}
/// <inheritdoc />
protected override void OnReseted()
{
_macd = null;
_prevHistogram = null;
_currentVolume = 0;
_consecutiveLosses = 0;
_entryPrice = 0;
_macdHistory.Clear();
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 MovingAverageConvergenceDivergence
from StockSharp.Algo.Strategies import Strategy
class macd_four_colors2_martingale_strategy(Strategy):
def __init__(self):
super(macd_four_colors2_martingale_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._fast_ema_period = self.Param("FastEmaPeriod", 20)
self._slow_ema_period = self.Param("SlowEmaPeriod", 50)
self._signal_period = self.Param("SignalPeriod", 12)
self._macd_history = []
self._prev_histogram = 0.0
self._has_prev = False
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def FastEmaPeriod(self):
return self._fast_ema_period.Value
@FastEmaPeriod.setter
def FastEmaPeriod(self, value):
self._fast_ema_period.Value = value
@property
def SlowEmaPeriod(self):
return self._slow_ema_period.Value
@SlowEmaPeriod.setter
def SlowEmaPeriod(self, value):
self._slow_ema_period.Value = value
@property
def SignalPeriod(self):
return self._signal_period.Value
@SignalPeriod.setter
def SignalPeriod(self, value):
self._signal_period.Value = value
def OnReseted(self):
super(macd_four_colors2_martingale_strategy, self).OnReseted()
self._macd_history = []
self._prev_histogram = 0.0
self._has_prev = False
self._entry_price = 0.0
def OnStarted2(self, time):
super(macd_four_colors2_martingale_strategy, self).OnStarted2(time)
self._macd_history = []
self._prev_histogram = 0.0
self._has_prev = False
self._entry_price = 0.0
macd = MovingAverageConvergenceDivergence()
macd.ShortMa.Length = self.FastEmaPeriod
macd.LongMa.Length = self.SlowEmaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(macd, self._process_candle).Start()
def _process_candle(self, candle, macd_value):
if candle.State != CandleStates.Finished:
return
macd_val = float(macd_value)
close = float(candle.ClosePrice)
sig_len = self.SignalPeriod
self._macd_history.append(macd_val)
while len(self._macd_history) > sig_len:
self._macd_history.pop(0)
if len(self._macd_history) < sig_len:
return
signal_val = sum(self._macd_history) / sig_len
histogram = macd_val - signal_val
if self._has_prev:
cross_up = self._prev_histogram < 0 and histogram >= 0
cross_down = self._prev_histogram >= 0 and histogram < 0
if cross_up:
if self.Position < 0:
self.BuyMarket()
self._entry_price = close
elif self.Position == 0:
self.BuyMarket()
self._entry_price = close
elif cross_down:
if self.Position > 0:
self.SellMarket()
self._entry_price = close
elif self.Position == 0:
self.SellMarket()
self._entry_price = close
self._prev_histogram = histogram
self._has_prev = True
def CreateClone(self):
return macd_four_colors2_martingale_strategy()