File size: 4,675 Bytes
a9237fb
 
 
 
 
 
 
 
 
 
 
82f3669
a9237fb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bd0531f
e20f3e9
a9237fb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import pandas as pd
import numpy as np
import yfinance as yf
from datetime import datetime, timedelta
import warnings
warnings.filterwarnings('ignore')

class DataProcessor:
    def __init__(self):
        pass
    
    def download_stock_data(self, symbol, period="1y", interval="1d"):
        """Download stock data using yfinance"""
        try:
            ticker = yf.Ticker(symbol)
            data = ticker.history(period=period, interval=interval)
            
            if data.empty:
                return None
            
            # Clean column names
            data.columns = [col.title() for col in data.columns]
            
            # Remove timezone info for consistency
            if data.index.tz is not None:
                data.index = data.index.tz_localize(None)
            
            return data
            
        except Exception as e:
            print(f"Error downloading data for {symbol}: {str(e)}")
            return None

    def prepare_features_and_labels(self, data, future_days=3, threshold=0.02):
        """Prepare features and labels for machine learning"""
        try:
            # Calculate future returns for labeling
            data = data.copy()
            data['Future_Return'] = data['Close'].pct_change(periods=future_days).shift(-future_days)
            
            # Create labels based on future returns
            # 1 = BUY (expected gain > threshold)
            # -1 = SELL (expected loss > threshold) 
            # 0 = HOLD (neutral)
            conditions = [
                data['Future_Return'] > threshold,
                data['Future_Return'] < -threshold
            ]
            choices = [1, -1]
            data['Label'] = np.select(conditions, choices, default=0)
            
            # Select feature columns (all technical indicators)
            feature_columns = [col for col in data.columns if col not in 
                             ['Open', 'High', 'Low', 'Close', 'Volume', 'Future_Return', 'Label']]
            
            # Remove rows with NaN values
            clean_data = data.dropna()
            
            if len(clean_data) == 0:
                return pd.DataFrame(), pd.Series()
            
            # Prepare features and labels
            features = clean_data[feature_columns]
            labels = clean_data['Label']
            
            return features, labels
            
        except Exception as e:
            print(f"Error preparing features and labels: {str(e)}")
            return pd.DataFrame(), pd.Series()
    
    def get_latest_features(self, data, feature_columns):
        """Extract latest features for prediction"""
        try:
            if data.empty or not feature_columns:
                return None
            
            # Get the latest row with all required features
            latest_data = data[feature_columns].dropna()
            
            if latest_data.empty:
                return None
            
            # Return the latest row as a list
            return latest_data.iloc[-1].values.tolist()
            
        except Exception as e:
            print(f"Error extracting latest features: {str(e)}")
            return None
    
    def calculate_returns(self, data, periods=[1, 3, 5]):
        """Calculate returns for different periods"""
        try:
            returns_data = data.copy()
            
            for period in periods:
                returns_data[f'Return_{period}d'] = data['Close'].pct_change(periods=period)
            
            return returns_data
            
        except Exception as e:
            print(f"Error calculating returns: {str(e)}")
            return data
    
    def add_price_features(self, data):
        """Add additional price-based features"""
        try:
            enhanced_data = data.copy()
            
            # Price position within daily range
            enhanced_data['Price_Position'] = (data['Close'] - data['Low']) / (data['High'] - data['Low'])
            enhanced_data['Price_Position'].fillna(0.5, inplace=True)
            
            # Gap from previous close
            enhanced_data['Gap'] = (data['Open'] - data['Close'].shift(1)) / data['Close'].shift(1)
            
            # Intraday return
            enhanced_data['Intraday_Return'] = (data['Close'] - data['Open']) / data['Open']
            
            # High-Low spread
            enhanced_data['HL_Spread'] = (data['High'] - data['Low']) / data['Close']
            
            return enhanced_data
            
        except Exception as e:
            print(f"Error adding price features: {str(e)}")
            return data