tbapi



Overview

tickblaze-api (tbapi)

tbapi is a package that allows you to develop scripts for the Tickblaze platform in Python. tbapi is the Python implementation of the core Tickblaze API, which is based on .NET.

Detailed documentation for the .NET version of the API can be found here. .NET Tickblaze-API



Setting up the local environment and workspace

This guide explains how to set up your environment for developing Tickblaze scripts using tbapi.
It includes information on how to install the package, initialize a workspace, and build a script.

Dependencies

To use tbapi on your local system, you need to have the .NET SDK version 10 or higher installed.
For Tickblaze platform users, no installation is required, as the .NET SDK is bundled with Tickblaze.

You also need to have Python version 3.12.8 installed: link

Install tbapi

To install the tbapi package, open a terminal and run the following command:

pip install tickblaze-api

Tbapi script builder CLI

The tbapi package comes with a script builder CLI for initializing workspaces and building scripts for the Tickblaze platform.
You can learn more about the script builder CLI in the next chapter.

Create a workspace

To create a workspace, create a directory, open a terminal in the desired folder, and run:

tbapi init

Alternatively, you can use the -p option to specify a custom path:

tbapi init -p path/to/directory

Package config

After creating a workspace, a package.config.toml file will appear, which contains information about the package.

name = "Example"
version = "1.0.0.0"
  • name — the package name. This name will be used in Tickblaze.
  • version — the package version. This version will be displayed in Tickblaze.

Getting Started

Creating a New Script

To create a script, you need to add a new .py file.
In this file, you should import tbapi, create a class that inherits from the corresponding tbapi base class, and add the appropriate decorator.

Here are examples of the required base classes and decorators depending on the type of script:

Indicator:

from tbapi import *

@tb_indicator
class MyIndicator(Indicator):

    def __init__(self, *args, **kwargs):
        ...

Drawing:

from tbapi import *

@tb_drawing()
class MyDrawing(Drawing):

    def __init__(self, *args, **kwargs):
        ...

Strategy:

from tbapi import *

@tb_strategy()
class MyStrategy(Strategy):

    def __init__(self, *args, **kwargs):
        ...

Trade Management Strategy:

from tbapi import *

@tb_tms()
class MyTms(TradeManagementStrategy):

    def __init__(self, *args, **kwargs):
        ...

Custom Bar Type:

from tbapi import *

@tb_bar_type()
class MyBarType(BarType):

    def __init__(self, *args, **kwargs):
        ...

IMPORTANT: All of these base types must have a constructor with the following signature.
This is a critical requirement for successful script compilation.

def __init__(self, *args, **kwargs):

After creating the script, you need to build it using the command:

tbapi build

More detailed script examples can be found later in the Examples section.

For more information about the build command and its arguments, see the section on the script builder CLI.



Script Descriptors

This document describes the main descriptors used for Tickblaze scripts: ScriptParameter, Plot, and Source. These descriptors provide metadata for script properties and enable Tickblaze to automatically expose them in the UI.

You can see more details on how to use the descriptors in the Examples section.


ScriptParameter

Class: ScriptParameter(TbDescriptorBase[T])

Specifies metadata for a parameter property in a script.

Attributes

  • name: The display name of the parameter.
  • group_name: Group name of the parameter (optional).
  • description: Description of the parameter (optional).
  • order: Order of the parameter (optional).
  • show_in_signature: Indicates whether the parameter is shown in the script signature.
  • numeric_range: Numeric range constraints for the parameter.

Example

@tb_indicator(display_name="Display Name")
class MyCloseIndicator(Indicator):

    def __init__(self, *args, **kwargs):
        self.is_overlay = True
        self.swing_strength = 1

    swing_strength: int = ScriptParameter(
        "Strength2",
        group_name="Swings2",
        description="Bar lookback to calculate swing high or low2",
        numeric_range=NumericRange.new(5,10, 2),
        order=5,
        show_in_signature=True,
    )

