Открыть на GitHub

Стратегия Casino111

Обзор

Casino111 — это контртрендовая стратегия прорыва, перенесённая из одноимённого советника MetaTrader 4. На каждой новой свече алгоритм сравнивает текущую цену открытия с опорным диапазоном, построенным по предыдущей дневной свече. Если открытие выходит за пределы дневного диапазона (с учётом настраиваемых буферов), стратегия сразу открывает рыночную позицию в противоположном направлении и ставит симметричные стоп-лосс и тейк-профит. Порт на StockSharp сохраняет одно-позиционную модель оригинального робота и предоставляет расширенный набор параметров для тестирования и оптимизации.

Логика входа и выхода

  1. Максимум и минимум предыдущего дня считываются через отдельную подписку на дневные свечи. Смещения UpperOffsetPoints и LowerOffsetPoints (в пунктах MetaTrader) расширяют опорный коридор.
  2. После закрытия каждой торговой свечи стратегия анализирует открытия текущей и предыдущей свечей:
    • Если новое открытие перепрыгивает над дневным максимумом плюс верхний буфер, открывается короткая позиция (игра против гэпа).
    • Если новое открытие падает ниже дневного минимума минус нижний буфер, открывается длинная позиция.
  3. Одновременно допускается только одна позиция; пока предыдущий ордер не исполнен, новые сигналы игнорируются.
  4. StartProtection выставляет фиксированные стоп и тейк, отстоящие от входа на BetPoints (значение автоматически переводится в ценовые шаги).

Управление капиталом

  • При UseMoneyManagement = false размер сделки фиксируется значением BaseVolume.
  • При UseMoneyManagement = true включается мартингейл, повторяющий MT4-реализацию:
    • После каждой убыточной или нулевой сделки следующий объём умножается на (BetPoints * 2) / (BetPoints - spreadPoints).
    • Спред оценивается по последним лучшим котировкам (best bid/ask), полученным из стакана. Если котировки пока недоступны, множитель равен 2.
    • Прибыльные сделки возвращают объём к BaseVolume. Расчётные значения подгоняются под VolumeStep инструмента и ограничиваются параметром MaxVolume.

Параметры

Имя Тип Значение по умолчанию Описание
EnableBuy bool true Разрешить длинные позиции при пробое нижней границы дневного канала.
EnableSell bool true Разрешить короткие позиции при пробое верхней границы дневного канала.
BetPoints decimal 400 Симметричный стоп-лосс и тейк-профит в пунктах MetaTrader (преобразуются в шаги цены).
UpperOffsetPoints decimal 97 Буфер над дневным максимумом для выявления медвежьих гэпов.
LowerOffsetPoints decimal 77 Буфер под дневным минимумом для выявления бычьих гэпов.
UseMoneyManagement bool false Включить мартингейл-увеличение объёма.
MaxVolume decimal 4 Максимально допустимый объём при активном управлении капиталом.
BaseVolume decimal 0.1 Базовый размер сделки после прибыльной операции или при выключенном мартингейле.
CandleType DataType H1 Основной таймфрейм, на котором проверяются условия гэпа (по умолчанию 1 час).
DailyCandleType DataType D1 Таймфрейм, предоставляющий дневные экстремумы (по умолчанию 1 день).

Особенности реализации

  • Используется высокоуровневый API StockSharp: SubscribeCandles обеспечивает торговые и дневные свечи, SubscribeOrderBook — актуальный спред для расчёта мартингейла.
  • StartProtection управляет обоими плечами защиты, поэтому каждая сделка получает симметричный стоп и тейк сразу после открытия, как и в MT4.
  • Все комментарии в коде оставлены на английском языке и отмечают ключевые точки принятия решений.
  • Алгоритм не обращается к историческим значениям индикаторов — достаточно текущих значений открытия, что повторяет логику Time[0] / Open[0] в MetaTrader.

Рекомендации по использованию

  • Подбирайте торговый таймфрейм исходя из задачи исследования: по умолчанию используется часовой график, но можно указать любой поддерживаемый DataType.
  • При активном управлении капиталом убедитесь, что MaxVolume соответствует ограничениям брокера; вспомогательный метод приведёт объём к VolumeStep, MinVolume и MaxVolume инструмента.
  • Поскольку стратегия удерживает не более одной позиции, удобно отслеживать сделки на графике StockSharp с отметками входов и выходов.
  • Перед подключением к реальному рынку протестируйте стратегию в режиме воспроизведения или на демо: торговля на гэпах требует стабильного спреда и быстрой ликвидности.
using System;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Casino111: RSI overbought/oversold reversal with ATR stops.
/// </summary>
public class Casino111Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiLength;
	private readonly StrategyParam<int> _atrLength;
	private readonly StrategyParam<int> _emaLength;

	private decimal _prevRsi;
	private decimal _entryPrice;

	public Casino111Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");

		_rsiLength = Param(nameof(RsiLength), 14)
			.SetDisplay("RSI Length", "RSI period.", "Indicators");

		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period.", "Indicators");

		_emaLength = Param(nameof(EmaLength), 50)
			.SetDisplay("EMA Length", "Trend filter.", "Indicators");
	}

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

	public int RsiLength
	{
		get => _rsiLength.Value;
		set => _rsiLength.Value = value;
	}

	public int AtrLength
	{
		get => _atrLength.Value;
		set => _atrLength.Value = value;
	}

	public int EmaLength
	{
		get => _emaLength.Value;
		set => _emaLength.Value = value;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_prevRsi = 0;
		_entryPrice = 0;
	}

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

		_prevRsi = 0;
		_entryPrice = 0;

		var rsi = new RelativeStrengthIndex { Length = RsiLength };
		var atr = new AverageTrueRange { Length = AtrLength };
		var ema = new ExponentialMovingAverage { Length = EmaLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(rsi, atr, ema, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, ema);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal rsiVal, decimal atrVal, decimal emaVal)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (_prevRsi == 0 || atrVal <= 0)
		{
			_prevRsi = rsiVal;
			return;
		}

		var close = candle.ClosePrice;

		if (Position > 0)
		{
			if (close >= _entryPrice + atrVal * 2.5m || close <= _entryPrice - atrVal * 1.5m || rsiVal > 70)
			{
				SellMarket();
				_entryPrice = 0;
			}
		}
		else if (Position < 0)
		{
			if (close <= _entryPrice - atrVal * 2.5m || close >= _entryPrice + atrVal * 1.5m || rsiVal < 30)
			{
				BuyMarket();
				_entryPrice = 0;
			}
		}

		if (Position == 0)
		{
			if (rsiVal > 50 && _prevRsi <= 50 && close > emaVal)
			{
				_entryPrice = close;
				BuyMarket();
			}
			else if (rsiVal < 50 && _prevRsi >= 50 && close < emaVal)
			{
				_entryPrice = close;
				SellMarket();
			}
		}

		_prevRsi = rsiVal;
	}
}