Skip to main content

Overview

CryptoView Pro provides a complete suite of technical indicators automatically calculated for all cryptocurrency pairs. The system combines multiple indicators to generate actionable trading signals.

Available Indicators

RSI (Relative Strength Index)

The RSI measures momentum and identifies overbought/oversold conditions.

RSI Interpretation

  • Above 70: Overbought (potential sell signal)
  • Below 30: Oversold (potential buy signal)
  • 50: Neutral zone

Implementation

from utils.indicators import TechnicalIndicators
import pandas as pd

# Calculate RSI for close prices
df['rsi'] = TechnicalIndicators.calculate_rsi(df['close'], periods=14)

# Check current RSI status
current_rsi = df['rsi'].iloc[-1]

if current_rsi > 70:
    print(f"OVERBOUGHT: RSI = {current_rsi:.2f}")
elif current_rsi < 30:
    print(f"OVERSOLD: RSI = {current_rsi:.2f}")
else:
    print(f"NEUTRAL: RSI = {current_rsi:.2f}")

RSI Formula

RSI is calculated using average gains and losses over a period:
def calculate_rsi(data: pd.Series, periods: int = 14) -> pd.Series:
    """
    RSI = 100 - (100 / (1 + RS))
    where RS = Average Gain / Average Loss
    """
    delta = data.diff()
    gain = (delta.where(delta > 0, 0)).rolling(window=periods).mean()
    loss = (-delta.where(delta < 0, 0)).rolling(window=periods).mean()
    
    rs = gain / loss
    rsi = 100 - (100 / (1 + rs))
    
    return rsi

MACD (Moving Average Convergence Divergence)

MACD identifies trend changes and momentum shifts using the relationship between two exponential moving averages.

MACD Line

12-period EMA minus 26-period EMAShows momentum direction

Signal Line

9-period EMA of MACDGenerates buy/sell signals

Histogram

MACD minus SignalVisualizes convergence/divergence

Trading Signals

  • Bullish Crossover: MACD crosses above signal line (buy signal)
  • Bearish Crossover: MACD crosses below signal line (sell signal)
  • Positive Histogram: MACD above signal (bullish momentum)
  • Negative Histogram: MACD below signal (bearish momentum)

Implementation

from utils.indicators import TechnicalIndicators

# Calculate MACD
macd, signal, histogram = TechnicalIndicators.calculate_macd(
    df['close'],
    fast=12,   # Fast EMA period
    slow=26,   # Slow EMA period
    signal=9   # Signal line period
)

df['macd'] = macd
df['macd_signal'] = signal
df['macd_hist'] = histogram

# Detect crossovers
df['macd_positive'] = df['macd'] > df['macd_signal']
df['macd_crossover'] = df['macd_positive'].diff()

# Get last crossover
last_crossover = df['macd_crossover'].iloc[-1]

if last_crossover == 1:
    print("BULLISH CROSSOVER: MACD crossed above signal")
elif last_crossover == -1:
    print("BEARISH CROSSOVER: MACD crossed below signal")

# Check current trend
if df['macd'].iloc[-1] > df['macd_signal'].iloc[-1]:
    print("Current trend: BULLISH")
else:
    print("Current trend: BEARISH")

Bollinger Bands

Bollinger Bands measure volatility and identify overbought/oversold conditions relative to recent price action.
Bollinger Bands consist of:
  • Middle Band: 20-period SMA
  • Upper Band: Middle + (2 × standard deviation)
  • Lower Band: Middle - (2 × standard deviation)

Implementation

from utils.indicators import TechnicalIndicators

# Calculate Bollinger Bands
upper, middle, lower = TechnicalIndicators.calculate_bollinger_bands(
    df['close'],
    period=20,
    std_dev=2
)

df['bb_upper'] = upper
df['bb_middle'] = middle
df['bb_lower'] = lower