Plot

Class: Plot(TbDescriptorBase[T])

Specifies metadata for a Plot property in a script.

Attributes

  • name: The display name of the plot.

Example

@tb_indicator(display_name="Display Name")
class MyCloseIndicator(Indicator):

    def __init__(self, *args, **kwargs):
        self.is_overlay = True
        self.result = PlotSeries.new("FirstSeries1", Color.Red, PlotStyle.Stair)

    result : PlotSeries = Plot(
        "FirstSeries2"
    )

Source

Class: Source(TbDescriptorBase[T])

Specifies metadata for a Source property in a script.

Attributes

  • name: The display name of the source.

Example

@tb_indicator(display_name="Display Name")
class MyCloseIndicator(Indicator):

    def __init__(self, *args, **kwargs):
        self.is_overlay = True

    source2: ISeries = Source("Source2")

These descriptors help Tickblaze automatically recognize script properties, display them in the UI, and handle interactions such as plotting, parameter input, and data sources.



Tickblaze Python Scripts Compiler CLI

The Tickblaze Python Scripts Compiler CLI provides two primary commands — Build and Init — for working with Python script projects. These commands allow you to initialize new projects and compile Python scripts into runnable Tickblaze packages. The CLI comes bundled with the tickblaze-api package.


Build Command

Description

The build command compiles a Python script project into a runnable Tickblaze script package.

Usage

tbapi build [options]

Options

Option Description Default
-p, --path <dir> Path to the directory containing source files. Current working directory
-n, --name <name> Script name. Empty
-d, --debug Enables debug mode. false
--port Port for the debug server. 5678

Init Command

Description

The init command initializes a new Python script project in the current or specified directory. It creates a default package configuration.

Usage

tbapi init [options]

Options

Option Description Default
-p, --path <dir> Directory where the project will be created. Current working directory

Examples

Close Indicator

from tbapi import *  


@tb_indicator  
class CloseIndicator(Indicator):  

    def __init__(self, *args, **kwargs):  
        self.is_overlay = True  
        self.name = "_python_example_close_indicator"  
        self.result = PlotSeries.new("FirstSeries1", Color.Red, PlotStyle.Stair)  

    result : PlotSeries = Plot(  
        "Result"  
    )  

    def calculate(self, index: int) -> None:  
        self.result[index] = self.bars[index].close  

Exponential Moving Average Indicator

from tbapi import *  


@tb_indicator  
class ExponentialMovingAverage(Indicator):  

    def __init__(self, *args, **kwargs):  
        self.is_overlay = True  
        self.name = "_python_example_exponential_moving_average"  
        self.short_name = "_p_EMA"  
        self.result = PlotSeries.new("Result", Color.Cyan, PlotStyle.Line)  
        self.period = 14  
        self.smooth_factor = 0  
        self.show_on_chart = True  

    result : PlotSeries = Plot(  
        "Result"  
    )  

    source: ISeries = Source()  

    period: int = ScriptParameter(  
        "Period",  
        numeric_range=NumericRange.new(1, 555)  
    )  

    def initialize(self) -> None:  
        self.smooth_factor = 2.0 / (self.period + 1)  

    def calculate(self, index: int) -> None:  
        if index == 0:  
            self.result[index] = self.source[index]  
        else:  
            self.result[index] = self.source[index] * self.smooth_factor + self.result[index - 1] * (  
                        1 - self.smooth_factor)

Horizontal line drawing

from tbapi import *  


