在 GitHub 上查看

Parabolic SAR Cross 策略

本策略是 MetaTrader 平台「PSAR Trader EA」专家顾问在 StockSharp 上的移植版本。算法持续监控价格与 Parabolic SAR 指标之间的关系,只在指标点从蜡烛一侧翻转到另一侧时做出反应。移植过程中保留了原始的资金管理思想:既可以使用固定手数,也可以根据账户余额动态调整下单量,同时设置固定的止损/止盈,并在盈利达到指定阈值后启动追踪止损。

交易逻辑

  • 在选定的 K 线序列上(默认 30 分钟周期)根据用户参数计算 Parabolic SAR 指标。
  • 当 SAR 点从蜡烛实体上方翻到下方时认定为看多翻转。若当前无持仓则市价买入;若持有空单则先平掉空头,等待下一根信号再开多。
  • 当 SAR 点从蜡烛实体下方翻到上方时认定为看空翻转。若当前空仓则市价卖出;若持有多单则先平掉多头,下一次信号再开空。
  • 每根收盘 K 线都会检查已有仓位:一旦当根最高价或最低价触及任何保护性价位(止损、止盈或追踪止损),即刻平仓。

风险控制

  • 止损以点数(价格最小变动单位)表示。多单止损设置在入场价下方,空单止损设置在入场价上方。
  • 止盈同样以点数表示,与止损距离对称,价格触及即平仓。
  • 追踪止损在价格向有利方向移动到指定点数后激活,仅在盈利方向上收紧止损,复刻原始 EA 中“只收紧不放松”的逻辑。

手数管理

  • 固定手数:关闭自动手数时,按照参数中的固定值下单。
  • 自动手数:开启后按 (账户余额 / 1000) * LotsPerThousand 计算下单量,并对齐品种的手数步长与最小下单量。

参数及默认值

  • SarStep — Parabolic SAR 加速步长,默认 0.02
  • SarMaximum — Parabolic SAR 最大加速度,默认 0.2
  • CandleType — 分析所用的 K 线类型,默认 30 分钟。
  • UseAutoLot — 是否启用自动手数,默认 false
  • FixedLot — 关闭自动手数时的下单量,默认 0.1
  • LotsPerThousand — 自动手数的余额系数,默认 0.05
  • StopLossPoints — 止损距离(点),默认 500
  • TakeProfitPoints — 止盈距离(点),默认 1000
  • TrailingStartPoints — 启动追踪止损的盈利阈值(点),默认 500
  • TrailingDistancePoints — 追踪止损的固定距离(点),默认 100

备注

  • 策略可做多亦可做空,但始终只保持单向一笔仓位。
  • 保护性价位基于收盘 K 线进行判断,若实际交易中存在低于当前周期的瞬时波动,可能会影响真实成交效果。
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Parabolic SAR Cross strategy: PSAR crossover.
/// Buys when close crosses above PSAR. Sells when close crosses below PSAR.
/// </summary>
public class ParabolicSarCrossStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;

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

	public ParabolicSarCrossStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

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

		var sar = new ParabolicSar { Acceleration = 0.02m, AccelerationStep = 0.02m, AccelerationMax = 0.2m };

		decimal? prevSar = null;
		decimal? prevClose = null;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(sar, (candle, sarVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				var close = candle.ClosePrice;

				if (prevSar.HasValue && prevClose.HasValue)
				{
					var crossUp = prevClose.Value <= prevSar.Value && close > sarVal;
					var crossDown = prevClose.Value >= prevSar.Value && close < sarVal;

					if (crossUp && Position <= 0)
						BuyMarket();
					else if (crossDown && Position >= 0)
						SellMarket();
				}

				prevSar = sarVal;
				prevClose = close;
			})
			.Start();

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