Creating an RVI Indicator

We write an indicator using the example of the relative vigor index.

This lesson is for beginners, however, it implies that the reader already has basic knowledge of the Java Script language and an understanding of the basic principles of object-oriented programming (OOP). Understanding the work of classes and inheritance is especially important for this lesson. You can read more about this here - developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes

In order to create an indicator for the Mobius Trader terminal, just enter the terminal, click on the `Indicators` button and select the` mCode Editor` menu item:

In the window that appears, click on the button `Create indicator`:

Enter the indicator name - `Relative_Vigor_Index`

And click on the `Add` button. After this action, the terminal will create an empty template file, with which we will work. If after this action you did not see the code editor, find your indicator in the upper left corner and click on it with the mouse. At this point, you should see a pattern like this:

The code in the template is from line number 2, where we see three keywords - `export`,` class` and `extends`.

The word `class` means that we are creating a new class called Main. The word `extends` means that our class will extend the already existing` Indicator` class, and that it will gain access to all parent functions. A class file in JavaScript is usually called a `module`. Without modules, the probability of collisions would be great for example, if two developers in the same program would declare a variable called `myVariable`, then only the one that was created last would be saved in the program memory. Thanks to the modules, this situation is eliminated, since the module is an isolated section of code.

And the last keyword in the second line is `export`. As said, a module is an isolated piece of code. Therefore, in order to use the module, we must first export its value. Another person will be able to use the module we wrote using the keywords `import` and` from`. You can familiarize yourself with the modular structure in JavaScript here -

developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export

developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import

Let's return to the development of the indicator.

The formula for calculating the indicator values is known, however, we do not need to try to reproduce it ourselves. The formula is already implemented, and we only need to call the corresponding function. All implemented formulas are inside the `Indicators` class. We are interested in the RVI function -

(mtrader7.com/ru/docs/Terminal/mScript/JavaScript/v1/Indicators/RVI)

We can call it as follows:

await Indicators.RVI(symbol, timeframe, period, priceType, mode)

As can be seen from the documentation of the RVI function, we must have 5 input parameters.

`symbol` and` timeframe` will be available "by default", since `symbol` is the current currency pair, and` timeframe` is the current selected time period. The `mode` parameter is optional, and we will not use it.

Thus, we only need to take care of the period and priceType parameters. We know that when creating an object (an instance of a class), the class constructor will be called. This function will be called only once, and it will be called earlier than anything else, because it is in this function that the initial “assembly” or birth of the object (in our case, the indicator) will occur.

Therefore, in the constructor of the class we will add the following lines of code:

this.addInput("ExtRVIPeriod", InputType.int, 10);

this.addInput("PriceType", InputType.PriceType, PriceType.Bid);

We could just write the values for the indicator in two fields this way:

this.ExtRVIPeriod = 10;

this.PriceType =  PriceType.Bid

But in this case, these parameters would be permanently sewn into the indicator. Using the function `this.addInput` we create two fields that can be changed during the work of our indicator. Let's check how it works - in the upper right corner, turn on the `Add to My Indicators` toggle switch and click on the` Save` button:

Now we return to the terminal, in the “Indicators” menu we look for the `Custom` item and there we select our indicator - Relative_Vigor_Index:

After that, we will see that the input parameters can already be controlled by the user:

Since the indicator is not ready, there is no point in adding it to the chart. Therefore, just click on the `Close` button and return to the code editor. Since we are making an oscillator, we must indicate that our indicator should not overlap the price chart, but should be displayed in a separate window. This can be done with the following line of code -

this.setProperty(Property.SeparateWindow, true);

Which we will add to the constructor of the class.

Since to display the data we need to store the results of the calculation of the `Indicators.RVI` function somewhere, we need to create two data stores -

this.buffers = {
    ExtRVIBuffer : this.addBuffer(),
    ExtRVISignalBuffer : this.addBuffer(),
};

