Spaces:
Sleeping
Sleeping
File size: 7,297 Bytes
3a7314c 147e9ed 3a7314c 147e9ed 3a7314c 147e9ed 3a7314c 147e9ed 3a7314c 147e9ed 3a7314c 147e9ed 3a7314c 147e9ed 3a7314c 147e9ed 3a7314c 147e9ed 3a7314c 147e9ed 3a7314c 147e9ed 3a7314c 147e9ed 3a7314c 147e9ed 3a7314c 147e9ed 3a7314c 147e9ed 3a7314c 147e9ed 3a7314c 147e9ed 3a7314c 147e9ed 3a7314c 147e9ed 3a7314c 147e9ed 3a7314c 147e9ed 3a7314c 147e9ed 31e81ea 3a7314c 147e9ed | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | ---
title: IndicatorsEnv
emoji: π
colorFrom: indigo
colorTo: blue
sdk: docker
pinned: true
tags:
- openenv
- reinforcement-learning
- finance
- stock-market
- technical-analysis
- rl-environment
license: mit
---
# IndicatorsEnv v4.1 β Multi-stock Portfolio MDP
> **An OpenEnv-compatible RL environment where agents learn within-sector relative alpha on real NSE (India) equities β with genuine portfolio capital dynamics.**
---
## Environment Description
`IndicatorsEnv` simulates the task a quantitative portfolio manager performs: given 3 stocks from the **same sector**, identify which has the strongest relative momentum signal, declare a direction, and set a conviction level. Reward is the **market-neutral alpha** the agent captures β the chosen stock's return minus the sector average.
### Why Multi-stock + Portfolio State
Single-stock environments collapse to contextual bandits once you remove multi-step structure. IndicatorsEnv v4.1 solves this with two sources of genuine MDP state:
1. **Signal history** β RSI trends, price momentum, and past pick outcomes accumulate across steps. The agent can detect multi-week divergence patterns.
2. **Portfolio capital** β `current_holding`, `capital`, and `drawdown` are in every observation. Switching holdings costs 0.1% of capital. This creates a real exploration-exploitation tradeoff: staying in a position avoids transaction cost; switching to a better signal costs capital.
A random policy earns β 0 expected reward (market-neutral by construction). A skilled policy earns consistently positive alpha.
---
## Action Space
```json
{
"stock": "HDFCBANK",
"direction": "Bullish",
"conviction": 0.8
}
```
| Field | Type | Description |
|---|---|---|
| `stock` | string | NSE symbol to trade, or `"NONE"` to pass this step |
| `direction` | string (enum) | `Bullish` (long alpha), `Bearish` (short alpha), or `NONE` |
| `conviction` | float [0, 1] | Kelly fraction β fraction of virtual wealth wagered |
Passing (`NONE`) skips the step with zero reward and preserves the current holding at no cost. Switching to a **different** stock from the one held last step costs 0.1% of current capital.
---
## Observation Space
```json
{
"step": 3,
"max_steps": 10,
"term": "MEDIUM",
"sector": "banking",
"available_stocks": ["HDFCBANK", "ICICIBANK", "AXISBANK"],
"stocks": {
"HDFCBANK": { "rsi_14": 61.2, "rsi_trend": "up", "price_momentum_pct": 2.4, "indicators": {...} },
"ICICIBANK": { "rsi_14": 54.8, "rsi_trend": "flat", "price_momentum_pct": 0.8, "indicators": {...} },
"AXISBANK": { "rsi_14": 48.1, "rsi_trend": "down", "price_momentum_pct": -1.1, "indicators": {...} }
},
"signal_history": [
{ "step": 1, "picked_stock": "HDFCBANK", "direction": "Bullish", "correct": true, "alpha_pct": 1.8, "reward": 0.63 },
{ "step": 2, "picked_stock": "NONE", "direction": "NONE", "correct": null, "alpha_pct": 0.0, "reward": 0.0 }
],
"current_holding": "HDFCBANK",
"capital": 1.0126,
"drawdown": 0.0,
"macro": null
}
```
### Per-stock Indicator Suite (25+ signals)
| Category | Indicators |
|---|---|
| **Moving Averages** | SMA(20/50/200), EMA(20/50), Golden/Death Cross |
| **Momentum** | RSI(14) + trend, MACD(12/26/9) + crossover, Stochastic(14/3) |
| **Volatility** | Bollinger Bands (%, width, squeeze), ATR(14), volatility regime |
| **Trend** | ADX(14), +DI/-DI, trend strength |
| **Volume** | OBV, VWAP, MFI(14), CMF(20), A/D Line, volume ratio |
| **Levels** | Pivot Points (R2/R1/P/S1/S2) |
---
## Tasks
### Task 1: Short-term Relative Alpha *(Easy)*
- **Steps**: 5 (1 trading day apart = 1 week)
- **GT**: 1-day forward return, Β±0.3% threshold
- **Portfolio**: capital tracked, 5% drawdown terminates episode early
- **Grader**: Directional accuracy on active (non-NONE) steps
### Task 2: Medium-term Relative Alpha *(Medium)*
- **Steps**: 10 (5 trading days apart = 10 weeks)
- **GT**: 5-day forward return, Β±1.5% threshold
- **Portfolio**: capital tracked, 10% drawdown terminates episode early
- **Grader**: Weighted accuracy β Bearish/Neutral correct = 1.5Γ weight; participation bonus
### Task 3: Long-term Risk-Constrained Alpha *(Hard)*
- **Steps**: 15 (20 trading days apart = 15 months)
- **GT**: 20-day forward return, Β±2.5% threshold
- **Portfolio**: capital tracked, 15% drawdown terminates episode early; macro context (NIFTY50 trend, market regime) added
- **Grader**: Conviction-calibrated accuracy β correct + conviction β₯ 0.7 β 1.0; overconfident wrong β β0.1
---
## Reward Function
```
alpha = chosen_stock_period_return β sector_average_return
direction_sign = +1 (Bullish) or β1 (Bearish)
raw_reward = alpha Γ direction_sign Γ conviction Γ 50
tx_cost = 0.001 Γ capital (if switching from a different held stock, else 0)
reward = clamp(raw_reward β tx_cost, β1.5, 1.5)
```
**Example (medium task, step 3):**
- HDFCBANK returns +3.5%, sector average +1.5%
- alpha = +2.0%, direction = Bullish, conviction = 0.8
- No switch (was already holding HDFCBANK): tx_cost = 0
- reward = 0.02 Γ 1 Γ 0.8 Γ 50 = **0.80**
**Market-neutral property:** Because reward is relative to the sector average, a random policy earns β 0 in expectation. Broad market moves cancel out. The agent profits only from correctly identifying within-sector outperformers.
**Kelly conviction:** Higher conviction amplifies both gains and losses, incentivizing calibrated confidence rather than uniform maximum bets.
---
## Episode Structure
```
reset() β sector=banking stocks=[HDFCBANK, ICICIBANK, AXISBANK] capital=1.0 holding=NONE
step 1 β pick HDFCBANK Bullish 0.7 reward=+0.63 done=False capital=1.009 tx_cost=0.0
step 2 β NONE reward=0.00 done=False capital=1.009 tx_cost=0.0
step 3 β pick ICICIBANK Bullish 0.8 reward=+0.41 done=False capital=1.017 tx_cost=0.001 β switch cost
step 4 β pick ICICIBANK Bullish 0.6 reward=-0.15 done=False capital=1.008 tx_cost=0.0 β same stock
step 5 β pick HDFCBANK Bearish 0.5 reward=+0.22 done=True capital=1.012 tx_cost=0.001 β switch cost
```
---
## Baseline Scores (Random Agent, seed=42)
| Task | Steps per run | Expected score |
|---|---|---|
| Short-term Direction | 50 (10 eps Γ 5 steps) | ~0.33 |
| Medium-term Direction | 100 (10 eps Γ 10 steps) | ~0.33 |
| Long-term Conviction | β€150 (10 eps Γ β€15 steps) | ~0.10 |
---
## Setup & Usage
### Local
```bash
pip install -r requirements-server.txt
cd env/
python indicators_env.py # Runs on http://localhost:7860
```
### Docker
```bash
docker build -t indicators-env .
docker run -p 7860:7860 indicators-env
```
### Inference Agent
```bash
export API_BASE_URL=https://router.huggingface.co/v1/
export MODEL_NAME=meta-llama/Llama-3.2-1B-Instruct
export HF_TOKEN=hf_your_token
python inference.py --env_url http://localhost:7860 --n_episodes 5
```
---
## Links
- **HF Space (live env)**: [bawsi99/indicators-env](https://huggingface.co/spaces/bawsi99/indicators-env)
- **Fine-tuned LoRA**: [bawsi99/indicators-grpo-qwen7b](https://huggingface.co/bawsi99/indicators-grpo-qwen7b)
- **OpenEnv**: [meta-pytorch/OpenEnv](https://github.com/meta-pytorch/OpenEnv)
|