Для изменения размера нажмите или перетащите
Собственный индикатор

Для того, чтобы создать свой собственный индикатор, необходимо реализовать интерфейс IIndicator. В качестве примера можно взять исходные коды других индикаторов, которые находятся в репозитории GitHub/StockSharp. Вот как выглядит код реализации индикатора простой скользящей средней SimpleMovingAverage:

C#
/// <summary>
/// Простая скользящая средняя.
/// </summary>
[DisplayName("SMA")]
[Description("Простая скользящая средняя.")]
public class SimpleMovingAverage : LengthIndicator<decimal>
{
    /// <summary>
    /// Создать <see cref="SimpleMovingAverage"/>.
    /// </summary>
    public SimpleMovingAverage()
        : base(typeof(decimal))
    {
    }

    /// <summary>
    /// Обработать входное значение.
    /// </summary>
    /// <param name="input">Входное значение.</param>
    /// <returns>Результирующее значение.</returns>
    public override decimal OnProcess(IIndicatorValue input)
    {
        var lastValue = LastValue;
        var newValue = input.GetValue<decimal>();

        // добавляем новое начало
        lastValue += newValue / Length;

        // если буффер стал достаточно большим (стал больше длины)
        if (IsFormed)
        {
            // удаляем хвостовое значение
            lastValue -= Buffer[0] / Length;
            Buffer.RemoveAt(0);
        }

        Buffer.Add(newValue);
        return lastValue;
    }
}

SimpleMovingAverage наследуется от класса LengthIndicatorTResult, от которого необходимо наследовать все индикаторы, имеющие в качестве параметра длину периода.

Некоторые индикаторы являются составными, и используют в своих рассчетах другие индикаторы. Поэтому индикаторы можно переиспользовать друг из друга, как показано в качестве примера реализация индикатора волатильности Чайкина ChaikinVolatility:

C#
/// <summary>
/// Волатильность Чайкина.
/// </summary>
/// <remarks>
/// http://www2.wealth-lab.com/WL5Wiki/Volatility.ashx
/// http://www.incrediblecharts.com/indicators/chaikin_volatility.php
/// </remarks>
[DisplayName("Волатильность")]
[Description("Волатильность Чайкина.")]
public class ChaikinVolatility : BaseIndicator<IIndicatorValue>
{
    /// <summary>
    /// Создать <see cref="ChaikinVolatility"/>.
    /// </summary>
    public ChaikinVolatility()
    {
        Ema = new ExponentialMovingAverage();
        Roc = new RateOfChange();
    }

    /// <summary>
    /// Скользящая средняя.
    /// </summary>
    [ExpandableObject]
    [DisplayName("MA")]
    [Description("Скользящая средняя.")]
    [Category("Основное")]
    public ExponentialMovingAverage Ema { get; private set; }

    /// <summary>
    /// Скорость изменения.
    /// </summary>
    [ExpandableObject]
    [DisplayName("ROC")]
    [Description("Скорость изменения.")]
    [Category("Основное")]
    public RateOfChange Roc { get; private set; }

    /// <summary>
    /// Сформирован ли индикатор.
    /// </summary>
    public override bool IsFormed
    {
        get { return Roc.IsFormed; }
    }

    /// <summary>
    /// Обработать входное значение.
    /// </summary>
    /// <param name="input">Входное значение.</param>
    /// <returns>Результирующее значение.</returns>
    public override IIndicatorValue OnProcess(IIndicatorValue input)
    {
        var candle = input.GetValue<Candle>();
        return Roc.Process(Ema.Process(input.SetValue(candle.HighPrice - candle.LowPrice)));
    }
}

Последний вид индикаторов - это те, которые не просто состоят из других индикаторов, но так же графически отображаются несколькими состояниями одновременно (несколькими линиями). Например, AverageDirectionalIndex:

C#
/// <summary>
/// Индекс среднего направления движения Welles Wilder.
/// </summary>
[DisplayName("ADX")]
[Description("Индекс среднего направления движения Welles Wilder.")]
public class AverageDirectionalIndex : BaseComplexIndicator
{
    /// <summary>
    /// Создать <see cref="AverageDirectionalIndex"/>.
    /// </summary>
    public AverageDirectionalIndex()
        : this(new DirectionalIndex { Length = 14 }, new WilderMovingAverage { Length = 14 })
    {
    }

    /// <summary>
    /// Создать <see cref="AverageDirectionalIndex"/>.
    /// </summary>
    /// <param name="dx">Индекса направленного движения Welles Wilder.</param>
    /// <param name="movingAverage">Скользящая средняя.</param>
    public AverageDirectionalIndex(DirectionalIndex dx, LengthIndicator<decimal> movingAverage)
    {
        if (dx == null)
            throw new ArgumentNullException("dx");

        if (movingAverage == null)
            throw new ArgumentNullException("movingAverage");

        InnerIndicators.Add(Dx = dx);
        InnerIndicators.Add(MovingAverage = movingAverage);
        Mode = ComplexIndicatorModes.Sequence;
    }

    /// <summary>
    /// Индекса направленного движения Welles Wilder.
    /// </summary>
    [Browsable(false)]
    public DirectionalIndex Dx { get; private set; }

    /// <summary>
    /// Скользящая средняя.
    /// </summary>
    [Browsable(false)]
    public LengthIndicator<decimal> MovingAverage { get; private set; }

    /// <summary>
    /// Длина периода.
    /// </summary>
    [DisplayName("Период")]
    [Description("Период индикатора.")]
    [Category("Основные")]
    public virtual int Length
    {
        get { return MovingAverage.Length; }
        set
        {
            MovingAverage.Length = Dx.Length = value;
            Reset();
        }
    }
}

Такие индикаторы должны наследоваться от класса BaseComplexIndicator, и передавать в BaseComplexIndicatorInnerIndicators составные части индикатора. BaseComplexIndicator будет обрабатывать данные части один за другим. Если BaseComplexIndicatorMode установлено в ComplexIndicatorModesSequence, то результирующее значение первого индикатора будет передано в качестве входного значения второму, и так далее до конца. Если же установлено значение ComplexIndicatorModesParallel, то результаты вложенных индикаторов игнорируются.