import gradio as gr from transformers import pipeline import hmac import hashlib import requests import time import os from datetime import datetime import plotly.express as px # Initialize hotdog classification pipeline with error handling hotdog_pipeline = None try: hotdog_pipeline = pipeline(task="image-classification", model="julien-c/hotdog-not-hotdog") except RuntimeError as e: print(f"Warning: Hotdog classifier failed to initialize: {e}. Image classification will be unavailable.") # Global state for API credentials (updated by user input) api_key = gr.State(os.getenv('BINGX_API_KEY', "")) api_secret = gr.State(os.getenv('BINGX_API_SECRET', "")) # Configuration API_BASE_URL = "https://open-api.bingx.com" # Generate Signature def generate_signature(api_secret, params_str): return hmac.new(api_secret.encode("utf-8"), params_str.encode("utf-8"), hashlib.sha256).hexdigest() # Parse Parameters def parse_params(params): sorted_keys = sorted(params.keys()) param_pairs = [f"{key}={params[key]}" for key in sorted_keys] params_str = "&".join(param_pairs) return params_str + "×tamp=" + str(int(time.time() * 1000)) # Fetch from BingX API def fetch_from_api(endpoint, params=None, api_key=api_key, api_secret=api_secret): if not api_key.value or not api_secret.value: raise ValueError("BingX API Key and Secret are not set. Please enter them in the Manage API Credentials section.") params = params or {} params['recvWindow'] = params.get('recvWindow', '5000') params_str = parse_params(params) signature = generate_signature(api_secret.value, params_str) url = f"{API_BASE_URL}{endpoint}?{params_str}&signature={signature}" try: response = requests.get(url, headers={'X-BX-APIKEY': api_key.value, 'Content-Type': 'application/json'}) response.raise_for_status() return response.json() except requests.exceptions.RequestException as e: raise Exception(f"API Error: {str(e)}") # Fetch Specific Data def fetch_balance(api_key=api_key, api_secret=api_secret): data = fetch_from_api('/openApi/swap/v3/user/balance', api_key=api_key, api_secret=api_secret) return data['data'][0]['walletBalance'] if data['data'] and data['data'][0]['asset'] == 'USDT' else 0 def fetch_open_positions(api_key=api_key, api_secret=api_secret): data = fetch_from_api('/openApi/swap/v2/user/positions', {'symbol': 'BTC-USDT'}, api_key=api_key, api_secret=api_secret) return data['data'] or [] def fetch_trade_history(api_key=api_key, api_secret=api_secret): data = fetch_from_api('/openApi/swap/v2/user/income', {'limit': 100}, api_key=api_key, api_secret=api_secret) return data['data'] or [] # Helper Functions def calculate_today_profit(trades): today = datetime.now().date() return sum(trade['income'] for trade in trades if datetime.fromtimestamp(trade['time'] / 1000).date() == today) def calculate_advanced_stats(trades): total_profit, total_loss, wins = 0, 0, 0 for trade in trades: pl = trade['income'] if pl > 0: total_profit += pl wins += 1 else: total_loss += abs(pl) profit_factor = total_loss and (total_profit / total_loss) or 0 win_rate = trades and (wins / len(trades) * 100) or 0 return {'profit_factor': profit_factor, 'win_rate': win_rate} def calculate_portfolio_allocation(positions): total_value = sum(pos['positionValue'] for pos in positions if 'positionValue' in pos) by_symbol = {} for pos in positions: by_symbol[pos['symbol']] = by_symbol.get(pos['symbol'], 0) + (pos.get('positionValue', 0)) labels = list(by_symbol.keys()) data = [val / total_value * 100 if total_value else 0 for val in by_symbol.values()] return {'labels': labels, 'data': data} # Update UI Functions def update_trading_table(positions, trades): table_rows = [] for pos in positions: table_rows.append(f""" {pos['symbol']} {pos['positionSide']} {pos['quantity']} ${pos['entryPrice']:.2f} ${pos['markPrice']:.2f} ${pos['unrealizedProfit']:.2f} Open """) for trade in trades[:5]: table_rows.append(f""" {trade['symbol']} {trade['positionSide']} {trade.get('quantity', 0)} ${trade.get('entryPrice', 0):.2f} ${trade.get('exitPrice', 0):.2f} ${trade['income']:.2f} Closed """) return gr.HTML("\n".join(table_rows)) def update_advanced_stats(stats): return gr.HTML(f"""
Profit Factor{stats['profit_factor']:.2f}
Win Rate{stats['win_rate']:.1f}%
""") def update_performance_chart(trades): monthly_pl = {} for trade in trades: month = datetime.fromtimestamp(trade['time'] / 1000).strftime('%b') monthly_pl[month] = monthly_pl.get(month, 0) + trade['income'] chart_data = { 'x': list(monthly_pl.keys()), 'y': list(monthly_pl.values()), 'color': ['#1E90FF'] * len(monthly_pl), 'title': 'Monthly Performance', 'x_title': 'Month', 'y_title': 'Profit/Loss ($)' } return gr.LinePlot(value=chart_data) def update_allocation_chart(allocation): chart_data = { 'labels': allocation['labels'], 'values': allocation['data'], 'color': ['#1E90FF', '#10b981', '#8b5cf6', '#f59e0b'], 'title': 'Portfolio Allocation' } fig = px.pie(names=chart_data['labels'], values=chart_data['values'], color_discrete_sequence=chart_data['color'], title=chart_data['title']) legend_html = "\n".join(f"""
{label} {data:.1f}%
""" for i, (label, data) in enumerate(zip(allocation['labels'], allocation['data']))) return gr.Plot(value=fig), gr.HTML(legend_html) # Main Data Fetch and Update Function def update_dashboard(api_key, api_secret): try: balance = fetch_balance() positions = fetch_open_positions() trades = fetch_trade_history() total_balance = f"${balance:.2f}" open_trades = len(positions) long_count = len([p for p in positions if p['positionSide'] == 'LONG']) today_profit = f"${calculate_today_profit(trades):.2f}" risk_percent = balance and (sum(p.get('positionValue', 0) for p in positions) / balance * 100) or 0 risk_exposure = 'Low' if risk_percent < 20 else 'Medium' if risk_percent < 50 else 'High' exposure_percent = f"{risk_percent:.1f}%" stats = calculate_advanced_stats(trades) allocation = calculate_portfolio_allocation(positions) return ( total_balance, open_trades, f"{long_count} Long • {len(positions) - long_count} Short", today_profit, risk_exposure, exposure_percent, update_trading_table(positions, trades), update_advanced_stats(stats), update_performance_chart(trades), update_allocation_chart(allocation), datetime.now().strftime('%I:%M %p'), datetime.now().strftime('%I:%M %p') ) except Exception as e: return ( "$Loading...", 0, "0 Long • 0 Short", "$0.00", "Low", "0%", gr.HTML("Error: Failed to sync with BingX API - Check credentials"), gr.HTML("
Error loading stats
"), gr.LinePlot(value={'x': [], 'y': [], 'color': [], 'title': 'Monthly Performance'}), (gr.Plot(value=px.pie(names=[], values=[], title='Portfolio Allocation')), gr.HTML("")), "Just now", "Just now" ) # Save Credentials Function def save_credentials(new_api_key, new_api_secret, api_key, api_secret): if not new_api_key or not new_api_secret: return gr.Warning("Both API Key and Secret are required."), api_key, api_secret return gr.Info("Credentials saved successfully! Syncing data..."), gr.State(value=new_api_key), gr.State(value=new_api_secret) # Toggle API Form Visibility def toggle_api_form(show_form): return gr.update(visible=show_form) # Gradio Interface with gr.Blocks(title="Nakhoda4X Pro") as demo: # Custom CSS and JS for Tailwind and dark mode demo.css = """ .trading-card:hover { transform: translateY(-5px); box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2); } .animate-pulse { animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } .coin-animation { animation: float 3s ease-in-out infinite; } @keyframes float { 0% { transform: translateY(0px); } 50% { transform: translateY(-10px); } 100% { transform: translateY(0px); } } .api-form { max-height: 0; overflow: hidden; transition: max-height 0.3s ease-in-out; } .api-form.open { max-height: 200px; } body { background-color: #f3f4f6; } body.dark { background-color: #111827; } .dark .bg-white { background-color: #1f2937; } .dark .text-gray-800 { color: #ffffff; } .dark .text-gray-500 { color: #9ca3af; } """ demo.js = """ () => [document.body.classList.toggle('dark', window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches)] """ # Header with gr.Row(): with gr.Column(scale=1): gr.HTML("""

Nakhoda4X Pro

""") with gr.Column(scale=1, elem_classes="flex justify-end items-center space-x-6"): theme_toggle = gr.Button(value="Toggle Theme", elem_classes="text-gray-600 dark:text-gray-300") gr.HTML('
3
') gr.HTML('

SahabatPipHijau

Premium Account

J
') # Main Content with gr.Row(): with gr.Column(): gr.Markdown("### Trading Dashboard") gr.Markdown("Connected to BingX via API") with gr.Row(): 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") # Stats Cards with gr.Row(elem_classes="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6"): total_balance = gr.HTML("

Total Balance

$0.00

0.0%last 24h
") open_trades = gr.HTML("

Open Trades

0

0 Long0 Short
") today_profit = gr.HTML("

Today's Profit

$0.00

0.0%vs yesterday
") risk_exposure = gr.HTML("

Risk Exposure

Low

0%of balance
") # Charts and Statistics with gr.Row(elem_classes="grid grid-cols-1 lg:grid-cols-3 gap-6"): with gr.Column(scale=2): performance_chart = gr.LinePlot() gr.HTML("

Monthly Performance

") with gr.Column(scale=1): advanced_stats = gr.HTML() # Trading Activity trading_activity = gr.HTML() gr.HTML("

Trading Activity

") # API Connection and Portfolio Allocation with gr.Row(elem_classes="grid grid-cols-1 lg:grid-cols-3 gap-6"): with gr.Column(): api_connection = gr.Blocks() with api_connection: gr.HTML("

BingX API Connected

Last synced: Just now

") show_form = gr.State(False) 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") with gr.Column(elem_classes="api-form", visible=False) as api_form: api_key_input = gr.Textbox(label="API Key", value=api_key.value, type="password") api_secret_input = gr.Textbox(label="API Secret", value=api_secret.value, type="password") save_btn = gr.Button("Save Credentials", elem_classes="w-full py-2 bg-primary text-white rounded-lg") 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") with gr.Column(scale=2): portfolio_allocation = gr.Blocks() with portfolio_allocation: gr.HTML("

Portfolio Allocation

Last updated: Just now
") allocation_chart, allocation_legend = gr.Plot(), gr.HTML() # Event Handlers toggle_btn.click(fn=toggle_api_form, inputs=[show_form], outputs=[api_form], _js="() => !document.querySelector('.api-form').classList.contains('open')") save_btn.click(fn=save_credentials, inputs=[api_key_input, api_secret_input, api_key, api_secret], outputs=[gr.Markdown(), api_key, api_secret]) demo.load(fn=update_dashboard, inputs=[api_key, api_secret], outputs=[ total_balance, open_trades, trade_types, today_profit, risk_exposure, exposure_percent, trading_activity, advanced_stats, performance_chart, (allocation_chart, allocation_legend), gr.State(value=None), gr.State(value=None) ]) refresh_btn.click(fn=update_dashboard, inputs=[api_key, api_secret], outputs=[ total_balance, open_trades, trade_types, today_profit, risk_exposure, exposure_percent, trading_activity, advanced_stats, performance_chart, (allocation_chart, allocation_legend), gr.State(value=None), gr.State(value=None) ]) sync_now.click(fn=update_dashboard, inputs=[api_key, api_secret], outputs=[ total_balance, open_trades, trade_types, today_profit, risk_exposure, exposure_percent, trading_activity, advanced_stats, performance_chart, (allocation_chart, allocation_legend), gr.State(value=None), gr.State(value=None) ]) # Hot Dog Classifier Tab with gr.Tab("Hot Dog Classifier"): gr.Markdown("### Hot Dog? Or Not?") with gr.Row(): input_img = gr.Image(label="Select hot dog candidate", sources=['upload', 'webcam'], type="pil") output_img = gr.Image(label="Processed Image") output_label = gr.Label(label="Result", num_top_classes=2) submit_btn = gr.Button("Classify") submit_btn.click(fn=lambda img: (img, {p["label"]: p["score"] for p in hotdog_pipeline(img)}) if hotdog_pipeline else (None, {"Error": "Classifier unavailable"}), inputs=input_img, outputs=[output_img, output_label]) # Theme Toggle theme_toggle.click(None, _js="() => document.body.classList.toggle('dark')") if __name__ == "__main__": demo.launch()