""" 🤖 Ultra Trading Agent - Gradio Dashboard ========================================== Full-featured trading bot with multi-timeframe analysis, dynamic leverage, SL/TP, and comprehensive backtesting. """ import gradio as gr import pandas as pd import numpy as np import plotly.graph_objects as go from plotly.subplots import make_subplots import json import sys import os import traceback sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from trading_bot.indicators import compute_all_indicators, ema, rsi, macd, bollinger_bands, atr from trading_bot.multi_timeframe import MultiTimeframeAnalyzer, resample_ohlcv, TIMEFRAME_HIERARCHY from trading_bot.risk_manager import RiskManager from trading_bot.backtester import Backtester from trading_bot.data_fetcher import generate_sample_data # ======================== # DATA LOADING # ======================== def load_data(source: str, symbol: str, days: int, volatility: float): """Load market data from selected source.""" if source == "📊 Données Synthétiques (Test)": df = generate_sample_data(days=days, timeframe='1h', start_price=45000, volatility=volatility) info = f"✅ Données synthétiques générées: {len(df)} barres sur {days} jours" elif source == "🔗 Binance (Live)": try: from trading_bot.data_fetcher import fetch_ohlcv_ccxt df = fetch_ohlcv_ccxt(symbol=symbol, timeframe='1h', exchange_name='binance', limit=days * 24) info = f"✅ Données live de Binance: {len(df)} barres pour {symbol}" except Exception as e: df = generate_sample_data(days=days, timeframe='1h', start_price=45000, volatility=volatility) info = f"⚠️ Binance non disponible ({str(e)[:50]}), données synthétiques utilisées" else: df = generate_sample_data(days=days, timeframe='1h', start_price=45000, volatility=volatility) info = f"✅ Données générées: {len(df)} barres" return df, info # ======================== # CHARTING # ======================== def create_candlestick_chart(df, trades_df=None, signals_df=None, title="Prix & Signaux"): """Create an interactive candlestick chart with indicators and trade markers.""" # Use last 500 bars for visibility plot_df = df.tail(500).copy() indicators = compute_all_indicators(plot_df) fig = make_subplots( rows=4, cols=1, shared_xaxes=True, vertical_spacing=0.03, row_heights=[0.5, 0.15, 0.15, 0.2], subplot_titles=[title, 'RSI', 'MACD', 'Volume'] ) # Candlesticks fig.add_trace(go.Candlestick( x=plot_df.index, open=plot_df['open'], high=plot_df['high'], low=plot_df['low'], close=plot_df['close'], name='Prix', increasing_line_color='#26a69a', decreasing_line_color='#ef5350' ), row=1, col=1) # EMAs for period, color, name in [(9, '#ff9800', 'EMA 9'), (21, '#2196f3', 'EMA 21'), (50, '#9c27b0', 'EMA 50'), (200, '#f44336', 'EMA 200')]: col = f'ema_{period}' if col in indicators.columns: fig.add_trace(go.Scatter( x=indicators.index, y=indicators[col], name=name, line=dict(color=color, width=1), opacity=0.7 ), row=1, col=1) # Bollinger Bands if 'bb_upper' in indicators.columns: fig.add_trace(go.Scatter( x=indicators.index, y=indicators['bb_upper'], name='BB Upper', line=dict(color='rgba(128,128,128,0.3)', width=1) ), row=1, col=1) fig.add_trace(go.Scatter( x=indicators.index, y=indicators['bb_lower'], name='BB Lower', line=dict(color='rgba(128,128,128,0.3)', width=1), fill='tonexty', fillcolor='rgba(128,128,128,0.05)' ), row=1, col=1) # Trade markers if trades_df is not None and len(trades_df) > 0: # Filter to visible range visible_trades = trades_df[ (trades_df.get('entry_time', pd.Series(dtype='datetime64[ns]')).notna()) & (trades_df.get('exit_time', pd.Series(dtype='datetime64[ns]')).notna()) ].copy() if 'entry_time' in visible_trades.columns: for _, trade in visible_trades.iterrows(): try: entry_t = pd.Timestamp(trade['entry_time']) exit_t = pd.Timestamp(trade['exit_time']) if entry_t < plot_df.index[0]: continue color = '#26a69a' if trade.get('pnl', 0) > 0 else '#ef5350' marker = '▲' if trade.get('side') == 'LONG' else '▼' # Entry fig.add_trace(go.Scatter( x=[entry_t], y=[trade['entry_price']], mode='markers+text', text=[marker], textposition='top center', marker=dict(color=color, size=10, symbol='triangle-up' if trade.get('side') == 'LONG' else 'triangle-down'), showlegend=False, hovertext=f"{trade.get('side','?')} | Entry: ${trade['entry_price']:,.2f} | Lev: {trade.get('leverage',1)}x" ), row=1, col=1) # Exit fig.add_trace(go.Scatter( x=[exit_t], y=[trade['exit_price']], mode='markers', marker=dict(color=color, size=8, symbol='x'), showlegend=False, hovertext=f"Exit: ${trade['exit_price']:,.2f} | PnL: ${trade.get('pnl',0):,.2f} | {trade.get('reason','?')}" ), row=1, col=1) except: pass # Signal arrows if signals_df is not None and len(signals_df) > 0: visible_signals = signals_df[signals_df['timestamp'] >= plot_df.index[0]].copy() entries = visible_signals[visible_signals['action'].str.contains('ENTER', na=False)] longs = entries[entries['action'] == 'ENTER_LONG'] shorts = entries[entries['action'] == 'ENTER_SHORT'] if len(longs) > 0: fig.add_trace(go.Scatter( x=longs['timestamp'], y=longs['price'], mode='markers', name='🟢 Long', marker=dict(color='#26a69a', size=12, symbol='triangle-up', line=dict(color='white', width=1)) ), row=1, col=1) if len(shorts) > 0: fig.add_trace(go.Scatter( x=shorts['timestamp'], y=shorts['price'], mode='markers', name='🔴 Short', marker=dict(color='#ef5350', size=12, symbol='triangle-down', line=dict(color='white', width=1)) ), row=1, col=1) # RSI if 'rsi' in indicators.columns: fig.add_trace(go.Scatter( x=indicators.index, y=indicators['rsi'], name='RSI', line=dict(color='#ff9800', width=1.5) ), row=2, col=1) fig.add_hline(y=70, line_dash="dash", line_color="red", opacity=0.5, row=2, col=1) fig.add_hline(y=30, line_dash="dash", line_color="green", opacity=0.5, row=2, col=1) fig.add_hrect(y0=30, y1=70, fillcolor="rgba(128,128,128,0.05)", line_width=0, row=2, col=1) # MACD if 'macd' in indicators.columns: fig.add_trace(go.Scatter( x=indicators.index, y=indicators['macd'], name='MACD', line=dict(color='#2196f3', width=1.5) ), row=3, col=1) fig.add_trace(go.Scatter( x=indicators.index, y=indicators['macd_signal'], name='Signal', line=dict(color='#ff5722', width=1.5) ), row=3, col=1) colors = ['#26a69a' if v > 0 else '#ef5350' for v in indicators['macd_hist'].fillna(0)] fig.add_trace(go.Bar( x=indicators.index, y=indicators['macd_hist'], name='Histogram', marker_color=colors, opacity=0.5 ), row=3, col=1) # Volume if 'volume' in plot_df.columns: colors = ['#26a69a' if c >= o else '#ef5350' for c, o in zip(plot_df['close'], plot_df['open'])] fig.add_trace(go.Bar( x=plot_df.index, y=plot_df['volume'], name='Volume', marker_color=colors, opacity=0.5 ), row=4, col=1) fig.update_layout( template='plotly_dark', height=900, showlegend=True, legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="center", x=0.5), xaxis_rangeslider_visible=False, margin=dict(l=60, r=20, t=80, b=20), paper_bgcolor='#1a1a2e', plot_bgcolor='#16213e', font=dict(color='#e0e0e0'), ) return fig def create_equity_chart(equity_data): """Create equity curve chart.""" if not equity_data: fig = go.Figure() fig.update_layout(template='plotly_dark', title="Pas de données") return fig eq_df = pd.DataFrame(equity_data) fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1, row_heights=[0.7, 0.3], subplot_titles=['💰 Courbe de Capital', '📉 Drawdown']) # Equity fig.add_trace(go.Scatter( x=eq_df['timestamp'], y=eq_df['equity'], name='Capital', fill='tozeroy', fillcolor='rgba(38, 166, 154, 0.2)', line=dict(color='#26a69a', width=2) ), row=1, col=1) # Drawdown equity_arr = eq_df['equity'].values peak = np.maximum.accumulate(equity_arr) dd = (peak - equity_arr) / peak * 100 fig.add_trace(go.Scatter( x=eq_df['timestamp'], y=-dd, name='Drawdown %', fill='tozeroy', fillcolor='rgba(239, 83, 80, 0.3)', line=dict(color='#ef5350', width=1.5) ), row=2, col=1) fig.update_layout( template='plotly_dark', height=500, paper_bgcolor='#1a1a2e', plot_bgcolor='#16213e', font=dict(color='#e0e0e0'), showlegend=False, margin=dict(l=60, r=20, t=40, b=20), ) return fig def create_trades_chart(trades): """Create trade analysis charts.""" if not trades: fig = go.Figure() fig.update_layout(template='plotly_dark', title="Aucun trade") return fig trades_df = pd.DataFrame(trades) fig = make_subplots(rows=2, cols=2, subplot_titles=['PnL par Trade', 'Distribution PnL (%)', 'PnL Cumulé', 'Leverage Utilisé']) # PnL per trade colors = ['#26a69a' if p > 0 else '#ef5350' for p in trades_df['pnl']] fig.add_trace(go.Bar( x=list(range(len(trades_df))), y=trades_df['pnl'], marker_color=colors, name='PnL' ), row=1, col=1) # PnL distribution fig.add_trace(go.Histogram( x=trades_df['pnl_pct'], nbinsx=30, name='PnL %', marker_color='#2196f3', opacity=0.7 ), row=1, col=2) # Cumulative PnL cum_pnl = trades_df['pnl'].cumsum() fig.add_trace(go.Scatter( x=list(range(len(cum_pnl))), y=cum_pnl, name='PnL Cumulé', fill='tozeroy', fillcolor='rgba(38, 166, 154, 0.2)', line=dict(color='#26a69a', width=2) ), row=2, col=1) # Leverage used fig.add_trace(go.Scatter( x=list(range(len(trades_df))), y=trades_df['leverage'], mode='markers+lines', name='Leverage', marker=dict(color='#ff9800', size=4), line=dict(color='#ff9800', width=1) ), row=2, col=2) fig.update_layout( template='plotly_dark', height=600, paper_bgcolor='#1a1a2e', plot_bgcolor='#16213e', font=dict(color='#e0e0e0'), showlegend=False, margin=dict(l=60, r=20, t=40, b=20), ) return fig # ======================== # MAIN BACKTEST FUNCTION # ======================== def run_backtest(source, symbol, days, volatility, capital, risk_pct, max_leverage, sl_mult, tp_mult, trailing_pct, use_trailing, min_confidence, min_confluence, min_rr, tf1, tf2, tf3): """Run the full backtest and return all visualizations.""" try: # Load data df, data_info = load_data(source, symbol, int(days), float(volatility)) # Build timeframes list timeframes = sorted( list(set([tf1, tf2, tf3])), key=lambda x: TIMEFRAME_HIERARCHY.get(x, 0) ) # Config config = { 'risk': { 'initial_capital': float(capital), 'risk_per_trade': float(risk_pct) / 100, 'max_leverage': int(max_leverage), 'sl_atr_multiplier': float(sl_mult), 'tp_atr_multiplier': float(tp_mult), 'trailing_stop_pct': float(trailing_pct) / 100, 'use_trailing': use_trailing, 'min_rr_ratio': float(min_rr), 'sizing_mode': 'fixed', 'max_drawdown': 0.99, }, 'min_confidence': float(min_confidence) / 100, 'min_confluence': float(min_confluence) / 100, } # Run backtest bt = Backtester(config) results = bt.run(df, base_tf=timeframes[0], timeframes=timeframes) # Get DataFrames equity_data = results.get('equity_curve', []) trades = results.get('trades', []) signals_df = pd.DataFrame(results.get('signals', [])) trades_df = pd.DataFrame(trades) # Create charts price_chart = create_candlestick_chart(df, trades_df, signals_df, f"📈 {symbol} - Multi-Timeframe Analysis") equity_chart = create_equity_chart(equity_data) trades_chart = create_trades_chart(trades) # Stats summary stats = results total_trades = stats.get('total_trades', 0) # Format numbers with capping for display final_capital = stats.get('capital', capital) total_pnl = stats.get('total_pnl', 0) return_pct = stats.get('return_pct', 0) # Cap display for extreme compounding if abs(return_pct) > 1e6: return_str = f"{'+'if return_pct>0 else ''}{return_pct:.2e}%" capital_str = f"${final_capital:.2e}" pnl_str = f"${total_pnl:.2e}" else: return_str = f"{'+'if return_pct>0 else ''}{return_pct:.1f}%" capital_str = f"${final_capital:,.2f}" pnl_str = f"${total_pnl:,.2f}" summary = f""" ## 📊 Résultats du Backtest | Métrique | Valeur | |----------|--------| | 📅 **Période** | {df.index[0].strftime('%Y-%m-%d')} → {df.index[-1].strftime('%Y-%m-%d')} | | 📊 **Barres analysées** | {len(df):,} | | 🕐 **Timeframes** | {', '.join(timeframes)} | | 💰 **Capital Initial** | ${float(capital):,.2f} | | 💰 **Capital Final** | {capital_str} | | 📈 **PnL Total** | {pnl_str} | | 📊 **Return** | {return_str} | | 🔢 **Trades Total** | {total_trades} | | ✅ **Win Rate** | {stats.get('win_rate', 0):.1%} | | 📊 **Profit Factor** | {stats.get('profit_factor', 0):.2f} | | 📉 **Max Drawdown** | {stats.get('max_drawdown', 0):.1%} | | 📈 **Sharpe Ratio** | {stats.get('sharpe_ratio', 0):.2f} | | 🏆 **Best Trade** | ${stats.get('best_trade', 0):,.2f} | | 💀 **Worst Trade** | ${stats.get('worst_trade', 0):,.2f} | | 💵 **Avg Win** | ${stats.get('avg_win', 0):,.2f} | | 💸 **Avg Loss** | ${stats.get('avg_loss', 0):,.2f} | | ⚡ **Avg Leverage** | {stats.get('avg_leverage', 0):.1f}x | | 💳 **Total Fees** | ${stats.get('total_fees', 0):,.2f} | | 📈 **Longs** | {stats.get('trades_long', 0)} | | 📉 **Shorts** | {stats.get('trades_short', 0)} | ### ℹ️ {data_info} """ # Trades table if len(trades_df) > 0: display_cols = ['side', 'entry_price', 'exit_price', 'pnl', 'pnl_pct', 'leverage', 'reason'] available_cols = [c for c in display_cols if c in trades_df.columns] table_df = trades_df[available_cols].copy() if 'pnl' in table_df.columns: table_df['pnl'] = table_df['pnl'].apply(lambda x: f"${x:,.2f}" if abs(x) < 1e8 else f"${x:.2e}") if 'pnl_pct' in table_df.columns: table_df['pnl_pct'] = table_df['pnl_pct'].apply(lambda x: f"{x:.1f}%") if 'entry_price' in table_df.columns: table_df['entry_price'] = table_df['entry_price'].apply(lambda x: f"${x:,.2f}") if 'exit_price' in table_df.columns: table_df['exit_price'] = table_df['exit_price'].apply(lambda x: f"${x:,.2f}") else: table_df = pd.DataFrame({"Info": ["Aucun trade exécuté"]}) return price_chart, equity_chart, trades_chart, summary, table_df except Exception as e: error_fig = go.Figure() error_fig.update_layout(template='plotly_dark', title=f"Erreur: {str(e)}") error_msg = f"## ❌ Erreur\n\n```\n{traceback.format_exc()}\n```" return error_fig, error_fig, error_fig, error_msg, pd.DataFrame({"Erreur": [str(e)]}) # ======================== # LIVE ANALYSIS # ======================== def run_live_analysis(symbol, days, tf1, tf2, tf3): """Run live analysis on current data (simulated).""" try: df = generate_sample_data(days=int(days), timeframe='1h', start_price=45000, volatility=0.025) timeframes = sorted(list(set([tf1, tf2, tf3])), key=lambda x: TIMEFRAME_HIERARCHY.get(x, 0)) # Get latest analysis tf_data = {timeframes[0]: df} for tf in timeframes: if tf != timeframes[0] and TIMEFRAME_HIERARCHY.get(tf, 0) > TIMEFRAME_HIERARCHY.get(timeframes[0], 0): tf_data[tf] = resample_ohlcv(df, tf) analyzer = MultiTimeframeAnalyzer(timeframes) result = analyzer.analyze(tf_data) # Compute ATR for SL/TP indicators = compute_all_indicators(df) current_price = df.iloc[-1]['close'] atr_val = indicators['atr'].iloc[-1] rm = RiskManager({'initial_capital': 10000, 'max_leverage': 20}) direction = result['direction'] confidence = result['confidence'] if direction in ['LONG', 'SHORT']: sl, tp = rm.calculate_sl_tp(current_price, atr_val, direction) lev = rm.calculate_leverage(atr_val/current_price, confidence, result.get('signals', {}).get(timeframes[0], {}).get('volatility', 0.5)) else: sl, tp = current_price, current_price lev = 1 direction_emoji = {"LONG": "🟢 LONG", "SHORT": "🔴 SHORT", "NEUTRAL": "⚪ NEUTRE"} analysis = f""" ## 🔍 Analyse Multi-Timeframe en Direct ### Signal: {direction_emoji.get(direction, '⚪ NEUTRE')} | Paramètre | Valeur | |-----------|--------| | **Prix Actuel** | ${current_price:,.2f} | | **Direction** | {direction} | | **Confiance** | {confidence:.0%} | | **Confluence** | {result.get('confluence', 0):.0%} | | **Score Combiné** | {result.get('combined_score', 0):.3f} | | **Leverage Suggéré** | {lev}x | | **Stop Loss** | ${sl:,.2f} ({abs(current_price-sl)/current_price*100:.2f}%) | | **Take Profit** | ${tp:,.2f} ({abs(tp-current_price)/current_price*100:.2f}%) | | **ATR** | ${atr_val:,.2f} | | **R:R Ratio** | {abs(tp-current_price)/abs(current_price-sl):.2f} | ### Analyse par Timeframe """ for tf, sig in result.get('signals', {}).items(): bias = sig.get('bias', 'NEUTRAL') bias_emoji = {"BULLISH": "🟢", "BEARISH": "🔴", "NEUTRAL": "⚪"} analysis += f"**{tf}** {bias_emoji.get(bias, '⚪')} {bias} | " analysis += f"Trend: {sig.get('trend', 0):.2f} | " analysis += f"Mom: {sig.get('momentum', 0):.2f} | " analysis += f"Str: {sig.get('strength', 0):.2f}\n\n" # Chart chart = create_candlestick_chart(df, title=f"📊 {symbol} - Analyse Live") # Add SL/TP lines if direction != 'NEUTRAL': chart.add_hline(y=sl, line_dash="dash", line_color="red", opacity=0.7, annotation_text=f"SL ${sl:,.0f}", row=1, col=1) chart.add_hline(y=tp, line_dash="dash", line_color="green", opacity=0.7, annotation_text=f"TP ${tp:,.0f}", row=1, col=1) chart.add_hline(y=current_price, line_dash="dot", line_color="yellow", opacity=0.5, annotation_text=f"Prix ${current_price:,.0f}", row=1, col=1) return chart, analysis except Exception as e: fig = go.Figure() fig.update_layout(template='plotly_dark') return fig, f"## ❌ Erreur\n\n{str(e)}" # ======================== # GRADIO UI # ======================== custom_css = """ .gradio-container { max-width: 1400px !important; background-color: #0a0a1a !important; } .dark { background-color: #0a0a1a !important; } h1 { text-align: center; background: linear-gradient(90deg, #26a69a, #2196f3, #9c27b0); -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-size: 2.5em !important; margin-bottom: 0 !important; } .subtitle { text-align: center; color: #888; font-size: 1.1em; margin-bottom: 20px; } """ with gr.Blocks(title="🤖 Ultra Trading Agent") as demo: gr.Markdown("# 🤖 Ultra Trading Agent") gr.Markdown("
Bot de Trading Multi-Timeframe avec Gestion Dynamique du Risque
") with gr.Tabs(): # ===================== # TAB 1: BACKTEST # ===================== with gr.Tab("📊 Backtest"): with gr.Row(): with gr.Column(scale=1): gr.Markdown("### ⚙️ Configuration") with gr.Accordion("📈 Données", open=True): data_source = gr.Dropdown( choices=["📊 Données Synthétiques (Test)", "🔗 Binance (Live)"], value="📊 Données Synthétiques (Test)", label="Source de Données" ) symbol_input = gr.Textbox(value="BTC/USDT", label="Symbole") days_input = gr.Slider(30, 730, 180, step=30, label="Jours de données") volatility_input = gr.Slider(0.005, 0.05, 0.025, step=0.005, label="Volatilité (synthétique)") with gr.Accordion("💰 Capital & Risque", open=True): capital_input = gr.Number(value=10000, label="Capital Initial ($)") risk_input = gr.Slider(0.5, 5, 2, step=0.5, label="Risque par Trade (%)") max_lev_input = gr.Slider(1, 50, 20, step=1, label="Leverage Maximum") min_rr_input = gr.Slider(1, 5, 1.5, step=0.5, label="R:R Minimum") with gr.Accordion("🎯 Stop-Loss & Take-Profit", open=True): sl_mult = gr.Slider(0.5, 3, 1.5, step=0.1, label="SL (× ATR)") tp_mult = gr.Slider(1, 6, 3.0, step=0.5, label="TP (× ATR)") trailing_pct = gr.Slider(0.5, 5, 1.5, step=0.5, label="Trailing Stop (%)") use_trailing = gr.Checkbox(value=True, label="Activer Trailing Stop") with gr.Accordion("🕐 Timeframes", open=True): tf1 = gr.Dropdown(choices=['5m','15m','30m','1h','2h','4h','6h','8h','12h','1d'], value='1h', label="Timeframe 1 (Entrée)") tf2 = gr.Dropdown(choices=['15m','30m','1h','2h','4h','6h','8h','12h','1d','3d','1w'], value='4h', label="Timeframe 2") tf3 = gr.Dropdown(choices=['1h','4h','6h','8h','12h','1d','3d','1w','1M'], value='1d', label="Timeframe 3") with gr.Accordion("🔧 Seuils de Signal", open=False): min_conf = gr.Slider(10, 80, 30, step=5, label="Confiance Min (%)") min_confl = gr.Slider(30, 100, 50, step=10, label="Confluence Min (%)") run_btn = gr.Button("🚀 Lancer le Backtest", variant="primary", size="lg") with gr.Column(scale=3): summary_output = gr.Markdown("*Configurez les paramètres et lancez le backtest...*") price_chart = gr.Plot(label="Graphique des Prix & Signaux") with gr.Row(): equity_chart = gr.Plot(label="Courbe de Capital") trades_chart = gr.Plot(label="Analyse des Trades") trades_table = gr.Dataframe(label="📋 Détail des Trades", wrap=True) run_btn.click( fn=run_backtest, inputs=[data_source, symbol_input, days_input, volatility_input, capital_input, risk_input, max_lev_input, sl_mult, tp_mult, trailing_pct, use_trailing, min_conf, min_confl, min_rr_input, tf1, tf2, tf3], outputs=[price_chart, equity_chart, trades_chart, summary_output, trades_table] ) # ===================== # TAB 2: LIVE ANALYSIS # ===================== with gr.Tab("🔍 Analyse Live"): with gr.Row(): with gr.Column(scale=1): gr.Markdown("### 🔍 Configuration") live_symbol = gr.Textbox(value="BTC/USDT", label="Symbole") live_days = gr.Slider(7, 90, 30, step=7, label="Jours de données") live_tf1 = gr.Dropdown(choices=['5m','15m','30m','1h','4h'], value='1h', label="TF Entrée") live_tf2 = gr.Dropdown(choices=['1h','4h','8h','12h','1d'], value='4h', label="TF Moyen") live_tf3 = gr.Dropdown(choices=['4h','1d','3d','1w'], value='1d', label="TF Long") analyze_btn = gr.Button("🔍 Analyser", variant="primary", size="lg") with gr.Column(scale=3): live_analysis = gr.Markdown("*Cliquez sur Analyser pour obtenir le signal en direct...*") live_chart = gr.Plot(label="Graphique Live") analyze_btn.click( fn=run_live_analysis, inputs=[live_symbol, live_days, live_tf1, live_tf2, live_tf3], outputs=[live_chart, live_analysis] ) # ===================== # TAB 3: DOCUMENTATION # ===================== with gr.Tab("📚 Guide"): gr.Markdown(""" # 📚 Guide du Trading Agent ## 🏗️ Architecture Ce bot utilise une **analyse multi-timeframe** pour identifier les meilleures opportunités de trading : ### 1. Indicateurs Techniques - **EMAs** (9, 21, 50, 200) — Identification de tendance - **RSI** (14) — Momentum et conditions de sur-achat/sur-vente - **MACD** (12, 26, 9) — Momentum et croisements - **Bollinger Bands** (20, 2σ) — Volatilité et niveaux extrêmes - **ATR** (14) — Calcul dynamique de SL/TP - **ADX** (14) — Force de la tendance - **Stochastique** (14, 3) — Momentum oscillant - **SuperTrend** (10, 3) — Direction de tendance - **Ichimoku Cloud** — Support/résistance dynamique ### 2. Analyse Multi-Timeframe Le bot analyse **3 timeframes simultanément** : - **TF Bas** (ex: 1h) — Timing d'entrée précis - **TF Moyen** (ex: 4h) — Confirmation de tendance - **TF Haut** (ex: 1D) — Direction générale du marché La **confluence** entre les timeframes détermine la force du signal. ### 3. Signaux de Trading - **🟢 LONG** — Acheter (toutes les TFs sont haussières) - **🔴 SHORT** — Vendre (toutes les TFs sont baissières) - **⚪ HOLD** — Pas de position (signal mixte ou faible) ### 4. Gestion du Risque - **Leverage Dynamique** — Ajusté en fonction de la volatilité (ATR), la confiance du signal, et le drawdown - **Position Sizing** — Basé sur le % de risque par trade - **Stop-Loss** — ATR × multiplicateur (par défaut 1.5) - **Take-Profit** — ATR × multiplicateur (par défaut 3.0) - **Trailing Stop** — S'active après un profit minimum, suit le prix - **Protection Max Drawdown** — Arrête le trading si le drawdown dépasse 15% - **Cooldown** — Pause après une série de pertes consécutives ### 5. Position Management - Maximum 3 positions simultanées - Retournement automatique si le signal s'inverse fortement - Fermeture sur SL, TP, trailing stop, ou signal contraire ## ⚡ Paramètres Clés | Paramètre | Description | Défaut | |-----------|-------------|--------| | Risk/Trade | % du capital risqué par trade | 2% | | Max Leverage | Leverage maximum autorisé | 20x | | SL ATR Mult | Multiplicateur ATR pour le stop-loss | 1.5x | | TP ATR Mult | Multiplicateur ATR pour le take-profit | 3.0x | | Min R:R | Ratio risque/récompense minimum | 1.5:1 | | Min Confiance | Score minimum pour entrer | 30% | | Min Confluence | % de TFs en accord | 50% | ## ⚠️ Avertissement Ce bot est un outil **éducatif et de recherche**. Le trading comporte des risques significatifs. Les performances passées ne garantissent pas les résultats futurs. **N'investissez jamais plus que ce que vous pouvez vous permettre de perdre.** """) if __name__ == "__main__": demo.launch(server_name="0.0.0.0", server_port=7860, theme=gr.themes.Soft(primary_hue="teal", secondary_hue="blue"), css=custom_css)