Data storages are quite complex objects, you can read more about them here -mtrader7.com/ru/docs/Terminal/mScript/JavaScript/v1/Buffer

Attentive readers noticed that the constructor code already contains a data warehouse that was automatically created. We do not need it, and we will remove it.

On this, the constructor function code will be completed, and it should look something like this:

As mentioned earlier, a data warehouse, or buffer, is a complex object. These repositories will contain information that will be presented graphically in the terminal. For this storage you need to configure. This is done inside the onInit function, which will be called immediately after the indicator is placed on the price chart, and every time after the user changes the input parameters (or settings) of the indicator. The function will look like this:

Let us dwell on this step, save the indicator and return to the price chart. Add the indicator to the chart again -

As we can see, the settings window has changed. Now we can control the colors and the type of lines of the future indicator. This data is taken from the buffer settings that we set inside the `onInit` function.

Now we move on to the key indicator algorithm - the onUpdate function. Finally, our code will take a finished look!

As you can see from the documentation for the Indicator class, the onUpdate function will be called whenever the price chart changes (when a new pip comes to the price chart). Thus, our indicator will always correspond to the price chart. So, let's see what happens inside the code.

The first thing that catches your eye is the async keyword. This word means that our method is asynchronous. We will not dwell on this, since the differences between synchronous and asynchronous methods are very large, and deserve a separate topic. You can read more about async here – developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

Now we return to the price chart, and again add the indicator. In the settings window, click on the `Ok` button. This time, we will see a ready-made indicator under the price chart:

As you can see, there is nothing complicated in the example. All mathematical functions are already implemented, and for programming indicators for Mobius Trader 7 you just need to get your hand in and remember how to use the key classes and functions that are described in the specification -mtrader7.com/ru/docs/Terminal/mScript/JavaScript/v1

The full code of the relative vigor indicator with all comments is available below:

/**
 * Relative_Vigor_Index Indicator (Relative Vigor Index)
 *
 * @module Relative_Vigor_Index
 * @see module:Indicator
 */
export class Main extends Indicator {

    /**
     * Class constructor.
     * Called once when creating an instance of the class for each instance.
     * It does not accept any arguments, implicitly returns the created instance.
     *
     * @see Buffer
     * @see mScrip::addBuffer
     */
    constructor() {
        //The `Indicator` class is declared the parent class for` Relative_Vigor_Index`.
        //For the inherited functions to work correctly, the parent class must be initialized
        //To do this, call the parent constructor:
super ();

        //Since the indicator `Relative_Vigor_Index` is an oscillator, then
        //we need to display it in a separate window, and not overlay the price chart.
        //To do this, we set the `SeparateWindow` property to` true`.
        this.setProperty(Property.SeparateWindow, true);

        //Set the input parameter for the indicator period `ExtRVIPeriod`
        //This parameter will be used by default, but it can be overridden by the user.
        //The value of the `ExtRVIPeriod` parameter will be 10
        this.addInput("ExtRVIPeriod", InputType.int, 10);

        //Set the input parameter for the price that will be used in the calculations.
//This parameter will be used by default, but it can be overridden by the user.
//The price we choose is Bid, or the price of the demand (sale).
//May be `PriceType.Bid` or` PriceType.Ask`
this.addInput ("PriceType", InputType.PriceType, PriceType.Bid);

        //For the indicator to work correctly, we need two storages for data (buffers).
//Data storages are instances of the `Buffer` class
//We will put both storages in the field of this object `this.buffers`.
//The `ExtRVIBuffer` buffer will store data to display the main line of the indicator
//The `ExtRVISignalBuffer` buffer will store data for displaying the signal line of the indicator
//The `this.addBuffer ()` method is not described in this class, but it is present in the mScript class.
//Since `Relative_Vigor_Index` is inherited from` Indicator`,
//and the `Indicator` is inherited from` mScript`, we can call it
this.buffers = {
ExtRVIBuffer: this.addBuffer (),
ExtRVISignalBuffer: this.addBuffer (),
};
}

