File size: 6,657 Bytes
e0ff5fb
 
 
 
 
 
 
 
 
 
1e81e10
03e6a37
1e81e10
 
 
 
 
 
e0ff5fb
 
 
 
1e81e10
22a0f86
 
 
 
 
 
 
024bb73
1e81e10
0559530
e0ff5fb
 
 
0559530
1e81e10
 
 
 
 
 
 
 
 
 
0559530
1e81e10
 
 
 
 
 
 
 
 
0559530
1e81e10
 
0559530
 
1e81e10
e0ff5fb
 
 
 
 
 
1e81e10
 
 
 
 
e0ff5fb
 
 
1e81e10
 
e0ff5fb
1e81e10
 
 
e0ff5fb
 
0559530
e0ff5fb
 
03e6a37
 
e0ff5fb
 
 
 
 
1e81e10
e0ff5fb
 
 
 
1e81e10
e0ff5fb
 
0559530
03e6a37
 
 
 
e0ff5fb
0559530
03e6a37
e0ff5fb
 
1e81e10
 
 
0559530
 
1e81e10
03e6a37
e0ff5fb
024bb73
03e6a37
 
024bb73
 
03e6a37
 
e0ff5fb
0559530
03e6a37
 
 
1e81e10
 
 
 
e0ff5fb
0559530
 
 
 
 
22a0f86
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import os
import pandas as pd
import numpy as np
from datetime import timedelta
from binance.client import Client
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report
import ta

# Function to log results to both console and file
# Does not insert blank lines; blank lines added explicitly after each asset block
def log_results(message, filename="predictions_results.txt"):
    print(message)
    with open(filename, "a") as f:
        f.write(message + "\n")

# Initialize Binance client
client = Client()

# Settings
interval = Client.KLINE_INTERVAL_4HOUR
result_file = "predictions_results.txt"

# Delete the results file if it exists for a fresh start
if os.path.exists(result_file):
    os.remove(result_file)

# Initialize result file header
with open(result_file, "w") as f:
    f.write("Asset,Time,Price,Prediction,Optimal_UP_TP,Optimal_UP_SL,Optimal_DN_TP,Optimal_DN_SL\n")

# Get USDT-quoted trading symbols
symbols = [s['symbol'] for s in client.get_exchange_info()['symbols']
           if s['status']=='TRADING' and s['quoteAsset']=='USDT']

# Optimize take-profit / stop-loss function
def optimize_tp_sl(df, signals, side, pgrid, lgrid):
    best = (0, 0, -np.inf)
    prices = df['close'].values
    idxs = np.where(signals == side)[0]
    for tp in pgrid:
        for sl in lgrid:
            rets = []
            for i in idxs:
                entry = prices[i]
                for j in range(i+1, min(i+11, len(prices))):
                    ret = (prices[j] - entry) / entry if side == 1 else (entry - prices[j]) / entry
                    if ret >= tp or ret <= -sl:
                        rets.append(np.sign(ret) * min(abs(ret), max(tp, sl)))
                        break
            if rets:
                avg_ret = np.mean(rets)
                if avg_ret > best[2]:
                    best = (tp, sl, avg_ret)
    return best

