daafa999 commited on
Commit
b25f99e
ยท
verified ยท
1 Parent(s): d340cdd

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +211 -0
app.py ADDED
@@ -0,0 +1,211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import ccxt
3
+ import pandas as pd
4
+ import pandas_ta as ta
5
+ import numpy as np
6
+ from sklearn.ensemble import RandomForestClassifier
7
+ from sklearn.preprocessing import MinMaxScaler
8
+ import joblib
9
+ import os
10
+ import json
11
+ from datetime import datetime
12
+
13
+ # Konfigurasi
14
+ SYMBOL = "ETH/USDT"
15
+ TIMEFRAME = "4h"
16
+ FEE = 0.0015
17
+ WINDOW = 60
18
+ MODEL_PATH = "rf_model.pkl"
19
+ SCALER_PATH = "scaler.pkl"
20
+
21
+ def fetch_data(symbol: str, timeframe: str, limit: int = 2000) -> pd.DataFrame:
22
+ """Ambil data dari Binance"""
23
+ try:
24
+ exchange = ccxt.binance({'enableRateLimit': True})
25
+ ohlcv = exchange.fetch_ohlcv(symbol, timeframe, limit=limit)
26
+ df = pd.DataFrame(ohlcv, columns=["timestamp", "open", "high", "low", "close", "volume"])
27
+ df["timestamp"] = pd.to_datetime(df["timestamp"], unit="ms")
28
+ return df
29
+ except Exception as e:
30
+ return pd.DataFrame()
31
+
32
+ def prepare_dataset(df: pd.DataFrame):
33
+ """Siapkan dataset dengan indikator teknikal"""
34
+ if df.empty:
35
+ return None, None, None, None, None
36
+
37
+ df = df.copy()
38
+
39
+ try:
40
+ df.ta.rsi(length=14, append=True)
41
+ df.ta.macd(fast=12, slow=26, signal=9, append=True)
42
+ df.ta.bbands(length=20, append=True)
43
+ df.ta.cci(length=14, append=True)
44
+ except Exception as e:
45
+ return None, None, None, None, None
46
+
47
+ df.dropna(inplace=True)
48
+
49
+ df["next_close"] = df["close"].shift(-1)
50
+ df["label"] = (df["next_close"] > df["close"] * (1 + FEE)).astype(int)
51
+ df.dropna(inplace=True)
52
+
53
+ X_list, y_list, idx_list = [], [], []
54
+ feature_cols = [col for col in df.columns if col not in ["timestamp", "next_close", "label"]]
55
+
56
+ for i in range(WINDOW, len(df)):
57
+ window = df.iloc[i-WINDOW:i][feature_cols]
58
+ X_list.append(window.values.flatten())
59
+ y_list.append(df.iloc[i]["label"])
60
+ idx_list.append(i)
61
+
62
+ X = np.array(X_list)
63
+ y = np.array(y_list)
64
+ scaler = MinMaxScaler()
65
+ X_scaled = scaler.fit_transform(X)
66
+
67
+ return X_scaled, y, idx_list, df, scaler
68
+
69
+ def train_model():
70
+ """Training model dan backtest"""
71
+ if os.path.exists(MODEL_PATH):
72
+ return "Model sudah ada. Hapus file model untuk retrain."
73
+
74
+ df = fetch_data(SYMBOL, TIMEFRAME)
75
+ if df.empty:
76
+ return "โŒ Gagal mengambil data"
77
+
78
+ X, y, idx, df_full, scaler = prepare_dataset(df)
79
+ if X is None:
80
+ return "โŒ Gagal menyiapkan dataset"
81
+
82
+ split = int(len(X) * 0.95)
83
+ X_train, X_test = X[:split], X[split:]
84
+ y_train, y_test = y[:split], y[split:]
85
+
86
+ model = RandomForestClassifier(n_estimators=500, max_depth=None, random_state=42, n_jobs=-1)
87
+ model.fit(X_train, y_train)
88
+ acc = float(model.score(X_test, y_test))
89
+
90
+ joblib.dump(model, MODEL_PATH)
91
+ joblib.dump(scaler, SCALER_PATH)
92
+
93
+ # Backtest
94
+ test_indices = idx[split:]
95
+ df_test = df_full.loc[test_indices].copy()
96
+ df_test["pred"] = model.predict(X_test)
97
+
98
+ pnl_list = []
99
+ for i in range(len(df_test) - 1):
100
+ if df_test.iloc[i]["pred"] == 1:
101
+ entry = df_test.iloc[i]["close"]
102
+ exit_ = df_test.iloc[i + 1]["close"]
103
+ ret = (exit_ - entry) / entry
104
+ pnl = ret - FEE
105
+ pnl_list.append(pnl)
106
+
107
+ wins = sum(1 for p in pnl_list if p > 0)
108
+ losses = len(pnl_list) - wins
109
+ gross_profit = sum(p for p in pnl_list if p > 0)
110
+ gross_loss = sum(abs(p) for p in pnl_list if p <= 0)
111
+ profit_factor = gross_profit / gross_loss if gross_loss > 0 else float("inf")
112
+
113
+ result = f"""
114
+ โœ… **Training Selesai!**
115
+
116
+ ๐Ÿ“Š **Hasil Backtest (66 hari):**
117
+ - Accuracy: {acc:.2%}
118
+ - Profit Factor: {profit_factor:.3f}
119
+ - Net Profit: {sum(pnl_list)*100:.2f}%
120
+ - Win Rate: {wins/len(pnl_list)*100:.2f}%
121
+ - Total Trades: {len(pnl_list)}
122
+ - Wins: {wins} | Losses: {losses}
123
+ """
124
+ return result
125
+
126
+ def predict_next_move():
127
+ """Prediksi pergerakan harga berikutnya"""
128
+ if not os.path.exists(MODEL_PATH):
129
+ return "โŒ Model belum dilatih. Klik tombol 'Train Model' terlebih dahulu."
130
+
131
+ df = fetch_data(SYMBOL, TIMEFRAME, limit=WINDOW + 10)
132
+ _, _, _, df_full, scaler = prepare_dataset(df)
133
+
134
+ if df_full is None or len(df_full) < WINDOW:
135
+ return "โŒ Data tidak cukup untuk prediksi"
136
+
137
+ feature_cols = [col for col in df_full.columns if col not in ["timestamp", "next_close", "label"]]
138
+ latest_window = df_full.iloc[-WINDOW:][feature_cols].values.flatten().reshape(1, -1)
139
+ latest_scaled = scaler.transform(latest_window)
140
+
141
+ model = joblib.load(MODEL_PATH)
142
+ pred = int(model.predict(latest_scaled)[0])
143
+ proba = model.predict_proba(latest_scaled)[0]
144
+
145
+ signal = "๐ŸŸข **BUY** (Hold 4 jam)" if pred == 1 else "๐Ÿ”ด **HOLD/SELL**"
146
+
147
+ result = f"""
148
+ ๐Ÿ“ˆ **Prediksi {SYMBOL} - {TIMEFRAME}**
149
+
150
+ Signal: {signal}
151
+
152
+ **Probabilitas:**
153
+ - Naik (>0.15%): {proba[1]*100:.2f}%
154
+ - Turun/Stagnan: {proba[0]*100:.2f}%
155
+ - Confidence: {max(proba)*100:.2f}%
156
+
157
+ **Waktu Prediksi:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
158
+ """
159
+ return result
160
+
161
+ def get_price_chart():
162
+ """Generate price chart data"""
163
+ df = fetch_data(SYMBOL, TIMEFRAME, limit=200)
164
+ if df.empty:
165
+ return None
166
+
167
+ # Buat simple chart data
168
+ chart_data = df[['timestamp', 'close']].tail(100).copy()
169
+ return chart_data
170
+
171
+ # Gradio Interface
172
+ with gr.Blocks(title="Crypto ML Trading Strategy", theme=gr.themes.Soft()) as demo:
173
+ gr.Markdown("""
174
+ # Crypto ML Trading Strategy
175
+ **Paper Reference:** [2105.06827v3](https://arxiv.org/abs/2105.06827)
176
+
177
+ Prediksi arah harga cryptocurrency menggunakan Machine Learning (Random Forest) dengan indikator teknikal.
178
+ """)
179
+
180
+ with gr.Row():
181
+ with gr.Column():
182
+ gr.Markdown("### ๐Ÿ“Š Kontrol")
183
+ train_btn = gr.Button("๐ŸŽฏ Train Model", variant="primary")
184
+ predict_btn = gr.Button("๐Ÿ”ฎ Prediksi Sekarang")
185
+ chart_btn = gr.Button("๐Ÿ“ˆ Lihat Chart")
186
+
187
+ with gr.Column():
188
+ gr.Markdown("### ๐Ÿ’ก Informasi")
189
+ gr.Markdown("""
190
+ - **Asset:** ETH/USDT
191
+ - **Timeframe:** 4 Jam
192
+ - **Model:** Random Forest
193
+ - **Threshold:** 0.15% (fee Binance)
194
+ - **Data:** 2017-2021
195
+ """)
196
+
197
+ output = gr.Textbox(label="Hasil", lines=15)
198
+ chart_output = gr.Dataframe(label="Price Data")
199
+
200
+ train_btn.click(fn=train_model, inputs=None, outputs=output)
201
+ predict_btn.click(fn=predict_next_move, inputs=None, outputs=output)
202
+ chart_btn.click(fn=get_price_chart, inputs=None, outputs=chart_output)
203
+
204
+ gr.Markdown("""
205
+ ---
206
+ **Disclaimer:** Ini adalah proof-of-concept akademis. Bukan saran finansial.
207
+ Trading cryptocurrency berisiko tinggi.
208
+ """)
209
+
210
+ if __name__ == "__main__":
211
+ demo.launch()