View on GitHub

Ultimate T3 Fibonacci BTC Scalping Strategy

This strategy applies two Tilson T3 moving averages to capture short-term BTC moves. A crossover between the Fibonacci-tuned and standard T3 lines generates long or short entries. Optional TP/SL management and closing on opposite signals are supported.

Testing indicates an average annual return of about 38%. It works best on BTC pairs with low latency.

The strategy buys when the fast T3 crosses above the slow T3 and sells on the opposite cross. Positions can be closed on reverse signals, or by percentage take profit and stop loss levels.

Details

  • Entry Criteria:
    • Long: Fast T3 crosses above slow T3.
    • Short: Fast T3 crosses below slow T3.
  • Long/Short: Both.
  • Exit Criteria:
    • Opposite crossover or TP/SL if enabled.
  • Stops: Optional percentage-based.
  • Filters:
    • None.
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy based on two T3-style moving averages for BTC scalping.
/// </summary>
public class UltimateT3FibonacciBtcScalpingStrategy : Strategy
{
	private readonly StrategyParam<int> _t3Length;
	private readonly StrategyParam<int> _t3FiboLength;
	private readonly StrategyParam<bool> _useOpposite;
	private readonly StrategyParam<bool> _useTradeManagement;
	private readonly StrategyParam<decimal> _takeProfit;
	private readonly StrategyParam<decimal> _stopLoss;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _entryPrice;
	private decimal _prevT3;
	private decimal _prevT3Fibo;

	public int T3Length { get => _t3Length.Value; set => _t3Length.Value = value; }
	public int T3FiboLength { get => _t3FiboLength.Value; set => _t3FiboLength.Value = value; }
	public bool UseOpposite { get => _useOpposite.Value; set => _useOpposite.Value = value; }
	public bool UseTradeManagement { get => _useTradeManagement.Value; set => _useTradeManagement.Value = value; }
	public decimal TakeProfit { get => _takeProfit.Value; set => _takeProfit.Value = value; }
	public decimal StopLoss { get => _stopLoss.Value; set => _stopLoss.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public UltimateT3FibonacciBtcScalpingStrategy()
	{
	    _t3Length = Param(nameof(T3Length), 33)
	        .SetGreaterThanZero()
	        .SetDisplay("T3 Length", "Main T3 length", "General");

	    _t3FiboLength = Param(nameof(T3FiboLength), 19)
	        .SetGreaterThanZero()
	        .SetDisplay("T3 Fibo Length", "Fibonacci T3 length", "General");

	    _useOpposite = Param(nameof(UseOpposite), true)
	        .SetDisplay("Use Opposite", "Close on opposite signal", "General");

	    _useTradeManagement = Param(nameof(UseTradeManagement), true)
	        .SetDisplay("Use Trade Management", "Enable TP/SL", "General");

	    _takeProfit = Param(nameof(TakeProfit), 15m)
	        .SetGreaterThanZero()
	        .SetDisplay("Take Profit %", "Take profit percentage", "Risk");

	    _stopLoss = Param(nameof(StopLoss), 2m)
	        .SetGreaterThanZero()
	        .SetDisplay("Stop Loss %", "Stop loss percentage", "Risk");

	    _candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
	        .SetDisplay("Candle Type", "Type of candles", "General");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_entryPrice = 0;
		_prevT3 = 0;
		_prevT3Fibo = 0;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
	    base.OnStarted2(time);

	    var t3 = new ExponentialMovingAverage { Length = T3Length };
	    var t3Fibo = new ExponentialMovingAverage { Length = T3FiboLength };

	    var subscription = SubscribeCandles(CandleType);
	    subscription.Bind(t3, t3Fibo, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal t3, decimal t3Fibo)
	{
	    if (candle.State != CandleStates.Finished)
	        return;

	    var crossUp = _prevT3Fibo <= _prevT3 && t3Fibo > t3;
	    var crossDown = _prevT3Fibo >= _prevT3 && t3Fibo < t3;
	    _prevT3 = t3;
	    _prevT3Fibo = t3Fibo;

	    if (crossUp && Position <= 0)
	    {
	        BuyMarket();
	        _entryPrice = candle.ClosePrice;
	    }
	    else if (crossDown && Position >= 0)
	    {
	        SellMarket();
	        _entryPrice = candle.ClosePrice;
	    }
	    else
	    {
	        if (UseOpposite)
	        {
	            if (Position > 0 && crossDown)
	                SellMarket();
	            else if (Position < 0 && crossUp)
	                BuyMarket();
	        }
	    }

	    if (UseTradeManagement && Position != 0)
	    {
	        var tp = _entryPrice * (1 + (Position > 0 ? TakeProfit : -TakeProfit) / 100m);
	        var sl = _entryPrice * (1 - (Position > 0 ? StopLoss : -StopLoss) / 100m);

	        if (Position > 0)
	        {
	            if (candle.ClosePrice >= tp || candle.ClosePrice <= sl)
	                SellMarket();
	        }
	        else if (Position < 0)
	        {
	            if (candle.ClosePrice <= tp || candle.ClosePrice >= sl)
	                BuyMarket();
	        }
	    }
	}
}