jhub123 commited on
Commit
3388264
·
verified ·
1 Parent(s): ac725f6

i want to see the actual predictions and charts

Browse files
Files changed (3) hide show
  1. backend/app.py +32 -11
  2. pair-details.html +215 -37
  3. script.js +18 -7
backend/app.py CHANGED
@@ -110,20 +110,41 @@ async def create_order():
110
  """Place new order"""
111
  # TODO: Implement Binance API integration with risk checks
112
  return {"status": "success", "message": "Order placed"}
113
-
114
  @app.get("/api/signal/{symbol}", dependencies=[Depends(get_api_key)])
115
  async def get_signal(symbol: str, timeframe: str = "5m"):
116
  """Get model prediction for symbol"""
117
- # TODO: Implement ML model prediction
118
- return {
119
- "symbol": symbol,
120
- "timeframe": timeframe,
121
- "prob_up": 0.67,
122
- "prob_down": 0.33,
123
- "confidence": 0.82,
124
- "advice": "long_bias"
125
- }
126
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  @app.get("/api/risk/check", dependencies=[Depends(get_api_key)])
128
  async def risk_check():
129
  """Check if trade passes risk parameters"""
 
110
  """Place new order"""
111
  # TODO: Implement Binance API integration with risk checks
112
  return {"status": "success", "message": "Order placed"}
 
113
  @app.get("/api/signal/{symbol}", dependencies=[Depends(get_api_key)])
114
  async def get_signal(symbol: str, timeframe: str = "5m"):
115
  """Get model prediction for symbol"""
116
+ try:
117
+ # Get latest klines from Binance
118
+ binance = BinanceAdapter()
119
+ klines = binance.get_klines(
120
+ symbol=symbol,
121
+ interval=timeframe,
122
+ limit=100
123
+ )
124
+
125
+ # Format candles for model
126
+ candles = [{
127
+ "open": float(k[1]),
128
+ "high": float(k[2]),
129
+ "low": float(k[3]),
130
+ "close": float(k[4]),
131
+ "volume": float(k[5]),
132
+ "timestamp": k[0]
133
+ } for k in klines]
134
+
135
+ # Get prediction from model
136
+ return await model_router.get_signal(symbol, candles)
137
+
138
+ except Exception as e:
139
+ logger.error(f"Error generating signal: {e}")
140
+ return {
141
+ "symbol": symbol,
142
+ "timeframe": timeframe,
143
+ "prob_up": 0.5,
144
+ "prob_down": 0.5,
145
+ "confidence": 0,
146
+ "advice": "neutral"
147
+ }
148
  @app.get("/api/risk/check", dependencies=[Depends(get_api_key)])
149
  async def risk_check():
150
  """Check if trade passes risk parameters"""
pair-details.html CHANGED
@@ -5,8 +5,20 @@
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>CryptoPilot Pro - Trading Pair</title>
7
  <link rel="stylesheet" href="style.css">
8
- <script src="https://cdn.tailwindcss.com"></script>
9
- <script src="https://unpkg.com/feather-icons"></script>
 
 
 
 
 
 
 
 
 
 
 
 
10
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
11
  </head>
12
  <body class="bg-gray-50 min-h-screen">
@@ -88,76 +100,242 @@
88
  </main>
89
 
90
  <custom-footer></custom-footer>
91
-
92
  <script src="components/navbar.js"></script>
93
  <script src="components/footer.js"></script>
94
  <script src="script.js"></script>
 
95
  <script>
96
- document.addEventListener('DOMContentLoaded', () => {
 
 
 
 
 
97
  feather.replace();
98
- loadPairData();
 
99
  });
100
 
101
  async function loadPairData() {
102
  const params = new URLSearchParams(window.location.search);
103
  const pair = params.get('pair') || 'BTC/USDT';
 
104
  document.getElementById('pair-title').textContent = pair;
105
 
106
  try {
107
- // Fetch pair data (simulated)
108
- const response = await fetch(`/api/signal/${pair.split('/')[0]}`);
109
- const data = await response.json();
110
-
111
- // Update UI
112
- document.getElementById('current-price').textContent = `$${(Math.random() * 10000).toFixed(2)}`;
113
- document.getElementById('up-prob').textContent = `${Math.round(data.prob_up * 100)}%`;
114
- document.getElementById('down-prob').textContent = `${Math.round(data.prob_down * 100)}%`;
115
- document.getElementById('up-progress').style.width = `${data.prob_up * 100}%`;
116
- document.getElementById('down-progress').style.width = `${data.prob_down * 100}%`;
117
- document.getElementById('trading-advice').textContent = data.advice.replace('_', ' ').toUpperCase();
 
 
 
 
 
 
 
 
 
 
 
 
118
 
119
- // Update chart
120
- updateChart(pair);
 
 
 
 
 
 
 
121
 
122
  // Update predictions table
123
- updatePredictionsTable(pair);
124
  } catch (error) {
125
  console.error('Error loading pair data:', error);
126
  }
127
  }
