conditionalIterate

Syntax

conditionalIterate(cond, trueValue, falseIterFunc)

This function can only be used as a state function in the reactive state engine.

Arguments

cond is a conditional expression or a function with BOOLEAN return values. It must contain fields from the input table. Constants/constant expressions are not supported.

trueValue is the calculation formula.

falseIterFunc is the function for iteration, whose only parameter is the column from the output table. Currently, only the following functions are supported (use partial application to specify functions with multiple parameters):

  • Moving functions: tmove, tmavg, tmmax, tmmin, tmsum, mavg, mmax, mmin, mcount, msum;

  • Cumulative window functions: cumlastNot, cumfirstNot;

  • Order-sensitive functions: ffill, move.

If cond returns true, the calculation of trueValue is triggered. If cond returns false, falseIterFunc is called for iteration.

Note:

  • As the iterations are performed based on the historical data, the output for the current record is calculated based on the historical results in the output table and X.

  • When calculating with time-based moving windows, windows are determined by the current timestamp T, i.e., (T - window, T).

  • The data type of the result column is determined by the result of trueValue. Therefore, the data type of the result of trueValue and falseIterFunc must be compatible. Data type compatibility rules:

    • INT, SHORT, LONG and CHAR are compatible;

    • FLOAT and DOUBLE are compatible;

    • STRING and SYMBOL are compatible.

Details

Supposing the iteration is based only on the previous result, for the k-th (k ∈ N+) record, the calculation logic is (where the column "factor" holds the results):

  • cond[k] == true: factor[k] = trueValue
  • cond[k] == false: factor[k] = falseIterFunc(factor)[k-1]

Note: If falseIterFunc is a window function, the iteration is based on multiple previous results.

Examples

Example 1. Understand the calculation logic of conditionalIterate with the following example.

trade = table(take("A", 10) as sym,  take(1 3 6, 10) as val0,  take(10, 10) as val1)
trade
sym val0 val1
A 1 10
A 3 10
A 6 10
A 1 10
A 3 10
A 6 10
A 1 10
A 3 10
A 6 10
A 1 10

Define a reactive state stream engine and group the data by "sym" for calculation.

  • If val0 > 5 returns true, the formula is factor[k]=trueValue. Output the value of val1.

  • If val0 > 5 returns false, the corresponding formula is factor[k]=falseIterFunc(factor)[k-1]. When k=3, then the corresponding val0=1, val1=10, factor=[NULL, NULL, 10], the result is msum([NULL, NULL, 10], 3)[2]=10. Similarly, when k=4, the corresponding val0=3, val1=10, factor=[NULL, NULL, 10, 10], the result is msum([NULL, NULL, 10, 10], 3)[3]=20.

inputTable = streamTable(1:0, `sym`val0`val1, [SYMBOL, INT, INT])
outputTable = table(100:0, `sym`factor, [STRING, DOUBLE])
rse = createReactiveStateEngine(name="rsTest", metrics=<conditionalIterate(val0 > 5, val1, msum{, 3})>, dummyTable=inputTable, outputTable=outputTable, keyColumn="sym")
rse.append!(trade)
select * from outputTable
sym factor
A
A
A 10
A 10
A 20
A 10
A 40
A 70
A 10
A 120

Example 2. The calculation logic of "factor":

def factor(TotalVolumeTrade, TotalValueTrade, HighPx, LowPx){
    factorValue = iif(TotalVolumeTrade < 1500000, pow(HighPx*LowPx, 0.5)-(TotalVolumeTrade/TotalValueTrade), mavg(factor(TotalVolumeTrade, TotalValueTrade, HighPx, LowPx), 3))
    return factorValue
}

The calculation of factor involves recursion. You can use function conditionalIterate to implement the factor in a reactive state engine with the following script:

@state
def factor1(TotalVolumeTrade, TotalValueTrade, HighPx, LowPx){
   factorValue = conditionalIterate(TotalVolumeTrade < 1500000, (pow(HighPx*LowPx, 0.5)-(TotalVolumeTrade/TotalValueTrade)), mavg{,3})
   return factorValue
}

SecurityID =  ["000001.SZ","000001.SZ","000001.SZ","000001.SZ","000001.SZ","000001.SZ","000001.SZ","000001.SZ","000001.SZ","000001.SZ"]$SYMBOL
Date = [2022.04.01,2022.04.01,2022.04.01,2022.04.01,2022.04.01,2022.04.01,2022.04.01,2022.04.01,2022.04.01,2022.04.01]
Time = [09:30:00.000,09:30:03.000,09:30:06.000,09:30:09.000,09:30:12.000,09:30:15.000,09:30:18.000,09:30:21.000,09:30:24.000,09:30:27.000]
TotalVolumeTrade = [844800,1035700,1240100,1304500,1457800,1522400,1550900,1663800,1692100,1767100]
TotalValueTrade = [12982101,15908020,19038479,20022525,22363886,23349799,23784950,25506625.75,25937850.75,27080561.75]
HighPx = [15.37,15.37,15.37,15.37,15.37,15.37,15.37,15.37,15.37,15.37]
LowPx = [15.3,15.3,15.29,15.28,15.24,15.24,15.24,15.22,15.22,15.22]
trade = table(SecurityID, Date, Time, TotalVolumeTrade, TotalValueTrade, HighPx, LowPx)

result = table(1:0, `SecurityID`Date`Time`Factor, `SYMBOL`DATE`TIME`DOUBLE)

factor=[<Date>,<Time>, <factor1(TotalVolumeTrade, TotalValueTrade, HighPx, LowPx)>]
rse = createReactiveStateEngine(name="rsTest", metrics=factor, dummyTable=trade, outputTable=result, keyColumn="SecurityID")
rse.append!(trade)

trade1 = select *,  (pow(HighPx*LowPx, 0.5)-(TotalVolumeTrade/TotalValueTrade)) as Factor0 from trade
select * from lj(trade1, result, `SecurityID`Date`Time)
dropStreamEngine("rsTest")

The following is part of the result:

For records in blue box, data in column Factor is the results of trueValue, which are the same as the output in Factor0. For records in red box, data in column Factor is the results of falseIterFunc, and each of them is the average of the previous three results.

Related functions: stateIterate