# Calculate BB position (0 = at lower band, 1 = at upper band)
df['bb_position'] = (df['close'] - df['bb_lower']) / (df['bb_upper'] - df['bb_lower'])

# Analyze current position
current_price = df['close'].iloc[-1]
bb_pos = df['bb_position'].iloc[-1]

if bb_pos > 0.95:
    print(f"Price near UPPER band ({bb_pos:.1%}): Potentially overbought")
elif bb_pos < 0.05:
    print(f"Price near LOWER band ({bb_pos:.1%}): Potentially oversold")
else:
    print(f"Price in middle zone ({bb_pos:.1%})")

# Calculate bandwidth (volatility measure)
bandwidth = (df['bb_upper'] - df['bb_lower']) / df['bb_middle']
print(f"Current volatility: {bandwidth.iloc[-1]:.2%}")

Trading Strategy

def bollinger_strategy(df: pd.DataFrame) -> str:
    """
    Simple Bollinger Band mean reversion strategy
    """
    current = df['close'].iloc[-1]
    upper = df['bb_upper'].iloc[-1]
    lower = df['bb_lower'].iloc[-1]
    middle = df['bb_middle'].iloc[-1]
    
    # Buy when price touches lower band
    if current <= lower:
        return "BUY: Price at lower band"
    
    # Sell when price touches upper band
    elif current >= upper:
        return "SELL: Price at upper band"
    
    # Exit position when price returns to middle
    elif abs(current - middle) / middle < 0.005:  # Within 0.5% of middle
        return "EXIT: Price returned to mean"
    
    return "HOLD: Wait for signal"

Exponential Moving Averages (EMA)

EMAs react faster to price changes than simple moving averages, making them ideal for trend identification.

Multi-Timeframe EMAs

from utils.indicators import TechnicalIndicators

# Calculate multiple EMAs
for period in [9, 21, 50, 200]:
    df[f'ema_{period}'] = TechnicalIndicators.calculate_ema(df['close'], period)

# Detect golden cross (bullish) and death cross (bearish)
def detect_ema_cross(df: pd.DataFrame, fast: int, slow: int) -> str:
    """
    Detect EMA crossovers
    """
    fast_ema = df[f'ema_{fast}']
    slow_ema = df[f'ema_{slow}']
    
    # Current and previous positions
    current = fast_ema.iloc[-1] > slow_ema.iloc[-1]
    previous = fast_ema.iloc[-2] > slow_ema.iloc[-2]
    
    if current and not previous:
        return f"GOLDEN CROSS: EMA{fast} crossed above EMA{slow}"
    elif not current and previous:
        return f"DEATH CROSS: EMA{fast} crossed below EMA{slow}"
    
    return "No crossover"

# Check for major crossovers
print(detect_ema_cross(df, 50, 200))  # Most significant
print(detect_ema_cross(df, 9, 21))    # Short-term trend

# Current trend analysis
def analyze_ema_trend(df: pd.DataFrame) -> dict:
    """
    Analyze trend using multiple EMAs
    """
    current_price = df['close'].iloc[-1]
    
    return {
        'above_ema9': current_price > df['ema_9'].iloc[-1],
        'above_ema21': current_price > df['ema_21'].iloc[-1],
        'above_ema50': current_price > df['ema_50'].iloc[-1],
        'above_ema200': current_price > df['ema_200'].iloc[-1],
        'ema_order': (
            df['ema_9'].iloc[-1] > df['ema_21'].iloc[-1] > 
            df['ema_50'].iloc[-1] > df['ema_200'].iloc[-1]
        )
    }

trend = analyze_ema_trend(df)
if all(trend.values()):
    print("STRONG UPTREND: All EMAs aligned")
elif not any([trend['above_ema9'], trend['above_ema21']]):
    print("DOWNTREND: Price below short-term EMAs")

Combined Signal Generation

The system aggregates multiple indicators to generate overall trading signals:
from utils.indicators import TechnicalIndicators

# Add all indicators
df = TechnicalIndicators.add_all_indicators(df)

