Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -119,11 +119,11 @@ def update_advanced_stats(stats):
|
|
119 |
return gr.HTML(f"""
|
120 |
<div class="space-y-5">
|
121 |
<div>
|
122 |
-
<div class="flex justify-between mb-1"><span class="text-gray-500 dark:text-gray-400">Profit Factor</span><span class="font-bold text-green-500">{stats['profit_factor']}</span></div>
|
123 |
<div class="w-full bg-gray-200 rounded-full h-2 dark:bg-gray-700"><div class="bg-green-600 h-2 rounded-full" style="width: {min(stats['profit_factor'] * 25, 100)}%"></div></div>
|
124 |
</div>
|
125 |
<div>
|
126 |
-
<div class="flex justify-between mb-1"><span class="text-gray-500 dark:text-gray-400">Win Rate</span><span class="font-bold text-purple-500">{stats['win_rate']}%</span></div>
|
127 |
<div class="w-full bg-gray-200 rounded-full h-2 dark:bg-gray-700"><div class="bg-purple-600 h-2 rounded-full" style="width: {stats['win_rate']}%"></div></div>
|
128 |
</div>
|
129 |
</div>
|
@@ -141,7 +141,7 @@ def update_performance_chart(trades):
|
|
141 |
return gr.Chart(value=chart_data, type="line", options={
|
142 |
'responsive': True,
|
143 |
'plugins': {'legend': {'display': False}},
|
144 |
-
'scales': {'y': {'grid': {'color': 'rgba(0, 0, 0, 0.05)', 'borderDash': [5]}, 'ticks': {'callback': lambda value: f'${value}'}}, 'x': {'grid': {'display':
|
145 |
})
|
146 |
|
147 |
def update_allocation_chart(allocation):
|
@@ -193,7 +193,7 @@ def update_dashboard(api_key, api_secret):
|
|
193 |
)
|
194 |
except Exception as e:
|
195 |
return (
|
196 |
-
"$
|
197 |
gr.HTML("<div>Error loading stats</div>"), gr.Chart(), (gr.Chart(), gr.HTML("")), "Just now", "Just now"
|
198 |
)
|
199 |
|
@@ -203,91 +203,116 @@ def save_credentials(new_api_key, new_api_secret, api_key, api_secret):
|
|
203 |
return gr.Warning("Both API Key and Secret are required."), api_key, api_secret
|
204 |
return gr.Info("Credentials saved successfully! Syncing data..."), gr.State(value=new_api_key), gr.State(value=new_api_secret)
|
205 |
|
|
|
|
|
|
|
|
|
206 |
# Gradio Interface
|
207 |
with gr.Blocks(title="Nakhoda4X Pro") as demo:
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
save_btn.click(
|
271 |
-
fn=save_credentials,
|
272 |
-
inputs=[api_key_input, api_secret_input, api_key, api_secret],
|
273 |
-
outputs=[gr.Markdown(), api_key, api_secret]
|
274 |
-
)
|
275 |
-
demo.load(fn=update_dashboard, inputs=[api_key, api_secret], outputs=[
|
276 |
-
total_balance, open_trades, trade_types, today_profit,
|
277 |
-
risk_exposure, exposure_percent, trading_activity, advanced_stats,
|
278 |
-
performance_chart, (allocation_chart, allocation_legend), gr.State(value=None), gr.State(value=None)
|
279 |
-
])
|
280 |
-
refresh_btn.click(fn=update_dashboard, inputs=[api_key, api_secret], outputs=[
|
281 |
-
total_balance, open_trades, trade_types, today_profit,
|
282 |
-
risk_exposure, exposure_percent, trading_activity, advanced_stats,
|
283 |
-
performance_chart, (allocation_chart, allocation_legend), gr.State(value=None), gr.State(value=None)
|
284 |
-
])
|
285 |
-
sync_now.click(fn=update_dashboard, inputs=[api_key, api_secret], outputs=[
|
286 |
-
total_balance, open_trades, trade_types, today_profit,
|
287 |
-
risk_exposure, exposure_percent, trading_activity, advanced_stats,
|
288 |
-
performance_chart, (allocation_chart, allocation_legend), gr.State(value=None), gr.State(value=None)
|
289 |
-
])
|
290 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
291 |
with gr.Tab("Hot Dog Classifier"):
|
292 |
gr.Markdown("### Hot Dog? Or Not?")
|
293 |
with gr.Row():
|
@@ -297,9 +322,7 @@ with gr.Blocks(title="Nakhoda4X Pro") as demo:
|
|
297 |
submit_btn = gr.Button("Classify")
|
298 |
submit_btn.click(fn=lambda img: (img, {p["label"]: p["score"] for p in hotdog_pipeline(img)}), inputs=input_img, outputs=[output_img, output_label])
|
299 |
|
300 |
-
|
301 |
-
with gr.Row():
|
302 |
-
theme_toggle = gr.Button("Toggle Theme", elem_classes="text-gray-600 dark:text-gray-300")
|
303 |
theme_toggle.click(None, _js="() => document.body.classList.toggle('dark')")
|
304 |
|
305 |
if __name__ == "__main__":
|
|
|
119 |
return gr.HTML(f"""
|
120 |
<div class="space-y-5">
|
121 |
<div>
|
122 |
+
<div class="flex justify-between mb-1"><span class="text-gray-500 dark:text-gray-400">Profit Factor</span><span class="font-bold text-green-500">{stats['profit_factor']:.2f}</span></div>
|
123 |
<div class="w-full bg-gray-200 rounded-full h-2 dark:bg-gray-700"><div class="bg-green-600 h-2 rounded-full" style="width: {min(stats['profit_factor'] * 25, 100)}%"></div></div>
|
124 |
</div>
|
125 |
<div>
|
126 |
+
<div class="flex justify-between mb-1"><span class="text-gray-500 dark:text-gray-400">Win Rate</span><span class="font-bold text-purple-500">{stats['win_rate']:.1f}%</span></div>
|
127 |
<div class="w-full bg-gray-200 rounded-full h-2 dark:bg-gray-700"><div class="bg-purple-600 h-2 rounded-full" style="width: {stats['win_rate']}%"></div></div>
|
128 |
</div>
|
129 |
</div>
|
|
|
141 |
return gr.Chart(value=chart_data, type="line", options={
|
142 |
'responsive': True,
|
143 |
'plugins': {'legend': {'display': False}},
|
144 |
+
'scales': {'y': {'grid': {'color': 'rgba(0, 0, 0, 0.05)', 'borderDash': [5]}, 'ticks': {'callback': lambda value: f'${value}'}}, 'x': {'grid': {'display': False}}}
|
145 |
})
|
146 |
|
147 |
def update_allocation_chart(allocation):
|
|
|
193 |
)
|
194 |
except Exception as e:
|
195 |
return (
|
196 |
+
"$Loading...", 0, "0 Long β’ 0 Short", "$0.00", "Low", "0%", gr.HTML("<tr><td colspan='8' class='py-4 text-center'>Error: Failed to sync with BingX API - Check credentials</td></tr>"),
|
197 |
gr.HTML("<div>Error loading stats</div>"), gr.Chart(), (gr.Chart(), gr.HTML("")), "Just now", "Just now"
|
198 |
)
|
199 |
|
|
|
203 |
return gr.Warning("Both API Key and Secret are required."), api_key, api_secret
|
204 |
return gr.Info("Credentials saved successfully! Syncing data..."), gr.State(value=new_api_key), gr.State(value=new_api_secret)
|
205 |
|
206 |
+
# Toggle API Form Visibility
|
207 |
+
def toggle_api_form(show_form):
|
208 |
+
return gr.update(visible=show_form)
|
209 |
+
|
210 |
# Gradio Interface
|
211 |
with gr.Blocks(title="Nakhoda4X Pro") as demo:
|
212 |
+
# Custom CSS and JS for Tailwind and dark mode
|
213 |
+
demo.css = """
|
214 |
+
.trading-card:hover { transform: translateY(-5px); box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2); }
|
215 |
+
.animate-pulse { animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; }
|
216 |
+
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
|
217 |
+
.coin-animation { animation: float 3s ease-in-out infinite; }
|
218 |
+
@keyframes float { 0% { transform: translateY(0px); } 50% { transform: translateY(-10px); } 100% { transform: translateY(0px); } }
|
219 |
+
.api-form { max-height: 0; overflow: hidden; transition: max-height 0.3s ease-in-out; }
|
220 |
+
.api-form.open { max-height: 200px; }
|
221 |
+
body { background-color: #f3f4f6; }
|
222 |
+
body.dark { background-color: #111827; }
|
223 |
+
.dark .bg-white { background-color: #1f2937; }
|
224 |
+
.dark .text-gray-800 { color: #ffffff; }
|
225 |
+
.dark .text-gray-500 { color: #9ca3af; }
|
226 |
+
"""
|
227 |
+
demo.js = """
|
228 |
+
() => [document.body.classList.toggle('dark', window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches)]
|
229 |
+
"""
|
230 |
+
|
231 |
+
# Header
|
232 |
+
with gr.Row():
|
233 |
+
with gr.Column(scale=1):
|
234 |
+
gr.HTML("""
|
235 |
+
<div class="bg-white dark:bg-darkCard shadow-sm flex items-center p-4">
|
236 |
+
<div class="bg-primary w-10 h-10 rounded-xl flex items-center justify-center mr-3 coin-animation">
|
237 |
+
<i class="fas fa-chart-line text-white text-xl"></i>
|
238 |
+
</div>
|
239 |
+
<h1 class="text-2xl font-bold text-gray-800 dark:text-white">Nakhoda4X <span class="text-primary">Pro</span></h1>
|
240 |
+
</div>
|
241 |
+
""")
|
242 |
+
with gr.Column(scale=1, elem_classes="flex justify-end items-center space-x-6"):
|
243 |
+
theme_toggle = gr.Button(value="Toggle Theme", elem_classes="text-gray-600 dark:text-gray-300")
|
244 |
+
gr.HTML('<div><i class="fas fa-bell text-gray-600 dark:text-gray-300 text-xl"></i><span class="absolute -top-2 -right-2 bg-red-500 text-white text-xs rounded-full h-5 w-5 flex items-center justify-center">3</span></div>')
|
245 |
+
gr.HTML('<div class="flex items-center"><div class="mr-3 text-right"><p class="font-semibold text-gray-800 dark:text-white">SahabatPipHijau</p><p class="text-sm text-gray-500">Premium Account</p></div><div class="h-10 w-10 rounded-full bg-gradient-to-r from-primary to-secondary flex items-center justify-center text-white font-bold">J</div></div>')
|
246 |
+
|
247 |
+
# Main Content
|
248 |
+
with gr.Row():
|
249 |
+
with gr.Column():
|
250 |
+
gr.Markdown("### Trading Dashboard")
|
251 |
+
gr.Markdown("Connected to BingX via API")
|
252 |
+
with gr.Row():
|
253 |
+
refresh_btn = gr.Button("Refresh", elem_classes="px-4 py-2 bg-white dark:bg-darkCard rounded-lg border border-gray-200 dark:border-gray-700 text-gray-700 dark:text-gray-300 flex items-center")
|
254 |
+
new_trade_btn = gr.Button("New Trade", elem_classes="px-4 py-2 bg-primary text-white rounded-lg flex items-center")
|
255 |
+
|
256 |
+
# Stats Cards
|
257 |
+
with gr.Row(elem_classes="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6"):
|
258 |
+
total_balance = gr.HTML("<div class='trading-card bg-white dark:bg-darkCard rounded-2xl shadow-md p-6'><div class='flex justify-between'><div><p class='text-gray-500 dark:text-gray-400'>Total Balance</p><h3 id='total-balance' class='text-2xl font-bold mt-2 dark:text-white'>$0.00</h3></div><div class='w-12 h-12 rounded-xl bg-blue-100 dark:bg-blue-900/30 flex items-center justify-center'><i class='fas fa-wallet text-blue-500 text-xl'></i></div></div><div id='balance-change' class='mt-4 flex items-center text-green-500'><i class='fas fa-caret-up mr-1'></i><span class='font-medium'>0.0%</span><span class='text-gray-500 ml-2 dark:text-gray-400'>last 24h</span></div></div>")
|
259 |
+
open_trades = gr.HTML("<div class='trading-card bg-white dark:bg-darkCard rounded-2xl shadow-md p-6'><div class='flex justify-between'><div><p class='text-gray-500 dark:text-gray-400'>Open Trades</p><h3 id='open-trades' class='text-2xl font-bold mt-2 dark:text-white'>0</h3></div><div class='w-12 h-12 rounded-xl bg-purple-100 dark:bg-purple-900/30 flex items-center justify-center'><i class='fas fa-exchange-alt text-purple-500 text-xl'></i></div></div><div id='trade-types' class='mt-4 flex items-center text-blue-500'><span class='font-medium'>0 Long</span><span class='text-gray-500 mx-2 dark:text-gray-400'>β’</span><span class='font-medium'>0 Short</span></div></div>")
|
260 |
+
today_profit = gr.HTML("<div class='trading-card bg-white dark:bg-darkCard rounded-2xl shadow-md p-6'><div class='flex justify-between'><div><p class='text-gray-500 dark:text-gray-400'>Today's Profit</p><h3 id='today-profit' class='text-2xl font-bold mt-2 dark:text-white'>$0.00</h3></div><div class='w-12 h-12 rounded-xl bg-green-100 dark:bg-green-900/30 flex items-center justify-center'><i class='fas fa-chart-bar text-green-500 text-xl'></i></div></div><div id='profit-change' class='mt-4 flex items-center text-green-500'><i class='fas fa-caret-up mr-1'></i><span class='font-medium'>0.0%</span><span class='text-gray-500 ml-2 dark:text-gray-400'>vs yesterday</span></div></div>")
|
261 |
+
risk_exposure = gr.HTML("<div class='trading-card bg-white dark:bg-darkCard rounded-2xl shadow-md p-6'><div class='flex justify-between'><div><p class='text-gray-500 dark:text-gray-400'>Risk Exposure</p><h3 id='risk-exposure' class='text-2xl font-bold mt-2 dark:text-white'>Low</h3></div><div class='w-12 h-12 rounded-xl bg-yellow-100 dark:bg-yellow-900/30 flex items-center justify-center'><i class='fas fa-exclamation-triangle text-yellow-500 text-xl'></i></div></div><div id='exposure-percent' class='mt-4 flex items-center text-gray-500 dark:text-gray-400'><span class='font-medium'>0%</span><span class='ml-2'>of balance</span></div></div>")
|
262 |
+
|
263 |
+
# Charts and Statistics
|
264 |
+
with gr.Row(elem_classes="grid grid-cols-1 lg:grid-cols-3 gap-6"):
|
265 |
+
with gr.Column(scale=2):
|
266 |
+
performance_chart = gr.Chart()
|
267 |
+
gr.HTML("<div class='flex justify-between items-center mb-6'><h3 class='text-lg font-bold text-gray-800 dark:text-white'>Monthly Performance</h3><div class='flex space-x-3'><button class='px-3 py-1 rounded-lg text-sm bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-white'>1M</button><button class='px-3 py-1 rounded-lg text-sm bg-primary text-white'>3M</button><button class='px-3 py-1 rounded-lg text-sm bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-white'>6M</button><button class='px-3 py-1 rounded-lg text-sm bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-white'>1Y</button></div></div>")
|
268 |
+
with gr.Column(scale=1):
|
269 |
+
advanced_stats = gr.HTML()
|
270 |
+
|
271 |
+
# Trading Activity
|
272 |
+
trading_activity = gr.HTML()
|
273 |
+
gr.HTML("<div class='flex justify-between items-center mb-6'><h3 class='text-lg font-bold text-gray-800 dark:text-white'>Trading Activity</h3><div class='flex space-x-3'><button class='px-3 py-1 rounded-lg text-sm bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-white'>All</button><button class='px-3 py-1 rounded-lg text-sm bg-primary text-white'>Open</button><button class='px-3 py-1 rounded-lg text-sm bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-white'>Closed</button></div></div>")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
274 |
|
275 |
+
# API Connection and Portfolio Allocation
|
276 |
+
with gr.Row(elem_classes="grid grid-cols-1 lg:grid-cols-3 gap-6"):
|
277 |
+
with gr.Column():
|
278 |
+
api_connection = gr.Blocks()
|
279 |
+
with api_connection:
|
280 |
+
gr.HTML("<div class='bg-gradient-to-r from-primary to-secondary rounded-2xl p-6'><div class='flex items-center mb-4'><div class='mr-4'><div class='h-12 w-12 rounded-xl bg-white/30 flex items-center justify-center'><i class='fas fa-plug text-white text-xl'></i></div></div><div><h3 class='text-lg font-bold text-white'>BingX API Connected</h3><p id='last-sync' class='text-blue-100'>Last synced: Just now</p></div></div>")
|
281 |
+
show_form = gr.State(False)
|
282 |
+
toggle_btn = gr.Button("Manage API Credentials", elem_classes="w-full py-2 bg-white rounded-xl text-primary font-bold flex items-center justify-center mb-2")
|
283 |
+
with gr.Column(elem_classes="api-form", visible=False) as api_form:
|
284 |
+
api_key_input = gr.Textbox(label="API Key", value=api_key.value, type="password")
|
285 |
+
api_secret_input = gr.Textbox(label="API Secret", value=api_secret.value, type="password")
|
286 |
+
save_btn = gr.Button("Save Credentials", elem_classes="w-full py-2 bg-primary text-white rounded-lg")
|
287 |
+
sync_now = gr.Button("Sync Now", elem_classes="mt-2 w-full py-3 bg-white rounded-xl text-primary font-bold flex items-center justify-center")
|
288 |
+
|
289 |
+
with gr.Column(scale=2):
|
290 |
+
portfolio_allocation = gr.Blocks()
|
291 |
+
with portfolio_allocation:
|
292 |
+
gr.HTML("<div class='bg-white dark:bg-darkCard rounded-2xl shadow-md p-6'><div class='flex justify-between items-center mb-6'><h3 class='text-lg font-bold text-gray-800 dark:text-white'>Portfolio Allocation</h3><div><span id='allocation-update' class='text-gray-500 dark:text-gray-400 text-sm'>Last updated: Just now</span></div></div>")
|
293 |
+
allocation_chart, allocation_legend = gr.Chart(), gr.HTML()
|
294 |
+
|
295 |
+
# Event Handlers
|
296 |
+
toggle_btn.click(fn=toggle_api_form, inputs=[show_form], outputs=[api_form], _js="() => !document.querySelector('.api-form').classList.contains('open')")
|
297 |
+
save_btn.click(fn=save_credentials, inputs=[api_key_input, api_secret_input, api_key, api_secret], outputs=[gr.Markdown(), api_key, api_secret])
|
298 |
+
demo.load(fn=update_dashboard, inputs=[api_key, api_secret], outputs=[
|
299 |
+
total_balance, open_trades, trade_types, today_profit,
|
300 |
+
risk_exposure, exposure_percent, trading_activity, advanced_stats,
|
301 |
+
performance_chart, (allocation_chart, allocation_legend), gr.State(value=None), gr.State(value=None)
|
302 |
+
])
|
303 |
+
refresh_btn.click(fn=update_dashboard, inputs=[api_key, api_secret], outputs=[
|
304 |
+
total_balance, open_trades, trade_types, today_profit,
|
305 |
+
risk_exposure, exposure_percent, trading_activity, advanced_stats,
|
306 |
+
performance_chart, (allocation_chart, allocation_legend), gr.State(value=None), gr.State(value=None)
|
307 |
+
])
|
308 |
+
sync_now.click(fn=update_dashboard, inputs=[api_key, api_secret], outputs=[
|
309 |
+
total_balance, open_trades, trade_types, today_profit,
|
310 |
+
risk_exposure, exposure_percent, trading_activity, advanced_stats,
|
311 |
+
performance_chart, (allocation_chart, allocation_legend), gr.State(value=None), gr.State(value=None)
|
312 |
+
])
|
313 |
+
new_trade_btn.click(None, _js="() => alert('New Trade functionality not implemented yet.')")
|
314 |
+
|
315 |
+
# Hot Dog Classifier Tab
|
316 |
with gr.Tab("Hot Dog Classifier"):
|
317 |
gr.Markdown("### Hot Dog? Or Not?")
|
318 |
with gr.Row():
|
|
|
322 |
submit_btn = gr.Button("Classify")
|
323 |
submit_btn.click(fn=lambda img: (img, {p["label"]: p["score"] for p in hotdog_pipeline(img)}), inputs=input_img, outputs=[output_img, output_label])
|
324 |
|
325 |
+
# Theme Toggle
|
|
|
|
|
326 |
theme_toggle.click(None, _js="() => document.body.classList.toggle('dark')")
|
327 |
|
328 |
if __name__ == "__main__":
|