在 GitHub 上查看

看涨反转策略

该策略寻找经典的看涨反转蜡烛形态。当任一形态出现在50期简单移动平均线之下时,策略开多单。可选的追踪止损用于保护已获得的利润。

形态

  • Abandoned Baby – 两根连续的阴线之后出现一根阳线收于第一根阴线开盘价上方,第二根阴线向下跳空。
  • Morning Doji Star – 先是阴线,然后是一根十字或小实体蜡烛,第三根阳线回到第一根蜡烛的实体内部。
  • Three Inside Up – 先是阴线,其内出现较小的阳线,第三根阳线收盘价高于第一根阴线的开盘价。
  • Three Outside Up – 阴线后跟随一根更大的阳线包住它,第三根阳线确认反转。
  • Three White Soldiers – 三根连续的阳线且收盘价逐步抬高。

细节

  • 入场条件:任一形态出现且最后一根蜡烛开盘价低于移动平均线
  • 多/空:多
  • 出场条件:可选追踪止损
  • 止损:追踪
  • 默认值
    • MaPeriod = 50
    • TrailingStop = 50
    • UseTrailingStop = true
  • 过滤
    • 类型:形态
    • 方向:做多
    • 指标:SMA
    • 止损:追踪
    • 复杂度:基础
    • 时间框架:日内
    • 季节性:无
    • 神经网络:无
    • 背离:无
    • 风险等级:中等
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy looking for bullish/bearish reversal candlestick patterns with MA filter.
/// </summary>
public class BullishReversalStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _maPeriod;

	private decimal _prevOpen1, _prevClose1, _prevLow1;
	private decimal _prevOpen2, _prevClose2, _prevLow2;
	private decimal _prevOpen3, _prevClose3, _prevLow3;
	private int _candleCount;

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

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

		_maPeriod = Param(nameof(MaPeriod), 50)
			.SetDisplay("MA Period", "EMA length", "Parameters")
			.SetGreaterThanZero();
	}

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

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevOpen1 = 0; _prevClose1 = 0; _prevLow1 = 0;
		_prevOpen2 = 0; _prevClose2 = 0; _prevLow2 = 0;
		_prevOpen3 = 0; _prevClose3 = 0; _prevLow3 = 0;
		_candleCount = 0;
	}

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

		var ema = new ExponentialMovingAverage { Length = MaPeriod };

		SubscribeCandles(CandleType).Bind(ema, ProcessCandle).Start();
	}

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

		_candleCount++;

		if (_candleCount < 4)
		{
			ShiftCandles(candle);
			return;
		}

		// Bullish patterns using stored values
		var threeWhiteSoldiers = _prevOpen3 < _prevClose3 && _prevOpen2 < _prevClose2 && _prevOpen1 < _prevClose1 &&
			_prevClose3 < _prevClose2 && _prevClose2 < _prevClose1;

		var threeInsideUp = _prevOpen3 > _prevClose3 &&
			Math.Abs(_prevClose2 - _prevOpen2) <= 0.6m * Math.Abs(_prevOpen3 - _prevClose3) &&
			_prevClose2 > _prevOpen2 && _prevClose1 > _prevOpen1 && _prevClose1 > _prevOpen3;

		// Bearish patterns
		var threeBlackCrows = _prevOpen3 > _prevClose3 && _prevOpen2 > _prevClose2 && _prevOpen1 > _prevClose1 &&
			_prevClose3 > _prevClose2 && _prevClose2 > _prevClose1;

		var threeInsideDown = _prevOpen3 < _prevClose3 &&
			Math.Abs(_prevClose2 - _prevOpen2) <= 0.6m * Math.Abs(_prevOpen3 - _prevClose3) &&
			_prevClose2 < _prevOpen2 && _prevClose1 < _prevOpen1 && _prevClose1 < _prevOpen3;

		var bullSignal = threeWhiteSoldiers || threeInsideUp;
		var bearSignal = threeBlackCrows || threeInsideDown;

		if (bullSignal && candle.ClosePrice > ma && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		else if (bearSignal && candle.ClosePrice < ma && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		ShiftCandles(candle);
	}

	private void ShiftCandles(ICandleMessage candle)
	{
		_prevOpen3 = _prevOpen2; _prevClose3 = _prevClose2; _prevLow3 = _prevLow2;
		_prevOpen2 = _prevOpen1; _prevClose2 = _prevClose1; _prevLow2 = _prevLow1;
		_prevOpen1 = candle.OpenPrice; _prevClose1 = candle.ClosePrice; _prevLow1 = candle.LowPrice;
	}
}