How to Generate Reports from the Daily Stock Analysis: Complete Implementation Guide

Use the NotificationService class in src/notification.py to convert AnalysisResult objects into markdown, WeChat, or brief text reports using methods like generate_aggregate_report() or generate_daily_report().

The daily_stock_analysis repository provides a flexible reporting pipeline that transforms stock analysis data into multiple output formats. By leveraging the NotificationService class and the underlying Jinja2-based ReportRenderer, you can programmatically generate everything from detailed decision dashboards to compact one-line summaries optimized for chat bots and SMS notifications.

Prerequisites: Preparing Analysis Results

Before generating reports, you need a list of AnalysisResult objects. These are typically produced by the Analyzer class defined in src/analyzer.py.

from typing import List
from src.analyzer import Analyzer
from src.schemas import AnalysisResult

# Example: Run analysis for multiple stock codes

codes = ["600519", "AAPL", "hk00700"]
results: List[AnalysisResult] = Analyzer().run(codes)

Each AnalysisResult contains fields such as code, name, sentiment_score, operation_advice, trend_prediction, and dashboard data that the reporting engine will format.

Understanding Report Types

The system uses the ReportType enum defined in src/enums.py (lines 20-23) to determine output formatting. The available options are:

  • SIMPLE: Generates brief one-line summaries per stock, ideal for chat bots or SMS limitations.
  • FULL / DETAILED: Produces rich markdown dashboards suitable for email or web interfaces.
  • BRIEF: Equivalent to SIMPLE, providing quick overviews without detailed metrics.
from src.enums import ReportType

# Select based on your delivery channel

report_type = ReportType.FULL  # Options: SIMPLE, FULL, DETAILED, BRIEF

Generating Reports with NotificationService

The NotificationService class in src/notification.py serves as the primary entry point for all report generation. It reads global configuration from src/config.py and automatically detects available notification channels.

Initialize the Service

from src.notification import NotificationService

# Construction loads configuration but makes no network calls

notifier = NotificationService()

Direct Report Methods

For specific formatting requirements, call the dedicated rendering methods directly:

generate_daily_report(results) (lines 525-635): Creates a comprehensive markdown report with full analysis details.

generate_dashboard_report(results) (lines 669-846): Generates a decision-dashboard format in rich markdown.

generate_wechat_dashboard(results) (lines 869-1055): Produces compact WeChat-compatible output with a ≤4000 character limit.

generate_brief_report(results) (lines 1066-1104): Outputs one-line summaries for quick scanning.


# Full markdown report

markdown = notifier.generate_daily_report(results)

# WeChat-compatible compact version

wechat_msg = notifier.generate_wechat_dashboard(results)

# Brief one-liners for bots

brief = notifier.generate_brief_report(results)

Convenience Wrapper Method

When you want the system to automatically select the appropriate format based on ReportType, use generate_aggregate_report() (lines 239-250). This method chooses between brief and dashboard formats automatically.

from src.enums import ReportType

# Automatically selects dashboard for FULL/DETAILED, brief for SIMPLE/BRIEF

content = notifier.generate_aggregate_report(results, ReportType.SIMPLE)

Template Customization with Jinja2

When config.report_renderer_enabled is True, the system delegates rendering to src/services/report_renderer.py, which uses Jinja2 templates. If templates are missing, it falls back to native Python formatters.

The renderer loads templates from the directory specified by config.report_templates_dir, typically:

  • templates/report_markdown.j2: For full markdown and dashboard reports.
  • templates/report_wechat.j2: For WeChat-compatible output.

Custom templates receive a rich context dictionary containing:

  • results: The analysis data
  • enriched: Pre-computed localization data
  • labels: Language-specific UI strings
  • report_language, summary_only, history_by_code

Complete Working Example

This end-to-end script demonstrates generating reports from the command line:

#!/usr/bin/env python

# generate_report.py

import sys
import argparse
from typing import List

from src.analyzer import Analyzer
from src.notification import NotificationService
from src.enums import ReportType

def main(codes: List[str], typ: str = "full"):
    # Step 1: Analyze the stocks

    results = Analyzer().run(codes)
    
    # Step 2: Initialize the notification service

    notifier = NotificationService()
    
    # Step 3: Map string to ReportType enum

    try:
        report_type = ReportType.from_str(typ)
    except ValueError:
        print(f"Unsupported type '{typ}'. Choose from: simple, full, detailed, brief")
        sys.exit(1)
    
    # Step 4: Generate the report

    report = notifier.generate_aggregate_report(results, report_type)
    
    # Step 5: Output

    print(report)

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Generate stock analysis reports")
    parser.add_argument("codes", nargs="+", help="Stock codes to analyze")
    parser.add_argument("--type", default="full", 
                       help="Report type (simple|full|detailed|brief)")
    args = parser.parse_args()
    main(args.codes, args.type)

Execute with: python generate_report.py 600519 AAPL --type full

Summary

  • NotificationService in src/notification.py is the primary entry point for generating reports from daily_stock_analysis.
  • ReportType enum controls output format: use SIMPLE or BRIEF for compact summaries, FULL or DETAILED for rich markdown dashboards.
  • Specific methods like generate_wechat_dashboard() and generate_daily_report() provide direct access to specific formats.
  • generate_aggregate_report() automatically selects the appropriate formatter based on the requested ReportType.
  • Jinja2 templates in the templates/ directory allow full customization of markdown and WeChat outputs, with fallback to native Python formatting if templates are unavailable.

Frequently Asked Questions

What is the difference between generate_daily_report and generate_dashboard_report?

generate_daily_report() (lines 525-635) produces a comprehensive markdown document containing all analysis fields and historical context, suitable for detailed review. generate_dashboard_report() (lines 669-846) generates a decision-focused dashboard format that emphasizes actionable insights and trend predictions in a structured layout.

How do I customize the report templates?

Create custom Jinja2 templates in the directory specified by your config.report_templates_dir setting (default: templates/). Name them report_markdown.j2 for standard reports or report_wechat.j2 for WeChat output. The ReportRenderer in src/services/report_renderer.py will automatically load your templates and inject the analysis context dictionary.

What happens if the Jinja2 template is missing?

The ReportRenderer implements graceful fallback behavior. If the configured template file cannot be found or if config.report_renderer_enabled is False, the system automatically falls back to the internal Python formatter methods defined in NotificationService, ensuring reports are always generated even without custom templates.

How do I generate a report for specific notification channels?

Use generate_wechat_dashboard() for WeChat messages (automatically handles the 4000-character limit), generate_brief_report() for SMS or bot integrations, or generate_daily_report() for email attachments. Alternatively, pass a ReportType value to generate_aggregate_report() to let the service automatically select the appropriate format for your target channel.

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 →