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
- Open Visual Studio Code.
- Go to Run -> Start Debugging.
- Set breakpoints as needed.
- 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 *