This strategy trades around classic daily pivot point levels. Pivot points are calculated from the previous day's high, low and close prices. Limit orders are placed at selected support or resistance levels and positions are managed with predefined stop-loss and take-profit levels.
Parameters
Volume – order volume.
Target Variant – selects which support/resistance levels are used for entry, stop and target:
Entry at S1/R1, stop at S2/R2, target at R1/S1.
Entry at S1/R1, stop at S2/R2, target at R2/S2.
Entry at S2/R2, stop at S3/R3, target at R1/S1.
Entry at S2/R2, stop at S3/R3, target at R2/S2.
Entry at S2/R2, stop at S3/R3, target at R3/S3.
Intraday Close – close any open position at 23:00.
Modify Stop Loss – move stop loss to the first target level after it has been reached.
Trading Logic
At the start of each day the strategy computes pivot, three resistance and three support levels using the previous day's data.
When price touches the chosen support or resistance level a limit order is sent in the opposite direction.
Position is closed when stop-loss or take-profit level is hit. Optional stop-loss modification can tighten risk after the first target.
If Intraday Close is enabled, any open position is closed at the end of the trading session.
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 point trading strategy based on previous period support/resistance levels.
/// Buys at support, sells at resistance, exits at opposite pivot level.
/// </summary>
public class TcpPivotLimitStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private DateTime _currentDay;
private decimal _dayHigh;
private decimal _dayLow;
private decimal _dayClose;
private decimal _pivot;
private decimal _r1, _s1;
private decimal _entryPrice;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public TcpPivotLimitStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_currentDay = default;
_dayHigh = 0;
_dayLow = 0;
_dayClose = 0;
_pivot = _r1 = _s1 = 0;
_entryPrice = 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;
var day = candle.OpenTime.Date;
if (_currentDay != day)
{
if (_currentDay != default)
{
_pivot = (_dayHigh + _dayLow + _dayClose) / 3m;
_r1 = 2m * _pivot - _dayLow;
_s1 = 2m * _pivot - _dayHigh;
}
_currentDay = day;
_dayHigh = candle.HighPrice;
_dayLow = candle.LowPrice;
_dayClose = candle.ClosePrice;
return;
}
_dayHigh = Math.Max(_dayHigh, candle.HighPrice);
_dayLow = Math.Min(_dayLow, candle.LowPrice);
_dayClose = candle.ClosePrice;
if (_pivot == 0) return;
var close = candle.ClosePrice;
if (Position == 0)
{
// Buy at support
if (close <= _s1)
{
BuyMarket();
_entryPrice = close;
}
// Sell at resistance
else if (close >= _r1)
{
SellMarket();
_entryPrice = close;
}
}
else if (Position > 0)
{
// Exit long at resistance or stop at entry - (r1 - s1)
if (close >= _r1 || close <= _entryPrice - (_r1 - _s1))
{
SellMarket();
_entryPrice = 0;
}
}
else if (Position < 0)
{
// Exit short at support or stop
if (close <= _s1 || close >= _entryPrice + (_r1 - _s1))
{
BuyMarket();
_entryPrice = 0;
}
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class tcp_pivot_limit_strategy(Strategy):
def __init__(self):
super(tcp_pivot_limit_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle type", "General")
self._current_day = None
self._day_high = 0.0
self._day_low = 0.0
self._day_close = 0.0
self._pivot = 0.0
self._r1 = 0.0
self._s1 = 0.0
self._entry_price = 0.0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(tcp_pivot_limit_strategy, self).OnReseted()
self._current_day = None
self._day_high = 0.0
self._day_low = 0.0
self._day_close = 0.0
self._pivot = 0.0
self._r1 = 0.0
self._s1 = 0.0
self._entry_price = 0.0
def OnStarted2(self, time):
super(tcp_pivot_limit_strategy, self).OnStarted2(time)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def on_process(self, candle):
if candle.State != CandleStates.Finished:
return
day = candle.OpenTime.Date
if self._current_day != day:
if self._current_day is not None:
self._pivot = (self._day_high + self._day_low + self._day_close) / 3.0
self._r1 = 2.0 * self._pivot - self._day_low
self._s1 = 2.0 * self._pivot - self._day_high
self._current_day = day
self._day_high = candle.HighPrice
self._day_low = candle.LowPrice
self._day_close = candle.ClosePrice
return
self._day_high = max(float(self._day_high), float(candle.HighPrice))
self._day_low = min(float(self._day_low), float(candle.LowPrice))
self._day_close = candle.ClosePrice
if self._pivot == 0:
return
close = candle.ClosePrice
if self.Position == 0:
# Buy at support
if close <= self._s1:
self.BuyMarket()
self._entry_price = close
# Sell at resistance
elif close >= self._r1:
self.SellMarket()
self._entry_price = close
elif self.Position > 0:
# Exit long at resistance or stop at entry - (r1 - s1)
if close >= self._r1 or close <= self._entry_price - (self._r1 - self._s1):
self.SellMarket()
self._entry_price = 0
elif self.Position < 0:
# Exit short at support or stop
if close <= self._s1 or close >= self._entry_price + (self._r1 - self._s1):
self.BuyMarket()
self._entry_price = 0
def CreateClone(self):
return tcp_pivot_limit_strategy()