Color HMA Reversal
Strategy based on Hull Moving Average slope changes. It closes positions against the new direction and opens positions along the trend when the Hull MA reverses.
Parameters
HmaPeriod— period for Hull Moving Average.CandleType— type of candles to use.BuyOpen,SellOpen— allow opening long/short positions.BuyClose,SellClose— allow closing long/short positions.
Signals
- Upward reversal: previous HMA was falling and current value rises → close shorts and open a long.
- Downward reversal: previous HMA was rising and current value falls → close longs and open a short.
The strategy uses market orders and trades with the volume specified in Strategy.Volume.
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>
/// Strategy that trades on Hull Moving Average slope reversals.
/// Buys when HMA turns up, sells when HMA turns down.
/// </summary>
public class ColorHmaReversalStrategy : Strategy
{
private readonly StrategyParam<int> _hmaPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevValue1;
private decimal _prevValue2;
private int _count;
public int HmaPeriod { get => _hmaPeriod.Value; set => _hmaPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ColorHmaReversalStrategy()
{
_hmaPeriod = Param(nameof(HmaPeriod), 13)
.SetGreaterThanZero()
.SetDisplay("HMA Period", "Hull Moving Average period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).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();
_prevValue1 = default;
_prevValue2 = default;
_count = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_count = 0;
var hma = new HullMovingAverage { Length = HmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(hma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, hma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal hmaValue)
{
if (candle.State != CandleStates.Finished)
return;
_count++;
if (_count <= 2)
{
_prevValue2 = _prevValue1;
_prevValue1 = hmaValue;
return;
}
var wasFalling = _prevValue1 < _prevValue2;
var wasRising = _prevValue1 > _prevValue2;
var nowRising = hmaValue > _prevValue1;
var nowFalling = hmaValue < _prevValue1;
// HMA slope reversal from falling to rising -> buy
if (wasFalling && nowRising && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
// HMA slope reversal from rising to falling -> sell
else if (wasRising && nowFalling && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevValue2 = _prevValue1;
_prevValue1 = hmaValue;
}
}
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 HullMovingAverage
from StockSharp.Algo.Strategies import Strategy
class color_hma_reversal_strategy(Strategy):
def __init__(self):
super(color_hma_reversal_strategy, self).__init__()
self._hma_period = self.Param("HmaPeriod", 13) \
.SetDisplay("HMA Period", "Hull Moving Average period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._prev_value1 = 0.0
self._prev_value2 = 0.0
self._count = 0
@property
def HmaPeriod(self):
return self._hma_period.Value
@HmaPeriod.setter
def HmaPeriod(self, value):
self._hma_period.Value = value
@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(color_hma_reversal_strategy, self).OnStarted2(time)
self._count = 0
hma = HullMovingAverage()
hma.Length = self.HmaPeriod
self.SubscribeCandles(self.CandleType) \
.Bind(hma, self.ProcessCandle) \
.Start()
def ProcessCandle(self, candle, hma_value):
if candle.State != CandleStates.Finished:
return
val = float(hma_value)
self._count += 1
if self._count <= 2:
self._prev_value2 = self._prev_value1
self._prev_value1 = val
return
was_falling = self._prev_value1 < self._prev_value2
was_rising = self._prev_value1 > self._prev_value2
now_rising = val > self._prev_value1
now_falling = val < self._prev_value1
if was_falling and now_rising and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif was_rising and now_falling and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_value2 = self._prev_value1
self._prev_value1 = val
def OnReseted(self):
super(color_hma_reversal_strategy, self).OnReseted()
self._prev_value1 = 0.0
self._prev_value2 = 0.0
self._count = 0
def CreateClone(self):
return color_hma_reversal_strategy()