Стратегия Fibo Stop
Обзор
Стратегия Fibo Stop сопровождает защитный стоп по уровням Фибоначчи, рассчитанным между двумя ценами: начальной и конечной. Открытие позиции происходит в направлении от начального уровня к конечному. Стоп переносится на новый уровень Фибоначчи после его пробоя ценой.
Алгоритм
- Определяется направление от начальной цены к конечной. Если конечная цена выше, открывается длинная позиция, иначе – короткая.
- Рассчитываются уровни Фибоначчи: 0%, 23.6%, 38.6%, 50%, 61.8%, 78.6%, 100%, 127% на основе диапазона.
- Начальный стоп ставится за стартовым уровнем с учетом заданного смещения в шагах цены.
- При движении цены и пробое следующего уровня Фибоначчи стоп переносится к этому уровню с учетом смещения.
- Позиция закрывается при достижении ценой перемещенного стопа.
Параметры
FiboStart– начальная цена для расчета уровней.FiboEnd– конечная цена диапазона.OffsetPoints– количество шагов цены за уровнем для установки стопа.CandleType– тип свечей для отслеживания цены.
Примечания
Стратегия использует только завершенные свечи и демонстрирует пример сопровождения позиции по уровням Фибоначчи с использованием высокоуровневого API StockSharp.
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>
/// Strategy that uses Fibonacci retracement levels for entry and trailing stop.
/// Enters on pullback to Fibonacci level and trails stop along levels.
/// </summary>
public class FiboStopStrategy : Strategy
{
private readonly StrategyParam<int> _lookbackPeriod;
private readonly StrategyParam<decimal> _entryFiboLevel;
private readonly StrategyParam<decimal> _stopLossPct;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<DataType> _candleType;
private decimal _highestHigh;
private decimal _lowestLow;
private int _barCount;
private int _barsSinceTrade;
private bool _rangeSet;
private decimal _entryPrice;
public int LookbackPeriod { get => _lookbackPeriod.Value; set => _lookbackPeriod.Value = value; }
public decimal EntryFiboLevel { get => _entryFiboLevel.Value; set => _entryFiboLevel.Value = value; }
public decimal StopLossPct { get => _stopLossPct.Value; set => _stopLossPct.Value = value; }
public int CooldownBars { get => _cooldownBars.Value; set => _cooldownBars.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public FiboStopStrategy()
{
_lookbackPeriod = Param(nameof(LookbackPeriod), 500)
.SetGreaterThanZero()
.SetDisplay("Lookback", "Bars to calculate high/low range", "General");
_entryFiboLevel = Param(nameof(EntryFiboLevel), 0.382m)
.SetDisplay("Entry Fibo", "Fibonacci level for entry (0.236, 0.382, 0.5, 0.618)", "Fibonacci");
_stopLossPct = Param(nameof(StopLossPct), 2m)
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk");
_cooldownBars = Param(nameof(CooldownBars), 50)
.SetGreaterThanZero()
.SetDisplay("Cooldown Bars", "Bars between new entries", "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();
_highestHigh = decimal.MinValue;
_lowestLow = decimal.MaxValue;
_barCount = 0;
_barsSinceTrade = CooldownBars;
_rangeSet = false;
_entryPrice = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_highestHigh = decimal.MinValue;
_lowestLow = decimal.MaxValue;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
StartProtection(
stopLoss: new Unit(StopLossPct, UnitTypes.Percent),
takeProfit: new Unit(2, UnitTypes.Percent)
);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
_barCount++;
_barsSinceTrade++;
if (candle.HighPrice > _highestHigh)
_highestHigh = candle.HighPrice;
if (candle.LowPrice < _lowestLow)
_lowestLow = candle.LowPrice;
if (_barCount < LookbackPeriod)
return;
if (!_rangeSet)
{
_rangeSet = true;
return;
}
var range = _highestHigh - _lowestLow;
if (range <= 0)
return;
// Calculate Fibonacci retracement levels from high
var fiboLevel = _highestHigh - range * EntryFiboLevel;
var fibo618 = _highestHigh - range * 0.618m;
if (Position == 0)
{
if (_barsSinceTrade < CooldownBars)
return;
if (candle.ClosePrice <= fiboLevel && candle.ClosePrice > fibo618)
{
BuyMarket();
_entryPrice = candle.ClosePrice;
_barsSinceTrade = 0;
}
else if (candle.ClosePrice >= _lowestLow + range * (1m - EntryFiboLevel) && candle.ClosePrice < _lowestLow + range * 0.382m)
{
SellMarket();
_entryPrice = candle.ClosePrice;
_barsSinceTrade = 0;
}
}
// Exits handled by StartProtection
// Update rolling high/low
if (_barCount > LookbackPeriod * 2)
{
_highestHigh = candle.HighPrice;
_lowestLow = candle.LowPrice;
_barCount = LookbackPeriod;
}
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Strategies import Strategy
class fibo_stop_strategy(Strategy):
def __init__(self):
super(fibo_stop_strategy, self).__init__()
self._lookback_period = self.Param("LookbackPeriod", 500) \
.SetGreaterThanZero() \
.SetDisplay("Lookback", "Bars to calculate high/low range", "General")
self._entry_fibo_level = self.Param("EntryFiboLevel", 0.382) \
.SetDisplay("Entry Fibo", "Fibonacci level for entry (0.236, 0.382, 0.5, 0.618)", "Fibonacci")
self._stop_loss_pct = self.Param("StopLossPct", 2.0) \
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk")
self._cooldown_bars = self.Param("CooldownBars", 50) \
.SetGreaterThanZero() \
.SetDisplay("Cooldown Bars", "Bars between new entries", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._highest_high = -1e18
self._lowest_low = 1e18
self._bar_count = 0
self._bars_since_trade = 0
self._range_set = False
self._entry_price = 0.0
@property
def lookback_period(self):
return self._lookback_period.Value
@property
def entry_fibo_level(self):
return self._entry_fibo_level.Value
@property
def stop_loss_pct(self):
return self._stop_loss_pct.Value
@property
def cooldown_bars(self):
return self._cooldown_bars.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(fibo_stop_strategy, self).OnReseted()
self._highest_high = -1e18
self._lowest_low = 1e18
self._bar_count = 0
self._bars_since_trade = self.cooldown_bars
self._range_set = False
self._entry_price = 0.0
def OnStarted2(self, time):
super(fibo_stop_strategy, self).OnStarted2(time)
self._highest_high = -1e18
self._lowest_low = 1e18
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.process_candle).Start()
self.StartProtection(
Unit(float(self.stop_loss_pct), UnitTypes.Percent),
Unit(2, UnitTypes.Percent))
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
self._bar_count += 1
self._bars_since_trade += 1
h = float(candle.HighPrice)
l = float(candle.LowPrice)
if h > self._highest_high:
self._highest_high = h
if l < self._lowest_low:
self._lowest_low = l
if self._bar_count < self.lookback_period:
return
if not self._range_set:
self._range_set = True
return
rng = self._highest_high - self._lowest_low
if rng <= 0:
return
fibo = float(self.entry_fibo_level)
fibo_level = self._highest_high - rng * fibo
fibo_618 = self._highest_high - rng * 0.618
close = float(candle.ClosePrice)
if self.Position == 0:
if self._bars_since_trade < self.cooldown_bars:
return
if close <= fibo_level and close > fibo_618:
self.BuyMarket()
self._entry_price = close
self._bars_since_trade = 0
elif close >= self._lowest_low + rng * (1.0 - fibo) and close < self._lowest_low + rng * 0.382:
self.SellMarket()
self._entry_price = close
self._bars_since_trade = 0
if self._bar_count > self.lookback_period * 2:
self._highest_high = h
self._lowest_low = l
self._bar_count = self.lookback_period
def CreateClone(self):
return fibo_stop_strategy()