πTutorial: Moving Average
Learn how to create and run a simple Moving Average indicator in FTO β perfect for getting started with custom indicators.
Ready to create your first custom indicator? Letβs start with a classic: the Moving Average.
In this tutorial, weβll walk step by step through building, coding, and running this popular indicator in FTO.
Donβt worry β even if youβre new to indicators, this oneβs a great warm-up. By the end, youβll have a working Moving Average ready to test and tweak on your charts.
To see how things work in practice, start by downloading the archive with the indicator example.
Once itβs on your computer, open it in any IDE you like β but we highly recommend Cursor IDE for the smoothest experience.
You can download the archive of Moving Average from here
How Custom Indicators Are Built
Every custom indicator in FTO starts with a simple but powerful idea: extend the IndicatorImplementation
class from the forex-tester-custom-indicator-api
library.
This class gives you all the building blocks you need β methods, structures, and tools β so you can focus on your logic instead of reinventing the wheel.
You can see a working version of this in action in the Moving Average example, which we described earlier in the Setup and Installation section. Itβs a great place to peek at the code and understand how everything fits together.
import { IndicatorImplementation } from "forex-tester-custom-indicator-api";
export default class MovingAverage extends IndicatorImplementation {
// indicator logic
}
Indicator Parameters
Every custom indicator can have its own set of adjustable parameters β things like periods, colors, or calculation methods.
These parameters are defined using the TOptValue class, which handles different types (numbers, booleans, lists, etc.) and makes them easy to edit.
When you add or edit your indicator in FTO, these parameters will appear in a user-friendly window where you (or your users) can tweak the settings to get just the right behavior.
Think of it as the dashboard for your indicator β all the knobs and switches in one place.
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...
}

For this, they need to be registered in the Init function.
Registering Parameters
Defining parameters is only half the story β to actually use them in your indicator, they need to be registered inside the Init function. This is where you βintroduceβ your parameters to FTO so theyβll show up in the indicator settings window.
Without registration, your parameters will just sit quietly in the code, never making it to the user interface.
Think of Init as the guest list at a party β if you donβt put your parameter on the list, it wonβt get through the door.
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
Where to Find Registration Methods
All the methods youβll need to register your parameters live in the external parameters definition section of the API.
Thatβs the place where FTO tells you: βHereβs how to make your parameters visible in the UI and ready for users to tweak.β
So whenever youβre setting up parameters in the Init function, just look back at those definitions β theyβre your cheat sheet for getting everything hooked up the right way.
Tip: Without registration, parameters stay hidden in the code. With registration, they become clickable, adjustable settings in the indicator window.
Buffers setup
Buffers are the backstage crew of your indicator.
Theyβre used to store all those calculated values and then display them as lines, histograms, or other visuals right on your chart.
Think of them as the buckets where your indicator keeps its data before painting it onto the screen.
No buffers = no output. With buffers, your calculations finally become visible magic on the chart.
public SSMA!: TIndexBuffer
private SMA!: TIndexBuffer
Buffers need to be both declared as class fields and initialized inside the Init function.
this.SMA = this.api.CreateIndexBuffer();
this.SSMA = this.api.CreateIndexBuffer();
Connecting Buffers to the Chart
Creating buffers is just the start β now you need to tell FTO how many buffers will actually show up on the chart, and then bind each one by its index (starting from 0).
Each index must be unique, like seat numbers in a cinema.
In this example, we only need one buffer, so the setup looks like this:
this.api.IndicatorBuffers(1);
this.api.SetIndexBuffer(0, this.SSMA);
IndicatorBuffers(1) β tells FTO, βIβve got one buffer to draw.β
SetIndexBuffer(0, this.SSMA) β assigns our buffer SSMA to slot #0 on the chart.
Tip: If you ever add more buffers later (say, for multiple lines), just increase the number in IndicatorBuffers() and assign each one to its own index.
Configuring Buffers
Each registered buffer isnβt just a data bucket β you can also configure how itβs displayed on the chart.
For example:
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);
SetIndexLabel(0, "MA") β gives your buffer a friendly name (βMAβ) so it shows up in the legend.
SetIndexStyle(...) β sets how it looks: here itβs a solid red line with thickness 1.
SetIndexDrawBegin(...) β defines the point on the chart where drawing should start (usually after enough data has been collected).
Tip: Donβt be afraid to play with colors, line styles, and labels. Itβs your indicator β make it not only useful but also easy to read at a glance.
Other settings
Always Recalculate (or Not?)
Inside the Init function, you can use a handy setting called RecalculateMeAlways. By default, FTO calculates each buffer index only once to save resources. Thatβs efficient, but sometimes it means your indicator wonβt be as accurate as youβd like.
If your calculations arenβt too heavy for the processor, we recommend always enabling this option. It ensures your indicator updates on every tick, keeping results fresh and reliable.
Tip: Think of it as βlive modeβ for your indicator β better accuracy in exchange for a tiny bit more CPU work.
Give Your Indicator a Name
Every indicator deserves an identity. With IndicatorShortName., you set the name that will show up in the indicator settings window and the context menu.
Think of it as the little nametag your indicator wears β something short, clear, and easy to recognize when youβre scrolling through the list.
Tip: Keep it simple (like βMoving Averageβ or βOBVβ) so you instantly know what it is at a glance.
Choose Where to Draw
By default, some indicators want to open their own little subwindow under the main chart. But for a Moving Average, it makes much more sense to see it directly on the main chart, hugging the price candles where it belongs.
Thatβs where SetOutputWindow comes in β it tells FTO exactly where to draw your indicator. In this case, we point it to the main chart so the Moving Average is right there in the action.
Tip: If youβre building other indicators (like oscillators), you can send them to their own window instead. For Moving Average, keep it on the main chart for the clearest view.
Skip the Zeroes
Sometimes indicators calculate values that are just 0 β and honestly, those donβt tell us much. With SetEmptyValue, you can tell FTO not to draw these points at all.
That way, the chart stays clean, without random flat lines cluttering your view.
Tip: Think of it like editing out background noise from a song β you only keep the meaningful parts, so the final output looks and sounds better.
Indicator's main function
At the heart of every custom indicator is the Calculate function. This is where the real action happens β all the math, logic, and updates take place here on each tick.
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
Sometimes you want your indicator to react when the user changes its settings β thatβs where the OnParamsChange method comes in.
This method lets you add custom logic that runs right after parameters are updated. For example, in the Moving Average indicator itβs used to handle the horizontal shift, so the line moves correctly on the chart when the shift value changes.
OnParamsChange is especially handy if your indicator uses custom objects or needs to redraw elements whenever a parameter is tweaked.
Tip: Think of it as your indicatorβs βrefresh buttonβ β it makes sure the chart always reflects the latest settings the user has chosen.
public OnParamsChange(): void {
this.api.SetBufferShift(0, this.Shift.value)
}
Wrapping Up
And there you have it β youβve just built and understood your first custom indicator: the Moving Average.
From setting up parameters and buffers to configuring styles and handling recalculations, you now know the essential steps behind making an indicator come alive in FTO.
This is a solid foundation β once youβve mastered the Moving Average, youβre ready to experiment, tweak, and create even more powerful custom tools for your trading.
Last updated