Стратегия Lucky Jump — это краткосрочная система возврата к среднему, реагирующая на резкие ценовые скачки по лучшим котировкам Bid и Ask. Когда Ask подскакивает вверх на заданное количество пунктов по сравнению с предыдущей котировкой, стратегия открывает короткую позицию в ожидании отката. Когда Bid падает на ту же величину, открывается длинная позиция. Позиции закрываются либо при первом благоприятном тике, либо при превышении заранее установленного лимита убытков.
Подход нацелен на захват быстрых коррекций после резких движений рынка и использует только данные Level1 без свечей и индикаторов.
Детали
Условия входа:
Продажа: Ask(t) - Ask(t-1) >= Shift * PriceStep.
Покупка: Bid(t-1) - Bid(t) >= Shift * PriceStep.
Условия выхода:
Закрыть позицию при появлении любой прибыли.
Закрыть позицию, если убыток превышает Limit * PriceStep.
Стопы: стоп реализован через параметр Limit.
Значения по умолчанию:
Shift = 30 пунктов.
Limit = 180 пунктов.
Volume = 1.
Фильтры:
Категория: Возврат к среднему
Направление: Оба
Индикаторы: Нет
Стопы: Да
Сложность: Простая
Таймфрейм: Очень краткосрочный
Сезонность: Нет
Нейросети: Нет
Дивергенция: Нет
Уровень риска: Высокий
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;
}
}