    /**
     * OnInit method
* Called when the indicator is placed on the price chart and every time when the input parameters change.
* Does not accept any arguments
* Returns nothing
*
     * @see mScript::getInputs
     *
     * @see Buffer::setShape
     * @see Buffer::setColor
     * @see Buffer::setLabel
     * @see Buffer::setShortName
     * @see Buffer::setDrawBegin
     *
     * @override
     * @return void
     */
    onInit () {
//Call the `this.getInputs ()` method to get the input parameters.
//The `this.getInputs` method is not described in this class, but it is present in the` mScript` class.
//Since `Relative_Vigor_Index` is inherited from the` Indicator` class,
//and the `Indicator` is inherited from mScript, we can call it
//Use object decomposition to create the local constant `ExtRVIPeriod`
const {ExtRVIPeriod} = this.getInputs ();


        //Set the settings for displaying the main line of the `Relative_Vigor_Index` indicator
//It will display a line - Shape.Line
//Green - Color.Green
//This line will be signed - "RVI"
//Also it will have a short name "RVI ($ {indicator period})"
//Line drawing starts 13 candles (bars) back from the current moment.
//The last value may change depending on the user's settings.
this.buffers.ExtRVIBuffer
.setShape (Shape.Line)
.setColor (Color.Green)
.setLabel ("RVI")
.setShortName ("RVI (" + ExtRVIPeriod + ")")
.setDrawBegin (ExtRVIPeriod + 3)
;


        //Set the settings for displaying the signal line of the `Relative_Vigor_Index` indicator
//It will display a line - Shape.Line
//Red - Color.Red
//This line will be signed - "RVIS"
//Also it will have a short name "RVI ($ {indicator period})"
//Line drawing starts 17 candles (bars) back from the current moment.
//The last value may change depending on the user's settings.
this.buffers.ExtRVISignalBuffer
.setShape (Shape.Line)
.setColor (Color.Red)
.setLabel ("RVIS")
.setShortName ("RVI (" + ExtRVIPeriod + ")")
.setDrawBegin (ExtRVIPeriod + 7)
;
}

/ **
* Asynchronous onUpdate method.
* Overrides the parent method from the Indicator class.
* This method will be called every time the price on the chart changes.
*
* @see Indicators :: RVI
* @see Buffer :: fill
*
* @override
* @return {Promise.}
* /
async onUpdate () {
//Call the `this.getInputs` method to get the input parameters.
//The `this.getInputs` method is not described in this class, but it is present in the` mScript` class.
//Since `Relative_Vigor_Index` is inherited from` Indicator`,
//and the `Indicator` is inherited from` mScript`, we can call it.
//Use object decomposition to create local constants `ExtRVIPeriod`,
//PriceType, ExtRVIBuffer and ExtRVISignalBuffer
const {ExtRVIPeriod, PriceType} = this.getInputs (),
{ExtRVIBuffer, ExtRVISignalBuffer} = this.buffers;

//Call the asynchronous method Indicators.RVI.
//The keyword `await` means that the script will stop this procedure until it receives
//result from Indicators.RVI. When the result is received, it will be assigned to the local variable `buffers`
let buffers = await Indicators.RVI (
Current.Symbol,
Current.TimeFrame,
ExtRVIPeriod,
PriceType
);

//If our chart has fewer bars than the `Indicators.RVI` function requires
//the value of `buffers` will be equal to` null`, and the execution of the current procedure will end
if (buffers) {
//Otherwise, the `buffers` variable will get the values ​​we need to display the indicators.
//In this case, we pass these parameters to our data stores:
ExtRVIBuffer.fill (buffers [IndicatorLine.Main]);
ExtRVISignalBuffer.fill (buffers [IndicatorLine.Signal]);
//At this point, the terminal will draw the main and signal line of the `Relative_Vigor_Index` indicator.
}
}
}