Buckets:
| # FinRL Environment | |
| A wrapper around [FinRL](https://github.com/AI4Finance-Foundation/FinRL) stock trading environments that conforms to the OpenEnv specification. | |
| ## Overview | |
| This environment enables reinforcement learning for stock trading tasks using FinRL's powerful StockTradingEnv, exposed through OpenEnv's simple HTTP API. It supports: | |
| - **Stock Trading**: Buy/sell actions across multiple stocks | |
| - **Portfolio Management**: Track balance, holdings, and portfolio value | |
| - **Technical Indicators**: MACD, RSI, CCI, DX, and more | |
| - **Flexible Configuration**: Custom data sources and trading parameters | |
| ## Quick Start | |
| ### 1. Build the Docker Image | |
| First, build the base image (from OpenEnv root): | |
| ```bash | |
| cd OpenEnv | |
| docker build -t envtorch-base:latest -f src/openenv/core/containers/images/Dockerfile . | |
| ``` | |
| Then build the FinRL environment image: | |
| ```bash | |
| docker build -t finrl-env:latest -f envs/finrl_env/server/Dockerfile . | |
| ``` | |
| ### 2. Run the Server | |
| #### Option A: With Default Sample Data | |
| ```bash | |
| docker run -p 8000:8000 finrl-env:latest | |
| ``` | |
| This starts the server with synthetic sample data for testing. | |
| #### Option B: With Custom Configuration | |
| Create a configuration file `config.json`: | |
| ```json | |
| { | |
| "data_path": "/data/stock_data.csv", | |
| "stock_dim": 3, | |
| "hmax": 100, | |
| "initial_amount": 100000, | |
| "num_stock_shares": [0, 0, 0], | |
| "buy_cost_pct": [0.001, 0.001, 0.001], | |
| "sell_cost_pct": [0.001, 0.001, 0.001], | |
| "reward_scaling": 0.0001, | |
| "state_space": 25, | |
| "action_space": 3, | |
| "tech_indicator_list": ["macd", "rsi_30", "cci_30", "dx_30"] | |
| } | |
| ``` | |
| Run with configuration: | |
| ```bash | |
| docker run -p 8000:8000 \ | |
| -v $(pwd)/config.json:/config/config.json \ | |
| -v $(pwd)/data:/data \ | |
| -e FINRL_CONFIG_PATH=/config/config.json \ | |
| finrl-env:latest | |
| ``` | |
| ### 3. Use the Client | |
| ```python | |
| from envs.finrl_env import FinRLEnv, FinRLAction | |
| import numpy as np | |
| # Connect to server | |
| client = FinRLEnv(base_url="http://localhost:8000") | |
| # Get configuration | |
| config = client.get_config() | |
| print(f"Trading {config['stock_dim']} stocks") | |
| print(f"Initial capital: ${config['initial_amount']:,.0f}") | |
| # Reset environment | |
| result = client.reset() | |
| print(f"Initial portfolio value: ${result.observation.portfolio_value:,.2f}") | |
| # Trading loop | |
| for step in range(100): | |
| # Get current state | |
| state = result.observation.state | |
| # Your RL policy here (example: random actions) | |
| num_stocks = config['stock_dim'] | |
| actions = np.random.uniform(-1, 1, size=num_stocks).tolist() | |
| # Execute action | |
| result = client.step(FinRLAction(actions=actions)) | |
| print(f"Step {step}: Portfolio=${result.observation.portfolio_value:,.2f}, " | |
| f"Reward={result.reward:.2f}") | |
| if result.done: | |
| print("Episode finished!") | |
| break | |
| client.close() | |
| ``` | |
| ## Architecture | |
| ``` | |
| ┌─────────────────────────────────────────────────────────────┐ | |
| │ RL Training Framework │ | |
| │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ | |
| │ │ Policy Net │ │ Value Net │ │ Replay │ │ | |
| │ │ (PyTorch) │ │ (PyTorch) │ │ Buffer │ │ | |
| │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ | |
| │ └──────────────────┴──────────────────┘ │ | |
| │ │ │ | |
| │ ┌────────▼────────┐ │ | |
| │ │ FinRLEnv │ ← HTTP Client │ | |
| │ │ (HTTPEnvClient) │ │ | |
| │ └────────┬────────┘ │ | |
| └────────────────────────────┼─────────────────────────────────┘ | |
| │ HTTP (JSON) | |
| ┌────────▼────────┐ | |
| │ Docker Container│ | |
| │ Port: 8000 │ | |
| │ │ | |
| │ ┌─────────────┐ │ | |
| │ │FastAPI │ │ | |
| │ │Server │ │ | |
| │ └──────┬──────┘ │ | |
| │ │ │ | |
| │ ┌──────▼──────┐ │ | |
| │ │ FinRL │ │ | |
| │ │ Environment │ │ | |
| │ └──────┬──────┘ │ | |
| │ │ │ | |
| │ ┌──────▼──────┐ │ | |
| │ │ FinRL │ │ | |
| │ │ StockTrading│ │ | |
| │ │ Env │ │ | |
| │ └─────────────┘ │ | |
| └─────────────────┘ | |
| ``` | |
| ## API Reference | |
| ### FinRLAction | |
| Trading action for the environment. | |
| **Attributes:** | |
| - `actions: list[float]` - Array of normalized action values (-1 to 1) for each stock | |
| - Positive values: Buy | |
| - Negative values: Sell | |
| - Magnitude: Relative trade size | |
| **Example:** | |
| ```python | |
| # Buy stock 0, sell stock 1, hold stock 2 | |
| action = FinRLAction(actions=[0.5, -0.3, 0.0]) | |
| ``` | |
| ### FinRLObservation | |
| Observation returned by the environment. | |
| **Attributes:** | |
| - `state: list[float]` - Flattened state vector | |
| - Structure: `[balance, prices..., holdings..., indicators...]` | |
| - `portfolio_value: float` - Total portfolio value (cash + holdings) | |
| - `date: str` - Current trading date | |
| - `done: bool` - Whether episode has ended | |
| - `reward: float` - Reward for the last action | |
| - `metadata: dict` - Additional information | |
| **Example:** | |
| ```python | |
| obs = result.observation | |
| print(f"Portfolio: ${obs.portfolio_value:,.2f}") | |
| print(f"Date: {obs.date}") | |
| print(f"State dimension: {len(obs.state)}") | |
| ``` | |
| ### Client Methods | |
| #### `reset() -> StepResult[FinRLObservation]` | |
| Reset the environment to start a new episode. | |
| ```python | |
| result = client.reset() | |
| ``` | |
| #### `step(action: FinRLAction) -> StepResult[FinRLObservation]` | |
| Execute a trading action. | |
| ```python | |
| action = FinRLAction(actions=[0.5, -0.3]) | |
| result = client.step(action) | |
| ``` | |
| #### `state() -> State` | |
| Get episode metadata (episode_id, step_count). | |
| ```python | |
| state = client.state() | |
| print(f"Episode: {state.episode_id}, Step: {state.step_count}") | |
| ``` | |
| #### `get_config() -> dict` | |
| Get environment configuration. | |
| ```python | |
| config = client.get_config() | |
| print(config['stock_dim']) | |
| print(config['initial_amount']) | |
| ``` | |
| ## Data Format | |
| The environment expects stock data in the following CSV format: | |
| | date | tic | close | high | low | open | volume | macd | rsi_30 | cci_30 | dx_30 | | |
| |------------|--------|--------|--------|--------|--------|---------|-------|--------|--------|-------| | |
| | 2020-01-01 | AAPL | 100.0 | 102.0 | 98.0 | 99.0 | 1000000 | 0.5 | 55.0 | 10.0 | 15.0 | | |
| | 2020-01-01 | GOOGL | 1500.0 | 1520.0 | 1480.0 | 1490.0 | 500000 | -0.3 | 48.0 | -5.0 | 20.0 | | |
| **Required columns:** | |
| - `date`: Trading date | |
| - `tic`: Stock ticker symbol | |
| - `close`, `high`, `low`, `open`: Price data | |
| - `volume`: Trading volume | |
| - Technical indicators (as specified in `tech_indicator_list`) | |
| ## Configuration Parameters | |
| | Parameter | Type | Description | | |
| |-----------|------|-------------| | |
| | `data_path` | str | Path to CSV file with stock data | | |
| | `stock_dim` | int | Number of stocks to trade | | |
| | `hmax` | int | Maximum shares per trade | | |
| | `initial_amount` | int | Starting cash balance | | |
| | `num_stock_shares` | list[int] | Initial holdings for each stock | | |
| | `buy_cost_pct` | list[float] | Transaction cost for buying (per stock) | | |
| | `sell_cost_pct` | list[float] | Transaction cost for selling (per stock) | | |
| | `reward_scaling` | float | Scaling factor for rewards | | |
| | `state_space` | int | Dimension of state vector | | |
| | `action_space` | int | Dimension of action space | | |
| | `tech_indicator_list` | list[str] | Technical indicators to include | | |
| ## Integration with RL Frameworks | |
| ### Stable Baselines 3 | |
| ```python | |
| from stable_baselines3 import PPO | |
| from envs.finrl_env import FinRLEnv, FinRLAction | |
| import numpy as np | |
| # Create custom wrapper for SB3 | |
| class SB3FinRLWrapper: | |
| def __init__(self, base_url): | |
| self.env = FinRLEnv(base_url=base_url) | |
| config = self.env.get_config() | |
| self.action_space = spaces.Box( | |
| low=-1, high=1, | |
| shape=(config['action_space'],), | |
| dtype=np.float32 | |
| ) | |
| self.observation_space = spaces.Box( | |
| low=-np.inf, high=np.inf, | |
| shape=(config['state_space'],), | |
| dtype=np.float32 | |
| ) | |
| def reset(self): | |
| result = self.env.reset() | |
| return np.array(result.observation.state, dtype=np.float32) | |
| def step(self, action): | |
| result = self.env.step(FinRLAction(actions=action.tolist())) | |
| return ( | |
| np.array(result.observation.state, dtype=np.float32), | |
| result.reward or 0.0, | |
| result.done, | |
| result.observation.metadata | |
| ) | |
| # Train | |
| env = SB3FinRLWrapper("http://localhost:8000") | |
| model = PPO("MlpPolicy", env, verbose=1) | |
| model.learn(total_timesteps=10000) | |
| ``` | |
| ## Troubleshooting | |
| ### Server won't start | |
| 1. Check if base image exists: | |
| ```bash | |
| docker images | grep envtorch-base | |
| ``` | |
| 2. Build base image if missing: | |
| ```bash | |
| docker build -t envtorch-base:latest -f src/openenv/core/containers/images/Dockerfile . | |
| ``` | |
| ### Import errors | |
| Make sure you're in the `src` directory: | |
| ```bash | |
| cd OpenEnv/src | |
| python -c "from envs.finrl_env import FinRLEnv" | |
| ``` | |
| ### Configuration errors | |
| Verify your data file has all required columns: | |
| ```python | |
| import pandas as pd | |
| df = pd.read_csv('your_data.csv') | |
| print(df.columns.tolist()) | |
| ``` | |
| ## Examples | |
| See the `examples/` directory for complete examples: | |
| - `examples/finrl_simple.py` - Basic usage | |
| - `examples/finrl_training.py` - Full training loop with PPO | |
| - `examples/finrl_backtesting.py` - Backtesting a trained agent | |
| ## License | |
| BSD 3-Clause License (see LICENSE file in repository root) | |
| ## References | |
| - [FinRL Paper](https://arxiv.org/abs/2011.09607) | |
| - [FinRL GitHub](https://github.com/AI4Finance-Foundation/FinRL) | |
| - [OpenEnv Documentation](README) | |
Xet Storage Details
- Size:
- 10.9 kB
- Xet hash:
- 0b6e6d1a646625be88e27cba0c03fc8a38535c94a4905acdbc0422d9f206213e
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.