View on GitHub

Coensio Swing Trader Strategy

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;
	}
}