Tonic commited on
Commit
cee45d4
·
1 Parent(s): eb30d21

Initial commit: Stock prediction application with Chronos integration

Browse files
Files changed (5) hide show
  1. .gitignore +41 -0
  2. README.md +34 -191
  3. app.py +26 -11
  4. src/app.py +117 -0
  5. src/data/stock_data.py +62 -0
.gitignore ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ *.egg-info/
20
+ .installed.cfg
21
+ *.egg
22
+
23
+ # Virtual Environment
24
+ venv/
25
+ env/
26
+ ENV/
27
+
28
+ # IDE
29
+ .idea/
30
+ .vscode/
31
+ *.swp
32
+ *.swo
33
+
34
+ # OS
35
+ .DS_Store
36
+ Thumbs.db
37
+
38
+ # Project specific
39
+ *.log
40
+ .env
41
+ .env.local
README.md CHANGED
@@ -13,223 +13,66 @@ tags:
13
  - mcp-server-track
14
  ---
15
 
16
- # Stock Analysis and Prediction Demo
17
 
18
- A comprehensive stock analysis and prediction tool built with Gradio, featuring multiple prediction strategies and technical analysis indicators. The application is particularly suited for structured financial product creation and analysis.
19
 
20
  ## Features
21
 
22
- - **Multiple Prediction Strategies**:
23
- - Chronos ML-based prediction
24
- - Technical analysis-based prediction
25
-
26
- - **Technical Indicators**:
27
- - RSI (Relative Strength Index)
28
- - MACD (Moving Average Convergence Divergence)
29
- - Bollinger Bands
30
- - Simple Moving Averages (20, 50, and 200-day)
31
-
32
- - **Trading Signals**:
33
- - Buy/Sell recommendations based on multiple indicators
34
- - Overall trading signal combining all indicators
35
- - Confidence intervals for predictions
36
-
37
- - **Interactive Visualizations**:
38
- - Price prediction with confidence intervals
39
- - Technical indicators overlay
40
- - Volume analysis
41
- - Historical price trends
42
-
43
- - **Structured Product Analysis**:
44
- - Extended prediction horizons (up to 1 year)
45
- - Historical analysis up to 10 years
46
- - Comprehensive risk metrics
47
- - Sector and industry analysis
48
- - Liquidity assessment
49
-
50
- ## Structured Product Features
51
-
52
- ### Extended Time Horizons
53
- - Prediction window up to 365 days
54
- - Historical data analysis up to 10 years
55
- - Long-term trend analysis
56
- - Extended technical indicators
57
-
58
- ### Risk Analysis
59
- - Annualized volatility
60
- - Maximum drawdown analysis
61
- - Current drawdown tracking
62
- - Sharpe and Sortino ratios
63
- - Risk-adjusted return metrics
64
-
65
- ### Product Metrics
66
- - Market capitalization
67
- - Sector and industry classification
68
- - Dividend yield analysis
69
- - Volume metrics
70
- - Liquidity scoring
71
-
72
- ### Sector Analysis
73
- - Market cap ranking (Large/Mid/Small)
74
- - Sector exposure
75
- - Industry classification
76
- - Liquidity assessment
77
 
78
  ## Installation
79
 
80
  1. Clone the repository:
81
  ```bash
82
- git clone <repository-url>
83
- cd stock-prediction
84
  ```
85
 
86
- 2. Create and activate a virtual environment:
87
- ```bash
88
- python -m venv .venv
89
- source .venv/bin/activate # On Windows: .venv\Scripts\activate
90
- ```
91
-
92
- 3. Install dependencies:
93
  ```bash
94
  pip install -r requirements.txt
95
  ```
96
 
97
  ## Usage
98
 
99
- 1. Start the Gradio demo:
100
  ```bash
101
  python app.py
102
  ```
103
 
