createThresholdEngine

First introduced in version: 3.00.3

Syntax

createThresholdEngine(name, threshold, metrics, dummyTable, outputTable, thresholdColumn, [keyColumn], [timeColumn], [sessionBegin], [sessionEnd], [keyPurgeDaily=false], [forceTriggerSessionEndTime=0], [snapshotDir], [snapshotIntervalInMsgCount], [outputElapsedMicroseconds=false], [outputThreshold=false])

Details

This function creates a threshold engine to implement aggregate calculations triggered by cumulative value thresholds. Each time the cumulative value of the threshold column (thresholdColumn) reaches a specific threshold (n * threshold), an aggregate calculation is triggered. Here, n is a positive integer that starts from 1 and increments by 1. It indicates which threshold boundary the current cumulative value has reached. The trigger boundaries are threshold, 2 * threshold, 3 * threshold, and so on.

  • If keyColumn is specified, the aggregate calculation will be performed independently in each group.
  • If sessionBegin and sessionEnd are specified, only data in the range [sessionBegin, sessionEnd] will be included in the calculation.

Parameters

name is a STRING scalar that specifies the name of the engine. It is the only identifier of an engine on a data or compute node. It can have letter, number and "_" and must start with a letter.

threshold is a positive integer that specifies the threshold step size.

