Skip to content

How to Add Methods to the cTrader API

Extension methods are a crucial tool if you want to add new functionality to the cTrader API. Using relatively simple syntax, you can add new behaviours to any pre-defined API class, such as Symbol or Position. After you define an extension method, you can call it from any object of the class that you extended.

Use Case for Extension Methods

First, we will conduct a quick demonstration of why you might want to use extension methods.

Using a cBot, we want to be able to access the size of a given position in lots as this information directly affects our preferred trading strategy. To do so, we can try to initialise a variable of the Position class and then try to access its Lots() method.

1
2
Position position = Positions.Last();
Print(position.Lots());

If we simply type the code as is, we will receive an error suggesting that the Lots() accessor does not exist in the API. But what if there was a way to add a new method to an existing API member without affecting any other functionalities?

On the assumption that this method existed, we could have created a simple cBot that, on every bar, would iterate over a list of all current positions and print their size in lots to the log. We would define the OnBar() method as follows.

1
2
3
4
5
6
protected override void OnBar()
{
    foreach (var position in Positions) {
        Print(position.Lots());
    }
}

Extension methods allow us to add the Lots() functionality in just a few lines of code and then reuse it whenever we want on any object of the Position class. Below, we explain how you can create one and provide several examples of algos using them.

How Extension Methods Work

When working with extension methods, be mindful of the following rules.

  • Extension methods are always static.

To declare a static method, all you have to do is use the static keyword. Below, declare the Lots() method with an empty body.

1
2
3
4
public static class MyExtensions {
    public static double Lots() {}

}
  • Extension methods can have any number of arguments but the first argument always has to designate the data type/class for which the method is supposed to be called preceded by the keyword this.

We will add an object of the Position class as the first and only argument of the Lots() method. As a Position object also contains information about the symbol for which the position is opened, we do not need any other arguments.

1
2
3
public static class MyExtensions {
    public static double Lots(this Position position) {}
}
  • Extension methods can contain any logic suitable for the provided arguments.

There is no need to use special syntax when defining the body of an extension method. We can treat it as any other method and, therefore, can define its body as follows.

1
2
3
4
5
public static class MyExtensions {
    public static double Lots(this Position position) {
        return position.VolumeInUnits / position.Symbol.LotSize;
    }
}
  • Extension methods can be called as instance methods or static methods.

There are two possible ways to call our extension method in the code of a cBot.

When using the instance method syntax, we simply call the method from any suitable object of the Position type.

1
2
var position = Positions.Last();
Print(position.Lots());

When using the static method syntax, we can call our extension method after fully specifying its corresponding static class.

1
2
var position = Positions.Last();
Print(MyExtensions.Lots(position));

It is up to you to determine which method of calling extension methods is the most convenient.

Method Signatures

When using instance syntax, avoid cases where your extension methods have the same signatures as any of the built-in API methods (e.g., Position.Close()). In these situations, a built-in method will be called every time you attempt to call an extension method with the matching signature.

IntelliSense

Note that when we attempt to call an extension method, IntelliSense uses a special icon to distinguish it from built-in API members.

To demonstrate our new method in action, we can create a cBot that places three orders on start each with different volume. On every bar, the bot prints the volume of all currently open positions in lots.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
protected override void OnStart()
{
    ExecuteMarketOrder(TradeType.Buy, SymbolName, 10000);
    ExecuteMarketOrder(TradeType.Buy, SymbolName, 100000);
    ExecuteMarketOrder(TradeType.Buy, SymbolName, 50000);
}

protected override void OnBar()
{
    foreach (var position in Positions) {
        Print(position.Lots());
    }
}

After building and launching our cBot, we should see the correct values being printed in the log.

Using Extension Methods in cBots

We will now try to create a more complex cBot. On every bar, our algo will go over the list of currently open positions and adjust their stop loss levels so that they are at break even. To do so, we will need to create a BreakEven() extension method for the Position class.

We create a new cBot and rename it. Afterward, we delete all the code we do not need and add the MyExtensions class.

1
2
3
public static class MyExtensions {

}

Our code for the BreakEven() method is relatively simple. We check if a position has a stop loss, whether its gross profit is greater than zero and whether the currently set stop loss is not equal to the position entry price. If all of these conditions are true, we modify the stop loss of the position so that it is equal to the position entry price.

1
2
3
4
5
6
7
public static class MyExtensions {
    public static void BreakEven(this Position position) {
        if (position.StopLoss is not null && position.GrossProfit > 0 && position.StopLoss != position.EntryPrice) {
            position.ModifyStopLossPrice(position.EntryPrice);
        }
    }
}

In the cBot itself, we do not need to use any other method other than OnBar(). On every bar we ask the bot to perform a simple operation, namely iterate over the Positions collection and call the new BreakEven() method for each element in it.

1
2
3
4
5
6
protected override void OnBar() 
{
    foreach (var position in Positions) {
        position.BreakEven();
    }
}

After we build and launch our bot, we can see it in action. It can be a handy trading assistant, especially when managing many open positions.

Using Extension Methods in Indicators

We will also create a useful indicator that relies on extension methods. The indicator will measure volatility by plotting the percentage by which the price of a symbol has changed on every bar compared to the opening price of said bar.

To do so, we will create a new indicator and rename it. In the code editor window, we will create the MyExtensions class to extend the Bar class.

1
2
3
public static class MyExtensions {

}

We will also add the PercentageChange() method. In the priceChange variable, we subtract the close price of a bar from its opening price. The method returns our price change divided by the open price and multiplied by 100.

1
2
3
4
5
6
7
8
public static class MyExtensions 
{
    public static double PercentageChange(this Bar bar) 
    {
        var priceChange = bar.Open - bar.Close;
        return priceChange / bar.Open * 100;
    }
}

In the indicator code itself, we have no need for the Initialize() method and unnecessary parameters. In the body of the Calculate() method, we simply call our new PercentageChange() method on every bar.

1
2
3
4
5
6
7
8
[Output("Main")]
public IndicatorDataSeries Result { get; set; }


public override void Calculate(int index)
{
    Result[index] = Bars[index].PercentageChange();
}

Afterward, we save and build our indicator. After creating an instance of it, we should see the correct percentage changes being plotted. They can be used to determine short and long-term volatility, benefitting all kinds of trading strategies.

Summary

To conclude, extension methods are a valuable tool if you want to create reausable code that adds new functionalities to the cTrader API. We highly recommend experimenting with extension methods as they can make your algos more efficient and easier to maintain. If you want to learn more about working with the Automate API, subscribe to our YouTube channel to be alerted every time we publish a new video.

Subscribe to our YouTube channel