Figaro - Remote Indicators

1Introduction to Figaro remote indicators

A user-defined indicator (UDI) for Figaro can run "remotely", outside the web/mobile platform, connecting via a hub application. This has two uses:

Remote indicators can be written in C# or Python instead of Javascript

Indicators which run remotely never have their code delivered to the web browser, and therefore the code cannot be inspected, decompiled, copied etc

There are two types of hub application:

A local hub which you download and run on your own computer, so that you can write indicators for yourself in C# or Python (instead of Javascript, inside the platform)

The FX Blue indicator hub, which lets you provide indicators remotely to other users without sharing the code (or lets you use your own C# or Python indicators on a device other than the one which is running the indicator code)

1.1Getting started

To get started with remote indicators, you need to do the following:

Download the local hub application

Download the code samples

Run one of the code samples

Add the indicator to a Figaro chart

1.2Providers and consumers

In the terminology of remote indicators, there are "providers" and "consumers".

A provider is a C# or Python or Node.js app which implements the code for one or more indicators.

A consumer is an instance of a UDI on a Figaro chart, requesting calculations from a provider.

1.3Provider IDs

A provider app is given an ID such as myindicator (configured, for example, in MyConfig.py or MyConfig.cs) and this corresponds to a path entered into Figaro's Add UDI dialog. For example:

ws://localhost:9115/myindicator

wss://indicators.fxblue.com/myindicator

For the FX Blue hub at wss://indicators.fxblue.com, the ID must be a username on www.fxblue.com.

For a copy of the indicator hub running locally, the ID can be any value of your choice.

1.4Multiple indicators per provider app

A single provider app can implement multiple indicators. In terms of code, an indicator is simply a class (in C# or Python or Javascript).

Each separate indicator in a provider app can then be requested using paths such as the following in the Add UDI dialog:

ws://localhost:9115/myindicator/sma

ws://localhost:9115/myindicator/ema

Provider apps have an indicator "factory" (for example, MyIndicatorFactory.cs, or the IndicatorFactory in run-indicator.py). The factory decides which of the app's indicators to create in response to different paths entered into the Add UDI dialog.

1.5Adding a remote indicator to a Figaro chart

You add a remote indicator to a Figaro chart as follows, telling it the location of the hub to use and the ID of the provider app:

Open the Add UDI dialog

Switch to the URL tab

Change the protocol from https:// to wss://

Enter a URL such as ws://localhost:9115/myindicator

2Running the local indicator hub

You can download and run the local copy of the indicator hub as follows:

Install .NET 8 (if not already present on your computer). Go to https://dotnet.microsoft.com/en-us/download/dotnet/8.0 and, in the ".NET Runtime 8.0.11" section, follow the instructions for your platform.

Download the hub application from https://www.fxblue.com/figaro/udi/figaroindicatorhub.zip

Extract the two files from the ZIP archive into any directory of your choice.

From the command line, run dotnet FigaroIndicatorHub.dll

By default, the hub listens on port 9115 (and the URL which you enter into the Figaro Add UDI dialog is therefore in the form ws://localhost:9115/myindicator etc).

You can change the port number by creating an XML file called FigaroIndicatorHubConfig.xml in the same directory as the executable. The format of the XML file should be as follows:

<settings>

<httpBinding>http://localhost:9115/</httpBinding>

</settings>

If you change the port number, you will also need to change the port which the code samples expect to connect to.

3Overview of code examples

There are examples of remote indicators written in C#, Python, and Javascript (Node.js). You can download the examples from:

https://www.fxblue.com/figaro/udi/remote-indicator-examples.zip

The C# and Python frameworks are, in essence, ports/conversions of the Javascript framework, and this overview should be read in conjunction with the Javascript guide at https://www.fxblue.com/figaro/udi/help.

This document does not attempt to (re-)describe the C# and Python frameworks fully, as standalone entities, without reference to the Javascript framework from which they both derive. It does not, for example, re-explain the fundamental difference between indicators which do have and do not have a Source field, https://www.fxblue.com/figaro/udi/help#3.3.

3.1Structure of the code samples

Each of the code samples consists of:

Example indicator(s)

An abstract UserDefinedIndicator class from which your indicator code inherits

Classes defining context and other data which can be passed to your indicator (such as IndicatorContext in C# or UDIContext in Python)

Framework for connecting to the indicator hub, which you can treat as "internal wiring" and shouldn't need to inspect

Configuration

The configuration consists of:

A server list, defining the hub to connect to. By default, the code examples expect to connect to the local indicator hub running at ws://localhost:9115/.

The provider ID to use

An indicator factory which creates an instance of an indicator class depending on the path requested in the Add UDI dialog

3.2UserDefinedIndicator class

In all the frameworks (C#, Python, and Node.js), an indicator is a class which inherits from the abstract UserDefinedIndicator class. It is equivalent to the UserIndicatorClass in the in-platform Javascript framework, https://www.fxblue.com/figaro/udi/help#2.

Your indicator must implement the initialisation function (on_init() in Python, onInit() in C# and Javascript) which returns a description of your indicator: the input fields which it wants, the output which it draws such as lines and/or histograms.

Your indicator will normally also implement a calculation function which receives input data and calculates the indicator's output, such as receiving bar data and calculating ATR. (However, it is possible for indicators only to create drawings, event markers etc, and not to need a calculation function.)

The UserDefinedIndicator class has event handlers which you can implement to be informed about changes to your indicator's settings, or changes to the chart configuration such as the selected symbol and timeframe.

The UserDefinedIndicator class also implements functions for interacting with the chart by creating drawings, event markers, HTML etc.

3.3Differences compared to in-platform indicators

There are some differences between remote indicators versus indicators running inside the platform.

3.3.1Re-painting

A key difference between remote indicators versus indicators running inside the web/mobile platform is that, by default, remote indicators cannot "re-paint". When only the current bar is changing, they can only update their current, most recent output value. Modifications of earlier, older output are ignored.

A remote indicator can temporarily change/override this by setting a repaint flag, using set_repaint() in Python or setRepaint() in C# or Javascript. This tells the framework that the indicator is about to return modified historic output from the in-progress or next call to its calculation function.

3.3.2UDIX / Framework access

In-platform indicators can be given framework access, letting them use the full Figaro programming framework, including the ability to place trades, see the account history, create dialogs etc. (In the terminology of Figaro indicators, this turns the UDI into a UDIX.)

Framework access is only available inside the platform. It is not available to remote indicators.

3.3.3Candle store and technical analysis library

Javascript indicators, whether in-platform or remote, have access to an FXB.ta library of indicator calculations and an FXB.CandleStore helper for working with candle calculations:

https://www.fxblue.com/figaro/udi/help#4.6

C# and Python indicators do not have access to these resources.

3.4Connecting to the FX Blue indicator hub

To connect a provider app to the FX Blue indicator hub, at wss://indicators.fxblue.com, you need to make the following changes to the code samples:

Register with www.fxblue.com and obtain a username and password

Change the config (MyConfig.py, MyConfig.cs, My-config.js) to use the FX Blue username and password

Change the server configuration to connect to the FX Blue hub instead of a local hub

To change the server configuration:

In C#, edit MyServerList.cs to comment-out the line which inherits from IndicatorServerList_Local, and un-comment the line which inherits from IndicatorServerList_Hub

In Python, edit MyServerList.py to remove the commenting-out of the non-null return value from server_list_endpoint(). (The server_list() function is then redundant and unused).

In Node.js, edit Server-list.js to remove the commenting-out of serverListEndpoint. (The serverList is then redundant and unused.)

4C#

C# indicator code can be relatively lengthy compared to Javascript and Python because the language is strongly typed. For example, on_init() in Python can return a simple dictionary describing the indicator. In C#, by contrast, onInit() must build and return an IndicatorDefinition which is a relatively complex object potentially containing lists of IndicatorDefinitionPlot and IndicatorDefinitionSettingsField objects.

The C# example code consists of the following:

Directory

Description

(root)

An example indicator (MyIndicator.cs) plus config defining the hub application to connect to and the provider ID to use

UDI Framework

The UserDefinedIndicator class, plus other objects which can be passed to or from your indicator code

Example indicators

Other example indicators

Internal wiring

Code for connecting to the hub application

Many of the files are partial classes, with their code split between "UDI Framework" and "Internal wiring". For example, UserDefinedIndicator.cs contains the properties and methods of UserDefinedIndicator which you may need to work with, whereas UserDefinedIndicator_InternalWiring.cs contains code which you should be able to ignore, handling the internal mechanics of communicating with the indicator hub.

4.1Indicator initialisation

Your indicator must implement onInit(), which returns a description of your indicator: the user-configurable input fields which it wants, the plots which it draws etc.

While the return value from onInit() is ultimately equivalent to the object returned by a Javascript indicator, https://www.fxblue.com/figaro/udi/help#3.1, in C# it is a strongly-typed IndicatorDefinition object. You create the object and then populate it further with other settings. For example:

// Create the definition object

var description = new IndicatorDefinition("My indicator caption");

// Populate with further settings

description.isOverlay = false;

4.1.1User-configurable settings

You define user-configurable settings for your indicator, such as a number of bars for a moving average, by adding to the settingsFields list of the IndicatorDefinition. For example:

description.settingsFields.Add(new IndicatorDefinitionSettingsField("Period", "period", 20, 2, 100));

The IndicatorDefinitionSettingsField class has different constructors for different types of field: int, float, list of options etc.

There is a special IndicatorDefinitionSettingsSourceField class for adding a Source field to an indicator (making it "value-based" rather than "bar-based"):

description.settingsFields.Add(new IndicatorDefinitionSettingsSourceField());

4.1.2Plots

You define plots for an indicator by adding to the plots list of the IndicatorDefinition. For example:

description.plots.Add(new IndicatorDefinitionPlot("SMA", "line", "blue"));

The second parameter for the IndicatorDefinitionPlot constructor, the type of plot, is one of the same textual values as for a Javascript indicator, https://www.fxblue.com/figaro/udi/help#3.2.

The type of plot determines the number of different values you need to calculate from the incoming data (one for a line, two for a channel etc).

4.2Calculation functions

The UserDefinedIndicator base class defines two calculation functions. You should only override one of the two, depending on whether your indicator has a Source field (or neither of the two, if your indicator only creates drawings, event markers and does not need to calculate and draw any plots such as lines or histograms).

If the indicator has a Source field, it calls onCalculateFromValueData(), passing an IndicatorInputValueData as input, containing a single list of values (plus their dates) for the indicator to work with.

If the indicator does not have a Source field, it calls onCalculateFromBarData(), passing full OHLCV bar data in an IndicatorInputBarData object.

Both calculation functions receive a CalculationEventType, specifying the reason for the call (change of the current bar, addition of a new bar, initial or complete reload of historic data).

Both calculation functions receive an IndicatorOutput object, and should update the output values within that object. As in a Javascript indicator, the IndicatorOutput is ultimately an array of arrays (strictly, a List of Lists in C#). The number of members in the top-level data list is determined by the plots which your indicator defines. Within each list, the number of items corresponds to the length of incoming data; the number of bars on the chart.

4.3Creating drawings, event markers, HTML etc

There are three main differences between a C# function such as createDrawing() and the equivalents in Javascript and Python:

The parameter for the Javascript and Python functions is a simple object/dictionary, whereas in C# it is a strongly typed object such as IndicatorRequestDrawing

The Javascript and Python functions accept either a single object or an array/list, whereas in C# there are separate createDrawing() and createDrawings() functions, or changeDrawing() and changeDrawings() etc, for acting either on one object or many.

The functions for creating drawings and event markers, which asynchronously return IDs for those objects, have a Task as a return value, and are awaitable

5Python

The Python example code consists of the following:

File

Description

Run-indicator.py

The runnable entry point for the provider app. Implements the indicator factory which creates a specific indicator class in response to a particular URL.

MyIndicator.py

The (main) indicator implemented by the app

ExampleIndicators.py

Other example indicators

UserDefinedIndicator.py

The UserDefinedIndicator class

IndicatorContext.py

Objects which can be passed to and from your indicator code, such as UDIData which is passed as a parameter to on_calculate()

MyServerList.py

Config defining the hub application to connect to

MyConfig.py

Config defining the provider ID to use

HubConnection.py

IndicatorProvider.py

Internal wiring of the application, which you should be able to ignore

The code has a dependency on the websockets module; pip3 install websockets

You run a Python indicator app using python run-indicator.py

5.1Indicator initialisation

Your class which inherits from UserDefinedIndicator must implement on_init(). This must return a dictionary with properties describing your indicator, largely identical to the object returned by a Javascript indicator, and described at https://www.fxblue.com/figaro/udi/help#3.

5.2Calculation function

An indicator will normally have an on_calculate() function, unless it is only creating drawings, event markers etc and is not drawing any plots on the chart.

The on_calculate() receives the following parameters:

Parameter

Description

calculation_type

The reason for the call. A textual value being one out of "update" (a change to the current bar), "new-bar" (addition of a new bar), or "full" (initial full load or reload of data)

data

A UDIData object, containing the parameters and context for the calculation. If the indicator has a Source field, then data.value_data is non-null. If it does not have a Source field, then data.bar_data is non-null.

output

The output into which the indicator should write its calculations: a list of lists, like the array of arrays in a Javascript indicator

5.3Creating drawings, event markers, HTML etc

A function such as create_drawing() is very similar to its Javascript equivalent: the parameter is either a dictionary (converted to JSON) describing a single drawing, or a list of dictionaries describing multiple drawings.

The asynchronous result of create_drawing() and create_event_marker(), containing the ID(s) of the created object(s), is notified via the optional on_create_drawing() and on_create_event_marker() event handlers.

6Node.js (Javascript)

Indicators written in Javascript can (obviously) run inside the Figaro web/mobile platform. The only purpose in using the Node.js remote indicator framework is to keep the Javascript code private, and not have it delivered to the web browser.

The Node.js example code consists of the following:

File

Description

Run-indicator.js

The runnable entry point for the provider app. Implements the createIndicatorInstance() indicator factory which creates a specific indicator class in response to a particular URL.

My-indicator.js

The indicator implemented by the app

Server-list.py

Config defining the hub application to connect to

My-config.py

Config defining the provider ID to use

Indicator-framework.js

Internal wiring of the application, replicating the in-platform framework described at https://www.fxblue.com/figaro/udi/help

The code has a dependency on the ws module; npm install ws

You run a Node.js indicator app using node run-indicator

6.1Converting in-platform indicators to the Node.js framework

Any in-platform Javascript indicator, such as any of the examples at https://www.fxblue.com/figaro/udi/help#1.2, can be converted to run within the Node.js framework by making two additions to its code: import the Node.js framework, and export the indicator class for use by the provider app:

// Import of Node.js remote indicator framework

const { UserDefinedIndicator, UDI, FXB } = require("./indicator-framework");

// The indicator code which can also run inside the platform

class MyIndicator extends UserDefinedIndicator {

};

// Export the indicator class for use by the app

module.exports = { MyIndicator };

Note: when running inside the platform, an indicator class must be called MyIndicator. Within the remote indicator Node.js framework, this is not necessary. The class can be given any name - provided that the indicator factory, in run-indicator.js, is correspondingly modified to create that class.