在 GitHub 上查看

SAR 自动化策略

该示例展示了基于 Parabolic SAR 指标的简单交易方法。 当价格高于 SAR 值且没有持仓时策略做多;当价格低于 SAR 值且没有持仓时策略做空。策略还包含固定止损、止盈以及可选的移动止损等风险控制功能。

参数

  • SarStep – SAR 指标的加速因子。
  • SarMax – SAR 指标的最大加速因子。
  • StopLoss – 以价格单位表示的止损距离。
  • TakeProfit – 以价格单位表示的止盈距离。
  • TrailingStop – 以价格单位表示的移动止损距离。
  • CandleType – 用于计算指标的K线类型。

交易逻辑

  1. 订阅K线并计算 Parabolic SAR 数值。
  2. 入场
    • 当 SAR 在收盘价下方且没有持仓时做多。
    • 当 SAR 在收盘价上方且没有持仓时做空。
  3. 出场
    • 当价格达到相反的 SAR 水平时平仓。
    • 应用止损、止盈和移动止损规则。

该策略仅供学习目的,展示了如何在高层 StockSharp API 中使用指标和风险控制。

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>
/// Simple Parabolic SAR based strategy with optional stop-loss,
/// take-profit and trailing stop management.
/// </summary>
public class SarAutomatedStrategy : Strategy
{
	private readonly StrategyParam<decimal> _sarStep;
	private readonly StrategyParam<decimal> _sarMax;
	private readonly StrategyParam<decimal> _stopLoss;
	private readonly StrategyParam<decimal> _takeProfit;
	private readonly StrategyParam<decimal> _trailingStop;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _entryPrice;
	private decimal _highestPrice;
	private decimal _lowestPrice;

	/// <summary>
	/// Parabolic SAR acceleration step.
	/// </summary>
	public decimal SarStep
	{
		get => _sarStep.Value;
		set => _sarStep.Value = value;
	}

	/// <summary>
	/// Parabolic SAR maximum acceleration.
	/// </summary>
	public decimal SarMax
	{
		get => _sarMax.Value;
		set => _sarMax.Value = value;
	}

	/// <summary>
	/// Stop loss in price units.
	/// </summary>
	public decimal StopLoss
	{
		get => _stopLoss.Value;
		set => _stopLoss.Value = value;
	}

	/// <summary>
	/// Take profit in price units.
	/// </summary>
	public decimal TakeProfit
	{
		get => _takeProfit.Value;
		set => _takeProfit.Value = value;
	}

	/// <summary>
	/// Trailing stop in price units.
	/// </summary>
	public decimal TrailingStop
	{
		get => _trailingStop.Value;
		set => _trailingStop.Value = value;
	}

	/// <summary>
	/// Candle type for calculations.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initialize <see cref="SarAutomatedStrategy"/>.
	/// </summary>
	public SarAutomatedStrategy()
	{
		_sarStep = Param(nameof(SarStep), 0.002m)
			.SetDisplay("SAR Step", "Acceleration factor for SAR", "Indicators");

		_sarMax = Param(nameof(SarMax), 0.02m)
			.SetDisplay("SAR Max", "Maximum acceleration for SAR", "Indicators");

		_stopLoss = Param(nameof(StopLoss), 3500m)
			.SetDisplay("Stop Loss", "Stop loss in price units", "Risk Management");

		_takeProfit = Param(nameof(TakeProfit), 6500m)
			.SetDisplay("Take Profit", "Take profit in price units", "Risk Management");

		_trailingStop = Param(nameof(TrailingStop), 800m)
			.SetDisplay("Trailing Stop", "Trailing stop in price units", "Risk Management");

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

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_entryPrice = 0m;
		_highestPrice = 0m;
		_lowestPrice = 0m;
	}

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

		var sar = new ParabolicSar
		{
			Acceleration = SarStep,
			AccelerationMax = SarMax
		};

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(sar, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, sar);
			DrawOwnTrades(area);
		}
	}

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		if (Position == 0)
		{
			if (sarValue < candle.ClosePrice)
			{
				BuyMarket();
				_entryPrice = candle.ClosePrice;
				_highestPrice = candle.ClosePrice;
				_lowestPrice = candle.ClosePrice;
			}
			else if (sarValue > candle.ClosePrice)
			{
				SellMarket();
				_entryPrice = candle.ClosePrice;
				_highestPrice = candle.ClosePrice;
				_lowestPrice = candle.ClosePrice;
			}
		}
		else if (Position > 0)
		{
			_highestPrice = Math.Max(_highestPrice, candle.HighPrice);

			if (candle.HighPrice - _entryPrice >= TakeProfit)
			{
				SellMarket();
				return;
			}

			if (_entryPrice - candle.LowPrice >= StopLoss)
			{
				SellMarket();
				return;
			}

			if (TrailingStop > 0m && _highestPrice - candle.ClosePrice >= TrailingStop)
			{
				SellMarket();
				return;
			}

			if (sarValue > candle.ClosePrice)
			{
				SellMarket();
			}
		}
		else if (Position < 0)
		{
			_lowestPrice = Math.Min(_lowestPrice, candle.LowPrice);

			if (_entryPrice - candle.LowPrice >= TakeProfit)
			{
				BuyMarket();
				return;
			}

			if (candle.HighPrice - _entryPrice >= StopLoss)
			{
				BuyMarket();
				return;
			}

			if (TrailingStop > 0m && candle.ClosePrice - _lowestPrice >= TrailingStop)
			{
				BuyMarket();
				return;
			}

			if (sarValue < candle.ClosePrice)
			{
				BuyMarket();
			}
		}
	}
}