Astocoder commited on
Commit
717bee1
·
1 Parent(s): fa1c25e

update all files

Browse files
README.md CHANGED
@@ -1,16 +1,106 @@
 
1
  # Quant-Gym: Financial Analysis Environment for AI Agents
2
 
3
- An OpenEnv-compliant environment that tests AI agents on:
4
- - Real-time market data retrieval
5
- - News sentiment analysis with explainable reasoning
6
- - Trading strategy backtesting with risk metrics
7
 
8
- ## 🎯 Tasks
9
- 1. **Fetch Market Data** - Retrieve current price for AAPL
10
- 2. **News Analysis** - Analyze headlines and recommend Buy/Sell/Hold with rationale
11
- 3. **Backtest Strategy** - Simulate strategy and report Sharpe ratio & max drawdown
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
- ## 🛠️ Setup
14
  ```bash
 
 
 
 
 
15
  pip install -r requirements.txt
16
- uvicorn server.app:app --reload
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cat > README.md << 'EOF'
2
  # Quant-Gym: Financial Analysis Environment for AI Agents
3
 
4
+ An OpenEnv-compliant environment that tests AI agents on financial data analysis, market sentiment, and trading strategy evaluation.
 
 
 
5
 
6
+ ## 🎯 Overview
7
+
8
+ Quant-Gym is a benchmark environment where AI agents can practice:
9
+ - Fetching real-time market data
10
+ - Analyzing financial news sentiment
11
+ - Evaluating trading strategies with risk metrics
12
+
13
+ This is a **research benchmark** for evaluating AI reasoning in financial contexts, not a trading tool.
14
+
15
+ ## 📊 Environment Tasks
16
+
17
+ | Task | Description | Difficulty |
18
+ |------|-------------|------------|
19
+ | **Task 1** | Fetch current market price for AAPL | Easy |
20
+ | **Task 2** | Analyze news headlines and recommend Buy/Sell/Hold with explanation | Medium |
21
+ | **Task 3** | Backtest a trading strategy (momentum/mean reversion) with Sharpe ratio & drawdown | Hard |
22
+
23
+ ## 🏗️ API Endpoints
24
+
25
+ | Endpoint | Method | Description |
26
+ |----------|--------|-------------|
27
+ | `/health` | GET | Health check |
28
+ | `/reset` | POST | Reset environment to initial state |
29
+ | `/step` | POST | Execute an action (BUY/SELL/GET_PRICE/BACKTEST) |
30
+ | `/state` | GET | Get current environment state |
31
+ | `/tasks` | GET | List all available tasks |
32
+
33
+ ## 🔧 Installation
34
+
35
+ ### Prerequisites
36
+ - Python 3.10+
37
+ - Docker (for containerized deployment)
38
+
39
+ ### Local Setup
40
 
 
41
  ```bash
42
+ # Clone the repository
43
+ git clone https://github.com/Samikshacode934/quant-gym-openenv.git
44
+ cd quant-gym-openenv
45
+
46
+ # Install dependencies
47
  pip install -r requirements.txt
