update all files
Browse files- README.md +100 -10
- graders/__init__.py +0 -0
- graders/task1_grader.py +13 -0
- graders/task2_grader.py +13 -0
- graders/task3_grader.py +11 -0
- inference.py +44 -0
- models.py +32 -0
- openenv.yaml +60 -0
- requirements.txt +10 -0
- server/Dockerfile +12 -0
- server/__init__.py +0 -0
- server/app.py +63 -0
- server/data/download_data.py +22 -0
- server/data/news.json +7 -0
- server/data/prices.csv +143 -0
- server/data/server/data/prices.csv +151 -0
- server/environment.py +66 -0
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 |
-
## 🎯
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
|
| 13 |
-
## 🛠️ Setup
|
| 14 |
```bash
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
pip install -r requirements.txt
|
| 16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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"}
|