Ver no GitHub

Hardcore FX Breakout

Adaptation of the MetaTrader "HardcoreFX" expert. The strategy tracks ZigZag pivot highs and lows and opens positions when price breaks beyond them. It applies fixed stop loss and take profit levels and also trails the position to protect accrued gains.

Details

  • Entry Criteria: Close above last ZigZag high to go long; close below last ZigZag low to go short.
  • Long/Short: Both directions.
  • Exit Criteria: Stop loss, take profit or trailing stop hit.
  • Stops: Fixed stop loss, take profit and trailing stop.
  • Default Values:
    • ZigzagLength = 17
    • StopLoss = 1400
    • TakeProfit = 5400
    • TrailingStop = 500
    • CandleType = TimeSpan.FromMinutes(1)
  • Filters:
    • Category: Breakout
    • Direction: Both
    • Indicators: Highest, Lowest
    • Stops: Stop loss, Take profit, Trailing stop
    • Complexity: Intermediate
    • Timeframe: Intraday
    • Seasonality: No
    • Neural Networks: No
    • Divergence: No
    • Risk Level: Medium
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>
/// Channel breakout strategy using Highest/Lowest.
/// </summary>
public class HardcoreFxStrategy : Strategy
{
	private readonly StrategyParam<int> _channelPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevHigh;
	private decimal _prevLow;
	private bool _hasPrev;

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

	public HardcoreFxStrategy()
	{
		_channelPeriod = Param(nameof(ChannelPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("Channel Period", "Highest/Lowest lookback", "Parameters");
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle type", "General");
	}

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

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevHigh = 0;
		_prevLow = 0;
		_hasPrev = false;
	}

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

		var highest = new Highest { Length = ChannelPeriod };
		var lowest = new Lowest { Length = ChannelPeriod };

		SubscribeCandles(CandleType)
			.Bind(highest, lowest, ProcessCandle)
			.Start();
	}

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

		if (!_hasPrev)
		{
			_prevHigh = highVal;
			_prevLow = lowVal;
			_hasPrev = true;
			return;
		}

		// Buy when close breaks above previous channel high
		if (candle.ClosePrice > _prevHigh && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		// Sell when close breaks below previous channel low
		else if (candle.ClosePrice < _prevLow && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevHigh = highVal;
		_prevLow = lowVal;
	}
}