# How Daily Stock Analysis Results Are Visualized and Presented in Text Reports

> Discover how daily stock analysis results are presented in text reports. This project uses Jinja2 templates for Markdown, WeChat, or summary outputs, no charts needed.

- Repository: [mumu/daily_stock_analysis](https://github.com/ZhuLinsen/daily_stock_analysis)
- Tags: how-to-guide
- Published: 2026-04-30

---

**The daily-stock-analysis project converts `AnalysisResult` objects into human-readable text reports using Jinja2 templates, generating Markdown, WeChat, or brief summary outputs without embedded graphical charts.**

The **daily-stock-analysis** repository by ZhuLinsen takes a template-driven approach to visualization, transforming raw stock analysis data into formatted text reports instead of traditional charts. Rather than embedding a graphical charting library, the system relies on **Jinja2** templating to render analysis results into multiple output formats suitable for command-line interfaces, chat bots, and web displays. This architecture ensures that complex financial signals—buy recommendations, sentiment scores, and market snapshots—remain accessible across platforms that prioritize text-based communication.

## The Template-Driven Rendering Architecture

The visualization system centers on [`src/services/report_renderer.py`](https://github.com/ZhuLinsen/daily_stock_analysis/blob/main/src/services/report_renderer.py), which serves as the core rendering engine. This module transforms lists of `AnalysisResult` objects into polished reports by selecting platform-specific templates and injecting rich contextual data.

### Platform-Specific Templates

The system supports three distinct output formats, each optimized for its destination channel:

- **Markdown** (`templates/report_markdown.j2`): Full-featured reports with tables, headings, and emojis for CLI output or GitHub comments.
- **WeChat** (`templates/report_wechat.j2`): Compact, line-oriented layouts designed for chat bubble readability.
- **Brief** (`templates/report_brief.j2`): Ultra-short summaries for push notifications or Slack alerts.

Template selection occurs dynamically based on the `platform` parameter passed to the renderer. As implemented in [`src/services/report_renderer.py`](https://github.com/ZhuLinsen/daily_stock_analysis/blob/main/src/services/report_renderer.py):

```python
template_name = f"report_{platform}.j2"          # ← src/services/report_renderer.py:L100‑L102

```

### The Rendering Pipeline

The `render()` function executes a three-stage pipeline to generate the final report:

1. **Template Selection**: Loads the appropriate Jinja2 template from the configured templates directory using `FileSystemLoader`.
2. **Context Assembly**: Builds a comprehensive context dictionary containing:
   - Report metadata (`report_date`)
   - Sorted analysis results and enriched data
   - Signal counts (`buy_count`, `sell_count`)
   - Localization labels from [`src/report_language.py`](https://github.com/ZhuLinsen/daily_stock_analysis/blob/main/src/report_language.py)
   - Helper functions for text processing (`escape_md`, `clean_sniper`)

   ```python
   context = {
       "report_date": report_date,
       "results": sorted_results,
       "enriched": sorted_enriched,
       "buy_count": buy_count, "sell_count": sell_count,
       "labels": labels,
       "escape_md": _escape_md,
       "clean_sniper": _clean_sniper_value,
       ...
   }                                            # src/services/report_renderer.py:L40‑L62

   ```

3. **Jinja2 Execution**: Renders the template with automatic escaping disabled for Markdown compatibility. If the template is missing or Jinja2 cannot be imported, the function returns `None` to allow fallback to plain-text formatters.

   ```python
   env = Environment(loader=FileSystemLoader(str(templates_dir)),
                     autoescape=select_autoescape(default=False))
   template = env.get_template(template_name)
   return template.render(**context)            # src/services/report_renderer.py:L65‑L72

   ```

## Template Structure and Content Layout

Each template follows a consistent structural pattern defined in `templates/_macros.j2`, ensuring that critical financial data appears regardless of output format.

### Markdown Reports

The `report_markdown.j2` template produces comprehensive reports containing:

- **Header block**: Report date with title emojis (e.g., `🎯`)
- **Executive summary**: Total stock count, buy/hold/sell tallies, and one-liner per stock including signal emojis and sentiment scores
- **Detailed analysis**: For each security:
  - Core conclusion (one-sentence investment thesis)
  - Intelligence blocks covering earnings outlook, sentiment summaries, risk alerts, and catalysts
  - Battle-plan tables displaying ideal buy prices, stop-loss levels, take-profit targets, and position sizing advice
  - Market snapshot macros showing price action, moving averages, volume data, and chip analysis

### WeChat and Brief Formats

The **WeChat template** strips down the Markdown formatting to fit mobile chat constraints, using emoji-rich, single-line layouts that render cleanly in message bubbles. The **brief template** condenses everything into a notification-friendly list showing only stock names, codes, and primary signals—ideal for SMS or push notifications requiring immediate scanning.

## Integrating the Report Renderer in Your Workflow

To generate reports programmatically, import the renderer and invoke it with your analysis results:

```python
from src.services.report_renderer import render
from src.analyzer import AnalysisResult

# Assume `analysis_results` is a List[AnalysisResult] produced by the pipeline.

markdown_report = render(
    platform="markdown",          # "markdown", "wechat", or "brief"

    results=analysis_results,
    report_date="2026-04-30",
    summary_only=False,
)

if markdown_report:
    print(markdown_report)        # prints a ready-to-copy Markdown report

else:
    # Fallback to a simple text formatter

    for r in analysis_results:
        print(f"{r.name} ({r.code}): {r.operation_advice} – {r.sentiment_score}")

```

**CLI integration** ([`src/main.py`](https://github.com/ZhuLinsen/daily_stock_analysis/blob/main/src/main.py)) calls this renderer to output reports to stdout or forwards them to notification services. **Bot integrations** such as [`src/notification_sender/wechat_sender.py`](https://github.com/ZhuLinsen/daily_stock_analysis/blob/main/src/notification_sender/wechat_sender.py) invoke the same function but pass `"wechat"` as the platform parameter to ensure mobile-optimized formatting. The optional **Web UI** (`apps/dsa-web`) bypasses the Jinja2 renderer for its React/Vite frontend, though [`src/webui_frontend.py`](https://github.com/ZhuLinsen/daily_stock_analysis/blob/main/src/webui_frontend.py) handles asset preparation for this alternative visualization path.

## Key Files and Configuration

Understanding the visualization pipeline requires familiarity with these specific source files:

| File | Role |
|------|------|
| **[`src/services/report_renderer.py`](https://github.com/ZhuLinsen/daily_stock_analysis/blob/main/src/services/report_renderer.py)** | Core Jinja2 rendering engine (selects template, builds context, handles errors). |
| **`templates/report_markdown.j2`** | Markdown-styled full report with tables and hierarchical headings. |
| **`templates/report_wechat.j2`** | WeChat-friendly version (compact, emoji-rich, line-oriented). |
| **`templates/report_brief.j2`** | Ultra-short summary for push notifications and quick alerts. |
| **`templates/_macros.j2`** | Re-usable Jinja2 macros (e.g., `market_snapshot`). |
| **[`src/report_language.py`](https://github.com/ZhuLinsen/daily_stock_analysis/blob/main/src/report_language.py)** | Provides localized label dictionaries and helper functions used in templates. |
| **[`src/analyzer.py`](https://github.com/ZhuLinsen/daily_stock_analysis/blob/main/src/analyzer.py)** & **[`src/services/analysis_service.py`](https://github.com/ZhuLinsen/daily_stock_analysis/blob/main/src/services/analysis_service.py)** | Produce `AnalysisResult` objects that feed the renderer. |
| **[`src/config.py`](https://github.com/ZhuLinsen/daily_stock_analysis/blob/main/src/config.py)** | Holds `report_templates_dir` configuration for custom template locations. |
| **[`src/webui_frontend.py`](https://github.com/ZhuLinsen/daily_stock_analysis/blob/main/src/webui_frontend.py)** | Prepares static front-end assets for the optional React-based web UI. |

## Summary

- **Text-based visualization**: The project uses Jinja2 templates rather than graphical charting libraries to present analysis results.
- **Three output formats**: Markdown (full detail), WeChat (mobile-optimized), and Brief (notifications) templates serve different consumption channels.
- **Centralized rendering**: [`src/services/report_renderer.py`](https://github.com/ZhuLinsen/daily_stock_analysis/blob/main/src/services/report_renderer.py) orchestrates template selection, context assembly, and final text generation.
- **Rich data context**: Templates receive not just raw results, but also enriched data, signal counts, localization labels, and text-processing helpers.
- **Flexible deployment**: Rendered outputs feed CLI tools, chat bots, and web interfaces through a unified Python API.

## Frequently Asked Questions

### Does the daily-stock-analysis project support graphical charts?

No. According to the source code, the project intentionally avoids embedded graphical charting libraries. Instead, it relies on **text-based Jinja2 templates** to visualize data through formatted tables, emojis, and hierarchical Markdown headings that display price data, moving averages, and technical indicators as structured text.

### How do I customize the report templates?

Modify the Jinja2 files located in the `templates/` directory, or override the `report_templates_dir` setting in **[`src/config.py`](https://github.com/ZhuLinsen/daily_stock_analysis/blob/main/src/config.py)** to point to a custom location. The renderer uses `FileSystemLoader` to discover templates at runtime, allowing you to swap the entire template suite without changing core logic.

### What platforms can receive these reports?

The system supports three primary destinations: **command-line terminals** (via the Markdown template), **WeChat chat bots** (via [`src/notification_sender/wechat_sender.py`](https://github.com/ZhuLinsen/daily_stock_analysis/blob/main/src/notification_sender/wechat_sender.py) using the WeChat template), and **notification systems** (via the Brief template for Slack, Telegram, or SMS-like alerts). Additionally, the React/Vite web frontend in `apps/dsa-web` presents the same data through a separate browser-based interface.

### How does the web UI display results differently?

While the Jinja2 templates generate static text for bots and terminals, the **Web UI** (`apps/dsa-web`) renders the same `AnalysisResult` data through a React-based frontend. The **[`src/webui_frontend.py`](https://github.com/ZhuLinsen/daily_stock_analysis/blob/main/src/webui_frontend.py)** module handles static asset preparation for this interface, which provides interactive browsing rather than the linear text format produced by the template renderer.