Iron Bot 統計的トレンドフィルター戦略
この戦略は、フィボナッチ範囲とZ-scoreから計算された統計的トレンドレベルに基づくブレイクアウトをトレードします。
詳細
- エントリー条件:
- ロング: 価格がトレンドラインと上方トレンドレベルを上抜け、Z-scoreが非負。
- ショート: 価格がトレンドラインと下方トレンドレベルを下抜け、Z-scoreが非正。
- ロング/ショート: 両方向。
- エグジット条件:
- エントリーから
SlRatioパーセントのストップロス。 - エントリーから4つのレベル(
Tp1Ratio–Tp4Ratio)のいずれかでテイクプロフィット。
- エントリーから
- ストップ: はい。
- デフォルト値:
ZLength= 40.AnalysisWindow= 44.HighTrendLimit= 0.236.LowTrendLimit= 0.786.EmaLength= 200.
- フィルター:
- カテゴリ: トレンドフォロー
- 方向: 両方
- インジケーター: Z-score, 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>
/// Iron Bot statistical trend filter strategy.
/// The highest high and lowest low of the last AnalysisWindow candles define a range. The trend line sits at its middle, the high
/// trend level HighTrendLimit of the range below the top and the low trend level LowTrendLimit of the range below the top. A close
/// crossing above the high trend level (and so above the trend line) with a non-negative Z-score of the close goes long, a close
/// crossing below the low trend level (and the trend line) with a non-positive Z-score goes short, reversing an opposite position.
/// A stop at SlRatio and a take profit at the TP ratio picked by TakeProfitLevel, both fractions of the entry price, close trades.
/// </summary>
public class IronBotStatisticalTrendFilterStrategy : Strategy
{
private readonly StrategyParam<int> _zLength;
private readonly StrategyParam<int> _analysisWindow;
private readonly StrategyParam<decimal> _highTrendLimit;
private readonly StrategyParam<decimal> _lowTrendLimit;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<decimal> _slRatio;
private readonly StrategyParam<decimal> _tp1Ratio;
private readonly StrategyParam<decimal> _tp2Ratio;
private readonly StrategyParam<decimal> _tp3Ratio;
private readonly StrategyParam<decimal> _tp4Ratio;
private readonly StrategyParam<int> _takeProfitLevel;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevClose;
/// <summary>
/// Length of the Z-score mean and deviation.
/// </summary>
public int ZLength
{
get => _zLength.Value;
set => _zLength.Value = value;
}
/// <summary>
/// Candles the trend range spans.
/// </summary>
public int AnalysisWindow
{
get => _analysisWindow.Value;
set => _analysisWindow.Value = value;
}
/// <summary>
/// Fibonacci fraction of the range below the top for the high trend level.
/// </summary>
public decimal HighTrendLimit
{
get => _highTrendLimit.Value;
set => _highTrendLimit.Value = value;
}
/// <summary>
/// Fibonacci fraction of the range below the top for the low trend level.
/// </summary>
public decimal LowTrendLimit
{
get => _lowTrendLimit.Value;
set => _lowTrendLimit.Value = value;
}
/// <summary>
/// EMA length shown on the chart.
/// </summary>
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
/// <summary>
/// Stop loss as a fraction of the entry price.
/// </summary>
public decimal SlRatio
{
get => _slRatio.Value;
set => _slRatio.Value = value;
}
/// <summary>
/// First take profit as a fraction of the entry price.
/// </summary>
public decimal Tp1Ratio
{
get => _tp1Ratio.Value;
set => _tp1Ratio.Value = value;
}
/// <summary>
/// Second take profit as a fraction of the entry price.
/// </summary>
public decimal Tp2Ratio
{
get => _tp2Ratio.Value;
set => _tp2Ratio.Value = value;
}
/// <summary>
/// Third take profit as a fraction of the entry price.
/// </summary>
public decimal Tp3Ratio
{
get => _tp3Ratio.Value;
set => _tp3Ratio.Value = value;
}
/// <summary>
/// Fourth take profit as a fraction of the entry price.
/// </summary>
public decimal Tp4Ratio
{
get => _tp4Ratio.Value;
set => _tp4Ratio.Value = value;
}
/// <summary>
/// Which take profit ratio (1-4) closes the trade.
/// </summary>
public int TakeProfitLevel
{
get => _takeProfitLevel.Value;
set => _takeProfitLevel.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public IronBotStatisticalTrendFilterStrategy()
{
_zLength = Param(nameof(ZLength), 40)
.SetGreaterThanZero()
.SetDisplay("Z Length", "Length of the Z-score mean and deviation", "Indicators");
_analysisWindow = Param(nameof(AnalysisWindow), 44)
.SetGreaterThanZero()
.SetDisplay("Analysis Window", "Candles the trend range spans", "Indicators");
_highTrendLimit = Param(nameof(HighTrendLimit), 0.236m)
.SetDisplay("High Trend Limit", "Fibonacci fraction below the top for the high trend level", "Indicators");
_lowTrendLimit = Param(nameof(LowTrendLimit), 0.786m)
.SetDisplay("Low Trend Limit", "Fibonacci fraction below the top for the low trend level", "Indicators");
_emaLength = Param(nameof(EmaLength), 200)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "EMA length shown on the chart", "Indicators");
_slRatio = Param(nameof(SlRatio), 0.008m)
.SetNotNegative()
.SetDisplay("SL Ratio", "Stop loss as a fraction of the entry price", "Risk");
_tp1Ratio = Param(nameof(Tp1Ratio), 0.0075m)
.SetNotNegative()
.SetDisplay("TP1 Ratio", "First take profit as a fraction of the entry price", "Risk");
_tp2Ratio = Param(nameof(Tp2Ratio), 0.011m)
.SetNotNegative()
.SetDisplay("TP2 Ratio", "Second take profit as a fraction of the entry price", "Risk");
_tp3Ratio = Param(nameof(Tp3Ratio), 0.015m)
.SetNotNegative()
.SetDisplay("TP3 Ratio", "Third take profit as a fraction of the entry price", "Risk");
_tp4Ratio = Param(nameof(Tp4Ratio), 0.02m)
.SetNotNegative()
.SetDisplay("TP4 Ratio", "Fourth take profit as a fraction of the entry price", "Risk");
_takeProfitLevel = Param(nameof(TakeProfitLevel), 1)
.SetRange(1, 4)
.SetDisplay("Take Profit Level", "Which take profit ratio (1-4) closes the trade", "Risk");
_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();
_prevClose = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevClose = null;
var mean = new SimpleMovingAverage { Length = ZLength };
var deviation = new StandardDeviation { Length = ZLength };
var highest = new Highest { Length = AnalysisWindow };
var lowest = new Lowest { Length = AnalysisWindow };
var ema = new ExponentialMovingAverage { Length = EmaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(mean, deviation, highest, lowest, ema, ProcessCandle)
.Start();
var takeRatio = TakeProfitLevel switch
{
2 => Tp2Ratio,
3 => Tp3Ratio,
4 => Tp4Ratio,
_ => Tp1Ratio,
};
StartProtection(
takeProfit: takeRatio > 0 ? new Unit(takeRatio * 100m, UnitTypes.Percent) : new Unit(),
stopLoss: SlRatio > 0 ? new Unit(SlRatio * 100m, UnitTypes.Percent) : new Unit(),
useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, highest);
DrawIndicator(area, lowest);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal meanValue, decimal deviationValue, decimal highestValue, decimal lowestValue, decimal emaValue)
{
if (candle.State != CandleStates.Finished)
return;
var prevClose = _prevClose;
var close = candle.ClosePrice;
_prevClose = close;
if (prevClose is not decimal prev || !IsFormedAndOnlineAndAllowTrading())
return;
var range = highestValue - lowestValue;
if (range <= 0)
return;
var zScore = deviationValue == 0m ? 0m : (close - meanValue) / deviationValue;
var highTrendLevel = highestValue - range * HighTrendLimit;
var trendLine = highestValue - range * 0.5m;
var lowTrendLevel = highestValue - range * LowTrendLimit;
var crossUp = close > trendLine && close > highTrendLevel && (prev <= trendLine || prev <= highTrendLevel);
var crossDown = close < trendLine && close < lowTrendLevel && (prev >= trendLine || prev >= lowTrendLevel);
if (crossUp && zScore >= 0m && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (crossDown && zScore <= 0m && Position >= 0)
SellMarket(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 SimpleMovingAverage, StandardDeviation, Highest, Lowest, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class iron_bot_statistical_trend_filter_strategy(Strategy):
"""
Iron Bot statistical trend filter strategy.
The highest high and lowest low of the last AnalysisWindow candles define a range. The trend line sits at its middle, the high
trend level HighTrendLimit of the range below the top and the low trend level LowTrendLimit of the range below the top. A close
crossing above the high trend level (and so above the trend line) with a non-negative Z-score of the close goes long, a close
crossing below the low trend level (and the trend line) with a non-positive Z-score goes short, reversing an opposite position.
A stop at SlRatio and a take profit at the TP ratio picked by TakeProfitLevel, both fractions of the entry price, close trades.
"""
def __init__(self):
super(iron_bot_statistical_trend_filter_strategy, self).__init__()
self._z_length = self.Param("ZLength", 40).SetGreaterThanZero().SetDisplay("Z Length", "Length of the Z-score mean and deviation", "Indicators")
self._analysis_window = self.Param("AnalysisWindow", 44).SetGreaterThanZero().SetDisplay("Analysis Window", "Candles the trend range spans", "Indicators")
self._high_trend_limit = self.Param("HighTrendLimit", 0.236).SetDisplay("High Trend Limit", "Fibonacci fraction below the top for the high trend level", "Indicators")
self._low_trend_limit = self.Param("LowTrendLimit", 0.786).SetDisplay("Low Trend Limit", "Fibonacci fraction below the top for the low trend level", "Indicators")
self._ema_length = self.Param("EmaLength", 200).SetGreaterThanZero().SetDisplay("EMA Length", "EMA length shown on the chart", "Indicators")
self._sl_ratio = self.Param("SlRatio", 0.008).SetNotNegative().SetDisplay("SL Ratio", "Stop loss as a fraction of the entry price", "Risk")
self._tp1_ratio = self.Param("Tp1Ratio", 0.0075).SetNotNegative().SetDisplay("TP1 Ratio", "First take profit as a fraction of the entry price", "Risk")
self._tp2_ratio = self.Param("Tp2Ratio", 0.011).SetNotNegative().SetDisplay("TP2 Ratio", "Second take profit as a fraction of the entry price", "Risk")
self._tp3_ratio = self.Param("Tp3Ratio", 0.015).SetNotNegative().SetDisplay("TP3 Ratio", "Third take profit as a fraction of the entry price", "Risk")
self._tp4_ratio = self.Param("Tp4Ratio", 0.02).SetNotNegative().SetDisplay("TP4 Ratio", "Fourth take profit as a fraction of the entry price", "Risk")
self._take_profit_level = self.Param("TakeProfitLevel", 1).SetRange(1, 4).SetDisplay("Take Profit Level", "Which take profit ratio (1-4) closes the trade", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_close = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(iron_bot_statistical_trend_filter_strategy, self).OnReseted()
self._prev_close = None
def OnStarted2(self, time):
super(iron_bot_statistical_trend_filter_strategy, self).OnStarted2(time)
self._prev_close = None
mean = SimpleMovingAverage()
mean.Length = self._z_length.Value
deviation = StandardDeviation()
deviation.Length = self._z_length.Value
highest = Highest()
highest.Length = self._analysis_window.Value
lowest = Lowest()
lowest.Length = self._analysis_window.Value
ema = ExponentialMovingAverage()
ema.Length = self._ema_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(mean, deviation, highest, lowest, ema, self._process_candle).Start()
level = self._take_profit_level.Value
if level == 2:
take_ratio = float(self._tp2_ratio.Value)
elif level == 3:
take_ratio = float(self._tp3_ratio.Value)
elif level == 4:
take_ratio = float(self._tp4_ratio.Value)
else:
take_ratio = float(self._tp1_ratio.Value)
sl_ratio = float(self._sl_ratio.Value)
take = Unit(Decimal(take_ratio * 100.0), UnitTypes.Percent) if take_ratio > 0 else Unit()
stop = Unit(Decimal(sl_ratio * 100.0), UnitTypes.Percent) if sl_ratio > 0 else Unit()
self.StartProtection(take, stop, useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, highest)
self.DrawIndicator(area, lowest)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def _process_candle(self, candle, mean_value, deviation_value, highest_value, lowest_value, ema_value):
if candle.State != CandleStates.Finished:
return
prev = self._prev_close
close = candle.ClosePrice
self._prev_close = close
if prev is None or not self.IsFormedAndOnlineAndAllowTrading():
return
rng = highest_value - lowest_value
if rng <= 0:
return
z_score = Decimal(0) if deviation_value == 0 else (close - mean_value) / deviation_value
high_trend_level = highest_value - rng * Decimal(self._high_trend_limit.Value)
trend_line = highest_value - rng * Decimal(0.5)
low_trend_level = highest_value - rng * Decimal(self._low_trend_limit.Value)
cross_up = close > trend_line and close > high_trend_level and (prev <= trend_line or prev <= high_trend_level)
cross_down = close < trend_line and close < low_trend_level and (prev >= trend_line or prev >= low_trend_level)
if cross_up and z_score >= 0 and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif cross_down and z_score <= 0 and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
def CreateClone(self):
return iron_bot_statistical_trend_filter_strategy()