3Commas HA & MA
Uses Heikin Ashi candles and a pair of exponential moving averages. A long trade occurs when a bearish HA candle is followed by a bullish one while the fast MA is above the slow MA. Shorts follow the opposite setup. Positions are closed when price crosses the slow MA or hits the swing stop.
Details
- Entry Criteria: Heikin Ashi reversal with MA confirmation.
- Long/Short: Both directions.
- Exit Criteria: Price crosses slow MA or stop.
- Stops: Swing high/low.
- Default Values:
MaFast= 9MaSlow= 18CandleType= TimeSpan.FromMinutes(1)
- Filters:
- Category: Trend
- Direction: Both
- Indicators: Heikin Ashi, EMA
- Stops: Yes
- Complexity: Intermediate
- Timeframe: Intraday
- Seasonality: No
- Neural Networks: No
- Divergence: No
- Risk Level: Medium
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>
/// Heikin Ashi with moving averages.
/// </summary>
public class ThreeCommasHaMaStrategy : Strategy
{
private readonly StrategyParam<int> _maFast;
private readonly StrategyParam<int> _maSlow;
private readonly StrategyParam<DataType> _candleType;
private decimal _haOpenPrev;
private decimal _haClosePrev;
private decimal _stopPrice;
public int MaFast
{
get => _maFast.Value;
set => _maFast.Value = value;
}
public int MaSlow
{
get => _maSlow.Value;
set => _maSlow.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public ThreeCommasHaMaStrategy()
{
_maFast = Param(nameof(MaFast), 9)
.SetDisplay("MA Fast", "Fast moving average period", "MA");
_maSlow = Param(nameof(MaSlow), 18)
.SetDisplay("MA Slow", "Slow moving average period", "MA");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_haOpenPrev = 0m;
_haClosePrev = 0m;
_stopPrice = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ma1 = new ExponentialMovingAverage { Length = MaFast };
var ma2 = new ExponentialMovingAverage { Length = MaSlow };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ma1, ma2, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ma1);
DrawIndicator(area, ma2);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal ma1, decimal ma2)
{
if (candle.State != CandleStates.Finished)
return;
var haClose = (candle.OpenPrice + candle.HighPrice + candle.LowPrice + candle.ClosePrice) / 4m;
var haOpen = (_haOpenPrev == 0m && _haClosePrev == 0m) ? (candle.OpenPrice + candle.ClosePrice) / 2m : (_haOpenPrev + _haClosePrev) / 2m;
var haBull = haClose > haOpen;
var haBearPrev = _haClosePrev < _haOpenPrev;
var haBullPrev = _haClosePrev > _haOpenPrev;
if (haBearPrev && ma1 > ma2 && haBull && candle.ClosePrice > ma1 && Position <= 0)
{
_stopPrice = candle.LowPrice;
BuyMarket();
}
else if (haBullPrev && ma1 < ma2 && !haBull && candle.ClosePrice < ma1 && Position >= 0)
{
_stopPrice = candle.HighPrice;
SellMarket();
}
if (Position > 0 && candle.ClosePrice < ma2)
SellMarket();
else if (Position < 0 && candle.ClosePrice > ma2)
BuyMarket();
_haOpenPrev = haOpen;
_haClosePrev = haClose;
}
}
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 three_commas_ha_ma_strategy(Strategy):
def __init__(self):
super(three_commas_ha_ma_strategy, self).__init__()
self._ma_fast = self.Param("MaFast", 9) \
.SetDisplay("MA Fast", "Fast moving average period", "MA")
self._ma_slow = self.Param("MaSlow", 18) \
.SetDisplay("MA Slow", "Slow moving average period", "MA")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._ha_open_prev = 0.0
self._ha_close_prev = 0.0
self._stop_price = 0.0
@property
def ma_fast(self):
return self._ma_fast.Value
@property
def ma_slow(self):
return self._ma_slow.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(three_commas_ha_ma_strategy, self).OnReseted()
self._ha_open_prev = 0.0
self._ha_close_prev = 0.0
self._stop_price = 0.0
def OnStarted2(self, time):
super(three_commas_ha_ma_strategy, self).OnStarted2(time)
ma1 = ExponentialMovingAverage()
ma1.Length = self.ma_fast
ma2 = ExponentialMovingAverage()
ma2.Length = self.ma_slow
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ma1, ma2, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ma1)
self.DrawIndicator(area, ma2)
self.DrawOwnTrades(area)
def on_process(self, candle, ma1, ma2):
if candle.State != CandleStates.Finished:
return
ha_close = (candle.OpenPrice + candle.HighPrice + candle.LowPrice + candle.ClosePrice) / 4
ha_open = ((candle.OpenPrice + candle.ClosePrice) / 2 if (self._ha_open_prev == 0 and self._ha_close_prev == 0) else (self._ha_open_prev + self._ha_close_prev) / 2)
ha_bull = ha_close > ha_open
ha_bear_prev = self._ha_close_prev < self._ha_open_prev
ha_bull_prev = self._ha_close_prev > self._ha_open_prev
if ha_bear_prev and ma1 > ma2 and ha_bull and candle.ClosePrice > ma1 and self.Position <= 0:
self._stop_price = candle.LowPrice
self.BuyMarket()
elif ha_bull_prev and ma1 < ma2 and not ha_bull and candle.ClosePrice < ma1 and self.Position >= 0:
self._stop_price = candle.HighPrice
self.SellMarket()
if self.Position > 0 and candle.ClosePrice < ma2:
self.SellMarket()
elif self.Position < 0 and candle.ClosePrice > ma2:
self.BuyMarket()
self._ha_open_prev = ha_open
self._ha_close_prev = ha_close
def CreateClone(self):
return three_commas_ha_ma_strategy()