trading-tools / utils /formatters /educational_content.py
Deploy Bot
Deploy Trading Analysis Platform to HuggingFace Spaces
a1bf219
"""Template-based educational content generator for technical indicators and patterns."""
from typing import Dict
# ============================================================================
# RSI (Relative Strength Index) Templates
# ============================================================================
RSI_TEMPLATES = {
"overbought": """
RSI measures momentum on a 0-100 scale. The current value of {rsi_value:.1f} is in the
**overbought zone** (above 70), which often indicates the stock has risen rapidly and may be
due for a pullback or consolidation. However, strong uptrends can remain overbought for
extended periods, so confirm with other indicators before acting.
""",
"oversold": """
RSI measures momentum on a 0-100 scale. The current value of {rsi_value:.1f} is in the
**oversold zone** (below 30), which often indicates the stock has declined sharply and may be
due for a bounce or reversal. However, strong downtrends can remain oversold, so look for
confirmation from price action or volume before entering.
""",
"neutral": """
RSI measures momentum on a 0-100 scale. The current value of {rsi_value:.1f} is in the
**neutral zone** (30-70), indicating balanced buying and selling pressure. This range typically
doesn't provide a strong directional signal on its own. Look for RSI to cross above 70
(overbought) or below 30 (oversold) for clearer momentum signals.
""",
}
def generate_rsi_explanation(rsi_value: float) -> str:
"""Generate educational note for RSI value.
Args:
rsi_value: Current RSI value (0-100)
Returns:
Plain-English explanation of RSI value
"""
if rsi_value >= 70:
template = RSI_TEMPLATES["overbought"]
elif rsi_value <= 30:
template = RSI_TEMPLATES["oversold"]
else:
template = RSI_TEMPLATES["neutral"]
return template.format(rsi_value=rsi_value).strip()
# ============================================================================
# MACD (Moving Average Convergence Divergence) Templates
# ============================================================================
MACD_TEMPLATES = {
"bullish_crossover": """
The MACD line crossed above the signal line, which is typically a **bullish signal** suggesting
upward momentum is building. This crossover is more reliable when it occurs below the zero line
and is accompanied by increasing volume. The current MACD value is {macd_value:.2f}.
""",
"bearish_crossover": """
The MACD line crossed below the signal line, which is typically a **bearish signal** suggesting
downward momentum is building. This crossover often precedes price declines. The current MACD
value is {macd_value:.2f}.
""",
"positive_divergence": """
The MACD histogram is positive (value: {histogram:.2f}), meaning the MACD line is above the
signal line. This indicates bullish momentum, but watch for the histogram bars to shrink
(momentum weakening) as a potential reversal signal.
""",
"negative_divergence": """
The MACD histogram is negative (value: {histogram:.2f}), meaning the MACD line is below the
signal line. This indicates bearish momentum, but watch for the histogram bars to shrink
(momentum weakening) as a potential reversal signal.
""",
}
def generate_macd_explanation(
macd_value: float, signal_value: float, histogram: float
) -> str:
"""Generate educational note for MACD values.
Args:
macd_value: Current MACD line value
signal_value: Current signal line value
histogram: MACD histogram (macd - signal)
Returns:
Plain-English explanation of MACD values
"""
if histogram > 0:
if histogram > 0.5: # Recent crossover
template = MACD_TEMPLATES["bullish_crossover"]
return template.format(macd_value=macd_value).strip()
else:
template = MACD_TEMPLATES["positive_divergence"]
return template.format(histogram=histogram).strip()
else:
if histogram < -0.5: # Recent crossover
template = MACD_TEMPLATES["bearish_crossover"]
return template.format(macd_value=macd_value).strip()
else:
template = MACD_TEMPLATES["negative_divergence"]
return template.format(histogram=histogram).strip()
# ============================================================================
# Stochastic Oscillator Templates
# ============================================================================
STOCHASTIC_TEMPLATES = {
"overbought": """
The Stochastic Oscillator compares current price to recent price range. %K (fast line) is
{k_value:.1f} and %D (slow line) is {d_value:.1f}. Both are in the **overbought zone** (above 80),
suggesting the stock may be due for a pullback. Watch for %K to cross below %D as a sell signal.
""",
"oversold": """
The Stochastic Oscillator compares current price to recent price range. %K (fast line) is
{k_value:.1f} and %D (slow line) is {d_value:.1f}. Both are in the **oversold zone** (below 20),
suggesting the stock may be due for a bounce. Watch for %K to cross above %D as a buy signal.
""",
"neutral": """
The Stochastic Oscillator shows %K (fast line) at {k_value:.1f} and %D (slow line) at {d_value:.1f}.
Values in the 20-80 range indicate normal price action without extreme conditions. Look for
crosses above 80 or below 20 for clearer signals.
""",
}
def generate_stochastic_explanation(k_value: float, d_value: float) -> str:
"""Generate educational note for Stochastic Oscillator.
Args:
k_value: %K value (fast line, 0-100)
d_value: %D value (slow line, 0-100)
Returns:
Plain-English explanation of Stochastic values
"""
if k_value >= 80 and d_value >= 80:
template = STOCHASTIC_TEMPLATES["overbought"]
elif k_value <= 20 and d_value <= 20:
template = STOCHASTIC_TEMPLATES["oversold"]
else:
template = STOCHASTIC_TEMPLATES["neutral"]
return template.format(k_value=k_value, d_value=d_value).strip()
# ============================================================================
# Pattern Templates
# ============================================================================
PATTERN_TEMPLATES = {
"head_and_shoulders": """
**What it is**: A Head and Shoulders pattern forms when price makes three peaks: a lower peak
(left shoulder), a higher peak (head), and another lower peak (right shoulder). The "neckline"
connects the lows between the peaks.
**What it means**: This pattern often signals a trend reversal from bullish to bearish. The
logic: buyers tried to push higher (head) but failed, and subsequent attempts (right shoulder)
couldn't reach the same level, showing weakening momentum.
**How to use it**: Traders typically wait for price to break below the neckline with strong
volume before entering short positions. The target is often the height of the head measured
down from the neckline.
**Reliability**: Moderate (works ~60-70% of the time). More reliable on longer timeframes
(weekly/monthly) than short-term charts.
""",
"double_bottom": """
**What it is**: A Double Bottom occurs when price tests the same support level twice, forms a
"W" shape, and then breaks above resistance (the middle peak).
**What it means**: This pattern suggests a potential trend reversal from bearish to bullish.
The logic: sellers tried to push lower twice but failed, showing support is strong and buyers
are stepping in.
**How to use it**: Traders typically wait for price to break above the resistance level
(middle peak) with confirmation from volume. Entry is often on the breakout or a pullback to
the resistance-turned-support.
**Reliability**: Good (works ~70-75% of the time when properly confirmed). More reliable when
the two bottoms are spaced weeks/months apart rather than days.
""",
"double_top": """
**What it is**: A Double Top occurs when price tests the same resistance level twice, forms an
"M" shape, and then breaks below support (the middle valley).
**What it means**: This pattern suggests a potential trend reversal from bullish to bearish.
The logic: buyers tried to push higher twice but failed, showing resistance is strong and
sellers are taking control.
**How to use it**: Traders typically wait for price to break below the support level with
volume confirmation. This validates the reversal and provides an entry point for short positions.
**Reliability**: Good (works ~70-75% of the time). More reliable when the two tops are spaced
weeks/months apart and occur after a significant uptrend.
""",
"ascending_triangle": """
**What it is**: An Ascending Triangle forms when price makes higher lows while repeatedly
testing a horizontal resistance level, creating a triangle shape that slopes upward.
**What it means**: This is typically a **bullish continuation pattern**. The higher lows show
increasing buying pressure, and once the resistance breaks, strong upward movement often follows.
**How to use it**: Wait for a decisive break above the resistance line with high volume. The
price target is often the height of the triangle added to the breakout point.
**Reliability**: Good (works ~70% of the time). More reliable in uptrends with clear volume
increase on breakout.
""",
"descending_triangle": """
**What it is**: A Descending Triangle forms when price makes lower highs while repeatedly
testing a horizontal support level, creating a triangle shape that slopes downward.
**What it means**: This is typically a **bearish continuation pattern**. The lower highs show
increasing selling pressure, and once the support breaks, strong downward movement often follows.
**How to use it**: Wait for a decisive break below the support line with high volume. The price
target is often the height of the triangle subtracted from the breakdown point.
**Reliability**: Good (works ~70% of the time). More reliable in downtrends with clear volume
increase on breakdown.
""",
}
def generate_pattern_explanation(pattern_name: str) -> str:
"""Generate educational note for chart pattern.
Args:
pattern_name: Name of the pattern (e.g., 'head_and_shoulders', 'double_bottom')
Returns:
Plain-English explanation of the pattern
"""
pattern_key = pattern_name.lower().replace(" ", "_").replace("-", "_")
if pattern_key in PATTERN_TEMPLATES:
return PATTERN_TEMPLATES[pattern_key].strip()
else:
return f"Pattern '{pattern_name}' detected. Research this pattern to understand its implications."
# ============================================================================
# Conflicting Signals Template
# ============================================================================
CONFLICT_TEMPLATE = """
⚠️ **Mixed Signals Detected**
{indicator1_name} suggests **{indicator1_signal}** ({indicator1_detail}), but {indicator2_name}
suggests **{indicator2_signal}** ({indicator2_detail}).
**What this means**: When indicators conflict, it often means the market is in transition or
lacks clear direction. This is NOT the time to take large positions with high conviction.
**How to proceed**:
1. Wait for indicators to align before acting
2. Use smaller position sizes due to uncertainty
3. Look for confirmation from price action and volume
4. Consider sitting on the sidelines until clarity emerges
"""
def generate_conflict_explanation(
indicator1_name: str,
indicator1_signal: str,
indicator1_detail: str,
indicator2_name: str,
indicator2_signal: str,
indicator2_detail: str,
) -> str:
"""Generate educational note for conflicting indicator signals.
Args:
indicator1_name: Name of first indicator (e.g., "RSI")
indicator1_signal: Signal from first indicator (e.g., "OVERBOUGHT")
indicator1_detail: Details of signal (e.g., "value: 73.2")
indicator2_name: Name of second indicator
indicator2_signal: Signal from second indicator
indicator2_detail: Details of signal
Returns:
Plain-English explanation of conflicting signals
"""
return CONFLICT_TEMPLATE.format(
indicator1_name=indicator1_name,
indicator1_signal=indicator1_signal,
indicator1_detail=indicator1_detail,
indicator2_name=indicator2_name,
indicator2_signal=indicator2_signal,
indicator2_detail=indicator2_detail,
).strip()
# ============================================================================
# Technical Terms Glossary
# ============================================================================
GLOSSARY: Dict[str, str] = {
"RSI": "Relative Strength Index - measures momentum on a 0-100 scale",
"MACD": "Moving Average Convergence Divergence - tracks trend and momentum",
"%K": "Fast line in Stochastic Oscillator showing recent price momentum",
"%D": "Slow line in Stochastic Oscillator (moving average of %K)",
"overbought": "condition where price has risen too far too fast, may reverse down",
"oversold": "condition where price has fallen too far too fast, may reverse up",
"breakout": "when price moves above resistance or below support with momentum",
"consolidation": "when price trades in a narrow range, 'resting' before next move",
"resistance": "price level where selling pressure historically overcomes buying pressure",
"support": "price level where buying pressure historically overcomes selling pressure",
"volume": "number of shares traded; high volume confirms price moves",
"trend": "general direction of price movement over time (up, down, or sideways)",
"momentum": "rate of change in price; strong momentum = rapid price movement",
"divergence": "when price and indicator move in opposite directions, signals potential reversal",
}
def get_glossary_definition(term: str) -> str:
"""Get plain-English definition of a technical term.
Args:
term: Technical term to look up
Returns:
Plain-English definition, or the original term if not found
"""
return GLOSSARY.get(term, term)