128
 
129
- function updateChart(pair) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  const ctx = document.getElementById('price-chart').getContext('2d');
131
- const labels = [];
132
- const data = [];
133
- let currentPrice = 50000;
134
 
135
- for (let i = 30; i >= 0; i--) {
136
- labels.push(`${i}m`);
137
- currentPrice += (Math.random() - 0.5) * 100;
138
- data.push(currentPrice);
139
- }
140
 
141
- new Chart(ctx, {
142
- type: 'line',
 
143
  data: {
144
  labels: labels,
145
  datasets: [{
146
  label: `${pair} Price`,
147
- data: data,
148
- borderColor: '#6366f1',
149
- tension: 0.1,
150
- fill: false
 
 
 
 
 
 
 
 
151
  }]
152
  },
153
  options: {
154
  responsive: true,
155
- maintainAspectRatio: false
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  }
157
- });
158
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
 
160
- function updatePredictionsTable(pair) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  const table = document.getElementById('predictions-table');
162
  const predictions = [
163
  { time: '5m ago', prediction: 'UP', actual: 'UP', confidence: '85%' },
 
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>CryptoPilot Pro - Trading Pair</title>
7
  <link rel="stylesheet" href="style.css">
8
+ <script src="https://cdn.tailwindcss.com">
9
+ </script>
10
+ <style>
11
+ #volume-chart {
12
+ height: 100px;
13
+ width: 100%;
14
+ margin-top: 1rem;
15
+ }
16
+ .chart-container {
17
+ position: relative;
18
+ height: 400px;
19
+ }
20
+ </style>
21
+ <script src="https://unpkg.com/feather-icons"></script>
22
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
23
  </head>
24
  <body class="bg-gray-50 min-h-screen">
 
100
  </main>
101
 
102
  <custom-footer></custom-footer>
 
103
  <script src="components/navbar.js"></script>
104
  <script src="components/footer.js"></script>
105
  <script src="script.js"></script>
106
+ <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
107
  <script>
108
+ // Binance API endpoints
109
+ const BINANCE_API = {
110
+ klines: 'https://api.binance.com/api/v3/klines',
111
+ ticker: 'https://api.binance.com/api/v3/ticker/24hr'
112
+ };
113
+ document.addEventListener('DOMContentLoaded', async () => {
114
  feather.replace();
115
+ await loadPairData();
116
+ initRealTimeUpdates();
117
  });
118
 
119
  async function loadPairData() {
120
  const params = new URLSearchParams(window.location.search);
121
  const pair = params.get('pair') || 'BTC/USDT';
122
+ const symbol = pair.replace('/', '');
123
  document.getElementById('pair-title').textContent = pair;
124
 
125
  try {
126
+ // Get latest price and 24h change
127
+ const [tickerRes, klinesRes] = await Promise.all([
128
+ axios.get(`${BINANCE_API.ticker}?symbol=${symbol}`),
129
+ axios.get(`${BINANCE_API.klines}?symbol=${symbol}&interval=5m&limit=100`)
130
+ ]);
131
+
132
+ const ticker = tickerRes.data;
133
+ const klines = klinesRes.data;
134
+
135
+ // Update price display
136
+ const currentPrice = parseFloat(ticker.lastPrice);
137
+ const priceChange = parseFloat(ticker.priceChangePercent);
138
+ document.getElementById('current-price').textContent = `${currentPrice.toFixed(2)}`;
139
+ const changeElement = document.getElementById('price-change');
140
+ changeElement.textContent = `${priceChange.toFixed(2)}% (${parseFloat(ticker.priceChange).toFixed(2)})`;
141
+ changeElement.className = priceChange >= 0 ? 'text-sm text-green-600' : 'text-sm text-red-600';
142
+
143
+ // Update chart with real data
144
+ updateChart(klines, pair);
145
+
146
+ // Get prediction from our API
147
+ const signalRes = await fetch(`/api/signal/${symbol}`);
148
+ const signal = await signalRes.json();
149
 
150
+ // Update prediction UI
151
+ document.getElementById('up-prob').textContent = `${Math.round(signal.prob_up * 100)}%`;
152
+ document.getElementById('down-prob').textContent = `${Math.round(signal.prob_down * 100)}%`;
153
+ document.getElementById('up-progress').style.width = `${signal.prob_up * 100}%`;
154
+ document.getElementById('down-progress').style.width = `${signal.prob_down * 100}%`;
155
+ document.getElementById('trading-advice').textContent = signal.advice.replace('_', ' ').toUpperCase();
156
+ document.getElementById('trading-advice').className =
157
+ signal.advice === 'long_bias' ? 'text-green-800' :
158
+ signal.advice === 'short_bias' ? 'text-red-800' : 'text-blue-800';
159
 
160
  // Update predictions table
161
+ updatePredictionsTable(symbol);
162
  } catch (error) {
163
  console.error('Error loading pair data:', error);
164
  }
165
  }