# Process each symbol
for symbol in symbols:
    log_results(f"=== {symbol} ===", result_file)

    # Load or download historical data
    data_file = f"{symbol}_data_4h_full.csv"
    if os.path.exists(data_file):
        df = pd.read_csv(data_file, index_col=0, parse_dates=True)
        last_ts = df.index[-1]
        start = (last_ts + timedelta(hours=4)).strftime("%d %B %Y %H:%M:%S")
        new = client.get_historical_klines(symbol, interval, start)
        if new:
            new_df = pd.DataFrame(new, columns=['timestamp','open','high','low','close','volume',
                                                'close_time','quote_av','trades','tb_base_av','tb_quote_av','ignore'])
            new_df = new_df[['timestamp','open','high','low','close','volume']].astype(float)
            new_df['timestamp'] = pd.to_datetime(new_df['timestamp'], unit='ms')
            new_df.set_index('timestamp', inplace=True)
            df = pd.concat([df, new_df]).drop_duplicates()
            df.to_csv(data_file)
    else:
        klines = client.get_historical_klines(symbol, interval, "01 December 2021")
        df = pd.DataFrame(klines, columns=['timestamp','open','high','low','close','volume',
                                           'close_time','quote_av','trades','tb_base_av','tb_quote_av','ignore'])
        df = df[['timestamp','open','high','low','close','volume']].astype(float)
        df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
        df.set_index('timestamp', inplace=True)
        df.to_csv(data_file)

    # Compute technical indicators
    df['rsi'] = ta.momentum.RSIIndicator(df['close'], window=14).rsi()
    df['macd'] = ta.trend.MACD(df['close']).macd()
    for s in [10, 20, 50, 100]: df[f'ema_{s}'] = df['close'].ewm(span=s).mean()
    for w in [10, 20, 50, 100]: df[f'sma_{w}'] = df['close'].rolling(window=w).mean()
    bb = ta.volatility.BollingerBands(df['close'], window=20, window_dev=2)
    df['bbw'] = (bb.bollinger_hband() - bb.bollinger_lband()) / bb.bollinger_mavg()
    df['atr'] = ta.volatility.AverageTrueRange(df['high'], df['low'], df['close'], window=14).average_true_range()
    df['adx'] = ta.trend.ADXIndicator(df['high'], df['low'], df['close'], window=14).adx()
    st = ta.momentum.StochasticOscillator(df['high'], df['low'], df['close'], window=14)
    df['st_k'] = st.stoch(); df['st_d'] = st.stoch_signal()
    df['wr'] = ta.momentum.WilliamsRIndicator(df['high'], df['low'], df['close'], lbp=14).williams_r()
    df['cci'] = ta.trend.CCIIndicator(df['high'], df['low'], df['close'], window=20).cci()
    df['mom'] = df['close'] - df['close'].shift(10)
    ichi = ta.trend.IchimokuIndicator(df['high'], df['low'], window1=9, window2=26, window3=52)
    df['span_a'] = ichi.ichimoku_a(); df['span_b'] = ichi.ichimoku_b()
    df.dropna(inplace=True)

    # Label signals based on Ichimoku cloud
    df['signal'] = np.select([
        (df['close'] > df['span_a']) & (df['close'] > df['span_b']),
        (df['close'] < df['span_a']) & (df['close'] < df['span_b'])
    ], [1, 0], default=-1)

    # Train/test split
    features = [c for c in df.columns if c not in ['open', 'high', 'low', 'close', 'volume', 'signal']]
    X, y = df[features], df['signal']
    Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.2, shuffle=False)
    model = RandomForestClassifier(n_estimators=200, class_weight='balanced', random_state=42)
    model.fit(Xtr, ytr)
    ypr = model.predict(Xte)

    # Log classification report
    report = classification_report(yte, ypr, zero_division=0)
    log_results(f"Classification report for {symbol}: {report}", result_file)

    # Predict latest trend and log time & price
    latest_df = X.iloc[-1:]  # DataFrame for prediction
    trend_label = model.predict(latest_df)[0]
    pred_time = df.index[-1]
    pred_price = df['close'].iloc[-1]
    trend_str = {1:'Uptrend', 0:'Downtrend', -1:'Neutral'}[trend_label]
    log_results(f"Time: {pred_time}, Price: {pred_price:.2f}, Prediction: {trend_str}", result_file)

    # Optimize TP/SL and log results
    hist_sign = model.predict(X)  # Pass DataFrame to avoid warning
    pgrid = np.arange(0.01, 0.1, 0.01)
    lgrid = np.arange(0.01, 0.1, 0.01)
    up_tp, up_sl, _ = optimize_tp_sl(df, hist_sign, 1, pgrid, lgrid)
    dn_tp, dn_sl, _ = optimize_tp_sl(df, hist_sign, 0, pgrid, lgrid)
    log_results(f"Optimal UP TP/SL: +{up_tp*100:.1f}% / -{up_sl*100:.1f}%", result_file)
    log_results(f"Optimal DN TP/SL: +{dn_tp*100:.1f}% / -{dn_sl*100:.1f}%", result_file)

    # Add a blank line after each asset block
    with open(result_file, "a") as f:
        f.write("\n")

# End of processing
log_results("All assets processed.", result_file)