Skip to content

Commit 8fa4a5f

Browse files
Add dynamic features
2 parents 07465b3 + c5807f0 commit 8fa4a5f

10 files changed

+201
-19
lines changed

docs/source/customization.rst

+8
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,11 @@ The ``.add_metric`` method takes 2 parameters :
5959
6060
6161
62+
.. note::
63+
64+
If you want to use your metrics to feed a custom logger, to visualize data or to track performance, you can access to results with ``env.get_metrics()`` **at the end of an episode**. In this case, it returns :
65+
66+
.. code-block:: python
67+
68+
{ "Market Return" : "25.30%", "Portfolio Return" : "45.24%", "Position Changes" : 28417, "Episode Lenght" : 33087 }
69+

docs/source/environment_desc.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ Observation Space
7878

7979
The observation space is an np.array containing:
8080

81-
* The row of your DataFrame columns containing ``features`` in their name, at a given step.
82-
* The current position of the environment to allow self-awareness for the agent. You can disable it by setting ``include_position_in_features`` to ``False``.
81+
* The row of your DataFrame columns containing ``features`` in their name, at a given step : the **static features**
82+
* The **dynamic features ** (by default, the last position taken by the agent, and the current real position).
8383
8484
.. code-block:: python
8585

docs/source/features.rst

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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+

docs/source/history.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ It was made to make everything easier :
2121
'step': 33091, #Step = t.
2222
'date': numpy.datetime64('2022-03-01T00:00:00.000000000'), #Date at step t, datetime.
2323
'position_index': 2, #Index of the position at step t among your position list.
24-
'position': 1, #Portfolio position at step t.
24+
'position': 1, # Last position taken by the agent.
25+
'real_position': 1.09848, # Real portfolio position = (asset owned - asset borrowed - asset interests) * current price / portfolio valuation
2526
'reward': 0.0028838985262525257, #Reward at step t.
2627
2728
# DataFrame info : Every column (except features) of your initial DataFrame preceded by 'data_'

docs/source/index.rst

+1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ Contents
8888

8989
rl_tutorial
9090
customization
91+
features
9192
multi_datasets
9293
vectorize_env
9394

docs/source/rl_tutorial.rst

+8-3
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ Create your features
8989
--------------------
9090

9191
Your RL-agent will need inputs. It is your job to make sure it has everything it needs.
92-
**The environment will recognize as inputs every column that contains the keyword 'feature' in its name.**
92+
9393

9494
.. code-block:: python
9595
@@ -112,10 +112,15 @@ Your RL-agent will need inputs. It is your job to make sure it has everything it
112112
113113
df.dropna(inplace= True) # Clean again !
114114
# Eatch step, the environment will return 5 inputs : "feature_close", "feature_open", "feature_high", "feature_low", "feature_volume"
115-
115+
116+
.. important::
117+
118+
The environment will recognize as inputs every column that contains the keyword '**feature**' in its name.
119+
120+
116121
.. note::
117122

118-
By default, the env will always add the **position reached** at the end of all your custom features. Indeed, in Reinforcement Learning, I find it really useful for the agent to know its current position. To disable this, you need to set the ``include_position_in_features`` parameter of the environment to ``False``.
123+
By default, the env will always add the 2 dynamics features. More informations in the **Feature** page.
119124

120125

121126
Create your first environment

examples/example_environnement.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,6 @@ def reward_function(history):
5050
while not done and not truncated:
5151
action = env.action_space.sample()
5252
observation, reward, done, truncated, info = env.step(action)
53-
53+
print(observation)
5454
# Save for render
55-
env.save_for_render()
55+
# env.save_for_render()

0 commit comments

Comments
 (0)