在 GitHub 上查看

终极 T3 斐波那契 BTC 剥头皮策略

该策略使用两条Tilson T3均线捕捉比特币的短期波动。斐波那契调校的T3与标准T3的交叉产生做多或做空信号,可选择在反向信号或百分比止盈/止损下平仓。

测试显示年化收益约为38%,在低延迟的BTC交易对上表现最佳。

当快速T3上穿慢速T3时买入,下穿时卖出。可选择在反向交叉时直接平仓,或使用百分比止盈止损管理仓位。

细节

  • 入场条件
    • 多头:快速T3上穿慢速T3。
    • 空头:快速T3下穿慢速T3。
  • 方向:双向。
  • 出场条件
    • 反向交叉或启用的止盈/止损。
  • 止损:可选百分比。
  • 过滤器
    • 无。
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();
	        }
	    }
	}
}