Investment Studio > Expressions > Functions > Matrix > CROSSES
| Scalar form: | float array[*][2] crosses(float array[*][*] values, integer value_column, float threshold) |
| Array form: | float array[*][2] crosses(float array[*][*] values, integer value_column, float array[*][*] thresholds, integer threshold_column) |
Returns a two-column listing of all occasions when a value in the value_column of the values array crosses the specified threshold(s).
If the value in column value_column, row n of the values array crosses a threshold, the result table will contain a row with the following entries:
| Column # | Content | ||||
| 1 | The value in column 1, row n of the values array. | ||||
| 2 |
|
Just touching the threshold does not count; if the threshold is touched from above, the value is still considered to be above the threshold, and vice versa.
The difference between scalar and array form lies in how thresholds are specified:
| Scalar form means that a single, constant threshold is used. | |
| Array
form means that threshold values are looked up
in the specified threshold_column of the thresholds
array. Rows in values and thresholds are synchronised based on the contents of their first column, which is assumed to contain chronological serial numbers (larger serial number = later time). For a crossing to be reported, two consecutive values must be on opposite sides of the last known threshold value in their respective position. The second value's position is the crossing's reported position. Note that this crossing criterion does not rely on linear interpolation of values and thresholds, and may not yield the same result as looking for an intercept between linearly interpolated values and thresholds when their "time coordinates" differ (see example below). |
| IMPORTANT: All array arguments must be time-sorted in ascending order: values and (if used) thresholds must be arranged so that row 1 contains the earliest (i.e. oldest) entry and the last row contains the latest (i.e. most recent) entry. |
Scalar example
Given the array
_values = {{15, 8}, {25, 5}, {35, 9}, {45, 7}}
the expression
=crosses(array(_values), 2, 6)
returns {{25, -1}, {35, 1}}.
The first row in the result ({25, -1}) means that the entries in column 2 (the value_column) of the _values array cross the constant threshold = 6 from above (hence the -1 in the result) at serial number 25 (first column of the _values array).
The second row in the result ({35, 1}) describes a second crossing of the threshold, this time from below, at serial number 35.
Given arrays
_values = {{15, 8}, {25, 5}, {35, 9}, {45, 7}}
and
_thresholds = {{10, -7, 10}, {25, 8, 5}, {30, 1, 15}, {45, 3, 0}}
the expression
=crosses(array(_values), 2, array(_thresholds), 3)
returns {{45, 1}}.
Here, the threshold values are specified in column 3 of the _thresholds array.
The first and third threshold rows, with serial numbers 10 and 30, do not match any entry in the _values array.
The second threshold row ({25, 8, 5}) does match a value row ({25, 5}) but is not a crossing since the value (5) equals the threshold exactly (touching is not the same as crossing). A crossing would be reported here if the threshold were any smaller (e.g. 4.9) or the value any larger (e.g. 5.1).
The fourth threshold row ({45, 3, 0}) also matches a value row ({45, 7}). The value (7) is above the threshold (0), while the previous value (9) is below the previous threshold (15). A crossing from below (1) is therefore reported.
Note that this conclusion is not watertight, since the previous value and threshold have different "time coordinates". To see this clearly, consider a third value row modified to {44, 9}. A straight line drawn in a rectangular coordinate system between value points (44, 9) and (45, 7) doesn't cross a straight line drawn between threshold points (30, 15) and (45, 0), but a crossing will still be reported. Whether this is right or wrong depends on the context (is linear interpolation in the serial number meaningful? are thresholds and values continuous?).