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;
}
}