# Tutorial: Moving Average

In this tutorial, we will look at an example implementation of the `MovingAverage` indicator.

To get acquainted with the implementation example, download the archive with the indicator example and open it in IDE of your choice, we suggest you use Cursor IDE.

{% hint style="info" %}
For more details on how to open it in Cursor IDE, you can refer to this [section](/fto-indicators-docs/setup-and-installation.md).
{% endhint %}

You can download the archive of Moving Average from here

## Indicator structure

A custom indicator is built by extending the `IndicatorImplementation` class, provided by the `forex-tester-custom-indicator-api` library.\
You can find this implementation in the source code of the **Moving Average** example described in the [**Setup and Installation**](/fto-indicators-docs/setup-and-installation.md) section.

```typescript
import { IndicatorImplementation } from "forex-tester-custom-indicator-api";

export default class MovingAverage extends IndicatorImplementation {
  // indicator logic
}
```

## Indicator parameters

These parameters can be of different types, they are determined by the [TOptValue](/fto-indicators-docs/indicators/indicator-structure/toptvalue.md) class, and they will be displayed in the indicator addition/editing window

```typescript
export default class MovingAverage extends IndicatorImplementation {
    // Declaring class-level fields
    public Period!: TOptValue_number;
    public Shift!: TOptValue_number;
    public MAtype!: TOptValue_number;
    public ApplyToPrice!: TOptValue_number;
    public VShift!: TOptValue_number;

    Init(): void {
        // Create parameters using factory method
        this.Period = this.api.createTOptValue_number(8);
        this.Shift = this.api.createTOptValue_number(0);
        this.MAtype = this.api.createTOptValue_number(E_MAType.SMA);
        this.ApplyToPrice = this.api.createTOptValue_number(TPriceType.CLOSE);
        this.VShift = this.api.createTOptValue_number(0);
    ...existing code...
    }
```

<figure><img src="/files/d4QaKa0YLnMYSrtjRRPC" alt=""><figcaption></figcaption></figure>

\
For this, they need to be registered in the [Init](/fto-indicators-docs/indicators/indicator-structure/init.md) function.

```typescript

public Init(): void {
  ...existing code...
  // Register parameter this.Period so it's shown in the indicator settings
  this.api.RegOption(
    'Period',
    TOptionType.INTEGER,
    this.Period
  );
  // Setting the maximum avalable range that can be used for Period value
  this.api.SetOptionRange(
    'Period',
    1,
    Number.MAX_SAFE_INTEGER
  );
  // Register parameter this.Shift so it's shown in the indicator settings
  this.api.RegOption(
    'Shift',
    TOptionType.INTEGER,
    this.Shift
  );
  // Register parameter this.VShift so it's its shown in the indicator settings
  this.api.RegOption(
    'VShift',
    TOptionType.INTEGER,
    this.VShift
  );
  // Register the MA type so it has a drowdown in the indicator settings
  this.api.RegMATypeOption(
    this.MAtype,
    'MAtype'
  );
  // Register the price type so it has a dropdown in the indicator settings.
  this.api.RegApplyToPriceOption(
    this.ApplyToPrice,
    'ApplyToPrice'
  );
...existing code...
}
```

You can see the methods for registering parameters in the [external parameters definition](/fto-indicators-docs/external_parameters_definition.md)

## Buffers setup

[Buffers](/fto-indicators-docs/visible-buffers.md) are used to store and display indicator values on the chart.

```typescript
public SSMA!: TIndexBuffer
private SMA!: TIndexBuffer
```

They need to be declared with all class fields and initialized in the [Init](/fto-indicators-docs/indicators/indicator-structure/init.md) function

```typescript
this.SMA = this.api.CreateIndexBuffer();
this.SSMA = this.api.CreateIndexBuffer();
```

After their creation, you need to tell how many buffers will be displayed on the chart and bind them by index, starting from 0 (the indices must be unique)\
In this case, there is one buffer

```typescript
this.api.IndicatorBuffers(1);
this.api.SetIndexBuffer(0, this.SSMA);
```

Each registered buffer can be [configured](/fto-indicators-docs/configure_indicator.md)

```typescript
this.api.SetIndexLabel(0, "MA");
this.api.SetIndexStyle(0, TDrawStyle.LINE, TPenStyle.SOLID, 1, "#FF0000");
this.api.SetIndexDrawBegin(0, this.Period.value - 1 + this.Shift.value);
```

## Other settings

Also, other methods for configuring the indicator are used in the [Init](/fto-indicators-docs/indicators/indicator-structure/init.md) function.\
To ensure the indicator recalculates on each tick, use the function [RecalculateMeAlways](/fto-indicators-docs/configure_indicator/recalculate-me-always.md).\
If this setting is not used, each buffer index will be calculated only once to save resources,\
but some indicators may be calculated inaccurately. If the calculations do not heavily load the processor, we recommend always using it.

Set the indicator name, which will be displayed in the indicator settings window and in the context menu: [IndicatorShortName](/fto-indicators-docs/configure_indicator/indicator-short-name.md).

We want the Moving Average indicator to be displayed on the main chart, so we use [SetOutputWindow](/fto-indicators-docs/configure_indicator/set-output-window.md).

Using this call, specify that values equal to 0 will not be drawn on the chart: [SetEmptyValue](/fto-indicators-docs/configure_indicator/set-empty-value.md).

## Indicator's main function

The main function of the indicator is the [Calculate](/fto-indicators-docs/indicators/indicator-structure/calculate.md) function, where the indicator values are calculated on each tick.

```typescript
public Calculate(index: number): void {
    // check if the index is in the valid range
    if (index + this.Period.value >= this.api.Bars()) {
        return
    }

    // calculate the SMA value
    const calculatedSMA = this.api.GetMA(
        index,
        0,
        this.Period.value,
        this.MAtype.value,
        this.ApplyToPrice.value,
        // here we get the value of the previous bar
        this.SMA.getValue(index + 1)
    )

    this.SMA.setValue(index, calculatedSMA)
    // set the value which is going to be displayed on the chart
    this.SSMA.setValue(index, calculatedSMA + this.VShift.value * this.api.Point())
}
```

## Changing parameters

To add custom logic after changing the indicator parameters, we use the [OnParamsChange](https://gitlab.com/fto-docs/strategies/-/blob/indicators/Quick%20guide/broken-reference/README.md) method.\
In Moving average, it is applied to the horizontal shift of the indicator.\
This method is often used to work with custom objects or to shift the indicator.

```typescript
public OnParamsChange(): void {
    this.api.SetBufferShift(0, this.Shift.value)
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://fto-2.gitbook.io/fto-indicators-docs/tutorial-moving-average.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
