This strategy trades breakouts when the closing price moves beyond recent extremes.
It calculates the highest and lowest closing prices over a configurable period.
A new uptrend is detected when the close exceeds the recent high,
while a downtrend starts when the close drops below the recent low.
When a new uptrend is detected, existing short positions can be closed and optional long positions opened.
Conversely, a new downtrend allows closing long positions and optionally opening shorts.
The strategy processes finished candles only and uses StockSharp's high level API.
Parameters
Period – number of bars to determine recent extremes.
Candle Type – timeframe of candles.
Open Long – allow opening long positions.
Open Short – allow opening short positions.
Close Long – allow closing long positions.
Close Short – allow closing short positions.
Logic
Subscribe to candle data of the selected timeframe.
Track highest and lowest closes over the period using Highest and Lowest indicators.
When price breaks above the highest close, signal an uptrend; when below the lowest close, signal a downtrend.
Enter or exit positions according to the new trend and enabled options.
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>
/// Trend arrows strategy based on breakouts of recent extremes.
/// Detects when price moves above the highest close or below the lowest close
/// over the specified period and trades in the direction of the breakout.
/// </summary>
public class TrendArrowsStrategy : Strategy
{
private readonly StrategyParam<int> _period;
private readonly StrategyParam<DataType> _candleType;
private bool _prevTrendUp;
private bool _prevTrendDown;
private decimal? _prevHighest;
private decimal? _prevLowest;
public int Period { get => _period.Value; set => _period.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public TrendArrowsStrategy()
{
_period = Param(nameof(Period), 15)
.SetDisplay("Period", "Number of bars for extreme calculation", "Parameters")
.SetOptimize(5, 30, 5);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe of candles", "Parameters");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevTrendUp = false;
_prevTrendDown = false;
_prevHighest = null;
_prevLowest = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevTrendUp = false;
_prevTrendDown = false;
_prevHighest = null;
_prevLowest = null;
var highest = new Highest { Length = Period };
var lowest = new Lowest { Length = Period };
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 highestVal, decimal lowestVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Use previous bar's highest/lowest to detect breakout
if (_prevHighest is null || _prevLowest is null)
{
_prevHighest = highestVal;
_prevLowest = lowestVal;
return;
}
var trendUp = false;
var trendDown = false;
if (candle.ClosePrice > _prevHighest.Value)
trendUp = true;
else if (candle.ClosePrice < _prevLowest.Value)
trendDown = true;
else
{
trendUp = _prevTrendUp;
trendDown = _prevTrendDown;
}
// Buy when up trend appears
if (!_prevTrendUp && trendUp && Position <= 0)
BuyMarket();
// Sell when down trend appears
if (!_prevTrendDown && trendDown && Position >= 0)
SellMarket();
_prevTrendUp = trendUp;
_prevTrendDown = trendDown;
_prevHighest = highestVal;
_prevLowest = lowestVal;
}
}
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 trend_arrows_strategy(Strategy):
def __init__(self):
super(trend_arrows_strategy, self).__init__()
self._period = self.Param("Period", 15) \
.SetDisplay("Period", "Number of bars for extreme calculation", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe of candles", "Parameters")
self._prev_trend_up = False
self._prev_trend_down = False
self._prev_highest = None
self._prev_lowest = None
@property
def period(self):
return self._period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(trend_arrows_strategy, self).OnReseted()
self._prev_trend_up = False
self._prev_trend_down = False
self._prev_highest = None
self._prev_lowest = None
def OnStarted2(self, time):
super(trend_arrows_strategy, self).OnStarted2(time)
self._prev_trend_up = False
self._prev_trend_down = False
self._prev_highest = None
self._prev_lowest = None
highest = Highest()
highest.Length = self.period
lowest = Lowest()
lowest.Length = self.period
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 process_candle(self, candle, highest_val, lowest_val):
if candle.State != CandleStates.Finished:
return
highest_val = float(highest_val)
lowest_val = float(lowest_val)
close_price = float(candle.ClosePrice)
if self._prev_highest is None or self._prev_lowest is None:
self._prev_highest = highest_val
self._prev_lowest = lowest_val
return
trend_up = False
trend_down = False
if close_price > self._prev_highest:
trend_up = True
elif close_price < self._prev_lowest:
trend_down = True
else:
trend_up = self._prev_trend_up
trend_down = self._prev_trend_down
if not self._prev_trend_up and trend_up and self.Position <= 0:
self.BuyMarket()
if not self._prev_trend_down and trend_down and self.Position >= 0:
self.SellMarket()
self._prev_trend_up = trend_up
self._prev_trend_down = trend_down
self._prev_highest = highest_val
self._prev_lowest = lowest_val
def CreateClone(self):
return trend_arrows_strategy()