Trendline breakout strategy using user-defined trend lines. The strategy computes linear projections from slope and intercept parameters for both bullish and bearish lines. When the close price exceeds the projected buy line by a threshold, a long position is opened. When the price falls below the sell line minus the threshold, a short position is entered.
Positions are protected by take profit and stop loss values in ticks. Optional trailing stop updates the protective stop as price moves in favor. An additional option closes the trade if the breakout fails on the next candle.
Details
Entry Criteria:
Long: Close > BuyLine + EntryThreshold
Short: Close < SellLine - EntryThreshold
Long/Short: Both
Exit Criteria: Stop loss, take profit, trailing stop or opposite signal
Stops:
Take profit in ticks
Stop loss in ticks
Optional trailing stop in ticks
Optional false breakout close on next candle
Default Values:
EntryThreshold = 15m
StopLossTicks = 50
TakeProfitTicks = 100
EnableTrailing = false
TrailingStepTicks = 5
FalseBreakClose = true
CandleType = TimeSpan.FromMinutes(5).TimeFrame()
BuyLineSlope = 0m
BuyLineIntercept = 0m
SellLineSlope = 0m
SellLineIntercept = 0m
Filters:
Category: Trend line breakout
Direction: Both
Indicators: None
Stops: Yes
Complexity: Medium
Timeframe: Intraday
Seasonality: No
Neural Networks: No
Divergence: No
Risk Level: Medium
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>
/// Swing trader using EMA crossover.
/// </summary>
public class CoensioSwingTraderStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public CoensioSwingTraderStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "Trading");
_slowPeriod = Param(nameof(SlowPeriod), 26)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "Trading");
_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();
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
SubscribeCandles(CandleType)
.Bind(fast, slow, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal)
{
if (candle.State != CandleStates.Finished) return;
if (!_hasPrev)
{
_prevFast = fastVal;
_prevSlow = slowVal;
_hasPrev = true;
return;
}
var crossUp = _prevFast <= _prevSlow && fastVal > slowVal;
var crossDown = _prevFast >= _prevSlow && fastVal < slowVal;
if (crossUp && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (crossDown && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevFast = fastVal;
_prevSlow = slowVal;
}
}