utilise yahoo finance pour récuper les data dans ce scripte et utilise des raccourcis pour calculer les différents ratios avec les données récupérées : 

import tkinter as tk
from tkinter import ttk, messagebox
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import requests
from bs4 import BeautifulSoup
import threading
import queue

# Liste des facteurs
FACTORS_LIST = [
    "Réglementation",
    "Adoption Institutionnelle",
    "Sentiment du Marché",
    "Conditions Économiques",
    "Évolution Technologique",
    "Offre et Demande",
    "Concurrence",
    "Intégration Financière",
    "Facteurs Géopolitiques",
    "Événements Spéciaux"
]

# Définir les poids pour chaque facteur
WEIGHTS = {
    "Réglementation": 1.0,
    "Adoption Institutionnelle": 1.0,
    "Sentiment du Marché": 1.5,
    "Conditions Économiques": 1.0,
    "Évolution Technologique": 1.0,
    "Offre et Demande": 2.0,
    "Concurrence": 0.8,
    "Intégration Financière": 0.8,
    "Facteurs Géopolitiques": 0.5,
    "Événements Spéciaux": 0.7
}

# Base price for normalization
BASE_PRICE = 50000

# Create a Queue for thread-safe communication
result_queue = queue.Queue()

def get_evolution_technologique():
    """
    Retrieves the technological evolution score by analyzing the latest headlines from Hacker News.

    Returns:
        float: Normalized score based on the presence of 'bitcoin' or 'blockchain' keywords.
    """
    try:
        url_tech_news = "https://news.ycombinator.com/"
        response = requests.get(url_tech_news, headers={'User-Agent': 'Mozilla/5.0'})
        soup = BeautifulSoup(response.text, 'html.parser')

        # Updated selector for Hacker News titles
        # Attempt 'titlelink' first, fallback to 'storylink' if necessary
        headlines = soup.find_all('a', class_='titlelink', limit=10)
        if not headlines:
            headlines = soup.find_all('a', class_='storylink', limit=10)  # Fallback

        tech_related = 0
        for headline in headlines:
            text = headline.get_text().lower()
            if "bitcoin" in text or "blockchain" in text:
                tech_related += 1
        tech_score = tech_related / 10  # Normalisation
        return tech_score
    except Exception as e:
        print(f"Erreur lors de la récupération de l'évolution technologique: {e}")
        # Instead of showing a message box here, enqueue the error message
        return 0.0

def get_reglementation():
    """
    Retrieves the regulation score by analyzing the latest articles from Reuters Business Finance.

    Returns:
        float: Normalized score based on positive and negative keywords in article titles.
    """
    try:
        url_regulation_news = "https://www.reuters.com/business/finance/"
        response = requests.get(url_regulation_news, headers={'User-Agent': 'Mozilla/5.0'})
        soup = BeautifulSoup(response.text, 'html.parser')

        # Updated selector based on Reuters' actual website structure
        # Attempt a known class, fallback if necessary
        articles = soup.find_all('h3', class_='story-title', limit=10)
        if not articles:
            articles = soup.find_all('h3', limit=10)  # Fallback

        positive = negative = 0
        for article in articles:
            text = article.get_text().lower()
            if any(word in text for word in ['approved', 'support', 'friendly', 'positive', 'growth', 'regulation']):
                positive += 1
            elif any(word in text for word in ['ban', 'restrict', 'negative', 'crackdown', 'regulation']):
                negative += 1
        reglementation_score = (positive - negative) / 10  # Normalisation
        return reglementation_score
    except Exception as e:
        print(f"Erreur lors de la récupération de la réglementation: {e}")
        return 0.0

def get_sentiment_du_marche():
    """
    Retrieves the market sentiment score by analyzing the latest news headlines related to Bitcoin.

    Returns:
        float: Normalized sentiment score based on positive and negative keywords in headlines.
    """
    try:
        url_news = "https://finance.yahoo.com/quote/BTC-USD/news"
        response_news = requests.get(url_news, headers={'User-Agent': 'Mozilla/5.0'})
        soup_news = BeautifulSoup(response_news.text, 'html.parser')

        headlines = soup_news.find_all('h3', limit=10)
        positive = negative = 0
        for headline in headlines:
            text = headline.get_text().lower()
            if any(word in text for word in ['up', 'gain', 'positive', 'bull', 'surge', 'increase']):
                positive += 1
            elif any(word in text for word in ['down', 'drop', 'negative', 'bear', 'decline', 'fall']):
                negative += 1
        sentiment_score = (positive - negative) / 10  # Normalisation
        return sentiment_score
    except Exception as e:
        print(f"Erreur lors de la récupération du sentiment du marché: {e}")
        return 0.0

def get_offre_et_demande():
    """
    Retrieves the supply and demand score based on the current Bitcoin price.

    Returns:
        float: Normalized score based on current price relative to the base price.
    """
    try:
        url_price = "https://finance.yahoo.com/quote/BTC-USD/"
        response_price = requests.get(url_price, headers={'User-Agent': 'Mozilla/5.0'})
        soup_price = BeautifulSoup(response_price.text, 'html.parser')

        price_tag = soup_price.find('fin-streamer', {'data-field': 'regularMarketPrice'})
        if price_tag:
            current_price_str = price_tag.text.replace(',', '').strip()
            # Handle cases where the price might not be directly convertible to float
            try:
                current_price = float(current_price_str)
            except ValueError:
                current_price = 0.0
            offre_et_demande_score = (current_price / BASE_PRICE) - 1  # Normalized score
            return offre_et_demande_score
        else:
            return 0.0
    except Exception as e:
        print(f"Erreur lors de la récupération du prix: {e}")
        return 0.0

