Lullooo commited on
Commit
880c461
·
verified ·
1 Parent(s): c33c83d

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +186 -0
app.py ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ################### PACKAGES
2
+ import pandas as pd
3
+ import numpy as np
4
+ from datetime import datetime, timedelta
5
+ import time
6
+ import requests
7
+ from pytrends.request import TrendReq
8
+ import joblib
9
+ import gradio as gr
10
+ from sklearn.preprocessing import StandardScaler
11
+
12
+
13
+ ################### MODEL LOADING
14
+ # Load XGBoost and NGBoost
15
+ xgb_artifact = joblib.load("xgb_volatility_model.joblib")
16
+ xgb_model = xgb_artifact["model"]
17
+ xgb_features = xgb_artifact["feature_names"]
18
+
19
+ ngb_artifact = joblib.load("ngb_volatility_model.joblib")
20
+ ngb_model = ngb_artifact["model"]
21
+ ngb_features = ngb_artifact["feature_names"]
22
+
23
+ forecast_ngb_artifact = joblib.load("Forecast_ngb_volatility_model.joblib")
24
+ forecast_ngb_model = forecast_ngb_artifact["model"]
25
+ forecast_ngb_features = forecast_ngb_artifact["feature_names"]
26
+
27
+ # Load KMeans + scaler
28
+ kmeans_artifact = joblib.load("kmeans_model.joblib")
29
+ kmeans_model = kmeans_artifact["model"]
30
+ cluster_scaler = kmeans_artifact["scaler"]
31
+ cluster_features_names = kmeans_artifact["feature_names"]
32
+
33
+
34
+ ################### FEATURE GATHERING
35
+ def fetch_ohlcv_last_n_days(date="2026-01-18", n_days=90):
36
+ end = pd.to_datetime(date)
37
+ start = end - timedelta(days=n_days)
38
+
39
+ url = "https://api.coingecko.com/api/v3/coins/bitcoin/market_chart/range"
40
+ params = {
41
+ "vs_currency": "usd",
42
+ "from": int(start.timestamp()),
43
+ "to": int(end.timestamp())
44
+ }
45
+
46
+ r = requests.get(url, params=params, timeout=20)
47
+ r.raise_for_status()
48
+ data = r.json()
49
+
50
+ prices = pd.DataFrame(data["prices"], columns=["timestamp", "close"])
51
+ volumes = pd.DataFrame(data["total_volumes"], columns=["timestamp", "volume"])
52
+
53
+ df = prices.merge(volumes, on="timestamp")
54
+ df["timestamp"] = pd.to_datetime(df["timestamp"], unit="ms")
55
+ df.set_index("timestamp", inplace=True)
56
+
57
+ df = df.resample("1D").agg(
58
+ open=("close", "first"),
59
+ high=("close", "max"),
60
+ low=("close", "min"),
61
+ close=("close", "last"),
62
+ volume=("volume", "sum")
63
+ ).dropna()
64
+
65
+ return df
66
+
67
+ def fetch_fg_last_6_days(df):
68
+ url = "https://api.alternative.me/fng/?limit=0&format=json"
69
+ response = requests.get(url)
70
+ fg_df = pd.DataFrame(response.json()["data"])
71
+ fg_df["timestamp"] = pd.to_datetime(fg_df["timestamp"], unit="s")
72
+ fg_df.set_index("timestamp", inplace=True)
73
+ fg_df = fg_df[["value"]].astype(float)
74
+ fg_df.rename(columns={"value":"fg_index"}, inplace=True)
75
+ fg_df = fg_df.reindex(df.index, method="ffill")
76
+ df["fg_index"] = fg_df["fg_index"].values
77
+ return df
78
+
79
+ def fetch_google_trend_for_date(keyword="Bitcoin", target_date="2024-01-15", window=7):
80
+ pytrends = TrendReq(hl="en-US", tz=360)
81
+ target_date = pd.to_datetime(target_date)
82
+ start_date = (target_date - timedelta(days=window)).strftime("%Y-%m-%d")
83
+ end_date = target_date.strftime("%Y-%m-%d")
84
+ timeframe = f"{start_date} {end_date}"
85
+ try:
86
+ pytrends.build_payload([keyword], timeframe=timeframe)
87
+ df = pytrends.interest_over_time()
88
+ if df.empty:
89
+ return 0
90
+ df = df.rename(columns={keyword: "trend"})
91
+ df = df.drop(columns=["isPartial"], errors="ignore")
92
+ df.index = pd.to_datetime(df.index)
93
+ if target_date in df.index:
94
+ return df.loc[target_date, "trend"]
95
+ else:
96
+ return 0
97
+ except:
98
+ return 0
99
+
100
+
101
+ ################### FEATURE ENGINEERING
102
+ def engineer_features(df):
103
+ df["log_return"] = np.log(df["close"] / df["close"].shift(1))
104
+ df["hl_spread"] = df["high"] - df["low"]
105
+ df["co_spread"] = df["close"] - df["open"]
106
+ df["momentum_3"] = df["close"] - df["close"].shift(3)
107
+ df["vol_change"] = df["volume"] - df["volume"].shift(1)
108
+ df["rolling_std_5"] = df["log_return"].rolling(5).std()
109
+ # Fill NaNs for first few rows
110
+ df = df.fillna(0)
111
+ return df
112
+
113
+ ################### ASSIGN CLUSTER
114
+ def assign_cluster(df):
115
+ cluster_features = df[cluster_features_names]
116
+ scaled = cluster_scaler.transform(cluster_features)
117
+ df["cluster"] = kmeans_model.predict(scaled)
118
+ return df
119
+
120
+
121
+ ################### PREDICTION FUNCTION
122
+ def predict_volatility(date):
123
+ # Fetch raw data
124
+ df = fetch_ohlcv_last_n_days(date=date, n_days=90)
125
+ df = fetch_fg_last_6_days(df)
126
+ trend_value = fetch_google_trend_for_date("Bitcoin", date)
127
+ df["trend"] = trend_value
128
+ df["trend"] = df["trend"].ffill().fillna(0)
129
+
130
+ # Feature engineering
131
+ df = engineer_features(df)
132
+ df = df.dropna()
133
+
134
+ # Clustering
135
+ df = assign_cluster(df)
136
+
137
+ # ---------------- NOWCASTING ----------------
138
+ X_xgb = df.iloc[-1:][xgb_features]
139
+ X_ngb = df.iloc[-1:][ngb_features]
140
+
141
+ point = xgb_model.predict(X_xgb)[0]
142
+ dist = ngb_model.pred_dist(X_ngb)
143
+ low, high = dist.ppf([0.025, 0.975])[0]
144
+
145
+ # ---------------- FORECASTING (t+1) ----------------
146
+ X_ngb_fore = df.iloc[-1:][forecast_ngb_features]
147
+
148
+ for_point = forecast_ngb_model.predict(X_ngb_fore)[0]
149
+ for_dist = forecast_ngb_model.pred_dist(X_ngb_fore)
150
+ for_low, for_high = for_dist.ppf([0.025, 0.975])[0]
151
+
152
+ return point, low, high, for_point, for_low, for_high
153
+
154
+
155
+
156
+ ################### GRADIO INTERFACE
157
+ def gradio_predict(date):
158
+ try:
159
+ pd.to_datetime(date)
160
+ except:
161
+ return "❌ Invalid date format. Please use YYYY-MM-DD."
162
+
163
+ try:
164
+ point, low, high, for_point, for_low, for_high = predict_volatility(date)
165
+
166
+ return (
167
+ f"NOWCAST (t)\n"
168
+ f"Volatility: {point:.4f}\n"
169
+ f"95% CI: [{low:.4f}, {high:.4f}]\n\n"
170
+ f"FORECAST (t+1)\n"
171
+ f"Volatility: {for_point:.4f}\n"
172
+ f"95% CI: [{for_low:.4f}, {for_high:.4f}]"
173
+ )
174
+ except Exception as e:
175
+ return f"⚠️ Error while computing prediction:\n{str(e)}"
176
+
177
+ demo = gr.Interface(
178
+ fn=gradio_predict,
179
+ inputs=gr.Textbox(label="Date (YYYY-MM-DD)"),
180
+ outputs=gr.Textbox(label="Prediction"),
181
+ title="Crypto Volatility Predictor",
182
+ description="Enter a date to get predicted volatility and 95% confidence interval."
183
+ )
184
+
185
+ if __name__ == "__main__":
186
+ demo.launch()