# Get comprehensive signals
signals = TechnicalIndicators.get_signals(df)

print(f"RSI Signal: {signals['rsi_signal']}")
print(f"MACD Signal: {signals['macd_signal']}")
print(f"Overall Signal: {signals['overall']}")

# Overall signal logic:
# BUY: RSI oversold + MACD bullish (2+ bullish signals)
# SELL: RSI overbought + MACD bearish (2+ bearish signals)
# NEUTRAL: Mixed signals

Signal Implementation

def get_signals(df: pd.DataFrame) -> dict:
    """
    Generate trading signals from technical indicators
    
    Returns:
        dict with signal types and overall recommendation
    """
    signals = {
        'rsi_signal': 'neutral',
        'macd_signal': 'neutral',
        'bb_signal': 'neutral',
        'overall': 'neutral'
    }
    
    last_row = df.iloc[-1]
    
    # RSI Signal
    if last_row['rsi'] > 70:
        signals['rsi_signal'] = 'overbought'
    elif last_row['rsi'] < 30:
        signals['rsi_signal'] = 'oversold'
    
    # MACD Signal
    if last_row['macd'] > last_row['macd_signal']:
        signals['macd_signal'] = 'bullish'
    else:
        signals['macd_signal'] = 'bearish'
    
    # Overall Signal (requires 2+ confirming indicators)
    bullish_count = sum([
        signals['rsi_signal'] == 'oversold',
        signals['macd_signal'] == 'bullish'
    ])
    
    bearish_count = sum([
        signals['rsi_signal'] == 'overbought',
        signals['macd_signal'] == 'bearish'
    ])
    
    if bullish_count >= 2:
        signals['overall'] = 'buy'
    elif bearish_count >= 2:
        signals['overall'] = 'sell'
    
    return signals

Advanced Analysis

Divergence Detection

Divergences between price and indicators can signal trend reversals:
import numpy as np
from scipy.signal import find_peaks

def detect_rsi_divergence(df: pd.DataFrame, lookback: int = 50) -> str:
    """
    Detect bullish and bearish divergences
    """
    recent = df.tail(lookback)
    
    # Find price peaks and troughs
    price_peaks, _ = find_peaks(recent['close'].values)
    price_troughs, _ = find_peaks(-recent['close'].values)
    
    # Find RSI peaks and troughs
    rsi_peaks, _ = find_peaks(recent['rsi'].values)
    rsi_troughs, _ = find_peaks(-recent['rsi'].values)
    
    # Bullish divergence: Price making lower lows, RSI making higher lows
    if len(price_troughs) >= 2 and len(rsi_troughs) >= 2:
        if (recent['close'].iloc[price_troughs[-1]] < recent['close'].iloc[price_troughs[-2]] and
            recent['rsi'].iloc[rsi_troughs[-1]] > recent['rsi'].iloc[rsi_troughs[-2]]):
            return "BULLISH DIVERGENCE: Potential reversal to upside"
    
    # Bearish divergence: Price making higher highs, RSI making lower highs
    if len(price_peaks) >= 2 and len(rsi_peaks) >= 2:
        if (recent['close'].iloc[price_peaks[-1]] > recent['close'].iloc[price_peaks[-2]] and
            recent['rsi'].iloc[rsi_peaks[-1]] < recent['rsi'].iloc[rsi_peaks[-2]]):
            return "BEARISH DIVERGENCE: Potential reversal to downside"
    
    return "No divergence detected"

print(detect_rsi_divergence(df))

Volume Analysis

