using System; using System.Diagnostics; using System.Collections.Generic; using System.Linq; using System.Text; using StockSharp.Algo.Indicators; using StockSharp.Algo.Indicators.Trend; using StockSharp.Algo; using StockSharp.Algo.Logging; using StockSharp.Algo.Strategies; using StockSharp.BusinessEntities; using Ecng.Common; using Ecng.Collections; namespace ra81.Algo.Strategies { public class BasketProtectionStrategy : Strategy, IProtectionStrategy { private object _globalLock = new object(); /// /// Защищаемая сделка. /// public MyTrade ProtectedTrade { get; protected set; } /// /// Текущее состояние стратегии, активирована она лии нет. /// public bool IsActivated { get; protected set; } /// /// Стратегия которая активировалась первой среди защитных. /// public IProtectionStrategy FirstActivated { get; protected set; } /// /// Событие вызывается сразу же как только защитная стратегия активировалась /// и начала закрывать позицию. /// public event Action Activated; public BasketProtectionStrategy() { ProtectedTrade = null; IsActivated = false; EnableRulesLog = true; ChildStrategies.Adding += ChildStrategiesOnAdding; } /// /// Метод вызывается тогда, когда вызвался метод , и состояние перешло в значение . /// protected override void OnStarting() { if (ChildStrategies.Count == 0) throw new InvalidOperationException("Дочерние стратегии отсутствуют, невозможно запустить комплесную защитную стратегию."); base.OnStarting(); } protected override void OnStopping() { Debug.WriteLine("OnStopping: Число правил {0}".Put(Rules.Count)); this.AddInfoLog("Очищая список правил стратегии."); Rules.Clear(); this.AddInfoLog("Останавливаю все дочерние стратегии."); ChildStrategies.ToArray().ForEach(s => s.Stop()); base.OnStopping(); } /// /// Метод вызывается при добавлении дочерней стратегии. Проверяет параметры стратегии и вешается на событие . /// /// Добавляемая защитная стратегия. Должна соответствовать интерфейсу private void ChildStrategiesOnAdding(Strategy strategy) { // проверяем чтобы защитная стратегия была, а не какая-то другая. if (!(strategy is IProtectionStrategy)) throw new InvalidOperationException("Дочерней может быть только защитная стратегия реализующая IProtectionStrategy."); var protectionStrategy = strategy as IProtectionStrategy; // проверяем чтобы защитные стратегии были для одной сделки. Если защищаемая сделка еще не определена, берем из добавляемой стратегии. ProtectedTrade = ProtectedTrade ?? protectionStrategy.ProtectedTrade; if (ProtectedTrade != protectionStrategy.ProtectedTrade) throw new InvalidOperationException("Добавляемые защитные стратегии должны защищать одну и ту же сделку."); // как только активировалась защита одной из дочерних стратегий, сразу же активируем защиту комплексной стратегии. this .When(protectionStrategy.ProtectionActivated()) .Do(s => Activate(s) ); Debug.WriteLine("OnAdding: Число правил {0}".Put(Rules.Count)); } /// /// Активирует защиту сделки, то есть начинает процедуру защиты. /// Если защита уже активирована, то ничего не делает. Состояние защиты проверяется /// через свойство . В случае активации генерирует событие /// /// Стратегия которая активировалась и вызвала активацию комплексной защитной стратегии. protected virtual void Activate(IProtectionStrategy strategy) { // защита от двойного входа в состояние защиты. lock (_globalLock) { if (IsActivated) return; IsActivated = true; FirstActivated = strategy; } // после остановки стратегии завершим базовую стратегию тоже. var s = strategy as Strategy; //this // .When(s.Stopped()) // .Do(Stop); Debug.WriteLine("Activate: Число правил {0}".Put(Rules.Count)); this.AddInfoLog("Активировалась одна из дочерних стратегий защиты, завершаем остальные стратегии защиты."); RaiseActivatedEvent(); // очищаем все правила стратегии и останавливаем все дочерние кроме активной. Когда активная тоже остановится, защитная стратегия тоже остановится. //Rules.Clear(); StopNotActiveChilds(); } /// /// Останавливает все дочерние защитные стратегии для сделки, кроме той которая активировалась. /// private void StopNotActiveChilds() { var firstActivated = FirstActivated as Strategy; var stoppingStrategies = ChildStrategies.Where(s => s != firstActivated).ToArray(); Debug.WriteLine("Нужно остановить {0} дочерних".Put(stoppingStrategies.Count())); stoppingStrategies.ForEach(s => Stop()); } /// /// Сгенерировать событие об активации защиты. /// protected virtual void RaiseActivatedEvent() { Activated.SafeInvoke(); } protected override void DisposeManaged() { ChildStrategies.Adding -= ChildStrategiesOnAdding; base.DisposeManaged(); } } }