在 GitHub 上查看

反向马丁策略

概述

反向马丁策略 是 MetaTrader 专家顾问 “Reversing Martingale EA” 的 C# 版本。策略始终保持仅有一笔市场头寸,并在每次平仓后反向开仓。如果上笔交易出现亏损,则根据马丁格尔倍数放大下一笔交易量;如果实现盈利,则重新使用初始手数。所有头寸均使用点数形式的对称止损和止盈进行保护。

该策略不依赖任何技术指标或市场结构,只对已完成的交易作出响应,从而在允许交易的时间段内持续保持市场敞口。

核心逻辑

  1. 初始化
    • 策略启动后立即按照 Start Volume(初始手数)和 First Trade Side(首笔方向)下达市价单。
    • 根据 Target (points) 参数指定的距离设置止损与止盈。
  2. 仓位管理
    • 任何时刻仅允许一笔持仓。策略等待当前仓位被保护单或外部操作完全平仓。
    • 平仓后立即反向下一笔交易方向(买→卖或卖→买)。
    • 若最近一笔交易亏损,则下一笔交易量 = 上一笔手数 × Lot Multiplier;若盈利,则重置为 Start Volume
  3. 循环继续
    • 计算出新方向和手数后立即再次下达市价单,从而让反向马丁循环持续运行。

参数

名称 说明
Start Volume 每个盈利周期起始时使用的交易手数。
Lot Multiplier 亏损后应用的马丁倍数(必须大于 1)。
First Trade Side 策略启动时首笔交易的方向。
Target (points) 止损与止盈的距离(以最小报价步长表示)。
Order Comment 可选的订单备注,将写入每笔市价单。

其他说明

  • 止损/止盈距离以 UnitTypes.Step 形式传递给 StartProtection,因此每次开仓都会自动挂出保护单。
  • NormalizeVolume 助手会根据交易品种的数量步长以及最小/最大手数限制调整下单量。
  • 策略依赖成交回报事件来驱动流程;当连接恢复或重新允许交易时,马丁循环会自动继续。
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Reversing Martingale strategy: WMA crossover.
/// Buys when fast WMA crosses above slow WMA. Sells on cross below.
/// </summary>
public class ReversingMartingaleStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;

	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 ReversingMartingaleStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");

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

		_slowPeriod = Param(nameof(SlowPeriod), 30)
			.SetGreaterThanZero()
			.SetDisplay("Slow WMA", "Slow WMA period", "Indicators");
	}

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

		var fast = new WeightedMovingAverage { Length = FastPeriod };
		var slow = new WeightedMovingAverage { Length = SlowPeriod };

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

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, slow, (candle, fastVal, slowVal) =>
			{
				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 && Position <= 0)
						BuyMarket();
					else if (crossDown && 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);
		}
	}
}