Picture this: You're hunched over your computer at 2 AM, squinting at candlestick charts while your coffee has gone cold for the third time. Your eyes burn from analyzing RSI divergences, MACD crossovers, and Bollinger Band squeezes. Sound familiar?
What if I told you that Ollama could automate this entire process, turning your sleepless nights into automated insights?
Traditional technical analysis requires constant monitoring and manual interpretation. Traders spend hours analyzing price movements, calculating indicators, and identifying patterns. This manual approach leads to missed opportunities, emotional decisions, and trader fatigue.
Ollama changes this game entirely. By automating RSI calculations, MACD signal detection, and Bollinger Band analysis, you transform from a chart-watching zombie into a strategic decision-maker. This guide shows you exactly how to build an intelligent technical analysis system that works while you sleep.
What Makes Ollama Perfect for Technical Analysis Automation
Ollama excels at pattern recognition and data interpretation - exactly what technical analysis requires. Unlike traditional trading bots that follow rigid rules, Ollama understands context and adapts to market conditions.
Key Advantages of Ollama for Trading Automation
Advanced Pattern Recognition: Ollama identifies complex chart patterns that simple algorithms miss. It recognizes head and shoulders formations, triangle breakouts, and support/resistance levels with remarkable accuracy.
Natural Language Processing: Convert technical analysis results into plain English explanations. Instead of raw numbers, receive clear insights like "Strong bullish divergence detected on RSI with MACD confirming upward momentum."
Multi-Timeframe Analysis: Ollama processes data across multiple timeframes simultaneously, providing comprehensive market context that manual analysis often overlooks.
Contextual Decision Making: Unlike mechanical trading systems, Ollama considers market sentiment, news events, and broader economic factors when interpreting technical indicators.
Setting Up Your Ollama Technical Analysis Environment
Before automating technical indicators, establish your development environment with proper data sources and Ollama integration.
Installing Required Dependencies
# Install essential packages for technical analysis automation
pip install ollama yfinance pandas numpy ta-lib matplotlib plotly
# Verify Ollama installation
import ollama
print(ollama.list())
Data Source Configuration
import yfinance as yf
import pandas as pd
import numpy as np
import talib
from datetime import datetime, timedelta
class MarketDataProvider:
def __init__(self):
self.symbols = []
def fetch_price_data(self, symbol, period="1y", interval="1d"):
"""
Fetch historical price data for technical analysis
Args:
symbol: Stock/crypto symbol (e.g., 'AAPL', 'BTC-USD')
period: Data period ('1d', '5d', '1mo', '3mo', '6mo', '1y', '2y', '5y', '10y', 'ytd', 'max')
interval: Data interval ('1m', '2m', '5m', '15m', '30m', '60m', '90m', '1h', '1d', '5d', '1wk', '1mo', '3mo')
"""
try:
ticker = yf.Ticker(symbol)
data = ticker.history(period=period, interval=interval)
if data.empty:
raise ValueError(f"No data found for symbol {symbol}")
# Clean and prepare data
data = data.dropna()
data.columns = data.columns.str.lower()
return data
except Exception as e:
print(f"Error fetching data for {symbol}: {str(e)}")
return None
Ollama Model Selection
# Configure Ollama for technical analysis tasks
OLLAMA_MODEL = "llama3.1:8b" # Recommended for financial analysis
OLLAMA_ENDPOINT = "http://localhost:11434"
def initialize_ollama():
"""Initialize Ollama client and verify model availability"""
try:
client = ollama.Client(host=OLLAMA_ENDPOINT)
# Check if model is available
models = client.list()
model_names = [model['name'] for model in models['models']]
if OLLAMA_MODEL not in model_names:
print(f"Pulling {OLLAMA_MODEL} model...")
client.pull(OLLAMA_MODEL)
return client
except Exception as e:
print(f"Failed to initialize Ollama: {str(e)}")
return None
Automating RSI Analysis with Ollama
The Relative Strength Index (RSI) measures momentum and identifies overbought/oversold conditions. Automating RSI analysis with Ollama adds intelligent interpretation to raw calculations.
RSI Calculation and Signal Detection
class RSIAnalyzer:
def __init__(self, period=14):
self.period = period
self.overbought_threshold = 70
self.oversold_threshold = 30
def calculate_rsi(self, price_data):
"""Calculate RSI using TA-Lib for accuracy"""
close_prices = price_data['close'].values
rsi_values = talib.RSI(close_prices, timeperiod=self.period)
# Add RSI to dataframe
price_data['rsi'] = rsi_values
return price_data
def detect_rsi_signals(self, price_data):
"""Detect RSI-based trading signals"""
signals = []
rsi_values = price_data['rsi'].values
for i in range(1, len(rsi_values)):
current_rsi = rsi_values[i]
previous_rsi = rsi_values[i-1]
# Overbought to normal transition (sell signal)
if previous_rsi > self.overbought_threshold and current_rsi <= self.overbought_threshold:
signals.append({
'date': price_data.index[i],
'type': 'sell',
'indicator': 'rsi',
'value': current_rsi,
'reason': 'RSI dropped below overbought threshold'
})
# Oversold to normal transition (buy signal)
elif previous_rsi < self.oversold_threshold and current_rsi >= self.oversold_threshold:
signals.append({
'date': price_data.index[i],
'type': 'buy',
'indicator': 'rsi',
'value': current_rsi,
'reason': 'RSI rose above oversold threshold'
})
return signals
def find_rsi_divergences(self, price_data):
"""Detect bullish/bearish RSI divergences"""
divergences = []
prices = price_data['close'].values
rsi_values = price_data['rsi'].values
# Look for divergences in recent data (last 20 periods)
lookback = min(20, len(prices))
recent_prices = prices[-lookback:]
recent_rsi = rsi_values[-lookback:]
# Find local highs and lows
price_highs = self._find_peaks(recent_prices)
price_lows = self._find_troughs(recent_prices)
rsi_highs = self._find_peaks(recent_rsi)
rsi_lows = self._find_troughs(recent_rsi)
# Check for bearish divergence (price makes higher highs, RSI makes lower highs)
if len(price_highs) >= 2 and len(rsi_highs) >= 2:
if (recent_prices[price_highs[-1]] > recent_prices[price_highs[-2]] and
recent_rsi[rsi_highs[-1]] < recent_rsi[rsi_highs[-2]]):
divergences.append({
'type': 'bearish',
'strength': 'strong' if abs(recent_rsi[rsi_highs[-1]] - recent_rsi[rsi_highs[-2]]) > 5 else 'weak'
})
# Check for bullish divergence (price makes lower lows, RSI makes higher lows)
if len(price_lows) >= 2 and len(rsi_lows) >= 2:
if (recent_prices[price_lows[-1]] < recent_prices[price_lows[-2]] and
recent_rsi[rsi_lows[-1]] > recent_rsi[rsi_lows[-2]]):
divergences.append({
'type': 'bullish',
'strength': 'strong' if abs(recent_rsi[rsi_lows[-1]] - recent_rsi[rsi_lows[-2]]) > 5 else 'weak'
})
return divergences
def _find_peaks(self, data, min_distance=3):
"""Find local peaks in data"""
peaks = []
for i in range(min_distance, len(data) - min_distance):
is_peak = True
for j in range(i - min_distance, i + min_distance + 1):
if j != i and data[j] >= data[i]:
is_peak = False
break
if is_peak:
peaks.append(i)
return peaks
def _find_troughs(self, data, min_distance=3):
"""Find local troughs in data"""
troughs = []
for i in range(min_distance, len(data) - min_distance):
is_trough = True
for j in range(i - min_distance, i + min_distance + 1):
if j != i and data[j] <= data[i]:
is_trough = False
break
if is_trough:
troughs.append(i)
return troughs
Intelligent RSI Interpretation with Ollama
def analyze_rsi_with_ollama(price_data, signals, divergences, ollama_client):
"""Use Ollama to provide intelligent RSI analysis"""
current_rsi = price_data['rsi'].iloc[-1]
rsi_trend = "increasing" if price_data['rsi'].iloc[-1] > price_data['rsi'].iloc[-2] else "decreasing"
# Prepare context for Ollama
context = f"""
Current RSI Analysis:
- Current RSI: {current_rsi:.2f}
- RSI Trend: {rsi_trend}
- Recent Signals: {len(signals)} signals in last 20 periods
- Divergences: {len(divergences)} divergences detected
Signal Details:
{'; '.join([f"{s['type']} signal on {s['date'].strftime('%Y-%m-%d')} (RSI: {s['value']:.2f})" for s in signals[-3:]])}
Divergence Details:
{'; '.join([f"{d['type']} divergence ({d['strength']} strength)" for d in divergences])}
"""
prompt = f"""
Analyze this RSI data and provide actionable trading insights:
{context}
Please provide:
1. Current momentum assessment
2. Probability of trend continuation or reversal
3. Recommended trading actions
4. Risk management considerations
5. Timeframe for next significant move
Keep the analysis practical and specific. Avoid generic advice.
"""
try:
response = ollama_client.generate(model=OLLAMA_MODEL, prompt=prompt)
return response['response']
except Exception as e:
return f"Error generating RSI analysis: {str(e)}"
MACD Automation for Trend Analysis
The Moving Average Convergence Divergence (MACD) identifies trend changes and momentum shifts. Automating MACD analysis provides reliable trend-following signals.
MACD Calculation and Signal Generation
class MACDAnalyzer:
def __init__(self, fast_period=12, slow_period=26, signal_period=9):
self.fast_period = fast_period
self.slow_period = slow_period
self.signal_period = signal_period
def calculate_macd(self, price_data):
"""Calculate MACD line, signal line, and histogram"""
close_prices = price_data['close'].values
# Calculate MACD components using TA-Lib
macd_line, signal_line, histogram = talib.MACD(
close_prices,
fastperiod=self.fast_period,
slowperiod=self.slow_period,
signalperiod=self.signal_period
)
# Add to dataframe
price_data['macd'] = macd_line
price_data['macd_signal'] = signal_line
price_data['macd_histogram'] = histogram
return price_data
def detect_macd_crossovers(self, price_data):
"""Detect MACD line and signal line crossovers"""
crossovers = []
macd_values = price_data['macd'].values
signal_values = price_data['macd_signal'].values
for i in range(1, len(macd_values)):
if np.isnan(macd_values[i]) or np.isnan(signal_values[i]):
continue
current_diff = macd_values[i] - signal_values[i]
previous_diff = macd_values[i-1] - signal_values[i-1]
# Bullish crossover (MACD crosses above signal)
if previous_diff <= 0 and current_diff > 0:
crossovers.append({
'date': price_data.index[i],
'type': 'bullish_crossover',
'macd': macd_values[i],
'signal': signal_values[i],
'strength': abs(current_diff)
})
# Bearish crossover (MACD crosses below signal)
elif previous_diff >= 0 and current_diff < 0:
crossovers.append({
'date': price_data.index[i],
'type': 'bearish_crossover',
'macd': macd_values[i],
'signal': signal_values[i],
'strength': abs(current_diff)
})
return crossovers
def analyze_macd_momentum(self, price_data):
"""Analyze MACD momentum and trend strength"""
histogram = price_data['macd_histogram'].values
# Recent histogram trend (last 5 periods)
recent_histogram = histogram[-5:]
increasing_momentum = all(recent_histogram[i] >= recent_histogram[i-1] for i in range(1, len(recent_histogram)))
decreasing_momentum = all(recent_histogram[i] <= recent_histogram[i-1] for i in range(1, len(recent_histogram)))
# Momentum strength based on histogram magnitude
current_histogram = histogram[-1] if not np.isnan(histogram[-1]) else 0
momentum_strength = abs(current_histogram)
# Trend direction
macd_current = price_data['macd'].iloc[-1]
signal_current = price_data['macd_signal'].iloc[-1]
trend_direction = "bullish" if macd_current > signal_current else "bearish"
return {
'trend_direction': trend_direction,
'momentum_increasing': increasing_momentum,
'momentum_decreasing': decreasing_momentum,
'momentum_strength': momentum_strength,
'current_histogram': current_histogram
}
def detect_macd_divergences(self, price_data):
"""Detect MACD divergences with price action"""
divergences = []
prices = price_data['close'].values
macd_values = price_data['macd'].values
# Analyze last 20 periods for divergences
lookback = min(20, len(prices))
recent_prices = prices[-lookback:]
recent_macd = macd_values[-lookback:]
# Remove NaN values
valid_indices = ~(np.isnan(recent_prices) | np.isnan(recent_macd))
recent_prices = recent_prices[valid_indices]
recent_macd = recent_macd[valid_indices]
if len(recent_prices) < 10: # Need enough data for analysis
return divergences
# Find peaks and troughs
price_peaks = self._find_peaks(recent_prices)
price_troughs = self._find_troughs(recent_prices)
macd_peaks = self._find_peaks(recent_macd)
macd_troughs = self._find_troughs(recent_macd)
# Check for bearish divergence
if len(price_peaks) >= 2 and len(macd_peaks) >= 2:
last_price_peak = price_peaks[-1]
prev_price_peak = price_peaks[-2]
last_macd_peak = macd_peaks[-1]
prev_macd_peak = macd_peaks[-2]
if (recent_prices[last_price_peak] > recent_prices[prev_price_peak] and
recent_macd[last_macd_peak] < recent_macd[prev_macd_peak]):
divergences.append({
'type': 'bearish',
'strength': abs(recent_macd[last_macd_peak] - recent_macd[prev_macd_peak])
})
# Check for bullish divergence
if len(price_troughs) >= 2 and len(macd_troughs) >= 2:
last_price_trough = price_troughs[-1]
prev_price_trough = price_troughs[-2]
last_macd_trough = macd_troughs[-1]
prev_macd_trough = macd_troughs[-2]
if (recent_prices[last_price_trough] < recent_prices[prev_price_trough] and
recent_macd[last_macd_trough] > recent_macd[prev_macd_trough]):
divergences.append({
'type': 'bullish',
'strength': abs(recent_macd[last_macd_trough] - recent_macd[prev_macd_trough])
})
return divergences
Advanced MACD Analysis with Ollama
def analyze_macd_with_ollama(price_data, crossovers, momentum_data, divergences, ollama_client):
"""Generate intelligent MACD analysis using Ollama"""
current_macd = price_data['macd'].iloc[-1]
current_signal = price_data['macd_signal'].iloc[-1]
current_histogram = price_data['macd_histogram'].iloc[-1]
context = f"""
MACD Technical Analysis:
Current Values:
- MACD Line: {current_macd:.4f}
- Signal Line: {current_signal:.4f}
- Histogram: {current_histogram:.4f}
Trend Analysis:
- Current Trend: {momentum_data['trend_direction']}
- Momentum Increasing: {momentum_data['momentum_increasing']}
- Momentum Strength: {momentum_data['momentum_strength']:.4f}
Recent Crossovers:
{'; '.join([f"{co['type']} on {co['date'].strftime('%Y-%m-%d')}" for co in crossovers[-3:]])}
Divergences:
{'; '.join([f"{div['type']} divergence (strength: {div['strength']:.4f})" for div in divergences])}
Price Context:
- Current Price: ${price_data['close'].iloc[-1]:.2f}
- 20-day Price Change: {((price_data['close'].iloc[-1] / price_data['close'].iloc[-20]) - 1) * 100:.2f}%
"""
prompt = f"""
As an expert technical analyst, interpret this MACD data and provide specific trading guidance:
{context}
Provide detailed analysis covering:
1. Current trend strength and direction
2. Probability of trend continuation vs reversal
3. Optimal entry and exit points
4. Stop-loss recommendations
5. Expected timeframe for next significant move
6. Risk-reward assessment
Be specific with price levels and avoid generic technical analysis language.
"""
try:
response = ollama_client.generate(model=OLLAMA_MODEL, prompt=prompt)
return response['response']
except Exception as e:
return f"Error generating MACD analysis: {str(e)}"
Bollinger Bands Automation for Volatility Analysis
Bollinger Bands measure volatility and identify potential support/resistance levels. Automating Bollinger Band analysis helps identify breakouts and mean reversion opportunities.
Bollinger Bands Calculation and Analysis
class BollingerBandsAnalyzer:
def __init__(self, period=20, std_dev=2):
self.period = period
self.std_dev = std_dev
def calculate_bollinger_bands(self, price_data):
"""Calculate Bollinger Bands using TA-Lib"""
close_prices = price_data['close'].values
# Calculate Bollinger Bands
upper_band, middle_band, lower_band = talib.BBANDS(
close_prices,
timeperiod=self.period,
nbdevup=self.std_dev,
nbdevdn=self.std_dev,
matype=0 # Simple Moving Average
)
# Add to dataframe
price_data['bb_upper'] = upper_band
price_data['bb_middle'] = middle_band
price_data['bb_lower'] = lower_band
# Calculate additional metrics
price_data['bb_width'] = (upper_band - lower_band) / middle_band * 100
price_data['bb_position'] = (close_prices - lower_band) / (upper_band - lower_band) * 100
return price_data
def detect_bb_signals(self, price_data):
"""Detect Bollinger Band trading signals"""
signals = []
close_prices = price_data['close'].values
upper_band = price_data['bb_upper'].values
lower_band = price_data['bb_lower'].values
bb_position = price_data['bb_position'].values
for i in range(1, len(close_prices)):
if np.isnan(upper_band[i]) or np.isnan(lower_band[i]):
continue
# Bollinger Band squeeze (low volatility)
current_width = price_data['bb_width'].iloc[i]
avg_width = price_data['bb_width'].iloc[max(0, i-20):i].mean()
if current_width < avg_width * 0.7: # Width 30% below average
signals.append({
'date': price_data.index[i],
'type': 'squeeze',
'description': 'Bollinger Band squeeze detected - low volatility',
'bb_width': current_width
})
# Price touching upper band (potential resistance)
if close_prices[i] >= upper_band[i] * 0.995: # Within 0.5% of upper band
signals.append({
'date': price_data.index[i],
'type': 'upper_band_touch',
'description': 'Price reached upper Bollinger Band',
'bb_position': bb_position[i]
})
# Price touching lower band (potential support)
elif close_prices[i] <= lower_band[i] * 1.005: # Within 0.5% of lower band
signals.append({
'date': price_data.index[i],
'type': 'lower_band_touch',
'description': 'Price reached lower Bollinger Band',
'bb_position': bb_position[i]
})
# Bollinger Band expansion (high volatility)
if current_width > avg_width * 1.5: # Width 50% above average
signals.append({
'date': price_data.index[i],
'type': 'expansion',
'description': 'Bollinger Band expansion - high volatility',
'bb_width': current_width
})
return signals
def analyze_bb_breakouts(self, price_data):
"""Analyze Bollinger Band breakouts"""
breakouts = []
close_prices = price_data['close'].values
upper_band = price_data['bb_upper'].values
lower_band = price_data['bb_lower'].values
volume = price_data['volume'].values if 'volume' in price_data.columns else None
for i in range(1, len(close_prices)):
if np.isnan(upper_band[i]) or np.isnan(lower_band[i]):
continue
# Upward breakout
if (close_prices[i-1] <= upper_band[i-1] and
close_prices[i] > upper_band[i]):
volume_confirmation = True
if volume is not None:
avg_volume = np.mean(volume[max(0, i-10):i])
volume_confirmation = volume[i] > avg_volume * 1.2
breakouts.append({
'date': price_data.index[i],
'type': 'upward_breakout',
'price': close_prices[i],
'band_level': upper_band[i],
'volume_confirmed': volume_confirmation
})
# Downward breakout
elif (close_prices[i-1] >= lower_band[i-1] and
close_prices[i] < lower_band[i]):
volume_confirmation = True
if volume is not None:
avg_volume = np.mean(volume[max(0, i-10):i])
volume_confirmation = volume[i] > avg_volume * 1.2
breakouts.append({
'date': price_data.index[i],
'type': 'downward_breakout',
'price': close_prices[i],
'band_level': lower_band[i],
'volume_confirmed': volume_confirmation
})
return breakouts
def calculate_bb_statistics(self, price_data):
"""Calculate Bollinger Band statistics"""
bb_position = price_data['bb_position'].dropna()
bb_width = price_data['bb_width'].dropna()
# Position statistics
avg_position = bb_position.mean()
position_std = bb_position.std()
# Width statistics
avg_width = bb_width.mean()
current_width = bb_width.iloc[-1]
width_percentile = (bb_width <= current_width).mean() * 100
# Recent behavior
recent_positions = bb_position.tail(10)
trending_up = (recent_positions > 70).any() # Recently in upper region
trending_down = (recent_positions < 30).any() # Recently in lower region
return {
'average_position': avg_position,
'current_position': bb_position.iloc[-1],
'position_volatility': position_std,
'average_width': avg_width,
'current_width': current_width,
'width_percentile': width_percentile,
'recently_overbought': trending_up,
'recently_oversold': trending_down
}
Intelligent Bollinger Bands Analysis with Ollama
def analyze_bollinger_bands_with_ollama(price_data, signals, breakouts, statistics, ollama_client):
"""Generate comprehensive Bollinger Bands analysis using Ollama"""
current_price = price_data['close'].iloc[-1]
current_position = statistics['current_position']
current_width = statistics['current_width']
context = f"""
Bollinger Bands Analysis:
Current Market Position:
- Price: ${current_price:.2f}
- BB Position: {current_position:.1f}% (0% = lower band, 100% = upper band)
- Band Width: {current_width:.2f}% (percentile: {statistics['width_percentile']:.0f}%)
Recent Signals:
{'; '.join([f"{s['type']} on {s['date'].strftime('%Y-%m-%d')}" for s in signals[-5:]])}
Breakout Analysis:
{'; '.join([f"{b['type']} on {b['date'].strftime('%Y-%m-%d')} (volume confirmed: {b['volume_confirmed']})" for b in breakouts[-3:]])}
Statistical Context:
- Average Position: {statistics['average_position']:.1f}%
- Position Volatility: {statistics['position_volatility']:.1f}%
- Recently Overbought: {statistics['recently_overbought']}
- Recently Oversold: {statistics['recently_oversold']}
Volatility Context:
- Current vs Average Width: {((current_width / statistics['average_width']) - 1) * 100:.1f}%
"""
prompt = f"""
Analyze this Bollinger Bands data and provide actionable trading insights:
{context}
Focus on:
1. Current volatility regime (high/low/normal)
2. Mean reversion vs breakout probability
3. Optimal trading strategies for current conditions
4. Support and resistance levels
5. Risk management based on band position
6. Expected volatility changes and timing
Provide specific price targets and stop-loss levels. Consider both scalping and swing trading perspectives.
"""
try:
response = ollama_client.generate(model=OLLAMA_MODEL, prompt=prompt)
return response['response']
except Exception as e:
return f"Error generating Bollinger Bands analysis: {str(e)}"
Integrating Multi-Indicator Analysis
Combining RSI, MACD, and Bollinger Bands creates powerful trading signals. This integration reduces false signals and improves trading accuracy.
Multi-Indicator Signal Coordination
class MultiIndicatorAnalyzer:
def __init__(self):
self.rsi_analyzer = RSIAnalyzer()
self.macd_analyzer = MACDAnalyzer()
self.bb_analyzer = BollingerBandsAnalyzer()
def comprehensive_analysis(self, symbol, period="6mo"):
"""Perform comprehensive technical analysis using all indicators"""
# Fetch market data
data_provider = MarketDataProvider()
price_data = data_provider.fetch_price_data(symbol, period)
if price_data is None or price_data.empty:
return None
# Calculate all indicators
price_data = self.rsi_analyzer.calculate_rsi(price_data)
price_data = self.macd_analyzer.calculate_macd(price_data)
price_data = self.bb_analyzer.calculate_bollinger_bands(price_data)
# Generate individual signals
rsi_signals = self.rsi_analyzer.detect_rsi_signals(price_data)
rsi_divergences = self.rsi_analyzer.find_rsi_divergences(price_data)
macd_crossovers = self.macd_analyzer.detect_macd_crossovers(price_data)
macd_momentum = self.macd_analyzer.analyze_macd_momentum(price_data)
macd_divergences = self.macd_analyzer.detect_macd_divergences(price_data)
bb_signals = self.bb_analyzer.detect_bb_signals(price_data)
bb_breakouts = self.bb_analyzer.analyze_bb_breakouts(price_data)
bb_statistics = self.bb_analyzer.calculate_bb_statistics(price_data)
# Combine signals for comprehensive analysis
combined_signals = self.combine_signals(
rsi_signals, macd_crossovers, bb_signals, price_data
)
return {
'symbol': symbol,
'price_data': price_data,
'rsi_analysis': {
'signals': rsi_signals,
'divergences': rsi_divergences
},
'macd_analysis': {
'crossovers': macd_crossovers,
'momentum': macd_momentum,
'divergences': macd_divergences
},
'bb_analysis': {
'signals': bb_signals,
'breakouts': bb_breakouts,
'statistics': bb_statistics
},
'combined_signals': combined_signals
}
def combine_signals(self, rsi_signals, macd_crossovers, bb_signals, price_data):
"""Combine signals from multiple indicators for stronger confirmations"""
combined = []
# Get recent signals (last 10 trading days)
recent_date = price_data.index[-10]
recent_rsi = [s for s in rsi_signals if s['date'] >= recent_date]
recent_macd = [s for s in macd_crossovers if s['date'] >= recent_date]
recent_bb = [s for s in bb_signals if s['date'] >= recent_date]
# Look for signal confirmations
for rsi_signal in recent_rsi:
confirmations = []
signal_date = rsi_signal['date']
# Check for MACD confirmation within 3 days
for macd_signal in recent_macd:
days_diff = abs((macd_signal['date'] - signal_date).days)
if days_diff <= 3:
if ((rsi_signal['type'] == 'buy' and macd_signal['type'] == 'bullish_crossover') or
(rsi_signal['type'] == 'sell' and macd_signal['type'] == 'bearish_crossover')):
confirmations.append('macd')
# Check for Bollinger Band confirmation
for bb_signal in recent_bb:
days_diff = abs((bb_signal['date'] - signal_date).days)
if days_diff <= 2:
if ((rsi_signal['type'] == 'buy' and bb_signal['type'] == 'lower_band_touch') or
(rsi_signal['type'] == 'sell' and bb_signal['type'] == 'upper_band_touch')):
confirmations.append('bollinger_bands')
if confirmations:
combined.append({
'date': signal_date,
'primary_signal': rsi_signal,
'confirmations': confirmations,
'strength': len(confirmations) + 1,
'type': rsi_signal['type']
})
return sorted(combined, key=lambda x: x['date'], reverse=True)
def calculate_signal_strength(self, analysis_data):
"""Calculate overall signal strength based on indicator alignment"""
current_rsi = analysis_data['price_data']['rsi'].iloc[-1]
current_macd_hist = analysis_data['price_data']['macd_histogram'].iloc[-1]
current_bb_pos = analysis_data['bb_analysis']['statistics']['current_position']
# Signal strength factors
strength_factors = []
# RSI contribution
if current_rsi > 70:
strength_factors.append(-2) # Bearish
elif current_rsi < 30:
strength_factors.append(2) # Bullish
elif 40 <= current_rsi <= 60:
strength_factors.append(0) # Neutral
else:
strength_factors.append(1 if current_rsi < 50 else -1)
# MACD contribution
if not np.isnan(current_macd_hist):
if current_macd_hist > 0:
strength_factors.append(2) # Bullish
else:
strength_factors.append(-2) # Bearish
# Bollinger Bands contribution
if current_bb_pos > 80:
strength_factors.append(-1) # Overbought
elif current_bb_pos < 20:
strength_factors.append(1) # Oversold
else:
strength_factors.append(0) # Neutral
# Calculate weighted strength
total_strength = sum(strength_factors)
max_possible = 6 # Maximum bullish score
min_possible = -6 # Maximum bearish score
# Normalize to 0-100 scale
normalized_strength = ((total_strength - min_possible) / (max_possible - min_possible)) * 100
return {
'raw_strength': total_strength,
'normalized_strength': normalized_strength,
'interpretation': self._interpret_strength(normalized_strength)
}
def _interpret_strength(self, strength):
"""Interpret normalized strength score"""
if strength >= 80:
return "Strong Bullish"
elif strength >= 65:
return "Moderate Bullish"
elif strength >= 55:
return "Weak Bullish"
elif strength >= 45:
return "Neutral"
elif strength >= 35:
return "Weak Bearish"
elif strength >= 20:
return "Moderate Bearish"
else:
return "Strong Bearish"
Comprehensive Multi-Indicator Analysis with Ollama
def generate_comprehensive_analysis(analysis_data, ollama_client):
"""Generate comprehensive trading analysis using all indicators and Ollama"""
symbol = analysis_data['symbol']
price_data = analysis_data['price_data']
current_price = price_data['close'].iloc[-1]
# Calculate signal strength
multi_analyzer = MultiIndicatorAnalyzer()
signal_strength = multi_analyzer.calculate_signal_strength(analysis_data)
# Prepare comprehensive context
context = f"""
Comprehensive Technical Analysis for {symbol}
Current Price: ${current_price:.2f}
SIGNAL STRENGTH: {signal_strength['interpretation']} ({signal_strength['normalized_strength']:.0f}/100)
RSI Analysis:
- Current RSI: {price_data['rsi'].iloc[-1]:.2f}
- Recent Signals: {len(analysis_data['rsi_analysis']['signals'])} in dataset
- Divergences: {len(analysis_data['rsi_analysis']['divergences'])} detected
MACD Analysis:
- Current MACD: {price_data['macd'].iloc[-1]:.4f}
- Current Signal: {price_data['macd_signal'].iloc[-1]:.4f}
- Current Histogram: {price_data['macd_histogram'].iloc[-1]:.4f}
- Trend Direction: {analysis_data['macd_analysis']['momentum']['trend_direction']}
- Recent Crossovers: {len(analysis_data['macd_analysis']['crossovers'])}
Bollinger Bands Analysis:
- BB Position: {analysis_data['bb_analysis']['statistics']['current_position']:.1f}%
- BB Width Percentile: {analysis_data['bb_analysis']['statistics']['width_percentile']:.0f}%
- Recent Signals: {len(analysis_data['bb_analysis']['signals'])} detected
- Recent Breakouts: {len(analysis_data['bb_analysis']['breakouts'])} detected
Combined Signals:
{'; '.join([f"{cs['type']} signal with {len(cs['confirmations'])} confirmations on {cs['date'].strftime('%Y-%m-%d')}" for cs in analysis_data['combined_signals'][:3]])}
Market Context:
- 5-day price change: {((current_price / price_data['close'].iloc[-6]) - 1) * 100:.2f}%
- 20-day price change: {((current_price / price_data['close'].iloc[-21]) - 1) * 100:.2f}%
- Volatility (20-day): {(price_data['close'].pct_change().tail(20).std() * np.sqrt(252) * 100):.1f}%
"""
prompt = f"""
As a professional trading analyst, provide a comprehensive investment recommendation based on this multi-indicator technical analysis:
{context}
Deliver a complete trading strategy including:
1. EXECUTIVE SUMMARY
- Overall market outlook (bullish/bearish/neutral)
- Confidence level (1-10) and reasoning
- Primary catalyst driving the recommendation
2. TRADE SETUP
- Recommended position (long/short/wait)
- Optimal entry price range
- Position sizing recommendation
- Expected holding period
3. RISK MANAGEMENT
- Stop-loss levels with technical justification
- Take-profit targets (multiple levels)
- Maximum risk per trade
- Position management rules
4. SCENARIO ANALYSIS
- Bull case: probability and price targets
- Bear case: probability and downside risks
- Base case: most likely outcome
5. MONITORING PLAN
- Key levels to watch
- Indicators that would change the thesis
- Exit signals for both profit and loss
Be specific with exact price levels, percentages, and timeframes. Avoid generic advice and focus on actionable insights based on the technical evidence provided.
"""
try:
response = ollama_client.generate(model=OLLAMA_MODEL, prompt=prompt)
return response['response']
except Exception as e:
return f"Error generating comprehensive analysis: {str(e)}"
Automation Framework and Deployment
Build a robust automation framework that monitors multiple symbols and generates real-time alerts.
Real-Time Monitoring System
import schedule
import time
import json
from datetime import datetime
import logging
class TechnicalAnalysisBot:
def __init__(self, symbols_list, ollama_client):
self.symbols = symbols_list
self.ollama_client = ollama_client
self.analyzer = MultiIndicatorAnalyzer()
self.setup_logging()
def setup_logging(self):
"""Configure logging for the trading bot"""
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('trading_bot.log'),
logging.StreamHandler()
]
)
self.logger = logging.getLogger(__name__)
def analyze_symbol(self, symbol):
"""Analyze a single symbol and return results"""
try:
self.logger.info(f"Analyzing {symbol}...")
# Perform comprehensive analysis
analysis_data = self.analyzer.comprehensive_analysis(symbol)
if analysis_data is None:
self.logger.warning(f"No data available for {symbol}")
return None
# Generate Ollama analysis
comprehensive_analysis = generate_comprehensive_analysis(
analysis_data, self.ollama_client
)
# Calculate signal strength
signal_strength = self.analyzer.calculate_signal_strength(analysis_data)
result = {
'symbol': symbol,
'timestamp': datetime.now().isoformat(),
'current_price': float(analysis_data['price_data']['close'].iloc[-1]),
'signal_strength': signal_strength,
'analysis': comprehensive_analysis,
'raw_data': {
'rsi': float(analysis_data['price_data']['rsi'].iloc[-1]),
'macd': float(analysis_data['price_data']['macd'].iloc[-1]),
'bb_position': analysis_data['bb_analysis']['statistics']['current_position']
}
}
self.logger.info(f"Analysis complete for {symbol}: {signal_strength['interpretation']}")
return result
except Exception as e:
self.logger.error(f"Error analyzing {symbol}: {str(e)}")
return None
def scan_all_symbols(self):
"""Scan all symbols and return prioritized results"""
results = []
for symbol in self.symbols:
result = self.analyze_symbol(symbol)
if result:
results.append(result)
# Sort by signal strength (strongest signals first)
results.sort(key=lambda x: abs(x['signal_strength']['normalized_strength'] - 50), reverse=True)
return results
def generate_alerts(self, results, threshold=70):
"""Generate trading alerts for strong signals"""
alerts = []
for result in results:
strength = result['signal_strength']['normalized_strength']
# Strong bullish signals
if strength >= threshold:
alerts.append({
'type': 'STRONG_BUY',
'symbol': result['symbol'],
'price': result['current_price'],
'strength': strength,
'message': f"Strong bullish signal for {result['symbol']} at ${result['current_price']:.2f}"
})
# Strong bearish signals
elif strength <= (100 - threshold):
alerts.append({
'type': 'STRONG_SELL',
'symbol': result['symbol'],
'price': result['current_price'],
'strength': strength,
'message': f"Strong bearish signal for {result['symbol']} at ${result['current_price']:.2f}"
})
return alerts
def save_results(self, results, filename_prefix="analysis"):
"""Save analysis results to JSON file"""
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"{filename_prefix}_{timestamp}.json"
try:
with open(filename, 'w') as f:
json.dump(results, f, indent=2, default=str)
self.logger.info(f"Results saved to {filename}")
except Exception as e:
self.logger.error(f"Error saving results: {str(e)}")
def run_analysis_cycle(self):
"""Run complete analysis cycle"""
self.logger.info("Starting analysis cycle...")
# Scan all symbols
results = self.scan_all_symbols()
# Generate alerts
alerts = self.generate_alerts(results)
# Save results
self.save_results(results)
# Log alerts
for alert in alerts:
self.logger.warning(f"ALERT: {alert['message']}")
self.logger.info(f"Analysis cycle complete. Processed {len(results)} symbols, generated {len(alerts)} alerts.")
return results, alerts
# Usage example
def setup_automated_trading_bot():
"""Setup and run the automated trading bot"""
# Initialize Ollama client
ollama_client = initialize_ollama()
if not ollama_client:
print("Failed to initialize Ollama. Please check your setup.")
return
# Define symbols to monitor
symbols_to_monitor = [
'AAPL', 'GOOGL', 'MSFT', 'AMZN', 'TSLA',
'NVDA', 'META', 'NFLX', 'AMD', 'INTC',
'BTC-USD', 'ETH-USD', 'SPY', 'QQQ', 'IWM'
]
# Create trading bot
bot = TechnicalAnalysisBot(symbols_to_monitor, ollama_client)
# Schedule regular analysis
schedule.every(30).minutes.do(bot.run_analysis_cycle)
schedule.every().day.at("09:30").do(bot.run_analysis_cycle) # Market open
schedule.every().day.at("16:00").do(bot.run_analysis_cycle) # Market close
print("Trading bot started. Press Ctrl+C to stop.")
try:
while True:
schedule.run_pending()
time.sleep(60) # Check every minute
except KeyboardInterrupt:
print("Trading bot stopped.")
if __name__ == "__main__":
setup_automated_trading_bot()
Visualization and Reporting
Create comprehensive visualizations and reports for your automated analysis.
Interactive Charts and Dashboards
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import plotly.express as px
def create_comprehensive_chart(analysis_data):
"""Create comprehensive technical analysis chart"""
price_data = analysis_data['price_data']
symbol = analysis_data['symbol']
# Create subplots
fig = make_subplots(
rows=4, cols=1,
shared_xaxes=True,
vertical_spacing=0.05,
subplot_titles=(
f'{symbol} Price with Bollinger Bands',
'RSI',
'MACD',
'Volume'
),
row_heights=[0.5, 0.2, 0.2, 0.1]
)
# Price chart with Bollinger Bands
fig.add_trace(
go.Candlestick(
x=price_data.index,
open=price_data['open'],
high=price_data['high'],
low=price_data['low'],
close=price_data['close'],
name='Price'
),
row=1, col=1
)
# Bollinger Bands
fig.add_trace(
go.Scatter(
x=price_data.index,
y=price_data['bb_upper'],
name='BB Upper',
line=dict(color='rgba(255,0,0,0.3)'),
fill=None
),
row=1, col=1
)
fig.add_trace(
go.Scatter(
x=price_data.index,
y=price_data['bb_lower'],
name='BB Lower',
line=dict(color='rgba(255,0,0,0.3)'),
fill='tonexty',
fillcolor='rgba(255,0,0,0.1)'
),
row=1, col=1
)
fig.add_trace(
go.Scatter(
x=price_data.index,
y=price_data['bb_middle'],
name='BB Middle',
line=dict(color='blue', dash='dash')
),
row=1, col=1
)
# RSI
fig.add_trace(
go.Scatter(
x=price_data.index,
y=price_data['rsi'],
name='RSI',
line=dict(color='purple')
),
row=2, col=1
)
# RSI levels
fig.add_hline(y=70, line_dash="dash", line_color="red", row=2, col=1)
fig.add_hline(y=30, line_dash="dash", line_color="green", row=2, col=1)
fig.add_hline(y=50, line_dash="dot", line_color="gray", row=2, col=1)
# MACD
fig.add_trace(
go.Scatter(
x=price_data.index,
y=price_data['macd'],
name='MACD',
line=dict(color='blue')
),
row=3, col=1
)
fig.add_trace(
go.Scatter(
x=price_data.index,
y=price_data['macd_signal'],
name='Signal',
line=dict(color='red')
),
row=3, col=1
)
fig.add_trace(
go.Bar(
x=price_data.index,
y=price_data['macd_histogram'],
name='Histogram',
marker_color='gray',
opacity=0.6
),
row=3, col=1
)
# Volume
if 'volume' in price_data.columns:
fig.add_trace(
go.Bar(
x=price_data.index,
y=price_data['volume'],
name='Volume',
marker_color='lightblue'
),
row=4, col=1
)
# Update layout
fig.update_layout(
title=f'{symbol} - Comprehensive Technical Analysis',
xaxis_rangeslider_visible=False,
height=800,
showlegend=True
)
# Update y-axes
fig.update_yaxes(title_text="Price ($)", row=1, col=1)
fig.update_yaxes(title_text="RSI", row=2, col=1, range=[0, 100])
fig.update_yaxes(title_text="MACD", row=3, col=1)
fig.update_yaxes(title_text="Volume", row=4, col=1)
return fig
def generate_analysis_report(results):
"""Generate comprehensive analysis report"""
report = f"""
# Technical Analysis Report
Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
## Executive Summary
Analyzed {len(results)} symbols using automated RSI, MACD, and Bollinger Bands analysis.
### Signal Distribution
"""
# Calculate signal distribution
signal_counts = {'Strong Bullish': 0, 'Moderate Bullish': 0, 'Weak Bullish': 0,
'Neutral': 0, 'Weak Bearish': 0, 'Moderate Bearish': 0, 'Strong Bearish': 0}
for result in results:
interpretation = result['signal_strength']['interpretation']
signal_counts[interpretation] += 1
for signal_type, count in signal_counts.items():
percentage = (count / len(results)) * 100 if results else 0
report += f"- {signal_type}: {count} symbols ({percentage:.1f}%)\n"
report += "\n## Top Opportunities\n\n"
# Top bullish opportunities
bullish_results = [r for r in results if r['signal_strength']['normalized_strength'] > 60]
bullish_results.sort(key=lambda x: x['signal_strength']['normalized_strength'], reverse=True)
report += "### Bullish Signals\n"
for result in bullish_results[:5]:
report += f"- **{result['symbol']}**: ${result['current_price']:.2f} - {result['signal_strength']['interpretation']} ({result['signal_strength']['normalized_strength']:.0f}/100)\n"
# Top bearish opportunities
bearish_results = [r for r in results if r['signal_strength']['normalized_strength'] < 40]
bearish_results.sort(key=lambda x: x['signal_strength']['normalized_strength'])
report += "\n### Bearish Signals\n"
for result in bearish_results[:5]:
report += f"- **{result['symbol']}**: ${result['current_price']:.2f} - {result['signal_strength']['interpretation']} ({result['signal_strength']['normalized_strength']:.0f}/100)\n"
report += "\n## Detailed Analysis\n\n"
# Detailed analysis for top signals
top_signals = sorted(results, key=lambda x: abs(x['signal_strength']['normalized_strength'] - 50), reverse=True)[:3]
for result in top_signals:
report += f"### {result['symbol']} - {result['signal_strength']['interpretation']}\n\n"
report += f"**Current Price**: ${result['current_price']:.2f}\n"
report += f"**Signal Strength**: {result['signal_strength']['normalized_strength']:.0f}/100\n\n"
report += f"**Technical Indicators**:\n"
report += f"- RSI: {result['raw_data']['rsi']:.2f}\n"
report += f"- MACD: {result['raw_data']['macd']:.4f}\n"
report += f"- BB Position: {result['raw_data']['bb_position']:.1f}%\n\n"
# Add Ollama analysis (truncated for report)
analysis_preview = result['analysis'][:500] + "..." if len(result['analysis']) > 500 else result['analysis']
report += f"**AI Analysis Preview**:\n{analysis_preview}\n\n"
report += "---\n\n"
return report
Conclusion: Transform Your Trading with Automated Technical Analysis
Automating technical analysis with Ollama revolutionizes how traders approach market analysis. Instead of spending hours manually interpreting charts, you now have an intelligent system that identifies opportunities, generates insights, and provides actionable recommendations 24/7.
The combination of RSI momentum analysis, MACD trend detection, and Bollinger Bands volatility assessment creates a comprehensive trading framework. Ollama's natural language processing transforms raw technical data into clear, strategic guidance that improves decision-making and reduces emotional trading mistakes.
This automated approach scales effortlessly across multiple symbols and timeframes, providing consistent analysis quality that manual methods cannot match. Whether you're a day trader seeking quick scalping opportunities or a swing trader looking for multi-day positions, this system adapts to your trading style and market conditions.
Start with a small watchlist of familiar symbols, test the automation framework with paper trading, and gradually expand as you gain confidence in the system. The combination of proven technical indicators and advanced AI analysis gives you a significant edge in today's fast-moving markets.
Your trading evolution begins now - let Ollama handle the analysis while you focus on strategy and execution.
Ready to automate your technical analysis? Download the complete code framework and start building your intelligent trading system today.