Стратегия ZZFibo Trader
Использует экстремумы ZigZag для построения уровней Фибоначчи. При появлении нового максимума или минимума уровни пересчитываются. Вход выполняется при пробое уровня 50% в сторону текущего тренда на заданную величину Breakout. Защита позиции может быть активирована через параметр Stop Loss в абсолютных пунктах.
Параметры
- Тип свечей
- Breakout
- Stop Loss
- ZigZag Depth
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 trades breakouts of Fibonacci 50% retracement levels from ZigZag pivots.
/// Uses Highest/Lowest to detect pivot points and enters on 50% level crossover.
/// </summary>
public class ZZFiboTraderStrategy : Strategy
{
private readonly StrategyParam<int> _zigZagDepth;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevPivot;
private decimal _currPivot;
private int _direction;
private decimal _level50;
public int ZigZagDepth
{
get => _zigZagDepth.Value;
set => _zigZagDepth.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public ZZFiboTraderStrategy()
{
_zigZagDepth = Param(nameof(ZigZagDepth), 12)
.SetDisplay("ZigZag Depth", "Number of bars to search for pivots", "ZigZag")
.SetGreaterThanZero();
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevPivot = 0m;
_currPivot = 0m;
_direction = 0;
_level50 = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevPivot = 0m;
_currPivot = 0m;
_direction = 0;
_level50 = 0m;
var highest = new Highest { Length = ZigZagDepth };
var lowest = new Lowest { Length = ZigZagDepth };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(highest, lowest, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, highest);
DrawIndicator(area, lowest);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal highest, decimal lowest)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Update pivots when new extremes appear
if (candle.HighPrice >= highest && candle.HighPrice != _currPivot)
{
_prevPivot = _currPivot;
_currPivot = candle.HighPrice;
UpdateLevels();
}
else if (candle.LowPrice <= lowest && candle.LowPrice != _currPivot)
{
_prevPivot = _currPivot;
_currPivot = candle.LowPrice;
UpdateLevels();
}
if (_direction == 0 || _level50 == 0m)
return;
// Enter when price crosses 50% level in direction of trend
if (_direction == 1 && Position <= 0 && candle.ClosePrice > _level50)
BuyMarket();
else if (_direction == -1 && Position >= 0 && candle.ClosePrice < _level50)
SellMarket();
}
private void UpdateLevels()
{
if (_prevPivot == 0m || _currPivot == 0m)
return;
_direction = _currPivot > _prevPivot ? 1 : -1;
var high = _direction == 1 ? _currPivot : _prevPivot;
var low = _direction == 1 ? _prevPivot : _currPivot;
_level50 = high - (high - low) * 0.5m;
}
}
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 Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class zz_fibo_trader_strategy(Strategy):
def __init__(self):
super(zz_fibo_trader_strategy, self).__init__()
self._zigzag_depth = self.Param("ZigZagDepth", 12) \
.SetDisplay("ZigZag Depth", "Number of bars to search for pivots", "ZigZag")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_pivot = 0.0
self._curr_pivot = 0.0
self._direction = 0
self._level50 = 0.0
@property
def zigzag_depth(self):
return self._zigzag_depth.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(zz_fibo_trader_strategy, self).OnReseted()
self._prev_pivot = 0.0
self._curr_pivot = 0.0
self._direction = 0
self._level50 = 0.0
def OnStarted2(self, time):
super(zz_fibo_trader_strategy, self).OnStarted2(time)
self._prev_pivot = 0.0
self._curr_pivot = 0.0
self._direction = 0
self._level50 = 0.0
highest = Highest()
highest.Length = self.zigzag_depth
lowest = Lowest()
lowest.Length = self.zigzag_depth
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(highest, lowest, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, highest)
self.DrawIndicator(area, lowest)
self.DrawOwnTrades(area)
def _update_levels(self):
if self._prev_pivot == 0.0 or self._curr_pivot == 0.0:
return
self._direction = 1 if self._curr_pivot > self._prev_pivot else -1
if self._direction == 1:
high = self._curr_pivot
low = self._prev_pivot
else:
high = self._prev_pivot
low = self._curr_pivot
self._level50 = high - (high - low) * 0.5
def process_candle(self, candle, highest, lowest):
if candle.State != CandleStates.Finished:
return
highest = float(highest)
lowest = float(lowest)
high_price = float(candle.HighPrice)
low_price = float(candle.LowPrice)
close_price = float(candle.ClosePrice)
if high_price >= highest and high_price != self._curr_pivot:
self._prev_pivot = self._curr_pivot
self._curr_pivot = high_price
self._update_levels()
elif low_price <= lowest and low_price != self._curr_pivot:
self._prev_pivot = self._curr_pivot
self._curr_pivot = low_price
self._update_levels()
if self._direction == 0 or self._level50 == 0.0:
return
if self._direction == 1 and self.Position <= 0 and close_price > self._level50:
self.BuyMarket()
elif self._direction == -1 and self.Position >= 0 and close_price < self._level50:
self.SellMarket()
def CreateClone(self):
return zz_fibo_trader_strategy()