アダプティブ Fibonacci プルバック戦略
この戦略は、Fibonacci 乗数 (0.618、1.618、2.618) で構築された 3 本の SuperTrend ラインを平均化し、その結果を EMA で平滑化します。このアダプティブトレンドへのプルバックに従ってトレードを行い、AMA ベースの中央線とオプションの RSI フィルターで方向を確認します。
詳細
- エントリー条件:
- 安値が平均 SuperTrend を下回り、終値がその平滑化された値を上回る。
- AMA 中央線に対する前の終値がプルバックを定義する。
- ロング: 終値が中央線を上回り、RSI > しきい値。
- ショート: 終値が中央線を下回り、RSI < しきい値。
- ロング/ショート: 両方向。
- エグジット条件:
- 終値が平滑化された SuperTrend を逆方向に横切る。
- ストップ:
StartProtectionによるパーセンテージストップロスとテイクプロフィット。 - デフォルト値:
AtrPeriod= 8SmoothLength= 21AmaLength= 55RsiLength= 7RsiBuy= 70RsiSell= 30TakeProfitPercent= 5StopLossPercent= 0.75
- フィルター:
- カテゴリ: トレンドプルバック
- 方向: 両方
- インジケーター: SuperTrend, EMA, AMA, RSI
- ストップ: はい
- 複雑さ: 中程度
- 時間軸: 任意
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
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>
/// Adaptive Fibonacci Pullback strategy.
/// Three SuperTrend lines with Fibonacci multipliers are averaged and the average is smoothed by an EMA. A long needs the low to dip
/// below the average while the close stays above the smoothed line, the previous and current close above the Kaufman AMA midline and
/// RSI above RsiBuy; a short mirrors this with RSI below RsiSell. Positions close when the close crosses the smoothed line against them,
/// and percent take profit and stop loss protect every trade.
/// </summary>
public class AdaptiveFibonacciPullbackStrategy : Strategy
{
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _factor1;
private readonly StrategyParam<decimal> _factor2;
private readonly StrategyParam<decimal> _factor3;
private readonly StrategyParam<int> _smoothLength;
private readonly StrategyParam<int> _amaLength;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<decimal> _rsiBuy;
private readonly StrategyParam<decimal> _rsiSell;
private readonly StrategyParam<decimal> _takeProfitPercent;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _smooth;
private decimal? _prevClose;
private decimal? _prevSmooth;
/// <summary>
/// ATR period of the SuperTrends.
/// </summary>
public int AtrPeriod
{
get => _atrPeriod.Value;
set => _atrPeriod.Value = value;
}
/// <summary>
/// Multiplier of the first SuperTrend.
/// </summary>
public decimal Factor1
{
get => _factor1.Value;
set => _factor1.Value = value;
}
/// <summary>
/// Multiplier of the second SuperTrend.
/// </summary>
public decimal Factor2
{
get => _factor2.Value;
set => _factor2.Value = value;
}
/// <summary>
/// Multiplier of the third SuperTrend.
/// </summary>
public decimal Factor3
{
get => _factor3.Value;
set => _factor3.Value = value;
}
/// <summary>
/// EMA length that smooths the SuperTrend average.
/// </summary>
public int SmoothLength
{
get => _smoothLength.Value;
set => _smoothLength.Value = value;
}
/// <summary>
/// Period of the AMA midline.
/// </summary>
public int AmaLength
{
get => _amaLength.Value;
set => _amaLength.Value = value;
}
/// <summary>
/// Period of RSI.
/// </summary>
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
/// <summary>
/// RSI level a long requires to exceed.
/// </summary>
public decimal RsiBuy
{
get => _rsiBuy.Value;
set => _rsiBuy.Value = value;
}
/// <summary>
/// RSI level a short requires to stay below.
/// </summary>
public decimal RsiSell
{
get => _rsiSell.Value;
set => _rsiSell.Value = value;
}
/// <summary>
/// Take profit percentage.
/// </summary>
public decimal TakeProfitPercent
{
get => _takeProfitPercent.Value;
set => _takeProfitPercent.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>
/// Constructor.
/// </summary>
public AdaptiveFibonacciPullbackStrategy()
{
_atrPeriod = Param(nameof(AtrPeriod), 8)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "ATR period of the SuperTrends", "SuperTrend");
_factor1 = Param(nameof(Factor1), 0.618m)
.SetGreaterThanZero()
.SetDisplay("Factor 1", "Multiplier of the first SuperTrend", "SuperTrend");
_factor2 = Param(nameof(Factor2), 1.618m)
.SetGreaterThanZero()
.SetDisplay("Factor 2", "Multiplier of the second SuperTrend", "SuperTrend");
_factor3 = Param(nameof(Factor3), 2.618m)
.SetGreaterThanZero()
.SetDisplay("Factor 3", "Multiplier of the third SuperTrend", "SuperTrend");
_smoothLength = Param(nameof(SmoothLength), 21)
.SetGreaterThanZero()
.SetDisplay("Smooth Length", "EMA length that smooths the SuperTrend average", "SuperTrend");
_amaLength = Param(nameof(AmaLength), 55)
.SetGreaterThanZero()
.SetDisplay("AMA Length", "Period of the AMA midline", "AMA");
_rsiLength = Param(nameof(RsiLength), 7)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "Period of RSI", "RSI");
_rsiBuy = Param(nameof(RsiBuy), 70m)
.SetDisplay("RSI Buy", "RSI level a long requires to exceed", "RSI");
_rsiSell = Param(nameof(RsiSell), 30m)
.SetDisplay("RSI Sell", "RSI level a short requires to stay below", "RSI");
_takeProfitPercent = Param(nameof(TakeProfitPercent), 5m)
.SetNotNegative()
.SetDisplay("Take Profit %", "Take profit percentage", "Risk");
_stopLossPercent = Param(nameof(StopLossPercent), 0.75m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).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();
_smooth = null;
_prevClose = null;
_prevSmooth = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevClose = null;
_prevSmooth = null;
var st1 = new SuperTrend { Length = AtrPeriod, Multiplier = Factor1 };
var st2 = new SuperTrend { Length = AtrPeriod, Multiplier = Factor2 };
var st3 = new SuperTrend { Length = AtrPeriod, Multiplier = Factor3 };
var ama = new KaufmanAdaptiveMovingAverage { Length = AmaLength };
var rsi = new RelativeStrengthIndex { Length = RsiLength };
_smooth = new ExponentialMovingAverage { Length = SmoothLength };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx([st1, st2, st3, ama, rsi], ProcessCandle)
.Start();
StartProtection(new Unit(TakeProfitPercent, UnitTypes.Percent), new Unit(StopLossPercent, UnitTypes.Percent), useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ama);
DrawOwnTrades(area);
var oscillators = CreateChartArea();
if (oscillators != null)
DrawIndicator(oscillators, rsi);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue[] values)
{
if (candle.State != CandleStates.Finished)
return;
foreach (var value in values)
{
if (!value.IsFormed)
return;
}
var average = (values[0].ToDecimal() + values[1].ToDecimal() + values[2].ToDecimal()) / 3m;
var mid = values[3].ToDecimal();
var rsi = values[4].ToDecimal();
var smoothValue = _smooth.Process(average, candle.ServerTime, true);
if (!_smooth.IsFormed)
return;
var smooth = smoothValue.ToDecimal();
var close = candle.ClosePrice;
var prevClose = _prevClose;
var prevSmooth = _prevSmooth;
_prevClose = close;
_prevSmooth = smooth;
if (prevClose is not decimal pc || prevSmooth is not decimal ps)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var longEntry = candle.LowPrice < average && close > smooth && pc > mid && close > mid && rsi > RsiBuy;
var shortEntry = candle.HighPrice > average && close < smooth && pc < mid && close < mid && rsi < RsiSell;
if (longEntry && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (shortEntry && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
else if (Position > 0 && pc >= ps && close < smooth)
SellMarket(Position);
else if (Position < 0 && pc <= ps && close > smooth)
BuyMarket(-Position);
}
}
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, Decimal, Array
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import IIndicator, SuperTrend, ExponentialMovingAverage, KaufmanAdaptiveMovingAverage, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class adaptive_fibonacci_pullback_strategy(Strategy):
"""
Adaptive Fibonacci Pullback strategy.
Three SuperTrend lines with Fibonacci multipliers are averaged and the average is smoothed by an EMA. A long needs the low to dip
below the average while the close stays above the smoothed line, the previous and current close above the Kaufman AMA midline and
RSI above RsiBuy; a short mirrors this with RSI below RsiSell. Positions close when the close crosses the smoothed line against them,
and percent take profit and stop loss protect every trade.
"""
def __init__(self):
super(adaptive_fibonacci_pullback_strategy, self).__init__()
self._atr_period = self.Param("AtrPeriod", 8).SetGreaterThanZero().SetDisplay("ATR Period", "ATR period of the SuperTrends", "SuperTrend")
self._factor1 = self.Param("Factor1", 0.618).SetGreaterThanZero().SetDisplay("Factor 1", "Multiplier of the first SuperTrend", "SuperTrend")
self._factor2 = self.Param("Factor2", 1.618).SetGreaterThanZero().SetDisplay("Factor 2", "Multiplier of the second SuperTrend", "SuperTrend")
self._factor3 = self.Param("Factor3", 2.618).SetGreaterThanZero().SetDisplay("Factor 3", "Multiplier of the third SuperTrend", "SuperTrend")
self._smooth_length = self.Param("SmoothLength", 21).SetGreaterThanZero().SetDisplay("Smooth Length", "EMA length that smooths the SuperTrend average", "SuperTrend")
self._ama_length = self.Param("AmaLength", 55).SetGreaterThanZero().SetDisplay("AMA Length", "Period of the AMA midline", "AMA")
self._rsi_length = self.Param("RsiLength", 7).SetGreaterThanZero().SetDisplay("RSI Length", "Period of RSI", "RSI")
self._rsi_buy = self.Param("RsiBuy", 70.0).SetDisplay("RSI Buy", "RSI level a long requires to exceed", "RSI")
self._rsi_sell = self.Param("RsiSell", 30.0).SetDisplay("RSI Sell", "RSI level a short requires to stay below", "RSI")
self._take_profit_percent = self.Param("TakeProfitPercent", 5.0).SetNotNegative().SetDisplay("Take Profit %", "Take profit percentage", "Risk")
self._stop_loss_percent = self.Param("StopLossPercent", 0.75).SetNotNegative().SetDisplay("Stop Loss %", "Stop loss percentage", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._smooth = None
self._prev_close = None
self._prev_smooth = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(adaptive_fibonacci_pullback_strategy, self).OnReseted()
self._smooth = None
self._prev_close = None
self._prev_smooth = None
def OnStarted2(self, time):
super(adaptive_fibonacci_pullback_strategy, self).OnStarted2(time)
self._prev_close = None
self._prev_smooth = None
st1 = SuperTrend()
st1.Length = self._atr_period.Value
st1.Multiplier = Decimal(self._factor1.Value)
st2 = SuperTrend()
st2.Length = self._atr_period.Value
st2.Multiplier = Decimal(self._factor2.Value)
st3 = SuperTrend()
st3.Length = self._atr_period.Value
st3.Multiplier = Decimal(self._factor3.Value)
ama = KaufmanAdaptiveMovingAverage()
ama.Length = self._ama_length.Value
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_length.Value
self._smooth = ExponentialMovingAverage()
self._smooth.Length = self._smooth_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(Array[IIndicator]([st1, st2, st3, ama, rsi]), self._process_candle).Start()
self.StartProtection(Unit(Decimal(self._take_profit_percent.Value), UnitTypes.Percent), 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, ama)
self.DrawOwnTrades(area)
oscillators = self.CreateChartArea()
if oscillators is not None:
self.DrawIndicator(oscillators, rsi)
def _process_candle(self, candle, values):
if candle.State != CandleStates.Finished:
return
for value in values:
if not value.IsFormed:
return
average = (values[0].GetValue[Decimal](None) + values[1].GetValue[Decimal](None) + values[2].GetValue[Decimal](None)) / Decimal(3)
mid = values[3].GetValue[Decimal](None)
rsi = values[4].GetValue[Decimal](None)
smooth_value = process_value(self._smooth, average, candle.ServerTime, True)
if not self._smooth.IsFormed:
return
smooth = smooth_value.GetValue[Decimal](None)
close = candle.ClosePrice
prev_close = self._prev_close
prev_smooth = self._prev_smooth
self._prev_close = close
self._prev_smooth = smooth
if prev_close is None or prev_smooth is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
long_entry = candle.LowPrice < average and close > smooth and prev_close > mid and close > mid and rsi > Decimal(self._rsi_buy.Value)
short_entry = candle.HighPrice > average and close < smooth and prev_close < mid and close < mid and rsi < Decimal(self._rsi_sell.Value)
if long_entry and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif short_entry and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
elif self.Position > 0 and prev_close >= prev_smooth and close < smooth:
self.SellMarket(self.Position)
elif self.Position < 0 and prev_close <= prev_smooth and close > smooth:
self.BuyMarket(-self.Position)
def CreateClone(self):
return adaptive_fibonacci_pullback_strategy()