Reporting System
The JT-Lib reporting system provides powerful tools for creating, displaying, and analyzing trading strategy results. Reports are displayed in the web interface and allow data visualization in various formats.
System Overview
The reporting system includes:
- Widgets - various types of data display (cards, tables, charts, text)
- Statistics - automatic analysis of trading results
- Data Export - saving results in various formats
- Interactivity - action buttons for real-time strategy management
Basic Operating Principles
- For the tester, the report should be updated in the
onStop()
function after script completion - For live trading, the report can be updated at time intervals (recommended no more than every 5 seconds)
- All logs are automatically added to the report by default
Available Objects and Quick Start
Global Report Object
The reporting system provides a ready-to-use global object globals.report
, which is automatically initialized when starting a trading script. All widgets are created automatically on first access to the corresponding methods.
Quick Start
The reporting system is ready to use immediately after starting a trading script. Below are examples of typical usage:
// Report setup
globals.report.setTitle('Grid Bot Example');
globals.report.setDescription('Multi-coin grid strategy example. Strategy logic is based in the GridBasket class.');
// Update cards (widgets are created automatically)
globals.report.cardSetValue('currentPrice', 50000);
globals.report.cardSetValue('profit', 1500, 'max');
globals.report.cardSetValue('totalOrders', 25);
// Update tables (widgets are created automatically)
globals.report.tableUpdate('orders', {
id: 1,
symbol: 'BTC/USDT',
side: 'buy',
amount: 0.1,
price: 50000,
status: 'closed'
});
// Add data to charts (widgets are created automatically)
globals.report.chartAddPointAgg('profit', 'profit', 1500, 'max');
globals.report.chartAddPoint('balance', 'balance', Date.now(), 10000);
// Update report
await globals.report.updateReport();
Important: No need to create widget instances manually. All widgets are created automatically on first call to the corresponding methods.
Main Reporting System Functions
cardSetValue
The cardSetValue
function automatically creates a card with the specified name and sets its value. The card is created on first call to the function if it doesn't exist yet.
Syntax:
globals.report.cardSetValue(name: string, value: number|string, aggType?: AggType)
Parameters:
name
- unique card namevalue
- value to display (number or string)aggType
- aggregation type (optional): 'last', 'min', 'max', 'sum', 'avg'
How it works:
- If a card with the specified name doesn't exist, a new card with
Number
type is created by default - Value is set according to the aggregation type
- On subsequent calls, the value is updated with aggregation applied
Usage examples:
// Simple value update
globals.report.cardSetValue('currentPrice', 50000);
// Update with aggregation - maximum value
globals.report.cardSetValue('maxProfit', 2000, 'max');
// Update with aggregation - sum
globals.report.cardSetValue('totalVolume', 1000, 'sum');
tableUpdate
The tableUpdate
function automatically creates a table with the specified name and updates it with data. The table is created on first call to the function if it doesn't exist yet.
Syntax:
globals.report.tableUpdate(name: string, data: TableRow|TableRow[])
Parameters:
name
- unique table namedata
- object with row data or array of objects for bulk update
How it works:
- If a table with the specified name doesn't exist, a new table is created
- If an object with an
id
field is passed, the system tries to update an existing record - If a record with the specified
id
is not found, a new record is created - If an array of objects is passed, bulk update is performed
- Old records are automatically removed when row limit is exceeded (300 by default)
Usage examples:
// Add new record
globals.report.tableUpdate('orders', {
id: 1,
symbol: 'BTC/USDT',
side: 'buy',
amount: 0.1,
price: 50000,
status: 'open'
});
// Update existing record
globals.report.tableUpdate('orders', {
id: 1,
status: 'closed',
profit: 500
});
// Bulk update
globals.report.tableUpdate('orders', [
{ id: 1, symbol: 'BTC/USDT', side: 'buy', amount: 0.1, price: 50000 },
{ id: 2, symbol: 'ETH/USDT', side: 'sell', amount: 1.0, price: 3000 }
]);
chartAddPointAgg
The chartAddPointAgg
function automatically creates a chart with the specified name and adds a data point with aggregation. The chart is created on first call to the function if it doesn't exist yet.
Syntax:
globals.report.chartAddPointAgg(name: string, lineName: string, value: number, aggType: AggType)
Parameters:
name
- unique chart namelineName
- line name on the chartvalue
- value to addaggType
- aggregation type: 'last', 'min', 'max', 'sum', 'avg'
How it works:
- If a chart with the specified name doesn't exist, a new
Line
type chart is created - If a line with the specified name doesn't exist, a new line is created
- Value is added with the specified aggregation applied
- Old points are automatically removed when limit is exceeded (5000 by default)
- Data is aggregated by time periods (1 day by default)
Usage examples:
// Add point with maximum value
globals.report.chartAddPointAgg('profitChart', 'profit', 1500, 'max');
// Add point with minimum value
globals.report.chartAddPointAgg('drawdownChart', 'drawdown', -200, 'min');
// Add point with average value
globals.report.chartAddPointAgg('balanceChart', 'balance', 10000, 'avg');
chartAddPoint
The chartAddPoint
function automatically creates a chart with the specified name and adds a data point with exact X and Y coordinates. The chart is created on first call to the function if it doesn't exist yet.
Syntax:
globals.report.chartAddPoint(name: string, lineName: string, valueX: number, valueY: number)
Parameters:
name
- unique chart namelineName
- line name on the chartvalueX
- X coordinate (usually time in milliseconds)valueY
- Y coordinate (value to display)
How it works:
- If a chart with the specified name doesn't exist, a new
Line
type chart is created - If a line with the specified name doesn't exist, a new line is created
- Point is added with exact coordinates without aggregation
- Old points are automatically removed when limit is exceeded (5000 by default)
- Data is displayed in original form without time aggregation
Usage examples:
// Add point with current time
globals.report.chartAddPoint('balanceChart', 'balance', Date.now(), 10000);
// Add point with specific time
const timestamp = new Date('2024-01-01T12:00:00Z').getTime();
globals.report.chartAddPoint('priceChart', 'price', timestamp, 50000);
// Add point with custom X coordinate
globals.report.chartAddPoint('customChart', 'data', 100, 250);
Widgets
1. Cards
// Automatic creation and value updates
globals.report.cardSetValue(name: string, value: number|string, aggType?: AggType)
// Manual creation (optional)
globals.report.createCard(name: string, options: CardOptions)
globals.report.addCard(name: string, card: ReportCard)
// Get existing widget
globals.report.getCardByName(name: string): ReportCard
2. Tables
// Automatic creation and data updates
globals.report.tableUpdate(name: string, data: TableRow|TableRow[])
// Manual creation (optional)
globals.report.createTable(name: string, title: string)
globals.report.addTable(name: string, table: ReportTable)
// Get existing widget
globals.report.getTableByName(name: string): ReportTable
3. Charts
// Automatic creation and data addition
globals.report.chartAddPointAgg(name: string, lineName: string, value: number, aggType: AggType)
globals.report.chartAddPointAggByDate(name: string, lineName: string, value: number, aggType: AggType)
globals.report.chartAddPoint(name: string, lineName: string, valueX: number, valueY: number)
// Manual creation (optional)
globals.report.createChart(name: string, options: ChartOptions)
globals.report.addChart(name: string, chart: ReportChart)
// Get existing widget
globals.report.getChartByName(name: string): ReportChart
4. Text Blocks
// Automatic creation
globals.report.createText(name: string, text: string, variant: string, align: string)
// Manual creation (optional)
globals.report.addText(name: string, text: ReportText)
// Get existing widget
globals.report.getTextByName(name: string): ReportText
5. Action Buttons
// Automatic creation
globals.report.createActionButton(title: string, action: string, value: string, callback?: Function, layoutIndex?: number)
// Manual creation (optional)
globals.report.addActionButton(name: string, button: ReportActionButton)
// Get existing widget
globals.report.getActionButtonByName(name: string): ReportActionButton
Data Types
AggType (Aggregation Types)
type AggType = 'last' | 'min' | 'max' | 'sum' | 'avg'
CardVariant (Card Types)
enum CardVariant {
Text = 'text', // Text values
Number = 'number', // Numeric values
Percent = 'percent' // Percentage values
}
ChartType (Chart Types)
enum ChartType {
Line = 'line', // Line chart
Area = 'area' // Area chart
}
Detailed Widget Description
1. Cards
Cards display individual variable values in a convenient format.
Creating a Card
// Recommended way - automatic creation when updating value
globals.report.cardSetValue('profit', 1500, 'max');
// Manual creation with settings (if customization is required)
globals.report.createCard('profit', {
title: 'Profit',
variant: CardVariant.Number,
options: {
format: CardNumberFormat.Currency,
currency: 'USD',
icon: 'chart-up'
}
});
// Create ReportCard instance (for advanced usage)
const profitCard = new ReportCard({
title: 'Profit',
variant: CardVariant.Number,
options: {
format: CardNumberFormat.Currency,
currency: 'USD'
}
});
globals.report.addCard('profit', profitCard);
Card Types
- Text - text values
- Number - numeric values
- Percent - percentage values
Display Formats
- Default - standard display
- Currency - currency format
- Date - date format
- Short - short format
Data Aggregation
// Last value
globals.report.cardSetValue('profit', 1500, 'last');
// Maximum value
globals.report.cardSetValue('maxProfit', 2000, 'max');
// Minimum value
globals.report.cardSetValue('minProfit', -500, 'min');
// Sum
globals.report.cardSetValue('totalVolume', 10000, 'sum');
// Average value
globals.report.cardSetValue('avgProfit', 150, 'avg');
Card Options
interface CardOptions {
format?: CardNumberFormat; // Display format
currency?: string; // Currency
icon?: string; // Icon
caption?: string; // Caption
isVisible?: boolean; // Visibility
}
2. Tables
Tables display structured data in rows and columns.
Creating a Table
// Recommended way - automatic creation when updating data
globals.report.tableUpdate('orders', {
id: 1,
symbol: 'BTC/USDT',
side: 'buy',
amount: 0.1,
price: 50000,
status: 'closed'
});
// Manual creation with title (if customization is required)
globals.report.createTable('orders', 'Order History');
// Create ReportTable instance (for advanced usage)
const ordersTable = new ReportTable('Order History');
globals.report.addTable('orders', ordersTable);
Working with Data
// Add record
globals.report.tableUpdate('orders', {
id: 1,
symbol: 'BTC/USDT',
side: 'buy',
amount: 0.1,
price: 50000,
status: 'closed',
profit: 500
});
// Update record
globals.report.tableUpdate('orders', {
id: 1,
status: 'closed',
profit: 750
});
// Bulk update
const orders = [
{ id: 1, symbol: 'BTC/USDT', side: 'buy', amount: 0.1, price: 50000 },
{ id: 2, symbol: 'ETH/USDT', side: 'sell', amount: 1.0, price: 3000 }
];
globals.report.tableUpdate('orders', orders);
ReportTable Methods
const table = globals.report.getTableByName('orders');
// Insert record
table.insert(row: TableRow, idField?: string): boolean
// Update record
table.update(row: TableRow, idField?: string): boolean
// Insert or update
table.upsert(row: TableRow, idField?: string): boolean
// Bulk operations
table.insertRecords(rows: TableRow[], idField?: string)
table.updateRecords(rows: TableRow[], idField?: string)
table.upsertRecords(rows: TableRow[], idField?: string)
// Clear table
table.clear(): boolean
// Set row limit
table.setMaxRows(maxRows: number)
Table Limitations
- Maximum 300 rows by default (configurable)
- Automatic removal of old records when limit is exceeded
3. Charts
Charts visualize data as lines or areas.
Creating a Chart
// Recommended way - automatic creation when adding data
globals.report.chartAddPointAgg('profitChart', 'profit', 1500, 'max');
// Manual creation with settings (if customization is required)
globals.report.createChart('profitChart', {
chartType: ChartType.Line,
maxPoints: 1000,
aggPeriod: 3600000 // 1 hour
});
// Create ReportChart instance (for advanced usage)
const profitChart = new ReportChart('Profit Chart', {
chartType: ChartType.Area,
maxPoints: 5000
});
globals.report.addChart('profitChart', profitChart);
Chart Types
- Line - line chart
- Area - area chart
Adding Data
// Add point with aggregation
globals.report.chartAddPointAgg('profitChart', 'profit', 1500, 'max');
// Add point by date
globals.report.chartAddPointAggByDate('profitChart', 'profit', 1500, 'max');
// Configure lines
const chart = globals.report.getChartByName('profitChart');
chart.setLineInfo('profit', 'max', '#3F51B5');
chart.setLineInfo('drawdown', 'min', '#FD6A6A');
ReportChart Methods
const chart = globals.report.getChartByName('profitChart');
// Configure lines
chart.setLineInfo(name: string, aggType: AggType, color?: string)
// Add points
chart.addPoint(lineName: string, valueX: number, valueY: number, color?: string)
chart.addPointByDate(lineName: string, valueY: number, color?: string)
chart.addPointAggByDate(lineName: string, value: number, aggType: AggType, color?: string)
// Get data
chart.getLine(name: string): number[]
chart.getLength(): number
// Clear
chart.clear()
// Configure aggregation
chart.setAggPeriodByDates(start: number, end: number, dotCount: number)
Chart Data Aggregation
- last - last value
- max - maximum value
- min - minimum value
- sum - sum of values
- avg - average value
Chart Options
interface ReportChartOptions {
maxPoints?: number; // Maximum points (default 5000)
aggPeriod?: number; // Aggregation period in ms (default 1 day)
chartType?: ChartType; // Chart type
layoutIndex?: number; // Layout index
}
4. Text Blocks
Text blocks display arbitrary text in the report.
Creating a Text Block
// Recommended way - direct creation
globals.report.createText('summary', 'Strategy Summary', 'subtitle1', 'center');
// Create ReportText instance (for advanced usage)
const summaryText = new ReportText('Strategy Summary', 'subtitle1', 'center');
globals.report.addText('summary', summaryText);
Display Variants
- h1, h2, h3 - different level headings
- subtitle1, subtitle2 - subtitles
- body1, body2 - main text
- caption - small text
Alignment
- left - left aligned
- center - center aligned
- right - right aligned
Text Options
interface TextOptions {
variant?: string; // Display variant
align?: string; // Alignment
isVisible?: boolean; // Visibility
}
5. Action Buttons
Action buttons allow sending commands to the running runtime.
Creating an Action Button
// Recommended way - direct creation
globals.report.createActionButton('Close Position', 'closePosition', 'BTC/USDT');
// Create with callback function
globals.report.createActionButton('Start Trading', 'startTrading', '', async (data) => {
this.isTrading = true;
await globals.report.updateReport();
});
// Create ReportActionButton instance (for advanced usage)
const closeButton = new ReportActionButton('Close Position', 'closePosition', 'BTC/USDT');
globals.report.addActionButton('closeButton', closeButton);
Handling Actions
async onReportAction(action: string, data: any) {
switch (action) {
case 'closePosition':
await this.closePosition(data);
break;
case 'startTrading':
this.isTrading = true;
break;
case 'stopTrading':
this.isTrading = false;
break;
}
await globals.report.updateReport();
}
Note: Action buttons are used only for real-time robots, not for the tester.
Statistics and Analysis
Automatic Statistics
The system automatically collects statistics on trading operations:
class Statistics extends BaseObject {
ordersOpenedCnt = 0; // Number of opened orders
ordersClosedCnt = 0; // Number of closed orders
ordersCanceledCnt = 0; // Number of canceled orders
ordersModifiedCnt = 0; // Number of modified orders
ordersTotalCnt = 0; // Total number of orders
volume = 0; // Total trading volume
profit = 0; // Total profit
bestTrade = 0; // Best trade
worstTrade = 0; // Worst trade
}
Creating Report with Statistics
async onStop() {
// Set values (cards are created automatically)
globals.report.cardSetValue('totalOrders', this.statistics.ordersTotalCnt);
globals.report.cardSetValue('profit', this.statistics.profit);
globals.report.cardSetValue('winRate', this.calculateWinRate());
// Update report
await globals.report.updateReport();
}
Data Export
Report Update
// Update report on server
await globals.report.updateReport();
// Force update (ignores frequency limitations)
await globals.report.updateReport({ isForce: true });
Report Data Structure
interface ReportData {
id: string; // Unique report identifier
symbol: string; // Trading symbol
description?: string; // Report description
blocks: ReportBlock[]; // Report blocks
}
interface ReportBlock {
type: ReportBlockType; // Block type
name?: string; // Block name
data: ReportBlockData; // Block data
}
Report Data Access
// Get report data
const reportData = globals.report.getReportData();
// Export to JSON
const jsonData = JSON.stringify(reportData, null, 2);
Practical Examples
Example 1: Basic Trading Strategy Report
class Script extends BaseScript {
async onInit() {
// Report setup
globals.report.setTitle('Trading Strategy Report');
globals.report.setDescription('Automated trading strategy with real-time monitoring');
// Widgets are created automatically on first access
// No additional actions required
}
async onTick() {
// Update cards (widgets are created automatically)
globals.report.cardSetValue('currentPrice', this.getCurrentPrice());
globals.report.cardSetValue('position', this.getPositionStatus());
// Add point to chart (widget is created automatically)
globals.report.chartAddPointAggByDate('profit', 'profit', this.getTotalProfit(), 'max');
// Update report every 5 ticks
if (this.tickCount % 5 === 0) {
await globals.report.updateReport();
}
}
async onOrderChange(order: Order) {
// Add order to table (widget is created automatically)
globals.report.tableUpdate('orders', {
id: order.id,
symbol: order.symbol,
side: order.side,
amount: order.amount,
price: order.price,
status: order.status,
timestamp: new Date().toISOString()
});
}
async onStop() {
// Final report update
await globals.report.updateReport();
}
}
Example 2: Optimization Report
class Script extends BaseScript {
async onStop() {
// Add optimization parameters
globals.report.optimizedSetValue('profit', this.totalProfit, 'max');
globals.report.optimizedSetValue('drawdown', this.maxDrawdown, 'min');
globals.report.optimizedSetValue('winRate', this.winRate, 'avg');
globals.report.optimizedSetValue('sharpeRatio', this.sharpeRatio, 'max');
// Create optimization results table
globals.report.createTable('optimization', 'Optimization Results');
globals.report.tableUpdate('optimization', {
parameter: 'RSI Period',
value: this.rsiPeriod,
profit: this.totalProfit,
drawdown: this.maxDrawdown,
winRate: this.winRate
});
await globals.report.updateReport();
}
}
Example 3: Interactive Report
class Script extends BaseScript {
async onInit() {
// Create control buttons
globals.report.createActionButton('Start Trading', 'startTrading', '');
globals.report.createActionButton('Stop Trading', 'stopTrading', '');
globals.report.createActionButton('Close All Positions', 'closeAll', '');
// Information cards are created automatically when updating values
}
async onReportAction(action: string, data: any) {
switch (action) {
case 'startTrading':
this.isTrading = true;
globals.report.cardSetValue('status', 'Trading Active');
break;
case 'stopTrading':
this.isTrading = false;
globals.report.cardSetValue('status', 'Trading Stopped');
break;
case 'closeAll':
await this.closeAllPositions();
globals.report.cardSetValue('status', 'All Positions Closed');
break;
}
await globals.report.updateReport();
}
}
Usage Recommendations
Performance
- Update Frequency: Don't update report more than every 5 seconds in live trading
- Data Limits: Use reasonable limits for tables and charts
- Aggregation: Use aggregation for large data volumes
Report Structure
- Header: Always set report title and description
- Logical Grouping: Group related widgets together
- Information Priority: Place most important information at the beginning of the report
Debugging
- Logging: Use built-in logging for debugging
- Data Validation: Check data correctness before adding to report
- Error Handling: Handle errors when creating and updating widgets
The JT-Lib reporting system provides all necessary tools for creating informative and interactive trading strategy reports, allowing traders to effectively analyze results and make informed decisions.