A small, agent-style Python project that fetches historical stock data, computes a set of technical indicators with worker agents, and produces a human-readable summary report. It also includes a value analysis worker that evaluates fundamentals and valuation. Summaries are generated via OpenAI if available, with a clear local fallback when it isn’t.
- Fetches historical price data for a ticker (via
yfinance) and caches it indata_hist/. - Spawns worker agents to compute indicators concurrently.
- Summarizes results using OpenAI (GPT-4 Turbo) when configured, or a simple local fallback summary otherwise.
- Uses Pydantic models for structured outputs.
- Uses an optional LLM-based orchestrator to plan which indicators to run and why (falls back to a deterministic plan when OpenAI is unavailable).
- Supports value analysis via a dedicated worker and orchestrator.
- Fetches recent news headlines and stores them in a Markdown report; also creates a final combined report.
main.py– CLI entry point.agents/– Orchestrators and workers (technical indicators, value analysis).core/– Minimal abstract base classes for orchestrator/worker.data/– Project data (not required for running; cache lives indata_hist/).data_hist/– CSV cache for historical data (auto-created).indicators/– Indicator implementations (sample, placeholder logic).reports/– Output reports (auto-created).
- Python 3.10+
- Packages (install with
pip install -r requirements.txt):pandas,yfinance,openai,pydantic
- Network access to fetch data from Yahoo Finance on the first run for a given ticker/period. Subsequent runs can use cached CSVs from
data_hist/. - Optional: OpenAI API key for LLM summarization.
- Environment variable:
OPENAI_API_KEY - Model:
gpt-4-turbo - Behavior: If the key is missing or any API call fails, the orchestrator falls back to a local, deterministic summary assembled from indicator outputs.
- The orchestrator also attempts an LLM planning step to choose/sequence indicators with rationale; this planning step similarly falls back to a deterministic plan.
- Create and activate a virtual environment (recommended)
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
- Install dependencies
pip install -r requirements.txt
- (Optional) Configure OpenAI
export OPENAI_API_KEY=your_api_key_here # Windows PowerShell: $Env:OPENAI_API_KEY="your_api_key_here"
- Run (defaults to both technical and value)
python main.py AAPL
- Default indicators:
RSI,MACD,Bollinger Bands,Moving Average - You can provide a custom subset:
python main.py AAPL --indicators RSI MACD
Value-only analysis:
python main.py AAPL --analysis value
Run only one type if desired:
python main.py AAPL --analysis technical
python main.py AAPL --analysis value
Include recent news headlines (works with any mode):
python main.py AAPL --news
- Output
- Technical:
reports/<TICKER>_<YYYYMMDD>_technical.md - Value:
reports/<TICKER>_<YYYYMMDD>_value.md - News:
reports/<TICKER>_news_<YYYYMMDD>.md - Final combined:
reports/<TICKER>_<YYYYMMDD>_final.md
- Price data is fetched with
yfinanceand cached todata_hist/<TICKER>_<period>.csv. - On subsequent runs, the cache is used when present. If network is unavailable, ensure the cache exists for your ticker.
Included sample indicators (with placeholder logic meant for demonstration):
RSI→indicators/rsi.py→ classRSIIndicatorMACD→indicators/macd.py→ classMACDIndicatorBollinger Bands→indicators/bollinger_bands.py→ classBollingerBandsIndicatorMoving Average→indicators/moving_average.py→ classMovingAverageIndicator
Extend or replace the placeholder logic with real calculations (e.g., using pandas-ta). Each indicator should implement calculate(self, stock_data: pd.DataFrame) -> dict and return a dict like:
{
"indicator": "RSI",
"signal": "Oversold",
"details": "RSI is currently at 28."
}
TechnicalAnalysisOrchestrator.run(ticker, indicators)- Fetches a
pandas.DataFrameviadata/data_fetcher.py. - Submits work to
IndicatorWorkerin a thread pool; each worker calculates one indicator. - Workers return
IndicatorResultPydantic models; orchestrator builds anAnalysisReportPydantic model. - Summarizes results via OpenAI (if configured) or local fallback.
- Writes a Markdown report to
reports/.
- Fetches a
- Workers return
IndicatorResult(indicator, signal, details, optional meta). - Orchestrator aggregates into
AnalysisReportwithSummaryResult. - Final output is Markdown; structured models are used internally (you can serialize them yourself if needed).
- OpenAI not configured: You’ll still get a valid local summary with a note about the fallback.
- No internet: Ensure a cached CSV exists in
data_hist/for your ticker/period. - Intel MKL warning: You may see a CPU capability warning from MKL; it’s informational and does not block execution.
- Pandas/JSON serialization errors: The system passes
DataFrameobjects to workers directly (no JSON round‑trip) to avoid such issues.
- Add new indicators to
indicators/and export a class named like<Name>Indicator(e.g.,RSIIndicator). - Indicators are loaded dynamically from their module names derived from the indicator label (e.g., "Bollinger Bands" →
indicators/bollinger_bands.py→BollingerBandsIndicator). - Reports are plain Markdown; feel free to enhance formatting or include charts.
# Default indicator set
python main.py MSFT
# Custom indicators
python main.py TSLA --indicators "Bollinger Bands" RSI
The resulting report appears in reports/ with the ticker and current date.
- Worker:
agents/value_analysis_worker.py→ classValueAnalysisWorker - Orchestrator:
agents/value_analysis_orchestrator.py→ classValueAnalysisOrchestrator - Uses yfinance fundamentals (e.g., P/E, P/B, margins, ROE, revenue growth, FCF yield, leverage) to compute a heuristic score and signal:
- Signals: Undervalued/Quality, Reasonable, Mixed/Neutral, Overvalued/Risky
- Report path:
reports/<TICKER>_<YYYYMMDD>_value.md- If OpenAI is configured, a concise Markdown summary is generated; otherwise a local fallback is used.