Bullish Harami 戦略
強気のハラミは、小さな実体が前の弱気ローソク足の範囲内に収まる2本のローソク足パターンです。売りモメンタムが失速し、買い手が再び参入する可能性があることを示しています。
テストでは平均年間リターンが約40%であることが示されています。暗号資産市場で最もパフォーマンスが優れています。
この戦略は、2本目のローソク足が1本目の中に収まって引けたらロングエントリーし、次のバーで上方への継続を期待します。
パターンの下に置かれたパーセントストップが保護を提供し、価格がセットアップを下回って戻った場合に取引が終了します。
詳細
- エントリー条件: パターン一致
- ロング/ショート: 両方
- エグジット条件: ストップロスまたは逆シグナル
- ストップ: はい、パーセントベース
- デフォルト値:
CandleType= 15分StopLoss= 2%
- フィルター:
- カテゴリ: パターン
- 方向: 両方
- インジケーター: Candlestick
- ストップ: はい
- 複雑さ: 中級
- 時間軸: イントラデイ
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
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>
/// Harami Bullish strategy.
/// Enters long on bullish harami (bearish candle followed by smaller bullish candle inside it).
/// Enters short on bearish harami (bullish candle followed by smaller bearish candle inside it).
/// Uses SMA for exit confirmation.
/// Uses cooldown to control trade frequency.
/// </summary>
public class HaramiBullishStrategy : Strategy
{
private readonly StrategyParam<int> _maLength;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private ICandleMessage _prevCandle;
private int _cooldown;
/// <summary>
/// MA period for exit.
/// </summary>
public int MaLength
{
get => _maLength.Value;
set => _maLength.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Cooldown bars.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public HaramiBullishStrategy()
{
_maLength = Param(nameof(MaLength), 20)
.SetRange(10, 50)
.SetDisplay("MA Length", "Period of SMA for exit", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_cooldownBars = Param(nameof(CooldownBars), 500)
.SetRange(1, 1000)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevCandle = null;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCandle = null;
_cooldown = 0;
var sma = new SimpleMovingAverage { Length = MaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_prevCandle == null)
{
_prevCandle = candle;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevCandle = candle;
return;
}
// Bullish Harami: prev bearish, current bullish, current inside prev
var bullishHarami =
_prevCandle.ClosePrice < _prevCandle.OpenPrice &&
candle.ClosePrice > candle.OpenPrice &&
candle.HighPrice < _prevCandle.HighPrice &&
candle.LowPrice > _prevCandle.LowPrice;
// Bearish Harami: prev bullish, current bearish, current inside prev
var bearishHarami =
_prevCandle.ClosePrice > _prevCandle.OpenPrice &&
candle.ClosePrice < candle.OpenPrice &&
candle.HighPrice < _prevCandle.HighPrice &&
candle.LowPrice > _prevCandle.LowPrice;
if (Position == 0 && bullishHarami)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (Position == 0 && bearishHarami)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position > 0 && candle.ClosePrice < smaValue)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && candle.ClosePrice > smaValue)
{
BuyMarket();
_cooldown = CooldownBars;
}
_prevCandle = candle;
}
}
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class harami_bullish_strategy(Strategy):
"""
Harami Bullish strategy.
Enters long on bullish harami (bearish candle followed by smaller bullish candle inside it).
Enters short on bearish harami (bullish candle followed by smaller bearish candle inside it).
Uses SMA for exit confirmation.
"""
def __init__(self):
super(harami_bullish_strategy, self).__init__()
self._ma_length = self.Param("MaLength", 20).SetDisplay("MA Length", "Period of SMA for exit", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._cooldown_bars = self.Param("CooldownBars", 500).SetDisplay("Cooldown Bars", "Bars to wait between trades", "General")
self._prev_candle = None
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(harami_bullish_strategy, self).OnReseted()
self._prev_candle = None
self._cooldown = 0
def OnStarted2(self, time):
super(harami_bullish_strategy, self).OnStarted2(time)
self._prev_candle = None
self._cooldown = 0
sma = SimpleMovingAverage()
sma.Length = self._ma_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sma, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def _process_candle(self, candle, sma_val):
if candle.State != CandleStates.Finished:
return
if self._prev_candle is None:
self._prev_candle = candle
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_candle = candle
return
cd = self._cooldown_bars.Value
sv = float(sma_val)
# Bullish Harami: prev bearish, current bullish, current inside prev
bullish_harami = (
self._prev_candle.ClosePrice < self._prev_candle.OpenPrice and
candle.ClosePrice > candle.OpenPrice and
candle.HighPrice < self._prev_candle.HighPrice and
candle.LowPrice > self._prev_candle.LowPrice
)
# Bearish Harami: prev bullish, current bearish, current inside prev
bearish_harami = (
self._prev_candle.ClosePrice > self._prev_candle.OpenPrice and
candle.ClosePrice < candle.OpenPrice and
candle.HighPrice < self._prev_candle.HighPrice and
candle.LowPrice > self._prev_candle.LowPrice
)
if self.Position == 0 and bullish_harami:
self.BuyMarket()
self._cooldown = cd
elif self.Position == 0 and bearish_harami:
self.SellMarket()
self._cooldown = cd
elif self.Position > 0 and float(candle.ClosePrice) < sv:
self.SellMarket()
self._cooldown = cd
elif self.Position < 0 and float(candle.ClosePrice) > sv:
self.BuyMarket()
self._cooldown = cd
self._prev_candle = candle
def CreateClone(self):
return harami_bullish_strategy()