The Lucky Jump strategy is a short-term mean reversion system that reacts to sudden price jumps on the best bid and ask. When the ask price jumps upward by a specified number of points compared to the previous quote, the strategy opens a short position expecting a pullback. Conversely, when the bid price drops by the same amount, it enters long. Positions are closed either at the first favorable tick or when the loss exceeds a predefined limit.
This approach attempts to capture quick corrections after aggressive market moves. It operates purely on Level1 quote data and does not rely on candles or indicators.
Details
Entry Criteria:
Short: Ask(t) - Ask(t-1) >= Shift * PriceStep.
Long: Bid(t-1) - Bid(t) >= Shift * PriceStep.
Exit Criteria:
Close position as soon as it becomes profitable.
Close if loss exceeds Limit * PriceStep.
Stops: implicit stop based on Limit parameter.
Default Values:
Shift = 30 points.
Limit = 180 points.
Volume = 1.
Filters:
Category: Mean reversion
Direction: Both
Indicators: None
Stops: Yes
Complexity: Simple
Timeframe: Ultra short-term
Seasonality: No
Neural networks: No
Divergence: No
Risk level: High
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>
/// Price jump reversal strategy using EMA crossover.
/// </summary>
public class LuckyJumpStrategy : 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 LuckyJumpStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "Trading");
_slowPeriod = Param(nameof(SlowPeriod), 26)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "Trading");
_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;
}
}