How the Technical Analyst Agent Calculates Chart Patterns in the AI Hedge Fund

The technical analyst agent calculates chart patterns by fetching historical OHLCV data, computing five distinct technical indicator signals—trend, mean-reversion, momentum, volatility, and statistical arbitrage—and aggregating them through a weighted ensemble algorithm to generate a final bullish, neutral, or bearish consensus with confidence scores.

The technical analyst agent in the virattt/ai-hedge-fund repository transforms raw market data into actionable trading signals through a sophisticated multi-stage pipeline. Located in src/agents/technicals.py, this agent implements a quantitative approach to technical analyst agent calculate chart patterns by combining classical technical indicators with statistical measures, then synthesizing them into a unified recommendation for downstream portfolio management agents.

The Four-Stage Chart Pattern Detection Pipeline

The agent processes market data through four discrete stages, converting raw price history into structured signals that other agents consume.

Stage 1: Data Acquisition from External APIs

For every ticker supplied in the workflow state, the agent fetches OHLCV (Open, High, Low, Close, Volume) data using the get_prices utility. This function, implemented in src/tools/api.py, retrieves market data and converts it into a pandas.DataFrame via prices_to_df. The agent iterates through the ticker list in src/agents/technicals.py (lines 55‑68), ensuring each symbol has sufficient historical data before proceeding to indicator calculations.

Stage 2: Individual Technical Indicator Calculations

Five independent technical analysis sub-routines run on the same DataFrame, each generating a signal, confidence score, and metric dictionary:

  • calculate_trend_signals (lines 60‑97): Detects trend-following patterns using EMA crossovers combined with ADX (Average Directional Index) strength indicators.
  • calculate_mean_reversion_signals (lines 99‑128): Identifies mean-reversion opportunities through Z-score analysis relative to Bollinger Bands and RSI (Relative Strength Index) thresholds.
  • calculate_momentum_signals (lines 130‑162): Measures momentum via multi-period return sums confirmed by volume analysis.
  • calculate_volatility_signals (lines 164‑202): Quantifies volatility regimes using historical volatility calculations and ATR (Average True Range) ratios.
  • calculate_stat_arb_signals (lines 204‑242): Assesses statistical arbitrage potential through Hurst exponent analysis, skewness, and kurtosis measurements.

Each function returns a standardized dictionary with signal (bullish/neutral/bearish), confidence (0‑1 float), and metrics (indicator values).

Stage 3: Weighted Signal Ensemble

The weighted_signal_combination function (lines 272‑299) merges the five sub-signals using predefined weights: trend 25 %, mean-reversion 20 %, momentum 25 %, volatility 15 %, and statistical arbitrage 15 %.

The algorithm converts textual signals to numeric values (bullish = 1, neutral = 0, bearish = ‑1), computes a weighted average normalized by total confidence, then maps the final score back to categorical signals. This ensemble approach prevents over-reliance on any single indicator when calculating chart patterns.

Stage 4: Result Packaging and State Update

The combined signal, its aggregate confidence, and a per-strategy breakdown are serialized using normalize_pandas and safe_float (lines 15‑32) to handle NaN values. The agent stores results in state["data"]["analyst_signals"] and emits a HumanMessage containing the JSON payload (lines 106‑158), enabling downstream LLM agents to access both the consensus and underlying reasoning.

Deep Dive into Technical Signal Calculations

Each calculation module implements distinct quantitative methods for pattern recognition.

Trend Following with EMA Crossovers and ADX

The trend module calculates multiple exponential moving averages (EMAs) and detects crossovers between short and long-term trends. It combines these with the ADX indicator to filter out weak trends, ensuring signals only fire when both direction and strength confirm a pattern.

Mean Reversion via Bollinger Bands and Z-Scores

This module computes rolling Z-scores relative to Bollinger Bands to identify statistically significant deviations from mean prices. It layers RSI confirmation to distinguish between temporary pullbacks and genuine reversals, providing confidence metrics based on deviation magnitude.

Multi-Period Momentum with Volume Confirmation

Momentum signals derive from summing returns across multiple lookback periods (e.g., 1‑month, 3‑month, 6‑month). The algorithm requires volume confirmation—ensuring momentum shifts coincide with increased trading activity—to filter out low-conviction moves.

Volatility Regime Detection using ATR Ratios

The volatility analyzer calculates historical volatility percentiles and ATR ratios to classify current market conditions as high, normal, or low volatility. This contextualizes other signals, as breakout patterns require different interpretation in high versus low volatility environments.

Statistical Arbitrage through Hurst Exponent Analysis

The statistical arbitrage module calculates the Hurst exponent to determine if price series exhibit trending (H > 0.5), mean-reverting (H < 0.5), or random walk (H ≈ 0.5) behavior. It supplements this with skewness and kurtosis analysis to detect tail-risk asymmetries that traditional momentum indicators might miss.

