TWM Wiki

Description

Create & Configure Custom Indicators in TWM

TWM comes preset with default indicators. Each indicator source code is open for review within the Custom project. Below you can find overall description of Indicator API.




Setting Name & Guid

Each indicator should be assigned a unique GUID. Each indicator class name must match indicator file name exactly. To create a GUID in Visual Studio proceed to Tools -> Create Guid -> New Guid and paste the string into new Guid("GUID string") method. GUID and name should be assigned inside the SetDefaults part of OnStaeChanged override.


public override void OnStateChanged()
{
if (State == State.SetDefaults)
{
Name = IndicatorName;
Guid = new Guid(IndicatorGuid);
}
}


Input

In the below example we can see that the Input[0] is used. This indicates that anyhting that the user assigns as the input will be passed into this series. This is true for UI as well as for bringing input from other indicators and/or strategies. By default the Close prices are passed, however this can be adjusted if the indicator is designed to do so.

public override void OnBarUpdate()
{
_priorSum = _sum;
_sum = _priorSum + Input[0] - (CurrentBar-1 >= Period ? Input[Period] : 0); MA[0] = _sum / (CurrentBar-1 < Period ? CurrentBar : Period);
}

Below we can see the EMA indicator gets initialized with a High and Low series passed as input. If we do not pass anything as the first parameter, the Close series will be passed by default under the hood.

private Indicator _maFast;private Indicator _maSlow;
private void AddIndicators()
{
_maFast = EMA(High, PeriodFast); _maSlow = EMA(Low, PeriodSlow);
}

Initialization from Strategy

The indicator will be plotted on chart by default if it is initialized without ScriptOptions parameter passed. User has an option to hide the indicator from chart or hide the indicator panel from chart by assigning appropriate ShowPlots and ShowPanes booleans in the ScriptOptions object.

private Indicator _maFast;
private void AddIndicators()
{
var options = new ScriptOptions { ShowPlots = true, ShowPanes = false};
_maFast = EMA(High, PeriodFast, options);
}

Pane & Plot & Series

The indicator has to be created in a certain order.

  1. Create Plot
  2. Create a custom pane if required and add plot to pane or to price pane
  3. Create Series
  4. Assign series data to the created plot
[Browsable(false)][XmlIgnore]
public Series<double> MA { get; set; }

private Plot _plot;

public override void OnStateChanged()
{
if (State == State.SetDefaults)
{
MAThickness = 1; MAColor = Colors.Green; Period = 14;

//1 - create plot
_plot = new Plot()
{
Thickness = MAThickness, Color = MAColor
};

//2 - adding plot to existing price pane does not require extra pane creation, just add.
AddPanePlot(_plot);

//alternatively you can add as many panes as you want and add plots to them
//you can have multiple panes within one indicator instance
var secondPane = AddPane();
AddPanePlot(secondPane, _plot);

}
else if (State == State.Configured)
{
//3 - create an empty series and use AddSeries to enable it
MA = new Series<double>();
AddSeries(MA);

//4 - asign series data to plot data source
_plot.DataSource = MA;
}
}

Plot Parameters

The plot can have some parameters that are possible to be assigned.

{
Name = "This name will come up in the data box";
Color = Colors.Blue; LineType = PlotLineType.Solid; //can also set Dashed
Thickness = 2;
ChartType = PlotChartType.Linear; //can also set Bars for histrogram style
}

If you plan to interact with plot colors inside the script, for instance by conditionally updating their color you need to make some extra settings and pass the PlotColors context.

public override void OnStateChanged()
{
if (State == State.SetDefaults)
{
_plot_.PlotColors = new ColorMap(DataCalcContext);
}
}

public override void OnBarUpdate()
{
if (Diff[0] > 0)
{
_diff.PlotColors[0] = Brushes.Green;
}
if (Diff[0] < 0)
{
_diff.PlotColors[0] = Brushes.Red;
}
}

Complex Calculations

You can also make your calculations within the script and pass the calculated values into another indicator. This is quite common for averaging purposes. For instance calculating something inside the OnBarUpdate and passing the calculated series into an SMA.