def evaluate_factors():
    """
    Evaluates all factors by retrieving their respective scores.

    Returns:
        dict: A dictionary containing factor names and their corresponding scores.
    """
    factors = {}

    # 1. Récupérer le prix actuel du Bitcoin
    factors['Offre et Demande'] = get_offre_et_demande()

    # 2. Récupérer le sentiment du marché via les dernières actualités
    factors['Sentiment du Marché'] = get_sentiment_du_marche()

    # 3. Récupérer l'évolution technologique
    factors['Évolution Technologique'] = get_evolution_technologique()

    # 4. Récupérer la réglementation
    factors['Réglementation'] = get_reglementation()

    # 5. Ajouter des données pour les autres facteurs (set to 0.0 if not implemented)
    for factor in FACTORS_LIST:
        if factor not in factors:
            factors[factor] = 0.0  # Neutre pour l'instant

    return factors

def calculate_index(factors):
    """
    Calculates the overall index based on factor scores and their weights.

    Args:
        factors (dict): Dictionary of factor scores.

    Returns:
        float: The calculated index.
    """
    total_score = 0
    for factor, score in factors.items():
        total_score += score * WEIGHTS.get(factor, 1)
    return total_score

def plot_factors(factors):
    """
    Plots a horizontal bar chart of the factor scores.

    Args:
        factors (dict): Dictionary of factor scores.
    """
    # Effacer le graphique précédent
    for widget in frame_plot.winfo_children():
        widget.destroy()

    factor_names = list(factors.keys())
    scores = list(factors.values())

    fig, ax = plt.subplots(figsize=(6, 4))
    colors = ['green' if x >= 0 else 'red' for x in scores]
    bars = ax.barh(factor_names, scores, color=colors)
    ax.axvline(0, color='black')
    ax.set_xlabel('Score')
    ax.set_title('Évaluation des Facteurs')

    # Ajouter les valeurs sur les barres
    for bar in bars:
        width = bar.get_width()
        label_x = width + (0.02 if width >= 0 else -0.02)
        alignment = 'left' if width >= 0 else 'right'
        ax.text(label_x, 
                bar.get_y() + bar.get_height() / 2, 
                f"{width:.2f}", 
                va='center',
                ha=alignment,
                fontsize=8,
                color='black')

    plt.tight_layout()
    canvas = FigureCanvasTkAgg(fig, master=frame_plot)
    canvas.draw()
    canvas.get_tk_widget().pack()

def update_results():
    """
    Fetches factor scores, calculates the index, and enqueues the results for GUI updating.
    """
    try:
        factors = evaluate_factors()
        index = calculate_index(factors)
        # Enqueue the results for the main thread to process
        result_queue.put((factors, index))
    except Exception as e:
        print(f"Erreur lors de la mise à jour des résultats: {e}")
        result_queue.put(("error", str(e)))

def process_queue():
    """
    Processes items in the result_queue and updates the GUI accordingly.
    This function is scheduled to run periodically using Tkinter's after method.
    """
    try:
        while not result_queue.empty():
            result = result_queue.get_nowait()
            if result[0] == "error":
                # Handle error
                messagebox.showerror("Erreur", f"Une erreur est survenue lors de la mise à jour des résultats: {result[1]}")
                label_result.config(text="Indice Prévisionnel : Erreur", fg="red")
            else:
                factors, index = result
                # Afficher les scores des facteurs
                for factor, score in factors.items():
                    tree.set(factor, "Score", f"{score:.2f}")

                # Afficher l'indice
                if index > 0:
                    trend = "Hausse prévue 📈"
                    color = "green"
                elif index < 0:
                    trend = "Baisse prévue 📉"
                    color = "red"
                else:
                    trend = "Stable ➖"
                    color = "gray"

                label_result.config(text=f"Indice Prévisionnel : {trend} (Score: {index:.2f})", fg=color)

                # Afficher un graphique simple
                plot_factors(factors)
    except Exception as e:
        print(f"Erreur lors du traitement de la file d'attente: {e}")
    finally:
        # Schedule the next queue check
        root.after(100, process_queue)

def update_results_threaded():
    """
    Starts the update_results function in a separate thread to keep the GUI responsive.
    """
    thread = threading.Thread(target=update_results)
    thread.start()

# Configuration de la fenêtre principale
root = tk.Tk()
root.title("Analyse du Prix du Bitcoin")

# Configuration de la disposition
root.geometry("800x700")
root.resizable(False, False)

# Titre
title = ttk.Label(root, text="Prédicteur de Tendance Bitcoin", font=("Helvetica", 16))
title.pack(pady=10)

# Tableau des facteurs
columns = ("Facteur", "Score")
tree = ttk.Treeview(root, columns=columns, show='headings', height=10)
tree.heading("Facteur", text="Facteur")
tree.heading("Score", text="Score")
tree.column("Facteur", width=200, anchor='center')
tree.column("Score", width=100, anchor='center')

# Insertion des facteurs avec `iid` correspondant au nom du facteur
for factor in FACTORS_LIST:
    tree.insert('', tk.END, iid=factor, values=(factor, "0.00"))

tree.pack(pady=10)

# Résultat de l'indice (utilisation de tkinter.Label)
label_result = tk.Label(root, text="Indice Prévisionnel : ", font=("Helvetica", 14))
label_result.pack(pady=10)

# Bouton de mise à jour
button_update = ttk.Button(root, text="Évaluer", command=update_results_threaded)
button_update.pack(pady=10)

# Frame pour le graphique
frame_plot = ttk.Frame(root)
frame_plot.pack(pady=10, fill='both', expand=True)

# Initial call to process_queue to start the periodic checking
root.after(100, process_queue)

# Exécution de la boucle principale
root.mainloop()