Открыть на GitHub

Стратегия Bronze Pan

Порт MetaTrader 4 советника «Bronzew_pan» на платформу StockSharp. Работает по одной бумаге, анализируя только завершённые свечи, и комбинирует осциллятор DayImpuls с индикаторами Williams %R и CCI для поиска импульсных разворотов.

Логика работы

  1. Подписывается на выбранный таймфрейм и рассчитывает DayImpuls, Williams %R и CCI с одинаковым периодом.
  2. Ведёт раздельный учёт длинных и коротких корзин, эмулируя хеджевый режим оригинального советника.
  3. Закрывает все позиции, когда плавающая прибыль достигает ProfitTarget либо падает ниже LossTarget.
  4. Открывает шорт, если DayImpuls выше DayImpulsShortLevel и снижается, Williams %R выше WilliamsLevelUp, а CCI превышает CciLevel.
  5. Открывает лонг, если DayImpuls ниже DayImpulsLongLevel и растёт, Williams %R ниже WilliamsLevelDown, а CCI меньше -CciLevel.
  6. При выходе плавающего PnL за пределы коридора PredBand отправляет крупный усредняющий ордер, умножая базовый объём на LotMultiplier, что повторяет аварийный разворот из MetaTrader.
  7. Контролирует отдельные стоп-лоссы и тейк-профиты для лонгов и шортов, переводя указанные в пунктах расстояния в цену.
  8. Новые сделки не открываются, если баланс ниже MinimumBalance или уже активны обе корзины одновременно.

Параметры

Название Описание Значение по умолчанию
TradeVolume Базовый объём входа. 0.1
LongStopLossPips Стоп-лосс для длинной корзины в пунктах. 0
ShortStopLossPips Стоп-лосс для короткой корзины в пунктах. 0
LongTakeProfitPips Тейк-профит для длинной корзины в пунктах. 0
ShortTakeProfitPips Тейк-профит для короткой корзины в пунктах. 0
IndicatorPeriod Период для DayImpuls, Williams %R и CCI. 14
CciLevel Абсолютный порог CCI для подтверждения экстремума. 150
WilliamsLevelUp Уровень Williams %R для входа в шорт. -15
WilliamsLevelDown Уровень Williams %R для входа в лонг. -85
DayImpulsShortLevel Порог DayImpuls для подтверждения шорта. 50
DayImpulsLongLevel Порог DayImpuls для подтверждения лонга. -50
ProfitTarget Плавающая прибыль, при которой всё закрывается. 500
LossTarget Плавающий убыток, при котором всё закрывается. -2000
PredBand Коридор прибыли для аварийного усреднения. 100
LotMultiplier Множитель объёма при усреднении. 30
MinimumBalance Минимальный баланс счёта для работы. 3000
CandleType Таймфрейм свечей. 15m

Дополнительно

  • DayImpuls реализован как двойное EMA-сглаживание тела свечи, переведённого в пункты, полностью повторяя оригинал.
  • Нулевые значения стопов и тейков отключают соответствующую защиту.
  • Стратегия обрабатывает только свечи со статусом Finished.
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Bronze Pan strategy - CCI with momentum confirmation.
/// Buys when CCI crosses above positive level and momentum is positive.
/// Sells when CCI crosses below negative level and momentum is negative.
/// </summary>
public class BronzePanStrategy : Strategy
{
	private readonly StrategyParam<int> _cciPeriod;
	private readonly StrategyParam<decimal> _cciLevel;
	private readonly StrategyParam<int> _momentumPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevCci;
	private bool _hasPrev;

	public int CciPeriod { get => _cciPeriod.Value; set => _cciPeriod.Value = value; }
	public decimal CciLevel { get => _cciLevel.Value; set => _cciLevel.Value = value; }
	public int MomentumPeriod { get => _momentumPeriod.Value; set => _momentumPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public BronzePanStrategy()
	{
		_cciPeriod = Param(nameof(CciPeriod), 14)
			.SetDisplay("CCI Period", "CCI lookback", "Indicators");

		_cciLevel = Param(nameof(CciLevel), 100m)
			.SetDisplay("CCI Level", "CCI threshold level", "Levels");

		_momentumPeriod = Param(nameof(MomentumPeriod), 14)
			.SetDisplay("Momentum Period", "Momentum lookback", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
	protected override void OnReseted() { base.OnReseted(); _prevCci = 0m; _hasPrev = false; }

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

		_hasPrev = false;

		var cci = new CommodityChannelIndex { Length = CciPeriod };
		var mom = new Momentum { Length = MomentumPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(cci, mom, ProcessCandle)
			.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal cci, decimal mom)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!_hasPrev)
		{
			_prevCci = cci;
			_hasPrev = true;
			return;
		}

		if (_prevCci <= CciLevel && cci > CciLevel && mom > 0 && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		else if (_prevCci >= -CciLevel && cci < -CciLevel && mom < 0 && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevCci = cci;
	}
}