@tb_drawing(points_count=2)  
class HorizontalLine(Drawing):  

    def __init__(self, *args, **kwargs):  
        self.thickness = 1  
        self.line_style = LineStyle.Solid  
        self.name = "_python_example_horizontal_line_drawing"  
        self.color = Color.from_argb(255, 55, 55, 55)  
        self.font_weight = FontWeight.ExtraBlack  

    color = ScriptParameter[Color](  
        "Color",  
        description="Color",  
    )  

    thickness = ScriptParameter[int](  
        "Thickness",  
        description="Thickness",  
        numeric_range=NumericRange.new(1,5),  
    )  

    line_style = ScriptParameter[LineStyle](  
        "Line Style",  
        description="Line Style",  
    )  

    def on_render(self, context: IDrawingContext) -> None:  
        y = self.points[0].y  
        p1 = Point.new(0, y)  
        p2 = Point.new(self.chart.width, y)  
        stroke = Stroke.new()  
        stroke.color = self.color  
        stroke.thickness = self.thickness  
        stroke.line_style = self.line_style  
        stroke.editable_fields = StrokeEditableFields.LineStyle | StrokeEditableFields.Color  
        context.draw_line_with_stroke(p1, p2, stroke)  
        b = MyClass(series=self.bars.close)  
        context.draw_text(Point.new(10, 10), str(self.chart.width), self.color, Font.new("Times new roman", 15, FontStyle.Italic, FontWeight.Bold))

Ema Crossover Strategy

from tbapi import *  

from Indicators.ema_indicator import ExponentialMovingAverage  


@tb_strategy  
class EmaCrossover(Strategy):  
    is_bullish_trend: BoolSeries = None  
    fast_moving_average: ExponentialMovingAverage = None  
    slow_moving_average: ExponentialMovingAverage = None  

    def __init__(self, *args, **kwargs):  
        self.name = "_python_example_EMA_CROSSOVER"  
        self.fast_period = 12  
        self.slow_period = 26  

    fast_period: int = ScriptParameter(  
        "Fast Period",  
        numeric_range=NumericRange.new(1)  
    )  

    slow_period: int = ScriptParameter(  
        "Slow Period",  
        numeric_range=NumericRange.new(1)  
    )  

    def initialize(self) -> None:  
        self.is_bullish_trend = BoolSeries()  

        self.fast_moving_average = ExponentialMovingAverage()  
        self.fast_moving_average.source = self.bars.close  
        self.fast_moving_average.period = self.fast_period  

        self.slow_moving_average = ExponentialMovingAverage()  
        self.slow_moving_average.source = self.bars.close  
        self.slow_moving_average.period = self.slow_period  


    def on_bar(self, index: int) -> None:  
        fast_moving_average_value = self.fast_moving_average.result[index]  
        slow_moving_average_value = self.slow_moving_average.result[index]  

        if fast_moving_average_value > slow_moving_average_value:  
            self.is_bullish_trend[index] = True  
        elif fast_moving_average_value < slow_moving_average_value:  
            self.is_bullish_trend[index] = False  
        elif index >= 1:  
            self.is_bullish_trend[index] = self.is_bullish_trend[index - 1]  

        if (index == 0) or (self.is_bullish_trend[index] == self.is_bullish_trend[index - 1]):  
            return  

        order_action = OrderAction.Buy if self.is_bullish_trend[index] else OrderAction.Sell  

        self.close_position()  
        self.execute_market_order(order_action, 1)

Multi time frame indicator

from tbapi import *  


@tb_indicator  
class MtfExampleIndicator(Indicator):  

    def __init__(self, *args, **kwargs):  
        self.is_overlay = True  
        self.name = "_python_example_mtf"  
        self.result = PlotSeries.new("FirstSeries1", Color.Red, PlotStyle.Stair)  
        self._bars : BarSeries = None  

    result : PlotSeries = Plot(  
        "Result"  
    )  

    def initialize(self):  
        st = SourceType.Day  
        pt = PeriodType.Day  
        size = 1  
        bar_period = BarPeriod.new(st, pt, size)  

        contract_settings = ContractSettings()  
        contract_settings.type = ContractType.ContinuousBackAdjusted  

        symbol_info = SymbolInfo()  
        symbol_info.symbol_code = self.symbol.code  
        symbol_info.exchange = self.symbol.exchange  
        symbol_info.instrument_type = self.symbol.type  
        symbol_info.contract = contract_settings  

        bsi = BarSeriesInfo()  
        bsi.period = bar_period  
        bsi.is_eth = True  
        bsi.symbol_info = symbol_info  
        bsi.start_time_utc = datetime(2024, 10, 7, 18, 45)  

        self._bars = self.get_bars(bsi)  

    def calculate(self, index: int) -> None:  
        if self._bars is not None and self._bars.count <= index:  
            return  

        self.result[index] = self._bars[index].close  

