MACD模式交易者
该策略在MACD的剧烈反转时开仓。它寻找在极小中间值周围出现的两个巨大峰值。当前一根MACD为正且当前值大幅跌入负区时做空;当条件相反时做多。止损和止盈基于最近的高点和低点。
该算法适用于动量快速反转的高波动市场。仅使用市价单,并依据历史K线计算风险水平。
详情
- 入场条件: 基于
RatioThreshold的MACD峰值比例。 - 多空方向: 双向。
- 退出条件: 在最近极值加偏移处止损或相反峰值出现。
- 止损: 是。
- 默认值:
FastEmaPeriod= 24SlowEmaPeriod= 13StopLossBars= 22TakeProfitBars= 32OffsetPoints= 40RatioThreshold= 5mCandleType= TimeSpan.FromMinutes(5)
- 过滤器:
- 类型: 模式
- 方向: 双向
- 指标: MACD
- 止损: 是
- 复杂度: 中等
- 时间框架: 日内 (5m)
- 季节性: 否
- 神经网络: 否
- 背离: 否
- 风险等级: 中等
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy that trades sharp MACD reversals using recent highs and lows for risk.
/// </summary>
public class MacdPatternTraderAllStrategy : Strategy
{
private readonly StrategyParam<int> _fastEmaPeriod;
private readonly StrategyParam<int> _slowEmaPeriod;
private readonly StrategyParam<int> _stopLossBars;
private readonly StrategyParam<int> _takeProfitBars;
private readonly StrategyParam<int> _offsetPoints;
private readonly StrategyParam<decimal> _ratioThreshold;
private readonly StrategyParam<DataType> _candleType;
private decimal _macdPrev;
private decimal _macdPrev2;
private decimal _stopLossPrice;
private decimal _takeProfitPrice;
/// <summary>
/// Fast EMA period for MACD.
/// </summary>
public int FastEmaPeriod { get => _fastEmaPeriod.Value; set => _fastEmaPeriod.Value = value; }
/// <summary>
/// Slow EMA period for MACD.
/// </summary>
public int SlowEmaPeriod { get => _slowEmaPeriod.Value; set => _slowEmaPeriod.Value = value; }
/// <summary>
/// Number of bars used to calculate stop loss.
/// </summary>
public int StopLossBars { get => _stopLossBars.Value; set => _stopLossBars.Value = value; }
/// <summary>
/// Number of bars used to calculate take profit.
/// </summary>
public int TakeProfitBars { get => _takeProfitBars.Value; set => _takeProfitBars.Value = value; }
/// <summary>
/// Offset in points added to stop loss.
/// </summary>
public int OffsetPoints { get => _offsetPoints.Value; set => _offsetPoints.Value = value; }
/// <summary>
/// Minimal ratio of MACD spikes to previous value.
/// </summary>
public decimal RatioThreshold { get => _ratioThreshold.Value; set => _ratioThreshold.Value = value; }
/// <summary>
/// Candle type used by the strategy.
/// </summary>
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
/// <summary>
/// Initializes a new instance of the <see cref="MacdPatternTraderAllStrategy"/> class.
/// </summary>
public MacdPatternTraderAllStrategy()
{
_fastEmaPeriod = Param(nameof(FastEmaPeriod), 24)
.SetDisplay("Fast EMA Period", "Period for fast EMA in MACD", "Indicators")
.SetOptimize(12, 40, 2);
_slowEmaPeriod = Param(nameof(SlowEmaPeriod), 13)
.SetDisplay("Slow EMA Period", "Period for slow EMA in MACD", "Indicators")
.SetOptimize(7, 26, 1);
_stopLossBars = Param(nameof(StopLossBars), 22)
.SetDisplay("Stop Loss Bars", "Bars to look back for stop loss", "Risk management")
.SetOptimize(10, 40, 1);
_takeProfitBars = Param(nameof(TakeProfitBars), 32)
.SetDisplay("Take Profit Bars", "Bars to look back for take profit", "Risk management")
.SetOptimize(10, 60, 2);
_offsetPoints = Param(nameof(OffsetPoints), 40)
.SetDisplay("Offset Points", "Point offset added to stop loss", "Risk management")
.SetOptimize(10, 60, 5);
_ratioThreshold = Param(nameof(RatioThreshold), 8m)
.SetDisplay("MACD Ratio", "Minimal ratio of surrounding MACD values", "Signals")
.SetOptimize(3m, 7m, 1m);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_macdPrev = 0m;
_macdPrev2 = 0m;
_stopLossPrice = 0m;
_takeProfitPrice = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var 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);
DrawIndicator(area, macd);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal macdValue)
{
if (candle.State != CandleStates.Finished)
return;
// Manage existing position by fixed stop and target
if (Position > 0)
{
if (candle.LowPrice <= _stopLossPrice || candle.HighPrice >= _takeProfitPrice)
{
SellMarket(Position);
_stopLossPrice = 0m;
_takeProfitPrice = 0m;
}
}
else if (Position < 0)
{
if (candle.HighPrice >= _stopLossPrice || candle.LowPrice <= _takeProfitPrice)
{
BuyMarket(Math.Abs(Position));
_stopLossPrice = 0m;
_takeProfitPrice = 0m;
}
}
if (!IsFormedAndOnlineAndAllowTrading())
{
_macdPrev2 = _macdPrev;
_macdPrev = macdValue;
return;
}
var priceStep = Security?.PriceStep ?? 1m;
var offset = OffsetPoints * priceStep;
var stopDistance = offset * 2m;
var takeDistance = offset * 4m;
var macdCurr = macdValue;
var macdLast = _macdPrev;
var macdLast3 = _macdPrev2;
if (macdLast != 0m)
{
var ratio1 = Math.Abs(macdLast3 / macdLast);
var ratio2 = Math.Abs(macdCurr / macdLast);
if ((macdLast3 > 0m || macdCurr < 0m) && ratio1 >= RatioThreshold && ratio2 >= RatioThreshold && Position >= 0)
{
var sl = candle.ClosePrice + stopDistance;
var tp = candle.ClosePrice - takeDistance;
var volume = Volume + Math.Abs(Position);
SellMarket(volume);
_stopLossPrice = sl;
_takeProfitPrice = tp;
}
else if ((macdLast3 < 0m || macdCurr > 0m) && ratio1 >= RatioThreshold && ratio2 >= RatioThreshold && Position <= 0)
{
var sl = candle.ClosePrice - stopDistance;
var tp = candle.ClosePrice + takeDistance;
var volume = Volume + Math.Abs(Position);
BuyMarket(volume);
_stopLossPrice = sl;
_takeProfitPrice = tp;
}
}
_macdPrev2 = _macdPrev;
_macdPrev = macdCurr;
}
}
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 MovingAverageConvergenceDivergence
from StockSharp.Algo.Strategies import Strategy
class macd_pattern_trader_all_strategy(Strategy):
def __init__(self):
super(macd_pattern_trader_all_strategy, self).__init__()
self._fast_ema_period = self.Param("FastEmaPeriod", 24)
self._slow_ema_period = self.Param("SlowEmaPeriod", 13)
self._stop_loss_bars = self.Param("StopLossBars", 22)
self._take_profit_bars = self.Param("TakeProfitBars", 32)
self._offset_points = self.Param("OffsetPoints", 40)
self._ratio_threshold = self.Param("RatioThreshold", 8.0)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1)))
self._macd_prev = 0.0
self._macd_prev2 = 0.0
self._stop_loss_price = 0.0
self._take_profit_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(macd_pattern_trader_all_strategy, self).OnStarted2(time)
self._macd_prev = 0.0
self._macd_prev2 = 0.0
self._stop_loss_price = 0.0
self._take_profit_price = 0.0
macd = MovingAverageConvergenceDivergence()
macd.ShortMa.Length = int(self._fast_ema_period.Value)
macd.LongMa.Length = int(self._slow_ema_period.Value)
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(macd, self.ProcessCandle).Start()
def ProcessCandle(self, candle, macd_value):
if candle.State != CandleStates.Finished:
return
macd_curr = float(macd_value)
close = float(candle.ClosePrice)
low = float(candle.LowPrice)
high = float(candle.HighPrice)
pos = float(self.Position)
# Manage existing position
if pos > 0:
if low <= self._stop_loss_price or high >= self._take_profit_price:
self.SellMarket(pos)
self._stop_loss_price = 0.0
self._take_profit_price = 0.0
elif pos < 0:
if high >= self._stop_loss_price or low <= self._take_profit_price:
self.BuyMarket(abs(pos))
self._stop_loss_price = 0.0
self._take_profit_price = 0.0
if not self.IsFormedAndOnlineAndAllowTrading():
self._macd_prev2 = self._macd_prev
self._macd_prev = macd_curr
return
price_step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
offset = float(self._offset_points.Value) * price_step
stop_distance = offset * 2.0
take_distance = offset * 4.0
macd_last = self._macd_prev
macd_last3 = self._macd_prev2
ratio_thresh = float(self._ratio_threshold.Value)
if macd_last != 0.0:
ratio1 = abs(macd_last3 / macd_last)
ratio2 = abs(macd_curr / macd_last)
pos = float(self.Position)
vol = float(self.Volume)
if (macd_last3 > 0.0 or macd_curr < 0.0) and ratio1 >= ratio_thresh and ratio2 >= ratio_thresh and pos >= 0:
sl = close + stop_distance
tp = close - take_distance
volume = vol + abs(pos)
self.SellMarket(volume)
self._stop_loss_price = sl
self._take_profit_price = tp
elif (macd_last3 < 0.0 or macd_curr > 0.0) and ratio1 >= ratio_thresh and ratio2 >= ratio_thresh and pos <= 0:
sl = close - stop_distance
tp = close + take_distance
volume = vol + abs(pos)
self.BuyMarket(volume)
self._stop_loss_price = sl
self._take_profit_price = tp
self._macd_prev2 = self._macd_prev
self._macd_prev = macd_curr
def OnReseted(self):
super(macd_pattern_trader_all_strategy, self).OnReseted()
self._macd_prev = 0.0
self._macd_prev2 = 0.0
self._stop_loss_price = 0.0
self._take_profit_price = 0.0
def CreateClone(self):
return macd_pattern_trader_all_strategy()