166
 
167
+ function initRealTimeUpdates() {
168
+ // Update price every 5 seconds
169
+ setInterval(async () => {
170
+ const pair = new URLSearchParams(window.location.search).get('pair') || 'BTC/USDT';
171
+ const symbol = pair.replace('/', '');
172
+
173
+ try {
174
+ const res = await axios.get(`${BINANCE_API.ticker}?symbol=${symbol}`);
175
+ const ticker = res.data;
176
+ const currentPrice = parseFloat(ticker.lastPrice);
177
+ document.getElementById('current-price').textContent = `${currentPrice.toFixed(2)}`;
178
+ } catch (error) {
179
+ console.error('Error updating price:', error);
180
+ }
181
+ }, 5000);
182
+ }
183
+ function updateChart(klines, pair) {
184
  const ctx = document.getElementById('price-chart').getContext('2d');
 
 
 
185
 
186
+ // Process klines data
187
+ const labels = klines.map(k => new Date(k[0]).toLocaleTimeString());
188
+ const closes = klines.map(k => parseFloat(k[4]));
189
+ const volumes = klines.map(k => parseFloat(k[5]));
 
190
 
191
+ // Create main price chart
192
+ const priceChart = new Chart(ctx, {
193
+ type: 'candlestick',
194
  data: {
195
  labels: labels,
196
  datasets: [{
197
  label: `${pair} Price`,
198
+ data: klines.map(k => ({
199
+ x: new Date(k[0]),
200
+ o: parseFloat(k[1]),
201
+ h: parseFloat(k[2]),
202
+ l: parseFloat(k[3]),
203
+ c: parseFloat(k[4])
204
+ })),
205
+ color: {
206
+ up: '#10b981',
207
+ down: '#ef4444',
208
+ unchanged: '#9ca3af',
209
+ }
210
  }]
211
  },
212
  options: {
213
  responsive: true,
214
+ maintainAspectRatio: false,
215
+ scales: {
216
+ x: {
217
+ type: 'time',
218
+ time: {
219
+ unit: 'hour'
220
+ }
221
+ },
222
+ y: {
223
+ position: 'right',
224
+ ticks: {
225
+ callback: function(value) {
226
+ return '
227
+ async function updatePredictionsTable(symbol) {
228
+ try {
229
+ // In a real app, this would come from your backend API
230
+ const predictions = await fetchHistoricalPredictions(symbol);
231
+ const table = document.getElementById('predictions-table');
232
+
233
+ table.innerHTML = predictions.map(pred => {
234
+ const time = new Date(pred.timestamp).toLocaleTimeString();
235
+ const isCorrect = pred.prediction === pred.actual;
236
+
237
+ return `
238
+ <tr class="border-b">
239
+ <td class="px-4 py-3">${time}</td>
240
+ <td class="px-4 py-3 font-semibold ${pred.prediction === 'UP' ? 'text-green-600' : 'text-red-600'}">
241
+ ${pred.prediction}
242
+ </td>
243
+ <td class="px-4 py-3 font-semibold ${pred.actual === 'UP' ? 'text-green-600' : 'text-red-600'}">
244
+ ${pred.actual} ${isCorrect ? '✓' : '✗'}
245
+ </td>
246
+ <td class="px-4 py-3">
247
+ <div class="w-full bg-gray-200 rounded-full h-2.5">
248
+ <div class="h-2.5 rounded-full ${isCorrect ? 'bg-green-600' : 'bg-red-600'}"
249
+ style="width: ${pred.confidence}%"></div>
250
+ </div>
251
+ <span class="text-xs">${pred.confidence}%</span>
252
+ </td>
253
+ </tr>
254
+ `;
255
+ }).join('');
256
+ } catch (error) {
257
+ console.error('Error loading predictions:', error);
258
+ }
259
+ }
260
+
261
+ async function fetchHistoricalPredictions(symbol) {
262
+ // Mock data - replace with actual API call to your backend
263
+ return [
264
+ {
265
+ timestamp: Date.now() - 300000,
266
+ prediction: 'UP',
267
+ actual: 'UP',
268
+ confidence: 85
269
+ },
270
+ {
271
+ timestamp: Date.now() - 600000,
272
+ prediction: 'DOWN',
273
+ actual: 'UP',
274
+ confidence: 72
275
+ },
276
+ {
277
+ timestamp: Date.now() - 900000,
278
+ prediction: 'UP',
279
+ actual: 'UP',
280
+ confidence: 91
281
  }
282
+ ];
283
  }
284
+ </script>
285
+ <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
286
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
287
+ </body>
288
+ </html> + value.toFixed(2);
289
+ }
290
+ }
291
+ }
292
+ },
293
+ plugins: {
294
+ tooltip: {
295
+ callbacks: {
296
+ label: function(context) {
297
+ return [
298
+ `Open: ${context.raw.o.toFixed(2)}`,
299
+ `High: ${context.raw.h.toFixed(2)}`,
300
+ `Low: ${context.raw.l.toFixed(2)}`,
301
+ `Close: ${context.raw.c.toFixed(2)}`
302
+ ];
303
+ }
304
+ }
305
+ }
306
+ }
307
+ }
308
+ });
309
 
310
+ // Add volume chart below
311
+ const volumeCtx = document.createElement('canvas');
312
+ volumeCtx.id = 'volume-chart';
313
+ document.querySelector('#price-chart').parentNode.appendChild(volumeCtx);
314
+
315
+ new Chart(volumeCtx, {
316
+ type: 'bar',
317
+ data: {
318
+ labels: labels,
319
+ datasets: [{
320
+ label: 'Volume',
321
+ data: volumes,
322
+ backgroundColor: klines.map((k, i) =>
323
+ parseFloat(k[4]) > parseFloat(k[1]) ? '#10b981' : '#ef4444'
324
+ )
325
+ }]
326
+ },
327
+ options: {
328
+ responsive: true,
329
+ maintainAspectRatio: false,
330
+ scales: {
331
+ x: {
332
+ display: false
333
+ }
334
+ }
335
+ }
336
+ });
337
+ }
338
+ function updatePredictionsTable(pair) {
339
  const table = document.getElementById('predictions-table');
340
  const predictions = [
341
  { time: '5m ago', prediction: 'UP', actual: 'UP', confidence: '85%' },
script.js CHANGED
@@ -50,18 +50,29 @@ function updateAccountDisplay(accountData) {
50
  }
51
  async function fetchSignal(symbol) {
52
  try {
53
- // Simulate API call with mock data
 
 
 
 
54
  return {
55
  symbol: symbol,
56
  timeframe: "5m",
57
- prob_up: Math.random(),
58
- prob_down: 1 - Math.random(),
59
- confidence: Math.random(),
60
- advice: ["long_bias", "short_bias", "neutral"][Math.floor(Math.random() * 3)]
61
  };
 
 
 
 
 
 
 
62
  } catch (error) {
63
- console.error('Error fetching signal:', error);
64
- return null;
65
  }
66
  }
67
  function initTradingUI() {
 
50
  }
51
  async function fetchSignal(symbol) {
52
  try {
53
+ const response = await fetch(`/api/signal/${symbol}`);
54
+ if (!response.ok) throw new Error('API request failed');
55
+ return await response.json();
56
+ } catch (error) {
57
+ console.error('Error fetching signal:', error);
58
  return {
59
  symbol: symbol,
60
  timeframe: "5m",
61
+ prob_up: 0.5,
62
+ prob_down: 0.5,
63
+ confidence: 0,
64
+ advice: "neutral"
65
  };
66
+ }
67
+ }
68
+
69
+ async function fetchBinanceKlines(symbol, interval='5m', limit=100) {
70
+ try {
71
+ const response = await axios.get(`https://api.binance.com/api/v3/klines?symbol=${symbol}&interval=${interval}&limit=${limit}`);
72
+ return response.data;
73
  } catch (error) {
74
+ console.error('Error fetching klines:', error);
75
+ return [];
76
  }
77
  }
78
  function initTradingUI() {