|
| 1 | +Features |
| 2 | +======== |
| 3 | + |
| 4 | +As seen previously in the tutorial. We can easily create features that will be returned as observation at each time step. |
| 5 | +This type of feature is called a **static feature** as it is computed once, at the very beggining of the DataFrame processing. |
| 6 | + |
| 7 | +.. hint:: |
| 8 | + |
| 9 | + **But what if you want to use a feature that we can not pre-compute ?** |
| 10 | + |
| 11 | +In this case, you will use a **dynamic feature** that will be compute at each step. |
| 12 | + |
| 13 | +Create static features |
| 14 | +---------------------- |
| 15 | + |
| 16 | +.. code-block:: python |
| 17 | +
|
| 18 | + # df is a DataFrame with columns : "open", "high", "low", "close", "Volume USD" |
| 19 | + |
| 20 | + # Create the feature : ( close[t] - close[t-1] )/ close[t-1] |
| 21 | + df["feature_close"] = df["close"].pct_change() |
| 22 | + |
| 23 | + # Create the feature : open[t] / close[t] |
| 24 | + df["feature_open"] = df["open"]/df["close"] |
| 25 | + |
| 26 | + # Create the feature : high[t] / close[t] |
| 27 | + df["feature_high"] = df["high"]/df["close"] |
| 28 | + |
| 29 | + # Create the feature : low[t] / close[t] |
| 30 | + df["feature_low"] = df["low"]/df["close"] |
| 31 | + |
| 32 | + # Create the feature : volume[t] / max(*volume[t-7*24:t+1]) |
| 33 | + df["feature_volume"] = df["Volume USD"] / df["Volume USD"].rolling(7*24).max() |
| 34 | + |
| 35 | + df.dropna(inplace= True) # Clean again ! |
| 36 | + # Eatch step, the environment will return 5 static inputs : "feature_close", "feature_open", "feature_high", "feature_low", "feature_volume" |
| 37 | +
|
| 38 | + env = gym.make('TradingEnv', |
| 39 | + df = df, |
| 40 | + .... |
| 41 | + ) |
| 42 | +
|
| 43 | +
|
| 44 | +.. important:: |
| 45 | + |
| 46 | + The environment will recognize as inputs every column that contains the keyword '**feature**' in its name. |
| 47 | + |
| 48 | +Create dynamic features |
| 49 | +----------------------- |
| 50 | + |
| 51 | +A **dynamic feature** is computed at each step. Be careful, dynamic features are *much less efficient* in terms of computing time than static features. |
| 52 | + |
| 53 | +.. important:: |
| 54 | + |
| 55 | + What is presented below is the default configuration of the dynamic features. |
| 56 | + |
| 57 | +.. code-block:: python |
| 58 | +
|
| 59 | + def dynamic_feature_last_position_taken(history): |
| 60 | + return history['position', -1] |
| 61 | +
|
| 62 | + def dynamic_feature_real_position(history): |
| 63 | + return history['real_position', -1] |
| 64 | + |
| 65 | + env = gym.make( |
| 66 | + "TradingEnv", |
| 67 | + df = df, |
| 68 | + dynamic_feature_functions = [dynamic_feature_last_position_taken, dynamic_feature_real_position], |
| 69 | + ... |
| 70 | + ) |
| 71 | +
|
| 72 | +At each step, the environment will compute and add these 2 features at the end of the *observation*. |
| 73 | + |
| 74 | + |
0 commit comments