finance2 / app.py
torxytonnicker's picture
Update app.py
2ecca54 verified
import gradio as gr
import json
import re
import sys
import os
from datetime import datetime
# Adicionar o diretório raiz ao path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# Dashboard não disponível - app rodado no Hugging Face Spaces
DASHBOARD_INTEGRATION_AVAILABLE = False
# Importar apenas o sistema de IA para análise
try:
from src.main import ScalpingBot
# Inicializar apenas para usar o sistema de IA
trading_bot = ScalpingBot()
print("✅ Sistema de IA BERT inicializado com sucesso")
# Verificar se o sistema de IA está disponível
if hasattr(trading_bot, 'hf_api') and trading_bot.hf_api:
TRANSFORMERS_AVAILABLE = True
current_model_info = {
"name": "Hugging Face Spaces",
"description": "IA FinBERT via Hugging Face Spaces",
"labels": {"LABEL_0": "NEGATIVO", "LABEL_1": "NEUTRO", "LABEL_2": "POSITIVO"}
}
print("✅ Sistema de IA BERT disponível para análise")
else:
TRANSFORMERS_AVAILABLE = False
print("⚠️ Sistema de IA BERT não disponível")
except ImportError as e:
TRANSFORMERS_AVAILABLE = False
trading_bot = None
current_model_info = None
print(f"⚠️ Sistema de IA não disponível: {e}")
def get_sample_market_data():
"""Retorna dados de exemplo para demonstração"""
return {
'price': 116500.25,
'variation': 0.15,
'rsi': 68.5,
'ema_trend': 'ALTA',
'bb_position': 'DENTRO',
'volume': 1.8,
'symbol': 'BTCUSD',
'timestamp': datetime.now().isoformat()
}
def parse_market_data(text):
"""Extrai dados de mercado do texto de entrada"""
try:
# Regex patterns para extrair dados
price_match = re.search(r'P:([0-9,]+\.?\d*)', text)
variation_match = re.search(r'\(([\+\-]\d+\.?\d*%?)\)', text)
rsi_match = re.search(r'RSI:(\d+)', text)
ema_match = re.search(r'EMA:(ALTA|BAIXA)', text)
bb_match = re.search(r'BB:(DENTRO|SOBRE|ABAIXO|ACIMA)', text)
vol_match = re.search(r'Vol:([0-9\.]+)', text)
# Extrair valores
price = float(price_match.group(1).replace(',', '')) if price_match else 0
variation_str = variation_match.group(1) if variation_match else "0"
variation = float(variation_str.replace('%', '').replace('+', '')) if variation_str != "0" else 0
rsi = int(rsi_match.group(1)) if rsi_match else 50
ema_trend = ema_match.group(1) if ema_match else "NEUTRO"
bb_position = bb_match.group(1) if bb_match else "DENTRO"
volume = float(vol_match.group(1)) if vol_match else 0
return {
'price': price,
'variation': variation,
'rsi': rsi,
'ema_trend': ema_trend,
'bb_position': bb_position,
'volume': volume
}
except Exception as e:
return None
def analyze_sentiment_with_bert(market_data):
"""Analisa o sentimento usando o sistema de IA BERT com fallback robusto"""
if not TRANSFORMERS_AVAILABLE or not trading_bot or not hasattr(trading_bot, 'hf_api'):
print("⚠️ BERT não disponível - usando sistema robusto")
return analyze_sentiment_robust(market_data)
try:
# Preparar dados para análise de IA
ai_market_data = {
'symbol': market_data.get('symbol', 'BTCUSD'),
'current_price': market_data.get('price', 0),
'rsi': market_data.get('rsi', 50),
'ema_12': market_data.get('ema_12', 0),
'ema_26': market_data.get('ema_26', 0),
'bb_upper': market_data.get('bb_upper', 0),
'bb_middle': market_data.get('bb_middle', 0),
'bb_lower': market_data.get('bb_lower', 0),
'volume_ratio': market_data.get('volume', 1.0),
'trend': market_data.get('ema_trend', 'NEUTRO'),
'price_change_pct': market_data.get('variation', 0),
'timestamp': datetime.now().isoformat()
}
# Enviar para análise de IA
ai_response = trading_bot.hf_api.send_analysis_request(ai_market_data)
if ai_response:
# Parse da resposta
ai_sentiment, ai_confidence, ai_analysis = trading_bot.hf_api.parse_ai_response(ai_response)
# Verificar se o BERT retornou dados estáticos (problema conhecido)
if ("$0.00" in ai_analysis or "RSI: 50" in ai_analysis or
"0.00%" in ai_analysis or "Volume: 0.0x" in ai_analysis):
print("⚠️ BERT retornou dados estáticos - usando sistema robusto")
return analyze_sentiment_robust(market_data)
# Mapear para o formato esperado
sentiment_mapping = {
'BULLISH': 'POSITIVO',
'BEARISH': 'NEGATIVO',
'NEUTRAL': 'NEUTRO',
'NEUTRO': 'NEUTRO',
'POSITIVO': 'POSITIVO',
'NEGATIVO': 'NEGATIVO'
}
sentiment_label = sentiment_mapping.get(ai_sentiment, 'NEUTRO')
print(f"✅ BERT Sentimento: {sentiment_label} ({ai_confidence:.1f}%)")
return {
'sentiment': ai_sentiment.lower(),
'confidence': ai_confidence / 100.0 if ai_confidence > 1 else ai_confidence,
'label': sentiment_label,
'analysis': ai_analysis
}
print("⚠️ BERT não respondeu - usando sistema robusto")
return analyze_sentiment_robust(market_data)
except Exception as e:
print(f"⚠️ Erro na análise BERT: {e} - usando sistema robusto")
return analyze_sentiment_robust(market_data)
def analyze_sentiment_robust(market_data):
"""Sistema de análise robusto que funciona quando o BERT falha"""
try:
# Extrair dados
price = market_data.get('price', 0)
rsi = market_data.get('rsi', 50)
ema_trend = market_data.get('ema_trend', 'NEUTRO')
volume_ratio = market_data.get('volume', 1.0)
price_change_pct = market_data.get('variation', 0)
symbol = market_data.get('symbol', 'BTCUSD')
print(f"📊 Análise Robusta {symbol}: Preço={price}, RSI={rsi}, Trend={ema_trend}")
# Análise de sentimento baseada em indicadores
sentiment_score = 0
confidence_score = 0
signals = []
# === ANÁLISE RSI ===
if rsi <= 30:
sentiment_score += 30 # Muito bullish
confidence_score += 25
signals.append(f"RSI {rsi} - Zona de sobrevenda (COMPRA)")
elif rsi >= 70:
sentiment_score -= 30 # Muito bearish
confidence_score += 25
signals.append(f"RSI {rsi} - Zona de sobrecompra (VENDA)")
elif 40 <= rsi <= 60:
sentiment_score += 5 # Neutro
confidence_score += 10
signals.append(f"RSI {rsi} - Zona neutra")
# === ANÁLISE EMA ===
if ema_trend == 'ALTA':
sentiment_score += 20
confidence_score += 15
signals.append("EMA em tendência de ALTA")
elif ema_trend == 'BAIXA':
sentiment_score -= 20
confidence_score += 15
signals.append("EMA em tendência de BAIXA")
# === ANÁLISE DE VOLUME ===
if volume_ratio > 1.5:
sentiment_score += 15
confidence_score += 10
signals.append(f"Volume alto ({volume_ratio:.1f}x) - Confirma movimento")
elif volume_ratio < 0.8:
sentiment_score -= 5
confidence_score += 5
signals.append(f"Volume baixo ({volume_ratio:.1f}x) - Cuidado")
# === ANÁLISE DE MOMENTUM ===
if price_change_pct > 0.1:
sentiment_score += 10
confidence_score += 10
signals.append(f"Momentum positivo (+{price_change_pct:.2f}%)")
elif price_change_pct < -0.1:
sentiment_score -= 10
confidence_score += 10
signals.append(f"Momentum negativo ({price_change_pct:.2f}%)")
# === ANÁLISE DE BOLLINGER BANDS ===
bb_position = market_data.get('bb_position', 'DENTRO')
if bb_position == 'ABAIXO':
sentiment_score += 25
confidence_score += 20
signals.append("Preço abaixo da banda inferior - Reversão esperada")
elif bb_position == 'ACIMA':
sentiment_score -= 25
confidence_score += 20
signals.append("Preço acima da banda superior - Reversão esperada")
# Determinar sentimento final
if sentiment_score >= 30:
sentiment = 'BULLISH'
sentiment_label = 'POSITIVO'
elif sentiment_score <= -30:
sentiment = 'BEARISH'
sentiment_label = 'NEGATIVO'
else:
sentiment = 'NEUTRAL'
sentiment_label = 'NEUTRO'
# Calcular confiança final
confidence = min(95, max(15, confidence_score))
print(f"✅ Análise Robusta: {sentiment} ({confidence:.1f}%)")
return {
'sentiment': sentiment.lower(),
'confidence': confidence / 100.0,
'label': sentiment_label,
'analysis': f'Análise robusta: {sentiment} ({confidence:.1f}%) - {len(signals)} sinais',
'signals': signals,
'sentiment_score': sentiment_score
}
except Exception as e:
print(f"❌ Erro na análise robusta: {e}")
return {
'sentiment': 'neutral',
'confidence': 0.5,
'label': 'NEUTRO',
'analysis': f'Erro na análise: {e}',
'signals': [],
'sentiment_score': 0
}
def analyze_scalping_signals(market_data, original_text=""):
"""Analisa sinais para scalping baseado em indicadores técnicos e sentimento IA"""
if not market_data:
return {
'action': 'AGUARDAR',
'confidence': 0,
'reason': 'Dados insuficientes para análise',
'sentiment': {'label': 'NEUTRO', 'confidence': 0.5}
}
# Análise de sentimento com BERT
sentiment_analysis = analyze_sentiment_with_bert(market_data)
price = market_data['price']
variation = market_data['variation']
rsi = market_data['rsi']
ema_trend = market_data['ema_trend']
bb_position = market_data['bb_position']
volume = market_data['volume']
# Pontuação de confiança
confidence_score = 0
signals = []
action = 'AGUARDAR'
# === ANÁLISE RSI ===
if rsi <= 30: # Oversold
signals.append("RSI em zona de sobrevenda ({}): COMPRA".format(rsi))
confidence_score += 25
if action == 'AGUARDAR':
action = 'COMPRAR'
elif rsi >= 70: # Overbought
signals.append("RSI em zona de sobrecompra ({}): VENDA".format(rsi))
confidence_score += 25
if action == 'AGUARDAR':
action = 'VENDER'
elif 45 <= rsi <= 55:
signals.append("RSI neutro ({}): aguardar confirmação".format(rsi))
# === ANÁLISE EMA ===
if ema_trend == 'ALTA':
signals.append("Tendência EMA ALTA: viés de COMPRA")
confidence_score += 15
if action == 'VENDER':
confidence_score -= 10 # Conflito
elif action == 'AGUARDAR':
action = 'COMPRAR'
elif ema_trend == 'BAIXA':
signals.append("Tendência EMA BAIXA: viés de VENDA")
confidence_score += 15
if action == 'COMPRAR':
confidence_score -= 10 # Conflito
elif action == 'AGUARDAR':
action = 'VENDER'
# === ANÁLISE BOLLINGER BANDS ===
if bb_position == 'ABAIXO':
signals.append("Preço abaixo da banda inferior: COMPRA (reversão)")
confidence_score += 20
if action == 'AGUARDAR':
action = 'COMPRAR'
elif bb_position == 'ACIMA' or bb_position == 'SOBRE':
signals.append("Preço acima da banda superior: VENDA (reversão)")
confidence_score += 20
if action == 'AGUARDAR':
action = 'VENDER'
elif bb_position == 'DENTRO':
signals.append("Preço dentro das bandas: aguardar breakout")
confidence_score += 5
# === ANÁLISE DE MOMENTUM (Variação) ===
if abs(variation) >= 0.05: # Movimento significativo
if variation > 0:
signals.append("Momentum positivo (+{:.2f}%): seguir tendência".format(variation))
confidence_score += 10
if action == 'VENDER':
confidence_score -= 5
else:
signals.append("Momentum negativo ({:.2f}%): seguir tendência".format(variation))
confidence_score += 10
if action == 'COMPRAR':
confidence_score -= 5
# === ANÁLISE DE VOLUME ===
if volume > 1.0: # Volume alto
signals.append("Volume alto ({:.1f}x): confirma movimento".format(volume))
confidence_score += 10
elif volume < 0.5: # Volume baixo
signals.append("Volume baixo ({:.1f}x): cuidado com falsos sinais".format(volume))
confidence_score -= 5
# === ANÁLISE DE SENTIMENTO IA (FinBERT) ===
sentiment_label = sentiment_analysis['label']
sentiment_conf = sentiment_analysis['confidence']
if sentiment_label == 'POSITIVO':
signals.append("🤖 IA Sentimento: POSITIVO ({:.1f}%): viés de COMPRA".format(sentiment_conf * 100))
confidence_score += int(sentiment_conf * 20) # Até 20 pontos
if action == 'AGUARDAR':
action = 'COMPRAR'
elif action == 'VENDER':
confidence_score -= 10 # Conflito com sentimento
elif sentiment_label == 'NEGATIVO':
signals.append("🤖 IA Sentimento: NEGATIVO ({:.1f}%): viés de VENDA".format(sentiment_conf * 100))
confidence_score += int(sentiment_conf * 20) # Até 20 pontos
if action == 'AGUARDAR':
action = 'VENDER'
elif action == 'COMPRAR':
confidence_score -= 10 # Conflito com sentimento
else:
signals.append("🤖 IA Sentimento: NEUTRO ({:.1f}%): sem viés claro".format(sentiment_conf * 100))
# === REGRAS ESPECÍFICAS DE SCALPING ===
# Scalping: RSI extremo + EMA contrária = reversão forte
if (rsi <= 25 and ema_trend == 'BAIXA') or (rsi >= 75 and ema_trend == 'ALTA'):
signals.append("🚨 SINAL FORTE: RSI extremo com EMA contrária - REVERSÃO")
confidence_score += 30
# Scalping: RSI + BB alinhados
if rsi <= 35 and bb_position == 'ABAIXO':
signals.append("🎯 SETUP PERFEITO: RSI baixo + BB abaixo - COMPRA FORTE")
confidence_score += 35
action = 'COMPRAR'
elif rsi >= 65 and (bb_position == 'ACIMA' or bb_position == 'SOBRE'):
signals.append("🎯 SETUP PERFEITO: RSI alto + BB acima - VENDA FORTE")
confidence_score += 35
action = 'VENDER'
# Limitar confiança
confidence_score = min(confidence_score, 95)
confidence_score = max(confidence_score, 10)
return {
'action': action,
'confidence': confidence_score,
'signals': signals,
'market_data': market_data,
'sentiment': sentiment_analysis
}
def generate_trading_response(analysis):
"""Gera resposta formatada para trading com análise de sentimento IA"""
action = analysis['action']
confidence = analysis['confidence']
signals = analysis.get('signals', [])
market_data = analysis.get('market_data', {})
sentiment = analysis.get('sentiment', {'label': 'NEUTRO', 'confidence': 0.5})
# Emojis e cores baseados na ação
if action == 'COMPRAR':
emoji = "🟢"
action_emoji = "📈"
color = "verde"
direction = "LONG"
elif action == 'VENDER':
emoji = "🔴"
action_emoji = "📉"
color = "vermelho"
direction = "SHORT"
else:
emoji = "🟡"
action_emoji = "⏸️"
color = "amarelo"
direction = "NEUTRO"
# Emojis para sentimento
sentiment_emojis = {
'POSITIVO': '😊💚',
'NEGATIVO': '😟💔',
'NEUTRO': '😐💛'
}
# Barra de confiança
confidence_bars = "█" * int(confidence / 10) + "░" * (10 - int(confidence / 10))
# Classificação de confiança
if confidence >= 80:
conf_level = "MUITO ALTA"
elif confidence >= 65:
conf_level = "ALTA"
elif confidence >= 50:
conf_level = "MODERADA"
else:
conf_level = "BAIXA"
# Timestamp
timestamp = datetime.now().strftime("%H:%M:%S")
response = f"""{emoji} **ANÁLISE SCALPING - BTCUSD M1/M5**
**⏰ Timestamp:** {timestamp}
**📊 Instrumento:** BTCUSD
**🎯 DECISÃO DE TRADING:**
• **Ação:** {action} {action_emoji}
• **Direção:** {direction}
• **Confiança:** {confidence:.0f}% ({conf_level})
• **Visual:** {confidence_bars}
**🤖 ANÁLISE DE SENTIMENTO IA (FinBERT):**
• **Sentimento:** {sentiment_emojis.get(sentiment['label'], '😐💛')} **{sentiment['label']}** ({sentiment['confidence']*100:.1f}%)
**📈 DADOS DE MERCADO:**
• **Preço:** ${market_data.get('price', 'N/A'):,.2f}
• **Variação:** {market_data.get('variation', 0):+.2f}%
• **RSI:** {market_data.get('rsi', 'N/A')}
• **EMA:** {market_data.get('ema_trend', 'N/A')}
• **Bollinger:** {market_data.get('bb_position', 'N/A')}
• **Volume:** {market_data.get('volume', 0):.1f}x
**🔍 ANÁLISE TÉCNICA + IA:**"""
for i, signal in enumerate(signals[:5], 1): # Máximo 5 sinais
response += f"\n{i}. {signal}"
# Recomendações específicas
response += f"\n\n**⚡ RECOMENDAÇÕES SCALPING:**"
if action == 'COMPRAR':
response += f"""
• **Stop Loss:** ${market_data.get('price', 0) * 0.9993:.2f} (-0.07%)
• **Take Profit:** ${market_data.get('price', 0) * 1.0015:.2f} (+0.15%)
• **Timeframe:** M1/M5
• **Risk/Reward:** 1:2"""
elif action == 'VENDER':
response += f"""
• **Stop Loss:** ${market_data.get('price', 0) * 1.0007:.2f} (+0.07%)
• **Take Profit:** ${market_data.get('price', 0) * 0.9985:.2f} (-0.15%)
• **Timeframe:** M1/M5
• **Risk/Reward:** 1:2"""
else:
response += """
• **Aguardar:** Setup mais definido
• **Monitorar:** Rompimentos de suporte/resistência
• **Observar:** Confluência de sinais técnicos"""
if confidence < 60:
response += f"\n\n⚠️ **ATENÇÃO:** Confiança {conf_level} - Aguarde confirmação adicional!"
response += f"\n\n---\n*🤖 Análise Scalping Automatizada - {timestamp}*"
return response
def process_trading_analysis(text):
"""Função principal que processa a análise de trading com BERT"""
if text and text.strip():
# Parse dos dados de mercado do texto
market_data = parse_market_data(text)
data_source = "Dados Inseridos"
if not market_data:
return "⚠️ **Erro:** Formato de dados inválido. Use o formato: P:preço(variação%) | EMA:ALTA/BAIXA | RSI:valor | BB:posição | Vol:volume"
else:
return "⚠️ **Erro:** Nenhum dado de mercado fornecido. Insira dados no formato correto."
# Análise dos sinais com BERT
analysis = analyze_scalping_signals(market_data, text or f"Dados {data_source}")
# Adicionar informação da fonte de dados
analysis['data_source'] = data_source
analysis['timestamp'] = datetime.now().isoformat()
# Gerar resposta formatada
response = generate_trading_response(analysis)
# Dashboard não disponível - app rodado no Hugging Face Spaces
print(f"✅ Análise BERT concluída - {data_source}")
return response
def get_sample_data_for_ui():
"""Retorna dados de exemplo formatados para a interface"""
sample_data = get_sample_market_data()
formatted_data = f"P:{sample_data['price']}({sample_data['variation']:+.2f}%) | EMA:{sample_data['ema_trend']} | RSI:{sample_data['rsi']:.1f} | BB:{sample_data['bb_position']} | Vol:{sample_data['volume']:.1f}"
return formatted_data
# CSS customizado com Bootstrap 5 integrado
custom_css = """
@import url('https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css');
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=Poppins:wght@300;400;500;600;700&display=swap');
:root {
--bs-primary: #00d4ff;
--bs-secondary: #ff6b6b;
--bs-success: #00ff88;
--bs-danger: #ff4757;
--bs-warning: #ffa502;
--bs-dark: #0a0a0a;
--bs-light: #f0f0f0;
--primary-bg: linear-gradient(135deg, #0a0a0a 0%, #1a0a1a 50%, #0a0a0a 100%);
--card-bg: rgba(30, 30, 40, 0.98);
--text-bright: #f0f0f0;
--text-secondary: #c0c0c0;
}
body {
font-family: 'Inter', 'Poppins', -apple-system, BlinkMacSystemFont, sans-serif !important;
background: var(--primary-bg) !important;
color: var(--text-bright) !important;
min-height: 100vh;
}
body::before {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image:
radial-gradient(circle at 25% 25%, rgba(255, 107, 107, 0.05) 0%, transparent 50%),
radial-gradient(circle at 75% 75%, rgba(78, 205, 196, 0.05) 0%, transparent 50%);
pointer-events: none;
z-index: -1;
}
.gradio-container {
max-width: 100% !important;
padding: 0 !important;
}
.main-header {
background: var(--card-bg);
border: 1px solid rgba(0, 212, 255, 0.2);
backdrop-filter: blur(20px);
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.6);
}
.main-header h1 {
color: #ffffff !important;
font-weight: 700 !important;
font-family: 'Poppins', sans-serif !important;
}
.main-header h2,
.main-header p,
.main-header p *,
.main-header p strong,
.main-header p em,
.main-header .text-white,
.main-header .text-white *,
.main-header .lead,
.main-header .lead * {
color: #ffffff !important;
text-shadow: none !important;
}
.card-custom {
background: var(--card-bg) !important;
border: 1px solid rgba(255, 255, 255, 0.1) !important;
backdrop-filter: blur(20px) !important;
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.6) !important;
}
.form-control {
background: rgba(0, 0, 0, 0.9) !important;
border: 1px solid rgba(0, 212, 255, 0.3) !important;
color: var(--text-bright) !important;
font-family: 'Inter', sans-serif !important;
}
.form-control:focus {
background: rgba(0, 0, 0, 0.9) !important;
border-color: var(--bs-primary) !important;
box-shadow: 0 0 25px rgba(0, 212, 255, 0.3) !important;
color: var(--text-bright) !important;
}
.form-control::placeholder {
color: var(--text-secondary) !important;
opacity: 0.7 !important;
}
.btn-primary {
background: linear-gradient(135deg, var(--bs-primary), #0099cc) !important;
border: none !important;
font-weight: 600 !important;
font-family: 'Inter', sans-serif !important;
box-shadow: 0 4px 12px rgba(0, 212, 255, 0.3) !important;
transition: all 0.3s ease !important;
}
.btn-primary:hover {
transform: translateY(-2px) !important;
box-shadow: 0 6px 16px rgba(0, 212, 255, 0.4) !important;
filter: brightness(1.05) !important;
}
.btn-secondary {
background: rgba(255, 255, 255, 0.1) !important;
border: 1px solid rgba(0, 212, 255, 0.3) !important;
color: var(--text-bright) !important;
font-family: 'Inter', sans-serif !important;
}
.btn-secondary:hover {
background: rgba(255, 255, 255, 0.2) !important;
border-color: rgba(0, 212, 255, 0.5) !important;
color: var(--text-bright) !important;
transform: translateY(-1px) !important;
}
.output-area {
background: rgba(0, 0, 0, 0.85) !important;
border: 1px solid rgba(0, 212, 255, 0.2) !important;
color: var(--text-bright) !important;
font-family: 'Inter', sans-serif !important;
max-height: 600px;
overflow-y: auto;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
.text-gradient {
color: #ffffff !important;
}
.strategy-card {
background: rgba(0, 0, 0, 0.6);
border: 2px solid rgba(0, 212, 255, 0.2);
backdrop-filter: blur(10px);
box-shadow: 0 0 20px rgba(0, 212, 255, 0.1);
}
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.1);
border-radius: 10px;
}
::-webkit-scrollbar-thumb {
background: var(--bs-primary);
border-radius: 10px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--bs-secondary);
}
/* Responsividade Mobile */
@media (max-width: 768px) {
.container-fluid {
padding: 0.5rem !important;
}
.main-header {
padding: 1.5rem !important;
}
.main-header h1 {
font-size: 2rem !important;
}
.main-header h2 {
font-size: 1.2rem !important;
}
.card-custom {
margin-bottom: 1rem !important;
}
.btn-lg {
font-size: 0.9rem !important;
padding: 0.5rem 1rem !important;
}
.form-control {
font-size: 14px !important;
}
.output-area {
font-size: 13px !important;
max-height: 400px !important;
}
.row.g-2 {
margin-top: 0.5rem !important;
}
.btn-sm {
font-size: 0.8rem !important;
padding: 0.25rem 0.5rem !important;
}
}
@media (max-width: 576px) {
.main-header h1 {
font-size: 1.5rem !important;
}
.main-header h2 {
font-size: 1rem !important;
}
.main-header p {
font-size: 0.9rem !important;
}
.card-header h3 {
font-size: 1rem !important;
}
.btn {
font-size: 0.8rem !important;
}
}
/* Melhorias para tablets */
@media (min-width: 769px) and (max-width: 1024px) {
.container-fluid {
padding: 1rem !important;
}
.main-header {
padding: 2rem !important;
}
}
/* Classes utilitárias responsivas */
.mobile-view .gradio-container {
padding: 0.5rem !important;
}
.mobile-view .main-header {
margin-bottom: 1rem !important;
}
/* Ajustes para elementos Gradio */
.gradio-container .gr-textbox,
.gradio-container textarea {
border-radius: 0.375rem !important;
}
.gradio-container .gr-button {
border-radius: 0.375rem !important;
}
.gradio-container .gr-markdown {
border-radius: 0.375rem !important;
}
"""
# Interface Gradio com Bootstrap 5
with gr.Blocks(css=custom_css, title="🤖 Serviço de Análise BERT - BotCS", theme=gr.themes.Base()) as demo:
# Container principal Bootstrap
gr.HTML("""
<div class="container-fluid">
<!-- Cabeçalho principal -->
<div class="row justify-content-center mb-4">
<div class="col-12">
<div class="main-header card-custom rounded-4 p-4 text-center">
<h1 class="display-4 fw-bold mb-3 text-white">🤖 SERVIÇO DE ANÁLISE BERT</h1>
<h2 class="h4 mb-3 text-white">📈 BotCS - Análise de Indicadores com IA FinBERT</h2>
<p class="lead mb-2 text-white"><strong>Serviço especializado em análise de indicadores técnicos com IA</strong></p>
<p class="mb-0 text-white"><em>🎯 RSI • 📊 EMA • 📉 Bollinger Bands • 📈 Volume • ⚡ Momentum • 🤖 FinBERT AI</em></p>
</div>
</div>
</div>
</div>
""")
# Layout principal responsivo
with gr.Row():
# Coluna esquerda - Input
with gr.Column(scale=1):
gr.HTML("""
<div class="card card-custom rounded-3 mb-3">
<div class="card-header bg-transparent border-0">
<h3 class="h5 fw-bold mb-0" style="color: #ffffff !important;">📊 INDICADORES TÉCNICOS</h3>
</div>
</div>
""")
input_text = gr.Textbox(
label="Insira os indicadores técnicos para análise...",
placeholder="Exemplo: P:115510.61(+0.05%) | EMA:ALTA | RSI:28 | BB:ABAIXO | Vol:1.2",
lines=4,
elem_classes=["form-control"]
)
with gr.Row():
analyze_btn = gr.Button(
"🤖 ANALISAR COM BERT",
variant="primary",
elem_classes=["btn", "btn-primary", "btn-lg"]
)
get_sample_data_btn = gr.Button(
"📊 DADOS EXEMPLO",
variant="secondary",
elem_classes=["btn", "btn-info"]
)
clear_btn = gr.Button(
"🗑️ LIMPAR",
variant="secondary",
elem_classes=["btn", "btn-secondary"]
)
# Botões de exemplo responsivos
gr.HTML("""
<div class="row g-2 mt-2">
<div class="col-12 col-md-4">
<button class="btn btn-outline-success btn-sm w-100" id="example-buy">📈 Exemplo COMPRA</button>
</div>
<div class="col-12 col-md-4">
<button class="btn btn-outline-danger btn-sm w-100" id="example-sell">📉 Exemplo VENDA</button>
</div>
<div class="col-12 col-md-4">
<button class="btn btn-outline-warning btn-sm w-100" id="example-neutral">⏸️ Exemplo NEUTRO</button>
</div>
</div>
""")
example1_btn = gr.Button("📈 Exemplo COMPRA", visible=False)
example2_btn = gr.Button("📉 Exemplo VENDA", visible=False)
example3_btn = gr.Button("⏸️ Exemplo NEUTRO", visible=False)
# Coluna direita - Output
with gr.Column(scale=1):
gr.HTML("""
<div class="card card-custom rounded-3 mb-3">
<div class="card-header bg-transparent border-0">
<h3 class="h5 fw-bold mb-0" style="color: #ffffff !important;">🤖 ANÁLISE BERT - AGUARDANDO INDICADORES</h3>
</div>
</div>
""")
# Seção de instruções destacada
gr.HTML("""
<div class="alert alert-info border-0 shadow-lg mb-3" style="background: linear-gradient(135deg, rgba(0, 212, 255, 0.15), rgba(255, 107, 107, 0.15)); border: 2px solid rgba(0, 212, 255, 0.3); backdrop-filter: blur(10px);">
<div class="text-center mb-3">
<h4 class="fw-bold mb-2" style="color: #ffffff !important;">📋 COMO USAR O SERVIÇO DE ANÁLISE BERT</h4>
</div>
<div class="row">
<div class="col-12">
<p class="lead text-light mb-3 text-center" style="color: #ffffff !important;">
<strong style="color: #ffffff !important;">Insira os indicadores técnicos para análise com IA FinBERT + Sistema Robusto:</strong>
</p>
</div>
</div>
<div class="row g-2">
<div class="col-12 col-md-6">
<div class="d-flex align-items-center mb-2">
<span class="badge bg-success me-2">✅</span>
<span class="text-light" style="color: #ffffff !important;"><strong style="color: #ffffff !important;">Sinal de entrada</strong> (COMPRAR/VENDER/AGUARDAR)</span>
</div>
<div class="d-flex align-items-center mb-2">
<span class="badge bg-success me-2">✅</span>
<span class="text-light" style="color: #ffffff !important;"><strong style="color: #ffffff !important;">Nível de confiança</strong> baseado em múltiplos indicadores</span>
</div>
<div class="d-flex align-items-center mb-2">
<span class="badge bg-success me-2">✅</span>
<span class="text-light" style="color: #ffffff !important;"><strong style="color: #ffffff !important;">Stop Loss e Take Profit</strong> calculados automaticamente</span>
</div>
</div>
<div class="col-12 col-md-6">
<div class="d-flex align-items-center mb-2">
<span class="badge bg-success me-2">✅</span>
<span class="text-light" style="color: #ffffff !important;"><strong style="color: #ffffff !important;">Análise de sentimento FinBERT</strong> + Sistema Robusto de fallback</span>
</div>
<div class="d-flex align-items-center mb-2">
<span class="badge bg-success me-2">✅</span>
<span class="text-light" style="color: #ffffff !important;"><strong style="color: #ffffff !important;">Recomendações específicas</strong> para scalping M1/M5</span>
</div>
</div>
</div>
<hr class="my-3" style="border-color: rgba(0, 212, 255, 0.3);">
<div class="text-center">
<p class="mb-0 text-light" style="color: #ffffff !important;">
<strong style="color: #ffffff !important;">📊 Indicadores analisados:</strong>
<span class="badge bg-primary me-1">RSI</span>
<span class="badge bg-primary me-1">EMA</span>
<span class="badge bg-primary me-1">Bollinger Bands</span>
<span class="badge bg-primary me-1">Volume</span>
<span class="badge bg-primary me-1">Momentum</span>
<span class="badge bg-success">🤖 FinBERT AI</span>
<span class="badge bg-warning">🔧 Sistema Robusto</span>
</p>
</div>
</div>
""")
output_text = gr.Markdown(
value="""<div style="color: #ffffff !important;"><strong style="color: #ffffff !important;">🤖 SERVIÇO DE ANÁLISE BERT - AGUARDANDO INDICADORES</strong></div>
<div style="color: #ffffff !important;">⏳ Aguardando indicadores técnicos para análise...</div>
<div style="color: #ffffff !important;">🎯 <strong style="color: #ffffff !important;">Sistema BERT pronto para análise de indicadores!</strong></div>""",
elem_classes=["output-area", "p-3", "rounded-3"]
)
# JavaScript para conectar botões Bootstrap aos botões Gradio ocultos
gr.HTML("""
<script>
document.addEventListener('DOMContentLoaded', function() {
// Conectar botões de exemplo Bootstrap aos botões Gradio ocultos
const exampleBuy = document.getElementById('example-buy');
const exampleSell = document.getElementById('example-sell');
const exampleNeutral = document.getElementById('example-neutral');
if (exampleBuy) {
exampleBuy.addEventListener('click', function() {
// Encontrar o botão de exemplo COMPRA oculto
const gradioButtons = document.querySelectorAll('button');
for (let btn of gradioButtons) {
if (btn.textContent.includes('📈 Exemplo COMPRA') && btn.style.display === 'none') {
btn.click();
break;
}
}
});
}
if (exampleSell) {
exampleSell.addEventListener('click', function() {
// Encontrar o botão de exemplo VENDA oculto
const gradioButtons = document.querySelectorAll('button');
for (let btn of gradioButtons) {
if (btn.textContent.includes('📉 Exemplo VENDA') && btn.style.display === 'none') {
btn.click();
break;
}
}
});
}
if (exampleNeutral) {
exampleNeutral.addEventListener('click', function() {
// Encontrar o botão de exemplo NEUTRO oculto
const gradioButtons = document.querySelectorAll('button');
for (let btn of gradioButtons) {
if (btn.textContent.includes('⏸️ Exemplo NEUTRO') && btn.style.display === 'none') {
btn.click();
break;
}
}
});
}
// Adicionar classes Bootstrap aos elementos Gradio
const textareas = document.querySelectorAll('textarea');
textareas.forEach(textarea => {
textarea.classList.add('form-control');
});
const buttons = document.querySelectorAll('button');
buttons.forEach(button => {
if (!button.classList.contains('btn')) {
button.classList.add('btn');
}
});
// Responsividade adicional
function handleResize() {
const container = document.querySelector('.gradio-container');
if (window.innerWidth < 768) {
container?.classList.add('mobile-view');
} else {
container?.classList.remove('mobile-view');
}
}
window.addEventListener('resize', handleResize);
handleResize();
});
</script>
""")
# Event handlers
analyze_btn.click(
fn=process_trading_analysis,
inputs=input_text,
outputs=output_text
)
get_sample_data_btn.click(
fn=get_sample_data_for_ui,
outputs=input_text
)
clear_btn.click(
lambda: ("", """**🤖 SERVIÇO DE ANÁLISE BERT - BotCS**
✅ **Análise técnica completa** com IA FinBERT
✅ **Indicadores técnicos** analisados
✅ **Sinais de trading** gerados
✅ **Recomendações específicas** para scalping
✅ **Análise de sentimento** com IA
✅ **Serviço online** no Hugging Face Spaces
**Indicadores analisados:** RSI, EMA, Bollinger Bands, Volume, Momentum"""),
outputs=[input_text, output_text]
)
# Exemplos (botões ocultos conectados via JavaScript)
example1_btn.click(
lambda: "Análise BTCUSD M1 | P:115510.61(+0.05%) | EMA:ALTA(115520.00/115500.00) | RSI:28 | BB:ABAIXO | Vol:1.2",
outputs=input_text
)
example2_btn.click(
lambda: "Análise BTCUSD M5 | P:115580.00(-0.03%) | EMA:BAIXA(115520.00/115560.00) | RSI:78 | BB:ACIMA | Vol:1.5",
outputs=input_text
)
example3_btn.click(
lambda: "Análise BTCUSD M1 | P:115550.00(+0.01%) | EMA:ALTA(115540.00/115530.00) | RSI:52 | BB:DENTRO | Vol:0.6",
outputs=input_text
)
# Status do sistema
gr.HTML("""
<div class="row g-3 mb-3">
<div class="col-12 col-md-6">
<div class="card card-custom rounded-3">
<div class="card-body text-center">
<h5 class="card-title text-white">🤖 IA FinBERT</h5>
<p class="card-text text-white">""" + ("✅ Ativa" if TRANSFORMERS_AVAILABLE and current_model_info else "❌ Indisponível") + """</p>
</div>
</div>
</div>
<div class="col-12 col-md-6">
<div class="card card-custom rounded-3">
<div class="card-body text-center">
<h5 class="card-title text-white">📊 Análise Técnica</h5>
<p class="card-text text-white">✅ Disponível</p>
</div>
</div>
</div>
</div>
""")
# Mostrar modelo de IA ativo
if TRANSFORMERS_AVAILABLE and current_model_info:
gr.HTML(f"""
<div class="alert alert-success border-0 shadow-lg mb-3" style="background: linear-gradient(135deg, rgba(0, 255, 136, 0.15), rgba(78, 205, 196, 0.15)); border: 2px solid rgba(0, 255, 136, 0.3); backdrop-filter: blur(10px);">
<div class="text-center">
<h4 class="fw-bold mb-2" style="color: #ffffff !important;">🤖 IA ATIVA: {current_model_info['description']}</h4>
<p class="mb-0" style="color: #ffffff !important;">Análise de sentimento financeiro com modelo especializado</p>
</div>
</div>
""")
else:
gr.HTML("""
<div class="alert alert-warning border-0 shadow-lg mb-3" style="background: linear-gradient(135deg, rgba(255, 165, 2, 0.15), rgba(255, 107, 107, 0.15)); border: 2px solid rgba(255, 165, 2, 0.3); backdrop-filter: blur(10px);">
<div class="text-center">
<h4 class="fw-bold mb-2" style="color: #ffffff !important;">⚠️ IA INDISPONÍVEL</h4>
<p class="mb-0" style="color: #ffffff !important;">Executando apenas análise técnica tradicional</p>
</div>
</div>
""")
# Footer com estratégias
footer_ai_info = ""
if TRANSFORMERS_AVAILABLE and current_model_info:
footer_ai_info = f"🤖 {current_model_info['description']}"
else:
footer_ai_info = "🤖 IA Indisponível"
gr.HTML(f"""
<div style="margin-top: 30px; padding: 35px; background: rgba(30, 30, 40, 0.98); color: #f8f9fa; border-radius: 25px; box-shadow: 0 30px 60px rgba(0, 0, 0, 0.6), 0 0 30px rgba(0, 212, 255, 0.1); border: 2px solid rgba(0, 212, 255, 0.3); backdrop-filter: blur(20px);">
<h3 style="text-align: center; color: #f0f0f0; font-size: 2.2rem; margin-bottom: 30px; font-family: 'Poppins', sans-serif; font-weight: 700; text-shadow: 0 2px 6px rgba(0, 212, 255, 0.3); letter-spacing: 1px;">
🎯 ESTRATÉGIA DE SCALPING AVANÇADA
</h3>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 25px;">
<div style="background: rgba(0, 0, 0, 0.6); padding: 30px; border-radius: 20px; border: 2px solid rgba(0, 212, 255, 0.2); box-shadow: 0 0 20px rgba(0, 212, 255, 0.1); backdrop-filter: blur(10px);">
<h4 style="color: #f0f0f0; margin-bottom: 20px; font-family: 'Poppins', sans-serif; font-weight: 600; font-size: 1.3rem; text-shadow: 0 1px 4px rgba(0, 255, 136, 0.25);">📈 SINAIS DE COMPRA:</h4>
<ul style="list-style: none; padding: 0;">
<li style="padding: 10px 0; color: #c8c8c8; font-weight: 500; letter-spacing: 0.3px;">▶ RSI ≤ 30 (Sobrevenda)</li>
<li style="padding: 10px 0; color: #c8c8c8; font-weight: 500; letter-spacing: 0.3px;">▶ Preço abaixo da Banda Inferior</li>
<li style="padding: 10px 0; color: #c8c8c8; font-weight: 500; letter-spacing: 0.3px;">▶ EMA em tendência de alta</li>
<li style="padding: 10px 0; color: #c8c8c8; font-weight: 500; letter-spacing: 0.3px;">▶ Volume acima da média</li>
</ul>
</div>
<div style="background: rgba(0, 0, 0, 0.6); padding: 30px; border-radius: 20px; border: 2px solid rgba(0, 212, 255, 0.2); box-shadow: 0 0 20px rgba(0, 212, 255, 0.1); backdrop-filter: blur(10px);">
<h4 style="color: #f0f0f0; margin-bottom: 20px; font-family: 'Poppins', sans-serif; font-weight: 600; font-size: 1.3rem; text-shadow: 0 1px 4px rgba(255, 71, 87, 0.25);">📉 SINAIS DE VENDA:</h4>
<ul style="list-style: none; padding: 0;">
<li style="padding: 10px 0; color: #c8c8c8; font-weight: 500; letter-spacing: 0.3px;">▶ RSI ≥ 70 (Sobrecompra)</li>
<li style="padding: 10px 0; color: #c8c8c8; font-weight: 500; letter-spacing: 0.3px;">▶ Preço acima da Banda Superior</li>
<li style="padding: 10px 0; color: #c8c8c8; font-weight: 500; letter-spacing: 0.3px;">▶ EMA em tendência de baixa</li>
<li style="padding: 10px 0; color: #c8c8c8; font-weight: 500; letter-spacing: 0.3px;">▶ Volume confirmando movimento</li>
</ul>
</div>
<div style="background: rgba(0, 0, 0, 0.6); padding: 30px; border-radius: 20px; border: 2px solid rgba(0, 212, 255, 0.2); box-shadow: 0 0 20px rgba(0, 212, 255, 0.1); backdrop-filter: blur(10px);">
<h4 style="color: #f0f0f0; margin-bottom: 20px; font-family: 'Poppins', sans-serif; font-weight: 600; font-size: 1.3rem; text-shadow: 0 1px 4px rgba(255, 165, 2, 0.25);">⚙️ CONFIGURAÇÕES:</h4>
<ul style="list-style: none; padding: 0;">
<li style="padding: 10px 0; color: #c8c8c8; font-weight: 500; letter-spacing: 0.3px;">▶ Timeframes: M1 e M5</li>
<li style="padding: 10px 0; color: #c8c8c8; font-weight: 500; letter-spacing: 0.3px;">▶ Stop Loss: 0.07% do preço (BTCUSD)</li>
<li style="padding: 10px 0; color: #c8c8c8; font-weight: 500; letter-spacing: 0.3px;">▶ Take Profit: 0.15% do preço (BTCUSD)</li>
<li style="padding: 10px 0; color: #c8c8c8; font-weight: 500; letter-spacing: 0.3px;">▶ Risk/Reward: 1:2</li>
</ul>
</div>
</div>
<div style="text-align: center; margin-top: 40px; padding-top: 25px; border-top: 2px solid rgba(0, 212, 255, 0.3); box-shadow: 0 -5px 15px rgba(0, 212, 255, 0.1);">
<p style="color: #ffffff; font-size: 1.1rem; font-weight: 500; letter-spacing: 0.3px;">🤖 <strong style="color: #ffffff !important;">Serviço de Análise BERT BotCS</strong> - IA FinBERT + Análise Técnica + Hugging Face Spaces</p>
<p style="color: #ffffff; font-size: 1rem; margin-top: 10px; font-weight: 500; letter-spacing: 0.3px;">🧠 <strong style="color: #ffffff !important;">Modelo Ativo:</strong> {footer_ai_info}</p>
<p style="color: #ffffff; font-size: 1rem; margin-top: 15px; font-weight: 500; text-shadow: 0 1px 3px rgba(0, 212, 255, 0.2);">⚠️ <em style="color: #ffffff !important;">Trading envolve riscos. Use sempre gerenciamento de risco adequado.</em></p>
</div>
</div>
""")
if __name__ == "__main__":
# App rodado no Hugging Face Spaces - sem dashboard local
print("🚀 Iniciando Serviço de Análise BERT no Hugging Face Spaces")
demo.launch()