MACD Liquidity Tracker
MACD Liquidity Tracker uses MACD colour states to generate trading signals. Four modes (Fast, Normal, Safe, Crossover) adjust signal sensitivity. Optional stop loss and take profit are supported.
Details
- Data: Price candles.
- Entry Criteria:
- Long: Depends on
SystemType(defaultNormaluses MACD above signal). - Short: Depends on
SystemType(defaultNormaluses MACD below signal).
- Long: Depends on
- Exit Criteria: Opposite signal.
- Stops: Optional stop loss and take profit.
- Default Values:
FastLength= 25SlowLength= 60SignalLength= 220AllowShortTrades= falseSystemType= NormalUseStopLoss= falseStopLossPercent= 3UseTakeProfit= falseTakeProfitPercent= 6StartDate= 2018-01-01EndDate= 2069-12-31CandleType= tf(5)
- Filters:
- Category: Trend
- Direction: Long & Short
- Indicators: MACD
- Stops: Yes
- Complexity: Basic
- Timeframe: Intraday (5m)
- Seasonality: No
- Neural Networks: No
- Divergence: No
- Risk Level: Medium
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class MacdLiquidityTrackerStrategy : Strategy
{
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _emaFast;
private ExponentialMovingAverage _emaSlow;
private decimal _prevMacd;
private bool _initialized;
private int _barsFromSignal;
public int FastLength { get => _fastLength.Value; set => _fastLength.Value = value; }
public int SlowLength { get => _slowLength.Value; set => _slowLength.Value = value; }
public int CooldownBars { get => _cooldownBars.Value; set => _cooldownBars.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public MacdLiquidityTrackerStrategy()
{
_fastLength = Param(nameof(FastLength), 12).SetDisplay("Fast", "Fast EMA", "MACD");
_slowLength = Param(nameof(SlowLength), 26).SetDisplay("Slow", "Slow EMA", "MACD");
_cooldownBars = Param(nameof(CooldownBars), 10).SetDisplay("Cooldown", "Bars between signals", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candles", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_emaFast = null;
_emaSlow = null;
_prevMacd = 0m;
_initialized = false;
_barsFromSignal = int.MaxValue;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevMacd = 0;
_initialized = false;
_barsFromSignal = int.MaxValue;
_emaFast = new ExponentialMovingAverage { Length = FastLength };
_emaSlow = new ExponentialMovingAverage { Length = SlowLength };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(_emaFast, _emaSlow, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _emaFast);
DrawIndicator(area, _emaSlow);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
if (fast == 0 || slow == 0)
return;
var isFastAbove = fast > slow;
if (!_initialized) { _prevMacd = isFastAbove ? 1m : -1m; _initialized = true; _barsFromSignal = 0; return; }
if (_barsFromSignal < 10000) _barsFromSignal++;
var prevAbove = _prevMacd > 0;
var crossUp = isFastAbove && !prevAbove;
var crossDown = !isFastAbove && prevAbove;
var canSignal = _barsFromSignal >= CooldownBars;
if (canSignal && crossUp && Position <= 0)
{
BuyMarket();
_barsFromSignal = 0;
}
else if (canSignal && crossDown && Position >= 0)
{
SellMarket();
_barsFromSignal = 0;
}
_prevMacd = isFastAbove ? 1m : -1m;
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class macd_liquidity_tracker_strategy(Strategy):
"""
MACD Liquidity Tracker: fast/slow EMA crossover with cooldown.
"""
def __init__(self):
super(macd_liquidity_tracker_strategy, self).__init__()
self._fast_length = self.Param("FastLength", 12).SetDisplay("Fast", "Fast EMA", "MACD")
self._slow_length = self.Param("SlowLength", 26).SetDisplay("Slow", "Slow EMA", "MACD")
self._cooldown_bars = self.Param("CooldownBars", 10).SetDisplay("Cooldown", "Bars between signals", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candles", "General")
self._prev_above = False
self._is_init = False
self._bars_from_signal = 9999
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(macd_liquidity_tracker_strategy, self).OnReseted()
self._prev_above = False
self._is_init = False
self._bars_from_signal = 9999
def OnStarted2(self, time):
super(macd_liquidity_tracker_strategy, self).OnStarted2(time)
fast = ExponentialMovingAverage()
fast.Length = self._fast_length.Value
slow = ExponentialMovingAverage()
slow.Length = self._slow_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast, slow, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def _process_candle(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
fast = float(fast_val)
slow = float(slow_val)
if fast == 0 or slow == 0:
return
is_above = fast > slow
if not self._is_init:
self._prev_above = is_above
self._is_init = True
self._bars_from_signal = 0
return
self._bars_from_signal += 1
cross_up = is_above and not self._prev_above
cross_down = not is_above and self._prev_above
can_signal = self._bars_from_signal >= self._cooldown_bars.Value
if can_signal and cross_up and self.Position <= 0:
self.BuyMarket()
self._bars_from_signal = 0
elif can_signal and cross_down and self.Position >= 0:
self.SellMarket()
self._bars_from_signal = 0
self._prev_above = is_above
def CreateClone(self):
return macd_liquidity_tracker_strategy()