intelligent-trading-bot/docs/labels.md

12 KiB

Labels

Labels as features generated from future data

Labels are normal columns that serve a special purpose in the context of ML features.

What is an ML feature? It is a standard feature defined in terms of other features that generates one or more new features with derived values. What distinguishes it is how it is configured. While standard features are configured using static parameters in their definition, ML features are configured using parameters stored in their trainable model.

What is the difference between static parameters and parameters in an ML model? The main difference is that parameters in standard feature definitions are provided by domain experts, often based on ad-hoc analysis. For example, we might choose to use a 20-day moving average and specify this number as a parameter in the feature definition. If the results are unsatisfactory, we could test another value, such as a 30-day moving average. In contrast, ML model parameter values are determined automatically during a specialized process called training. Training is a distinct run mode that signals ML features to derive their own parameters by analyzing available data and storing the optimal parameters in the ML model (rather than relying on parameters in the feature definition). The ML feature detects this "train" mode, uses the available data to find optimal parameters, and applies these parameters to generate output. The output of ML features is referred to as predictions.

Crucially, training an ML algorithm typically (though not always) requires training data represented by features and ground truth data represented by labels. Labels can be viewed as standard columns in the training dataset that play a special role during training but are neither needed nor used during prediction. In time-series analysis, labels typically represent future events. For example, a label column might equal the future value of an existing feature column, such as price. In this case, the label column is generated by shifting the price column so that each row contains both the current price as a standard feature and a label representing the future value of that same feature. These must reside in the same row so the forecasting algorithm can train its parameters effectively. In more complex scenarios, a label could represent a compound event, such as whether the price increases by 3% over the next 10 days.

Technically, both features and labels are columns computed from other columns. Their primary distinction is that features are computed from historical data, while labels are computed from future data. In fact, they could sometimes be implemented as a single feature where the use of past or future data is controlled by a configuration parameter. For example, we could implement a moving average calculation using either past or future data based on the sign of the window length: a positive sign indicates the use of past data, while a negative sign indicates the use of future data (and thus designates it as a label).

Label definitions

Labels are defined exactly like features; each label has a definition with the same structure as a feature definition. However, because labels serve a special role and are required only in train mode, they are defined in a dedicated section:

"label_sets": [
  {...}, // First label
  {...}, // Second label
  {...} // Third label
]

In train mode, when "train": true is set in the configuration file, all columns corresponding to the label definitions are generated. Both feature and label columns are then used by ML features to train their models. These trained models are subsequently used to generate output features as predictions.

Label columns are computed by generators, and every label definition includes a generator attribute. ITB provides built-in generators such as topbot2 and highlow2, described below. However, custom label generators can also be defined in exactly the same manner as custom features.

topbot2 label generator

topbot2 is a label generator that produces binary values by evaluating the future and past values of a single input column. This input column is typically price, but it can be any numeric column, such as a technical indicator like a moving average. The goal is to predict a binary event based on the future and past behavior of this input column. The input column name is specified in the columns attribute, for example: columns: "price".

This generator returns either true or false depending on whether the current value is a maximum or minimum relative to its neighbors. The choice to return all maxima (as true values) or all minima (also as true values) is controlled by the function attribute, which accepts either top (to identify all maxima) or bot (to identify all minima). For example, if function: "top", the computed label column will be true when the price reaches a relative maximum at that time step.

A relative maximum (top) means the value exceeds its left and right minima by a specified margin. While the algorithm identifies all minima and maxima, it does not select all of them. It selects only those maxima surrounded by two minima (one on the left and one on the right) where both differences meet a minimum threshold. The minimum required difference between adjacent extrema is specified in the level attribute. For example, when identifying tops with level: 0.02, a true label at the current moment indicates there exists a past minimum (bottom) with a price 2% lower and a future minimum also 2% lower. Note that the existence of these two minima implies they each have adjacent maxima that are 2% higher. Also note that the minimum level between an adjacent minimum and maximum is specified as a factor or proportion (not as a percentage), and this value is always positive.

Once all maximum and minimum values meeting the required distance criteria are identified, they are marked as true. However, direct neighbors are sometimes nearly equal to the maximum or minimum. For instance, the maximum price might be 45,678 while the preceding or succeeding price is 45,679—only slightly lower. In such cases, we may want to treat these points as tops or bottoms in the price trajectory as well. To accommodate this, the generator provides a tolerances attribute, which is a list of numeric values.

