File size: 3,744 Bytes
03d7347
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import yfinance as yf
import pandas as pd
import numpy as np

def fetch_data(symbol, period='2y', interval='1d'):
    """

    Fetch historical data for a given symbol.

    Symbols: BTC-USD, ETH-USD, GC=F (Gold), CL=F (Oil), SI=F (Silver)

    """
    ticker = yf.Ticker(symbol)
    df = ticker.history(period=period, interval=interval)
    return df

def add_indicators(df):
    """

    Add technical indicators manually to avoid dependency issues with pandas_ta on Python 3.14.

    """
    # EMA for trend
    df['EMA_20'] = df['Close'].ewm(span=20, adjust=False).mean()
    df['EMA_50'] = df['Close'].ewm(span=50, adjust=False).mean()
    
    # RSI for momentum
    delta = df['Close'].diff()
    gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
    loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
    # Handle division by zero safely
    rs = gain / loss.replace(0, np.finfo(float).eps)
    df['RSI'] = 100 - (100 / (1 + rs))
    
    # MACD
    exp1 = df['Close'].ewm(span=12, adjust=False).mean()
    exp2 = df['Close'].ewm(span=26, adjust=False).mean()
    df['MACD'] = exp1 - exp2
    df['MACD_Signal'] = df['MACD'].ewm(span=9, adjust=False).mean()
    
    # Bollinger Bands
    df['BB_Mid'] = df['Close'].rolling(window=20).mean()
    df['BB_Std'] = df['Close'].rolling(window=20).std()
    df['BB_Upper'] = df['BB_Mid'] + (df['BB_Std'] * 2)
    df['BB_Lower'] = df['BB_Mid'] - (df['BB_Std'] * 2)
    
    # ATR for volatility
    high_low = df['High'] - df['Low']
    high_close = np.abs(df['High'] - df['Close'].shift())
    low_close = np.abs(df['Low'] - df['Close'].shift())
    ranges = pd.concat([high_low, high_close, low_close], axis=1)
    true_range = np.max(ranges, axis=1)
    df['ATR'] = true_range.rolling(window=14).mean()
    
    # Simple Candlestick Patterns
    # Hammer: Small body, long lower shadow, little/no upper shadow
    body = (df['Close'] - df['Open']).abs()
    range_ = df['High'] - df['Low']
    # Hammer definition: lower shadow > 2 * body, upper shadow < body, body in upper 1/3 of range
    df['CDL_Hammer'] = (range_ > 3 * body) & \
                       ((df[['Open', 'Close']].min(axis=1) - df['Low']) > 2 * body) & \
                       ((df['High'] - df[['Open', 'Close']].max(axis=1)) < body)
    
    # Engulfing: Current body completely covers previous body with opposite direction
    prev_open = df['Open'].shift(1)
    prev_close = df['Close'].shift(1)
    # Bullish Engulfing
    bull_eng = (df['Close'] > df['Open']) & (prev_close < prev_open) & \
               (df['Close'] > prev_open) & (df['Open'] < prev_close)
    # Bearish Engulfing
    bear_eng = (df['Close'] < df['Open']) & (prev_close > prev_open) & \
               (df['Close'] < prev_open) & (df['Open'] > prev_close)
    
    df['CDL_Bull_Engulfing'] = bull_eng
    df['CDL_Bear_Engulfing'] = bear_eng

    df.dropna(inplace=True)
    return df

def prepare_ml_data(df, window_size=10):
    """

    Prepare sequences for the model.

    """
    # Select numeric features only
    features = ['Open', 'High', 'Low', 'Close', 'Volume', 'EMA_20', 'EMA_50', 'RSI', 'MACD', 'ATR']
    data = df[features].values
    
    # Target: Close price of the next day > current Close price
    target = (df['Close'].shift(-1) > df['Close']).astype(int).values
    
    X = []
    y = []
    
    for i in range(window_size, len(data) - 1):
        X.append(data[i-window_size:i])
        y.append(target[i])
        
    # Also return the latest window for prediction (we don't have target for this one)
    latest_window = data[len(data)-window_size:]
    
    return np.array(X), np.array(y), latest_window