doulfa's picture
Upload app.py with huggingface_hub
da462a3 verified
"""
🤖 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("<p class='subtitle'>Bot de Trading Multi-Timeframe avec Gestion Dynamique du Risque</p>")
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)