Below is an illustrated example with SMA indicator initialized on the main price pane and two extra indicators engaged on an extra pane. The additional indicators are MIN and MAX indicators using the calculated SMA value from within a single instance of the same indicator.

Image


[Browsable(false)]
[XmlIgnore]
public Series<double> MA { get; set; }
[Browsable(false)]

[XmlIgnore]
public Series<double> MAMin { get; set; }
[Browsable(false)]

[XmlIgnore]
public Series<double> MAMax { get; set; }

private Plot _plot;
private Plot _plotMaMin;
private Plot _plotMaMax;

// Additional indicators to be used with calculations
private Indicator _maMax;
private Indicator _maMin;

public override void OnStateChanged()
{
if (State == State.SetDefaults)
{
Name = IndicatorName;
Version = IndicatorVersion;

var MAThickness = 1;
var MAColor = Colors.Green;
Period = 14;

_plot = new Plot() { Thickness = MAThickness, Color = MAColor };
AddPanePlot(_plot);

// Creating two extra plots for MIN and MAX
_plotMaMin = new Plot() { Thickness = MAThickness, Color = Colors.Blue };
_plotMaMax = new Plot() { Thickness = MAThickness, Color = Colors.Orange };

// Adding both to same new pane
var maMixMinPane = AddPane();
AddPanePlot(maMixMinPane, _plotMaMin);
AddPanePlot(maMixMinPane, _plotMaMax);
}
else if (State == State.Configured)
{
MA = new Series<double>();
AddSeries(MA);
_plot.DataSource = MA;

MAMin = new Series<double>();
AddSeries(MAMin);
_plotMaMin.DataSource = MAMin;

MAMax = new Series<double>();
AddSeries(MAMax);
_plotMaMax.DataSource = MAMax;

// Assigning MA series as the input of the indicators
_maMax = Max(MA, Period);
_maMin = Min(MA, Period);
}
}

public override void OnBarUpdate()
{
_priorSum = _sum;
_sum = _priorSum + Input[0] - (CurrentBar - 1 >= Period ? Input[Period] : 0);
MA[0] = _sum / (CurrentBar - 1 < Period ? CurrentBar : Period);

// Getting the values
MAMax[0] = _maMax[0];
MAMin[0] = _maMin[0];
}

Although the exact same output can be achieved using the next example, it is highly unrecommended to use do this because this boosts up CPU usage significantly especially of complex calculations.

public override void OnBarUpdate()
{
_priorSum = _sum;
_sum = _priorSum + Input[0] - (CurrentBar - 1 >= Period ? Input[Period] : 0);

MA[0] = _sum / (CurrentBar - 1 < Period ? CurrentBar : Period);

// NOT RECOMMENDED!!!
MAMax[0] = Max(MA, Period)[0];
MAMin[0] = Min(MA, Period)[0];
}



Important

  1. Indicator class name MUST match file name.
  2. Unique GUID should be generated for each IndicatorGuid parameter.
  3. If you create an indicator in an extended namespace, it will create a folder inside the indicator UI inside TWM. If you do so, you MUST create a physical folder on the file structure as well.


Common Mistakes

The most common mistake users will make is get index out of range exception. When OnBarUpdate method executes on the first bar you cannot address a previous bar yet because it does not exist. If your logic requires that, in that case you need to skip this bar. See example below. Please note that in TWM first bar on the left hand side of the chart is CurrentBar = 1.


