Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
import requests
|
| 2 |
-
from typing import List, Dict
|
| 3 |
import numpy as np
|
| 4 |
import yaml
|
| 5 |
from smolagents import CodeAgent, HfApiModel, load_tool, tool
|
|
@@ -10,7 +10,7 @@ from Gradio_UI import GradioUI
|
|
| 10 |
# ✅ Final Answer Tool
|
| 11 |
final_answer = FinalAnswerTool()
|
| 12 |
|
| 13 |
-
# ✅ AI Model
|
| 14 |
model = HfApiModel(
|
| 15 |
max_tokens=2096,
|
| 16 |
temperature=0.5,
|
|
@@ -28,9 +28,16 @@ with open("prompts.yaml", 'r') as stream:
|
|
| 28 |
|
| 29 |
# --- Utility Functions ---
|
| 30 |
|
| 31 |
-
def fetch_data(url, params=None):
|
| 32 |
"""
|
| 33 |
Utility function to make GET requests and return the response as JSON.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
"""
|
| 35 |
try:
|
| 36 |
response = requests.get(url, params=params)
|
|
@@ -40,9 +47,16 @@ def fetch_data(url, params=None):
|
|
| 40 |
return {"error": str(e)}
|
| 41 |
|
| 42 |
|
| 43 |
-
def compute_moving_average(prices, window):
|
| 44 |
"""
|
| 45 |
Computes the moving average for the given price data over a specified window.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
"""
|
| 47 |
return np.mean(prices[-window:]) if len(prices) >= window else np.mean(prices)
|
| 48 |
|
|
@@ -51,50 +65,65 @@ def compute_moving_average(prices, window):
|
|
| 51 |
|
| 52 |
### 🔹 1. Fetch Latest BTC News ###
|
| 53 |
@tool
|
| 54 |
-
def
|
| 55 |
"""
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
Arguments:
|
| 59 |
-
articles (List[Dict[str, str]]): A list of dictionaries representing Bitcoin news articles.
|
| 60 |
-
Each dictionary contains the 'title' and 'url' of the article.
|
| 61 |
|
| 62 |
Returns:
|
| 63 |
-
|
|
|
|
| 64 |
"""
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
return {
|
| 71 |
-
"sentiment_score": avg_sentiment,
|
| 72 |
-
"sentiment_label": sentiment_label,
|
| 73 |
-
"keywords": keywords
|
| 74 |
-
}
|
| 75 |
-
|
| 76 |
### 🔹 2. Analyze News Sentiment ###
|
| 77 |
@tool
|
| 78 |
-
def analyze_btc_news(articles: List[Dict[str, str]]) -> Dict[str,
|
| 79 |
"""
|
| 80 |
Analyzes sentiment of Bitcoin news articles using TextBlob.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
"""
|
| 82 |
sentiments = [TextBlob(article["title"]).sentiment.polarity for article in articles]
|
| 83 |
avg_sentiment = np.mean(sentiments) if sentiments else 0
|
| 84 |
sentiment_label = "Positive 😊" if avg_sentiment > 0 else "Negative 😡" if avg_sentiment < 0 else "Neutral 😐"
|
| 85 |
-
keywords = list(set(
|
| 86 |
-
|
| 87 |
return {
|
| 88 |
-
"sentiment_score": avg_sentiment,
|
| 89 |
-
"sentiment_label": sentiment_label,
|
| 90 |
"keywords": keywords
|
| 91 |
}
|
| 92 |
|
|
|
|
| 93 |
### 🔹 3. Get BTC Market Insights ###
|
| 94 |
@tool
|
| 95 |
-
def btc_market_insights() -> Dict[str,
|
| 96 |
"""
|
| 97 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 98 |
"""
|
| 99 |
# Fetch current BTC price
|
| 100 |
price_url = "https://api.coingecko.com/api/v3/simple/price"
|
|
@@ -108,12 +137,12 @@ def btc_market_insights() -> Dict[str, any]:
|
|
| 108 |
prices = [entry[1] for entry in hist_data.get("prices", [])]
|
| 109 |
|
| 110 |
# Compute moving averages for different timeframes
|
| 111 |
-
ma_5m = compute_moving_average(prices, 1)
|
| 112 |
ma_1h = compute_moving_average(prices, 12) # 1-hour
|
| 113 |
ma_1d = compute_moving_average(prices, 24) # 1-day
|
| 114 |
-
ma_7d = compute_moving_average(prices, 168)
|
| 115 |
-
ma_1m = compute_moving_average(prices, 720)
|
| 116 |
-
ma_1y = compute_moving_average(prices, 8760)
|
| 117 |
|
| 118 |
# Fetch Fear & Greed Index
|
| 119 |
fgi_url = "https://api.alternative.me/fng/"
|
|
@@ -137,9 +166,16 @@ def btc_market_insights() -> Dict[str, any]:
|
|
| 137 |
|
| 138 |
### 🔹 4. Make Buy/Sell/HODL Decision ###
|
| 139 |
@tool
|
| 140 |
-
def btc_decision(news_analysis: Dict[str,
|
| 141 |
"""
|
| 142 |
-
Aggregates news sentiment
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 143 |
"""
|
| 144 |
sentiment_score = news_analysis["sentiment_score"]
|
| 145 |
fgi = int(market_insights["fear_greed"])
|
|
@@ -153,7 +189,7 @@ def btc_decision(news_analysis: Dict[str, any], market_insights: Dict[str, any])
|
|
| 153 |
ma_1m = market_insights["ma_1m"]
|
| 154 |
ma_1y = market_insights["ma_1y"]
|
| 155 |
|
| 156 |
-
#
|
| 157 |
decision = {
|
| 158 |
"5m-1H": "HODL 🤔",
|
| 159 |
"1D": "HODL 🤔",
|
|
@@ -162,8 +198,8 @@ def btc_decision(news_analysis: Dict[str, any], market_insights: Dict[str, any])
|
|
| 162 |
"1Y": "HODL 🤔"
|
| 163 |
}
|
| 164 |
|
| 165 |
-
#
|
| 166 |
-
def make_decision(timeframe, ma, price, sentiment, fear_greed):
|
| 167 |
if price > ma and fear_greed < 40 and sentiment > 0:
|
| 168 |
decision[timeframe] = "BUY 🚀"
|
| 169 |
elif price < ma and fear_greed > 60 and sentiment < 0:
|
|
@@ -181,7 +217,7 @@ def btc_decision(news_analysis: Dict[str, any], market_insights: Dict[str, any])
|
|
| 181 |
# --- Agent Setup ---
|
| 182 |
agent = CodeAgent(
|
| 183 |
model=model,
|
| 184 |
-
tools=[final_answer, fetch_btc_news, analyze_btc_news, btc_market_insights, btc_decision],
|
| 185 |
max_steps=6,
|
| 186 |
verbosity_level=1,
|
| 187 |
prompt_templates=prompt_templates
|
|
|
|
| 1 |
import requests
|
| 2 |
+
from typing import List, Dict, Any
|
| 3 |
import numpy as np
|
| 4 |
import yaml
|
| 5 |
from smolagents import CodeAgent, HfApiModel, load_tool, tool
|
|
|
|
| 10 |
# ✅ Final Answer Tool
|
| 11 |
final_answer = FinalAnswerTool()
|
| 12 |
|
| 13 |
+
# ✅ AI Model Setup
|
| 14 |
model = HfApiModel(
|
| 15 |
max_tokens=2096,
|
| 16 |
temperature=0.5,
|
|
|
|
| 28 |
|
| 29 |
# --- Utility Functions ---
|
| 30 |
|
| 31 |
+
def fetch_data(url: str, params: Dict[str, Any] = None) -> Dict[str, Any]:
|
| 32 |
"""
|
| 33 |
Utility function to make GET requests and return the response as JSON.
|
| 34 |
+
|
| 35 |
+
Arguments:
|
| 36 |
+
url (str): The API endpoint URL.
|
| 37 |
+
params (Dict[str, Any], optional): Query parameters for the request.
|
| 38 |
+
|
| 39 |
+
Returns:
|
| 40 |
+
Dict[str, Any]: The JSON response from the API.
|
| 41 |
"""
|
| 42 |
try:
|
| 43 |
response = requests.get(url, params=params)
|
|
|
|
| 47 |
return {"error": str(e)}
|
| 48 |
|
| 49 |
|
| 50 |
+
def compute_moving_average(prices: List[float], window: int) -> float:
|
| 51 |
"""
|
| 52 |
Computes the moving average for the given price data over a specified window.
|
| 53 |
+
|
| 54 |
+
Arguments:
|
| 55 |
+
prices (List[float]): List of historical price values.
|
| 56 |
+
window (int): The number of data points to include in the average.
|
| 57 |
+
|
| 58 |
+
Returns:
|
| 59 |
+
float: The computed moving average.
|
| 60 |
"""
|
| 61 |
return np.mean(prices[-window:]) if len(prices) >= window else np.mean(prices)
|
| 62 |
|
|
|
|
| 65 |
|
| 66 |
### 🔹 1. Fetch Latest BTC News ###
|
| 67 |
@tool
|
| 68 |
+
def fetch_btc_news() -> List[Dict[str, str]]:
|
| 69 |
"""
|
| 70 |
+
Fetches the latest Bitcoin news from the CryptoPanic API.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
|
| 72 |
Returns:
|
| 73 |
+
List[Dict[str, str]]: A list of dictionaries, each containing the 'title' and 'url'
|
| 74 |
+
of a Bitcoin news article.
|
| 75 |
"""
|
| 76 |
+
url = "https://cryptopanic.com/api/v1/posts/?auth_token=ccbeafb47d266a78086f76c3f547546f6b747e88¤cies=BTC"
|
| 77 |
+
data = fetch_data(url)
|
| 78 |
+
return [{"title": post["title"], "url": post["url"]} for post in data.get("results", [])[:5]]
|
| 79 |
+
|
| 80 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
### 🔹 2. Analyze News Sentiment ###
|
| 82 |
@tool
|
| 83 |
+
def analyze_btc_news(articles: List[Dict[str, str]]) -> Dict[str, Any]:
|
| 84 |
"""
|
| 85 |
Analyzes sentiment of Bitcoin news articles using TextBlob.
|
| 86 |
+
|
| 87 |
+
Arguments:
|
| 88 |
+
articles (List[Dict[str, str]]): A list of dictionaries representing Bitcoin news articles.
|
| 89 |
+
Each dictionary should contain 'title' and 'url'.
|
| 90 |
+
|
| 91 |
+
Returns:
|
| 92 |
+
Dict[str, Any]: A dictionary containing:
|
| 93 |
+
- 'sentiment_score': The average sentiment polarity of the article titles.
|
| 94 |
+
- 'sentiment_label': A label ('Positive 😊', 'Negative 😡', or 'Neutral 😐')
|
| 95 |
+
based on the sentiment score.
|
| 96 |
+
- 'keywords': A list of keywords extracted from the article titles.
|
| 97 |
"""
|
| 98 |
sentiments = [TextBlob(article["title"]).sentiment.polarity for article in articles]
|
| 99 |
avg_sentiment = np.mean(sentiments) if sentiments else 0
|
| 100 |
sentiment_label = "Positive 😊" if avg_sentiment > 0 else "Negative 😡" if avg_sentiment < 0 else "Neutral 😐"
|
| 101 |
+
keywords = list(set(word for article in articles for word in article["title"].split()[:5]))
|
|
|
|
| 102 |
return {
|
| 103 |
+
"sentiment_score": avg_sentiment,
|
| 104 |
+
"sentiment_label": sentiment_label,
|
| 105 |
"keywords": keywords
|
| 106 |
}
|
| 107 |
|
| 108 |
+
|
| 109 |
### 🔹 3. Get BTC Market Insights ###
|
| 110 |
@tool
|
| 111 |
+
def btc_market_insights() -> Dict[str, Any]:
|
| 112 |
"""
|
| 113 |
+
Fetches BTC price, historical trends, moving averages, and the Fear & Greed Index.
|
| 114 |
+
|
| 115 |
+
Returns:
|
| 116 |
+
Dict[str, Any]: A dictionary containing:
|
| 117 |
+
- 'price': Current BTC price in USD.
|
| 118 |
+
- '24h_change': 24-hour price change percentage.
|
| 119 |
+
- 'ma_5m': 5-minute moving average.
|
| 120 |
+
- 'ma_1h': 1-hour moving average.
|
| 121 |
+
- 'ma_1d': 1-day moving average.
|
| 122 |
+
- 'ma_7d': 7-day moving average.
|
| 123 |
+
- 'ma_1m': 1-month moving average.
|
| 124 |
+
- 'ma_1y': 1-year moving average.
|
| 125 |
+
- 'fear_greed': Current Fear & Greed index value.
|
| 126 |
+
- 'fgi_text': Classification of the Fear & Greed index.
|
| 127 |
"""
|
| 128 |
# Fetch current BTC price
|
| 129 |
price_url = "https://api.coingecko.com/api/v3/simple/price"
|
|
|
|
| 137 |
prices = [entry[1] for entry in hist_data.get("prices", [])]
|
| 138 |
|
| 139 |
# Compute moving averages for different timeframes
|
| 140 |
+
ma_5m = compute_moving_average(prices, 1) # 5-minute
|
| 141 |
ma_1h = compute_moving_average(prices, 12) # 1-hour
|
| 142 |
ma_1d = compute_moving_average(prices, 24) # 1-day
|
| 143 |
+
ma_7d = compute_moving_average(prices, 168) # 7-day
|
| 144 |
+
ma_1m = compute_moving_average(prices, 720) # 1-month
|
| 145 |
+
ma_1y = compute_moving_average(prices, 8760) # 1-year
|
| 146 |
|
| 147 |
# Fetch Fear & Greed Index
|
| 148 |
fgi_url = "https://api.alternative.me/fng/"
|
|
|
|
| 166 |
|
| 167 |
### 🔹 4. Make Buy/Sell/HODL Decision ###
|
| 168 |
@tool
|
| 169 |
+
def btc_decision(news_analysis: Dict[str, Any], market_insights: Dict[str, Any]) -> Dict[str, str]:
|
| 170 |
"""
|
| 171 |
+
Aggregates news sentiment and market insights to suggest a Buy, Sell, or HODL decision.
|
| 172 |
+
|
| 173 |
+
Arguments:
|
| 174 |
+
news_analysis (Dict[str, Any]): Output from the news sentiment analysis tool.
|
| 175 |
+
market_insights (Dict[str, Any]): BTC market data from the market insights tool.
|
| 176 |
+
|
| 177 |
+
Returns:
|
| 178 |
+
Dict[str, str]: A dictionary mapping timeframes to a decision ("BUY 🚀", "SELL 📉", or "HODL 🤔").
|
| 179 |
"""
|
| 180 |
sentiment_score = news_analysis["sentiment_score"]
|
| 181 |
fgi = int(market_insights["fear_greed"])
|
|
|
|
| 189 |
ma_1m = market_insights["ma_1m"]
|
| 190 |
ma_1y = market_insights["ma_1y"]
|
| 191 |
|
| 192 |
+
# Initialize decision template
|
| 193 |
decision = {
|
| 194 |
"5m-1H": "HODL 🤔",
|
| 195 |
"1D": "HODL 🤔",
|
|
|
|
| 198 |
"1Y": "HODL 🤔"
|
| 199 |
}
|
| 200 |
|
| 201 |
+
# Internal helper to update decision based on parameters
|
| 202 |
+
def make_decision(timeframe: str, ma: float, price: float, sentiment: float, fear_greed: int) -> str:
|
| 203 |
if price > ma and fear_greed < 40 and sentiment > 0:
|
| 204 |
decision[timeframe] = "BUY 🚀"
|
| 205 |
elif price < ma and fear_greed > 60 and sentiment < 0:
|
|
|
|
| 217 |
# --- Agent Setup ---
|
| 218 |
agent = CodeAgent(
|
| 219 |
model=model,
|
| 220 |
+
tools=[final_answer, fetch_btc_news, analyze_btc_news, btc_market_insights, btc_decision],
|
| 221 |
max_steps=6,
|
| 222 |
verbosity_level=1,
|
| 223 |
prompt_templates=prompt_templates
|