Manus AI commited on
Commit
05f52ea
·
1 Parent(s): d645a04

Fix: ImportError for 'preprocess_data' by moving the function from core/data_2.py to core/data.py and deleting data_2.py

Browse files
Files changed (2) hide show
  1. core/data.py +34 -0
  2. core/data_2.py +0 -325
core/data.py CHANGED
@@ -372,3 +372,37 @@ def sentiment_analysis(ticker, start_date, end_date, api_key):
372
  except Exception as e:
373
  print_log(f"Sentiment analysis failed: {str(e)}", 'ERROR')
374
  return f"Sentiment analysis failed: {str(e)}", None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
372
  except Exception as e:
373
  print_log(f"Sentiment analysis failed: {str(e)}", 'ERROR')
374
  return f"Sentiment analysis failed: {str(e)}", None
375
+
376
+
377
+ def preprocess_data(df, features, target, window_size, horizon):
378
+ try:
379
+ print_log(f"Starting preprocessing: features={features}, target={target}, window={window_size}, horizon={horizon}")
380
+
381
+ if not isinstance(df.index, pd.DatetimeIndex):
382
+ raise ValueError("DataFrame index must be a DatetimeIndex for preprocessing.")
383
+
384
+ updated_feature_cols = [f for f in features if f in df.columns]
385
+ if not updated_feature_cols:
386
+ raise ValueError("None of the selected features are available in the data.")
387
+
388
+ data = df[updated_feature_cols].values
389
+
390
+ scaler = MinMaxScaler(feature_range=(0, 1))
391
+ scaled_data = scaler.fit_transform(data)
392
+
393
+ X, y = [], []
394
+ for i in range(len(scaled_data) - window_size - horizon + 1):
395
+ X.append(scaled_data[i:(i + window_size), :])
396
+ y.append(scaled_data[i + window_size + horizon - 1, updated_feature_cols.index(target)])
397
+
398
+ X, y = np.array(X), np.array(y)
399
+
400
+ if X.shape[1] != window_size or X.shape[2] != len(updated_feature_cols):
401
+ raise ValueError(f"Shape mismatch in X: expected ({len(scaled_data) - window_size - horizon + 1}, {window_size}, {len(updated_feature_cols)}), got {X.shape}")
402
+
403
+ print_log(f"Preprocessing complete. X shape: {X.shape}, y shape: {y.shape}")
404
+ return X, y, scaler, updated_feature_cols
405
+ except Exception as e:
406
+ print_log(f"Error in preprocess_data: {str(e)}", 'ERROR')
407
+ raise ValueError(f"Failed to preprocess data: {str(e)}")
408
+
core/data_2.py DELETED
@@ -1,325 +0,0 @@
1
- import pandas as pd
2
- import numpy as np
3
- import yfinance as yf
4
- import os
5
- try:
6
- import talib as ta
7
- except ImportError:
8
- ta = None
9
- from datetime import datetime, timedelta
10
- from newsapi import NewsApiClient
11
- from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
12
- from sklearn.preprocessing import MinMaxScaler
13
- from alpha_vantage.timeseries import TimeSeries
14
- import time
15
- import logging
16
-
17
- # Configure logging
18
- logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
19
-
20
- def print_log(message, level='INFO'):
21
- if level == 'INFO':
22
- logging.info(message)
23
- elif level == 'WARNING':
24
- logging.warning(message)
25
- elif level == 'ERROR':
26
- logging.error(message)
27
- else:
28
- logging.debug(message)
29
-
30
- analyzer = SentimentIntensityAnalyzer()
31
-
32
- def load_data(data_src='yahoo', ticker='AAPL', start='2020-01-01', end='2023-01-01', interval='1d', file_upload=None, alpha_api_key=None):
33
- try:
34
- print_log(f"Loading data: source={data_src}, ticker={ticker}, start={start}, end={end}, interval={interval}, file_upload={'set' if file_upload else 'unset'}, alpha_api_key={'set' if alpha_api_key else 'unset'}")
35
-
36
- start_date = pd.to_datetime(start)
37
- end_date = pd.to_datetime(end)
38
- if start_date >= end_date:
39
- raise ValueError(f"Start date {start} must be before end date {end}")
40
- if end_date > datetime.now():
41
- print_log(f"End date {end} is in the future. Using current date as end date.", 'WARNING')
42
- end_date = datetime.now()
43
-
44
- df = pd.DataFrame()
45
-
46
- if data_src == 'csv' and file_upload:
47
- try:
48
- file_path = getattr(file_upload, 'name', file_upload)
49
- print_log(f"Loading CSV from {file_path}")
50
- df = pd.read_csv(file_path)
51
- if 'Date' not in df.columns:
52
- raise ValueError("CSV must contain a 'Date' column")
53
- df['Date'] = pd.to_datetime(df['Date']).dt.tz_localize(None)
54
- df = df.set_index('Date')
55
- if 'Close' not in df.columns and 'value' not in df.columns:
56
- raise ValueError("CSV must contain 'Close' or 'value' column")
57
- if 'Close' in df.columns:
58
- df = df.rename(columns={'Close': 'value'})
59
- if df.empty:
60
- raise ValueError(f"CSV data is empty for {ticker}")
61
- if df['value'].isna().all():
62
- raise ValueError(f"CSV 'value' column contains only NaNs for {ticker}")
63
- except Exception as e:
64
- print_log(f"Failed to load CSV {file_path}: {str(e)}", 'ERROR')
65
- raise ValueError(f"Failed to load CSV: {str(e)}")
66
- else:
67
- # Try Alpha Vantage first for intraday intervals if API key is provided
68
- if interval in ['1m', '5m', '15m', '30m', '60m'] and alpha_api_key:
69
- print_log(f"Attempting Alpha Vantage for {ticker}, interval {interval}")
70
- try:
71
- ts = TimeSeries(key=alpha_api_key, output_format='pandas')
72
- df_av, _ = ts.get_intraday(symbol=ticker, interval=interval, outputsize='full')
73
- if df_av.empty:
74
- raise ValueError(f"No data returned from Alpha Vantage for {ticker}")
75
- if '4. close' not in df_av.columns:
76
- raise ValueError(f"Alpha Vantage data missing '4. close' column for {ticker}")
77
- df_av = df_av.rename(columns={'4. close': 'value', '1. open': 'Open', '2. high': 'High', '3. low': 'Low', '5. volume': 'Volume'})
78
- df_av['Date'] = pd.to_datetime(df_av.index)
79
- df_av = df_av.reset_index(drop=True)
80
- if df_av['value'].isna().all():
81
- raise ValueError(f"Alpha Vantage 'value' column contains only NaNs for {ticker}")
82
- if df_av['value'].empty:
83
- raise ValueError(f"Alpha Vantage 'value' column is empty for {ticker}")
84
- df = df_av # Use Alpha Vantage data if successful
85
- except Exception as e:
86
- print_log(f"Alpha Vantage failed: {str(e)}. Falling back to Yahoo Finance.", 'WARNING')
87
-
88
- # If Alpha Vantage failed or not used, try Yahoo Finance
89
- if df.empty:
90
- print_log(f"Fetching data for {ticker} from Yahoo Finance")
91
- try:
92
- df = yf.download(ticker, start=start_date, end=end_date, interval=interval, progress=False, auto_adjust=False)
93
- if isinstance(df.columns, pd.MultiIndex):
94
- df.columns = df.columns.droplevel(1)
95
- if df.empty:
96
- raise ValueError(f"No data returned from Yahoo Finance for {ticker}")
97
- if 'Close' not in df.columns:
98
- raise ValueError(f"Yahoo Finance data missing 'Close' column for {ticker}")
99
- df = df.rename(columns={'Close': 'value'})
100
- if df['value'].isna().all():
101
- raise ValueError(f"Yahoo Finance 'value' column contains only NaNs for {ticker}")
102
- if df['value'].empty:
103
- raise ValueError(f"Yahoo Finance 'value' column is empty for {ticker}")
104
- except Exception as e:
105
- print_log(f"Yahoo Finance failed for {ticker}: {str(e)}", 'ERROR')
106
- raise ValueError(f"Yahoo Finance failed for {ticker}: {str(e)}")
107
-
108
- if df.empty:
109
- raise ValueError(f"No data loaded for {ticker} from {data_src}")
110
-
111
- if not isinstance(df.index, pd.DatetimeIndex):
112
- df.index = pd.to_datetime(df.index)
113
- df = df.sort_index()
114
-
115
- required_cols = ['Open', 'High', 'Low', 'value', 'Volume']
116
- for col in required_cols:
117
- if col not in df.columns:
118
- df[col] = np.nan
119
-
120
- if 'value' not in df.columns:
121
- raise ValueError(f"Target column 'value' is missing for {ticker}")
122
- if df['value'].isna().all():
123
- raise ValueError(f"Target column 'value' contains only NaNs for {ticker}")
124
- if df['value'].empty:
125
- raise ValueError(f"Target column 'value' is empty for {ticker}")
126
-
127
- print_log(f"Data loaded for {ticker} with date range: {df.index.min()} to {df.index.max()}, shape: {df.shape}")
128
- return df
129
- except Exception as e:
130
- print_log(f"Error in load_data for {ticker}: {str(e)}", 'ERROR')
131
- raise ValueError(f"Failed to load data for {ticker}: {str(e)}")
132
-
133
- def add_technical_indicators(df, selected_indicators):
134
- try:
135
- print_log(f"Starting add_technical_indicators with indicators: {selected_indicators}")
136
- if df.empty:
137
- print_log("DataFrame is empty, skipping technical indicator calculation.", "WARNING")
138
- return df, []
139
-
140
- for col in ['Open', 'High', 'Low', 'value', 'Volume']:
141
- if col not in df.columns:
142
- df[col] = np.nan
143
- df[col] = pd.to_numeric(df[col], errors='coerce')
144
-
145
- df.dropna(subset=['Open', 'High', 'Low', 'value', 'Volume'], inplace=True)
146
- if df.empty:
147
- print_log("DataFrame is empty after dropping NaNs for technical indicators.", "WARNING")
148
- return df, []
149
-
150
- if ta is None:
151
- print_log("TA-Lib not available. Cannot compute indicators. Falling back to 'value'.", 'ERROR')
152
- return df, []
153
-
154
- close = df['value'].values
155
- high = df['High'].values
156
- low = df['Low'].values
157
- volume = df['Volume'].values
158
- open_ = df['Open'].values
159
-
160
- indicator_map = {
161
- 'rsi': {'func': ta.RSI, 'inputs': ['close'], 'params': {'timeperiod': 14}, 'output': ['rsi_14']},
162
- 'macd': {'func': ta.MACD, 'inputs': ['close'], 'params': {'fastperiod': 12, 'slowperiod': 26, 'signalperiod': 9}, 'output': ['macd_12_26_9', 'macds_12_26_9', 'macdh_12_26_9']},
163
- 'bbands': {'func': ta.BBANDS, 'inputs': ['close'], 'params': {'timeperiod': 20, 'nbdevup': 2, 'nbdevdn': 2}, 'output': ['bbu_20_2.0', 'bbm_20_2.0', 'bbl_20_2.0']},
164
- 'sma': {'func': ta.SMA, 'inputs': ['close'], 'params': {'timeperiod': 20}, 'output': ['sma_20']},
165
- 'ema': {'func': ta.EMA, 'inputs': ['close'], 'params': {'timeperiod': 20}, 'output': ['ema_20']},
166
- 'atr': {'func': ta.ATR, 'inputs': ['high', 'low', 'close'], 'params': {'timeperiod': 14}, 'output': ['atr_14']},
167
- 'stoch': {'func': ta.STOCH, 'inputs': ['high', 'low', 'close'], 'params': {'fastk_period': 14, 'slowk_period': 3, 'slowd_period': 3}, 'output': ['stochk_14_3_3', 'stochd_14_3_3']},
168
- 'adx': {'func': ta.ADX, 'inputs': ['high', 'low', 'close'], 'params': {'timeperiod': 14}, 'output': ['adx_14']},
169
- 'willr': {'func': ta.WILLR, 'inputs': ['high', 'low', 'close'], 'params': {'timeperiod': 14}, 'output': ['willr_14']},
170
- 'cci': {'func': ta.CCI, 'inputs': ['high', 'low', 'close'], 'params': {'timeperiod': 20}, 'output': ['cci_20']},
171
- 'pdi': {'func': ta.PLUS_DI, 'inputs': ['high', 'low', 'close'], 'params': {'timeperiod': 14}, 'output': ['pdi_14']},
172
- 'mdi': {'func': ta.MINUS_DI, 'inputs': ['high', 'low', 'close'], 'params': {'timeperiod': 14}, 'output': ['mdi_14']}
173
- }
174
-
175
- input_dict = {'close': close, 'high': high, 'low': low, 'open': open_, 'volume': volume}
176
-
177
- valid_indicators = []
178
- for ind in selected_indicators:
179
- if ind in indicator_map:
180
- print_log(f"Computing indicator: {ind}")
181
- config = indicator_map[ind]
182
- func = config['func']
183
- inputs = config['inputs']
184
- params = config['params']
185
- try:
186
- input_arrays = [input_dict[inp] for inp in inputs]
187
- result = func(*input_arrays, **params)
188
- if isinstance(result, tuple):
189
- for j, (res, out_col) in enumerate(zip(result, config['output'])):
190
- if isinstance(res, np.ndarray) and len(res) == len(df):
191
- df[out_col] = res
192
- nan_count = np.isnan(res).sum()
193
- if nan_count < len(res) * 0.5:
194
- valid_indicators.append(out_col)
195
- else:
196
- print_log(f"{out_col} has excessive NaNs: {nan_count}/{len(res)}. Excluding from valid indicators.", 'WARNING')
197
- else:
198
- print_log(f"Invalid output for {out_col}: {type(res)}, length: {len(res) if hasattr(res, '__len__') else 'N/A'}", 'WARNING')
199
- else:
200
- if isinstance(result, np.ndarray) and len(result) == len(df):
201
- df[config['output'][0]] = result
202
- nan_count = np.isnan(result).sum()
203
- if nan_count < len(result) * 0.5:
204
- valid_indicators.append(config['output'][0])
205
- else:
206
- print_log(f"{config['output'][0]} has excessive NaNs: {nan_count}/{len(result)}. Excluding from valid indicators.", 'WARNING')
207
- else:
208
- print_log(f"Invalid output for {ind}: {type(result)}, length: {len(result) if hasattr(result, '__len__') else 'N/A'}", 'WARNING')
209
- except Exception as e:
210
- print_log(f"Error computing {ind}: {str(e)}", 'ERROR')
211
- else:
212
- print_log(f"Indicator {ind} not supported by TA-Lib", 'WARNING')
213
-
214
- initial_rows = len(df)
215
- df = df.dropna(subset=['value']).reset_index(drop=False)
216
- print_log(f"Dropped {initial_rows - len(df)} rows with NaN in 'value'")
217
-
218
- for col in df.columns:
219
- if col not in ['Date', 'Open', 'High', 'Low', 'value', 'Volume']:
220
- nan_ratio = df[col].isna().mean()
221
- if nan_ratio > 0.5:
222
- print_log(f"Dropping {col} due to excessive NaNs: {nan_ratio:.2%}", 'WARNING')
223
- df = df.drop(columns=[col])
224
- if col in valid_indicators:
225
- valid_indicators.remove(col)
226
-
227
- if not valid_indicators:
228
- print_log("No valid indicators computed. Falling back to 'value'.", "WARNING")
229
- valid_indicators.append('value')
230
-
231
- print_log(f"Valid indicators: {valid_indicators}")
232
- print_log(f"Technical indicators added successfully, shape: {df.shape}")
233
- df.set_index('Date', inplace=True)
234
- return df, valid_indicators
235
- except Exception as e:
236
- print_log(f"Error in add_technical_indicators: {str(e)}", 'ERROR')
237
- return df, []
238
-
239
- def add_sentiment(df, ticker, news_api_key, start_date, end_date):
240
- try:
241
- print_log(f"Starting add_sentiment for {ticker} from {start_date} to {end_date}")
242
- if not news_api_key:
243
- print_log("News API key not provided. Skipping sentiment analysis.", 'WARNING')
244
- df['sentiment_score'] = 0.0
245
- return df
246
-
247
- newsapi = NewsApiClient(api_key=news_api_key)
248
- all_articles = []
249
- current_date = pd.to_datetime(start_date)
250
- end_date = pd.to_datetime(end_date)
251
-
252
- while current_date <= end_date:
253
- from_param = current_date.strftime("%Y-%m-%d")
254
- to_param = (current_date + timedelta(days=1)).strftime("%Y-%m-%d")
255
- print_log(f"Fetching news for {ticker} from {from_param} to {to_param}")
256
- try:
257
- articles = newsapi.get_everything(q=ticker, language='en', sort_by='relevancy', from_param=from_param, to=to_param)
258
- all_articles.extend(articles["articles"])
259
- except Exception as e:
260
- print_log(f"Error fetching news for {ticker} on {from_param}: {str(e)}", 'ERROR')
261
- current_date += timedelta(days=1)
262
- time.sleep(0.1)
263
-
264
- if not all_articles:
265
- print_log(f"No articles found for {ticker}. Setting sentiment to 0.", 'WARNING')
266
- df['sentiment_score'] = 0.0
267
- return df
268
-
269
- sentiment_data = []
270
- for article in all_articles:
271
- if article["publishedAt"] and article["description"]:
272
- date = pd.to_datetime(article["publishedAt"]).tz_localize(None).date()
273
- text = article["description"]
274
- vs = analyzer.polarity_scores(text)
275
- sentiment_data.append({"Date": date, "sentiment_score": vs["compound"]})
276
-
277
- sentiment_df = pd.DataFrame(sentiment_data)
278
- sentiment_df["Date"] = pd.to_datetime(sentiment_df["Date"])
279
- sentiment_df = sentiment_df.groupby("Date")["sentiment_score"].mean().reset_index()
280
-
281
- df.reset_index(inplace=True)
282
- df['Date'] = pd.to_datetime(df['Date'])
283
- df = pd.merge(df, sentiment_df, on="Date", how="left")
284
- df['sentiment_score'] = df['sentiment_score'].fillna(0.0)
285
- df.set_index('Date', inplace=True)
286
-
287
- print_log(f"Sentiment analysis completed for {ticker}. Added sentiment_score column.")
288
- return df
289
- except Exception as e:
290
- print_log(f"Error in add_sentiment for {ticker}: {str(e)}", 'ERROR')
291
- df['sentiment_score'] = 0.0
292
- return df
293
-
294
- def preprocess_data(df, features, target, window_size, horizon):
295
- try:
296
- print_log(f"Starting preprocessing: features={features}, target={target}, window={window_size}, horizon={horizon}")
297
-
298
- if not isinstance(df.index, pd.DatetimeIndex):
299
- raise ValueError("DataFrame index must be a DatetimeIndex for preprocessing.")
300
-
301
- updated_feature_cols = [f for f in features if f in df.columns]
302
- if not updated_feature_cols:
303
- raise ValueError("None of the selected features are available in the data.")
304
-
305
- data = df[updated_feature_cols].values
306
-
307
- scaler = MinMaxScaler(feature_range=(0, 1))
308
- scaled_data = scaler.fit_transform(data)
309
-
310
- X, y = [], []
311
- for i in range(len(scaled_data) - window_size - horizon + 1):
312
- X.append(scaled_data[i:(i + window_size), :])
313
- y.append(scaled_data[i + window_size + horizon - 1, updated_feature_cols.index(target)])
314
-
315
- X, y = np.array(X), np.array(y)
316
-
317
- if X.shape[1] != window_size or X.shape[2] != len(updated_feature_cols):
318
- raise ValueError(f"Shape mismatch in X: expected ({len(scaled_data) - window_size - horizon + 1}, {window_size}, {len(updated_feature_cols)}), got {X.shape}")
319
-
320
- print_log(f"Preprocessing complete. X shape: {X.shape}, y shape: {y.shape}")
321
- return X, y, scaler, updated_feature_cols
322
- except Exception as e:
323
- print_log(f"Error in preprocess_data: {str(e)}", 'ERROR')
324
- raise ValueError(f"Failed to preprocess data: {str(e)}")
325
-