Composite indicator (An indicator that contains another indicator)

Important! Initialization of the internal indicator must be performed in the initialize() function.

from tbapi import *  
from close import MyCloseIndicator  


@tb_indicator  
class CompositeIndicator(Indicator):  

    def __init__(self, *args, **kwargs):  
        self.is_overlay = True  
        self.name = "_python composite Indicator"  
        self.swing_strength = Color.Red  
        self.result = PlotSeries.new("FirstSeries1", Color.Red, PlotStyle.Stair)  
        self.inner = None  

    result : PlotSeries = Plot(  
        "Result"  
    )  

    def initialize(self) -> None:  
        self.inner = MyCloseIndicator()  
        self.inner.source = self.bars.close  

    def calculate(self, index: int) -> None:  
        self.result[index] = self.inner.result[index]  

Shade between indicator (Indicator containing a BandSeries)

from tbapi import *  


@tb_indicator  
class ShadeIndicator(Indicator):  

    def __init__(self, *args, **kwargs):  
        self.is_overlay = True  
        self.name = "_python_shade_indicator"  
        self.first_result = PlotSeries.new("FirstSeries", Color.Red, PlotStyle.Line)  
        self.second_result = PlotSeries.new("SecondSeries", Color.Cyan, PlotStyle.Line)  

    first_result : PlotSeries = Plot(  
        "FirstSeries"  
    )  

    second_result : PlotSeries = Plot(  
        "SecondSeries"  
    )  

    def initialize(self):  
        self.shade_between(self.first_result, self.second_result, self.first_result.color, self.second_result.color, 0.5)  

    def calculate(self, index: int) -> None:  
        b = BarPeriod  
        self.first_result[index] = self.bars[index].close + 25  
        self.second_result[index] = self.bars[index].open + 25

How To Debug

To debug scripts, use Visual Studio Code.

Setup

In your workspace directory, create a .vscode/launch.json file:

MyScriptsWorkspace/.vscode/launch.json

The file should contain the following configuration:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python: Attach (listen for incoming)",
            "type": "python",
            "request": "attach",
            "listen": {
                "host": "localhost",
                "port": 5678
            },
            "justMyCode": false
        }
    ]
}

Building Scripts for Debugging

Build your scripts with the --debug flag:

tbapi build --debug

If you need to use a different debugger port, add the --port argument (default is 5678):

tbapi build --debug --port 5678

Running the Debugger

  1. Open Visual Studio Code.
  2. Go to Run -> Start Debugging.
  3. Set breakpoints as needed.
  4. Launch Tickblaze, add your script to a chart, or start a strategy. The debugger will connect automatically.

Note: You do not need to restart Tickblaze. If Tickblaze is already running, simply reload the chart or strategy to connect the debugger.

 1r'''
 2
 3.. include:: ../pages/OVERVIEW.md
 4
 5.. include:: ../pages/SET_UP.md
 6
 7.. include:: ../pages/GETTING_STARTED.md
 8
 9.. include:: ../pages/DESCRIPTORS.md
10
11.. include:: ../pages/COMPILER_CLI.md
12
13.. include:: ../pages/EXAMPLES.md
14
15.. include:: ../pages/HOW_TO_DEBUG.md
16
17'''
18
19__version__ = "0.1.0"
20
21from .imports import *
22from .common import *
23
24
25from .api import *
26from .core import *