metrics is metacode scalar, vector, or a tuple that specifies the calculation formulas. For more information about metacode please refer to Metaprogramming.

  • It can use one or more built-in or user-defined aggregate functions (which must be defined by the defg keyword) such as <[sum(volume), avg(price)]>, or expressions of aggregate functions such as as <[avg(price1)-avg(price2)]>, or aggregate functions involving multiple columns such as <[std(price1-price2)]>.
  • You can specify functions that return multiple values for metrics, such as <func(price) as `col1`col2> (it's optional to specify the column names).
Note:
  • The column names specified in metrics are not case-sensitive and can be inconsistent with the column names of the input tables.
  • Nested aggregate function calls are not supported in metrics.

dummyTable is a table object whose schema must be the same as the input stream table. Whether dummyTable contains data does not matter.

outputTable is the output table for calculation results. It can be an in-memory table or a DFS table. Before using the createThresholdEngine function, you must predefine the output table as an empty table and specify the column names and data types. After the threshold engine triggers a calculation, it inserts the output results into this table in column-position order.

Note:

The columns of outputTable correspond to the engine output results by position, not by column name. Therefore, the column names in the output table can be user-defined, but the column order and column types must match the following output order. For details, see the description of outputTable in Example 1.

The output table columns are ordered as follows:

Order

Required Column Meaning Type Description
1 Required when timeColumn is specified Time column Must match the output time type corresponding to timeColumn Records the data time that triggered the current calculation. If timeColumn is a single column, the type must match that column. If timeColumn is [date, time], the column type must match the result type of concatDateTime(date, time).
2 Required when keyColumn is specified Grouping column Must match the types and order of the columns specified by keyColumn If keyColumn contains multiple columns, the output table must also define multiple grouping columns in the same order.
3 Required when outputThreshold=true Column for right boundaries of the threshold window LONG Records the threshold boundary value for the current trigger, such as threshold, 2 * threshold, 3 * threshold, and so on.
4 Required when outputThreshold=true Cumulative sum column DOUBLE Records the cumulative sum of thresholdColumn when the calculation is triggered. This value may be greater than the right boundary of the threshold window.
5 Required when outputElapsedMicroseconds=true Elapsed-time column LONG Records the elapsed time from calculation trigger to result output, in microseconds.
6 Always required Calculation result column Must match the result type of the corresponding metric in metrics Corresponds to the metrics in the order in which they are specified in metrics. If the metrics parameter contains multiple metrics, you must define multiple result columns. If a metric returns multiple values, you must also define a corresponding output column for each returned value.

keyColumn (optional) is a STRING scalar or vector that specifies the name of the grouping column(s). If it is specified, the engine conducts the calculations within each group. For example, group the data by stock symbol and apply moving aggregation functions to each stock.

timeColumn (optional) is a STRING scalar or vector that specifies the time column(s) of the subscribed stream table. When useSystemTime = false, it must be specified.

Note: If timeColumn is a vector, it must have a date element (of DATE type) and a time element (of TIME, SECOND or NANOTIME type). In this case, the first column in outputTable must take the data type of concatDateTime(date, time).

sessionBegin (optional) can be a scalar or vector of type SECOND, TIME or NANOTIME corresponding to the data type of the time column, specifying the starting time of each session. If it is a vector, it must be increasing.

sessionEnd (optional) can be a scalar or vector of type SECOND, TIME or NANOTIME corresponding to the data type of the time column, specifying the end time of each session. Specify sessionEnd as 00:00:00 to indicate the beginning of the next day (i.e., 24:00:00 of the current day).

keyPurgeDaily (optional) is a BOOL scalar. Specifies whether, when the engine receives the first batch of data containing a new date, it first clears all previously saved groups before processing that batch. The default value is false, which means the engine does not clear the previous day's groups.

forceTriggerSessionEndTime (optional) is a non-negative integer. The unit of forceTriggerSessionEndTime is consistent with the precision of timeColumn. It indicates the waiting time to force trigger calculation in the window containing the sessionEnd, if it ends without calculation. The default value is 0, indicating the calculation will not be triggered in this way.

Note:
  • forceTriggerSessionEndTime is mainly used in streaming scenarios. It means that when the system time reaches sessionEnd + forceTriggerSessionEndTime, the engine forcibly triggers the calculation within the current session.
  • In replay scenarios, triggering does not depend on system time. Instead, it is driven by the timeColumn of the input data. When the timeColumn of subsequent input data is later than sessionEnd, the engine determines that the current session has ended and triggers the calculation within the current session. Therefore, in replay scenarios, forceTriggerSessionEndTime should not be interpreted as a delay based on replay timestamps.

snapshotDir (optional) is a string indicating the directory where the streaming engine snapshot is saved. The directory must already exist, otherwise an exception is thrown. If snapshotDir is specified, the system checks whether a snapshot already exists in the directory when creating a streaming engine. If it exists, the snapshot will be loaded to restore the engine state. Multiple streaming engines can share a directory where the snapshot files are named as the engine names.

The file extension of a snapshot can be:

  • <engineName>.tmp: temporary snapshot
    • <engineName>.snapshot: a snapshot that is generated and flushed to disk
    • <engineName>.old: if a snapshot with the same name already exists, the previous snapshot is renamed to <engineName>.old.

snapshotIntervalInMsgCount (optional) is a positive integer indicating the number of messages to receive before the next snapshot is saved.

outputElapsedMicroseconds (optional) is a BOOLEAN value. The default value is false. It determines whether to output the elapsed time (in microseconds) from the time the calculation is triggered to the output of result for each window.

outputThreshold (optional) is a BOOLEAN value. It determines whether to output the threshold window values and the cumulative sums of thresholdColumn.

Returns

A table object. Data written to this table is ingested into the engine for aggregation.

Examples

Example 1

// data preparation
n = 1000000;
sampleDate = 2019.11.07;
symbols = `600519`000001`600000`601766;
trade = table(take(sampleDate, n) as date, 
	(09:30:00.000 + rand(7200000, n/2)).sort!() join (13:00:00.000 + rand(7200000, n/2)).sort!() as time, 
	rand(symbols, n) as symbol, 
	100+cumsum(rand(0.02, n)-0.01) as price, 
	rand(1000, n) as volume)

// create the dummyTable and outputTable	
share(streamTable(10:0,`date`time`symbol`price`volumn,[DATE, TIME, SYMBOL, DOUBLE, DOUBLE]), `trades);
share(table(1:0, `timestamp`symbol`open`high`low`close, [TIMESTAMP,SYMBOL,DOUBLE,DOUBLE,DOUBLE,DOUBLE]), `outputTable);
go
// create the threshold engine
thresholdEngine = createThresholdEngine(name="demo", threshold=1000000, metrics=<[first(price), max(price), min(price), last(price)]>, dummyTable=trades, outputTable=outputTable, thresholdColumn=`volumn, keyColumn=`symbol, timeColumn=[`date, `time]);

// insert data
thresholdEngine.append!(trade);

// query the result
select * from outputTable

Some of results are as follows:

timestamp symbol open high low close
2019.11.07 09:31:54.986 000001 99.98404977017083 100.52950904161203 99.56823161885143 100.5279260600172
2019.11.07 09:33:51.890 000001 100.51835866520182 100.92578917419537 100.49741881850642 100.70077057819347
2019.11.07 09:35:48.298 000001 100.71148486480116 100.787968895277 99.84565304366406 100.61527177638374
2019.11.07 09:37:49.058 000001 100.61627630640287 101.55438607632183 100.48305282644462 101.33690219670534
2019.11.07 09:39:44.562 000001 101.32348716112786 101.55176323080435 100.74830873960164 100.77029377058614
2019.11.07 09:41:38.118 000001 100.78262700690422 101.24037498458289 100.67253582042176 100.7765302780131

Description of the outputTable definition in this example:

When the engine is created, timeColumn, keyColumn, and metrics are specified, while outputThreshold=true and outputElapsedMicroseconds=true are not specified. Therefore, the columns of outputTable correspond to the following items in order:

outputTable column

Type Source Description
timestamp TIMESTAMP timeColumn=[date, time] Derived by combining date and time, and used to record the data time that triggered the current calculation.
symbol SYMBOL keyColumn=`symbol Grouping column, with the same type as the symbol column in the input table.
open DOUBLE first(price) The result of the first metric in metrics.
high DOUBLE max(price) The result of the second metric in metrics.
low DOUBLE min(price) The result of the third metric in metrics.
close DOUBLE last(price) The result of the fourth metric in metrics.

Example 2 Restrict calculations to specified trading sessions with sessionBegin and sessionEnd

// Prepare data
t = table(
    2024.01.02 2024.01.02 2024.01.02 2024.01.02 2024.01.02 as date,
    09:20:00.000 09:31:00.000 10:15:00.000 11:35:00.000 13:05:00.000 as time,
    `A`A`A`A`A as sym,
    10.1 10.2 10.3 10.4 10.5 as price,
    200 500 600 700 800 as volume
)
date time sym price volume
2024.01.02 09:20:00.000 A 10.1 200
2024.01.02 09:31:00.000 A 10.2 500
2024.01.02 10:15:00.000 A 10.3 600
2024.01.02 11:35:00.000 A 10.4 700
2024.01.02 13:05:00.000 A 10.5 800
// Create dummyTable and outputTable
share(streamTable(10:0, `date`time`sym`price`volume, [DATE, TIME, SYMBOL, DOUBLE, DOUBLE]), `trades1)
share(table(10:0, `timestamp`sym`sumVol, [TIMESTAMP, SYMBOL, DOUBLE]), `outputTable1)
go
// Create threshold engine
engine = createThresholdEngine(
    name="thresholdDemo1",
    threshold=1000,
    metrics=<[sum(volume)]>,
    dummyTable=trades1,
    outputTable=outputTable1,
    thresholdColumn=`volume,
    keyColumn=`sym,
    timeColumn=[`date, `time],
    sessionBegin=09:30:00.000 13:00:00.000,
    sessionEnd=11:30:00.000 15:00:00.000
)

// Insert data
engine.append!(t)

// Query the results
select * from outputTable1
timestamp sym sumVol
2024.01.02 10:15:00.000 A 1,100

Example 3 Control whether group states are cleared across trading days with keyPurgeDaily

// Prepare data
t = table(
    2024.01.02 2024.01.03 2024.01.03 as date,
    14:59:00.000 09:31:00.000 09:31:01.000 as time,
    `A`A`A as sym,
    10.1 10.2 10.3 as price,
    600 500 700 as volume
)

// Create dummyTable and outputTable
share(streamTable(10:0, `date`time`sym`price`volume, [DATE, TIME, SYMBOL, DOUBLE, DOUBLE]), `trades)
share(table(10:0, `timestamp`sym`sumVol, [TIMESTAMP, SYMBOL, DOUBLE]), `output1)
share(table(10:0, `timestamp`sym`sumVol, [TIMESTAMP, SYMBOL, DOUBLE]), `output2)
go

// keyPurgeDaily=true: clear the previous day's group state upon receiving data of a new date
engine1 = createThresholdEngine(
    name="thresholdDemo2_true",
    threshold=1000,
    metrics=<[sum(volume)]>,
    dummyTable=trades,
    outputTable=output1,
    thresholdColumn=`volume,
    keyColumn=`sym,
    timeColumn=[`date, `time],
    keyPurgeDaily=true
)

// keyPurgeDaily=false: keep the previous day's group state upon receiving data of a new date
engine2 = createThresholdEngine(
    name="thresholdDemo2_false",
    threshold=1000,
    metrics=<[sum(volume)]>,
    dummyTable=trades,
    outputTable=output2,
    thresholdColumn=`volume,
    keyColumn=`sym,
    timeColumn=[`date, `time],
    keyPurgeDaily=false
)

// Insert data
engine1.append!(t)
engine2.append!(t)

// Query the results
select * from output1
timestamp sym sumVol
2024.01.02 14:59:00.000 A 600
2024.01.03 09:31:01.000 A 1,200
select * from output2
timestamp sym sumVol
2024.01.03 09:31:00.000 A 1,100

Example 4 Output the elapsed time of each calculation with outputElapsedMicroseconds

// Prepare data
t = table(
    2024.01.02 2024.01.02 2024.01.02 as date,
    09:31:00.000 09:32:00.000 09:33:00.000 as time,
    `A`A`A as sym,
    10.1 10.2 10.3 as price,
    300 400 500 as volume
)

// Create dummyTable and outputTable

share(streamTable(10:0, `date`time`sym`price`volume, [DATE, TIME, SYMBOL, DOUBLE, DOUBLE]), `trades)
share(table(10:0, `timestamp`sym`elapsed`avgPrice`sumVol, [TIMESTAMP, SYMBOL, LONG, DOUBLE, DOUBLE]), `outputTable)
go
// Create threshold engine
engine = createThresholdEngine(
    name="thresholdDemo4",
    threshold=1000,
    metrics=<[avg(price), sum(volume)]>,
    dummyTable=trades,
    outputTable=outputTable,
    thresholdColumn=`volume,
    keyColumn=`sym,
    timeColumn=[`date, `time],
    outputElapsedMicroseconds=true
)

// Insert data
engine.append!(t)

// Query the results
select * from outputTable
timestamp sym elapsed avgPrice sumVol
2024.01.02 09:33:00.000 A 1 10.2 1,200
Example 5 Output the threshold window value and cumulative thresholdColumn with outputThreshold
// Prepare data
t = table(
    2024.01.02 2024.01.02 2024.01.02 as date,
    09:31:00.000 09:32:00.000 09:33:00.000 as time,
    `A`A`A as sym,
    10.1 10.2 10.3 as price,
    300 400 500 as volume
)

// Create dummyTable and outputTable
share(streamTable(10:0, `date`time`sym`price`volume, [DATE, TIME, SYMBOL, DOUBLE, DOUBLE]), `trades)
share(table(10:0, `timestamp`sym`thresholdValue`cumThreshold`lastPrice, [TIMESTAMP, SYMBOL, LONG, DOUBLE, DOUBLE]), `outputTable)
go

// Create threshold engine
engine = createThresholdEngine(
    name="thresholdDemo5",
    threshold=1000,
    metrics=<[last(price)]>,
    dummyTable=trades,
    outputTable=outputTable,
    thresholdColumn=`volume,
    keyColumn=`sym,
    timeColumn=[`date, `time],
    outputThreshold=true
)

// Insert data
engine.append!(t)

// Query the results
select * from outputTable
timestamp sym thresholdValue cumThreshold lastPrice
2024.01.02 09:33:00.000 A 1,000 1,200 10.3