Each tolerance is interpreted as a fraction of the level (where the level itself is a fraction of the price). For example, if the level is 0.1 (10% price change) and the tolerance is 0.2 (20% of the level), the resulting price tolerance is 0.02 (2%). If the identified top price is 100.0, its immediate neighbors with prices between 98.0 and 100.0 will also be marked as tops (returning true). Note that the left and right minima must still have a price of 90.0 or lower, since the level is 0.1 (10% of the price).

Below is an example that defines two binary label columns:

"label_sets": [
  {
    "generator": "topbot2",
    "column_prefix": "",
    "feature_prefix": "",
    "config":  {"columns": "close", "function": "top", "level": 0.02, "tolerances": [0.1], "names": ["top_2"]}
  },
  {
    "generator": "topbot2",
    "column_prefix": "",
    "feature_prefix": "",
    "config":  {"columns": "close", "function": "bot", "level": 0.02, "tolerances": [0.1], "names": ["bot_2"]}
  }
]

The first label definition (in train mode) generates a binary column that is true when the close price is a maximum relative to left and right minima, requiring a minimum price change of 2% with a 0.2% tolerance. The second label definition identifies all bottom values using the same level and tolerance. The desired output column names are specified in the names attribute.

These labels can be used to train a classification ML algorithm. In prediction mode, the algorithm will estimate the probability that the current price is a local maximum (top) and is therefore likely to drop significantly in the near future, or, for the second label, that it is a local minimum (bottom) and is likely to rise in the near future.

highlow2 label generator

This label generator returns true or false values by determining whether the price increases (or decreases) significantly within a specified future time horizon.

The generator accepts the following configuration parameters:

  • function: Either high or low.
    • high returns true if the price increases significantly; otherwise, it returns false.
    • low returns true if the price decreases significantly; otherwise, it returns false.
  • columns: A list of three column names whose roles depend on their position in the list:
    • The first column determines the current (reference) price. This is frequently (but not necessarily) the close price.
    • The second column determines the price increase and whether the reference price has risen significantly. This is frequently (but not necessarily) the high price.
    • The third column determines the price decrease and whether the reference price has fallen significantly. This is frequently (but not necessarily) the low price.
  • thresholds: A list of percentage values defining how much the price must increase (or decrease) for the generator to return true. One output column is generated for each threshold value.
  • tolerance: A factor relative to the thresholds used to determine acceptable adverse price movement relative to the reference (close) price. For example, a value of 1.0 equals the full threshold, while 0.5 represents 50% of the threshold. This defines the allowable price move in the direction opposite to the expected trend. If the price moves in this adverse direction beyond the specified tolerance before reaching the target threshold, the generator returns false.
  • horizon: The number of future rows over which the analysis is performed. If the price fails to reach the required level within this period, the generator returns false.

Below is an example of two label definitions that generate four binary output columns:

"label_sets": [
  {
    "generator": "highlow2",
    "column_prefix": "",
    "feature_prefix": "",
    "config":  {
      "columns": ["close", "high", "low"],
      "function": "high",
      "thresholds": [2.0, 4.0], "tolerance": 0.5, "horizon": 10,
      "names": ["high_2", "high_3"]
    }
  },
  {
    "column_prefix": "",
    "generator": "highlow2",
    "feature_prefix": "",
    "config":  {
      "columns": ["close", "high", "low"],
      "function": "low",
      "thresholds": [2.0, 4.0], "tolerance": 0.5, "horizon": 10,
      "names": ["low_2", "low_3"]
    }
  }
]

The first generator detects sufficiently significant increases in the close price over the next 10 time intervals. Specifically, it returns two columns: the first identifies 2% price increases (relative to the close price, using the high price), and the second detects stronger 4% increases (with all other parameters held constant). Importantly, if the price drops by 1% (tolerance × 2% threshold) or 2% (for the second output) before reaching its target threshold, the generator returns false.

The combination of thresholds and tolerance functions similarly to TP (Take Profit) and SL (Stop Loss) levels in trading, which define opposing price targets. The order in which these levels are reached is critical. If the threshold (TP) is reached before the tolerance limit (SL) is breached—and this occurs within the horizon—true is returned.

If the tolerance is set to 0.0, the label returns true only if the price never falls below the current value before the threshold is reached. Because this scenario is rare and minor fluctuations before a significant move are generally acceptable, a zero tolerance is usually impractical. Therefore, the tolerance parameter should specify a value representing minor random movement or noise that should be disregarded when identifying significant changes.