在 GitHub 上查看

Smart AC Trader 策略

概述

Smart AC Trader 将 MetaTrader 中的 "Smart AC Trader" 专家顾问移植到 StockSharp 的高级 API。原始 EA 会比较货币对中各货币的强弱并在基准货币强于报价货币时入场。在 StockSharp 中我们使用指数移动平均线(EMA)和动量指标率(ROC)来模拟这种强弱筛选,同时仅对所连接的单一证券进行交易:

  • 快速 EMA 反映短期趋势方向。
  • 慢速 EMA 表示主要趋势。
  • ROC 确认价格动量是否支持当前趋势,从而决定是否可以入场。

开仓后,策略会结合止损、止盈、移动止损以及保本管理,以复刻原始 EA 丰富的资金管理设置。

交易逻辑

  1. 订阅设定的 K 线类型(时间框),在每根 K 线收盘时计算快速 EMA、慢速 EMA 和 ROC。
  2. 当快速 EMA 高于慢速 EMA 且 ROC 大于等于买入动量阈值时做多。如当前持有空头,将先平仓再建立多头。
  3. 当快速 EMA 低于慢速 EMA 且 ROC 小于等于卖出动量阈值的负值时做空。如当前持有多头,将先平仓再建立空头。
  4. 在每根已完成的 K 线上管理持仓:
    • 根据设定的价格步长距离触发止盈或止损。
    • 可选:价格向有利方向移动达到触发距离后启动保本保护,若价格回撤到保留的距离则平仓。
    • 可选:以设定的价格步长距离从入场后的最高价(多头)或最低价(空头)回撤时平仓,实现移动止损。

参数

参数 说明
Fast EMA 快速 EMA 的周期长度。
Slow EMA 慢速 EMA 的周期长度。
ROC Period ROC 动量过滤的回溯长度。
Buy Momentum 开多所需的最小正 ROC。
Sell Momentum 开空所需的最小负 ROC(绝对值)。
Stop Loss 以价格步长表示的止损距离。
Take Profit 以价格步长表示的止盈距离。
Use Trailing 是否启用移动止损。
Trailing 移动止损的价格步长距离。
Use Break Even 是否启用保本保护。
Break Even Trigger 启动保本所需的盈利价格步长。
Break Even Offset 保本触发后保留的价格步长距离。
Candle Type 用于计算指标的 K 线类型。

备注

  • 策略在启动时调用 Strategy.StartProtection(),以激活项目指南推荐的持仓保护机制。
  • 仓位规模使用基类 Strategy.Volume 属性。反向信号会自动考虑当前仓位,使得反向指令既能平仓也能建立新方向。
  • 所有风险参数均以价格步长表示,延续了原始 EA 的点数(pip)概念。请确保交易品种配置了有效的 PriceStep
namespace StockSharp.Samples.Strategies;

using System;

using Ecng.Common;

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

/// <summary>
/// Smart AC Trader: EMA trend + ROC momentum filter.
/// Buys when fast EMA above slow EMA and ROC positive.
/// Sells when fast EMA below slow EMA and ROC negative.
/// </summary>
public class SmartAcTraderStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _rocPeriod;

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

	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	public int RocPeriod
	{
		get => _rocPeriod.Value;
		set => _rocPeriod.Value = value;
	}

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

		_fastPeriod = Param(nameof(FastPeriod), 10)
			.SetGreaterThanZero()
			.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");

		_rocPeriod = Param(nameof(RocPeriod), 13)
			.SetGreaterThanZero()
			.SetDisplay("ROC Period", "Rate of Change period", "Indicators");
	}

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

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var roc = new RateOfChange { Length = RocPeriod };

		decimal? prevFast = null;
		decimal? prevSlow = null;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, slow, roc, (candle, fastVal, slowVal, rocVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				if (prevFast.HasValue && prevSlow.HasValue)
				{
					var crossUp = prevFast.Value <= prevSlow.Value && fastVal > slowVal;
					var crossDown = prevFast.Value >= prevSlow.Value && fastVal < slowVal;

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

				prevFast = fastVal;
				prevSlow = slowVal;
			})
			.Start();

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