Ichimoku クラウド買いカスタムEMAエグジット戦略
カスタムEMAエグジットと出来高フィルターを備えたIchimokuクラウド買い戦略の実装です。価格がクラウドの上にあり、出来高が平均を超えているときに買いエントリーします。オプションで価格がEMAの上にあることを要求できます。価格がEMAを下回るか、またはストップロスに達した時点でポジションを手仕舞います。
詳細
- エントリー条件:
- ロング:
Price > Cloud && Volume > AvgVolume && (Price > EMA if enabled)
- ロング:
- ロング/ショート: ロングのみ
- エグジット条件:
Price < EMA
- ストップ:
StopLossPercentを使用したパーセントベース - デフォルト値:
TenkanPeriod= 9KijunPeriod= 26SenkouSpanPeriod= 52EmaLength= 44VolumeAvgPeriod= 10StopLossPercent= 2CandleType= TimeSpan.FromMinutes(5).TimeFrame()
- フィルター:
- カテゴリ: トレンドフォロー
- 方向: ロングのみ
- インジケーター: Ichimoku Cloud, EMA, 出来高
- ストップ: はい
- 複雑さ: 初心者
- 時間軸: 中期
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
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 cloud buy with custom EMA exit strategy.
/// Long only. A long opens when the close is above the Ichimoku cloud and the candle volume exceeds its VolumeAvgPeriod average,
/// optionally also requiring the close above the EmaLength EMA. The position closes when the close falls below the EMA,
/// and a percent stop loss limits the loss.
/// </summary>
public class IchimokuCloudBuyCustomEmaExitStrategy : Strategy
{
private readonly StrategyParam<int> _tenkanPeriod;
private readonly StrategyParam<int> _kijunPeriod;
private readonly StrategyParam<int> _senkouSpanPeriod;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _volumeAvgPeriod;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<bool> _useEmaFilter;
private readonly StrategyParam<DataType> _candleType;
private SimpleMovingAverage _volumeSma;
/// <summary>
/// Tenkan-sen period.
/// </summary>
public int TenkanPeriod
{
get => _tenkanPeriod.Value;
set => _tenkanPeriod.Value = value;
}
/// <summary>
/// Kijun-sen period.
/// </summary>
public int KijunPeriod
{
get => _kijunPeriod.Value;
set => _kijunPeriod.Value = value;
}
/// <summary>
/// Senkou Span B period.
/// </summary>
public int SenkouSpanPeriod
{
get => _senkouSpanPeriod.Value;
set => _senkouSpanPeriod.Value = value;
}
/// <summary>
/// Exit EMA period.
/// </summary>
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
/// <summary>
/// Volume average period.
/// </summary>
public int VolumeAvgPeriod
{
get => _volumeAvgPeriod.Value;
set => _volumeAvgPeriod.Value = value;
}
/// <summary>
/// Stop loss percentage from entry price.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Require the close above the EMA for entries.
/// </summary>
public bool UseEmaFilter
{
get => _useEmaFilter.Value;
set => _useEmaFilter.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public IchimokuCloudBuyCustomEmaExitStrategy()
{
_tenkanPeriod = Param(nameof(TenkanPeriod), 9)
.SetGreaterThanZero()
.SetDisplay("Tenkan Period", "Tenkan-sen period", "Ichimoku");
_kijunPeriod = Param(nameof(KijunPeriod), 26)
.SetGreaterThanZero()
.SetDisplay("Kijun Period", "Kijun-sen period", "Ichimoku");
_senkouSpanPeriod = Param(nameof(SenkouSpanPeriod), 52)
.SetGreaterThanZero()
.SetDisplay("Senkou Span Period", "Senkou Span B period", "Ichimoku");
_emaLength = Param(nameof(EmaLength), 44)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "Exit EMA period", "Exit");
_volumeAvgPeriod = Param(nameof(VolumeAvgPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Volume Avg Period", "Volume average period", "Volume");
_stopLossPercent = Param(nameof(StopLossPercent), 2m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk");
_useEmaFilter = Param(nameof(UseEmaFilter), true)
.SetDisplay("Use EMA Filter", "Require the close above the EMA for entries", "Exit");
_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();
_volumeSma = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_volumeSma = new SimpleMovingAverage { Length = VolumeAvgPeriod };
var ichimoku = new Ichimoku
{
Tenkan = { Length = TenkanPeriod },
Kijun = { Length = KijunPeriod },
SenkouB = { Length = SenkouSpanPeriod },
};
var ema = new ExponentialMovingAverage { Length = EmaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(ichimoku, ema, ProcessCandle)
.Start();
StartProtection(new Unit(), new Unit(StopLossPercent, UnitTypes.Percent), useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ichimoku);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue ichimokuValue, IIndicatorValue emaValue)
{
if (candle.State != CandleStates.Finished)
return;
var volume = candle.TotalVolume;
var volumeValue = _volumeSma.Process(new DecimalIndicatorValue(_volumeSma, volume, candle.OpenTime) { IsFinal = true });
if (!_volumeSma.IsFormed || volumeValue.IsEmpty || !emaValue.IsFormed)
return;
if (!ichimokuValue.IsFormed || ichimokuValue is not IchimokuValue { SenkouA: decimal senkouA, SenkouB: decimal senkouB })
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var averageVolume = volumeValue.GetValue<decimal>();
var ema = emaValue.GetValue<decimal>();
var close = candle.ClosePrice;
if (Position > 0)
{
if (close < ema)
SellMarket(Position);
return;
}
var aboveCloud = close > Math.Max(senkouA, senkouB);
var emaOk = !UseEmaFilter || close > ema;
if (aboveCloud && volume > averageVolume && emaOk)
BuyMarket(Volume + Math.Abs(Position));
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import Ichimoku, ExponentialMovingAverage, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class ichimoku_cloud_buy_custom_ema_exit_strategy(Strategy):
"""
Ichimoku cloud buy with custom EMA exit strategy.
Long only. A long opens when the close is above the Ichimoku cloud and the candle volume exceeds its VolumeAvgPeriod average,
optionally also requiring the close above the EmaLength EMA. The position closes when the close falls below the EMA,
and a percent stop loss limits the loss.
"""
def __init__(self):
super(ichimoku_cloud_buy_custom_ema_exit_strategy, self).__init__()
self._tenkan_period = self.Param("TenkanPeriod", 9).SetGreaterThanZero().SetDisplay("Tenkan Period", "Tenkan-sen period", "Ichimoku")
self._kijun_period = self.Param("KijunPeriod", 26).SetGreaterThanZero().SetDisplay("Kijun Period", "Kijun-sen period", "Ichimoku")
self._senkou_span_period = self.Param("SenkouSpanPeriod", 52).SetGreaterThanZero().SetDisplay("Senkou Span Period", "Senkou Span B period", "Ichimoku")
self._ema_length = self.Param("EmaLength", 44).SetGreaterThanZero().SetDisplay("EMA Length", "Exit EMA period", "Exit")
self._volume_avg_period = self.Param("VolumeAvgPeriod", 10).SetGreaterThanZero().SetDisplay("Volume Avg Period", "Volume average period", "Volume")
self._stop_loss_percent = self.Param("StopLossPercent", 2.0).SetNotNegative().SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk")
self._use_ema_filter = self.Param("UseEmaFilter", True).SetDisplay("Use EMA Filter", "Require the close above the EMA for entries", "Exit")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._volume_sma = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(ichimoku_cloud_buy_custom_ema_exit_strategy, self).OnReseted()
self._volume_sma = None
def OnStarted2(self, time):
super(ichimoku_cloud_buy_custom_ema_exit_strategy, self).OnStarted2(time)
self._volume_sma = SimpleMovingAverage()
self._volume_sma.Length = self._volume_avg_period.Value
ichimoku = Ichimoku()
ichimoku.Tenkan.Length = self._tenkan_period.Value
ichimoku.Kijun.Length = self._kijun_period.Value
ichimoku.SenkouB.Length = self._senkou_span_period.Value
ema = ExponentialMovingAverage()
ema.Length = self._ema_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(ichimoku, ema, self._process_candle).Start()
self.StartProtection(Unit(), Unit(Decimal(self._stop_loss_percent.Value), UnitTypes.Percent), useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ichimoku)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def _process_candle(self, candle, ichimoku_value, ema_value):
if candle.State != CandleStates.Finished:
return
volume = candle.TotalVolume
volume_value = process_value(self._volume_sma, volume, candle.OpenTime, True)
if not self._volume_sma.IsFormed or volume_value.IsEmpty or not ema_value.IsFormed:
return
if not ichimoku_value.IsFormed or ichimoku_value.SenkouA is None or ichimoku_value.SenkouB is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
average_volume = to_decimal(volume_value)
ema = ema_value.GetValue[Decimal](None)
close = candle.ClosePrice
if self.Position > 0:
if close < ema:
self.SellMarket(self.Position)
return
above_cloud = close > max(ichimoku_value.SenkouA, ichimoku_value.SenkouB)
ema_ok = not self._use_ema_filter.Value or close > ema
if above_cloud and volume > average_volume and ema_ok:
self.BuyMarket(self.Volume + abs(self.Position))
def CreateClone(self):
return ichimoku_cloud_buy_custom_ema_exit_strategy()