在 GitHub 上查看

Swing Cyborg 策略

概述

Swing Cyborg 是一种辅助型策略,根据交易者对中长期趋势的主观判断来执行交易。用户设置预期的趋势方向以及该趋势有效的时间段,策略使用 RSI 指标确认入场并通过固定的目标管理退出。

参数

  • Volume – 下单手数。
  • TrendPrediction – 预期趋势方向(Uptrend 或 Downtrend)。
  • TrendTimeframe – 用于计算 RSI 和交易的时间周期(M30、H1 或 H4)。
  • TrendStart – 趋势开始时间。
  • TrendEnd – 趋势结束时间。
  • Aggressiveness – 资金管理等级:
    • 低:止盈 300 点,止损 200 点。
    • 中:止盈 500 点,止损 250 点。
    • 高:止盈 600 点,止损 300 点。

交易逻辑

  1. 等待所选周期形成新的蜡烛。
  2. 仅在当前时间位于 TrendStartTrendEnd 之间时交易。
  3. 计算 RSI(14)。
  4. 若没有持仓:
    • TrendPrediction 为 Uptrend 且 RSI ≤ 65 时买入。
    • TrendPrediction 为 Downtrend 且 RSI ≥ 35 时卖出。
  5. 使用 StartProtection 在达到预设盈利或亏损点数时自动平仓。

策略仅在蜡烛收盘后作出决策,并且在持有仓位时不会开立新的仓位。

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>
/// SwingCyborg strategy using RSI overbought/oversold levels.
/// </summary>
public class SwingCyborgStrategy : Strategy
{
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevRsi;
	private bool _hasPrev;

	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public SwingCyborgStrategy()
	{
		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period", "Parameters");
		_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();
		_prevRsi = 0;
		_hasPrev = false;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };

		SubscribeCandles(CandleType)
			.Bind(rsi, ProcessCandle)
			.Start();
	}

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

		if (!_hasPrev)
		{
			_prevRsi = rsiVal;
			_hasPrev = true;
			return;
		}

		// Buy when RSI exits oversold
		if (_prevRsi <= 30m && rsiVal > 30m && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		// Sell when RSI exits overbought
		else if (_prevRsi >= 70m && rsiVal < 70m && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevRsi = rsiVal;
	}
}