Volume confirms price movements and identifies potential breakouts:
def analyze_volume(df: pd.DataFrame) -> dict:
    """
    Analyze volume patterns
    """
    # Calculate volume moving averages
    df['volume_ma_7'] = df['volume'].rolling(window=7).mean()
    df['volume_ma_20'] = df['volume'].rolling(window=20).mean()
    
    current_volume = df['volume'].iloc[-1]
    avg_volume = df['volume_ma_20'].iloc[-1]
    
    # Volume ratio
    volume_ratio = current_volume / avg_volume
    
    # Price change with volume
    price_change = df['close'].pct_change().iloc[-1]
    
    analysis = {
        'volume_spike': volume_ratio > 1.5,
        'volume_ratio': volume_ratio,
        'confirmation': abs(price_change) > 0.01 and volume_ratio > 1.2
    }
    
    if analysis['volume_spike']:
        if price_change > 0:
            analysis['signal'] = "Strong buying pressure"
        else:
            analysis['signal'] = "Strong selling pressure"
    else:
        analysis['signal'] = "Normal volume"
    
    return analysis

vol_analysis = analyze_volume(df)
print(f"Volume Ratio: {vol_analysis['volume_ratio']:.2f}x")
print(f"Signal: {vol_analysis['signal']}")

Visualization

The UI displays technical indicators on interactive charts:
import plotly.graph_objects as go
from plotly.subplots import make_subplots

def create_technical_chart(df: pd.DataFrame) -> go.Figure:
    """
    Create comprehensive technical analysis chart
    """
    fig = make_subplots(
        rows=3, cols=1,
        shared_xaxes=True,
        vertical_spacing=0.03,
        row_heights=[0.5, 0.25, 0.25],
        subplot_titles=('Price & EMAs', 'RSI', 'MACD')
    )
    
    # Price + Bollinger Bands + EMAs
    fig.add_trace(go.Candlestick(
        x=df.index, open=df['open'], high=df['high'],
        low=df['low'], close=df['close'], name='Price'
    ), row=1, col=1)
    
    # Bollinger Bands
    fig.add_trace(go.Scatter(
        x=df.index, y=df['bb_upper'],
        name='BB Upper', line=dict(dash='dash', color='gray')
    ), row=1, col=1)
    fig.add_trace(go.Scatter(
        x=df.index, y=df['bb_lower'],
        name='BB Lower', line=dict(dash='dash', color='gray'),
        fill='tonexty', fillcolor='rgba(128,128,128,0.1)'
    ), row=1, col=1)
    
    # EMAs
    fig.add_trace(go.Scatter(
        x=df.index, y=df['ema_50'],
        name='EMA 50', line=dict(color='orange')
    ), row=1, col=1)
    fig.add_trace(go.Scatter(
        x=df.index, y=df['ema_200'],
        name='EMA 200', line=dict(color='purple')
    ), row=1, col=1)
    
    # RSI
    fig.add_trace(go.Scatter(
        x=df.index, y=df['rsi'],
        name='RSI', line=dict(color='blue')
    ), row=2, col=1)
    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)
    
    # MACD
    fig.add_trace(go.Scatter(
        x=df.index, y=df['macd'],
        name='MACD', line=dict(color='cyan')
    ), row=3, col=1)
    fig.add_trace(go.Scatter(
        x=df.index, y=df['macd_signal'],
        name='Signal', line=dict(color='red')
    ), row=3, col=1)
    colors = ['green' if v >= 0 else 'red' for v in df['macd_hist']]
    fig.add_trace(go.Bar(
        x=df.index, y=df['macd_hist'],
        name='Histogram', marker_color=colors
    ), row=3, col=1)
    
    fig.update_layout(height=900, showlegend=True)
    return fig
View implementation at app.py:860

Code Reference

Key files for technical analysis:
  • utils/indicators.py:12 - RSI calculation
  • utils/indicators.py:24 - MACD calculation
  • utils/indicators.py:36 - Bollinger Bands calculation
  • utils/indicators.py:52 - Add all indicators function
  • utils/indicators.py:78 - Signal generation logic
  • app.py:544 - Metrics display
  • app.py:860 - Technical analysis tab
Combine multiple indicators for higher confidence signals. No single indicator is perfect - use confluence for best results.

Build docs developers (and LLMs) love