using System;
using System.Collections.Generic;
using System.ComponentModel;
using GanovCubes;
using TSLab.Script.Handlers;
using static GanovCubes.FileLogger;
namespace CubesLib
{
///
/// Тип сравнения показателей
///
public enum RaiseFall { Растет, Падает, НеМеняется };
///
/// Делегат для сравнения двух чисел типа Double
///
/// Число №1
/// Число №2
/// Результат сравнения
public delegate bool CompareMethod(double val1, double val2);
#region CubeDescription
[Obsolete]
[HandlerCategory("Ganov Cubes. Indicators")]
[HandlerName("FallRaiseSomeBars", Language = "ru-ru")]
[Description("Кубик выдает сигнал в случае если показатель растет/падает/равен эн-ное кол-во баров подряд. Обычно для выявления роста падения необходимо применять" +
" формулу с указанием, что показатель на текущем баре больше покателя на предыдущем баре, показатель на предыдущем баре больше показетеля два бара назад" +
" и так далее. Такие формулы усложняют скрипт и его восприятие, поэтому удобнее воспользоваться текущим кубиком. Кубик на вход может принимать как серию значений" +
" так и рассчитываемые на каждом баре данные. На выходе кубик выдает булево")]
[InputsCount(1)]
[Input(0, TemplateTypes.DOUBLE, Name = "Значение")]
[OutputsCount(1)]
[OutputType(TemplateTypes.BOOL)]
#endregion
public class FallRaiseSomeBars : IValuesHandlerWithNumber, IStreamHandler, IDoubleInput0, IBooleanReturns, IContextUses
{
#region Fields
private double[] _barsValues;
private bool[] _boolValues;
private CompareMethod _compare;
#endregion
#region Properties
public IContext Context { get; set; }
///
/// Баров для анализа
///
[HandlerParameter(true, "1", NotOptimized = false, Name = "Баров для анализа", IsVisibleInBlock = false)]
[Description("Данная настройка определяет количество баров от текущего назад, за которое будет анализироваться рост или падение (не включая текущий бар)" +
" показателя. В случае если указано отрицательное или нелевое значение, то будет использовано значение по умолчанию \"один\", то есть будет показан" +
" рост только с прошлого бара. В случае если указанное кол-во баров для анализа больше текущего кол-ва баров, то до момента достижения указанного " +
" бара кубик будет выдавать \"false\". Например, если указано 5 баров, то первое значение появится только по закрытию пятого бара, то этого момента" +
" кубик будет выдавать \"false\"")]
public int BarsToAnalize { get; set; }
///
/// Тип сравнения
///
[HandlerParameter(true, "Растет", NotOptimized = true, Name = "Тип сравнения", IsVisibleInBlock = false)]
[Description("Данная настройка задает тип справнения показателей: Растет, Падает, НеМеняется")]
public RaiseFall СompareType { get; set; }
#endregion
public bool Execute(double value, int bar)
{
if (bar == 0)
{
if (BarsToAnalize <= 0) BarsToAnalize = 1;
_barsValues = Context.GetArray(Context.BarsCount);
_compare = СompareType switch { RaiseFall.Растет => CondRaise, RaiseFall.Падает => CondFall, _ => CondEquil };
}
var retValue = false;
_barsValues[bar] = value;
if (bar >= BarsToAnalize)
{
for (int i = 0; i < BarsToAnalize; i++)
{
var barNum = i + (bar - BarsToAnalize);
if (_compare(_barsValues[barNum], _barsValues[barNum + 1])) retValue = true;
else
{
retValue = false;
break;
}
}
}
return retValue;
}
public IList Execute(IList values)
{
_boolValues = Context.GetArray(Context.BarsCount);
if (_boolValues.Length == values.Count)
for (int i = 0; i < values.Count; i++)
_boolValues[i] = Execute(values[i], i);
return _boolValues;
}
///
/// Метод сравниваниет два входящих числа типа Double
///
/// Число №1
/// Число №2
/// Первое больше второго - True, наоборот - False
bool CondRaise(double val1, double val2) => val1 < val2;
///
/// Метод сравниваниет два входящих числа типа Double
///
/// Число №1
/// Число №2
/// Первое меньше второго - True, наоборот - False
bool CondFall(double val1, double val2) => val1 > val2;
///
/// Метод сравниваниет два входящих числа типа Double
///
/// Число №1
/// Число №2
/// Первое равно второму - True, наоборот - False
bool CondEquil(double val1, double val2) => val1.CompareDouble(val2);
}
}