在 GitHub 上查看

ADX & MA 策略

概述

该策略是 MetaTrader 专家顾问 ADX_MA (fortrader) 的 StockSharp 移植版本。 它将平滑移动平均线(SMMA)趋势过滤器与平均方向指数(ADX)结合, 只有在出现均线穿越并且 ADX 显示出足够强势的情况下才允许开仓。 移植版本保留了原始机器人的非对称风险控制: 多头采用更宽的止盈和跟踪止损距离,空头则使用更紧的目标和保护。

交易逻辑

  1. 使用设定周期在 K 线中位价上构建 SMMA,并计算相同周期的 ADX。
  2. 仅在收盘 K 线上进行信号判断,以模仿 MQL4 中 iClose(...,1)iClose(...,2) 的行为。
  3. 当上一根 K 线收盘价高于 SMMA、再前一根收盘价低于同一 SMMA 值且上一根 ADX 大于阈值时开多。
  4. 当上一根 K 线收盘价低于 SMMA、再前一根收盘价高于同一 SMMA 值且 ADX 高于阈值时开空。
  5. 持仓后的离场条件包括:
    • 均线重新穿越到反方向;
    • 依据各自的止损/止盈距离(以点数表示);
    • 可选的跟踪止损,在价格朝有利方向移动后逐步抬升或下移。

所有价差都会根据标的的最小报价步长进行点值换算,若证券未提供有效步长则使用 1 作为兜底值。

参数

名称 说明
SMMA Period 平滑移动平均线周期(默认 21)。
ADX Period ADX 指标周期(默认 14)。
ADX Threshold 允许开仓所需的最小 ADX 值(默认 16)。
Long Take Profit (pips) 多头止盈点数(默认 1300 点)。
Long Stop Loss (pips) 多头止损点数(默认 30 点)。
Long Trailing Stop (pips) 多头跟踪止损点数(默认 270 点)。
Short Take Profit (pips) 空头止盈点数(默认 160 点)。
Short Stop Loss (pips) 空头止损点数(默认 50 点)。
Short Trailing Stop (pips) 空头跟踪止损点数(默认 20 点)。
Volume 新开仓使用的下单量(默认 0.1)。
Candle Type 计算所使用的主 K 线序列(默认 1 分钟)。

所有参数都可用于优化,默认值与原始 EA 设置保持一致。

注意事项

  • 跟踪止损只有在价格至少向有利方向移动指定距离后才会启动。
  • 反向信号会在开新仓之前平掉现有仓位。
  • 如果图表区域可用,策略会自动绘制 K 线、指标以及自身成交记录。
  • 本策略没有自动化测试,请使用回测或模拟环境验证其在目标市场上的表现。
using System;

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

namespace StockSharp.Samples.Strategies;

public class AdxMaStrategy : Strategy
{
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _smaPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevClose; private decimal _prevEma; private bool _hasPrev;

	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
	public int SmaPeriod { get => _smaPeriod.Value; set => _smaPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public AdxMaStrategy()
	{
		_emaPeriod = Param(nameof(EmaPeriod), 14).SetDisplay("EMA Period", "EMA lookback", "Indicators");
		_smaPeriod = Param(nameof(SmaPeriod), 50).SetDisplay("SMA Period", "SMA trend filter", "Indicators");
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevClose = 0;
		_prevEma = 0;
		_hasPrev = false;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_hasPrev = false;
		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ema, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal ema)
	{
		if (candle.State != CandleStates.Finished) return;
		var close = candle.ClosePrice;
		if (!_hasPrev) { _prevClose = close; _prevEma = ema; _hasPrev = true; return; }

		if (_prevClose <= _prevEma && close > ema && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); }
		else if (_prevClose >= _prevEma && close < ema && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); }
		_prevClose = close; _prevEma = ema;
	}
}