在 GitHub 上查看

Auto Trading Publish 策略

概述

该策略是 MetaTrader 4 工具 “Auto Trading Publish” 的 StockSharp 版本。策略不会主动下单,而是专注于控制何时允许运行交易。通过订阅蜡烛数据来跟踪市场时间,一旦到达预设的开始或结束小时,就切换 AutoTradingActive 标志,从而模拟原工具自动切换 MT4 “AutoTrading” 按钮的行为。

交易逻辑

  • 默认订阅 1 分钟蜡烛流,即使没有真实成交也能持续获得时间戳。
  • 当有完整蜡烛的时间等于 StartHour 时,启用 AutoTradingActive 并记录日志。
  • 当有完整蜡烛的时间等于 StopHour 时,关闭 AutoTradingActive 并记录日志。
  • 如果同一小时内出现多根蜡烛,只会触发一次切换,避免日志被重复信息淹没。

参数

参数 说明
StartHour 打开自动交易的小时(0-23)。
StopHour 关闭自动交易的小时(0-23)。
CandleType 用于轮询市场时间的蜡烛时间框架,越短反应越快。

使用说明

  • 策略不会发送任何订单,只会提供 AutoTradingActive 状态,供其它策略或控制面板决定是否允许交易。
  • 当开始小时与结束小时相同,结束事件会在开始事件之后执行,因此交易保持关闭,与原始 EA 完全一致。
  • 请选择与所需反应速度相匹配的蜡烛周期;1 分钟周期在响应速度与资源占用之间取得了平衡。

与 MetaTrader 版本的差异

  • MT4 版本通过 Windows 消息控制整个平台按钮;StockSharp 版本提供策略级标志,更易于与其它自动化组件整合。
  • 移植版本完全使用高层 API,无需低层消息钩子,可方便地与图表或其它辅助策略组合使用。
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Auto Trading Publish strategy: SMA crossover + RSI confirmation.
/// Buys when close crosses above SMA and RSI is below 40.
/// Sells when close crosses below SMA and RSI is above 60.
/// </summary>
public class AutoTradingPublishStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _smaPeriod;
	private readonly StrategyParam<int> _rsiPeriod;

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

	public int SmaPeriod
	{
		get => _smaPeriod.Value;
		set => _smaPeriod.Value = value;
	}

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

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

		_smaPeriod = Param(nameof(SmaPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("SMA Period", "SMA period", "Indicators");

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period", "Indicators");
	}

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

		var sma = new SimpleMovingAverage { Length = SmaPeriod };
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };

		decimal? prevClose = null;
		decimal? prevSma = null;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(sma, rsi, (candle, smaVal, rsiVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				var close = candle.ClosePrice;

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

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

				prevClose = close;
				prevSma = smaVal;
			})
			.Start();

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