在 GitHub 上查看

简单马丁模板策略

概述

该策略将 MT4 的 “Simple Martingale Template” 概念迁移到 StockSharp 平台。策略处理所选 CandleType 周期的已完成 K 线,利用一快一慢两条简单移动平均线(SMA)结合突破过滤条件进行入场判定。仓位规模采用马丁格尔资金管理:每次亏损后下笔交易的手数乘以系数,盈利后恢复为基础手数。

交易逻辑

  1. 订阅指定 CandleType 周期的蜡烛,仅在蜡烛收盘后才参与信号计算。
  2. 计算基于收盘价的快线 SMA(FastPeriod)与慢线 SMA(SlowPeriod)。
  3. 当以下条件成立时发出做多信号:
    • 最近已完成蜡烛的收盘价高于快线 SMA;
    • 快线 SMA 位于慢线 SMA 之上;
    • 前一根蜡烛中快线 SMA 位于慢线 SMA 之下;
    • 最近蜡烛的收盘价高于两根之前蜡烛的最高价。
  4. 当出现对称的反向条件(包括收盘价跌破两根之前蜡烛的最低价)时发出做空信号。
  5. 当无持仓且没有活动委托时,根据当前马丁格尔手数发送市价单入场。
  6. 通过程序方式记录止损与止盈价格,并在后续蜡烛的最高价/最低价触及相应水平时立即平仓。
  7. 仓位关闭且组合余额更新后:
    • 若余额上升,则手数恢复为 BaseVolume
    • 若余额下降,则将上一笔交易的手数乘以 Multiplier 并按品种的最小手数对齐。

参数说明

参数 描述
StopLossPoints 入场价到止损价的距离(以点数表示)。
TakeProfitPoints 入场价到止盈价的距离(以点数表示)。
BaseVolume 马丁格尔第一步使用的基础手数。
Multiplier 亏损后用于放大下一笔手数的倍数。
FastPeriod 快线 SMA 的周期。
SlowPeriod 慢线 SMA 的周期。
CandleType 策略分析使用的蜡烛类型(时间框架)。

资金管理

  • 只有在没有持仓且没有挂单时才会检查账户余额,从而调整下一笔交易的手数;微小波动(±0.01 货币单位)会被忽略。
  • 下单前会根据 VolumeStepMinVolumeMaxVolume 对手数进行合法化处理,保证满足交易所约束。
  • 止损与止盈通过监控蜡烛极值实现,行为与原始 MQL 方案一致,即使用市价单离场。

使用建议

  • 在启用策略前请确保历史数据足够,使两条 SMA 都已完成初始化(至少需要两个以上的收盘蜡烛)。
  • StopLossPointsTakeProfitPoints 为点数而非价格差,请结合标的的最小跳动值调整。
  • 马丁格尔资金管理增长迅速,请合理设置 MultiplierBaseVolume 以匹配账户承受能力。
  • 策略启动时会调用 StartProtection(),以便与 StockSharp 的保护机制协同工作。
namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// Simple Martingale Template strategy: SMA crossover with momentum confirmation.
/// Buys on fast SMA crossing above slow SMA, sells on crossing below.
/// </summary>
public class SimpleMartingaleTemplateStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;

	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;

	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 SimpleMartingaleTemplateStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_fastPeriod = Param(nameof(FastPeriod), 5)
			.SetGreaterThanZero()
			.SetDisplay("Fast SMA", "Fast SMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 15)
			.SetGreaterThanZero()
			.SetDisplay("Slow SMA", "Slow SMA period", "Indicators");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = 0;
		_prevSlow = 0;
		_hasPrev = false;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_hasPrev = false;
		var fast = new SimpleMovingAverage { Length = FastPeriod };
		var slow = new SimpleMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;

		if (_hasPrev)
		{
			if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
				BuyMarket();
			else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
				SellMarket();
		}
		else
		{
			if (fastValue > slowValue && Position <= 0)
				BuyMarket();
			else if (fastValue < slowValue && Position >= 0)
				SellMarket();
		}

		_prevFast = fastValue;
		_prevSlow = slowValue;
		_hasPrev = true;
	}
}