Эта стратегия торгует пробои дневной линии пи́вота. Пи́воты рассчитываются по классической формуле трейдеров биржевого пола из максимумов, минимумов и закрытий предыдущего дня. Длинная позиция открывается, когда цена закрытия пересекает пи́вот снизу вверх. Короткая позиция открывается, когда цена закрытия пересекает пи́вот сверху вниз.
После входа система использует один из уровней поддержки или сопротивления как цель по прибыли и одновременно стоп-лосс. Конкретный уровень задаётся параметром Target Level:
1 – используются уровни Support1/Resistance1.
2 – используются уровни Support2/Resistance2.
3 – используются уровни Support3/Resistance3.
При включённом параметре Intraday Only все открытые позиции закрываются в 23:00 по времени терминала.
Детали
Условия входа
Long: предыдущее закрытие ≤ пи́вот и текущее закрытие > пи́вота.
Short: предыдущее закрытие ≥ пи́вот и текущее закрытие < пи́вота.
Условия выхода
Long: закрытие ≥ выбранный уровень сопротивления или закрытие ≤ выбранный уровень поддержки.
Short: закрытие ≤ выбранный уровень поддержки или закрытие ≥ выбранный уровень сопротивления.
Если активен параметр Intraday Only, все позиции закрываются в 23:00.
Индикаторы: используется только расчёт пи́вота.
Таймфрейм: задаётся параметром, по умолчанию 5‑минутные свечи.
Стопы: стоп-лосс и тейк-профит выбираются из уровней пи́вота.
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>
/// Pivot-based breakout strategy.
/// Buys when close crosses above calculated pivot, sells when it crosses below.
/// Uses support/resistance levels for exits.
/// </summary>
public class TcpPivotStopStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private decimal _pivot;
private decimal _res1, _sup1;
private decimal _prevClose;
private decimal _prevHigh;
private decimal _prevLow;
private int _barCount;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public TcpPivotStopStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Time frame", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_pivot = _res1 = _sup1 = 0;
_prevClose = _prevHigh = _prevLow = 0;
_barCount = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
SubscribeCandles(CandleType).Bind(ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished) return;
_barCount++;
// Recalculate pivot every 12 bars (~2 days for 4h candles)
if (_barCount % 12 == 0 && _prevHigh > 0)
{
_pivot = (_prevHigh + _prevLow + _prevClose) / 3m;
_res1 = 2m * _pivot - _prevLow;
_sup1 = 2m * _pivot - _prevHigh;
}
_prevHigh = candle.HighPrice;
_prevLow = candle.LowPrice;
var close = candle.ClosePrice;
if (_pivot > 0 && _prevClose > 0)
{
// Cross above pivot => long
if (_prevClose <= _pivot && close > _pivot && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
// Cross below pivot => short
else if (_prevClose >= _pivot && close < _pivot && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
// Exit long at resistance or support
else if (Position > 0 && (close >= _res1 || close <= _sup1))
{
SellMarket();
}
// Exit short at support or resistance
else if (Position < 0 && (close <= _sup1 || close >= _res1))
{
BuyMarket();
}
}
_prevClose = close;
}
}
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.Strategies import Strategy
class tcp_pivot_stop_strategy(Strategy):
"""Pivot-based breakout with support/resistance exits."""
def __init__(self):
super(tcp_pivot_stop_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))).SetDisplay("Candle Type", "Time frame", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(tcp_pivot_stop_strategy, self).OnReseted()
self._pivot = 0
self._res1 = 0
self._sup1 = 0
self._prev_close = 0
self._prev_high = 0
self._prev_low = 0
self._bar_count = 0
def OnStarted2(self, time):
super(tcp_pivot_stop_strategy, self).OnStarted2(time)
self._pivot = 0
self._res1 = 0
self._sup1 = 0
self._prev_close = 0
self._prev_high = 0
self._prev_low = 0
self._bar_count = 0
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawOwnTrades(area)
def OnProcess(self, candle):
if candle.State != CandleStates.Finished:
return
self._bar_count += 1
high = float(candle.HighPrice)
low = float(candle.LowPrice)
close = float(candle.ClosePrice)
# Recalculate pivot every 12 bars
if self._bar_count % 12 == 0 and self._prev_high > 0:
self._pivot = (self._prev_high + self._prev_low + self._prev_close) / 3.0
self._res1 = 2.0 * self._pivot - self._prev_low
self._sup1 = 2.0 * self._pivot - self._prev_high
self._prev_high = high
self._prev_low = low
if self._pivot > 0 and self._prev_close > 0:
# Cross above pivot => long
if self._prev_close <= self._pivot and close > self._pivot and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Cross below pivot => short
elif self._prev_close >= self._pivot and close < self._pivot and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
# Exit long at resistance or support
elif self.Position > 0 and (close >= self._res1 or close <= self._sup1):
self.SellMarket()
# Exit short at support or resistance
elif self.Position < 0 and (close <= self._sup1 or close >= self._res1):
self.BuyMarket()
self._prev_close = close
def CreateClone(self):
return tcp_pivot_stop_strategy()