Heikin Ashi Consecutive 戦略
連続Heikin Ashi足に基づく戦略
テストでは年平均リターンが約73%であることが示されています。暗号資産市場で最もよく機能します。
Heikin Ashi Consecutiveは、モメンタムを確認するために同じ色のHeikin Ashi足が複数連続するのを待ちます。強気または弱気のバーが連続した後、戦略はその動きに乗り、最初の逆方向の足またはパーセントストップで退場します。
Heikin Ashiチャートは価格データを平滑化するため、同じ色の足の連続は強い方向性の動きを強調します。パーセントストップは、連続が急反転した場合の損失を限定します。
詳細
- エントリー条件: Heikinに基づくシグナル。
- ロング/ショート: 両方向。
- エグジット条件: 逆シグナルまたはストップ。
- ストップ: はい。
- デフォルト値:
ConsecutiveCandles= 3StopLossPercent= 2mCandleType= TimeSpan.FromMinutes(5)
- フィルター:
- カテゴリ: トレンド
- 方向: 両方
- インジケーター: Heikin
- ストップ: はい
- 複雑さ: 基本
- 時間軸: イントラデイ (5m)
- 季節性: いいえ
- Neural Networks: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
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 consecutive Heikin Ashi candles.
/// It enters long position after a sequence of bullish Heikin Ashi candles and
/// short position after a sequence of bearish Heikin Ashi candles,
/// and exits on the first opposite candle or at the percent stop.
/// </summary>
public class HeikinAshiConsecutiveStrategy : Strategy
{
private readonly StrategyParam<int> _consecutiveCandles;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
// State tracking
private int _bullishCount;
private int _bearishCount;
private decimal? _prevHaOpen;
private decimal _prevHaClose;
/// <summary>
/// Number of consecutive candles required for signal.
/// </summary>
public int ConsecutiveCandles
{
get => _consecutiveCandles.Value;
set => _consecutiveCandles.Value = value;
}
/// <summary>
/// Stop-loss percentage.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initialize the Heikin Ashi Consecutive strategy.
/// </summary>
public HeikinAshiConsecutiveStrategy()
{
_consecutiveCandles = Param(nameof(ConsecutiveCandles), 3)
.SetGreaterThanZero()
.SetDisplay("Consecutive Candles", "Number of consecutive candles required for signal", "Trading parameters")
.SetOptimize(5, 10, 1);
_stopLossPercent = Param(nameof(StopLossPercent), 2m)
.SetNotNegative()
.SetDisplay("Stop Loss (%)", "Stop loss as a percentage of entry price", "Risk parameters")
.SetOptimize(1, 3, 0.5m);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_bullishCount = default;
_bearishCount = default;
_prevHaOpen = null;
_prevHaClose = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Create subscription
var subscription = SubscribeCandles(CandleType);
// We need to calculate Heikin-Ashi candles in the ProcessCandle handler
subscription
.Bind(ProcessCandle)
.Start();
// Setup chart visualization if available
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
// Start protection with stop loss
StartProtection(new Unit(), new Unit(StopLossPercent, UnitTypes.Percent), useMarketOrders: true, isLocalStop: true);
// The stop has to see prices between candles, not only at their close.
foreach (var field in new[] { Level1Fields.BestBidPrice, Level1Fields.BestAskPrice })
{
var quotes = new Subscription(DataType.Level1, Security);
quotes.MarketData.BuildField = field;
SubscribeLevel1(quotes).Bind(ObserveProtectionQuote).Start();
}
}
private void ObserveProtectionQuote(Level1ChangeMessage quote)
{
// The high-level handler activates native protection before this callback, also between signal bars.
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var haClose = (candle.OpenPrice + candle.ClosePrice + candle.HighPrice + candle.LowPrice) / 4;
var haOpen = _prevHaOpen is decimal prevOpen
? (prevOpen + _prevHaClose) / 2
: (candle.OpenPrice + candle.ClosePrice) / 2;
_prevHaOpen = haOpen;
_prevHaClose = haClose;
var isBullish = haClose > haOpen;
var isBearish = haClose < haOpen;
_bullishCount = isBullish ? _bullishCount + 1 : 0;
_bearishCount = isBearish ? _bearishCount + 1 : 0;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (Position > 0)
{
// The first bearish candle ends a long position.
if (isBearish)
SellMarket(_bearishCount >= ConsecutiveCandles ? Volume + Position : Position);
}
else if (Position < 0)
{
if (isBullish)
BuyMarket(_bullishCount >= ConsecutiveCandles ? Volume - Position : -Position);
}
else if (_bullishCount >= ConsecutiveCandles)
{
BuyMarket(Volume);
}
else if (_bearishCount >= ConsecutiveCandles)
{
SellMarket(Volume);
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan, Math, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes, Level1Fields
from StockSharp.BusinessEntities import Subscription
from StockSharp.Algo.Strategies import Strategy
class heikin_ashi_consecutive_strategy(Strategy):
"""
Strategy based on consecutive Heikin Ashi candles.
It enters long position after a sequence of bullish Heikin Ashi candles and
short position after a sequence of bearish Heikin Ashi candles,
and exits on the first opposite candle or at the percent stop.
"""
def __init__(self):
super(heikin_ashi_consecutive_strategy, self).__init__()
self._consecutive_candles = self.Param("ConsecutiveCandles", 3) \
.SetGreaterThanZero() \
.SetDisplay("Consecutive Candles", "Number of consecutive candles required for signal", "Trading parameters")
self._stop_loss_percent = self.Param("StopLossPercent", 2.0) \
.SetNotNegative() \
.SetDisplay("Stop Loss (%)", "Stop loss as a percentage of entry price", "Risk parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._bullish_count = 0
self._bearish_count = 0
self._prev_ha_open = None
self._prev_ha_close = Decimal(0)
def OnStarted2(self, time):
super(heikin_ashi_consecutive_strategy, self).OnStarted2(time)
subscription = self.SubscribeCandles(self._candle_type.Value)
subscription.Bind(self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
self.StartProtection(Unit(), Unit(Decimal(self._stop_loss_percent.Value), UnitTypes.Percent), useMarketOrders=True, isLocalStop=True)
# The stop has to see prices between candles, not only at their close.
for field in (Level1Fields.BestBidPrice, Level1Fields.BestAskPrice):
quotes = Subscription(DataType.Level1, self.Security)
quotes.MarketData.BuildField = field
self.SubscribeLevel1(quotes).Bind(self._observe_protection_quote).Start()
def _observe_protection_quote(self, quote):
# The high-level handler activates native protection before the callback, including between bars.
pass
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
ha_close = (candle.OpenPrice + candle.ClosePrice + candle.HighPrice + candle.LowPrice) / Decimal(4)
if self._prev_ha_open is None:
ha_open = (candle.OpenPrice + candle.ClosePrice) / Decimal(2)
else:
ha_open = (self._prev_ha_open + self._prev_ha_close) / Decimal(2)
self._prev_ha_open = ha_open
self._prev_ha_close = ha_close
is_bullish = ha_close > ha_open
is_bearish = ha_close < ha_open
self._bullish_count = self._bullish_count + 1 if is_bullish else 0
self._bearish_count = self._bearish_count + 1 if is_bearish else 0
if not self.IsFormedAndOnlineAndAllowTrading():
return
required = self._consecutive_candles.Value
position = self.Position
if position > 0:
# The first bearish candle ends a long position.
if is_bearish:
self.SellMarket(self.Volume + position if self._bearish_count >= required else position)
elif position < 0:
if is_bullish:
self.BuyMarket(self.Volume - position if self._bullish_count >= required else -position)
elif self._bullish_count >= required:
self.BuyMarket(self.Volume)
elif self._bearish_count >= required:
self.SellMarket(self.Volume)
def OnReseted(self):
super(heikin_ashi_consecutive_strategy, self).OnReseted()
self._bullish_count = 0
self._bearish_count = 0
self._prev_ha_open = None
self._prev_ha_close = Decimal(0)
def CreateClone(self):
return heikin_ashi_consecutive_strategy()