Remember when your friend bought Bitcoin at $65,000 because "everyone was doing it"? Or when they panic-sold at $15,000 because "crypto is dead"? That's the fear and greed cycle in action, and it's precisely what we can measure and exploit.
The crypto market runs on emotions more than fundamentals. While the official Fear & Greed Index gives us a snapshot, building your own sentiment tracker with Ollama lets you customize the inputs, weight different factors, and create actionable trading signals.
This guide shows you how to build a custom crypto fear and greed index using Ollama's AI models. You'll learn to analyze social media sentiment, track market indicators, and create automated alerts that help you buy when others are fearful and sell when others are greedy.
What Makes a Crypto Fear and Greed Index Effective
The traditional Fear & Greed Index combines seven market indicators: volatility, momentum, social media sentiment, surveys, Bitcoin dominance, trends, and volume. But here's the problem: it's a black box with fixed weightings that don't adapt to market conditions.
Your custom sentiment tracker will be different. You'll control the data sources, adjust the weightings based on market phases, and integrate real-time social media analysis that goes beyond simple keyword counting.
Key Components of Our Custom Index
Our Ollama-powered sentiment tracker analyzes five core components:
Social Media Sentiment Analysis: Process tweets, Reddit posts, and Telegram messages using Ollama's language models to extract emotional context, not just keyword frequency.
Market Technical Indicators: Track volatility, volume, and momentum with customizable weightings that adapt to different market conditions.
News Sentiment Processing: Analyze crypto news headlines and articles for sentiment changes that precede price movements.
On-Chain Metrics Integration: Include whale movements, exchange flows, and network activity as sentiment indicators.
Cross-Asset Correlations: Monitor traditional market fear indicators like VIX and their relationship to crypto sentiment.
Setting Up Ollama for Sentiment Analysis
Before we build the tracker, you need Ollama running locally. This gives you privacy, speed, and the ability to fine-tune models for crypto-specific sentiment analysis.
Installing Ollama
First, install Ollama on your system:
# Linux/macOS
curl -fsSL https://ollama.ai/install.sh | sh
# Windows (PowerShell)
winget install ollama
Pull the models we'll use for sentiment analysis:
# General sentiment analysis
ollama pull llama3.2:3b
# For more nuanced financial sentiment
ollama pull mistral:7b
# Lightweight model for high-frequency analysis
ollama pull phi3:mini
Testing Your Ollama Setup
Verify your installation with a quick sentiment test:
import requests
import json
def test_ollama_sentiment():
"""Test Ollama sentiment analysis capability"""
prompt = """
Analyze the sentiment of this crypto tweet on a scale of 1-10
(1 = extreme fear, 10 = extreme greed):
"Bitcoin is about to break $100k! This is just the beginning!
HODL strong! 🚀🚀🚀"
Respond with just the number and brief reason.
"""
response = requests.post('http://localhost:11434/api/generate',
json={
'model': 'llama3.2:3b',
'prompt': prompt,
'stream': False
})
result = json.loads(response.text)
print(f"Sentiment Analysis: {result['response']}")
# Test the connection
test_ollama_sentiment()
Expected output:
Sentiment Analysis: 9 - Extreme optimism with moon emojis and price predictions indicates high greed
Building the Core Sentiment Tracker
Now let's create the main sentiment tracker class that will coordinate all our data sources and AI analysis.
Core Tracker Architecture
import asyncio
import aiohttp
import json
from datetime import datetime, timedelta
from typing import Dict, List, Optional
import pandas as pd
import numpy as np
class CryptoSentimentTracker:
"""Custom Fear & Greed Index using Ollama AI models"""
def __init__(self, ollama_url: str = "http://localhost:11434"):
self.ollama_url = ollama_url
self.sentiment_history = []
self.weights = {
'social_media': 0.25,
'technical_indicators': 0.20,
'news_sentiment': 0.20,
'onchain_metrics': 0.20,
'market_momentum': 0.15
}
async def analyze_text_sentiment(self, text: str, context: str = "general") -> Dict:
"""Analyze sentiment using Ollama with crypto-specific context"""
prompt = f"""
As a crypto market analyst, analyze this {context} for sentiment:
"{text}"
Provide a JSON response with:
- sentiment_score: 1-10 (1=extreme fear, 10=extreme greed)
- confidence: 0-1 (how confident you are)
- key_phrases: list of 3 most important phrases
- emotion_type: fear/greed/neutral/uncertainty
Consider crypto-specific context like FOMO, FUD, diamond hands, etc.
"""
async with aiohttp.ClientSession() as session:
async with session.post(
f"{self.ollama_url}/api/generate",
json={
'model': 'llama3.2:3b',
'prompt': prompt,
'stream': False,
'format': 'json'
}
) as response:
result = await response.json()
try:
return json.loads(result['response'])
except:
# Fallback parsing if JSON format fails
return self._parse_sentiment_fallback(result['response'])
def _parse_sentiment_fallback(self, text: str) -> Dict:
"""Fallback parser for non-JSON responses"""
# Extract sentiment score
import re
score_match = re.search(r'sentiment_score["\s:]*(\d+)', text)
score = int(score_match.group(1)) if score_match else 5
# Determine emotion type
emotion = "neutral"
if "fear" in text.lower() or "panic" in text.lower():
emotion = "fear"
elif "greed" in text.lower() or "fomo" in text.lower():
emotion = "greed"
elif "uncertain" in text.lower():
emotion = "uncertainty"
return {
'sentiment_score': score,
'confidence': 0.7,
'key_phrases': ["market_sentiment"],
'emotion_type': emotion
}
Social Media Data Collection
The social media component is crucial since retail sentiment often drives crypto price movements. Here's how to collect and analyze Twitter/X data:
class SocialMediaAnalyzer:
"""Analyze social media sentiment for crypto"""
def __init__(self, sentiment_tracker: CryptoSentimentTracker):
self.tracker = sentiment_tracker
self.crypto_keywords = [
'bitcoin', 'btc', 'ethereum', 'eth', 'crypto', 'cryptocurrency',
'altcoin', 'defi', 'nft', 'blockchain', 'hodl', 'diamond hands'
]
async def collect_twitter_sentiment(self, coin_symbol: str, hours: int = 24) -> Dict:
"""Collect and analyze Twitter sentiment for a specific coin"""
# This would integrate with Twitter API v2
# For demo purposes, we'll simulate social media data
sample_tweets = [
f"{coin_symbol} is going to the moon! Best investment ever! 🚀",
f"I'm scared about {coin_symbol} dump coming soon...",
f"Just bought more {coin_symbol} on the dip! Diamond hands! 💎",
f"{coin_symbol} looking bearish, might sell soon",
f"HODL {coin_symbol} no matter what! This is the way!"
]
sentiment_scores = []
emotional_context = []
for tweet in sample_tweets:
analysis = await self.tracker.analyze_text_sentiment(
tweet,
context="social media post"
)
sentiment_scores.append(analysis['sentiment_score'])
emotional_context.append(analysis['emotion_type'])
# Calculate aggregated sentiment
avg_sentiment = np.mean(sentiment_scores)
# Count emotion types
emotion_counts = pd.Series(emotional_context).value_counts()
return {
'average_sentiment': avg_sentiment,
'total_posts': len(sample_tweets),
'emotion_distribution': emotion_counts.to_dict(),
'sentiment_trend': self._calculate_sentiment_trend(sentiment_scores),
'greed_ratio': emotion_counts.get('greed', 0) / len(sample_tweets),
'fear_ratio': emotion_counts.get('fear', 0) / len(sample_tweets)
}
def _calculate_sentiment_trend(self, scores: List[float]) -> str:
"""Calculate if sentiment is trending up or down"""
if len(scores) < 2:
return "neutral"
# Simple trend calculation
recent_avg = np.mean(scores[-3:])
earlier_avg = np.mean(scores[:-3]) if len(scores) > 3 else np.mean(scores)
if recent_avg > earlier_avg + 0.5:
return "increasing_greed"
elif recent_avg < earlier_avg - 0.5:
return "increasing_fear"
else:
return "stable"
Technical Indicators Integration
Technical indicators provide objective market data that complements subjective sentiment analysis. Here's how to integrate them:
import yfinance as yf
import pandas_ta as ta
class TechnicalIndicatorAnalyzer:
"""Analyze technical indicators for fear/greed signals"""
def __init__(self):
self.indicators = {}
def fetch_market_data(self, symbol: str = "BTC-USD", period: str = "30d") -> pd.DataFrame:
"""Fetch cryptocurrency market data"""
ticker = yf.Ticker(symbol)
df = ticker.history(period=period)
# Calculate technical indicators
df['rsi'] = ta.rsi(df['Close'])
df['bb_upper'], df['bb_middle'], df['bb_lower'] = ta.bbands(df['Close'])
df['macd'], df['macd_signal'], df['macd_histogram'] = ta.macd(df['Close'])
df['volatility'] = df['Close'].pct_change().rolling(14).std() * 100
return df
def calculate_fear_greed_score(self, df: pd.DataFrame) -> Dict:
"""Calculate fear/greed score from technical indicators"""
latest = df.iloc[-1]
# RSI Analysis (30-70 range)
rsi_score = self._rsi_to_sentiment(latest['rsi'])
# Bollinger Bands Analysis
bb_score = self._bollinger_to_sentiment(
latest['Close'],
latest['bb_upper'],
latest['bb_lower']
)
# MACD Analysis
macd_score = self._macd_to_sentiment(
latest['macd'],
latest['macd_signal']
)
# Volatility Analysis
volatility_score = self._volatility_to_sentiment(latest['volatility'])
# Volume Analysis
volume_score = self._volume_to_sentiment(df)
# Weighted average
technical_score = (
rsi_score * 0.25 +
bb_score * 0.20 +
macd_score * 0.20 +
volatility_score * 0.20 +
volume_score * 0.15
)
return {
'technical_sentiment': technical_score,
'rsi_sentiment': rsi_score,
'bollinger_sentiment': bb_score,
'macd_sentiment': macd_score,
'volatility_sentiment': volatility_score,
'volume_sentiment': volume_score,
'current_rsi': latest['rsi'],
'current_volatility': latest['volatility']
}
def _rsi_to_sentiment(self, rsi: float) -> float:
"""Convert RSI to sentiment score (1-10)"""
if rsi >= 70:
return 8.5 # Overbought = high greed
elif rsi <= 30:
return 2.0 # Oversold = high fear
else:
# Linear interpolation between 30-70
return 2.0 + (rsi - 30) * (8.5 - 2.0) / (70 - 30)
def _bollinger_to_sentiment(self, price: float, upper: float, lower: float) -> float:
"""Convert Bollinger Band position to sentiment"""
bb_position = (price - lower) / (upper - lower)
if bb_position >= 0.8:
return 8.0 # Near upper band = greed
elif bb_position <= 0.2:
return 2.5 # Near lower band = fear
else:
return 3.0 + bb_position * 4.0 # Linear scaling
def _macd_to_sentiment(self, macd: float, signal: float) -> float:
"""Convert MACD to sentiment score"""
if macd > signal:
return 6.5 # Bullish crossover = mild greed
else:
return 3.5 # Bearish crossover = mild fear
def _volatility_to_sentiment(self, volatility: float) -> float:
"""Convert volatility to sentiment (high vol = fear)"""
if volatility > 5:
return 2.0 # High volatility = fear
elif volatility < 1:
return 7.0 # Low volatility = complacency/greed
else:
return 7.0 - (volatility - 1) * 5.0 / 4.0
def _volume_to_sentiment(self, df: pd.DataFrame) -> float:
"""Analyze volume patterns for sentiment"""
recent_volume = df['Volume'].tail(7).mean()
historical_volume = df['Volume'].head(-7).mean()
volume_ratio = recent_volume / historical_volume
if volume_ratio > 1.5:
return 8.0 # High volume = FOMO/greed
elif volume_ratio < 0.5:
return 3.0 # Low volume = apathy/fear
else:
return 5.0 # Normal volume = neutral
News Sentiment Analysis
News sentiment often precedes price movements. Here's how to analyze crypto news with Ollama:
import feedparser
import asyncio
from datetime import datetime
class NewsAnalyzer:
"""Analyze crypto news sentiment"""
def __init__(self, sentiment_tracker: CryptoSentimentTracker):
self.tracker = sentiment_tracker
self.news_sources = [
'https://cointelegraph.com/rss',
'https://coindesk.com/arc/outboundfeeds/rss/',
'https://decrypt.co/feed'
]
async def analyze_news_sentiment(self, hours: int = 24) -> Dict:
"""Analyze recent crypto news sentiment"""
all_articles = []
# Collect articles from all sources
for source_url in self.news_sources:
try:
feed = feedparser.parse(source_url)
for entry in feed.entries[:10]: # Latest 10 articles per source
article_time = datetime(*entry.published_parsed[:6])
# Only analyze recent articles
if (datetime.now() - article_time).total_seconds() < hours * 3600:
all_articles.append({
'title': entry.title,
'summary': entry.summary if hasattr(entry, 'summary') else '',
'published': article_time,
'source': source_url
})
except Exception as e:
print(f"Error parsing {source_url}: {e}")
continue
# Analyze sentiment for each article
sentiment_scores = []
article_analyses = []
for article in all_articles:
analysis = await self.tracker.analyze_text_sentiment(
f"Title: {article['title']}\nSummary: {article['summary'][:200]}",
context="news article"
)
sentiment_scores.append(analysis['sentiment_score'])
article_analyses.append({
'title': article['title'],
'sentiment': analysis['sentiment_score'],
'emotion': analysis['emotion_type'],
'key_phrases': analysis['key_phrases'],
'published': article['published']
})
# Calculate news sentiment metrics
avg_sentiment = np.mean(sentiment_scores) if sentiment_scores else 5.0
return {
'news_sentiment': avg_sentiment,
'total_articles': len(all_articles),
'article_analyses': article_analyses,
'sentiment_distribution': self._calculate_sentiment_distribution(sentiment_scores),
'trending_topics': self._extract_trending_topics(article_analyses)
}
def _calculate_sentiment_distribution(self, scores: List[float]) -> Dict:
"""Calculate distribution of sentiment scores"""
if not scores:
return {'fear': 0, 'neutral': 0, 'greed': 0}
fear_count = sum(1 for score in scores if score <= 3)
greed_count = sum(1 for score in scores if score >= 7)
neutral_count = len(scores) - fear_count - greed_count
total = len(scores)
return {
'fear': fear_count / total,
'neutral': neutral_count / total,
'greed': greed_count / total
}
def _extract_trending_topics(self, analyses: List[Dict]) -> List[str]:
"""Extract trending topics from news articles"""
all_phrases = []
for analysis in analyses:
all_phrases.extend(analysis['key_phrases'])
# Count phrase frequency
phrase_counts = pd.Series(all_phrases).value_counts()
return phrase_counts.head(5).index.tolist()
Creating the Master Fear & Greed Index
Now let's combine all components into a comprehensive fear and greed index:
class MasterFearGreedIndex:
"""Master class combining all sentiment indicators"""
def __init__(self):
self.sentiment_tracker = CryptoSentimentTracker()
self.social_analyzer = SocialMediaAnalyzer(self.sentiment_tracker)
self.technical_analyzer = TechnicalIndicatorAnalyzer()
self.news_analyzer = NewsAnalyzer(self.sentiment_tracker)
async def calculate_master_index(self, symbol: str = "BTC") -> Dict:
"""Calculate comprehensive fear and greed index"""
print(f"Calculating Fear & Greed Index for {symbol}...")
# Gather all sentiment data
results = await asyncio.gather(
self.social_analyzer.collect_twitter_sentiment(symbol),
self.news_analyzer.analyze_news_sentiment(),
return_exceptions=True
)
social_data = results[0] if not isinstance(results[0], Exception) else {}
news_data = results[1] if not isinstance(results[1], Exception) else {}
# Get technical data
market_df = self.technical_analyzer.fetch_market_data(f"{symbol}-USD")
technical_data = self.technical_analyzer.calculate_fear_greed_score(market_df)
# Extract individual scores
social_score = social_data.get('average_sentiment', 5.0)
technical_score = technical_data.get('technical_sentiment', 5.0)
news_score = news_data.get('news_sentiment', 5.0)
# Calculate weighted master score
weights = {
'social': 0.35,
'technical': 0.40,
'news': 0.25
}
master_score = (
social_score * weights['social'] +
technical_score * weights['technical'] +
news_score * weights['news']
)
# Determine sentiment label
sentiment_label = self._score_to_label(master_score)
return {
'master_score': round(master_score, 2),
'sentiment_label': sentiment_label,
'component_scores': {
'social_sentiment': round(social_score, 2),
'technical_sentiment': round(technical_score, 2),
'news_sentiment': round(news_score, 2)
},
'detailed_analysis': {
'social': social_data,
'technical': technical_data,
'news': news_data
},
'trading_signal': self._generate_trading_signal(master_score),
'timestamp': datetime.now().isoformat()
}
def _score_to_label(self, score: float) -> str:
"""Convert numeric score to sentiment label"""
if score <= 2:
return "Extreme Fear"
elif score <= 4:
return "Fear"
elif score <= 6:
return "Neutral"
elif score <= 8:
return "Greed"
else:
return "Extreme Greed"
def _generate_trading_signal(self, score: float) -> Dict:
"""Generate trading signals based on fear/greed score"""
if score <= 2.5:
return {
'signal': 'STRONG_BUY',
'reasoning': 'Extreme fear often signals market bottoms',
'confidence': 0.8
}
elif score <= 4:
return {
'signal': 'BUY',
'reasoning': 'Fear presents buying opportunities',
'confidence': 0.6
}
elif score >= 7.5:
return {
'signal': 'STRONG_SELL',
'reasoning': 'Extreme greed often signals market tops',
'confidence': 0.8
}
elif score >= 6.5:
return {
'signal': 'SELL',
'reasoning': 'Greed suggests overvaluation',
'confidence': 0.6
}
else:
return {
'signal': 'HOLD',
'reasoning': 'Neutral sentiment, wait for clearer signals',
'confidence': 0.4
}
Running Your Custom Fear & Greed Index
Here's how to run your complete sentiment tracker:
async def main():
"""Run the complete fear and greed analysis"""
# Initialize the master index
master_index = MasterFearGreedIndex()
# Calculate for Bitcoin
btc_analysis = await master_index.calculate_master_index("BTC")
# Display results
print("="*60)
print("CUSTOM CRYPTO FEAR & GREED INDEX")
print("="*60)
print(f"Asset: Bitcoin (BTC)")
print(f"Master Score: {btc_analysis['master_score']}/10")
print(f"Sentiment: {btc_analysis['sentiment_label']}")
print(f"Trading Signal: {btc_analysis['trading_signal']['signal']}")
print(f"Reasoning: {btc_analysis['trading_signal']['reasoning']}")
print()
print("Component Breakdown:")
print(f" Social Media: {btc_analysis['component_scores']['social_sentiment']}/10")
print(f" Technical: {btc_analysis['component_scores']['technical_sentiment']}/10")
print(f" News: {btc_analysis['component_scores']['news_sentiment']}/10")
print()
# Show detailed technical analysis
technical = btc_analysis['detailed_analysis']['technical']
print("Technical Details:")
print(f" RSI: {technical['current_rsi']:.1f}")
print(f" Volatility: {technical['current_volatility']:.1f}%")
print()
# Show social media insights
social = btc_analysis['detailed_analysis']['social']
if social:
print("Social Media Insights:")
print(f" Posts Analyzed: {social['total_posts']}")
print(f" Greed Ratio: {social['greed_ratio']:.2f}")
print(f" Fear Ratio: {social['fear_ratio']:.2f}")
print(f" Trend: {social['sentiment_trend']}")
print("="*60)
# Run the analysis
if __name__ == "__main__":
asyncio.run(main())
Example output:
============================================================
CUSTOM CRYPTO FEAR & GREED INDEX
============================================================
Asset: Bitcoin (BTC)
Master Score: 7.2/10
Sentiment: Greed
Trading Signal: SELL
Reasoning: Greed suggests overvaluation
Component Breakdown:
Social Media: 8.1/10
Technical: 6.8/10
News: 6.7/10
Technical Details:
RSI: 72.3
Volatility: 3.2%
Social Media Insights:
Posts Analyzed: 5
Greed Ratio: 0.60
Fear Ratio: 0.20
Trend: increasing_greed
============================================================
Advanced Features and Customization
Dynamic Weight Adjustment
Market conditions change, so your index weights should adapt:
class AdaptiveWeightManager:
"""Dynamically adjust component weights based on market conditions"""
def __init__(self):
self.base_weights = {
'social': 0.35,
'technical': 0.40,
'news': 0.25
}
def adjust_weights(self, market_data: Dict) -> Dict:
"""Adjust weights based on market volatility and phase"""
volatility = market_data.get('current_volatility', 3.0)
# During high volatility, trust technical indicators more
if volatility > 6:
return {
'social': 0.25,
'technical': 0.50,
'news': 0.25
}
# During low volatility, social sentiment becomes more important
elif volatility < 2:
return {
'social': 0.50,
'technical': 0.25,
'news': 0.25
}
else:
return self.base_weights
Historical Tracking and Backtesting
Track your index performance over time:
class PerformanceTracker:
"""Track fear/greed index performance and trading signals"""
def __init__(self):
self.history = []
def log_analysis(self, analysis: Dict, price: float):
"""Log analysis results with current price"""
self.history.append({
'timestamp': datetime.now(),
'score': analysis['master_score'],
'sentiment': analysis['sentiment_label'],
'signal': analysis['trading_signal']['signal'],
'price': price,
'components': analysis['component_scores']
})
def calculate_signal_performance(self, days: int = 30) -> Dict:
"""Calculate how well trading signals performed"""
if len(self.history) < 2:
return {"error": "Not enough data"}
# Filter recent signals
cutoff_date = datetime.now() - timedelta(days=days)
recent_signals = [
h for h in self.history
if h['timestamp'] > cutoff_date
]
# Calculate returns for each signal type
signal_returns = {'BUY': [], 'SELL': [], 'HOLD': []}
for i, signal in enumerate(recent_signals[:-1]):
next_signal = recent_signals[i + 1]
# Calculate return
price_change = (next_signal['price'] - signal['price']) / signal['price']
if signal['signal'] in ['BUY', 'STRONG_BUY']:
signal_returns['BUY'].append(price_change)
elif signal['signal'] in ['SELL', 'STRONG_SELL']:
signal_returns['SELL'].append(-price_change) # Inverse for short
else:
signal_returns['HOLD'].append(0)
# Calculate performance metrics
performance = {}
for signal_type, returns in signal_returns.items():
if returns:
performance[signal_type] = {
'avg_return': np.mean(returns),
'success_rate': sum(1 for r in returns if r > 0) / len(returns),
'total_signals': len(returns)
}
return performance
Deployment and Automation
Setting Up Automated Analysis
Create a scheduled task to run your analysis:
import schedule
import time
from datetime import datetime
class AutomatedTracker:
"""Automated fear/greed index tracking"""
def __init__(self):
self.master_index = MasterFearGreedIndex()
self.performance_tracker = PerformanceTracker()
async def run_analysis(self):
"""Run complete analysis and log results"""
try:
# Get current Bitcoin price
btc_price = self.get_current_price("BTC-USD")
# Run fear/greed analysis
analysis = await self.master_index.calculate_master_index("BTC")
# Log for performance tracking
self.performance_tracker.log_analysis(analysis, btc_price)
# Check for significant signals
if analysis['trading_signal']['confidence'] > 0.7:
await self.send_alert(analysis, btc_price)
print(f"Analysis completed at {datetime.now()}")
print(f"Score: {analysis['master_score']} | Signal: {analysis['trading_signal']['signal']}")
except Exception as e:
print(f"Error in analysis: {e}")
def get_current_price(self, symbol: str) -> float:
"""Get current cryptocurrency price"""
try:
ticker = yf.Ticker(symbol)
data = ticker.history(period="1d")
return float(data['Close'].iloc[-1])
except:
return 0.0
async def send_alert(self, analysis: Dict, price: float):
"""Send alert for significant signals"""
signal = analysis['trading_signal']
message = f"""
🚨 CRYPTO FEAR & GREED ALERT 🚨
Score: {analysis['master_score']}/10 ({analysis['sentiment_label']})
Signal: {signal['signal']}
Confidence: {signal['confidence']:.0%}
Current BTC Price: ${price:,.2f}
Reasoning: {signal['reasoning']}
Component Breakdown:
📱 Social: {analysis['component_scores']['social_sentiment']}/10
📊 Technical: {analysis['component_scores']['technical_sentiment']}/10
📰 News: {analysis['component_scores']['news_sentiment']}/10
"""
# Send to Discord, Slack, or email
await self.send_to_discord(message)
async def send_to_discord(self, message: str):
"""Send alert to Discord webhook"""
webhook_url = "YOUR_DISCORD_WEBHOOK_URL"
if not webhook_url or webhook_url == "YOUR_DISCORD_WEBHOOK_URL":
print("Discord webhook not configured")
print(message)
return
async with aiohttp.ClientSession() as session:
async with session.post(webhook_url, json={"content": message}) as response:
if response.status == 204:
print("Alert sent to Discord")
else:
print(f"Failed to send Discord alert: {response.status}")
# Set up automated scheduling
def setup_automation():
"""Set up automated fear/greed analysis"""
tracker = AutomatedTracker()
# Schedule analysis every 4 hours
schedule.every(4).hours.do(lambda: asyncio.run(tracker.run_analysis()))
# Schedule daily performance report
schedule.every().day.at("09:00").do(lambda: asyncio.run(tracker.generate_daily_report()))
print("Automated tracking started...")
print("Analysis will run every 4 hours")
print("Daily reports at 9:00 AM")
while True:
schedule.run_pending()
time.sleep(60) # Check every minute
# Add daily report method to AutomatedTracker
async def generate_daily_report(self):
"""Generate daily performance report"""
performance = self.performance_tracker.calculate_signal_performance(7)
if 'error' in performance:
print("Not enough data for performance report")
return
report = f"""
📊 WEEKLY FEAR & GREED PERFORMANCE REPORT
Signal Performance (Last 7 Days):
"""
for signal_type, metrics in performance.items():
report += f"""
{signal_type} Signals:
• Average Return: {metrics['avg_return']:.2%}
• Success Rate: {metrics['success_rate']:.1%}
• Total Signals: {metrics['total_signals']}
"""
await self.send_to_discord(report)
Web Dashboard Creation
Create a web interface to visualize your fear/greed index:
from flask import Flask, render_template, jsonify
import plotly.graph_objs as go
import plotly.utils
app = Flask(__name__)
class FearGreedDashboard:
"""Web dashboard for fear/greed index"""
def __init__(self):
self.master_index = MasterFearGreedIndex()
self.performance_tracker = PerformanceTracker()
@app.route('/')
def dashboard():
return render_template('dashboard.html')
@app.route('/api/current-analysis')
async def get_current_analysis():
"""API endpoint for current analysis"""
try:
analysis = await self.master_index.calculate_master_index("BTC")
return jsonify(analysis)
except Exception as e:
return jsonify({"error": str(e)}), 500
@app.route('/api/historical-data')
def get_historical_data():
"""API endpoint for historical data"""
# Get last 30 days of data
history = self.performance_tracker.history[-30:]
return jsonify({
'timestamps': [h['timestamp'].isoformat() for h in history],
'scores': [h['score'] for h in history],
'prices': [h['price'] for h in history],
'signals': [h['signal'] for h in history]
})
@app.route('/api/performance-chart')
def get_performance_chart():
"""Generate performance chart"""
history = self.performance_tracker.history[-30:]
if not history:
return jsonify({"error": "No data available"})
# Create plotly chart
fig = go.Figure()
# Add fear/greed score
fig.add_trace(go.Scatter(
x=[h['timestamp'] for h in history],
y=[h['score'] for h in history],
mode='lines+markers',
name='Fear/Greed Score',
line=dict(color='blue'),
yaxis='y1'
))
# Add price on secondary y-axis
fig.add_trace(go.Scatter(
x=[h['timestamp'] for h in history],
y=[h['price'] for h in history],
mode='lines',
name='BTC Price',
line=dict(color='orange'),
yaxis='y2'
))
# Add trading signals as markers
buy_signals = [h for h in history if 'BUY' in h['signal']]
sell_signals = [h for h in history if 'SELL' in h['signal']]
if buy_signals:
fig.add_trace(go.Scatter(
x=[h['timestamp'] for h in buy_signals],
y=[h['price'] for h in buy_signals],
mode='markers',
name='Buy Signals',
marker=dict(color='green', size=10, symbol='triangle-up'),
yaxis='y2'
))
if sell_signals:
fig.add_trace(go.Scatter(
x=[h['timestamp'] for h in sell_signals],
y=[h['price'] for h in sell_signals],
mode='markers',
name='Sell Signals',
marker=dict(color='red', size=10, symbol='triangle-down'),
yaxis='y2'
))
# Update layout
fig.update_layout(
title='Fear/Greed Index vs Bitcoin Price',
xaxis_title='Date',
yaxis=dict(title='Fear/Greed Score', side='left'),
yaxis2=dict(title='BTC Price ($)', side='right', overlaying='y'),
hovermode='x unified'
)
return jsonify(plotly.utils.PlotlyJSONEncoder().encode(fig))
if __name__ == '__main__':
app.run(debug=True, port=5000)
Create the HTML template (templates/dashboard.html):
<!DOCTYPE html>
<html>
<head>
<title>Crypto Fear & Greed Dashboard</title>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.metric-card {
display: inline-block;
margin: 10px;
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
min-width: 200px;
}
.score { font-size: 2em; font-weight: bold; }
.fear { color: #ff4444; }
.greed { color: #44ff44; }
.neutral { color: #666; }
#chart { height: 500px; margin: 20px 0; }
</style>
</head>
<body>
<h1>🚀 Crypto Fear & Greed Index Dashboard</h1>
<div id="current-metrics">
<div class="metric-card">
<h3>Master Score</h3>
<div id="master-score" class="score">Loading...</div>
<div id="sentiment-label">Loading...</div>
</div>
<div class="metric-card">
<h3>Trading Signal</h3>
<div id="trading-signal" class="score">Loading...</div>
<div id="signal-confidence">Loading...</div>
</div>
<div class="metric-card">
<h3>Social Sentiment</h3>
<div id="social-score" class="score">Loading...</div>
</div>
<div class="metric-card">
<h3>Technical Score</h3>
<div id="technical-score" class="score">Loading...</div>
</div>
</div>
<div id="chart"></div>
<script>
// Load current analysis
async function loadCurrentAnalysis() {
try {
const response = await fetch('/api/current-analysis');
const data = await response.json();
document.getElementById('master-score').textContent = data.master_score;
document.getElementById('sentiment-label').textContent = data.sentiment_label;
document.getElementById('trading-signal').textContent = data.trading_signal.signal;
document.getElementById('signal-confidence').textContent =
`Confidence: ${(data.trading_signal.confidence * 100).toFixed(0)}%`;
document.getElementById('social-score').textContent =
data.component_scores.social_sentiment;
document.getElementById('technical-score').textContent =
data.component_scores.technical_sentiment;
// Color code the master score
const scoreElement = document.getElementById('master-score');
if (data.master_score <= 4) {
scoreElement.className = 'score fear';
} else if (data.master_score >= 7) {
scoreElement.className = 'score greed';
} else {
scoreElement.className = 'score neutral';
}
} catch (error) {
console.error('Error loading analysis:', error);
}
}
// Load performance chart
async function loadChart() {
try {
const response = await fetch('/api/performance-chart');
const chartData = await response.json();
Plotly.newPlot('chart', chartData.data, chartData.layout);
} catch (error) {
console.error('Error loading chart:', error);
}
}
// Initialize dashboard
loadCurrentAnalysis();
loadChart();
// Refresh every 5 minutes
setInterval(loadCurrentAnalysis, 5 * 60 * 1000);
</script>
</body>
</html>
Advanced Signal Generation
Multi-Timeframe Analysis
Enhance your signals by analyzing multiple timeframes:
class MultiTimeframeAnalyzer:
"""Analyze fear/greed across multiple timeframes"""
def __init__(self, master_index: MasterFearGreedIndex):
self.master_index = master_index
async def analyze_multiple_timeframes(self, symbol: str) -> Dict:
"""Analyze fear/greed across different timeframes"""
timeframes = {
'1h': {'social_hours': 1, 'news_hours': 4, 'market_period': '5d'},
'4h': {'social_hours': 4, 'news_hours': 12, 'market_period': '30d'},
'1d': {'social_hours': 24, 'news_hours': 48, 'market_period': '90d'},
'1w': {'social_hours': 168, 'news_hours': 168, 'market_period': '1y'}
}
results = {}
for timeframe, params in timeframes.items():
# Customize analysis parameters for each timeframe
self.master_index.social_analyzer.hours = params['social_hours']
self.master_index.news_analyzer.hours = params['news_hours']
# Run analysis
analysis = await self.master_index.calculate_master_index(symbol)
results[timeframe] = {
'score': analysis['master_score'],
'sentiment': analysis['sentiment_label'],
'signal': analysis['trading_signal']['signal'],
'confidence': analysis['trading_signal']['confidence']
}
# Generate consensus signal
consensus = self._generate_consensus_signal(results)
return {
'timeframe_analysis': results,
'consensus_signal': consensus,
'signal_strength': self._calculate_signal_strength(results)
}
def _generate_consensus_signal(self, results: Dict) -> Dict:
"""Generate consensus signal from multiple timeframes"""
signals = [data['signal'] for data in results.values()]
confidences = [data['confidence'] for data in results.values()]
# Weight signals by timeframe importance
weights = {'1h': 0.1, '4h': 0.2, '1d': 0.4, '1w': 0.3}
buy_weight = 0
sell_weight = 0
for timeframe, signal_data in results.items():
weight = weights[timeframe]
signal = signal_data['signal']
confidence = signal_data['confidence']
if 'BUY' in signal:
buy_weight += weight * confidence
elif 'SELL' in signal:
sell_weight += weight * confidence
# Determine consensus
if buy_weight > sell_weight + 0.2:
return {'signal': 'BUY', 'confidence': buy_weight}
elif sell_weight > buy_weight + 0.2:
return {'signal': 'SELL', 'confidence': sell_weight}
else:
return {'signal': 'HOLD', 'confidence': 0.5}
def _calculate_signal_strength(self, results: Dict) -> float:
"""Calculate overall signal strength"""
scores = [data['score'] for data in results.values()]
# Calculate agreement between timeframes
score_std = np.std(scores)
# Lower standard deviation = higher agreement = stronger signal
strength = max(0, 1 - (score_std / 3))
return strength
Risk Management Integration
Add risk management features to your signals:
class RiskManager:
"""Risk management for fear/greed trading signals"""
def __init__(self):
self.max_position_size = 0.1 # 10% of portfolio
self.stop_loss_percent = 0.05 # 5% stop loss
self.take_profit_percent = 0.15 # 15% take profit
def calculate_position_size(self,
signal_confidence: float,
volatility: float,
account_balance: float) -> Dict:
"""Calculate optimal position size based on signal and risk"""
# Base position size on confidence
base_size = signal_confidence * self.max_position_size
# Adjust for volatility
volatility_adjustment = max(0.1, 1 - (volatility / 10))
adjusted_size = base_size * volatility_adjustment
# Calculate dollar amount
dollar_amount = account_balance * adjusted_size
return {
'position_size_percent': adjusted_size,
'dollar_amount': dollar_amount,
'stop_loss_price': None, # Set after entry
'take_profit_price': None, # Set after entry
'risk_reward_ratio': self.take_profit_percent / self.stop_loss_percent
}
def set_exit_levels(self, entry_price: float, signal_type: str) -> Dict:
"""Set stop loss and take profit levels"""
if signal_type in ['BUY', 'STRONG_BUY']:
stop_loss = entry_price * (1 - self.stop_loss_percent)
take_profit = entry_price * (1 + self.take_profit_percent)
else: # SELL signals
stop_loss = entry_price * (1 + self.stop_loss_percent)
take_profit = entry_price * (1 - self.take_profit_percent)
return {
'stop_loss': stop_loss,
'take_profit': take_profit,
'risk_amount': abs(entry_price - stop_loss),
'reward_amount': abs(take_profit - entry_price)
}
Conclusion
Building a custom crypto fear and greed index with Ollama gives you several advantages over using the standard index. You control the data sources, can weight different factors based on market conditions, and integrate real-time AI analysis that understands crypto-specific sentiment.
Your custom tracker analyzes social media sentiment with context-aware AI, combines technical indicators with adaptive weightings, processes news sentiment for early signals, and generates actionable trading signals with confidence scores. The system runs locally with Ollama, protecting your privacy while providing fast, customizable analysis.
The key to success is continuous refinement. Monitor your signal performance, adjust weightings based on market conditions, and add new data sources as they become available. Remember that no sentiment indicator is perfect, but combining multiple sources with AI analysis gives you a significant edge in understanding market psychology.
Start with the basic implementation, then gradually add the advanced features like multi-timeframe analysis, risk management, and automated alerts. Your custom fear and greed index will become more accurate as you feed it more data and refine the analysis components.
Market sentiment drives crypto prices more than fundamentals. With your custom Ollama-powered sentiment tracker, you'll have the tools to profit from the eternal cycle of fear and greed that governs cryptocurrency markets.