TWM Wiki

Description

Core – Build in the Custom Project for TWM in C#

Custom Project

TWM allows users to write their own extendable modules using C# language.

In this section you will find tutorials and help on the main API. TWM is installed together with a Custom project file where the user can write code. You can use any IDE of your choice.

In our documentation, we will be demonstrating everyhting with the help of Visual Studio Community Edition, which is a free IDE that can be downloaded from here.


Your initial installation will place the TWMCustom project in:

C:\Users\<UserName>\Documents\Twm\bin\Custom

In order to start working with the custom project, locate this folder and open the project or solution file Twm.Custom.csproj or Twm.Custom.sln

You can compile the custom project from within the IDE or by running any compilation commands from within TWM. You can learn more about compiling and debuging here.


Debuging

To Debug your project using an external IDE, please read this section You may alternatively debug using the Debug window of TWM, found in the Admin panel under New -> Debug. Use the command below to print to Debug window.

Print("Debug your code using this command");

Parameters

All parameters should be prefixed with a [TwmProperty] tag. In case this is an Indicator parameter, it will be passed to TWM auto code generator upon compilation, and become accessible inside the strategy code. For a strategy parameter, it will become available inside theOptimizer.

Parameter defaults should be assigned inside the OnStateChanged event

[TwmProperty]
[Display(Name = "Period", GroupName = Parameters, Order = 2)]
public int Period { get; set; }

Execution

Whenever a strategy or indicator changes state, the OnStateChanged event takes place. You can retrieve the new state of the tool and work with it. Some global parameters (such as Name and Version) should be set here.

  1. SetDefaults - whenever a user opens the UI for indicators or strategies (e.g., the dialog box listing all indicators and strategies). Use this state to set the default values that appear when you enable them.
  2. Configured - this is a one time call when users enable the strategy/indicator. Called when user clicks enable or apply.
public override void OnStateChanged()
{
if (State == State.SetDefaults)
{
Name = "Indicator Name";
Version = "1.0";

}
else if (State == State.Configured)
{
}
}

All historical and live execution of TWM strategies and indicators occurs in OnBarClose. Please use the method below to create your code logic inside these overrides. To adress current bar values, please use the zero index as below. Previous bar index would be 1 in this case, etc. Please note that if you address a bar that does not exist on the chart you will get an index out of range exception. For instance, if there are only 5 bars on the chart, and you try and look back at Close[6] you will get an exception.

public override void OnBarUpdate()
{
var close = Close[0];
var open = Open[0];
var high = High[0];
var low = Low[0];
var time = DateTime[0];
}

During live execution of TWM strategies and indicators you can also use OnTickUpdate to execute your logic on a tick-by-tick basis. Address the live candle values appropriately.

public override void OnTickUpdate(ICandle candle, ICandle tick)
{
var close = candle.C;
var high = candle.H;
var low = candle.L;
var open = candle.O;
var time = candle.t;

Print("LIVE CANDLE. Close: " + close + " High: " +high +
" Low: " + low + " Open: " + open + " Time: " + time);

}

OnOrderUpdate event will occur every time there is any change inside the strategy order. Use this to manage your orders during historical strategy execution.

public override void OnOrderUpdate(Order order)
{
Print("On order update: " + order.Name +
" Qnt: " + order.Quantity +
" Price: " + order.FillPrice+
" Guid: "+ order.Guid +
" State: "+ order.OrderState);

if (State == State.Historical)
ManageOrders(order);
}

OnExecutionUpdate will occur only when something occurs to the order during live exectuion i.e., on the connection provider side. The OnExecutionUpdate event executes only when we get a callback from the exchange, it will not execute during historical strategy execution. Please make sure you are using OnOrderUpdate during historical execution.

public override void OnExecutionUpdate(Order order)
{
if (State == State.RealTime)
ManageOrders(order);
}

Adding Data Series

It is possible to add additional data series to an indicator or strategy. The SymbolName string is optional, if omitted, the series uses the same instrument.

Symbol name must match exactly as listed in the instrument list., and you must also specify the type:SPOT or FUTURE. The available connection short names are BybitMainnet and/or BinanceMainnet. You can add as many data series as you like.