Implementing the Weighted Consensus Algorithm

The ensemble logic demonstrates how the technical analyst agent balances competing signals. When trend and momentum indicate bullish conditions but volatility signals warn of elevated risk, the weighted combination produces a moderated confidence score rather than a binary decision.

from src.agents.technicals import weighted_signal_combination

# Example sub-signals from the five calculation modules

signals = {
    "trend": {"signal": "bullish", "confidence": 0.78},
    "mean_reversion": {"signal": "neutral", "confidence": 0.50},
    "momentum": {"signal": "bullish", "confidence": 0.65},
    "volatility": {"signal": "bearish", "confidence": 0.45},
    "stat_arb": {"signal": "neutral", "confidence": 0.60},
}

# Predefined strategy weights as implemented in the source

weights = {
    "trend": 0.25,
    "mean_reversion": 0.20,
    "momentum": 0.25,
    "volatility": 0.15,
    "stat_arb": 0.15
}

combined = weighted_signal_combination(signals, weights)
print(combined)

# Output: {'signal': 'bullish', 'confidence': 0.62}

Practical Code Examples

Running the Technical Analyst Agent Standalone

Execute the agent independently to inspect chart pattern calculations for specific tickers:

from src.graph.state import AgentState
from src.agents.technicals import technical_analyst_agent

# Minimal workflow state configuration

state: AgentState = {
    "data": {
        "start_date": "2023-01-01",
        "end_date": "2023-12-31",
        "tickers": ["AAPL", "MSFT"],
        "analyst_signals": {}
    },
    "metadata": {"show_reasoning": True},
    "messages": [],
    "graph": {},
}

# Execute and extract the JSON signal payload

result = technical_analyst_agent(state)
signal_payload = result["messages"][-1].content
print(signal_payload)

Extending with Custom Technical Indicators

To add a VWAP (Volume Weighted Average Price) based signal to the pipeline:

def calculate_vwap_signal(prices_df):
    """Calculate VWAP-based chart pattern signal."""
    typical_price = (prices_df["high"] + prices_df["low"] + prices_df["close"]) / 3
    vwap = (typical_price * prices_df["volume"]).cumsum() / prices_df["volume"].cumsum()
    
    last_price = prices_df["close"].iloc[-1]
    last_vwap = vwap.iloc[-1]
    
    signal = "bullish" if last_price > last_vwap else "bearish"
    confidence = abs(last_price - last_vwap) / last_vwap
    
    return {
        "signal": signal,
        "confidence": min(confidence, 1.0),
        "metrics": {"vwap": float(last_vwap), "price": float(last_price)}
    }

Integrate this into src/agents/technicals.py by adding the call within technical_analyst_agent and updating the strategy_weights dictionary to include your new component.

Summary

  • The technical analyst agent processes OHLCV data through five specialized calculators: trend, mean-reversion, momentum, volatility, and statistical arbitrage.
  • Each calculator generates normalized signals with confidence scores, stored in the shared workflow state.
  • The weighted_signal_combination function aggregates individual signals using fixed weights (trend 25 %, momentum 25 %, mean-reversion 20 %, volatility 15 %, stat-arb 15 %).
  • Results are serialized via safe_float to handle missing data, then packaged as JSON for downstream consumption by portfolio management and risk analysis agents.
  • The implementation resides primarily in src/agents/technicals.py, with data fetching utilities in src/tools/api.py.

Frequently Asked Questions

What data sources does the technical analyst agent use?

The agent retrieves historical price data through the get_prices function in src/tools/api.py, which interfaces with external financial data APIs. It requires valid API credentials stored in the workflow state and returns OHLCV data formatted as a pandas.DataFrame for internal processing.

How are the signal weights determined in the ensemble?

The weights are hardcoded in the technical_analyst_agent function as a strategy_weights dictionary: trend and momentum each receive 25 %, mean-reversion receives 20 %, while volatility and statistical arbitrage each receive 15 %. These values reflect a balanced approach emphasizing directional signals while maintaining risk awareness through volatility and statistical measures.

Can I modify the technical indicators used by the agent?

Yes. The modular architecture in src/agents/technicals.py allows you to modify existing calculation functions or add new ones. Each calculator must return a dictionary with signal, confidence, and metrics keys. After adding a new calculator, register it in the agent's execution flow and update the strategy_weights dictionary to include your new signal component.

How does the agent handle incomplete or invalid price data?

The agent uses the safe_float utility (lines 15‑32) to sanitize metric values before serialization, converting NaN or infinite values to None. Additionally, the normalize_pandas helper ensures DataFrame outputs are converted to plain Python types compatible with the workflow state's JSON structure, preventing downstream errors from malformed numerical data.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →