Table of Contents

Creating an Indicator

Creating your own indicator in API is described in the section Custom Indicator. Such indicators are fully compatible with Designer.

To create an indicator, on the Scheme panel you need to select the Indicators folder, right-click and in the context menu select Add:

Designer_Source_Code_Indicator_00

The indicator code will look like this:

/// <summary>
/// Sample indicator demonstrating how to save and load parameters.
/// Changes the input price by +20% or -20%.
///
/// See more examples:
/// https://github.com/StockSharp/StockSharp/tree/master/Algo/Indicators
///
/// Documentation:
/// https://doc.stocksharp.com/topics/designer/strategies/using_code/fsharp/create_own_indicator.html
/// </summary>
type EmptyIndicator() as this =
    inherit BaseIndicator()

    // Internal fields
    let mutable changeValue = 20
    let mutable counter = 0
    let mutable isFormedValue = false

    /// <summary>
    /// The percentage value (+/-) used to modify the input price.
    /// </summary>
    member this.Change
        with get () = changeValue
        and set value =
            changeValue <- value
            this.Reset()

    /// <summary>
    /// Defines if the indicator has formed (became ready for trading).
    /// </summary>
    override this.CalcIsFormed() = isFormedValue

    /// <summary>
    /// Resets the indicator to its initial state.
    /// </summary>
    override this.Reset() =
        base.Reset()
        isFormedValue <- false
        counter <- 0

    /// <summary>
    /// The main logic to process input values.
    /// </summary>
    override this.OnProcess(input: IIndicatorValue) : IIndicatorValue =
        // every 10th call try to return an "empty" value
        if RandomGen.GetInt(0, 10) = 0 then
            // empty value still contains just time, no actual data
            DecimalIndicatorValue(this, input.Time)
        else
            // increment counter on each call
            counter <- counter + 1

            // after 5 inputs, indicator is considered formed
            if counter = 5 then
                isFormedValue <- true

            let mutable value = input.ToDecimal()

            // random change by a factor of +/- Change%
            let randomFactor = decimal (RandomGen.GetInt(-changeValue, changeValue)) / 100m
            value <- value + (value * randomFactor)

            // return final indicator value
            let result = DecimalIndicatorValue(this, value, input.Time)
            // randomly mark it as final or not
            result.IsFinal <- RandomGen.GetBool()
            result

    /// <summary>
    /// Load indicator settings from a given <see cref="SettingsStorage"/>.
    /// </summary>
    override this.Load(storage: SettingsStorage) =
        base.Load(storage)
        this.Change <- storage.GetValue<int>(nameof(this.Change))

    /// <summary>
    /// Save indicator settings to a given <see cref="SettingsStorage"/>.
    /// </summary>
    override this.Save(storage: SettingsStorage) =
        base.Save(storage)
        storage.SetValue(nameof(this.Change), this.Change)

    /// <summary>
    /// A string representation that includes the current <see cref="Change"/> value.
    /// </summary>
    override this.ToString() =
        sprintf "Change: %d" this.Change

This indicator receives an incoming value and makes an arbitrary deviation on the set parameter Change value.

The description of the indicator methods is available in the section Custom Indicator.

To add the created indicator to the diagram, you need to use the Indicator cube, and in it, specify the necessary indicator:

Designer_Source_Code_Indicator_01

The Change parameter, previously set in the indicator code, is shown in the properties panel.

Warning

Indicators from F# code cannot be used in strategies created in F# code. They can only be used in strategies created from cubes.