Ichimoku 転換線/基準線クロスストラテジー
Ichimokuインジケーターは完全なトレンドフォローシステムを提供します。このアプローチは、価格が雲(Kumo)に対してどこで取引されているかを見ながら、転換線(Tenkan-sen)が基準線(Kijun-sen)を交差する点に焦点を当てます。雲の上でのブルッシュなクロスはトレンド継続の上昇を示し、雲の下でのベアリッシュなクロスは弱さを示唆します。
テストでは年平均リターン約142%を示しています。株式市場で最も優れたパフォーマンスを発揮します。
稼働中、戦略は各バーでIchimokuのコンポーネントを計算します。転換線が基準線を上抜け、価格が雲の上にある場合、基準線近くにストップを置いたロングトレードが開始されます。雲の下での逆方向のクロスが同様のストップ配置でショートを引き起こします。
システムはストップが当たるかクロスが反転するまでトレードを保持し、雲の方向に沿った持続的な動きを捉えることを目指します。
詳細
- エントリー条件: 雲(Kumo)に対する価格の位置を伴う転換線/基準線クロス。
- ロング/ショート: 両方。
- エグジット条件: ストップロスまたは逆方向のクロス。
- ストップ: はい、基準線レベル。
- デフォルト値:
TenkanPeriod= 9KijunPeriod= 26SenkouSpanBPeriod= 52CandleType= 30 minute
- フィルター:
- カテゴリ: トレンドフォロー
- 方向: 両方
- インジケーター: Ichimoku
- ストップ: はい
- 複雑さ: 中級
- 時間軸: スイング
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
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>
/// Ichimoku Tenkan/Kijun Cross strategy.
/// Enters long when Tenkan crosses above Kijun and price is above Kumo.
/// Enters short when Tenkan crosses below Kijun and price is below Kumo.
/// Exits on opposite cross or Kumo breach.
/// </summary>
public class IchimokuTenkanKijunStrategy : Strategy
{
private readonly StrategyParam<int> _tenkanPeriod;
private readonly StrategyParam<int> _kijunPeriod;
private readonly StrategyParam<int> _senkouSpanBPeriod;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private decimal _prevTenkan;
private decimal _prevKijun;
private int _cooldown;
/// <summary>
/// Tenkan period.
/// </summary>
public int TenkanPeriod
{
get => _tenkanPeriod.Value;
set => _tenkanPeriod.Value = value;
}
/// <summary>
/// Kijun period.
/// </summary>
public int KijunPeriod
{
get => _kijunPeriod.Value;
set => _kijunPeriod.Value = value;
}
/// <summary>
/// Senkou Span B period.
/// </summary>
public int SenkouSpanBPeriod
{
get => _senkouSpanBPeriod.Value;
set => _senkouSpanBPeriod.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 IchimokuTenkanKijunStrategy()
{
_tenkanPeriod = Param(nameof(TenkanPeriod), 9)
.SetRange(7, 13)
.SetDisplay("Tenkan Period", "Period for Tenkan-sen", "Ichimoku");
_kijunPeriod = Param(nameof(KijunPeriod), 26)
.SetRange(20, 30)
.SetDisplay("Kijun Period", "Period for Kijun-sen", "Ichimoku");
_senkouSpanBPeriod = Param(nameof(SenkouSpanBPeriod), 52)
.SetRange(40, 60)
.SetDisplay("Senkou Span B Period", "Period for Senkou Span B", "Ichimoku");
_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();
_prevTenkan = default;
_prevKijun = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevTenkan = 0;
_prevKijun = 0;
_cooldown = 0;
var ichimoku = new Ichimoku
{
Tenkan = { Length = TenkanPeriod },
Kijun = { Length = KijunPeriod },
SenkouB = { Length = SenkouSpanBPeriod }
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(ichimoku, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ichimoku);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue ichimokuIv)
{
if (candle.State != CandleStates.Finished)
return;
if (!ichimokuIv.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var iv = (IchimokuValue)ichimokuIv;
if (iv.Tenkan is not decimal tenkan || iv.Kijun is not decimal kijun ||
iv.SenkouA is not decimal senkouA || iv.SenkouB is not decimal senkouB)
return;
if (_prevTenkan == 0 || _prevKijun == 0)
{
_prevTenkan = tenkan;
_prevKijun = kijun;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevTenkan = tenkan;
_prevKijun = kijun;
return;
}
var bullishCross = _prevTenkan <= _prevKijun && tenkan > kijun;
var bearishCross = _prevTenkan >= _prevKijun && tenkan < kijun;
var upperKumo = Math.Max(senkouA, senkouB);
var lowerKumo = Math.Min(senkouA, senkouB);
if (Position == 0 && bullishCross && candle.ClosePrice > upperKumo)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (Position == 0 && bearishCross && candle.ClosePrice < lowerKumo)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position > 0 && (bearishCross || candle.ClosePrice < lowerKumo))
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && (bullishCross || candle.ClosePrice > upperKumo))
{
BuyMarket();
_cooldown = CooldownBars;
}
_prevTenkan = tenkan;
_prevKijun = kijun;
}
}
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 Ichimoku
from StockSharp.Algo.Strategies import Strategy
class ichimoku_tenkan_kijun_strategy(Strategy):
"""
Ichimoku Tenkan/Kijun Cross strategy.
Enters long when Tenkan crosses above Kijun and price is above Kumo.
Enters short when Tenkan crosses below Kijun and price is below Kumo.
Exits on opposite cross or Kumo breach.
"""
def __init__(self):
super(ichimoku_tenkan_kijun_strategy, self).__init__()
self._tenkan_period = self.Param("TenkanPeriod", 9).SetDisplay("Tenkan Period", "Period for Tenkan-sen", "Ichimoku")
self._kijun_period = self.Param("KijunPeriod", 26).SetDisplay("Kijun Period", "Period for Kijun-sen", "Ichimoku")
self._senkou_span_b_period = self.Param("SenkouSpanBPeriod", 52).SetDisplay("Senkou Span B Period", "Period for Senkou Span B", "Ichimoku")
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_tenkan = 0.0
self._prev_kijun = 0.0
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(ichimoku_tenkan_kijun_strategy, self).OnReseted()
self._prev_tenkan = 0.0
self._prev_kijun = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(ichimoku_tenkan_kijun_strategy, self).OnStarted2(time)
self._prev_tenkan = 0.0
self._prev_kijun = 0.0
self._cooldown = 0
ichimoku = Ichimoku()
ichimoku.Tenkan.Length = self._tenkan_period.Value
ichimoku.Kijun.Length = self._kijun_period.Value
ichimoku.SenkouB.Length = self._senkou_span_b_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(ichimoku, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ichimoku)
self.DrawOwnTrades(area)
def _process_candle(self, candle, ichimoku_iv):
if candle.State != CandleStates.Finished:
return
if not ichimoku_iv.IsFormed:
return
tenkan_val = ichimoku_iv.Tenkan
kijun_val = ichimoku_iv.Kijun
senkou_a_val = ichimoku_iv.SenkouA
senkou_b_val = ichimoku_iv.SenkouB
if tenkan_val is None or kijun_val is None or senkou_a_val is None or senkou_b_val is None:
return
tenkan = float(tenkan_val)
kijun = float(kijun_val)
senkou_a = float(senkou_a_val)
senkou_b = float(senkou_b_val)
if self._prev_tenkan == 0 or self._prev_kijun == 0:
self._prev_tenkan = tenkan
self._prev_kijun = kijun
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_tenkan = tenkan
self._prev_kijun = kijun
return
bullish_cross = self._prev_tenkan <= self._prev_kijun and tenkan > kijun
bearish_cross = self._prev_tenkan >= self._prev_kijun and tenkan < kijun
upper_kumo = max(senkou_a, senkou_b)
lower_kumo = min(senkou_a, senkou_b)
close = float(candle.ClosePrice)
cd = self._cooldown_bars.Value
if self.Position == 0 and bullish_cross and close > upper_kumo:
self.BuyMarket()
self._cooldown = cd
elif self.Position == 0 and bearish_cross and close < lower_kumo:
self.SellMarket()
self._cooldown = cd
elif self.Position > 0 and (bearish_cross or close < lower_kumo):
self.SellMarket()
self._cooldown = cd
elif self.Position < 0 and (bullish_cross or close > upper_kumo):
self.BuyMarket()
self._cooldown = cd
self._prev_tenkan = tenkan
self._prev_kijun = kijun
def CreateClone(self):
return ichimoku_tenkan_kijun_strategy()