Ver no GitHub

Timeshifter Triple Timeframe Strategy

Strategy trading across three timeframes with optional ADX confirmation and session filters.

Testing indicates an average annual return of about 37%. It performs best in the forex market.

The system aligns with the higher timeframe trend, enters on medium timeframe breakouts and exits on lower timeframe reversals. Trades can be limited to London, New York and Tokyo sessions. An ADX filter can be used to ensure sufficient momentum.

Details

  • Entry Criteria:
    • Long: Higher timeframe close above its SMA and medium timeframe price crosses above its SMA.
    • Short: Higher timeframe close below its SMA and medium timeframe price crosses below its SMA.
  • Long/Short: Both sides.
  • Exit Criteria:
    • Long: Lower timeframe price crosses below its SMA.
    • Short: Lower timeframe price crosses above its SMA.
  • Stops: No.
  • Default Values:
    • HigherMaLength = 50
    • MediumMaLength = 20
    • LowerMaLength = 10
    • AdxLength = 14
    • AdxThreshold = 25
  • Filters:
    • Category: Trend following
    • Direction: Both
    • Indicators: SMA, ADX
    • Stops: No
    • Complexity: Complex
    • Timeframe: Multi-timeframe
    • 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>
/// Timeshifter Triple Timeframe strategy using EMA crossover.
/// </summary>
public class TimeshifterTripleTimeframeStrategy : Strategy
{
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<DataType> _candleType;

	public int SlowLength { get => _slowLength.Value; set => _slowLength.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public TimeshifterTripleTimeframeStrategy()
	{
		_slowLength = Param(nameof(SlowLength), 40)
			.SetGreaterThanZero()
			.SetDisplay("Slow Length", "Slow EMA period", "General");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle type", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		var fast = new ExponentialMovingAverage { Length = 14 };
		var slow = new ExponentialMovingAverage { Length = SlowLength };
		var prevF = 0m; var prevS = 0m; var init = false;
		var lastSignal = DateTimeOffset.MinValue;
		var cooldown = TimeSpan.FromMinutes(360);
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, (candle, f, s) =>
		{
			if (candle.State != CandleStates.Finished) return;
			if (!fast.IsFormed || !slow.IsFormed) return;
			if (!init) { prevF = f; prevS = s; init = true; return; }
			if (candle.OpenTime - lastSignal >= cooldown)
			{
				if (prevF <= prevS && f > s && Position <= 0) { BuyMarket(); lastSignal = candle.OpenTime; }
				else if (prevF >= prevS && f < s && Position >= 0) { SellMarket(); lastSignal = candle.OpenTime; }
			}
			prevF = f; prevS = s;
		}).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fast); DrawIndicator(area, slow); DrawOwnTrades(area); }
	}
}