AddDataSeries(DataSeriesType.Hour, 1,"DOGEUSDT", "FUTURE","BybitMainnet");

To address data contained with the added data series please use the below syntax.

public override void OnBarUpdate()
{
Print("Close:" + Closes[1][0] + " Open: " + Opens[1][0] + " High: " + Highs[1][0] + " Low: "+ Lows[1][0] + " Time: " + DateTimes[1][0]);
}

If you would like to submit a LIVE order against an added data series, please use the selected bars in progress parameter available inside each order method. In the case below the order will be submitted to the first added extra series.

_entryOrder = SubmitOrder(1, OrderAction.Buy, OrderType.Limit, PosSize, price, 0,0, "", EnterLongName);

Comissions

Comissions are an extendable TWM module. There are several pre-configured setups available. The comissions are calculated at the end of each trade and we have a chance to interact with the trade data in order to make extra calculations. The returned comissions value is deducted from the total P&L of the trade. Below is an example of most popular % based comission calculation.

public override double GetCommission(Trade trade)
{
var entry = (trade.ExitQuantity * trade.EntryPrice)*Commission/100;
var exit = (trade.ExitQuantity * trade.ExitPrice)*Commission/100;


return entry + exit;
}

TWM is already prese

t with spot and futures comissions presets for taker and maker options.

Optimization Fitness

You can access and code your own optimization fitness coefficient. Please look for examples in the optimization fitness folder. The optimzer will always try and find the max Value parameter that you pass from here.

public class MaxProfitFactor : OptimizationFitness
{
private const string OptimizationFitnessName = "Max Profit Factor";

public override void OnCalculatePerformanceValue(StrategyBase strategy)
{
Value = strategy.SystemPerformance.Summary.GetValue(AnalyticalFeature.ProfitFactor);
}
}


Using OnRender to Draw Objects on Chart

Alhtough TWM does provide some standard API to draw objects that are later treated inside the TWM UI it is also possible to use a much faster method to plot any drawing objects on chart using the standard System.Windows.Media methods inside the OnRender override. Below you can find an example of a strategy code that simply collects data from bar high and low values that are later used to draw a connecting line. Please do note that using this method has one limitation. The objects that is drawn has to be on the chart completely. If an object goes off chart partly it will not be plot untill you scroll horizontally and the object becomes completely visible.


public class RenderStrategy : Strategy
{
#region Constants

private const string SystemVersion = " V1.0";
private const string StrategyName = "On Render Strategy";
private const string StrategyGuid = "F715FC72-66EB-4A30-9461-48562117BC9D";

#endregion

#region Values

#endregion

#region Init

public override void OnStateChanged()
{
if (State == State.SetDefaults)
{
SetDefaults();
SetParameters();
}
else if (State == State.Configured)
{
ClearDebug();
}
}

private void SetDefaults()
{
IsAutoscale = true;
Name = StrategyName + SystemVersion;
Guid = new Guid(StrategyGuid);
Version = SystemVersion;

}

private void SetParameters()
{

}

#endregion

private class Data
{
public double Price { get; set; }
public int BarIndex { get; set; }
}

private List<Data> _highs = new List<Data>();
private List<Data> _lows = new List<Data>();

public override void OnBarUpdate()
{
_highs.Add(new Data()
{
Price = High[0],
BarIndex = CurrentBar
});

_lows.Add(new Data()
{
Price = Low[0],
BarIndex = CurrentBar
});
}

public override void OnRender(DrawingContext drawingContext)
{
var pen = new Pen(Brushes.Blue, 2);
pen.Freeze();

for (int i = Chart.VisibleCandlesRange.StartIndex; i <= Chart.VisibleCandlesRange.EndIndex; i++)
{
if (i - 1 < 0)
continue;

var startX = Chart.GetXByBarIndex(_highs[i - 1].BarIndex);
var startY = Chart.GetYByPrice(_highs[i - 1].Price);
var endX = Chart.GetXByBarIndex(_lows[i].BarIndex);
var endY = Chart.GetYByPrice(_lows[i].Price);

var point1 = new Point(startX, startY);
var point2 = new Point(endX, endY);

drawingContext.DrawLine(pen, point1, point2);
}
}
}


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.