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();
}
}
}