Estratégia Macd Vwap
Estratégia baseada nos indicadores MACD e VWAP. Entra comprado quando MACD > Signal e preço > VWAP. Entra vendido quando MACD < Signal e preço < VWAP.
Os testes indicam um retorno anual médio de aproximadamente 109%. Funciona melhor no mercado de criptomoedas.
O momentum do MACD é medido em relação à linha VWAP. Operações compradas buscam força do MACD abaixo do VWAP, enquanto as vendidas se formam acima dele.
Ideal para operadores de momentum intradiário que usam referências ponderadas por volume. Stops baseados em ATR gerenciam o risco.
Detalhes
- Critérios de entrada:
- Comprado:
MACD > Signal && Close > VWAP - Vendido:
MACD < Signal && Close < VWAP
- Comprado:
- Comprado/Vendido: Ambos
- Critérios de saída: Cruzamento do MACD na direção oposta
- Stops: Percentual usando
StopLossPercent - Valores padrão:
MacdFast= 12MacdSlow= 26MacdSignal= 9StopLossPercent= 2.0mCandleType= TimeSpan.FromMinutes(5).TimeFrame()
- Filtros:
- Categoria: Reversão à média
- Direção: Ambos
- Indicadores: MACD, VWAP
- Stops: Sim
- Complexidade: Intermediário
- Período: Médio prazo
- Sazonalidade: Não
- Redes neurais: Não
- Divergência: Não
- Nível de risco: Médio
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 based on MACD and VWAP indicators.
/// Enters long when MACD > Signal and price > VWAP
/// Enters short when MACD < Signal and price < VWAP
/// </summary>
public class MacdVwapStrategy : Strategy
{
private readonly StrategyParam<int> _macdFast;
private readonly StrategyParam<int> _macdSlow;
private readonly StrategyParam<int> _macdSignal;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private int _cooldown;
private bool _hasPrevDiff;
private decimal _prevDiff;
/// <summary>
/// MACD fast period
/// </summary>
public int MacdFast
{
get => _macdFast.Value;
set => _macdFast.Value = value;
}
/// <summary>
/// MACD slow period
/// </summary>
public int MacdSlow
{
get => _macdSlow.Value;
set => _macdSlow.Value = value;
}
/// <summary>
/// MACD signal period
/// </summary>
public int MacdSignal
{
get => _macdSignal.Value;
set => _macdSignal.Value = value;
}
/// <summary>
/// Bars to wait between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Stop-loss percentage
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Candle type for strategy calculation
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor
/// </summary>
public MacdVwapStrategy()
{
_macdFast = Param(nameof(MacdFast), 12)
.SetGreaterThanZero()
.SetDisplay("MACD Fast Period", "Fast EMA period for MACD", "Indicators")
.SetOptimize(8, 16, 2);
_macdSlow = Param(nameof(MacdSlow), 26)
.SetGreaterThanZero()
.SetDisplay("MACD Slow Period", "Slow EMA period for MACD", "Indicators")
.SetOptimize(20, 30, 2);
_macdSignal = Param(nameof(MacdSignal), 9)
.SetGreaterThanZero()
.SetDisplay("MACD Signal Period", "Signal line period for MACD", "Indicators")
.SetOptimize(7, 12, 1);
_cooldownBars = Param(nameof(CooldownBars), 35)
.SetRange(1, 200)
.SetDisplay("Cooldown Bars", "Bars between new entries", "General");
_stopLossPercent = Param(nameof(StopLossPercent), 2.0m)
.SetGreaterThanZero()
.SetDisplay("Stop Loss %", "Stop loss as percentage of entry price", "Risk Management")
.SetOptimize(1.0m, 3.0m, 0.5m);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for strategy", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_cooldown = 0;
_hasPrevDiff = false;
_prevDiff = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Create indicators
var macd = new MovingAverageConvergenceDivergenceSignal
{
Macd =
{
ShortMa = { Length = MacdFast },
LongMa = { Length = MacdSlow },
},
SignalMa = { Length = MacdSignal }
};
var vwap = new VolumeWeightedMovingAverage();
// Subscribe to candles and bind indicators
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(macd, vwap, ProcessCandle)
.Start();
// Setup chart visualization if available
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, macd);
DrawIndicator(area, vwap);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue, IIndicatorValue vwapValue)
{
// Skip unfinished candles
if (candle.State != CandleStates.Finished)
return;
// Check if strategy is ready to trade
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Get additional values from MACD (signal line)
var macdTyped = (MovingAverageConvergenceDivergenceSignalValue)macdValue;
var macd = macdTyped.Macd ?? 0m;
var signal = macdTyped.Signal ?? 0m;
var vwap = vwapValue.ToDecimal();
// Current price (close of the candle)
var price = candle.ClosePrice;
var diff = macd - signal;
if (!_hasPrevDiff)
{
_hasPrevDiff = true;
_prevDiff = diff;
return;
}
var crossUp = _prevDiff <= 0m && diff > 0m;
var crossDown = _prevDiff >= 0m && diff < 0m;
if (_cooldown > 0)
{
_cooldown--;
_prevDiff = diff;
return;
}
// Trading logic
if (crossUp && price > vwap * 1.001m && Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
_cooldown = CooldownBars;
}
else if (crossDown && price < vwap * 0.999m && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
_cooldown = CooldownBars;
}
else if (crossDown && Position > 0)
{
SellMarket(Position);
_cooldown = CooldownBars;
}
else if (crossUp && Position < 0)
{
BuyMarket(Math.Abs(Position));
_cooldown = CooldownBars;
}
_prevDiff = diff;
}
}
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 MovingAverageConvergenceDivergenceSignal, VolumeWeightedMovingAverage
from StockSharp.Algo.Strategies import Strategy
class macd_vwap_strategy(Strategy):
"""
MACD + VWAP: enters long when MACD crosses above signal and price above VWAP.
"""
def __init__(self):
super(macd_vwap_strategy, self).__init__()
self._macd_fast = self.Param("MacdFast", 12).SetDisplay("MACD Fast", "Fast EMA period", "Indicators")
self._macd_slow = self.Param("MacdSlow", 26).SetDisplay("MACD Slow", "Slow EMA period", "Indicators")
self._macd_signal = self.Param("MacdSignal", 9).SetDisplay("MACD Signal", "Signal line period", "Indicators")
self._cooldown_bars = self.Param("CooldownBars", 35).SetDisplay("Cooldown Bars", "Bars between entries", "General")
self._stop_loss_percent = self.Param("StopLossPercent", 2.0).SetDisplay("Stop Loss %", "Stop loss pct", "Risk Management")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Timeframe", "General")
self._cooldown = 0
self._has_prev_diff = False
self._prev_diff = 0.0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(macd_vwap_strategy, self).OnReseted()
self._cooldown = 0
self._has_prev_diff = False
self._prev_diff = 0.0
def OnStarted2(self, time):
super(macd_vwap_strategy, self).OnStarted2(time)
self._cooldown = 0
self._has_prev_diff = False
self._prev_diff = 0.0
macd = MovingAverageConvergenceDivergenceSignal()
macd.Macd.ShortMa.Length = self._macd_fast.Value
macd.Macd.LongMa.Length = self._macd_slow.Value
macd.SignalMa.Length = self._macd_signal.Value
vwap = VolumeWeightedMovingAverage()
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(macd, vwap, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, macd)
self.DrawIndicator(area, vwap)
self.DrawOwnTrades(area)
def _process_candle(self, candle, macd_value, vwap_value):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
macd_line = macd_value.Macd
signal_line = macd_value.Signal
if macd_line is None or signal_line is None:
return
macd_f = float(macd_line)
signal_f = float(signal_line)
vwap_f = float(vwap_value)
price = float(candle.ClosePrice)
diff = macd_f - signal_f
if not self._has_prev_diff:
self._has_prev_diff = True
self._prev_diff = diff
return
cross_up = self._prev_diff <= 0 and diff > 0
cross_down = self._prev_diff >= 0 and diff < 0
if self._cooldown > 0:
self._cooldown -= 1
self._prev_diff = diff
return
if cross_up and price > vwap_f * 1.001 and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
self._cooldown = self._cooldown_bars.Value
elif cross_down and price < vwap_f * 0.999 and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
self._cooldown = self._cooldown_bars.Value
elif cross_down and self.Position > 0:
self.SellMarket(self.Position)
self._cooldown = self._cooldown_bars.Value
elif cross_up and self.Position < 0:
self.BuyMarket(abs(self.Position))
self._cooldown = self._cooldown_bars.Value
self._prev_diff = diff
def CreateClone(self):
return macd_vwap_strategy()