public override void OnBarUpdate()
{
if (CurrentBar < 2)
return;

//logic that requires previous bar
if (High[0] > High[1]
{

}
}

Another common mistake would be placing cs files into the project by manually copying them into the file structure. If you do so make sure the information about the file exists inside the csproj file. Usually you would use Add Existing File command inside VS to add it properly so it imports correctly into the project structure. TWM uses the project file XML information and therefore if the newly added file meta data does not exist inside the csproj file there is no way for it to be seen within TWM.


Necessary cookies help make the website usable by enabling basic functions such as consent storage, security protection, language preferences, authentication, and preserving the active navigation context.

  • Necessary cookies

    UserUUID

    Technical identifier used to manage and persist cookie consent preferences.

    Maximum storage duration: 12 Months | Type: Necessary cookies
    consent

    Stores your cookie consent choices and selected preferences.

    Maximum storage duration: 12 Months | Type: Necessary cookies
    site_mode

    Preserves the active navigation context, for example keeping the user in the standard website flow or the Start Trading flow when shared navigation elements are used.

    Maximum storage duration: Up to 30 Days | Type: Necessary cookies
    .AspNet.Consent

    Indicates whether the user has provided cookie consent.

    Maximum storage duration: 1 Year | Type: Necessary cookies
    .AspNetCore.Antiforgery

    Used to prevent CSRF attacks and protect form submissions and user data.

    Maximum storage duration: Session | Type: Necessary cookies
    .AspNetCore.Cookies

    Used to manage authentication information and signed-in sessions.

    Maximum storage duration: 1 Year | Type: Necessary cookies
    .AspNetCore.Culture

    Stores the user’s language and localization preferences.

    Maximum storage duration: 1 Year | Type: Necessary cookies

Functional cookies allow the website to remember preferences and support enhanced features or integrations such as Google services, maps, embedded media, or account-related personalization.

  • Functional Cookies

    LSOLH

    Used by Google to store session information and support service-related functionality.


    Maximum storage duration: Session | Type: Functional Cookies
    COMPASS

    Used by Google to remember settings and improve navigation across integrated services.

    Maximum storage duration: 6 Months | Type: Functional Cookies
    ACCOUNT_CHOOSER

    Remembers which Google accounts have been used on the device.

    Maximum storage duration: 1 Year | Type: Functional Cookies
    APISID

    Used by Google to store preferences and information when using integrated Google services such as Maps.

    Maximum storage duration: 2 Years | Type: Functional Cookies
    LSID

    Used by Google to store preferences while viewing pages that incorporate Google services.

    Maximum storage duration: 2 Years | Type: Functional Cookies
    NID

    Used by Google to remember preferences such as preferred language and interface settings.

    Maximum storage duration: 6 Months | Type: Functional Cookies
    SAPISID

    Used by Google services to support embedded content, maps, and account-related personalization.

    Maximum storage duration: 2 Years | Type: Functional Cookies
    __Host-GAPS

    Used by Google to support service preferences and related functionality on pages integrating Google services.

    Maximum storage duration: 2 Years | Type: Functional Cookies

Statistical cookies help us understand how visitors interact with the site, measure performance, and improve services. Depending on configuration, data may be processed in aggregated or pseudonymized form.

  • Statistical Cookies

    CLID

    Microsoft Clarity identifier used to distinguish visitors and support analytics reporting.


    Maximum storage duration: 1 Year | Type: Statistical Cookies
    MR

    Microsoft cookie used for analytics-related measurement and service improvement.

    Maximum storage duration: 7 Days | Type: Statistical Cookies
    SM

    Used by Microsoft Clarity to maintain the current analytics session.

    Maximum storage duration: Session | Type: Statistical Cookies

Marketing cookies are used for advertising, campaign attribution, conversion tracking, personalization, and cross-platform measurement by providers such as Google, Microsoft, Meta, and TikTok.

  • Marketing Cookies

    AID

    Used by Google to link activity across devices and improve ad attribution.


    Maximum storage duration: 1 Year | Type: Marketing Cookies
    ANONCHK

    Used by Microsoft Advertising to validate and support ad-related requests.

    Maximum storage duration: 10 Minutes | Type: Marketing Cookies
    MUID

    Microsoft advertising identifier used to recognize browsers across Microsoft domains.

    Maximum storage duration: 13 Months | Type: Marketing Cookies
    __Secure-3PSID, __Secure-3PAPISID, __Secure-3PSIDTS, __Secure-3PSIDCC

    Google advertising and personalization cookies used to build preference profiles and support ad delivery.

    Maximum storage duration: 2 Years | Type: Marketing Cookies
    ADS_VISITOR_ID

    Used by Google to identify visitors for advertising and attribution purposes.

    Maximum storage duration: 2 Years | Type: Marketing Cookies
    OTZ

    Used by Google to support ad personalization and service optimization.

    Maximum storage duration: 1 Month | Type: Marketing Cookies
    __Secure-1PAPISID, __Secure-1PSID

    Google cookies used to support more relevant ads and account-related ad security.

    Maximum storage duration: 2 Years | Type: Marketing Cookies
    IDE, DSID, FLC

    DoubleClick / Google Ads cookies used for campaign attribution, ad delivery, and remarketing.

    Maximum storage duration: Varies by cookie | Type: Marketing Cookies
    datr, fr, sb, xs

    Meta / Facebook cookies used for browser recognition, security, ad measurement, and personalization across Meta services and partner sites.

    Maximum storage duration: Varies by cookie | Type: Marketing Cookies
    ttcsid

    TikTok identifier used for session-level event attribution, conversion tracking, and advertising measurement.

    Maximum storage duration: Varies by configuration | Type: Marketing Cookies
    ttcsid_D5GFV53C77U3VC0C2T50

    TikTok pixel-specific session cookie used for conversion attribution and advertising performance reporting.

    Maximum storage duration: Varies by configuration | Type: Marketing Cookies
    odin_tt

    TikTok cookie used for campaign attribution, browser recognition, and advertising performance measurement.

    Maximum storage duration: Varies by cookie | Type: Marketing Cookies
    tt_chain_token

    TikTok cookie used for event attribution and campaign linkage across sessions.

    Maximum storage duration: Varies by cookie | Type: Marketing Cookies
    ttwid

    TikTok browser identifier used for attribution, advertising measurement, and remarketing support.

    Maximum storage duration: Varies by cookie | Type: Marketing Cookies
    NID, UULE

    Google cookies that may support ad personalization, localization, and service preference handling depending on the integration and browser state.

    Maximum storage duration: Varies by cookie | Type: Marketing Cookies
    SEARCH_SAMESITE

    Google cookie used to support secure cookie handling across requests and service interactions.

    Maximum storage duration: 6 Months | Type: Marketing Cookies
About cookies and consent

This website uses cookies and similar technologies to ensure its proper functioning and, with your consent, to support functionality, measure usage, improve performance, and provide advertising, attribution, or personalized content. The legal basis for the use of necessary cookies is the legitimate interest of the data controller (Art. 6(1)(f) GDPR), while functional, statistical, and marketing cookies are used only upon your explicit consent (Art. 6(1)(a) GDPR).

Cookies are small text files stored on your device to make the website work efficiently and improve your experience. Some cookies are placed directly by us, while others may be set by third-party services integrated into our pages.

Cookie categories
  • Necessary cookies: enable core site functionality such as consent storage, navigation context, language selection, authentication, and access to secure areas. These cannot be disabled.
  • Functional cookies: allow the website to remember settings and support integrations such as embedded or third-party services.
  • Statistical cookies: collect usage and performance data to help understand and improve the site.
  • Marketing cookies: support advertising, campaign attribution, personalization, and remarketing across providers and services.
Storage and consent management

Your cookie preferences are stored locally in a cookie named consent, valid for 12 months, and pseudonymously on our systems using a technical identifier (UserUUID), which does not allow direct identification of the user. A technical cookie named site_mode may also be used to preserve the current navigation context across pages. You may change or withdraw your consent at any time via the cookie settings button visible at the bottom left of the site.

Third-party cookies

Some cookies are provided by third-party services such as Google, Microsoft, Meta, and TikTok. These third parties may act as independent controllers for the data collected through their own technologies and services.

Your rights

You can withdraw or modify your consent at any time, delete cookies through your browser settings, and exercise your rights under Articles 15–22 GDPR (access, rectification, deletion, limitation, opposition, portability) by contacting us via the details provided in the Privacy Policy.

This Cookie Policy is aligned with Regulation (EU) 2016/679 (GDPR) and the ePrivacy Directive.