MACD 出来高 XAUUSD 戦略
XAUUSD 向けの 15 分足戦略で、MACD のゼロライン・クロスと出来高オシレーター・フィルター、固定リスクパラメーターを組み合わせます。
詳細
- エントリー条件: 出来高オシレーターが正で出来高比較を満たした状態で MACD がゼロラインを交差。
- ロング/ショート: 両方向。
- エグジット条件: ストップロスまたはテイクプロフィット水準。
- ストップ: 固定ストップロスとテイクプロフィット乗数。
- デフォルト値:
ShortLength= 5LongLength= 8FastLength= 16SlowLength= 26SignalLength= 9Leverage= 1.0StopLoss= 10100TakeProfitMultiplier= 1.1CandleType= TimeSpan.FromMinutes(15)
- フィルター:
- カテゴリ: トレンドフォロー
- 方向: 両方
- インジケーター: MACD、EMA、Volume
- ストップ: はい
- 複雑さ: 基本
- 時間軸: イントラデイ (15m)
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// MACD Volume XAUUSD strategy.
/// The volume oscillator is 100 * (EMA(volume, ShortLength) - EMA(volume, LongLength)) / EMA(volume, LongLength). The MACD line
/// crossing above zero with a positive oscillator and volume above the previous candle's volume goes long; crossing below zero
/// under the same volume conditions goes short, reversing an opposite position. The stop is StopLoss price steps from the entry
/// and the take profit is StopLoss * TakeProfitMultiplier steps. Leverage scales the order volume.
/// </summary>
public class MacdVolumeXauusdStrategy : Strategy
{
private readonly StrategyParam<int> _shortLength;
private readonly StrategyParam<int> _longLength;
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
private readonly StrategyParam<int> _signalLength;
private readonly StrategyParam<decimal> _leverage;
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<decimal> _takeProfitMultiplier;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _shortVolumeEma;
private ExponentialMovingAverage _longVolumeEma;
private decimal? _prevMacd;
private decimal? _prevVolume;
/// <summary>
/// Short volume EMA length.
/// </summary>
public int ShortLength
{
get => _shortLength.Value;
set => _shortLength.Value = value;
}
/// <summary>
/// Long volume EMA length.
/// </summary>
public int LongLength
{
get => _longLength.Value;
set => _longLength.Value = value;
}
/// <summary>
/// MACD fast EMA length.
/// </summary>
public int FastLength
{
get => _fastLength.Value;
set => _fastLength.Value = value;
}
/// <summary>
/// MACD slow EMA length.
/// </summary>
public int SlowLength
{
get => _slowLength.Value;
set => _slowLength.Value = value;
}
/// <summary>
/// MACD signal line length.
/// </summary>
public int SignalLength
{
get => _signalLength.Value;
set => _signalLength.Value = value;
}
/// <summary>
/// Multiplier of the order volume.
/// </summary>
public decimal Leverage
{
get => _leverage.Value;
set => _leverage.Value = value;
}
/// <summary>
/// Stop loss distance in price steps.
/// </summary>
public decimal StopLoss
{
get => _stopLoss.Value;
set => _stopLoss.Value = value;
}
/// <summary>
/// Take profit distance as a multiple of the stop loss.
/// </summary>
public decimal TakeProfitMultiplier
{
get => _takeProfitMultiplier.Value;
set => _takeProfitMultiplier.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public MacdVolumeXauusdStrategy()
{
_shortLength = Param(nameof(ShortLength), 5)
.SetGreaterThanZero()
.SetDisplay("Short Length", "Short volume EMA length", "Volume");
_longLength = Param(nameof(LongLength), 8)
.SetGreaterThanZero()
.SetDisplay("Long Length", "Long volume EMA length", "Volume");
_fastLength = Param(nameof(FastLength), 16)
.SetGreaterThanZero()
.SetDisplay("Fast Length", "MACD fast EMA length", "MACD");
_slowLength = Param(nameof(SlowLength), 26)
.SetGreaterThanZero()
.SetDisplay("Slow Length", "MACD slow EMA length", "MACD");
_signalLength = Param(nameof(SignalLength), 9)
.SetGreaterThanZero()
.SetDisplay("Signal Length", "MACD signal line length", "MACD");
_leverage = Param(nameof(Leverage), 1m)
.SetGreaterThanZero()
.SetDisplay("Leverage", "Multiplier of the order volume", "Risk");
_stopLoss = Param(nameof(StopLoss), 10100m)
.SetNotNegative()
.SetDisplay("Stop Loss", "Stop loss distance in price steps", "Risk");
_takeProfitMultiplier = Param(nameof(TakeProfitMultiplier), 1.1m)
.SetNotNegative()
.SetDisplay("Take Profit Multiplier", "Take profit distance as a multiple of the stop loss", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_shortVolumeEma = null;
_longVolumeEma = null;
_prevMacd = null;
_prevVolume = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevMacd = null;
_prevVolume = null;
_shortVolumeEma = new ExponentialMovingAverage { Length = ShortLength };
_longVolumeEma = new ExponentialMovingAverage { Length = LongLength };
var macd = new MovingAverageConvergenceDivergenceSignal
{
Macd =
{
ShortMa = { Length = FastLength },
LongMa = { Length = SlowLength },
},
SignalMa = { Length = SignalLength }
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(macd, ProcessCandle)
.Start();
var step = Security?.PriceStep ?? 1m;
StartProtection(
new Unit(StopLoss * TakeProfitMultiplier * step, UnitTypes.Absolute),
new Unit(StopLoss * step, UnitTypes.Absolute),
useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
var oscillators = CreateChartArea();
if (oscillators != null)
DrawIndicator(oscillators, macd);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue)
{
if (candle.State != CandleStates.Finished)
return;
var volume = candle.TotalVolume;
var shortValue = _shortVolumeEma.Process(new DecimalIndicatorValue(_shortVolumeEma, volume, candle.OpenTime) { IsFinal = true });
var longValue = _longVolumeEma.Process(new DecimalIndicatorValue(_longVolumeEma, volume, candle.OpenTime) { IsFinal = true });
var prevVolume = _prevVolume;
_prevVolume = volume;
if (!macdValue.IsFormed || macdValue is not IMovingAverageConvergenceDivergenceSignalValue { Macd: decimal macdLine })
return;
var prevMacd = _prevMacd;
_prevMacd = macdLine;
if (!_shortVolumeEma.IsFormed || !_longVolumeEma.IsFormed || prevMacd is not decimal pm || prevVolume is not decimal pv)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var longEma = longValue.GetValue<decimal>();
if (longEma == 0)
return;
var oscillator = 100m * (shortValue.GetValue<decimal>() - longEma) / longEma;
var volumeOk = oscillator > 0 && volume > pv;
var orderVolume = Volume * Leverage;
if (volumeOk && pm <= 0 && macdLine > 0 && Position <= 0)
BuyMarket(orderVolume + Math.Abs(Position));
else if (volumeOk && pm >= 0 && macdLine < 0 && Position >= 0)
SellMarket(orderVolume + Math.Abs(Position));
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import ExponentialMovingAverage, MovingAverageConvergenceDivergenceSignal
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class macd_volume_xauusd_strategy(Strategy):
"""
MACD Volume XAUUSD strategy.
The volume oscillator is 100 * (EMA(volume, ShortLength) - EMA(volume, LongLength)) / EMA(volume, LongLength). The MACD line
crossing above zero with a positive oscillator and volume above the previous candle's volume goes long; crossing below zero
under the same volume conditions goes short, reversing an opposite position. The stop is StopLoss price steps from the entry
and the take profit is StopLoss * TakeProfitMultiplier steps. Leverage scales the order volume.
"""
def __init__(self):
super(macd_volume_xauusd_strategy, self).__init__()
self._short_length = self.Param("ShortLength", 5).SetGreaterThanZero().SetDisplay("Short Length", "Short volume EMA length", "Volume")
self._long_length = self.Param("LongLength", 8).SetGreaterThanZero().SetDisplay("Long Length", "Long volume EMA length", "Volume")
self._fast_length = self.Param("FastLength", 16).SetGreaterThanZero().SetDisplay("Fast Length", "MACD fast EMA length", "MACD")
self._slow_length = self.Param("SlowLength", 26).SetGreaterThanZero().SetDisplay("Slow Length", "MACD slow EMA length", "MACD")
self._signal_length = self.Param("SignalLength", 9).SetGreaterThanZero().SetDisplay("Signal Length", "MACD signal line length", "MACD")
self._leverage = self.Param("Leverage", 1.0).SetGreaterThanZero().SetDisplay("Leverage", "Multiplier of the order volume", "Risk")
self._stop_loss = self.Param("StopLoss", 10100.0).SetNotNegative().SetDisplay("Stop Loss", "Stop loss distance in price steps", "Risk")
self._take_profit_multiplier = self.Param("TakeProfitMultiplier", 1.1).SetNotNegative().SetDisplay("Take Profit Multiplier", "Take profit distance as a multiple of the stop loss", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._short_volume_ema = None
self._long_volume_ema = None
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._prev_macd = None
self._prev_volume = None
def OnReseted(self):
super(macd_volume_xauusd_strategy, self).OnReseted()
self._short_volume_ema = None
self._long_volume_ema = None
self._reset_state()
def OnStarted2(self, time):
super(macd_volume_xauusd_strategy, self).OnStarted2(time)
self._reset_state()
self._short_volume_ema = ExponentialMovingAverage()
self._short_volume_ema.Length = self._short_length.Value
self._long_volume_ema = ExponentialMovingAverage()
self._long_volume_ema.Length = self._long_length.Value
macd = MovingAverageConvergenceDivergenceSignal()
macd.Macd.ShortMa.Length = self._fast_length.Value
macd.Macd.LongMa.Length = self._slow_length.Value
macd.SignalMa.Length = self._signal_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(macd, self._process_candle).Start()
step = Decimal(1)
if self.Security is not None and self.Security.PriceStep is not None:
step = self.Security.PriceStep
stop = Decimal(self._stop_loss.Value)
take = stop * Decimal(self._take_profit_multiplier.Value)
self.StartProtection(Unit(take * step, UnitTypes.Absolute), Unit(stop * step, UnitTypes.Absolute), useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
oscillators = self.CreateChartArea()
if oscillators is not None:
self.DrawIndicator(oscillators, macd)
def _process_candle(self, candle, macd_value):
if candle.State != CandleStates.Finished:
return
volume = candle.TotalVolume
short_value = process_value(self._short_volume_ema, volume, candle.OpenTime, True)
long_value = process_value(self._long_volume_ema, volume, candle.OpenTime, True)
prev_volume = self._prev_volume
self._prev_volume = volume
if not macd_value.IsFormed:
return
macd_line = macd_value.Macd
if macd_line is None:
return
pm = self._prev_macd
self._prev_macd = macd_line
if not self._short_volume_ema.IsFormed or not self._long_volume_ema.IsFormed or pm is None or prev_volume is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
zero = Decimal(0)
long_ema = long_value.GetValue[Decimal](None)
if long_ema == zero:
return
oscillator = Decimal(100) * (short_value.GetValue[Decimal](None) - long_ema) / long_ema
volume_ok = oscillator > zero and volume > prev_volume
order_volume = self.Volume * Decimal(self._leverage.Value)
if volume_ok and pm <= zero and macd_line > zero and self.Position <= 0:
self.BuyMarket(order_volume + abs(self.Position))
elif volume_ok and pm >= zero and macd_line < zero and self.Position >= 0:
self.SellMarket(order_volume + abs(self.Position))
def CreateClone(self):
return macd_volume_xauusd_strategy()