diff --git a/demos/agno_agent.py b/demos/agno_agent.py index 35acf59..02ebc75 100644 --- a/demos/agno_agent.py +++ b/demos/agno_agent.py @@ -8,9 +8,7 @@ try: reasoning_agent = Agent( model=Gemini(), - tools=[ - ReasoningTools(), - ], + tools=[ReasoningTools()], instructions="Use tables to display data.", markdown=True, ) diff --git a/demos/api_market_providers.py b/demos/api_market_providers.py new file mode 100644 index 0000000..a9ba754 --- /dev/null +++ b/demos/api_market_providers.py @@ -0,0 +1,12 @@ +from dotenv import load_dotenv +from app.api.tools import MarketAPIsTool + +def main(): + api = MarketAPIsTool() + prices_aggregated = api.get_historical_prices_aggregated("BTC", limit=5) + for price in prices_aggregated: + print(f"== [{price.timestamp}] {price.low:.2f} - {price.high:.2f} ==") + +if __name__ == "__main__": + load_dotenv() + main() diff --git a/demos/api_news_providers.py b/demos/api_news_providers.py new file mode 100644 index 0000000..4ac2f01 --- /dev/null +++ b/demos/api_news_providers.py @@ -0,0 +1,16 @@ +from dotenv import load_dotenv +from app.api.tools import NewsAPIsTool + +def main(): + api = NewsAPIsTool() + articles_aggregated = api.get_latest_news_aggregated(query="bitcoin", limit=2) + for provider, articles in articles_aggregated.items(): + print("===================================") + print(f"Provider: {provider}") + for article in articles: + print(f"== [{article.time}] {article.title} ==") + print(f" {article.description}") + +if __name__ == "__main__": + load_dotenv() + main() diff --git a/demos/api_socials_providers.py b/demos/api_socials_providers.py new file mode 100644 index 0000000..fb9da6e --- /dev/null +++ b/demos/api_socials_providers.py @@ -0,0 +1,17 @@ +from dotenv import load_dotenv +from app.api.tools import SocialAPIsTool + +def main(): + api = SocialAPIsTool() + articles_aggregated = api.get_top_crypto_posts_aggregated(limit_per_wrapper=2) + for provider, posts in articles_aggregated.items(): + print("===================================") + print(f"Provider: {provider}") + for post in posts: + print(f"== [{post.time}] - {post.title} ==") + print(f" {post.description}") + print(f" {len(post.comments)}") + +if __name__ == "__main__": + load_dotenv() + main() diff --git a/demos/market_providers_api_demo.py b/demos/market_providers_api_demo.py deleted file mode 100644 index a958532..0000000 --- a/demos/market_providers_api_demo.py +++ /dev/null @@ -1,353 +0,0 @@ -#!/usr/bin/env python3 -""" -Demo Completo per Market Data Providers -======================================== - -Questo script dimostra l'utilizzo di tutti i wrapper che implementano BaseWrapper: -- CoinBaseWrapper (richiede credenziali) -- CryptoCompareWrapper (richiede API key) -- BinanceWrapper (richiede credenziali) -- PublicBinanceAgent (accesso pubblico) -- YFinanceWrapper (accesso gratuito a dati azionari e crypto) - -Lo script effettua chiamate GET a diversi provider e visualizza i dati -in modo strutturato con informazioni dettagliate su timestamp, stato -delle richieste e formattazione tabellare. -""" - -import sys -import os -from pathlib import Path -from datetime import datetime -from typing import Dict, List, Optional, Any -import traceback - -# Aggiungi il path src al PYTHONPATH -project_root = Path(__file__).parent.parent -sys.path.insert(0, str(project_root / "src")) - -from dotenv import load_dotenv -from app.api.markets import ( - CoinBaseWrapper, - CryptoCompareWrapper, - BinanceWrapper, - YFinanceWrapper, - MarketWrapper -) - -# Carica variabili d'ambiente -load_dotenv() - -class DemoFormatter: - """Classe per formattare l'output del demo in modo strutturato.""" - - @staticmethod - def print_header(title: str, char: str = "=", width: int = 80): - """Stampa un'intestazione formattata.""" - print(f"\n{char * width}") - print(f"{title:^{width}}") - print(f"{char * width}") - - @staticmethod - def print_subheader(title: str, char: str = "-", width: int = 60): - """Stampa una sotto-intestazione formattata.""" - print(f"\n{char * width}") - print(f" {title}") - print(f"{char * width}") - - @staticmethod - def print_request_info(provider_name: str, method: str, timestamp: datetime, - status: str, error: Optional[str] = None): - """Stampa informazioni sulla richiesta.""" - print(f"๐Ÿ•’ Timestamp: {timestamp.strftime('%Y-%m-%d %H:%M:%S')}") - print(f"๐Ÿท๏ธ Provider: {provider_name}") - print(f"๐Ÿ”ง Method: {method}") - print(f"๐Ÿ“Š Status: {status}") - if error: - print(f"โŒ Error: {error}") - print() - - @staticmethod - def print_product_table(products: List[Any], title: str = "Products"): - """Stampa una tabella di prodotti.""" - if not products: - print(f"๐Ÿ“‹ {title}: Nessun prodotto trovato") - return - - print(f"๐Ÿ“‹ {title} ({len(products)} items):") - print(f"{'Symbol':<15} {'ID':<20} {'Price':<12} {'Quote':<10} {'Status':<10}") - print("-" * 67) - - for product in products[:10]: # Mostra solo i primi 10 - symbol = getattr(product, 'symbol', 'N/A') - product_id = getattr(product, 'id', 'N/A') - price = getattr(product, 'price', 0.0) - quote = getattr(product, 'quote_currency', 'N/A') - status = getattr(product, 'status', 'N/A') - - # Tronca l'ID se troppo lungo - if len(product_id) > 18: - product_id = product_id[:15] + "..." - - price_str = f"${price:.2f}" if price > 0 else "N/A" - - print(f"{symbol:<15} {product_id:<20} {price_str:<12} {quote:<10} {status:<10}") - - if len(products) > 10: - print(f"... e altri {len(products) - 10} prodotti") - print() - - @staticmethod - def print_prices_table(prices: List[Any], title: str = "Historical Prices"): - """Stampa una tabella di prezzi storici.""" - if not prices: - print(f"๐Ÿ’ฐ {title}: Nessun prezzo trovato") - return - - print(f"๐Ÿ’ฐ {title} ({len(prices)} entries):") - print(f"{'Time':<12} {'Open':<12} {'High':<12} {'Low':<12} {'Close':<12} {'Volume':<15}") - print("-" * 75) - - for price in prices[:5]: # Mostra solo i primi 5 - time_str = getattr(price, 'time', 'N/A') - # Il time รจ giร  una stringa, non serve strftime - if len(time_str) > 10: - time_str = time_str[:10] # Tronca se troppo lungo - - open_price = f"${getattr(price, 'open', 0):.2f}" - high_price = f"${getattr(price, 'high', 0):.2f}" - low_price = f"${getattr(price, 'low', 0):.2f}" - close_price = f"${getattr(price, 'close', 0):.2f}" - volume = f"{getattr(price, 'volume', 0):,.0f}" - - print(f"{time_str:<12} {open_price:<12} {high_price:<12} {low_price:<12} {close_price:<12} {volume:<15}") - - if len(prices) > 5: - print(f"... e altri {len(prices) - 5} prezzi") - print() - -class ProviderTester: - """Classe per testare i provider di market data.""" - - def __init__(self): - self.formatter = DemoFormatter() - self.test_symbols = ["BTC", "ETH", "ADA"] - - def test_provider(self, wrapper: MarketWrapper, provider_name: str) -> Dict[str, Any]: - """Testa un provider specifico con tutti i metodi disponibili.""" - results: Dict[str, Any] = { - "provider_name": provider_name, - "tests": {}, - "overall_status": "SUCCESS" - } - - self.formatter.print_subheader(f"๐Ÿ” Testing {provider_name}") - - # Test get_product - for symbol in self.test_symbols: - timestamp = datetime.now() - try: - product = wrapper.get_product(symbol) - self.formatter.print_request_info( - provider_name, f"get_product({symbol})", timestamp, "โœ… SUCCESS" - ) - if product: - print(f"๐Ÿ“ฆ Product: {product.symbol} (ID: {product.id})") - print(f" Price: ${product.price:.2f}, Quote: {product.currency}") - print(f" Volume 24h: {product.volume_24h:,.2f}") - else: - print(f"๐Ÿ“ฆ Product: Nessun prodotto trovato per {symbol}") - - results["tests"][f"get_product_{symbol}"] = "SUCCESS" - - except Exception as e: - error_msg = str(e) - self.formatter.print_request_info( - provider_name, f"get_product({symbol})", timestamp, "โŒ ERROR", error_msg - ) - results["tests"][f"get_product_{symbol}"] = f"ERROR: {error_msg}" - results["overall_status"] = "PARTIAL" - - # Test get_products - timestamp = datetime.now() - try: - products = wrapper.get_products(self.test_symbols) - self.formatter.print_request_info( - provider_name, f"get_products({self.test_symbols})", timestamp, "โœ… SUCCESS" - ) - self.formatter.print_product_table(products, f"{provider_name} Products") - results["tests"]["get_products"] = "SUCCESS" - - except Exception as e: - error_msg = str(e) - self.formatter.print_request_info( - provider_name, f"get_products({self.test_symbols})", timestamp, "โŒ ERROR", error_msg - ) - results["tests"]["get_products"] = f"ERROR: {error_msg}" - results["overall_status"] = "PARTIAL" - - # Test get_historical_prices - timestamp = datetime.now() - try: - prices = wrapper.get_historical_prices("BTC") - self.formatter.print_request_info( - provider_name, "get_historical_prices(BTC)", timestamp, "โœ… SUCCESS" - ) - self.formatter.print_prices_table(prices, f"{provider_name} BTC Historical Prices") - results["tests"]["get_historical_prices"] = "SUCCESS" - - except Exception as e: - error_msg = str(e) - self.formatter.print_request_info( - provider_name, "get_historical_prices(BTC)", timestamp, "โŒ ERROR", error_msg - ) - results["tests"]["get_historical_prices"] = f"ERROR: {error_msg}" - results["overall_status"] = "PARTIAL" - - return results - -def check_environment_variables() -> Dict[str, bool]: - """Verifica la presenza delle variabili d'ambiente necessarie.""" - env_vars = { - "COINBASE_API_KEY": bool(os.getenv("COINBASE_API_KEY")), - "COINBASE_API_SECRET": bool(os.getenv("COINBASE_API_SECRET")), - "CRYPTOCOMPARE_API_KEY": bool(os.getenv("CRYPTOCOMPARE_API_KEY")), - "BINANCE_API_KEY": bool(os.getenv("BINANCE_API_KEY")), - "BINANCE_API_SECRET": bool(os.getenv("BINANCE_API_SECRET")), - } - return env_vars - -def initialize_providers() -> Dict[str, MarketWrapper]: - """Inizializza tutti i provider disponibili.""" - providers: Dict[str, MarketWrapper] = {} - env_vars = check_environment_variables() - - # CryptoCompareWrapper - if env_vars["CRYPTOCOMPARE_API_KEY"]: - try: - providers["CryptoCompare"] = CryptoCompareWrapper() - print("โœ… CryptoCompareWrapper inizializzato con successo") - except Exception as e: - print(f"โŒ Errore nell'inizializzazione di CryptoCompareWrapper: {e}") - else: - print("โš ๏ธ CryptoCompareWrapper saltato: CRYPTOCOMPARE_API_KEY non trovata") - - # CoinBaseWrapper - if env_vars["COINBASE_API_KEY"] and env_vars["COINBASE_API_SECRET"]: - try: - providers["CoinBase"] = CoinBaseWrapper() - print("โœ… CoinBaseWrapper inizializzato con successo") - except Exception as e: - print(f"โŒ Errore nell'inizializzazione di CoinBaseWrapper: {e}") - else: - print("โš ๏ธ CoinBaseWrapper saltato: credenziali Coinbase non complete") - - # BinanceWrapper - try: - providers["Binance"] = BinanceWrapper() - print("โœ… BinanceWrapper inizializzato con successo") - except Exception as e: - print(f"โŒ Errore nell'inizializzazione di BinanceWrapper: {e}") - - # YFinanceWrapper (sempre disponibile - dati azionari e crypto gratuiti) - try: - providers["YFinance"] = YFinanceWrapper() - print("โœ… YFinanceWrapper inizializzato con successo") - except Exception as e: - print(f"โŒ Errore nell'inizializzazione di YFinanceWrapper: {e}") - return providers - -def print_summary(results: List[Dict[str, Any]]): - """Stampa un riassunto finale dei risultati.""" - formatter = DemoFormatter() - formatter.print_header("๐Ÿ“Š RIASSUNTO FINALE", "=", 80) - - total_providers = len(results) - successful_providers = sum(1 for r in results if r["overall_status"] == "SUCCESS") - partial_providers = sum(1 for r in results if r["overall_status"] == "PARTIAL") - - print(f"๐Ÿ”ข Provider testati: {total_providers}") - print(f"โœ… Provider completamente funzionanti: {successful_providers}") - print(f"โš ๏ธ Provider parzialmente funzionanti: {partial_providers}") - print(f"โŒ Provider non funzionanti: {total_providers - successful_providers - partial_providers}") - - print("\n๐Ÿ“‹ Dettaglio per provider:") - for result in results: - provider_name = result["provider_name"] - status = result["overall_status"] - status_icon = "โœ…" if status == "SUCCESS" else "โš ๏ธ" if status == "PARTIAL" else "โŒ" - - print(f"\n{status_icon} {provider_name}:") - for test_name, test_result in result["tests"].items(): - test_icon = "โœ…" if test_result == "SUCCESS" else "โŒ" - print(f" {test_icon} {test_name}: {test_result}") - -def main(): - """Funzione principale del demo.""" - formatter = DemoFormatter() - - # Intestazione principale - formatter.print_header("๐Ÿš€ DEMO COMPLETO MARKET DATA PROVIDERS", "=", 80) - - print(f"๐Ÿ•’ Avvio demo: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") - print("๐Ÿ“ Questo demo testa tutti i wrapper BaseWrapper disponibili") - print("๐Ÿ” Ogni test include timestamp, stato della richiesta e dati formattati") - - # Verifica variabili d'ambiente - formatter.print_subheader("๐Ÿ” Verifica Configurazione") - env_vars = check_environment_variables() - - print("Variabili d'ambiente:") - for var_name, is_present in env_vars.items(): - status = "โœ… Presente" if is_present else "โŒ Mancante" - print(f" {var_name}: {status}") - - # Inizializza provider - formatter.print_subheader("๐Ÿ—๏ธ Inizializzazione Provider") - providers = initialize_providers() - - if not providers: - print("โŒ Nessun provider disponibile. Verifica la configurazione.") - return - - print(f"\n๐ŸŽฏ Provider disponibili per il test: {list(providers.keys())}") - - # Testa ogni provider - formatter.print_header("๐Ÿงช ESECUZIONE TEST PROVIDER", "=", 80) - - tester = ProviderTester() - all_results: List[Dict[str, Any]] = [] - - for provider_name, wrapper in providers.items(): - try: - result = tester.test_provider(wrapper, provider_name) - all_results.append(result) - except Exception as e: - print(f"โŒ Errore critico nel test di {provider_name}: {e}") - traceback.print_exc() - all_results.append({ - "provider_name": provider_name, - "tests": {}, - "overall_status": "CRITICAL_ERROR", - "error": str(e) - }) - - # Stampa riassunto finale - print_summary(all_results) - - # Informazioni aggiuntive - formatter.print_header("โ„น๏ธ INFORMAZIONI AGGIUNTIVE", "=", 80) - print("๐Ÿ“š Documentazione:") - print(" - BaseWrapper: src/app/markets/base.py") - print(" - Test completi: tests/agents/test_market.py") - print(" - Configurazione: .env") - - print("\n๐Ÿ”ง Per abilitare tutti i provider:") - print(" 1. Configura le credenziali nel file .env") - print(" 2. Segui la documentazione di ogni provider") - print(" 3. Riavvia il demo") - - print(f"\n๐Ÿ Demo completato: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/demos/news_api.py b/demos/news_api.py deleted file mode 100644 index ef71974..0000000 --- a/demos/news_api.py +++ /dev/null @@ -1,18 +0,0 @@ -#### FOR ALL FILES OUTSIDE src/ FOLDER #### -import sys -import os -sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../src'))) -########################################### - -from dotenv import load_dotenv -from app.api.news import NewsApiWrapper - -def main(): - api = NewsApiWrapper() - articles = api.get_latest_news(query="bitcoin", limit=5) - assert len(articles) > 0 - print("ok") - -if __name__ == "__main__": - load_dotenv() - main() \ No newline at end of file diff --git a/demos/ollama_demo.py b/demos/ollama_demo.py index 1e52f5f..8a327a6 100644 --- a/demos/ollama_demo.py +++ b/demos/ollama_demo.py @@ -1,20 +1,4 @@ -#!/usr/bin/env python3 -""" -Demo di Ollama (Python) โ€“ mostra: - 1. Elenco dei modelli disponibili - 2. Generazione di testo semplice - 3. Chat con streaming - 4. Calcolo di embeddings - 5. Esempio (opzionale) di function calling / tools - -Uso: - python ollama_demo.py - -Requisiti: - pip install ollama - Avviare il server Ollama (es. 'ollama serve' o l'app desktop) e avere i modelli giร  pullati. -""" - +from typing import Any import ollama # Configurazione modelli @@ -33,8 +17,8 @@ def list_models(): print(" (Nessun modello trovato)") return for m in models: - name = getattr(m, 'model', None) or (m.get('model') if isinstance(m, dict) else 'sconosciuto') - details = getattr(m, 'details', None) + name = getattr(m, 'model', None) or (m.get('model') if isinstance(m, dict) else 'sconosciuto') # type: ignore + details = getattr(m, 'details', None) # type: ignore fmt = getattr(details, 'format', None) if details else 'unknown' print(f" โ€ข {name} โ€“ {fmt}") except Exception as e: @@ -46,7 +30,7 @@ def list_models(): def generate_text(model: str, prompt: str, max_tokens: int = 200) -> str: """Genera testo dal modello indicato.""" print(f"\n[2] Generazione testo con '{model}'") - response = ollama.chat( + response = ollama.chat( # type: ignore model=model, messages=[{"role": "user", "content": prompt}] ) @@ -57,10 +41,10 @@ def generate_text(model: str, prompt: str, max_tokens: int = 200) -> str: # 3. Chat con streaming -------------------------------------------------------- -def chat_streaming(model: str, messages: list) -> str: +def chat_streaming(model: str, messages: list[dict[str, str]]) -> str: """Esegue una chat mostrando progressivamente la risposta.""" print(f"\n[3] Chat (streaming) con '{model}'") - stream = ollama.chat(model=model, messages=messages, stream=True) + stream = ollama.chat(model=model, messages=messages, stream=True) # type: ignore full = "" for chunk in stream: if 'message' in chunk and 'content' in chunk['message']: @@ -91,7 +75,7 @@ def get_embedding(model: str, text: str): def try_tools(model: str): """Esempio di function calling; se non supportato mostra messaggio informativo.""" print(f"\n[5] Function calling / tools con '{model}'") - tools = [ + tools: list[dict[str, Any]] = [ { "type": "function", "function": { @@ -109,7 +93,7 @@ def try_tools(model: str): } ] try: - response = ollama.chat( + response = ollama.chat( # type: ignore model=model, messages=[{"role": "user", "content": "Che tempo fa a Milano?"}], tools=tools diff --git a/docs/App_Architecture_Diagrams.md b/docs/App_Architecture_Diagrams.md index a498770..6eb4308 100644 --- a/docs/App_Architecture_Diagrams.md +++ b/docs/App_Architecture_Diagrams.md @@ -1,255 +1,160 @@ -# ๐Ÿ“Š Architettura e Flussi dell'App upo-appAI +# ๐Ÿ“Š Architettura upo-appAI -## ๐Ÿ—๏ธ Diagramma Architettura Generale +## ๐Ÿ—๏ธ Architettura Generale ``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ ๐ŸŒ GRADIO UI โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ User Input โ”‚ โ”‚ Provider โ”‚ โ”‚ Style โ”‚ โ”‚ -โ”‚ โ”‚ (Query) โ”‚ โ”‚ (Model) โ”‚ โ”‚ (Conservative/ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ Aggressive) โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โ”‚ - โ–ผ -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ ๐Ÿ”ง TOOL AGENT โ”‚ -โ”‚ (Central Orchestrator) โ”‚ -โ”‚ โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ 1. Collect Data โ”‚ โ”‚ 2. Analyze โ”‚ โ”‚ 3. Predict & โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ Sentiment โ”‚ โ”‚ Recommend โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โ”‚ - โ–ผ -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ ๐Ÿ“Š AGENT ECOSYSTEM โ”‚ -โ”‚ โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”โ”‚ -โ”‚ โ”‚ MARKET โ”‚ โ”‚ NEWS โ”‚ โ”‚ SOCIAL โ”‚ โ”‚ PREDICTOR โ”‚โ”‚ -โ”‚ โ”‚ AGENT โ”‚ โ”‚ AGENT โ”‚ โ”‚ AGENT โ”‚ โ”‚ AGENT โ”‚โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚โ”‚ -โ”‚ โ”‚ ๐Ÿ“ˆ Coinbase โ”‚ โ”‚ ๐Ÿ“ฐ News API โ”‚ โ”‚ ๐Ÿฆ Social โ”‚ โ”‚ ๐Ÿค– LLM โ”‚โ”‚ -โ”‚ โ”‚ ๐Ÿ“Š CryptoCmpโ”‚ โ”‚ โ”‚ โ”‚ Media โ”‚ โ”‚ Analysis โ”‚โ”‚ -โ”‚ โ”‚ ๐ŸŸก Binance โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +INTERFACCE UTENTE +โ”œโ”€โ”€ ๐Ÿ’ฌ Gradio Web (Chat + Dropdown modelli/strategie) +โ””โ”€โ”€ ๐Ÿ“ฑ Telegram Bot (Mini App) + โ”‚ + โ–ผ +CHAT MANAGER +โ”œโ”€โ”€ Storico messaggi +โ”œโ”€โ”€ Gestione PipelineInputs +โ””โ”€โ”€ Salva/Carica chat + โ”‚ + โ–ผ +AGNO WORKFLOW PIPELINE (4 Steps) +โ”œโ”€โ”€ 1. Query Check โ†’ Verifica crypto +โ”œโ”€โ”€ 2. Condition โ†’ Valida procedere +โ”œโ”€โ”€ 3. Info Recovery โ†’ Team raccolta dati +โ””โ”€โ”€ 4. Report Generation โ†’ Report finale + โ”‚ + โ–ผ +AGNO AGENT ECOSYSTEM +โ”œโ”€โ”€ ๐Ÿ‘” TEAM LEADER (coordina Market, News, Social) +โ”‚ Tools: ReasoningTools, PlanMemoryTool, CryptoSymbolsTools +โ”œโ”€โ”€ ๐Ÿ“ˆ MARKET AGENT โ†’ MarketAPIsTool +โ”œโ”€โ”€ ๐Ÿ“ฐ NEWS AGENT โ†’ NewsAPIsTool +โ”œโ”€โ”€ ๐Ÿฆ SOCIAL AGENT โ†’ SocialAPIsTool +โ”œโ”€โ”€ ๐Ÿ” QUERY CHECK AGENT โ†’ QueryOutputs (is_crypto: bool) +โ””โ”€โ”€ ๐Ÿ“‹ REPORT GENERATOR AGENT โ†’ Strategia applicata ``` -## ๐Ÿ”„ Flusso di Esecuzione Dettagliato +## ๐Ÿ”„ Flusso Esecuzione -``` -๐Ÿ‘ค USER REQUEST - โ”‚ - โ”‚ "Analizza Bitcoin con strategia aggressiva" - โ–ผ -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ ๐Ÿ”ง TOOL AGENT โ”‚ -โ”‚ โ”‚ -โ”‚ def interact(query, provider, style): โ”‚ -โ”‚ โ”‚ โ”‚ -โ”‚ โ”œโ”€โ”€ ๐Ÿ“Š market_data = market_agent.analyze(query) โ”‚ -โ”‚ โ”œโ”€โ”€ ๐Ÿ“ฐ news_sentiment = news_agent.analyze(query) โ”‚ -โ”‚ โ”œโ”€โ”€ ๐Ÿฆ social_sentiment = social_agent.analyze(query) โ”‚ -โ”‚ โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€ ๐Ÿค– prediction = predictor_agent.predict(...) โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โ”‚ - โ–ผ -๐Ÿ“Š MARKET AGENT - Parallel Data Collection -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ โ”‚ -โ”‚ ๐Ÿ” Auto-detect Available Providers: โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ Coinbase โ”‚ โ”‚ CryptoComp โ”‚ โ”‚ Binance โ”‚ โ”‚ -โ”‚ โ”‚ REST โ”‚ โ”‚ API โ”‚ โ”‚ Mock โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โœ… Active โ”‚ โ”‚ โœ… Active โ”‚ โ”‚ โœ… Active โ”‚ โ”‚ -โ”‚ โ”‚ $63,500 BTC โ”‚ โ”‚ $63,450 BTC โ”‚ โ”‚ $63,600 BTC โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ”‚ โ”‚ -โ”‚ ๐Ÿ“ˆ Aggregated Result: โ”‚ -โ”‚ { โ”‚ -โ”‚ "aggregated_data": { โ”‚ -โ”‚ "BTC_USD": { โ”‚ -โ”‚ "price": 63516.67, โ”‚ -โ”‚ "confidence": 0.94, โ”‚ -โ”‚ "sources_count": 3 โ”‚ -โ”‚ } โ”‚ -โ”‚ }, โ”‚ -โ”‚ "individual_sources": {...}, โ”‚ -โ”‚ "market_signals": {...} โ”‚ -โ”‚ } โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โ”‚ - โ–ผ -๐Ÿ“ฐ NEWS AGENT + ๐Ÿฆ SOCIAL AGENT -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ โ”‚ -โ”‚ ๐Ÿ“ฐ News Sentiment: "Positive momentum, institutional โ”‚ -โ”‚ adoption increasing..." โ”‚ -โ”‚ โ”‚ -โ”‚ ๐Ÿฆ Social Sentiment: "Bullish sentiment on Reddit, โ”‚ -โ”‚ Twitter mentions up 15%..." โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โ”‚ - โ–ผ -๐Ÿค– PREDICTOR AGENT -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ โ”‚ -โ”‚ Input: โ”‚ -โ”‚ โ”œโ”€โ”€ ๐Ÿ“Š Market Data (aggregated + confidence) โ”‚ -โ”‚ โ”œโ”€โ”€ ๐Ÿ“ฐ๐Ÿฆ Combined Sentiment โ”‚ -โ”‚ โ”œโ”€โ”€ ๐ŸŽฏ Style: "aggressive" โ”‚ -โ”‚ โ””โ”€โ”€ ๐Ÿค– Provider: "openai/anthropic/google..." โ”‚ -โ”‚ โ”‚ -โ”‚ ๐Ÿง  LLM Processing: โ”‚ -โ”‚ "Based on high confidence market data (0.94) showing โ”‚ -โ”‚ $63,516 BTC with positive sentiment across news and โ”‚ -โ”‚ social channels, aggressive strategy recommendation..." โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โ”‚ - โ–ผ -๐Ÿ“‹ FINAL OUTPUT -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ ๐Ÿ“Š Market Data Summary โ”‚ -โ”‚ ๐Ÿ“ฐ๐Ÿฆ Sentiment Analysis โ”‚ -โ”‚ ๐Ÿ“ˆ Final Recommendation: โ”‚ -โ”‚ "Strong BUY signal with 85% confidence..." โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +**Input:** "Analizza Bitcoin con strategia aggressiva" + +1. CHAT MANAGER riceve e prepara PipelineInputs +2. WORKFLOW PIPELINE esegue 4 step: + - Query Check: valida `is_crypto: true` + - Condition: se false, termina + - Info Recovery: Team raccoglie dati + - Report Generation: genera report +3. OUTPUT: Report con analisi + raccomandazioni + +## ๐Ÿ›๏ธ Architettura API + +**Tools (Agno Toolkit):** +- MarketAPIsTool: Binance, YFinance, CoinBase, CryptoCompare +- NewsAPIsTool: NewsAPI, GoogleNews, DuckDuckGo, CryptoPanic +- SocialAPIsTool: Reddit, X, 4chan +- CryptoSymbolsTools: `resources/cryptos.csv` + +**WrapperHandler:** Failover automatico (3 tentativi/wrapper, 2s delay) + +## ๐Ÿ“Š Data Aggregation + +**ProductInfo:** +- Volume: media tra sources +- Price: weighted average (price ร— volume) +- Confidence: spread + numero sources + +**Historical Price:** +- Align per timestamp +- Media: high, low, open, close, volume + +## ๐ŸŽฏ Configuration + +**configs.yaml:** +```yaml +port: 8000 +models: [Ollama, OpenAI, Anthropic, Google] +strategies: [Conservative, Aggressive] +agents: {team_model, team_leader_model, ...} +api: {retry_attempts: 3, retry_delay_seconds: 2} ``` -## ๐Ÿ›๏ธ Architettura dei Provider (Market Agent) +**.env (API Keys):** +- Market: CDP_API_KEY, CRYPTOCOMPARE_API_KEY, ... +- News: NEWS_API_KEY, CRYPTOPANIC_API_KEY, ... +- Social: REDDIT_CLIENT_ID, X_API_KEY, ... +- LLM: OPENAI_API_KEY, ANTHROPIC_API_KEY, ... +- Bot: TELEGRAM_BOT_TOKEN + +## ๐Ÿ—‚๏ธ Struttura Progetto ``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ ๐Ÿ“Š MARKET AGENT โ”‚ -โ”‚ โ”‚ -โ”‚ ๐Ÿ” Provider Detection Logic: โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”โ”‚ -โ”‚ โ”‚ def _setup_providers(): โ”‚โ”‚ -โ”‚ โ”‚ โ”œโ”€โ”€ ๐Ÿ”‘ Check CDP_API_KEY_NAME + CDP_API_PRIVATE_KEY โ”‚โ”‚ -โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ โœ… Setup Coinbase Advanced Trade โ”‚โ”‚ -โ”‚ โ”‚ โ”œโ”€โ”€ ๐Ÿ”‘ Check CRYPTOCOMPARE_API_KEY โ”‚โ”‚ -โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ โœ… Setup CryptoCompare โ”‚โ”‚ -โ”‚ โ”‚ โ””โ”€โ”€ ๐Ÿ”‘ Check BINANCE_API_KEY (future) โ”‚โ”‚ -โ”‚ โ”‚ โ””โ”€โ”€ โœ… Setup Binance API โ”‚โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜โ”‚ -โ”‚ โ”‚ -โ”‚ ๐Ÿ“ก Data Flow: โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ Provider 1 โ”‚โ”€โ”€โ”€โ–ถโ”‚ โ”‚โ—€โ”€โ”€โ”€โ”‚ Provider 2 โ”‚ โ”‚ -โ”‚ โ”‚ Coinbase โ”‚ โ”‚ AGGREGATOR โ”‚ โ”‚ CryptoComp โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ Real-time โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ Real-time โ”‚ โ”‚ -โ”‚ โ”‚ Market Data โ”‚ โ”‚ โ”‚Confidenceโ”‚ โ”‚ โ”‚ Market Data โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚Scoring โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ Spread โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ Provider 3 โ”‚โ”€โ”€โ”€โ–ถโ”‚ โ”‚Analysis โ”‚ โ”‚โ—€โ”€โ”€โ”€โ”‚ Provider N โ”‚ โ”‚ -โ”‚ โ”‚ Binance โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ Future โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ Mock Data โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +src/app/ +โ”œโ”€โ”€ __main__.py +โ”œโ”€โ”€ configs.py +โ”œโ”€โ”€ agents/ +โ”‚ โ”œโ”€โ”€ core.py +โ”‚ โ”œโ”€โ”€ pipeline.py +โ”‚ โ”œโ”€โ”€ plan_memory_tool.py +โ”‚ โ””โ”€โ”€ prompts/ +โ”œโ”€โ”€ api/ +โ”‚ โ”œโ”€โ”€ wrapper_handler.py +โ”‚ โ”œโ”€โ”€ core/ (markets, news, social) +โ”‚ โ”œโ”€โ”€ markets/ (Binance, CoinBase, CryptoCompare, YFinance) +โ”‚ โ”œโ”€โ”€ news/ (NewsAPI, GoogleNews, DuckDuckGo, CryptoPanic) +โ”‚ โ”œโ”€โ”€ social/ (Reddit, X, 4chan) +โ”‚ โ””โ”€โ”€ tools/ (Agno Toolkits) +โ””โ”€โ”€ interface/ (chat.py, telegram_app.py) + +tests/ +demos/ +resources/cryptos.csv +docs/ +configs.yaml +.env ``` -## ๐Ÿ”ง Signers Architecture +## ๐Ÿ”‘ Componenti Chiave -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ ๐Ÿ” SIGNERS ECOSYSTEM โ”‚ -โ”‚ โ”‚ -โ”‚ ๐Ÿ“ src/app/signers/market_signers/ โ”‚ -โ”‚ โ”‚ โ”‚ -โ”‚ โ”œโ”€โ”€ ๐Ÿฆ coinbase_rest_signer.py โ”‚ -โ”‚ โ”‚ โ”œโ”€โ”€ ๐Ÿ”‘ Uses: CDP_API_KEY_NAME + CDP_API_PRIVATE_KEY โ”‚ -โ”‚ โ”‚ โ”œโ”€โ”€ ๐Ÿ“ก RESTClient from coinbase.rest โ”‚ -โ”‚ โ”‚ โ”œโ”€โ”€ ๐Ÿ“Š get_asset_info() โ†’ Real Coinbase data โ”‚ -โ”‚ โ”‚ โ””โ”€โ”€ ๐Ÿ“ˆ get_multiple_assets() โ†’ Bulk data โ”‚ -โ”‚ โ”‚ โ”‚ -โ”‚ โ”œโ”€โ”€ ๐Ÿ“Š cryptocompare_signer.py โ”‚ -โ”‚ โ”‚ โ”œโ”€โ”€ ๐Ÿ”‘ Uses: CRYPTOCOMPARE_API_KEY โ”‚ -โ”‚ โ”‚ โ”œโ”€โ”€ ๐Ÿ“ก Direct HTTP requests โ”‚ -โ”‚ โ”‚ โ”œโ”€โ”€ ๐Ÿ’ฐ get_crypto_prices() โ†’ Multi-currency โ”‚ -โ”‚ โ”‚ โ””โ”€โ”€ ๐Ÿ† get_top_cryptocurrencies() โ†’ Market cap โ”‚ -โ”‚ โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€ ๐ŸŸก binance_signer.py โ”‚ -โ”‚ โ”œโ”€โ”€ ๐Ÿ”‘ Uses: BINANCE_API_KEY (future) โ”‚ -โ”‚ โ”œโ”€โ”€ ๐Ÿ“ก Mock implementation โ”‚ -โ”‚ โ”œโ”€โ”€ ๐ŸŽญ Simulated market data โ”‚ -โ”‚ โ””โ”€โ”€ ๐Ÿ“ˆ Compatible interface โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +1. **Agno Framework**: Agent, Team, Workflow, Toolkit, RunEvent +2. **WrapperHandler**: Failover, Retry logic, Type safety +3. **Data Aggregation**: Multiple sources, Confidence score +4. **Multi-Interface**: Gradio + Telegram +5. **Configuration**: configs.yaml + .env + +## ๐Ÿš€ Deployment + +**Docker:** +```bash +docker-compose up --build -d ``` -## ๐Ÿš€ Future Enhancement: Async Flow - -``` - ๐Ÿ“ฑ USER REQUEST - โ”‚ - โ–ผ - ๐Ÿ”ง TOOL AGENT (async) - โ”‚ - โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚ โ”‚ โ”‚ - โ–ผ โ–ผ โ–ผ - ๐Ÿ“Š Market ๐Ÿ“ฐ News ๐Ÿฆ Social - Agent (async) Agent (async) Agent (async) - โ”‚ โ”‚ โ”‚ - โ”Œโ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ - โ–ผ โ–ผ โ–ผ โ”‚ โ”‚ - Coinbase โ”‚ Binance โ”‚ โ”‚ - CC โ”‚ โ”‚ โ”‚ - โ–ผโ–ผโ–ผ โ–ผ โ–ผ - ๐Ÿ”„ Parallel ๐Ÿ“ฐ Sentiment ๐Ÿฆ Sentiment - Aggregation Analysis Analysis - โ”‚ โ”‚ โ”‚ - โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โ–ผ - ๐Ÿค– PREDICTOR AGENT - (LLM Analysis) - โ”‚ - โ–ผ - ๐Ÿ“‹ FINAL RESULT - (JSON + Confidence) +**Local (UV):** +```bash +uv venv +uv pip install -e . +uv run src/app ``` -## ๐Ÿ“Š Data Flow Example +## ๐ŸŽฏ Workflow Asincrono -``` -Input: "Analyze Bitcoin aggressive strategy" -โ”‚ -โ”œโ”€โ”€ ๐Ÿ“Š Market Agent Output: -โ”‚ { -โ”‚ "aggregated_data": { -โ”‚ "BTC_USD": {"price": 63516.67, "confidence": 0.94} -โ”‚ }, -โ”‚ "individual_sources": { -โ”‚ "coinbase": {"price": 63500, "volume": "1.2M"}, -โ”‚ "cryptocompare": {"price": 63450, "volume": "N/A"}, -โ”‚ "binance": {"price": 63600, "volume": "2.1M"} -โ”‚ }, -โ”‚ "market_signals": { -โ”‚ "spread_analysis": "Low spread (0.24%) - healthy liquidity", -โ”‚ "price_divergence": "Max deviation: 0.24% - Normal range" -โ”‚ } -โ”‚ } -โ”‚ -โ”œโ”€โ”€ ๐Ÿ“ฐ News Sentiment: "Positive institutional adoption news..." -โ”œโ”€โ”€ ๐Ÿฆ Social Sentiment: "Bullish Reddit sentiment, +15% mentions" -โ”‚ -โ””โ”€โ”€ ๐Ÿค– Predictor Output: - "๐Ÿ“ˆ Strong BUY recommendation based on: - - High confidence market data (94%) - - Positive news sentiment - - Bullish social indicators - - Low spread indicates healthy liquidity - - Aggressive Strategy: Consider 15-20% portfolio allocation" +```python +workflow = Workflow(steps=[ + query_check, condition, + info_recovery, report_generation +]) + +iterator = await workflow.arun(query, stream=True) + +async for event in iterator: + if event.event == PipelineEvent.TOOL_USED: + log(f"Tool: {event.tool.tool_name}") ``` ---- -*Diagrammi creati: 2025-09-23* -*Sistema: upo-appAI Market Analysis Platform* \ No newline at end of file +**Vantaggi:** Asincrono, Streaming, Condizionale, Retry + +## ๐Ÿ“ˆ Future Enhancements + +- Parallel Tool Execution +- Caching (Redis) +- Database (PostgreSQL) +- Real-time WebSocket +- ML Models +- User Profiles +- Backtesting diff --git a/docs/Async_Implementation_Detail.md b/docs/Async_Implementation_Detail.md deleted file mode 100644 index 9642dff..0000000 --- a/docs/Async_Implementation_Detail.md +++ /dev/null @@ -1,203 +0,0 @@ -# ๐Ÿš€ Diagramma Dettaglio: Implementazione Asincrona - -## โšก Async Market Data Collection (Fase 3) - -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ ๐Ÿ”ง TOOL AGENT โ”‚ -โ”‚ โ”‚ -โ”‚ async def interact(query, provider, style): โ”‚ -โ”‚ โ”‚ โ”‚ -โ”‚ โ”œโ”€โ”€ ๐Ÿ“Š market_data = await market_agent.analyze_async() โ”‚ -โ”‚ โ”œโ”€โ”€ ๐Ÿ“ฐ news_data = await news_agent.analyze_async() โ”‚ -โ”‚ โ”œโ”€โ”€ ๐Ÿฆ social_data = await social_agent.analyze_async() โ”‚ -โ”‚ โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€ ๐Ÿค– prediction = await predictor.predict_async(...) โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โ”‚ - โ–ผ -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ ๐Ÿ“Š MARKET AGENT - ASYNC IMPLEMENTATION โ”‚ -โ”‚ โ”‚ -โ”‚ async def analyze_async(self, query): โ”‚ -โ”‚ symbols = extract_symbols(query) # ["BTC", "ETH"] โ”‚ -โ”‚ โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€ ๐Ÿ”„ tasks = [ โ”‚ -โ”‚ โ”‚ self._query_coinbase_async(symbols), โ”‚ -โ”‚ โ”‚ self._query_cryptocompare_async(symbols), โ”‚ -โ”‚ โ”‚ self._query_binance_async(symbols) โ”‚ -โ”‚ โ”‚ ] โ”‚ -โ”‚ โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€ ๐Ÿ“Š results = await asyncio.gather(*tasks) โ”‚ -โ”‚ โ”‚ โ”‚ -โ”‚ โ–ผ โ”‚ -โ”‚ ๐Ÿงฎ aggregate_results(results) โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โ”‚ - โ–ผ -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ โฑ๏ธ TIMING DIAGRAM โ”‚ -โ”‚ โ”‚ -โ”‚ Time: 0ms 500ms 1000ms 1500ms 2000ms โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ ๐Ÿ“ก Start all requests โ”‚ -โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ ๐Ÿฆ Coinbase Request โ”‚ โ”‚ -โ”‚ โ”‚ โœ… Response โ”‚ (1.2s) โ”‚ -โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ -โ”‚ โ”‚ ๐Ÿ“Š CryptoCompare Request โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โœ… Response (0.8s) โ”‚ โ”‚ -โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ ๐ŸŸก Binance โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โœ… Response (0.3s - mock) โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ Wait for all... โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ -โ”‚ ๐Ÿงฎ Aggregate (1.2s total) โ”‚ -โ”‚ โ”‚ -โ”‚ ๐Ÿ“ˆ Performance Gain: โ”‚ -โ”‚ Sequential: 1.2s + 0.8s + 0.3s = 2.3s โ”‚ -โ”‚ Parallel: max(1.2s, 0.8s, 0.3s) = 1.2s โ”‚ -โ”‚ Improvement: ~48% faster! ๐Ÿš€ โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - -## ๐Ÿงฎ Aggregation Algorithm Detail - -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ ๐Ÿ”ฌ DATA AGGREGATION LOGIC โ”‚ -โ”‚ โ”‚ -โ”‚ def aggregate_market_data(results): โ”‚ -โ”‚ โ”‚ โ”‚ -โ”‚ โ”œโ”€โ”€ ๐Ÿ“Š Input Data: โ”‚ -โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ โ”‚ coinbase: {"BTC": 63500, "ETH": 4150} โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ cryptocomp: {"BTC": 63450, "ETH": 4160} โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ binance: {"BTC": 63600, "ETH": 4140} โ”‚ โ”‚ -โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ”‚ โ”‚ โ”‚ -โ”‚ โ”œโ”€โ”€ ๐Ÿงฎ Price Calculation: โ”‚ -โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ โ”‚ BTC_prices = [63500, 63450, 63600] โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ BTC_avg = 63516.67 โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ BTC_std = 75.83 โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ BTC_spread = (max-min)/avg = 0.24% โ”‚ โ”‚ -โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ”‚ โ”‚ โ”‚ -โ”‚ โ”œโ”€โ”€ ๐ŸŽฏ Confidence Scoring: โ”‚ -โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ โ”‚ confidence = 1 - (std_dev / mean) โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ if spread < 0.5%: confidence += 0.1 โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ if sources >= 3: confidence += 0.05 โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ BTC_confidence = 0.94 (excellent!) โ”‚ โ”‚ -โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ”‚ โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€ ๐Ÿ“ˆ Market Signals: โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ spread_analysis: โ”‚ โ”‚ -โ”‚ โ”‚ "Low spread (0.24%) indicates healthy liq." โ”‚ โ”‚ -โ”‚ โ”‚ volume_trend: โ”‚ โ”‚ -โ”‚ โ”‚ "Combined volume: 4.1M USD" โ”‚ โ”‚ -โ”‚ โ”‚ price_divergence: โ”‚ โ”‚ -โ”‚ โ”‚ "Max deviation: 0.24% - Normal range" โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - -## ๐Ÿ”„ Error Handling & Resilience - -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ ๐Ÿ›ก๏ธ RESILIENCE STRATEGY โ”‚ -โ”‚ โ”‚ -โ”‚ Scenario 1: One Provider Fails โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ ๐Ÿฆ Coinbase: โœ… Success (BTC: $63500) โ”‚ โ”‚ -โ”‚ โ”‚ ๐Ÿ“Š CryptoComp: โŒ Timeout/Error โ”‚ โ”‚ -โ”‚ โ”‚ ๐ŸŸก Binance: โœ… Success (BTC: $63600) โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ Result: Continue with 2 sources โ”‚ โ”‚ -โ”‚ โ”‚ Confidence: 0.89 (slightly reduced) โ”‚ โ”‚ -โ”‚ โ”‚ Note: "CryptoCompare unavailable" โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ”‚ โ”‚ -โ”‚ Scenario 2: Multiple Providers Fail โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ ๐Ÿฆ Coinbase: โŒ API Limit โ”‚ โ”‚ -โ”‚ โ”‚ ๐Ÿ“Š CryptoComp: โœ… Success (BTC: $63450) โ”‚ โ”‚ -โ”‚ โ”‚ ๐ŸŸก Binance: โŒ Network Error โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ Result: Single source data โ”‚ โ”‚ -โ”‚ โ”‚ Confidence: 0.60 (low - warn user) โ”‚ โ”‚ -โ”‚ โ”‚ Note: "Limited data - consider waiting" โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ”‚ โ”‚ -โ”‚ Scenario 3: All Providers Fail โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ ๐Ÿฆ Coinbase: โŒ Maintenance โ”‚ โ”‚ -โ”‚ โ”‚ ๐Ÿ“Š CryptoComp: โŒ API Down โ”‚ โ”‚ -โ”‚ โ”‚ ๐ŸŸก Binance: โŒ Rate Limit โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ Result: Graceful degradation โ”‚ โ”‚ -โ”‚ โ”‚ Message: "Market data temporarily unavailable" โ”‚ โ”‚ -โ”‚ โ”‚ Fallback: Cached data (if available) โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - -## ๐Ÿ“Š JSON Output Schema - -```json -{ - "aggregated_data": { - "BTC_USD": { - "price": 63516.67, - "confidence": 0.94, - "sources_count": 3, - "last_updated": "2025-09-23T17:30:00Z" - }, - "ETH_USD": { - "price": 4150.33, - "confidence": 0.91, - "sources_count": 3, - "last_updated": "2025-09-23T17:30:00Z" - } - }, - "individual_sources": { - "coinbase": { - "BTC": {"price": 63500, "volume": "1.2M", "status": "online"}, - "ETH": {"price": 4150, "volume": "25.6M", "status": "online"} - }, - "cryptocompare": { - "BTC": {"price": 63450, "volume": "N/A", "status": "active"}, - "ETH": {"price": 4160, "volume": "N/A", "status": "active"} - }, - "binance": { - "BTC": {"price": 63600, "volume": "2.1M", "status": "mock"}, - "ETH": {"price": 4140, "volume": "18.3M", "status": "mock"} - } - }, - "market_signals": { - "spread_analysis": "Low spread (0.24%) indicates healthy liquidity", - "volume_trend": "Combined BTC volume: 3.3M USD (+12% from avg)", - "price_divergence": "Max deviation: 0.24% - Normal range", - "data_quality": "High - 3 sources, low variance", - "recommendation": "Data suitable for trading decisions" - }, - "metadata": { - "query_time_ms": 1247, - "sources_queried": ["coinbase", "cryptocompare", "binance"], - "sources_successful": ["coinbase", "cryptocompare", "binance"], - "sources_failed": [], - "aggregation_method": "weighted_average", - "confidence_threshold": 0.75 - } -} -``` - ---- -*Diagramma dettaglio asincrono: 2025-09-23* -*Focus: Performance, Resilienza, Qualitร  Dati* \ No newline at end of file diff --git a/docs/Market_Data_Implementation_Plan.md b/docs/Market_Data_Implementation_Plan.md deleted file mode 100644 index e494ca7..0000000 --- a/docs/Market_Data_Implementation_Plan.md +++ /dev/null @@ -1,96 +0,0 @@ -# ๐Ÿš€ Piano di Implementazione - Market Data Enhancement - -## ๐Ÿ“‹ Roadmap Implementazioni - -### **Fase 1: Binance Mock Provider** -**Obiettivo**: Aggiungere terzo provider per test aggregazione -- โœ… Creare `binance_signer.py` con mock data -- โœ… Integrare nel MarketAgent -- โœ… Testare detection automatica provider -- **Deliverable**: 3 provider funzionanti (Coinbase, CryptoCompare, Binance) - -### **Fase 2: Interrogazione Condizionale** -**Obiettivo**: Auto-detection credenziali e interrogazione intelligente -- โœ… Migliorare detection chiavi API nel MarketAgent -- โœ… Skip provider se credenziali mancanti (no errori) -- โœ… Logging informativo per provider disponibili/non disponibili -- โœ… Gestione graceful degradation -- **Deliverable**: Sistema resiliente che funziona con qualsiasi combinazione di provider - -### **Fase 3: Interrogazione Asincrona + Aggregazione JSON** -**Obiettivo**: Performance boost e formato dati professionale - -#### **3A. Implementazione Asincrona** -- โœ… Refactor MarketAgent per supporto `async/await` -- โœ… Chiamate parallele a tutti i provider disponibili -- โœ… Timeout management per provider lenti -- โœ… Error handling per provider che falliscono - -#### **3B. Aggregazione Dati Intelligente** -- โœ… Calcolo `confidence` basato su concordanza prezzi -- โœ… Analisi `spread` tra provider -- โœ… Detection `price_divergence` per anomalie -- โœ… Volume trend analysis -- โœ… Formato JSON strutturato: - -```json -{ - "aggregated_data": { - "BTC_USD": { - "price": 43250.12, - "confidence": 0.95, - "sources_count": 4 - } - }, - "individual_sources": { - "coinbase": {"price": 43245.67, "volume": "1.2M"}, - "binance": {"price": 43255.89, "volume": "2.1M"}, - "cryptocompare": {"price": 43248.34, "volume": "0.8M"} - }, - "market_signals": { - "spread_analysis": "Low spread (0.02%) indicates healthy liquidity", - "volume_trend": "Volume up 15% from 24h average", - "price_divergence": "Max deviation: 0.05% - Normal range" - } -} -``` - -**Deliverable**: Sistema asincrono con analisi avanzata dei dati di mercato - -## ๐ŸŽฏ Benefici Attesi - -### **Performance** -- โšก Tempo risposta: da ~4s sequenziali a ~1s paralleli -- ๐Ÿ”„ Resilienza: sistema funziona anche se 1-2 provider falliscono -- ๐Ÿ“Š Qualitร  dati: validazione incrociata tra provider - -### **Professionalitร ** -- ๐Ÿ“ˆ Confidence scoring per decisioni informate -- ๐Ÿ” Market signals per trading insights -- ๐Ÿ“‹ Formato standardizzato per integrazioni future - -### **Scalabilitร ** -- โž• Facile aggiunta nuovi provider -- ๐Ÿ”ง Configurazione flessibile via environment -- ๐Ÿ“ Logging completo per debugging - -## ๐Ÿงช Test Strategy - -1. **Unit Tests**: Ogni provider singolarmente -2. **Integration Tests**: Aggregazione multi-provider -3. **Performance Tests**: Confronto sync vs async -4. **Resilience Tests**: Fallimento provider singoli -5. **E2E Tests**: Full workflow con UI Gradio - -## ๐Ÿ“… Timeline Stimata - -- **Fase 1**: ~1h (setup Binance mock) -- **Fase 2**: ~1h (detection condizionale) -- **Fase 3**: ~2-3h (async + aggregazione) -- **Testing**: ~1h (validation completa) - -**Total**: ~5-6h di lavoro strutturato - ---- -*Documento creato: 2025-09-23* -*Versione: 1.0* \ No newline at end of file diff --git a/docs/Piano di Sviluppo.md b/docs/Piano di Sviluppo.md deleted file mode 100644 index c4b1a51..0000000 --- a/docs/Piano di Sviluppo.md +++ /dev/null @@ -1,73 +0,0 @@ -# Guida alla Realizzazione del Progetto - -Questa guida รจ una lista di controllo per l'implementazione del tuo progetto. รˆ divisa in fasi logiche, ognuna con i compiti specifici da svolgere. - -## Fase 1: Preparazione e Architettura di Base - -### Impostazione dell'ambiente - -* Scegliere il linguaggio di programmazione (es. **Python**). -* Utilizzare la libreria `agno` per la creazione di agenti e **LangChain/LlamaIndex** per la gestione dell'LLM e dell'orchestrazione. - -### Definizione dell'Architettura degli agenti - -* Definire la classe base per gli agenti, con metodi comuni come `execute()` e `reason()`. -* Delineare i ruoli e le interfacce di tutti gli agenti (`RicercatoreDati`, `AnalistaSentiment`, `MotorePredittivo`, `Orchestratore`), stabilendo come comunicheranno tra loro. - ---- - -## Fase 2: Implementazione degli Agenti Core - -### Agente `RicercatoreDati` - -* Implementare la logica per connettersi a un'API di exchange (es. **Binance, Coindesk, CoinMarketCap**). -* Testare la capacitร  di recuperare dati in tempo reale per diverse criptovalute (prezzo, volume, capitalizzazione) e **assicurarsi che la gestione degli errori sia robusta**. - -### Agente `AnalistaSentiment` - -* **Agente `Social`:** - * Scegliere un metodo per lo scraping di forum e social media (es. **Reddit API, librerie per Twitter/X, BeautifulSoup per web scraping**). - * Implementare un modulo di analisi del testo per classificare il sentiment (positivo, negativo, neutro) utilizzando **modelli pre-addestrati (es. VADER) o fine-tuning di modelli piรน avanzati**. -* **Agente `News`:** - * Ottenere una chiave API per un servizio di notizie (es. **NewsAPI**). - * Implementare la logica per cercare articoli pertinenti a una criptovaluta specifica o al mercato in generale, e **filtrare le notizie in base a parole chiave rilevanti**. - -### Agente `MotorePredittivo` - -* Definire la logica per integrare i dati numerici del `RicercatoreDati` con il sentiment dell'`AnalistaSentiment`. -* Creare un **prompt avanzato** per l'LLM che lo guidi a generare previsioni e strategie. Dovrai usare tecniche come la **chain-of-thought** per rendere il ragionamento trasparente. Assicurarsi che il prompt includa vincoli specifici per lo stile di investimento (aggressivo/conservativo). - ---- - -## Fase 3: Costruzione dell'Orchestratore e Test di Integrazione - -### Implementazione dell'Agente Orchestratore - -* **Gestione dell'Input Utente:** Creare un metodo che riceve la richiesta dell'utente (es. `analizza_cripto('Bitcoin', 'aggressivo')`). Analizzare il tipo di richiesta e le preferenze utente. -* **Recupero della Memoria Utente:** Integrare la logica per recuperare la cronologia delle richieste passate dal database e preparare i dati come contesto aggiuntivo per l'LLM. -* **Orchestrazione e Flusso di Lavoro:** Chiamare gli agenti (`RicercatoreDati`, `AnalistaSentiment`) e passare i risultati combinati all'**Agente `MotorePredittivo`** per generare previsioni e strategie. -* **Valutazione e Selezione Strategica:** Ricevere le previsioni dal `MotorePredittivo` e applicare le regole di valutazione basate sulle preferenze dell'utente per selezionare le strategie piรน appropriate. -* **Presentazione e Persistenza:** Costruire il report finale e salvare la sessione completa nel database. - ---- - -## Fase 4: Gestione della Persistenza e dell'Interfaccia Utente - -* **Database per la persistenza:** Scegli un database (es. **Firestore, MongoDB, PostgreSQL**) per salvare la cronologia delle richieste degli utenti. Implementa la logica per salvare e recuperare le sessioni di consulenza passate, associandole a un ID utente, e **struttura i dati per una ricerca efficiente**. - -* **Interfaccia utente (UI):** Costruisci un'interfaccia utente semplice e intuitiva che permetta di inserire i parametri di richiesta. Aggiungi una sezione per visualizzare i risultati, inclusi i grafici e le note che spiegano il ragionamento dell'agente. - ---- - -## Fase 5: Test del Sistema - -* **Test unitari:** Esegui test su ogni agente singolarmente per assicurarti che funzioni correttamente (es. l'agente `RicercatoreDati` recupera i dati, l'agente `AnalistaSentiment` classifica correttamente un testo). **Crea dei mock per le API esterne per testare la logica interna senza dipendenze esterne**. -* **Test di integrazione:** Esegui scenari di test completi per l'intero sistema. Verifica che l'orchestrazione tra gli agenti avvenga senza intoppi e che i dati vengano passati correttamente tra di essi. - ---- - -## Fase 6: Valutazione dei Risultati - -* **Valutazione della qualitร :** Verifica la qualitร  delle raccomandazioni generate. L'output รจ logico e ben argomentato? -* **Trasparenza del ragionamento:** Controlla che le note (`Ragionamenti`) siano chiare e forniscano un'effettiva trasparenza del processo decisionale dell'agente. -* **Confronto e validazione:** Confronta le raccomandazioni con dati storici e scenari ipotetici per valutarne la plausibilitร . \ No newline at end of file