在 GitHub 上查看

VR Smart Grid Lite 策略

VR Smart Grid Lite 策略 重现了同名 MetaTrader 智能交易系统的运行方式。策略通过市价单构建马丁格尔式网格,在价格逆势移动达到设定步长时加仓。网格支持两种出场方式:在加权平均价一次性平掉最旧与最新订单,或部分减仓以保留网格结构。

参数

  • Take Profit (pips) – 当仅有一笔仓位时使用的止盈距离。
  • Start Volume – 每个方向首笔订单的初始手数。
  • Maximal Volume – 单笔订单允许的最大手数。
  • Close ModeAverage 在权重目标价同时平掉最旧和最新订单;PartClose 仅减掉最新订单的起始手数并完全平掉最旧订单。
  • Order Step (pips) – 价格逆势移动达到该步长后才会加仓。
  • Minimal Profit (pips) – 在加权平均价基础上追加的额外利润缓冲。
  • Slippage (pips) – 保留自原始 EA 的滑点输入,用于文档完整性。
  • Candle Type – 用于驱动逻辑的 K 线周期,上一根已完成 K 线决定当前偏向。

算法

  1. 每当收到新的完结 K 线时,读取上一根 K 线的方向。
  2. 如果上一根 K 线收阳,且当前没有多单或价格较最低买入价下跌超过设定步长,则以市价买入新仓。
  3. 如果上一根 K 线收阴,且当前没有空单或价格较最高卖出价上涨超过设定步长,则以市价卖出新仓。
  4. 新仓手数来源于当前方向最低(或最高)价格订单的手数,并在每次加仓时加倍,同时遵守最大手数和交易所的最小手数/步长限制。
  5. 当某方向只剩一笔仓位时,使用固定止盈距离退出。
  6. 当存在多笔仓位时,根据最旧与最新订单计算加权平均价并决定出场:
    • Average 模式:价格触及权重目标价加上利润缓冲时,同时平掉最旧和最新订单。
    • PartClose 模式:价格触及目标时,按起始手数减仓最新订单,并完全平掉最旧订单,其余网格继续保持。
  7. 策略跟踪所有开仓与平仓,保持内部网格状态与真实持仓同步。

注意事项

  • 策略使用市价单,实际成交价与滑点取决于经纪商与市场流动性。
  • 请确认交易品种的最小手数与步长与设定的起始手数兼容。
  • 网格/马丁策略在强趋势行情中风险迅速累积,请务必做好资金管理。
namespace StockSharp.Samples.Strategies;

using System;

using Ecng.Common;

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

/// <summary>
/// VR Smart Grid Lite: grid trading based on price levels with SMA filter.
/// </summary>
public class VrSmartGridLiteStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<decimal> _gridPercent;
	private readonly StrategyParam<int> _smaPeriod;

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

	public decimal GridPercent
	{
		get => _gridPercent.Value;
		set => _gridPercent.Value = value;
	}

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

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

		_gridPercent = Param(nameof(GridPercent), 3.0m)
			.SetGreaterThanZero()
			.SetDisplay("Grid %", "Grid step percentage", "Grid");

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

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

		var sma = new SimpleMovingAverage { Length = SmaPeriod };

		decimal? lastTradePrice = null;

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

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				var close = candle.ClosePrice;

				if (!lastTradePrice.HasValue)
				{
					lastTradePrice = close;
					return;
				}

				var step = lastTradePrice.Value * GridPercent / 100m;

				if (close <= lastTradePrice.Value - step)
				{
					BuyMarket();
					lastTradePrice = close;
				}
				else if (close >= lastTradePrice.Value + step)
				{
					SellMarket();
					lastTradePrice = close;
				}
			})
			.Start();

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