在 GitHub 上查看

OHLC Check 策略

概述

OHLC Check 策略复刻了经典的 MetaTrader 智能交易系统:它观察历史蜡烛的开盘价、最高价、最低价和收盘价,并根据蜡烛实体的方向来下单。策略允许用户选择信号引用的历史偏移量,还可以反转信号方向,从而在没有技术指标的情况下完成基于价格行为的交易。

运行逻辑

  1. 策略订阅所选周期的蜡烛,只有在蜡烛收盘后才会处理数据。
  2. 每根收盘蜡烛都会存储其开盘价与收盘价,供 SignalShift 参数访问较早的历史数据。
  3. 如果收盘价高于开盘价,生成做多信号;如果收盘价低于开盘价,生成做空信号;若两者相等则跳过交易。
  4. ReverseSignals 参数可以反转方向,完全模拟原始 EA 的反向交易模式。
  5. 当当前没有持仓时,只要最新买卖价之间的差值不超过 SpreadLimitPips 所设的阈值,策略就会按信号方向发送市价单。买卖差值通过订阅深度数据实时跟踪。
  6. 如果已经持仓,出现反向信号时策略仅关闭原有仓位,而不是直接反手,这与 MQL 实现保持一致。
  7. 在启动阶段会按照点值距离创建止盈和止损保护,数值会按照交易品种的价格步长自动换算。

参数

参数 默认值 说明
CandleType 5 分钟周期 用于判断信号的蜡烛类型。
StopLossPips 50 止损距离(点);为 0 时关闭止损。
TakeProfitPips 100 止盈距离(点);为 0 时关闭止盈。
ReverseSignals false 是否反转多空信号。
SpreadLimitPips 1 开仓时允许的最大点差。
SignalShift 1 用于计算信号的历史偏移量(1 表示上一根已收盘蜡烛)。
OrderVolume 1 每次市价单的下单数量。

使用提示

  • 策略会根据交易品种的价格精度自动将点值转换成价格步长;当报价保留 3 或 5 位小数时,会自动乘以 10 以匹配常规点值。
  • 为了正确检查点差,需要在数据源中启用委托簿/盘口订阅。如果没有可用的买价或卖价,策略会跳过开仓。
  • 止盈止损在 OnStarted 阶段只初始化一次,若需要修改距离请在修改参数后重新启动策略。
  • 该策略只关注蜡烛实体,不会使用最高价与最低价,与原始 MQL 代码完全一致。

部署步骤

  1. 将策略应用到同时提供蜡烛数据和盘口数据的交易品种上。
  2. 根据交易风格设置周期、点值距离和下单量等参数。
  3. 启动策略,策略会等待下一根收盘蜡烛后开始执行。
  4. 观察日志中的点差拒绝或成交记录,并根据需要微调参数。
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// OHLC check strategy. Trades based on candle structure (bullish/bearish body).
/// </summary>
public class OhlcCheckStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _confirmBars;

	private int _bullCount;
	private int _bearCount;

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

	public int ConfirmBars
	{
		get => _confirmBars.Value;
		set => _confirmBars.Value = value;
	}

	public OhlcCheckStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_confirmBars = Param(nameof(ConfirmBars), 3)
			.SetGreaterThanZero()
			.SetDisplay("Confirm Bars", "Consecutive candles to confirm direction", "Trading");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_bullCount = 0;
		_bearCount = 0;
	}

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

		_bullCount = 0;
		_bearCount = 0;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ProcessCandle)
			.Start();

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		if (candle.ClosePrice > candle.OpenPrice)
		{
			_bullCount++;
			_bearCount = 0;
		}
		else if (candle.ClosePrice < candle.OpenPrice)
		{
			_bearCount++;
			_bullCount = 0;
		}

		// Consecutive bullish candles → buy
		if (_bullCount >= ConfirmBars && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
			_bullCount = 0;
		}
		// Consecutive bearish candles → sell
		else if (_bearCount >= ConfirmBars && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
			_bearCount = 0;
		}
	}
}