Strategy designed for high-volatility news releases. It places symmetric stop orders on both sides of the current price to catch breakouts. Once one order triggers, the opposite pending order is cancelled and a trailing stop protects the open position.
Details
Entry Criteria: wait for spread below SpreadOperation, then place buy stop at Ask + PipsAway points and sell stop at Bid - PipsAway points
Long/Short: Both
Exit Criteria: protective stop loss or take profit, or trailing stop when price retraces by TrailingStop points
Stops: Initial stop loss and take profit via StartProtection; custom trailing stop in code
Default Values:
StopLoss = 100
TakeProfit = 300
TrailingStop = 50
PipsAway = 50
BalanceUsed = 0.01
SpreadOperation = 25
Leverage = 400
Filters:
Category: Breakout
Direction: Both
Indicators: None
Stops: Yes
Complexity: Basic
Timeframe: Level1 / Tick
Seasonality: No
Neural networks: No
Divergence: No
Risk level: High
How It Works
Subscribe to Level1 quotes to access current bid and ask prices.
When spread is small enough, calculate volume using portfolio value, leverage and BalanceUsed.
Place pending buy and sell stop orders at offsets defined by PipsAway.
When a position opens, cancel the opposite pending order.
Attach stop loss and take profit orders based on StopLoss and TakeProfit.
Track highest/lowest price since entry and exit if price retraces more than TrailingStop points.
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>
/// EMA crossover strategy.
/// </summary>
public class StraddleNewsStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public StraddleNewsStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 26)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "Indicators");
_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();
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
SubscribeCandles(CandleType)
.Bind(fast, slow, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal)
{
if (candle.State != CandleStates.Finished) return;
if (!_hasPrev)
{
_prevFast = fastVal;
_prevSlow = slowVal;
_hasPrev = true;
return;
}
var crossUp = _prevFast <= _prevSlow && fastVal > slowVal;
var crossDown = _prevFast >= _prevSlow && fastVal < slowVal;
if (crossUp && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (crossDown && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevFast = fastVal;
_prevSlow = slowVal;
}
}