104
- 2. Open your web browser and navigate to the URL shown in the terminal (typically http://localhost:7860)
105
-
106
- 3. Enter a stock symbol (e.g., AAPL, GOOGL, MSFT) and select your desired parameters:
107
- - Timeframe (1d, 1h, 15m)
108
- - Number of days to predict (up to 365 days)
109
- - Historical lookback period (up to 10 years)
110
- - Prediction strategy (Chronos or Technical)
111
-
112
- 4. Click "Analyze Stock" to get:
113
- - Price predictions and trading signals
114
- - Structured product metrics
115
- - Risk analysis
116
- - Sector analysis
117
-
118
- ## Using for Structured Products
119
-
120
- ### Initial Screening
121
- 1. Use extended lookback period (up to 10 years) for long-term performance analysis
122
- 2. Look for stocks with stable volatility and good risk-adjusted returns
123
- 3. Check liquidity scores for trading feasibility
124
-
125
- ### Risk Assessment
126
- 1. Review risk metrics to match client risk profile
127
- 2. Analyze maximum drawdowns for worst-case scenarios
128
- 3. Compare risk-adjusted returns using Sharpe and Sortino ratios
129
-
130
- ### Product Structuring
131
- 1. Use prediction horizon (up to 1 year) for product maturity design
132
- 2. Consider dividend yields for income-generating products
133
- 3. Use sector analysis for proper diversification
134
 
135
- ### Portfolio Construction
136
- 1. Analyze multiple stocks for diversified bundles
137
- 2. Use sector metrics to avoid overexposure
138
- 3. Consider market cap rankings for appropriate sizing
139
-
140
- ## Prediction Strategies
141
-
142
- ### Chronos Strategy
143
- Uses Amazon's Chronos model for ML-based price prediction. This strategy:
144
- - Analyzes historical price patterns
145
- - Generates probabilistic forecasts
146
- - Provides confidence intervals
147
-
148
- ### Technical Strategy
149
- Uses traditional technical analysis indicators to generate predictions:
150
- - RSI for overbought/oversold conditions
151
- - MACD for trend direction
152
- - Bollinger Bands for volatility
153
- - Moving Averages for trend confirmation
154
 
155
- ## Trading Signals
 
 
 
 
 
156
 
157
- The demo provides trading signals based on multiple technical indicators:
158
- - RSI: Oversold (<30), Overbought (>70), Neutral
159
- - MACD: Buy (MACD > Signal), Sell (MACD < Signal)
160
- - Bollinger Bands: Buy (price < lower band), Sell (price > upper band)
161
- - SMA: Buy (20-day > 50-day), Sell (20-day < 50-day)
162
 
163
- An overall trading signal is calculated by combining all individual signals.
164
 
165
  ## Contributing
166
 
167
  Contributions are welcome! Please feel free to submit a Pull Request.
168
-
169
- ## License
170
-
171
- This project is licensed under the MIT License - see the LICENSE file for details.
172
-
173
- ## Practical Example: Creating a 6-Month 8% Yield Structured Product
174
-
175
- ### Scenario
176
- A bank needs to create a structured product that offers an 8% yield over 6 months while maintaining profitability for the institution.
177
-
178
- ### Step-by-Step Implementation
179
-
180
- 1. **Initial Stock Screening**
181
- - Use the application to analyze stocks with:
182
- - High liquidity (for easy hedging)
183
- - Stable volatility (for predictable risk)
184
- - Strong technical indicators
185
- - Positive long-term trends
186
- - Recommended stocks: AAPL, MSFT, GOOGL (high liquidity, stable volatility)
187
-
188
- 2. **Product Structure Design**
189
- - Use the 6-month prediction horizon
190
- - Analyze historical volatility for barrier setting
191
- - Set participation rate based on risk metrics
192
- - Structure: Reverse Convertible with 8% coupon
193
-
194
- 3. **Risk Analysis**
195
- - Use the application's risk metrics:
196
- - Check maximum drawdown (should be < 15% for 6 months)
197
- - Verify liquidity scores (should be > 80%)
198
- - Analyze Sharpe ratio (should be > 1.5)
199
-
200
- 4. **Business Case Example**
201
-
202
- **Product Parameters:**
203
- - Notional Amount: $1,000,000
204
- - Term: 6 months
205
- - Coupon: 8% p.a. (4% for 6 months)
206
- - Underlying: AAPL
207
- - Barrier: 85% of initial price
208
- - Participation: 100%
209
-
210
- **Revenue Structure:**
211
- - Client receives: 8% p.a. (4% for 6 months)
212
- - Bank's hedging cost: ~5% p.a.
213
- - Bank's profit margin: ~3% p.a.
214
- - Total client payout: $40,000 (4% of $1M)
215
- - Bank's profit: $15,000 (1.5% of $1M)
216
-
217
- 5. **Implementation Steps**
218
- - Use the application's extended prediction horizon (180 days)
219
- - Set technical indicators to monitor barrier risk
220
- - Implement dynamic delta hedging based on predictions
221
- - Monitor risk metrics daily using the application
222
-
223
- 6. **Risk Management**
224
- - Use the application's volatility predictions for dynamic hedging
225
- - Monitor technical indicators for early warning signals
226
- - Set up automated alerts for barrier proximity
227
- - Regular rebalancing based on prediction updates
228
-
229
- ### Key Success Factors
230
- - Regular monitoring of prediction accuracy
231
- - Dynamic adjustment of hedging strategy
232
- - Clear communication of product risks to clients
233
- - Proper documentation of all assumptions and methodologies
234
-
235
- This example demonstrates how the application can be used to create profitable structured products while managing risk effectively. The bank can use this framework to create similar products with different underlying assets, terms, and yield targets.
 
13
  - mcp-server-track
14
  ---
15
 
16
+ # Stock Predictions with Chronos
17
 
18
+ A powerful stock prediction application that uses the Chronos model and technical analysis to predict stock prices across different timeframes.
19
 
20
  ## Features
21
 
22
+ - Multiple timeframe analysis (Daily, Hourly, 15-minute)
23
+ - Integration with Chronos AI model for predictions
24
+ - Technical analysis with multiple indicators
25
+ - Real-time market data using Yahoo Finance
26
+ - Beautiful interactive visualizations using Plotly
27
+ - Risk analysis and sector metrics
28
+ - Trading signals generation
29
+
30
+ ## Requirements
31
+
32
+ - Python 3.8+
33
+ - PyTorch
34
+ - Gradio
35
+ - yfinance
36
+ - pandas
37
+ - numpy
38
+ - plotly
39
+ - scikit-learn
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
  ## Installation
42
 
43
  1. Clone the repository:
44
  ```bash
45
+ git clone https://github.com/yourusername/stock-predictions.git
46
+ cd stock-predictions
47
  ```
48
 
49
+ 2. Install the required packages:
 
 
 
 
 
 
50
  ```bash
51
  pip install -r requirements.txt
52
  ```
53
 
54
  ## Usage
55
 
56
+ Run the application:
57
  ```bash
58
  python app.py
59
  ```
60
 
61
+ The application will start and provide a local URL (usually http://127.0.0.1:7860) where you can access the interface.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
+ ## Features
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
+ - **Daily Analysis**: Long-term predictions and analysis
66
+ - **Hourly Analysis**: Medium-term predictions with 30-day lookback
67
+ - **15-Minute Analysis**: Short-term predictions with 5-day lookback
68
+ - **Technical Indicators**: RSI, MACD, Bollinger Bands, SMAs
69
+ - **Risk Metrics**: Volatility, Drawdown, Sharpe Ratio
70
+ - **Sector Analysis**: Market cap, industry classification, liquidity metrics
71
 
72
+ ## License
 
 
 
 
73
 
74
+ MIT License
75
 
76
  ## Contributing
77
 
78
  Contributions are welcome! Please feel free to submit a Pull Request.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app.py CHANGED
@@ -137,16 +137,17 @@ def get_historical_data(symbol: str, timeframe: str = "1d", lookback_days: int =
137
  sma_window_200 = 200 * 24 # ~40 trading days
138
  vol_window = 20 * 24
139
 
140
- df['SMA_20'] = df['Close'].rolling(window=sma_window_20).mean()
141
- df['SMA_50'] = df['Close'].rolling(window=sma_window_50).mean()
142
- df['SMA_200'] = df['Close'].rolling(window=sma_window_200).mean()
 
143
  df['RSI'] = calculate_rsi(df['Close'])
144
  df['MACD'], df['MACD_Signal'] = calculate_macd(df['Close'])
145
  df['BB_Upper'], df['BB_Middle'], df['BB_Lower'] = calculate_bollinger_bands(df['Close'])
146
 
147
  # Calculate returns and volatility
148
  df['Returns'] = df['Close'].pct_change()
149
- df['Volatility'] = df['Returns'].rolling(window=vol_window).std()
150
  df['Annualized_Vol'] = df['Volatility'] * np.sqrt(252)
151
 
152
  # Calculate drawdown metrics
@@ -155,11 +156,21 @@ def get_historical_data(symbol: str, timeframe: str = "1d", lookback_days: int =
155
  df['Max_Drawdown'] = df['Drawdown'].rolling(window=len(df), min_periods=1).min()
156
 
157
  # Calculate liquidity metrics
158
- df['Avg_Daily_Volume'] = df['Volume'].rolling(window=vol_window).mean()
159
- df['Volume_Volatility'] = df['Volume'].rolling(window=vol_window).std()
160
-
161
- # Drop NaN values
162
- df = df.dropna()
 
 
 
 
 
 
 
 
 
 
163
 
164
  if len(df) < 2:
165
  raise Exception(f"Insufficient data points for {symbol} in {timeframe} timeframe")
@@ -217,14 +228,18 @@ def make_prediction(symbol: str, timeframe: str = "1d", prediction_days: int = 5
217
  returns = df['Returns'].values
218
  normalized_returns = (returns - returns.mean()) / returns.std()
219
 
220
- # Ensure we have enough data points
221
  min_data_points = 64 # Minimum required by Chronos
222
  if len(normalized_returns) < min_data_points:
223
  # Pad the data with the last value
224
  padding = np.full(min_data_points - len(normalized_returns), normalized_returns[-1])
225
  normalized_returns = np.concatenate([padding, normalized_returns])
 
 
 
226
 
227
- context = torch.tensor(normalized_returns.reshape(-1, 1), dtype=torch.float32)
 
228
 
229
  # Make prediction with GPU acceleration
230
  pipe = load_pipeline()
 
137
  sma_window_200 = 200 * 24 # ~40 trading days
138
  vol_window = 20 * 24
139
 
140
+ # Calculate technical indicators
141
+ df['SMA_20'] = df['Close'].rolling(window=sma_window_20, min_periods=1).mean()
142
+ df['SMA_50'] = df['Close'].rolling(window=sma_window_50, min_periods=1).mean()
143
+ df['SMA_200'] = df['Close'].rolling(window=sma_window_200, min_periods=1).mean()
144
  df['RSI'] = calculate_rsi(df['Close'])
145
  df['MACD'], df['MACD_Signal'] = calculate_macd(df['Close'])
146
  df['BB_Upper'], df['BB_Middle'], df['BB_Lower'] = calculate_bollinger_bands(df['Close'])
147
 
148
  # Calculate returns and volatility
149
  df['Returns'] = df['Close'].pct_change()
150
+ df['Volatility'] = df['Returns'].rolling(window=vol_window, min_periods=1).std()
151
  df['Annualized_Vol'] = df['Volatility'] * np.sqrt(252)
152
 
153
  # Calculate drawdown metrics
 
156
  df['Max_Drawdown'] = df['Drawdown'].rolling(window=len(df), min_periods=1).min()
157
 
158
  # Calculate liquidity metrics
159
+ df['Avg_Daily_Volume'] = df['Volume'].rolling(window=vol_window, min_periods=1).mean()
160
+ df['Volume_Volatility'] = df['Volume'].rolling(window=vol_window, min_periods=1).std()
161
+
162
+ # Fill NaN values with forward fill, then backward fill
163
+ df = df.fillna(method='ffill').fillna(method='bfill')
164
+
165
+ # Ensure we have enough data points
166
+ min_required_points = 64 # Minimum required for Chronos
167
+ if len(df) < min_required_points:
168
+ # Try to fetch more historical data
169
+ extended_start_date = start_date - timedelta(days=min_required_points - len(df))
170
+ extended_df = ticker.history(start=extended_start_date, end=start_date, interval=interval)
171
+ if not extended_df.empty:
172
+ df = pd.concat([extended_df, df])
173
+ df = df.fillna(method='ffill').fillna(method='bfill')
174
 
175
  if len(df) < 2:
176
  raise Exception(f"Insufficient data points for {symbol} in {timeframe} timeframe")
 
228
  returns = df['Returns'].values
229
  normalized_returns = (returns - returns.mean()) / returns.std()
230
 
231
+ # Ensure we have enough data points and pad if necessary
232
  min_data_points = 64 # Minimum required by Chronos
233
  if len(normalized_returns) < min_data_points:
234
  # Pad the data with the last value
235
  padding = np.full(min_data_points - len(normalized_returns), normalized_returns[-1])
236
  normalized_returns = np.concatenate([padding, normalized_returns])
237
+ elif len(normalized_returns) > min_data_points:
238
+ # Take the most recent data points
239
+ normalized_returns = normalized_returns[-min_data_points:]
240
 
241
+ # Reshape for Chronos (batch_size=1, sequence_length, features=1)
242
+ context = torch.tensor(normalized_returns.reshape(1, -1, 1), dtype=torch.float32)
243
 
244
  # Make prediction with GPU acceleration
245
  pipe = load_pipeline()
src/app.py ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ import yfinance as yf
4
+ import pandas as pd
5
+ from datetime import datetime, timedelta
6
+ import logging
7
+ from typing import Optional
8
+
9
+ # Configure logging
10
+ logging.basicConfig(level=logging.INFO)
11
+ logger = logging.getLogger(__name__)
12
+
13
+ app = FastAPI()
14
+
15
+ # Configure CORS
16
+ app.add_middleware(
17
+ CORSMiddleware,
18
+ allow_origins=["*"], # Allows all origins
19
+ allow_credentials=True,
20
+ allow_methods=["*"], # Allows all methods
21
+ allow_headers=["*"], # Allows all headers
22
+ )
23
+
24
+ def fetch_stock_data(symbol: str, period: str = "1y") -> pd.DataFrame:
25
+ """
26
+ Fetch historical stock data for a given symbol using yfinance with authentication.
27
+
28
+ Args:
29
+ symbol (str): Stock symbol (e.g., 'AAPL')
30
+ period (str): Time period to fetch (default: '1y')
31
+
32
+ Returns:
33
+ pd.DataFrame: DataFrame containing historical stock data
34
+ """
35
+ try:
36
+ # Create a Ticker object with authentication
37
+ ticker = yf.Ticker(symbol)
38
+
39
+ # Set authentication credentials
40
+ ticker._session.headers.update({
41
+ 'User-Agent': 'Mozilla/5.0',
42
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
43
+ 'Accept-Language': 'en-US,en;q=0.5',
44
+ 'Connection': 'keep-alive',
45
+ 'Upgrade-Insecure-Requests': '1',
46
+ })
47
+
48
+ # Fetch historical data
49
+ df = ticker.history(period=period)
50
+
51
+ if df.empty:
52
+ logger.warning(f"No data found for symbol {symbol}")
53
+ return pd.DataFrame()
54
+
55
+ # Reset index to make Date a column
56
+ df = df.reset_index()
57
+
58
+ # Rename columns to match expected format
59
+ df = df.rename(columns={
60
+ 'Date': 'date',
61
+ 'Open': 'open',
62
+ 'High': 'high',
63
+ 'Low': 'low',
64
+ 'Close': 'close',
65
+ 'Volume': 'volume'
66
+ })
67
+
68
+ # Convert date to string format
69
+ df['date'] = df['date'].dt.strftime('%Y-%m-%d')
70
+
71
+ logger.info(f"Successfully fetched data for {symbol}")
72
+ return df
73
+
74
+ except Exception as e:
75
+ logger.error(f"Error fetching data for {symbol}: {str(e)}")
76
+ return pd.DataFrame()
77
+
78
+ @app.get("/")
79
+ async def root():
80
+ return {"message": "Stock Prediction API"}
81
+
82
+ @app.get("/api/stock/{symbol}")
83
+ async def get_stock_data(symbol: str, period: Optional[str] = "1y"):
84
+ """
85
+ Get historical stock data for a given symbol.
86
+
87
+ Args:
88
+ symbol (str): Stock symbol (e.g., 'AAPL')
89
+ period (str, optional): Time period to fetch. Defaults to "1y".
90
+ Valid periods: 1d, 5d, 1mo, 3mo, 6mo, 1y, 2y, 5y, 10y, ytd, max
91
+
92
+ Returns:
93
+ dict: Dictionary containing stock data and metadata
94
+ """
95
+ try:
96
+ df = fetch_stock_data(symbol, period)
97
+
98
+ if df.empty:
99
+ raise HTTPException(status_code=404, detail=f"No data found for symbol {symbol}")
100
+
101
+ # Convert DataFrame to dictionary format
102
+ data = df.to_dict(orient='records')
103
+
104
+ return {
105
+ "symbol": symbol,
106
+ "period": period,
107
+ "data": data,
108
+ "count": len(data)
109
+ }
110
+
111
+ except Exception as e:
112
+ logger.error(f"Error processing request for {symbol}: {str(e)}")
113
+ raise HTTPException(status_code=500, detail=str(e))
114
+
115
+ if __name__ == "__main__":
116
+ import uvicorn
117
+ uvicorn.run(app, host="0.0.0.0", port=8000)
src/data/stock_data.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import yfinance as yf
2
+ import pandas as pd
3
+ from datetime import datetime, timedelta
4
+ import logging
5
+
6
+ # Configure logging
7
+ logging.basicConfig(level=logging.INFO)
8
+ logger = logging.getLogger(__name__)
9
+
10
+ def fetch_stock_data(symbol: str, period: str = "1y") -> pd.DataFrame:
11
+ """
12
+ Fetch historical stock data for a given symbol using yfinance with authentication.
13
+
14
+ Args:
15
+ symbol (str): Stock symbol (e.g., 'AAPL')
16
+ period (str): Time period to fetch (default: '1y')
17
+
18
+ Returns:
19
+ pd.DataFrame: DataFrame containing historical stock data
20
+ """
21
+ try:
22
+ # Create a Ticker object with authentication
23
+ ticker = yf.Ticker(symbol)
24
+
25
+ # Set authentication credentials
26
+ ticker._session.headers.update({
27
+ 'User-Agent': 'Mozilla/5.0',
28
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
29
+ 'Accept-Language': 'en-US,en;q=0.5',
30
+ 'Connection': 'keep-alive',
31
+ 'Upgrade-Insecure-Requests': '1',
32
+ })
33
+
34
+ # Fetch historical data
35
+ df = ticker.history(period=period)
36
+
37
+ if df.empty:
38
+ logger.warning(f"No data found for symbol {symbol}")
39
+ return pd.DataFrame()
40
+
41
+ # Reset index to make Date a column
42
+ df = df.reset_index()
43
+
44
+ # Rename columns to match expected format
45
+ df = df.rename(columns={
46
+ 'Date': 'date',
47
+ 'Open': 'open',
48
+ 'High': 'high',
49
+ 'Low': 'low',
50
+ 'Close': 'close',
51
+ 'Volume': 'volume'
52
+ })
53
+
54
+ # Convert date to string format
55
+ df['date'] = df['date'].dt.strftime('%Y-%m-%d')
56
+
57
+ logger.info(f"Successfully fetched data for {symbol}")
58
+ return df
59
+
60
+ except Exception as e:
61
+ logger.error(f"Error fetching data for {symbol}: {str(e)}")
62
+ return pd.DataFrame()