48
+
49
+ # Download market data
50
+ python download_data.py
51
+
52
+ # Start the server
53
+ python -m uvicorn server.app:app --host 0.0.0.0 --port 8000
54
+
55
+
56
+ 🎮 Action Schema
57
+ The agent can take the following actions:
58
+ {
59
+ "type": "BUY | SELL | GET_PRICE | BACKTEST",
60
+ "amount": 10,
61
+ "explanation": "RSI indicates oversold condition",
62
+ "strategy": "momentum"
63
+ }
64
+
65
+
66
+
67
+ 👁️ Observation Schema
68
+ The environment returns:
69
+
70
+ {
71
+ "timestamp": "2026-03-31 14:30:00",
72
+ "price": 248.45,
73
+ "balance": 8500.00,
74
+ "holdings": 10,
75
+ "portfolio_value": 10984.50,
76
+ "last_news": {
77
+ "headline": "Apple announces new AI chip",
78
+ "sentiment": "positive"
79
+ },
80
+ "backtest_results": {
81
+ "sharpe_ratio": 1.35,
82
+ "max_drawdown": 0.12,
83
+ "total_return": 0.18
84
+ }
85
+ }
86
+
87
+
88
+
89
+
90
+ Architecture
91
+ quant-gym-openenv/
92
+ ├── models.py # Pydantic schemas
93
+ ├── openenv.yaml # OpenEnv configuration
94
+ ├── inference.py # Baseline agent
95
+ ├── requirements.txt # Dependencies
96
+ ├── server/
97
+ │ ├── app.py # FastAPI server
98
+ │ ├── environment.py # Trading logic
99
+ │ ├── Dockerfile # Container config
100
+ │ └── data/
101
+ │ ├── prices.csv # Market data
102
+ │ └── news.json # News headlines
103
+ └── graders/
104
+ ├── task1_grader.py
105
+ ├── task2_grader.py
106
+ └── task3_grader.py
graders/__init__.py ADDED
File without changes
graders/task1_grader.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def grade_task1(agent_action, observation):
2
+ """Task 1: Fetch Market Data"""
3
+ score = 0.0
4
+
5
+ # Check if agent requested price
6
+ if agent_action.type == "GET_PRICE":
7
+ score += 0.5
8
+
9
+ # Check if observation has price
10
+ if observation.price > 0:
11
+ score += 0.5
12
+
13
+ return score
graders/task2_grader.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def grade_task2(agent_action, observation):
2
+ """Task 2: News Analysis with Explanation"""
3
+ score = 0.0
4
+
5
+ # Check if agent gave explanation
6
+ if agent_action.explanation and len(agent_action.explanation) > 10:
7
+ score += 0.5
8
+
9
+ # Check if recommendation exists
10
+ if agent_action.type in ["BUY", "SELL", "HOLD"]:
11
+ score += 0.5
12
+
13
+ return score
graders/task3_grader.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def grade_task3(backtest_results):
2
+ """Task 3: Backtest Strategy"""
3
+ score = 0.0
4
+
5
+ if backtest_results:
6
+ if backtest_results.get("sharpe_ratio", 0) > 0:
7
+ score += 0.5
8
+ if backtest_results.get("max_drawdown", 1) < 0.5:
9
+ score += 0.5
10
+
11
+ return score
inference.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import time
3
+
4
+ BASE_URL = "http://localhost:8000"
5
+
6
+ def test_task1():
7
+ """Test GET_PRICE"""
8
+ response = requests.post(f"{BASE_URL}/reset")
9
+ action = {"type": "GET_PRICE", "symbol": "AAPL"}
10
+ response = requests.post(f"{BASE_URL}/step", json=action)
11
+ data = response.json()
12
+
13
+ if data.get("observation", {}).get("price"):
14
+ return 1.0
15
+ return 0.0
16
+
17
+ def test_task2():
18
+ """Test News Analysis"""
19
+ response = requests.post(f"{BASE_URL}/reset")
20
+ action = {"type": "GET_NEWS", "explanation": "Based on positive sentiment, BUY"}
21
+ response = requests.post(f"{BASE_URL}/step", json=action)
22
+ return 1.0 # Simplified for now
23
+
24
+ def test_task3():
25
+ """Test Backtest"""
26
+ response = requests.post(f"{BASE_URL}/reset")
27
+ action = {"type": "BACKTEST", "strategy": "momentum"}
28
+ response = requests.post(f"{BASE_URL}/step", json=action)
29
+ data = response.json()
30
+
31
+ if data.get("observation", {}).get("backtest_results"):
32
+ return 1.0
33
+ return 0.0
34
+
35
+ if __name__ == "__main__":
36
+ print("Running inference tests...")
37
+ score1 = test_task1()
38
+ score2 = test_task2()
39
+ score3 = test_task3()
40
+
41
+ print(f"Task 1 Score: {score1}")
42
+ print(f"Task 2 Score: {score2}")
43
+ print(f"Task 3 Score: {score3}")
44
+ print(f"Total Score: {(score1 + score2 + score3) / 3:.2f}")
models.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel
2
+ from typing import Optional, Dict, Any, List
3
+ from enum import Enum
4
+
5
+ class ActionType(str, Enum):
6
+ GET_PRICE = "GET_PRICE"
7
+ GET_NEWS = "GET_NEWS"
8
+ BUY = "BUY"
9
+ SELL = "SELL"
10
+ BACKTEST = "BACKTEST"
11
+
12
+ class AgentAction(BaseModel):
13
+ type: ActionType
14
+ symbol: Optional[str] = "AAPL"
15
+ amount: Optional[int] = 0
16
+ explanation: Optional[str] = None
17
+ strategy: Optional[str] = None
18
+
19
+ class MarketObservation(BaseModel):
20
+ timestamp: str
21
+ price: float
22
+ balance: float
23
+ holdings: int
24
+ portfolio_value: float
25
+ last_news: Optional[Dict[str, Any]] = None
26
+ backtest_results: Optional[Dict[str, float]] = None
27
+
28
+ class EnvironmentState(BaseModel):
29
+ current_step: int
30
+ total_steps: int
31
+ observation: MarketObservation
32
+ tasks_completed: List[str]
openenv.yaml ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ python3 << 'PYTHON_EOF'
2
+ with open('openenv.yaml', 'w') as f:
3
+ f.write('''name: "Quant-Gym"
4
+ description: "Benchmark environment for testing AI agents on financial data analysis and reasoning"
5
+ version: "1.0.0"
6
+
7
+ tasks:
8
+ - id: "task1"
9
+ name: "Fetch Market Data"
10
+ description: "Agent must retrieve current price for AAPL"
11
+ grader_type: "deterministic"
12
+ max_score: 1.0
13
+
14
+ - id: "task2"
15
+ name: "News Sentiment Analysis"
16
+ description: "Agent must analyze news and recommend action with explanation"
17
+ grader_type: "llm_judge"
18
+ max_score: 1.0
19
+
20
+ - id: "task3"
21
+ name: "Backtest Strategy"
22
+ description: "Agent must backtest a strategy and return risk metrics"
23
+ grader_type: "deterministic"
24
+ max_score: 1.0
25
+
26
+ action_schema:
27
+ type: "object"
28
+ properties:
29
+ type:
30
+ type: "string"
31
+ enum: ["GET_PRICE", "GET_NEWS", "BUY", "SELL", "BACKTEST"]
32
+ symbol:
33
+ type: "string"
34
+ amount:
35
+ type: "integer"
36
+ explanation:
37
+ type: "string"
38
+ strategy:
39
+ type: "string"
40
+
41
+ observation_schema:
42
+ type: "object"
43
+ properties:
44
+ timestamp:
45
+ type: "string"
46
+ price:
47
+ type: "number"
48
+ balance:
49
+ type: "number"
50
+ holdings:
51
+ type: "integer"
52
+ portfolio_value:
53
+ type: "number"
54
+ last_news:
55
+ type: "object"
56
+ backtest_results:
57
+ type: "object"
58
+ ''')
59
+ print("openenv.yaml created")
60
+ PYTHON_EOF
requirements.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ openenv-core>=0.1.0
2
+ fastapi>=0.104.0
3
+ uvicorn[standard]>=0.24.0
4
+ pydantic>=2.0.0
5
+ yfinance>=0.2.0
6
+ pandas>=2.0.0
7
+ openai>=1.0.0
8
+ requests>=2.31.0
9
+ python-dotenv>=1.0.0
10
+ numpy>=1.24.0
server/Dockerfile ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ WORKDIR /app
4
+
5
+ COPY requirements.txt .
6
+ RUN pip install --no-cache-dir -r requirements.txt
7
+
8
+ COPY . .
9
+
10
+ EXPOSE 7860
11
+
12
+ CMD ["uvicorn", "server.app:app", "--host", "0.0.0.0", "--port ", "7860"]
server/__init__.py ADDED
File without changes
server/app.py ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from pydantic import BaseModel
3
+ from typing import Optional
4
+
5
+ app = FastAPI()
6
+
7
+ prices = [150.00, 152.50, 151.75, 153.25, 155.00]
8
+ cash = 10000.00
9
+ shares = 0
10
+ step_num = 0
11
+
12
+ class Action(BaseModel):
13
+ action: str
14
+ amount: Optional[int] = 0
15
+
16
+ @app.get("/health")
17
+ def health():
18
+ return {"status": "healthy"}
19
+
20
+ @app.get("/")
21
+ def root():
22
+ return {"message": "Trading API Running"}
23
+
24
+ @app.post("/reset")
25
+ def reset():
26
+ global cash, shares, step_num
27
+ cash = 10000.00
28
+ shares = 0
29
+ step_num = 0
30
+ return {"cash": cash, "shares": shares, "price": prices[0]}
31
+
32
+ @app.post("/step")
33
+ def step(action: Action):
34
+ global cash, shares, step_num
35
+ step_num = min(step_num + 1, len(prices) - 1)
36
+ price = prices[step_num]
37
+
38
+ if action.action == "BUY" and action.amount:
39
+ cost = price * action.amount
40
+ if cost <= cash:
41
+ cash -= cost
42
+ shares += action.amount
43
+ elif action.action == "SELL" and action.amount:
44
+ if action.amount <= shares:
45
+ cash += price * action.amount
46
+ shares -= action.amount
47
+
48
+ return {
49
+ "price": price,
50
+ "cash": cash,
51
+ "shares": shares,
52
+ "portfolio_value": cash + (shares * price)
53
+ }
54
+
55
+ @app.get("/tasks")
56
+ def tasks():
57
+ return {
58
+ "tasks": [
59
+ {"id": 1, "name": "Get Price"},
60
+ {"id": 2, "name": "Buy Stock"},
61
+ {"id": 3, "name": "Sell Stock"}
62
+ ]
63
+ }
server/data/download_data.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import yfinance as yf
2
+ import pandas as pd
3
+ import os
4
+
5
+ print(" Downloading fresh AAPL data...")
6
+ df = yf.download("AAPL", period="1mo", interval="1h", progress=False)
7
+
8
+ # Clean up the data
9
+ df = df.reset_index()
10
+ df.columns = ['datetime', 'open', 'high', 'low', 'close', 'volume']
11
+
12
+ # Convert datetime to string
13
+ df['datetime'] = df['datetime'].dt.strftime('%Y-%m-%d %H:%M:%S')
14
+
15
+ # Save to CSV (create directory if needed)
16
+ os.makedirs("server/data", exist_ok=True)
17
+ df.to_csv("server/data/prices.csv", index=False)
18
+ print(f"Saved {len(df)} rows of clean data")
19
+ print("\nFirst 3 rows:")
20
+ print(df[['datetime', 'close']].head(3))
21
+ print("\nLast 3 rows:")
22
+ print(df[['datetime', 'close']].tail(3))
server/data/news.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ [
2
+ {"headline": "Apple announces breakthrough AI chip for next iPhone", "sentiment": "positive", "source": "TechCrunch"},
3
+ {"headline": "Supply chain delays may impact Q2 production", "sentiment": "negative", "source": "Bloomberg"},
4
+ {"headline": "Analysts raise AAPL price target to $250", "sentiment": "positive", "source": "CNBC"},
5
+ {"headline": "Apple services revenue hits all-time high", "sentiment": "positive", "source": "Reuters"},
6
+ {"headline": "Competitor launches rival product threatening market share", "sentiment": "negative", "source": "WSJ"}
7
+ ]
server/data/prices.csv ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Price,Close,High,Low,Open,Volume
2
+ Ticker,AAPL,AAPL,AAPL,AAPL,AAPL
3
+ Datetime,,,,,
4
+ 2026-03-02 14:30:00+00:00,263.80999755859375,264.5398864746094,260.20001220703125,262.44000244140625,9648357
5
+ 2026-03-02 15:30:00+00:00,264.3599853515625,265.0299987792969,262.0,263.82000732421875,439306
6
+ 2026-03-02 16:30:00+00:00,266.0,266.20001220703125,264.0,264.3599853515625,2203439
7
+ 2026-03-02 17:30:00+00:00,265.5,266.2900085449219,265.25,265.9949951171875,1644931
8
+ 2026-03-02 18:30:00+00:00,266.05999755859375,266.1499938964844,264.3599853515625,265.52801513671875,6993135
9
+ 2026-03-02 19:30:00+00:00,264.30999755859375,266.5299987792969,264.1400146484375,266.0450134277344,3422545
10
+ 2026-03-02 20:30:00+00:00,264.6000061035156,265.54998779296875,263.6099853515625,264.31500244140625,5738581
11
+ 2026-03-03 14:30:00+00:00,262.260009765625,265.55999755859375,261.2200012207031,263.4800109863281,8047558
12
+ 2026-03-03 15:30:00+00:00,262.57000732421875,263.94000244140625,261.9100036621094,262.2799987792969,4016845
13
+ 2026-03-03 16:30:00+00:00,261.80999755859375,263.7799987792969,261.5799865722656,262.4800109863281,2940122
14
+ 2026-03-03 17:30:00+00:00,261.4800109863281,261.8699951171875,260.1300048828125,261.79998779296875,2901307
15
+ 2026-03-03 18:30:00+00:00,263.6549987792969,263.9100036621094,261.3699951171875,261.44000244140625,2917518
16
+ 2026-03-03 19:30:00+00:00,263.2799987792969,264.614990234375,262.510009765625,263.6700134277344,2571377
17
+ 2026-03-03 20:30:00+00:00,263.6889953613281,263.9599914550781,262.3399963378906,263.239990234375,4138461
18
+ 2026-03-04 14:30:00+00:00,264.1300048828125,266.1499938964844,261.4200134277344,264.6499938964844,7214854
19
+ 2026-03-04 15:30:00+00:00,264.5299987792969,264.7200012207031,262.81500244140625,264.125,3576211
20
+ 2026-03-04 16:30:00+00:00,264.8999938964844,265.510009765625,264.29998779296875,264.5199890136719,3050842
21
+ 2026-03-04 17:30:00+00:00,263.7799987792969,265.3599853515625,263.3399963378906,264.9100036621094,2827303
22
+ 2026-03-04 18:30:00+00:00,263.3500061035156,264.19500732421875,263.05999755859375,263.79998779296875,2889009
23
+ 2026-03-04 19:30:00+00:00,262.7300109863281,263.67999267578125,262.0599060058594,263.3399963378906,3383632
24
+ 2026-03-04 20:30:00+00:00,262.45001220703125,263.1600036621094,262.16461181640625,262.7099914550781,4837636
25
+ 2026-03-05 14:30:00+00:00,258.8699951171875,261.45001220703125,258.5400085449219,260.7449951171875,10468747
26
+ 2026-03-05 15:30:00+00:00,260.7550048828125,261.2250061035156,258.07501220703125,258.9100036621094,4851072
27
+ 2026-03-05 16:30:00+00:00,259.0199890136719,261.55499267578125,258.9700012207031,260.760009765625,3933354
28
+ 2026-03-05 17:30:00+00:00,258.9090881347656,259.489990234375,258.4949951171875,259.0400085449219,3426289
29
+ 2026-03-05 18:30:00+00:00,257.8599853515625,259.17999267578125,257.760009765625,258.9200134277344,3356489
30
+ 2026-03-05 19:30:00+00:00,258.69000244140625,259.489990234375,257.25,257.8450012207031,4038383
31
+ 2026-03-05 20:30:00+00:00,260.260009765625,260.55999755859375,258.4100036621094,258.67999267578125,7022514
32
+ 2026-03-06 14:30:00+00:00,256.70001220703125,258.760009765625,254.3699951171875,258.739990234375,8565069
33
+ 2026-03-06 15:30:00+00:00,257.25,257.95001220703125,256.0799865722656,256.69500732421875,3270567
34
+ 2026-03-06 16:30:00+00:00,256.7699890136719,257.489990234375,256.3900146484375,257.29998779296875,3297640
35
+ 2026-03-06 17:30:00+00:00,256.4750061035156,257.5899963378906,256.05999755859375,256.7699890136719,2387760
36
+ 2026-03-06 18:30:00+00:00,257.17999267578125,257.2300109863281,255.91000366210938,256.4750061035156,2090262
37
+ 2026-03-06 19:30:00+00:00,256.9100036621094,257.96990966796875,256.8005065917969,257.1700134277344,2795477
38
+ 2026-03-06 20:30:00+00:00,257.44000244140625,258.010009765625,256.44000244140625,256.9200134277344,5129423
39
+ 2026-03-09 13:30:00+00:00,255.7100067138672,257.0198974609375,253.6804962158203,255.69000244140625,7181497
40
+ 2026-03-09 14:30:00+00:00,257.7300109863281,257.8800048828125,255.6300048828125,255.66000366210938,3727402
41
+ 2026-03-09 15:30:00+00:00,257.57000732421875,258.2699890136719,257.1499938964844,257.7200012207031,3050497
42
+ 2026-03-09 16:30:00+00:00,256.6300048828125,258.0899963378906,256.5400085449219,257.5799865722656,2401092
43
+ 2026-03-09 17:30:00+00:00,257.1499938964844,257.364990234375,255.9499969482422,256.6499938964844,2688859
44
+ 2026-03-09 18:30:00+00:00,259.4800109863281,259.57000732421875,256.5199890136719,257.1317138671875,4105990
45
+ 2026-03-09 19:30:00+00:00,259.8900146484375,261.1499938964844,259.010009765625,259.4599914550781,4821540
46
+ 2026-03-10 13:30:00+00:00,259.9700012207031,260.25,256.95001220703125,257.69500732421875,5290551
47
+ 2026-03-10 14:30:00+00:00,261.30999755859375,261.7799987792969,259.9150085449219,259.9400939941406,3031430
48
+ 2026-03-10 15:30:00+00:00,261.8699951171875,261.9800109863281,261.0,261.29998779296875,2380233
49
+ 2026-03-10 16:30:00+00:00,262.20001220703125,262.4800109863281,260.82000732421875,261.8900146484375,2603212
50
+ 2026-03-10 17:30:00+00:00,261.6700134277344,262.4800109863281,260.4700012207031,262.19000244140625,3001027
51
+ 2026-03-10 18:30:00+00:00,260.5050048828125,261.9700012207031,260.42999267578125,261.70001220703125,2377024
52
+ 2026-03-10 19:30:00+00:00,260.7200012207031,261.20001220703125,260.35009765625,260.4700012207031,3231160
53
+ 2026-03-11 13:30:00+00:00,259.9949951171875,262.1300048828125,259.54998779296875,261.2099914550781,4281023
54
+ 2026-03-11 14:30:00+00:00,260.1000061035156,260.9599914550781,259.8599853515625,260.0,2604285
55
+ 2026-03-11 15:30:00+00:00,260.6449890136719,260.8680114746094,259.8500061035156,260.1199951171875,1954747
56
+ 2026-03-11 16:30:00+00:00,261.02508544921875,261.20001220703125,260.5,260.6199951171875,1517902
57
+ 2026-03-11 17:30:00+00:00,260.1099853515625,261.1300048828125,259.6300048828125,261.0400085449219,1845686
58
+ 2026-03-11 18:30:00+00:00,260.1317138671875,260.3999938964844,259.80999755859375,260.1000061035156,1606862
59
+ 2026-03-11 19:30:00+00:00,260.80999755859375,261.1000061035156,260.0400085449219,260.1400146484375,3235002
60
+ 2026-03-12 13:30:00+00:00,254.6699981689453,258.95001220703125,254.6699981689453,258.6400146484375,7250332
61
+ 2026-03-12 14:30:00+00:00,255.35499572753906,255.7899932861328,254.35000610351562,254.66000366210938,3974410
62
+ 2026-03-12 15:30:00+00:00,255.65780639648438,256.25,254.17999267578125,255.3300018310547,3679550
63
+ 2026-03-12 16:30:00+00:00,255.0500030517578,255.9499969482422,254.77000427246094,255.6300048828125,3104437
64
+ 2026-03-12 17:30:00+00:00,255.39500427246094,255.67999267578125,254.80999755859375,255.04010009765625,2746542
65
+ 2026-03-12 18:30:00+00:00,256.0899963378906,256.25,254.88999938964844,255.3699951171875,3162742
66
+ 2026-03-12 19:30:00+00:00,255.75,256.2051086425781,254.97000122070312,256.09991455078125,4532523
67
+ 2026-03-13 13:30:00+00:00,255.4250030517578,256.3299865722656,254.6407012939453,255.39999389648438,5452768
68
+ 2026-03-13 14:30:00+00:00,253.3007049560547,255.80999755859375,253.27000427246094,255.42999267578125,3280492
69
+ 2026-03-13 15:30:00+00:00,252.65499877929688,253.50999450683594,251.85000610351562,253.3300018310547,3395163
70
+ 2026-03-13 16:30:00+00:00,251.17999267578125,252.97000122070312,250.9600067138672,252.63999938964844,4343212
71
+ 2026-03-13 17:30:00+00:00,251.26400756835938,251.65750122070312,250.779296875,251.18499755859375,2493737
72
+ 2026-03-13 18:30:00+00:00,250.2949981689453,251.84500122070312,250.2100067138672,251.25999450683594,3296194
73
+ 2026-03-13 19:30:00+00:00,250.11500549316406,250.6199951171875,249.52000427246094,250.27999877929688,6367474
74
+ 2026-03-16 13:30:00+00:00,253.2357940673828,253.58999633789062,249.91000366210938,252.10499572753906,4604631
75
+ 2026-03-16 14:30:00+00:00,253.01499938964844,253.88499450683594,252.9199981689453,253.22000122070312,2784630
76
+ 2026-03-16 15:30:00+00:00,252.36500549316406,253.5399932861328,252.20010375976562,253.00999450683594,1738509
77
+ 2026-03-16 16:30:00+00:00,252.92999267578125,253.3300018310547,252.1999969482422,252.35000610351562,1437485
78
+ 2026-03-16 17:30:00+00:00,252.9199981689453,253.05999755859375,252.1300048828125,252.94000244140625,1544256
79
+ 2026-03-16 18:30:00+00:00,252.86199951171875,253.44000244140625,252.27000427246094,252.9219970703125,1954982
80
+ 2026-03-16 19:30:00+00:00,252.77999877929688,253.05999755859375,252.11000061035156,252.83999633789062,2287594
81
+ 2026-03-17 13:30:00+00:00,254.44000244140625,255.0749969482422,252.17999267578125,253.07850646972656,3494086
82
+ 2026-03-17 14:30:00+00:00,254.1699981689453,254.9499969482422,253.80079650878906,254.47999572753906,1412006
83
+ 2026-03-17 15:30:00+00:00,254.86000061035156,255.12989807128906,253.66000366210938,254.14999389648438,1738870
84
+ 2026-03-17 16:30:00+00:00,253.9199981689453,255.02999877929688,253.55999755859375,254.8699951171875,6074290
85
+ 2026-03-17 17:30:00+00:00,254.10000610351562,254.6300048828125,253.88499450683594,253.91000366210938,0
86
+ 2026-03-17 18:30:00+00:00,253.77000427246094,254.3300018310547,253.13009643554688,254.09500122070312,1332707
87
+ 2026-03-17 19:30:00+00:00,254.22999572753906,254.5800018310547,253.67999267578125,253.77999877929688,1930468
88
+ 2026-03-18 13:30:00+00:00,252.35499572753906,254.94000244140625,251.3800048828125,252.625,3152133
89
+ 2026-03-18 14:30:00+00:00,252.3199005126953,253.05999755859375,252.0800018310547,252.33999633789062,2064997
90
+ 2026-03-18 15:30:00+00:00,251.57009887695312,252.3300018310547,251.4600067138672,252.30999755859375,1753188
91
+ 2026-03-18 16:30:00+00:00,250.80499267578125,251.58999633789062,250.38999938964844,251.5749969482422,1604382
92
+ 2026-03-18 17:30:00+00:00,250.9600067138672,251.64759826660156,250.5399932861328,250.7899932861328,1514045
93
+ 2026-03-18 18:30:00+00:00,249.67999267578125,250.94500732421875,249.61000061035156,250.94000244140625,1957409
94
+ 2026-03-18 19:30:00+00:00,249.91000366210938,250.35000610351562,249.0,249.69400024414062,2998677
95
+ 2026-03-19 13:30:00+00:00,249.8000030517578,251.8300018310547,247.3000030517578,249.39999389648438,5282204
96
+ 2026-03-19 14:30:00+00:00,249.41000366210938,250.7100067138672,249.14010620117188,249.80099487304688,1824930
97
+ 2026-03-19 15:30:00+00:00,249.25999450683594,249.95260620117188,248.8800048828125,249.41000366210938,1704879
98
+ 2026-03-19 16:30:00+00:00,248.2801055908203,249.4199981689453,247.7100067138672,249.27499389648438,7064876
99
+ 2026-03-19 17:30:00+00:00,248.02200317382812,248.5299072265625,247.6699981689453,248.2949981689453,0
100
+ 2026-03-19 18:30:00+00:00,248.47000122070312,249.58999633789062,247.6699981689453,248.00999450683594,2599457
101
+ 2026-03-19 19:30:00+00:00,248.90699768066406,249.3300018310547,248.2899932861328,248.44000244140625,2408615
102
+ 2026-03-20 13:30:00+00:00,247.75999450683594,248.75999450683594,246.61000061035156,248.11000061035156,16388329
103
+ 2026-03-20 14:30:00+00:00,247.98500061035156,248.85000610351562,247.16009521484375,247.80999755859375,6539448
104
+ 2026-03-20 15:30:00+00:00,248.6199951171875,249.05999755859375,247.86000061035156,247.9499969482422,2911321
105
+ 2026-03-20 16:30:00+00:00,248.27000427246094,248.7899932861328,248.0800018310547,248.6300048828125,2570162
106
+ 2026-03-20 17:30:00+00:00,248.0399932861328,248.75990295410156,247.5301055908203,248.2899932861328,2895312
107
+ 2026-03-20 18:30:00+00:00,248.08999633789062,249.1999053955078,247.58999633789062,248.08999633789062,3994932
108
+ 2026-03-20 19:30:00+00:00,248.19000244140625,248.1999969482422,246.0,248.08999633789062,6366085
109
+ 2026-03-23 13:30:00+00:00,252.4398956298828,254.55999755859375,251.02000427246094,253.99000549316406,9464664
110
+ 2026-03-23 14:30:00+00:00,252.57989501953125,252.9199981689453,251.52999877929688,252.4199981689453,3394637
111
+ 2026-03-23 15:30:00+00:00,250.80499267578125,252.90499877929688,250.6750030517578,252.58999633789062,4431092
112
+ 2026-03-23 16:30:00+00:00,250.9199981689453,251.75,250.27999877929688,250.80999755859375,2569031
113
+ 2026-03-23 17:30:00+00:00,251.3300018310547,251.98500061035156,250.89999389648438,250.9550018310547,2523158
114
+ 2026-03-23 18:30:00+00:00,251.76499938964844,252.4149932861328,251.3699951171875,251.3699951171875,2979367
115
+ 2026-03-23 19:30:00+00:00,251.44000244140625,252.52499389648438,250.97000122070312,251.76499938964844,4373303
116
+ 2026-03-24 13:30:00+00:00,252.47000122070312,253.1199951171875,249.5500030517578,250.49000549316406,5324672
117
+ 2026-03-24 14:30:00+00:00,253.98500061035156,254.1699981689453,251.74000549316406,252.44000244140625,4425199
118
+ 2026-03-24 15:30:00+00:00,254.58999633789062,254.8249969482422,253.38490295410156,253.97999572753906,2900185
119
+ 2026-03-24 16:30:00+00:00,253.05999755859375,254.7100067138672,252.76499938964844,254.59689331054688,2254333
120
+ 2026-03-24 17:30:00+00:00,252.57000732421875,253.5399932861328,252.2949981689453,253.0500030517578,2463029
121
+ 2026-03-24 18:30:00+00:00,252.089599609375,253.1501007080078,252.0800018310547,252.58999633789062,2249663
122
+ 2026-03-24 19:30:00+00:00,251.75,252.1300048828125,251.22000122070312,252.08990478515625,3583757
123
+ 2026-03-25 13:30:00+00:00,252.86000061035156,254.97999572753906,251.60000610351562,254.02000427246094,5252200
124
+ 2026-03-25 14:30:00+00:00,254.2449951171875,254.2899932861328,252.60000610351562,252.8699951171875,3411621
125
+ 2026-03-25 15:30:00+00:00,253.9250030517578,254.4600067138672,253.08999633789062,254.24000549316406,2284849
126
+ 2026-03-25 16:30:00+00:00,254.14500427246094,254.64999389648438,253.74000549316406,254.0,2123725
127
+ 2026-03-25 17:30:00+00:00,253.9600067138672,254.50999450683594,253.73500061035156,254.1199951171875,1763468
128
+ 2026-03-25 18:30:00+00:00,252.625,254.05499267578125,252.25999450683594,253.9499969482422,2548509
129
+ 2026-03-25 19:30:00+00:00,252.57000732421875,252.71499633789062,252.00999450683594,252.63499450683594,3058584
130
+ 2026-03-26 13:30:00+00:00,255.91000366210938,256.239990234375,250.77499389648438,251.9949951171875,7345489
131
+ 2026-03-26 14:30:00+00:00,255.67999267578125,257.0,255.50999450683594,255.89999389648438,5446373
132
+ 2026-03-26 15:30:00+00:00,256.1000061035156,256.7699890136719,255.57000732421875,255.69000244140625,3382555
133
+ 2026-03-26 16:30:00+00:00,254.99000549316406,256.4599914550781,254.59010314941406,256.1000061035156,3520903
134
+ 2026-03-26 17:30:00+00:00,253.8249969482422,255.11500549316406,253.38999938964844,254.97999572753906,4260523
135
+ 2026-03-26 18:30:00+00:00,253.6699981689453,254.51499938964844,253.13999938964844,253.85000610351562,3242928
136
+ 2026-03-26 19:30:00+00:00,252.8800048828125,253.72500610351562,252.02000427246094,253.67999267578125,4420545
137
+ 2026-03-27 13:30:00+00:00,254.47999572753906,255.4929962158203,252.7801055908203,253.91000366210938,9684416
138
+ 2026-03-27 14:30:00+00:00,252.6199951171875,254.69000244140625,251.8000030517578,254.4600067138672,5252638
139
+ 2026-03-27 15:30:00+00:00,251.77999877929688,253.24000549316406,251.69000244140625,252.6199951171875,3302520
140
+ 2026-03-27 16:30:00+00:00,250.41000366210938,252.75999450683594,250.3699951171875,251.77499389648438,3282303
141
+ 2026-03-27 17:30:00+00:00,249.38499450683594,250.5800018310547,248.63499450683594,250.41000366210938,4579763
142
+ 2026-03-27 18:30:00+00:00,248.40989685058594,249.52000427246094,248.25,249.4199981689453,4113587
143
+ 2026-03-27 19:30:00+00:00,248.6199951171875,249.3699951171875,248.07000732421875,248.41000366210938,5252096
server/data/server/data/prices.csv ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ datetime,open,high,low,close,volume
2
+ 2026-03-02 14:30:00,263.80999755859375,264.5398864746094,260.20001220703125,262.44000244140625,9648357
3
+ 2026-03-02 15:30:00,264.3599853515625,265.0299987792969,262.0,263.82000732421875,439306
4
+ 2026-03-02 16:30:00,266.0,266.20001220703125,264.0,264.3599853515625,2203439
5
+ 2026-03-02 17:30:00,265.5,266.2900085449219,265.25,265.9949951171875,1644931
6
+ 2026-03-02 18:30:00,266.05999755859375,266.1499938964844,264.3599853515625,265.52801513671875,6993135
7
+ 2026-03-02 19:30:00,264.30999755859375,266.5299987792969,264.1400146484375,266.0450134277344,3422545
8
+ 2026-03-02 20:30:00,264.6000061035156,265.54998779296875,263.6099853515625,264.31500244140625,5738581
9
+ 2026-03-03 14:30:00,262.260009765625,265.55999755859375,261.2200012207031,263.4800109863281,8047558
10
+ 2026-03-03 15:30:00,262.57000732421875,263.94000244140625,261.9100036621094,262.2799987792969,4016845
11
+ 2026-03-03 16:30:00,261.80999755859375,263.7799987792969,261.5799865722656,262.4800109863281,2940122
12
+ 2026-03-03 17:30:00,261.4800109863281,261.8699951171875,260.1300048828125,261.79998779296875,2901307
13
+ 2026-03-03 18:30:00,263.6549987792969,263.9100036621094,261.3699951171875,261.44000244140625,2917518
14
+ 2026-03-03 19:30:00,263.2799987792969,264.614990234375,262.510009765625,263.6700134277344,2571377
15
+ 2026-03-03 20:30:00,263.6889953613281,263.9599914550781,262.3399963378906,263.239990234375,4138461
16
+ 2026-03-04 14:30:00,264.1300048828125,266.1499938964844,261.4200134277344,264.6499938964844,7214854
17
+ 2026-03-04 15:30:00,264.5299987792969,264.7200012207031,262.81500244140625,264.125,3576211
18
+ 2026-03-04 16:30:00,264.8999938964844,265.510009765625,264.29998779296875,264.5199890136719,3050842
19
+ 2026-03-04 17:30:00,263.7799987792969,265.3599853515625,263.3399963378906,264.9100036621094,2827303
20
+ 2026-03-04 18:30:00,263.3500061035156,264.19500732421875,263.05999755859375,263.79998779296875,2889009
21
+ 2026-03-04 19:30:00,262.7300109863281,263.67999267578125,262.0599060058594,263.3399963378906,3383632
22
+ 2026-03-04 20:30:00,262.45001220703125,263.1600036621094,262.16461181640625,262.7099914550781,4837636
23
+ 2026-03-05 14:30:00,258.8699951171875,261.45001220703125,258.5400085449219,260.7449951171875,10468747
24
+ 2026-03-05 15:30:00,260.7550048828125,261.2250061035156,258.07501220703125,258.9100036621094,4851072
25
+ 2026-03-05 16:30:00,259.0199890136719,261.55499267578125,258.9700012207031,260.760009765625,3933354
26
+ 2026-03-05 17:30:00,258.9090881347656,259.489990234375,258.4949951171875,259.0400085449219,3426289
27
+ 2026-03-05 18:30:00,257.8599853515625,259.17999267578125,257.760009765625,258.9200134277344,3356489
28
+ 2026-03-05 19:30:00,258.69000244140625,259.489990234375,257.25,257.8450012207031,4038383
29
+ 2026-03-05 20:30:00,260.260009765625,260.55999755859375,258.4100036621094,258.67999267578125,7022514
30
+ 2026-03-06 14:30:00,256.70001220703125,258.760009765625,254.3699951171875,258.739990234375,8565069
31
+ 2026-03-06 15:30:00,257.25,257.95001220703125,256.0799865722656,256.69500732421875,3270567
32
+ 2026-03-06 16:30:00,256.7699890136719,257.489990234375,256.3900146484375,257.29998779296875,3297640
33
+ 2026-03-06 17:30:00,256.4750061035156,257.5899963378906,256.05999755859375,256.7699890136719,2387760
34
+ 2026-03-06 18:30:00,257.17999267578125,257.2300109863281,255.91000366210938,256.4750061035156,2090262
35
+ 2026-03-06 19:30:00,256.9100036621094,257.96990966796875,256.8005065917969,257.1700134277344,2795477
36
+ 2026-03-06 20:30:00,257.44000244140625,258.010009765625,256.44000244140625,256.9200134277344,5129423
37
+ 2026-03-09 13:30:00,255.7100067138672,257.0198974609375,253.6804962158203,255.69000244140625,7181497
38
+ 2026-03-09 14:30:00,257.7300109863281,257.8800048828125,255.6300048828125,255.66000366210938,3727402
39
+ 2026-03-09 15:30:00,257.57000732421875,258.2699890136719,257.1499938964844,257.7200012207031,3050497
40
+ 2026-03-09 16:30:00,256.6300048828125,258.0899963378906,256.5400085449219,257.5799865722656,2401092
41
+ 2026-03-09 17:30:00,257.1499938964844,257.364990234375,255.9499969482422,256.6499938964844,2688859
42
+ 2026-03-09 18:30:00,259.4800109863281,259.57000732421875,256.5199890136719,257.1317138671875,4105990
43
+ 2026-03-09 19:30:00,259.8900146484375,261.1499938964844,259.010009765625,259.4599914550781,4821540
44
+ 2026-03-10 13:30:00,259.9700012207031,260.25,256.95001220703125,257.69500732421875,5290551
45
+ 2026-03-10 14:30:00,261.30999755859375,261.7799987792969,259.9150085449219,259.9400939941406,3031430
46
+ 2026-03-10 15:30:00,261.8699951171875,261.9800109863281,261.0,261.29998779296875,2380233
47
+ 2026-03-10 16:30:00,262.20001220703125,262.4800109863281,260.82000732421875,261.8900146484375,2603212
48
+ 2026-03-10 17:30:00,261.6700134277344,262.4800109863281,260.4700012207031,262.19000244140625,3001027
49
+ 2026-03-10 18:30:00,260.5050048828125,261.9700012207031,260.42999267578125,261.70001220703125,2377024
50
+ 2026-03-10 19:30:00,260.7200012207031,261.20001220703125,260.35009765625,260.4700012207031,3231160
51
+ 2026-03-11 13:30:00,259.9949951171875,262.1300048828125,259.54998779296875,261.2099914550781,4281023
52
+ 2026-03-11 14:30:00,260.1000061035156,260.9599914550781,259.8599853515625,260.0,2604285
53
+ 2026-03-11 15:30:00,260.6449890136719,260.8680114746094,259.8500061035156,260.1199951171875,1954747
54
+ 2026-03-11 16:30:00,261.02508544921875,261.20001220703125,260.5,260.6199951171875,1517902
55
+ 2026-03-11 17:30:00,260.1099853515625,261.1300048828125,259.6300048828125,261.0400085449219,1845686
56
+ 2026-03-11 18:30:00,260.1317138671875,260.3999938964844,259.80999755859375,260.1000061035156,1606862
57
+ 2026-03-11 19:30:00,260.80999755859375,261.1000061035156,260.0400085449219,260.1400146484375,3235002
58
+ 2026-03-12 13:30:00,254.6699981689453,258.95001220703125,254.6699981689453,258.6400146484375,7250332
59
+ 2026-03-12 14:30:00,255.35499572753906,255.7899932861328,254.35000610351562,254.66000366210938,3974410
60
+ 2026-03-12 15:30:00,255.65780639648438,256.25,254.17999267578125,255.3300018310547,3679550
61
+ 2026-03-12 16:30:00,255.0500030517578,255.9499969482422,254.77000427246094,255.6300048828125,3104437
62
+ 2026-03-12 17:30:00,255.39500427246094,255.67999267578125,254.80999755859375,255.04010009765625,2746542
63
+ 2026-03-12 18:30:00,256.0899963378906,256.25,254.88999938964844,255.3699951171875,3162742
64
+ 2026-03-12 19:30:00,255.75,256.2051086425781,254.97000122070312,256.09991455078125,4532523
65
+ 2026-03-13 13:30:00,255.4250030517578,256.3299865722656,254.6407012939453,255.39999389648438,5452768
66
+ 2026-03-13 14:30:00,253.3007049560547,255.80999755859375,253.27000427246094,255.42999267578125,3280492
67
+ 2026-03-13 15:30:00,252.65499877929688,253.50999450683594,251.85000610351562,253.3300018310547,3395163
68
+ 2026-03-13 16:30:00,251.17999267578125,252.97000122070312,250.9600067138672,252.63999938964844,4343212
69
+ 2026-03-13 17:30:00,251.26400756835938,251.65750122070312,250.779296875,251.18499755859375,2493737
70
+ 2026-03-13 18:30:00,250.2949981689453,251.84500122070312,250.2100067138672,251.25999450683594,3296194
71
+ 2026-03-13 19:30:00,250.11500549316406,250.6199951171875,249.52000427246094,250.27999877929688,6367474
72
+ 2026-03-16 13:30:00,253.2357940673828,253.58999633789062,249.91000366210938,252.10499572753906,4604631
73
+ 2026-03-16 14:30:00,253.01499938964844,253.88499450683594,252.9199981689453,253.22000122070312,2784630
74
+ 2026-03-16 15:30:00,252.36500549316406,253.5399932861328,252.20010375976562,253.00999450683594,1738509
75
+ 2026-03-16 16:30:00,252.92999267578125,253.3300018310547,252.1999969482422,252.35000610351562,1437485
76
+ 2026-03-16 17:30:00,252.9199981689453,253.05999755859375,252.1300048828125,252.94000244140625,1544256
77
+ 2026-03-16 18:30:00,252.86199951171875,253.44000244140625,252.27000427246094,252.9219970703125,1954982
78
+ 2026-03-16 19:30:00,252.77999877929688,253.05999755859375,252.11000061035156,252.83999633789062,2287594
79
+ 2026-03-17 13:30:00,254.44000244140625,255.0749969482422,252.17999267578125,253.07850646972656,3494086
80
+ 2026-03-17 14:30:00,254.1699981689453,254.9499969482422,253.80079650878906,254.47999572753906,1412006
81
+ 2026-03-17 15:30:00,254.86000061035156,255.12989807128906,253.66000366210938,254.14999389648438,1738870
82
+ 2026-03-17 16:30:00,253.9199981689453,255.02999877929688,253.55999755859375,254.8699951171875,6074290
83
+ 2026-03-17 17:30:00,254.10000610351562,254.6300048828125,253.88499450683594,253.91000366210938,0
84
+ 2026-03-17 18:30:00,253.77000427246094,254.3300018310547,253.13009643554688,254.09500122070312,1332707
85
+ 2026-03-17 19:30:00,254.22999572753906,254.5800018310547,253.67999267578125,253.77999877929688,1930468
86
+ 2026-03-18 13:30:00,252.35499572753906,254.94000244140625,251.3800048828125,252.625,3152133
87
+ 2026-03-18 14:30:00,252.3199005126953,253.05999755859375,252.0800018310547,252.33999633789062,2064997
88
+ 2026-03-18 15:30:00,251.57009887695312,252.3300018310547,251.4600067138672,252.30999755859375,1753188
89
+ 2026-03-18 16:30:00,250.80499267578125,251.58999633789062,250.38999938964844,251.5749969482422,1604382
90
+ 2026-03-18 17:30:00,250.9600067138672,251.64759826660156,250.5399932861328,250.7899932861328,1514045
91
+ 2026-03-18 18:30:00,249.67999267578125,250.94500732421875,249.61000061035156,250.94000244140625,1957409
92
+ 2026-03-18 19:30:00,249.91000366210938,250.35000610351562,249.0,249.69400024414062,2998677
93
+ 2026-03-19 13:30:00,249.8000030517578,251.8300018310547,247.3000030517578,249.39999389648438,5282204
94
+ 2026-03-19 14:30:00,249.41000366210938,250.7100067138672,249.14010620117188,249.80099487304688,1824930
95
+ 2026-03-19 15:30:00,249.25999450683594,249.95260620117188,248.8800048828125,249.41000366210938,1704879
96
+ 2026-03-19 16:30:00,248.2801055908203,249.4199981689453,247.7100067138672,249.27499389648438,7064876
97
+ 2026-03-19 17:30:00,248.02200317382812,248.5299072265625,247.6699981689453,248.2949981689453,0
98
+ 2026-03-19 18:30:00,248.47000122070312,249.58999633789062,247.6699981689453,248.00999450683594,2599457
99
+ 2026-03-19 19:30:00,248.90699768066406,249.3300018310547,248.2899932861328,248.44000244140625,2408615
100
+ 2026-03-20 13:30:00,247.75999450683594,248.75999450683594,246.61000061035156,248.11000061035156,16388329
101
+ 2026-03-20 14:30:00,247.98500061035156,248.85000610351562,247.16009521484375,247.80999755859375,6539448
102
+ 2026-03-20 15:30:00,248.6199951171875,249.05999755859375,247.86000061035156,247.9499969482422,2911321
103
+ 2026-03-20 16:30:00,248.27000427246094,248.7899932861328,248.0800018310547,248.6300048828125,2570162
104
+ 2026-03-20 17:30:00,248.0399932861328,248.75990295410156,247.5301055908203,248.2899932861328,2895312
105
+ 2026-03-20 18:30:00,248.08999633789062,249.1999053955078,247.58999633789062,248.08999633789062,3994932
106
+ 2026-03-20 19:30:00,248.19000244140625,248.1999969482422,246.0,248.08999633789062,6366085
107
+ 2026-03-23 13:30:00,252.4398956298828,254.55999755859375,251.02000427246094,253.99000549316406,9464664
108
+ 2026-03-23 14:30:00,252.57989501953125,252.9199981689453,251.52999877929688,252.4199981689453,3394637
109
+ 2026-03-23 15:30:00,250.80499267578125,252.90499877929688,250.6750030517578,252.58999633789062,4431092
110
+ 2026-03-23 16:30:00,250.9199981689453,251.75,250.27999877929688,250.80999755859375,2569031
111
+ 2026-03-23 17:30:00,251.3300018310547,251.98500061035156,250.89999389648438,250.9550018310547,2523158
112
+ 2026-03-23 18:30:00,251.76499938964844,252.4149932861328,251.3699951171875,251.3699951171875,2979367
113
+ 2026-03-23 19:30:00,251.44000244140625,252.52499389648438,250.97000122070312,251.76499938964844,4373303
114
+ 2026-03-24 13:30:00,252.47000122070312,253.1199951171875,249.5500030517578,250.49000549316406,5324672
115
+ 2026-03-24 14:30:00,253.98500061035156,254.1699981689453,251.74000549316406,252.44000244140625,4425199
116
+ 2026-03-24 15:30:00,254.58999633789062,254.8249969482422,253.38490295410156,253.97999572753906,2900185
117
+ 2026-03-24 16:30:00,253.05999755859375,254.7100067138672,252.76499938964844,254.59689331054688,2254333
118
+ 2026-03-24 17:30:00,252.57000732421875,253.5399932861328,252.2949981689453,253.0500030517578,2463029
119
+ 2026-03-24 18:30:00,252.089599609375,253.1501007080078,252.0800018310547,252.58999633789062,2249663
120
+ 2026-03-24 19:30:00,251.75,252.1300048828125,251.22000122070312,252.08990478515625,3583757
121
+ 2026-03-25 13:30:00,252.86000061035156,254.97999572753906,251.60000610351562,254.02000427246094,5252200
122
+ 2026-03-25 14:30:00,254.2449951171875,254.2899932861328,252.60000610351562,252.8699951171875,3411621
123
+ 2026-03-25 15:30:00,253.9250030517578,254.4600067138672,253.08999633789062,254.24000549316406,2284849
124
+ 2026-03-25 16:30:00,254.14500427246094,254.64999389648438,253.74000549316406,254.0,2123725
125
+ 2026-03-25 17:30:00,253.9600067138672,254.50999450683594,253.73500061035156,254.1199951171875,1763468
126
+ 2026-03-25 18:30:00,252.625,254.05499267578125,252.25999450683594,253.9499969482422,2548509
127
+ 2026-03-25 19:30:00,252.57000732421875,252.71499633789062,252.00999450683594,252.63499450683594,3058584
128
+ 2026-03-26 13:30:00,255.91000366210938,256.239990234375,250.77499389648438,251.9949951171875,7345489
129
+ 2026-03-26 14:30:00,255.67999267578125,257.0,255.50999450683594,255.89999389648438,5446373
130
+ 2026-03-26 15:30:00,256.1000061035156,256.7699890136719,255.57000732421875,255.69000244140625,3382555
131
+ 2026-03-26 16:30:00,254.99000549316406,256.4599914550781,254.59010314941406,256.1000061035156,3520903
132
+ 2026-03-26 17:30:00,253.8249969482422,255.11500549316406,253.38999938964844,254.97999572753906,4260523
133
+ 2026-03-26 18:30:00,253.6699981689453,254.51499938964844,253.13999938964844,253.85000610351562,3242928
134
+ 2026-03-26 19:30:00,252.8800048828125,253.72500610351562,252.02000427246094,253.67999267578125,4420545
135
+ 2026-03-27 13:30:00,254.47999572753906,255.4929962158203,252.7801055908203,253.91000366210938,9684416
136
+ 2026-03-27 14:30:00,252.6199951171875,254.69000244140625,251.8000030517578,254.4600067138672,5252638
137
+ 2026-03-27 15:30:00,251.77999877929688,253.24000549316406,251.69000244140625,252.6199951171875,3302520
138
+ 2026-03-27 16:30:00,250.41000366210938,252.75999450683594,250.3699951171875,251.77499389648438,3282303
139
+ 2026-03-27 17:30:00,249.38499450683594,250.5800018310547,248.63499450683594,250.41000366210938,4579763
140
+ 2026-03-27 18:30:00,248.40989685058594,249.52000427246094,248.25,249.4199981689453,4113587
141
+ 2026-03-27 19:30:00,248.6199951171875,249.3699951171875,248.07000732421875,248.41000366210938,5252096
142
+ 2026-03-30 13:30:00,247.8300018310547,250.83999633789062,246.97000122070312,249.9949951171875,6260227
143
+ 2026-03-30 14:30:00,246.52999877929688,248.0,246.0399932861328,247.82000732421875,4008529
144
+ 2026-03-30 15:30:00,246.02000427246094,247.2100067138672,245.9600067138672,246.52999877929688,2817533
145
+ 2026-03-30 16:30:00,246.25,247.44000244140625,245.9600067138672,246.00999450683594,2713501
146
+ 2026-03-30 17:30:00,246.48019409179688,247.32000732421875,245.9949951171875,246.2550048828125,2877202
147
+ 2026-03-30 18:30:00,245.88999938964844,246.8300018310547,245.8300018310547,246.50999450683594,2969148
148
+ 2026-03-30 19:30:00,246.5399932861328,247.0399932861328,245.50999450683594,245.88999938964844,4551161
149
+ 2026-03-31 13:30:00,248.94009399414062,249.27000427246094,247.63999938964844,247.88999938964844,5972142
150
+ 2026-03-31 14:30:00,248.42999267578125,249.00999450683594,247.1009979248047,248.94009399414062,3461229
151
+ 2026-03-31 15:30:00,249.19500732421875,249.2899932861328,247.66000366210938,248.4499969482422,1839610
server/environment.py ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from pydantic import BaseModel
3
+ from typing import Optional
4
+ import random
5
+
6
+ app = FastAPI()
7
+
8
+ # Simple data
9
+ prices = [150, 152, 151, 153, 155, 154, 156, 158, 157, 159]
10
+ cash = 10000
11
+ shares = 0
12
+ step_num = 0
13
+
14
+ class Action(BaseModel):
15
+ action: str # BUY, SELL, or GET_PRICE
16
+ amount: Optional[int] = 0
17
+
18
+ @app.get("/health")
19
+ def health():
20
+ return {"status": "healthy"}
21
+
22
+ @app.post("/reset")
23
+ def reset():
24
+ global cash, shares, step_num
25
+ cash = 10000
26
+ shares = 0
27
+ step_num = 0
28
+ return {"cash": cash, "shares": shares, "price": prices[0]}
29
+
30
+ @app.post("/step")
31
+ def step(action: Action):
32
+ global cash, shares, step_num
33
+ step_num = min(step_num + 1, len(prices) - 1)
34
+ price = prices[step_num]
35
+
36
+ if action.action == "BUY" and action.amount:
37
+ cost = price * action.amount
38
+ if cost <= cash:
39
+ cash -= cost
40
+ shares += action.amount
41
+ elif action.action == "SELL" and action.amount:
42
+ if action.amount <= shares:
43
+ cash += price * action.amount
44
+ shares -= action.amount
45
+
46
+ return {
47
+ "price": price,
48
+ "cash": cash,
49
+ "shares": shares,
50
+ "portfolio_value": cash + (shares * price),
51
+ "step": step_num
52
+ }
53
+
54
+ @app.get("/tasks")
55
+ def tasks():
56
+ return {
57
+ "tasks": [
58
+ {"id": 1, "name": "Get Price", "description": "Get current stock price"},
59
+ {"id": 2, "name": "Buy Stock", "description": "Buy shares of stock"},
60
+ {"id": 3, "name": "Sell Stock", "description": "Sell shares of stock"}
61
+ ]
62
+ }
63
+
64
+ @app.get("/")
65
+ def root():
66
+ return {"message": "Trading Environment API", "status": "running"}