cicboy commited on
Commit
1dece25
·
1 Parent(s): adf3bae

Add tools folder with market, sentiment, historical and analytical tools

Browse files
tools/__pycache__/analytics_tool.cpython-313.pyc ADDED
Binary file (3.01 kB). View file
 
tools/__pycache__/historical_data_tool.cpython-313.pyc ADDED
Binary file (3.06 kB). View file
 
tools/__pycache__/market_data.cpython-313.pyc ADDED
Binary file (1.88 kB). View file
 
tools/__pycache__/sentiment_tool.cpython-313.pyc ADDED
Binary file (3.87 kB). View file
 
tools/analytics_tool.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from crewai_tools import RagTool
2
+ import json
3
+
4
+ class AnalyticsTool(RagTool):
5
+ name: str = "analytics_tool"
6
+ description: str = (
7
+ "Processes and aggregates outputs from market, historical and sentiment agents"
8
+ "to generate structured indicators and performance metrics, giving a holistic view of the cryptocurrency's condition."
9
+ )
10
+
11
+ def _run(self, market_data: dict, historical_data: dict, sentiment_data: dict):
12
+ # combine results from the other agents into structured numeric metrics
13
+
14
+ try:
15
+ #Normalize strings -> dicts
16
+ if isinstance(market_data, str):
17
+ market_data = json.loads(market_data)
18
+ if isinstance(historical_data, str):
19
+ historical_data = json.loads(historical_data)
20
+ if isinstance(sentiment_data, str):
21
+ sentiment_data = json.loads(sentiment_data)
22
+
23
+ #Extract info safely
24
+ current_price = market_data.get("price") or market_data.get("latest_price")
25
+ pct_change = historical_data.get("pct_change", 0)
26
+ volatility = historical_data.get("volatility_pct", 0)
27
+ trend = historical_data.get("trend", "unknown")
28
+ sentiment = sentiment_data.get("final_sentiment_classification", "neutral")
29
+
30
+ #Compute basic consistency logic
31
+ aligned = (
32
+ (trend == "upward" and "bullish" in sentiment.lower()) or
33
+ (trend == "downward" and "bearish" in sentiment.lower())
34
+ )
35
+
36
+ score = (
37
+ (pct_change/10) + (0.2 if aligned else -0.2)
38
+ + (0.1 if "bullish" in sentiment.lower() else -0.1 if "bearish" in sentiment.lower() else 0)
39
+ )
40
+
41
+ score = round(max(-1, min(1, score)), 2)
42
+
43
+ return {
44
+ "price": current_price,
45
+ "pct_change": pct_change,
46
+ "volatility": volatility,
47
+ "trend": trend,
48
+ "sentiment": sentiment,
49
+ "alignment": "aligned" if aligned else "divergent",
50
+ "composite_score": score,
51
+ "summary": f"Trend={trend}, Sentiment={sentiment}, Alignment={'aligned' if aligned else 'divergent'}, Score = {score}"
52
+ }
53
+ except Exception as e:
54
+ return {"error": f"AnalyticsTool failed: {str(e)}"}
tools/historical_data_tool.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # tools/historical_data_tool.py
2
+ from crewai_tools import RagTool
3
+ import requests
4
+ from datetime import datetime
5
+ import statistics
6
+
7
+ class HistoricalDataTool(RagTool):
8
+ name: str = "get_historical_data"
9
+ description: str = (
10
+ "Fetches and analyzes historical cryptocurrency market data "
11
+ "from the CoinGecko API for trend insights."
12
+ )
13
+
14
+ def _run(self, symbol: str = "bitcoin", currency: str = "usd", days: int = 30) -> dict:
15
+ """
16
+ Fetch historical data for the specified cryptocurrency over a given number of days.
17
+ Computes basic trend and volatility statistics.
18
+ """
19
+ url = f"https://api.coingecko.com/api/v3/coins/{symbol}/market_chart"
20
+ params = {"vs_currency": currency, "days": days}
21
+
22
+ try:
23
+ response = requests.get(url, params=params, timeout=10)
24
+ response.raise_for_status()
25
+ data = response.json()
26
+
27
+ prices = data.get("prices", [])
28
+ if not prices:
29
+ return {"error": f"No data found for {symbol}."}
30
+
31
+ # Extract date and price
32
+ history = [
33
+ {"date": datetime.utcfromtimestamp(p[0] / 1000).strftime("%Y-%m-%d"), "price": p[1]}
34
+ for p in prices
35
+ ]
36
+
37
+ # Calculate simple stats
38
+ first, last = history[0]["price"], history[-1]["price"]
39
+ pct_change = ((last - first) / first) * 100
40
+ daily_returns = [
41
+ (history[i + 1]["price"] - history[i]["price"]) / history[i]["price"]
42
+ for i in range(len(history) - 1)
43
+ ]
44
+ volatility = statistics.stdev(daily_returns) * 100 if len(daily_returns) > 1 else 0
45
+
46
+ trend = "upward" if pct_change > 0 else "downward" if pct_change < 0 else "sideways"
47
+
48
+ return {
49
+ "symbol": symbol,
50
+ "currency": currency,
51
+ "days": days,
52
+ "start_price": round(first, 2),
53
+ "end_price": round(last, 2),
54
+ "pct_change": round(pct_change, 2),
55
+ "volatility_pct": round(volatility, 2),
56
+ "trend": trend,
57
+ }
58
+
59
+ except Exception as e:
60
+ return {"error": str(e)}
tools/market_data.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from crewai_tools import RagTool
3
+ import requests
4
+
5
+ class MarketDataTool(RagTool):
6
+ name: str ="get_market_data"
7
+ description: str ="Fetches the current market price of a cryptocurrency in a chosen fiat currency using the CoinGecko API."
8
+
9
+ def _run(self, symbol="bitcoin", currency="usd"):
10
+ url = f"https://api.coingecko.com/api/v3/simple/price?ids={symbol}&vs_currencies={currency}"
11
+ try:
12
+ response = requests.get(url, timeout=10)
13
+ response.raise_for_status()
14
+ data = response.json()
15
+ price = data.get(symbol, {}).get(currency)
16
+ if price is None:
17
+ return {
18
+ "symbol": symbol,
19
+ "currency": currency,
20
+ "error": f"Could not find data for {symbol.upper()} in {currency.upper()}."
21
+ }
22
+ return {
23
+ "symbol": symbol,
24
+ "currency": currency,
25
+ "latest_price": price,
26
+ "formatted": f"{symbol.capitalize()} price: {price} {currency.upper()}"
27
+ }
28
+ except Exception as e:
29
+ return {"error": str(e)}
30
+
31
+
tools/sentiment_tool.py ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import requests
3
+ from crewai_tools import RagTool
4
+ from openai import OpenAI
5
+ from pathlib import Path
6
+ from dotenv import load_dotenv
7
+
8
+ env_path = Path("/Users/clydecossey/Documents/Python/Crypto_Analysis_Agent/Open_AI.env")
9
+ load_dotenv(dotenv_path=env_path)
10
+ OPENAI_API_KEY = os.getenv(key = "OPENAI_API_KEY")
11
+
12
+ client = OpenAI(api_key=OPENAI_API_KEY)
13
+
14
+ serper_env_path = Path("Users/clydecossey/Documents/Python/Crypto_Analysis_Agent/Serper.env")
15
+ load_dotenv(dotenv_path=serper_env_path)
16
+ SERPER_API_KEY = os.getenv(key="SERPER_API_KEY")
17
+
18
+ class SentimentTool(RagTool):
19
+ name: str = "get_crypto_sentiment"
20
+ description: str = (
21
+ "Fetches recent cryptocurrency news and Reddit discussions,"
22
+ "then analyses sentiment as bullish, bearish or neutral."
23
+ )
24
+
25
+ def _run(self, query: str = "bitcoin") -> str:
26
+ try:
27
+ #Google news sentiment
28
+ news_url = "https://google.serper.dev/news"
29
+ headers = {"X-API-KEY": SERPER_API_KEY, "Content-Type": "application/json"}
30
+ payload = {"q": f"{query} crypto", "num": 5}
31
+ news_response = requests.post(news_url, headers=headers, json=payload, timout=10)
32
+ news = news_response.json().get("news", [])
33
+ headlines = [n["title"] for n in news[:5]]
34
+
35
+ #Reddit sentiment
36
+ reddit_url = f"https://www.reddit.com/search.json?q={query}&sort=new&limit=5"
37
+ reddit_headers = {"User-Agent": "CryptoAgent/1.0"}
38
+ reddit_response = requests.get(reddit_url,headers=reddit_headers, timeout=10)
39
+ reddit_posts = reddit_response.json().get("data", {}).get("children", [])
40
+ reddit_titles = [p["data"]["title"] for p in reddit_posts[:5]]
41
+
42
+ combined_text = "News: " + " | ".join(headlines) + "\nReddit: " + " | ".join(reddit_titles)
43
+
44
+ #analyze sentiment
45
+ sentiment_prompt = f"""
46
+ You are a crypto sentiment analyst. Based on the following headlines and Reddit posts,
47
+ intuitively determine if the overall sentiment towards "{query}" is bullish, bearish, or neutral.
48
+ Respond with a short summary and a one-word sentiment classification.
49
+
50
+ {combined_text}
51
+ """
52
+ completion = client.chat.completions.create(
53
+ model="gpt-5-mini",
54
+ messages=[
55
+ {"role": "system", "content": "You are a precise sentiment classifier."},
56
+ {"role": "user", "content": sentiment_prompt}
57
+ ],
58
+ temperature=0.2
59
+ )
60
+ sentiment_result = completion.choices[0].message.content.strip()
61
+ return sentiment_result
62
+
63
+ except Exception as e:
64
+ return f"Error fetching sentiment data: {str(e)}"
65
+