Script Indicator (C#)

HTS's Script Indicator is a custom Indicator for the Trade Bot. This feature allows you to create and share your own indicators.
Check out Pshai's scripts for a set of pre-made custom indicators for use with your custom bot.

Supported license & Trade types

Supported License
Supported Trade Types
Spot trading
Simple license
Margin trading
Advanced license
Leverage trading


The Script Indicator has only one setting: the full path to the script.


The scripts are C#-scripts, using the CS-Script CLR.


All indicator scripts must fully implement the IndicatorScript-interface:
public interface IIndicatorScript
string Name { get; }
int TicksBack { get; }
void Init();
IndicatorResult GetResult(IndicatorContext context);
List<ChartRecord> GetChartLines();
List<decimal> GetChartData();
List<ScriptParameter> GetParameters();
void SetParameters(Dictionary<string,object> parameters);


This property returns the name of the indicator. Haasbot will use this name for the indicator, instead of the general "Script Indicator", so it is clear for the user which script is being used.
string Name { get { return "My Indicator"; } }


With this property you can configure how much price data (Bid, Ask, High, Low, Volume) must be kept in memory by the IndicatorContext. Make sure this is big enough to have enough data to do the necessary calculations in your script, while keeping it small enough to reduce memory usage and unnecessary CPU load when doing these calculations.
using TicTacTec.TA.Library;
// ...
int TicksBack { get { return Core.SmaLookback(sma_length); } }


This method is executed after creating the script-object the first time. You can use this to do any necessary initialization. The created script-object will stay in memory and will be used until the script is recompiled. An indicator-script is recompiled when Haasbot starts and when the Script Indicator settings-window is closed.


This method will be executed every time Haasbot checks the indicator. It should return an IndicatorResult (Stay, Buy or Sell). An IndicatorContext-object is passed, containing current price details and a reference to the IndicatorAPI, giving access to historical price data for all supported platforms and currency pairs. The default behavior of this method is to always return Stay.


GetChartLines is a property defining the chart lines which will be shown on the indicator chart. This property has to return a list of ChartRecord-objects, which define the properties of one chart line. For each line in the chart, you have to define a name, on which chart it has to be shown (0 on main chart - 1,2 and 3 will create their own charts) and optionally a color. When no color is defined, Haasbot assigns a color automatically. For an example, see lines 65 to 76 in the example script.


This method returns the data points which have to be shown in the chart(s). It should return a list of decimal's, in the same order as the ChartRecords returned by the GetChartLines-property. The length of the list returned by the GetChartLines-property should be the same length as the list returned by GetChartData. This method is called after calling GetResult(), so if any chart data is generated in the GetResult-method, you can store it in a class member, and return it in GetChartData to be shown on the indicator chart.GetParametersThis method returns the parameters the user can configure for this script. It should return a list ScriptParameter objects. These ScriptParameter objects define for each parameter the name, current value, type and optionally some info text shown to the user. The user will be able to configure these parameters in the Haasbot user interface. The current value has to be cast into string.
List<ScriptParameter> GetParameters()
return new List<ScriptParameter>
new ScriptParameter("SMA Length", ScriptParameterType.Integer, sma_length.ToString()),
new ScriptParameter("A Useless Decimal", ScriptParameterType.Decimal, (123.456M).ToString()),
new ScriptParameter("Foo", ScriptParameterType.String, "Bar")


This method is called when the script parameters are modified in the Haasbot user interface. The argument is a dictionary with the parameter names as dictionary-keys, and the parameter values as dictionary-values. The type of the values is object, so you need to cast them to the correct type (the same type as you defined in the ScriptParameter in GetParameters). When only specific values or range of values is valid for a certain parameter, you can do the checks here and revert to the previous value if an invalid value was set by the user.After SetParameters is called, the name of the script (the Name-property) is retrieved again. This way, when parameters are used in the name, the name is updated when the parameters are updated.
void SetParameters(Dictionary<string, object> parameters)
sma_length = Convert.ToInt32( parameters["SMA Length"] );


In an indicator script you have access to TA-Lib for calculating any technical analysis indicators. All functions are static members of the static class Core in the namespace TicTacTec.TA.Library. It is not necessary to include external references to use TA-Lib, but having them allows the of your IDEs intellisense.
The PriceInstrument property in the IndicatorContext contains multiple arrays of doubles (Asks, Bids, High, Low, Volume), which can directly be used as input for the TA-Lib-functions.

Creating classes

You can define your own classes and structs in a script. You only have to make sure the class implementing the IIndicatorScript-interface is the first class in the file.


Writing to log-file

You can write debug-info to a log file, by calling Logger.LogToFile(message) on the IndicatorContext-object. The message will be written (together with a timestamp) to a log-file. The log-file has the name of the script and is located at the Haasbot execution path.

Step-by-step debugging

Coming soon

Example script

// The reference files (found in Haasbot installation folder):
// - TradeServer.ScriptingDriver.dll
// - TradeServer.Interfaces.dll
// - TA-Lib-Core.dll
using TradeServer.ScriptingDriver.DataObjects;
using TradeServer.ScriptingDriver.Interfaces;
using TicTacTec.TA.Library;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System;
public class ExampleScript : IIndicatorScript
//Data to be shown in the indicator-chart:
private double buyPrice;
private double emaShort;
private double emaLong;
private int emaShortLength = 7;
private int emaLongLength = 30;
public string Name
get{ return string.Format("Script: EMA {0}-{1}", emaShortLength, emaLongLength); }
public int TicksBack
get { return Core.EmaLookback(emaLongLength) + 1; }
public List<ScriptParameter> GetParameters()
return new List<ScriptParameter>(){
new ScriptParameter(){Name = "EMA short length",
Type = ScriptParameterType.Integer,
Value = emaShortLength.ToString(),
Info = "The length of the shorter/faster EMA."},
new ScriptParameter(){Name = "EMA long length", Type = ScriptParameterType.Integer, Value = emaLongLength.ToString()}
public void SetParameters(Dictionary<string, object> parameters)
emaShortLength = Convert.ToInt32(parameters["EMA short length"]);
emaLongLength = Convert.ToInt32(parameters["EMA long length"]);
public IndicatorResult GetResult(IndicatorContext context)
PriceInstrument instrument = context.PriceInstrument;
int dataCount = instrument.Close.Length;
int beginIndexShort, outNBElementsShort;
int beginIndexLong, outNBElementsLong;
double[] emaShortValues = new double[dataCount];
double[] emaLongValues = new double[dataCount];
var emaShortReturnCode = Core.Ema(0, dataCount - 1, instrument.Close, emaShortLength, out beginIndexShort, out outNBElementsShort, emaShortValues);
var emaLongReturnCode = Core.Ema(0, dataCount - 1, instrument.Close, emaLongLength, out beginIndexLong, out outNBElementsLong, emaLongValues);
if (emaShortReturnCode == Core.RetCode.Success && emaLongReturnCode == Core.RetCode.Success){
buyPrice = instrument.Close[dataCount - 1]; //Take current (last) value
if(outNBElementsShort == 0 || outNBElementsLong == 0){
// Something went wrong
emaShort = buyPrice;
emaLong = buyPrice;
return IndicatorResult.Stay;
emaShort = emaShortValues[outNBElementsShort - 1]; //Take current EMA (last one of the valid values)
emaLong = emaLongValues[outNBElementsLong - 1]; //Take current EMA (last one of the valid values)
context.Logger.LogToFile("EMA Short: " + emaShort + "\tEMA Long:" + emaLong); //Log to file
//Determine indicator signal
if(emaShort > emaLong)
return IndicatorResult.Buy;
else if(emaLong > emaShort)
return IndicatorResult.Sell;
return IndicatorResult.Stay;
context.Logger.LogToFile("EMA calculation failed."); //Log to file
return IndicatorResult.Stay;
public List<ChartRecord> GetChartLines()
return new List<ChartRecord>()
new ChartRecord(ChartIndex = 1, Name = "Buy Price", HexLineColor = "#00FF00"),
new DataSerie(Name = "EMA Short", ChartIndex = 1, HexLineColor = "#FF0000"),
new DataSerie(Name = "EMA Long", ChartIndex = 1, HexLineColor = "#FFFF00")
public List<double> GetChartData()
return new List<double>()