using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using GanovCubes; using TSLab.Script; using TSLab.Script.Handlers; namespace CubesLib { public enum Period { Год, Месяц, День }; #region CubeDescription [Obsolete] [HandlerCategory("Ganov Cubes. StatData")] [HandlerName("CloseEveryPeriod", Language = "ru-ru")] [Description("Кубик определяет финальные даты каждого периода: месяц, год, день и дает сигнал на выход на предпоследнем баре каждого периода, " + "то есть фактически выход будет осуществлен на следующем последнем баре. По умолчанию настройка установлена на 1, то есть сигнал на выход " + "появится на предпоследнем баре. В случае если есть опасения, что система может не выйти на последнем баре, можно сместить настройку на нужное кол-во " + "баров назад, но не более 3х. Если кол-во баров сессии меньше, чем установленное значение баров, то сигнал выхода выдается на первом баре соответствующей сессии")] [InputsCount(1)] [Input(0, TemplateTypes.SECURITY, Name = "Sec")] [OutputsCount(1)] [OutputType(TemplateTypes.BOOL)] #endregion // IStreamHandler - при наследовании IStreamHandler система не даст запустить скрипт, если на все входы не поданы значения public class CloseEveryPeriod : IContextUses, IStreamHandler, ISecurityInput0, IBar2BoolsHandler, IBooleanReturns { public IContext Context { set; get; } public static Stopwatch sw = new Stopwatch(); [HandlerParameter(true, "1", NotOptimized = true, Name = "Баров назад", IsVisibleInBlock = true)] [Description("Баров назад")] public int BarsBeforeLast { get; set; } [HandlerParameter(true, "Год", NotOptimized = true, Name = "Период выхода", IsVisibleInBlock = true)] [Description("Период выхода из позиции, на предпоследнем баре каждого периода кубик будет выдавать True на выход")] public Period ExitPeriod { get; set; } public IList Execute(ISecurity sec) { var lastBars = sec.Bars .GroupBy(bar => bar.Date.ToString(ExitPeriod switch { Period.День => "yyyyMMdd", Period.Месяц => "yyMM", _ => "yyyy" })) .Select(el => el.OrderByDescending(bar => bar.Date).First()) .OrderBy(bar => bar.Date) .ToArray(); var retValue = Context.GetArray(sec.Bars.Count); if (lastBars.Count() == 0 || sec.IsRealtime || Context.Runtime.IsAgentMode || Context.Runtime.IsRealTime) return retValue; var TFMinutes = sec.GetSecIntervalInMinutes(); if (BarsBeforeLast > 3) BarsBeforeLast = 3; if (sec.Bars.Count == 1) BarsBeforeLast = 0; var counter = 0; var barsCol = sec.Bars.ToList(); var lastBarsCount = lastBars.Count(); var lastSessionBarsNumCalculateBar = 0; for (int i = 0; i < sec.Bars.Count; i++) { if (counter < lastBarsCount && sec.Bars[i] == lastBars[counter]) { if (BarsBeforeLast != 0) { var curIntervalBars = i - lastSessionBarsNumCalculateBar; var barsToSkip = curIntervalBars - (int)(1440 / TFMinutes); var curSessionBarsNum = barsCol.Skip(barsToSkip).Take(curIntervalBars - barsToSkip).Where(bar => string.Equals($"{bar.Date:yyMMdd}", $"{sec.Bars[i].Date:yyMMdd}")).Count(); barsCol.RemoveRange(0, curIntervalBars); if (BarsBeforeLast > sec.Bars.Count || BarsBeforeLast > curSessionBarsNum) BarsBeforeLast = Math.Min(1, curSessionBarsNum > 1 ? 1 : 0); lastSessionBarsNumCalculateBar = i; } counter++; retValue[i - BarsBeforeLast] = true; } } return retValue; } } }