
Financial Deep Research
- 914 installs
- 15 repo stars
- Updated June 16, 2026
- eng0ai/eng0-template-skills
financial-deep-research is a Claude Code skill that runs institutional-grade financial analysis with prioritized regulatory and market data sources for developers who need SEC filings, ratings, and news before building f
About
financial-deep-research is a Claude Code skill that extends deep-research with financial services specialization. The skill prioritizes SEC filings, Bloomberg, Reuters, S&P, and Morningstar, then runs multi-mode depth analysis and writes outputs to a research_output directory as PDF and HTML artifacts. Developers reach for financial-deep-research when building trading dashboards, compliance workflows, or investment research agents that need source-ranked evidence instead of generic web summaries. The skill targets terminal-based research inside Claude Code rather than a separate SaaS research UI.
- 8.5-phase financial research pipeline: Scope > Plan > Retrieve (Parallel) > Triangulate > Outline Refinement > Synthesiz
- Four research modes: Quick, Standard, Deep, and UltraDeep
- Financial credibility scoring with tiered source evaluation
- Prioritizes Tier-1 regulatory sources including SEC EDGAR, Federal Reserve FRED, and company IR
- Produces investment-grade professional reports suitable for institutional use
Financial Deep Research by the numbers
- 914 all-time installs (skills.sh)
- Ranked #520 of 3,282 Productivity & Planning skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Jul 30, 2026 (Skillselion catalog sync)
npx skills add https://github.com/eng0ai/eng0-template-skills --skill financial-deep-researchAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 914 |
|---|---|
| repo stars | ★ 15 |
| Security audit | 2 / 3 scanners passed |
| Last updated | June 16, 2026 |
| Repository | eng0ai/eng0-template-skills ↗ |
How do you run institutional financial research in Claude Code?
Run institutional-grade financial analysis with prioritized regulatory sources and multi-mode depth directly inside Claude Code.
Who is it for?
Developers building fintech APIs, trading tools, or compliance features who need ranked SEC and market-data research before writing code.
Skip if: Developers who only need quick stock quotes or non-financial general web research without regulatory source prioritization.
When should I use this skill?
A developer asks for SEC filing analysis, institutional financial research, or market-data-backed due diligence inside Claude Code.
What you get
Prioritized financial research briefs saved as PDF and HTML files under research_output with cited regulatory and market sources.
- PDF research reports
- HTML research reports
- Prioritized source briefs
By the numbers
- Prioritizes 5 named financial data sources: SEC filings, Bloomberg, Reuters, S&P, and Morningstar
- Exports research artifacts as PDF and HTML into research_output
Files
Financial Deep Research
<!-- STATIC CONTEXT BLOCK START - Optimized for prompt caching --> <!-- All static instructions, methodology, and templates below this line --> <!-- Dynamic content (user queries, results) added after this block -->
Core System Instructions
Purpose: Deliver citation-backed, verified financial research reports through 8-phase pipeline (Scope > Plan > Retrieve > Triangulate > Synthesize > Critique > Refine > Package) with financial source credibility scoring, regulatory compliance tracking, and progressive context management.
Financial Focus: This skill specializes in:
- Market analysis and investment research
- Due diligence and competitive benchmarking
- Regulatory compliance and risk assessment
- Financial modeling support and valuation analysis
- Earnings analysis and financial statement review
- Sector/industry deep dives
Context Strategy: This skill uses 2025 context engineering best practices:
- Static instructions cached (this section)
- Progressive disclosure (load references only when needed)
- Avoid "loss in the middle" (critical info at start/end, not buried)
- Explicit section markers for context navigation
---
Decision Tree (Execute First)
Request Analysis
|-- Simple stock quote? -> STOP: Use WebSearch, not this skill
|-- Basic company lookup? -> STOP: Use WebSearch, not this skill
|-- Debugging code? -> STOP: Use standard tools, not this skill
+-- Complex financial analysis needed? -> CONTINUE
Mode Selection
|-- Quick market check? -> quick (3 phases, 2-5 min)
|-- Standard analysis? -> standard (6 phases, 5-10 min) [DEFAULT]
|-- Investment decision? -> deep (8 phases, 10-20 min)
|-- Due diligence/M&A? -> ultradeep (8+ phases, 20-45 min)
Execution Loop (per phase)
|-- Load phase instructions from [methodology](./reference/methodology.md#phase-N)
|-- Execute phase tasks
|-- Spawn parallel agents if applicable
+-- Update progress
Validation Gate
|-- Run `python scripts/validate_report.py --report [path]`
|-- Pass? -> Deliver
+-- Fail? -> Fix (max 2 attempts) -> Still fails? -> Escalate---
Workflow (Clarify > Plan > Act > Verify > Report)
AUTONOMY PRINCIPLE: This skill operates independently. Infer assumptions from query context. Only stop for critical errors or incomprehensible queries.
1. Clarify (Rarely Needed - Prefer Autonomy)
DEFAULT: Proceed autonomously. Derive assumptions from query signals.
ONLY ask if CRITICALLY ambiguous:
- Query is incomprehensible (e.g., "analyze the thing")
- Contradictory requirements (e.g., "quick 50-source ultradeep analysis")
- Critical compliance/regulatory scope unclear
When in doubt: PROCEED with standard mode. User will redirect if incorrect.
Default assumptions:
- Company analysis -> Assume investor/analyst audience
- Sector query -> Assume comprehensive market view needed
- Valuation query -> Assume institutional-quality analysis
- Regulatory query -> Assume US jurisdiction unless specified
- Standard mode is default for most queries
---
2. Plan
Mode selection criteria:
- Quick (2-5 min): Market snapshot, earnings preview, quick check
- Standard (5-10 min): Most analysis, balanced depth/speed [DEFAULT]
- Deep (10-20 min): Investment decisions, detailed due diligence
- UltraDeep (20-45 min): M&A due diligence, comprehensive sector analysis
Announce plan and execute:
- Briefly state: selected mode, estimated time, number of sources
- Example: "Starting standard mode financial research (5-10 min, 15-30 sources)"
- Proceed without waiting for approval
---
3. Act (Phase Execution)
All modes execute:
- Phase 1: SCOPE - Define financial analysis boundaries (method)
- Phase 3: RETRIEVE - Parallel financial data gathering (5-10 concurrent searches + agents) (method)
- Phase 8: PACKAGE - Generate report using template
Standard/Deep/UltraDeep execute:
- Phase 2: PLAN - Financial research strategy formulation
- Phase 4: TRIANGULATE - Verify 3+ sources per financial claim
- Phase 4.5: OUTLINE REFINEMENT - Adapt structure based on evidence (WebWeaver 2025) (method)
- Phase 5: SYNTHESIZE - Generate investment insights
Deep/UltraDeep execute:
- Phase 6: CRITIQUE - Risk analysis and bear case
- Phase 7: REFINE - Address gaps, strengthen thesis
Critical: Avoid "Loss in the Middle"
- Place key findings at START and END of sections, not buried
- Use explicit headers and markers
- Structure: Summary > Details > Conclusion (not Details sandwiched)
Progressive Context Loading:
- Load methodology sections on-demand
- Load template only for Phase 8
- Do not inline everything - reference external files
Anti-Hallucination Protocol (CRITICAL for Financial Data):
- Source grounding: Every financial claim MUST cite a specific source immediately [N]
- Clear boundaries: Distinguish between FACTS (from filings/data) and ANALYSIS (your interpretation)
- Explicit markers: Use "According to [1]..." or "[1] reports..." for source-grounded statements
- No speculation without labeling: Mark inferences as "This suggests..." not "Data shows..."
- Verify before citing: If unsure whether source actually says X, do NOT fabricate citation
- When uncertain: Say "No sources found for X" rather than inventing references
- Financial precision: Always include specific numbers, dates, and currency when available
Parallel Execution Requirements (CRITICAL for Speed):
Phase 3 RETRIEVE - Mandatory Parallel Financial Search: 1. Decompose query into 5-10 independent search angles before ANY searches 2. Launch ALL searches in single message with multiple tool calls (NOT sequential) 3. Quality threshold monitoring for FFS pattern:
- Track source count and avg credibility score
- Proceed when threshold reached (mode-specific, see methodology)
- Continue background searches for additional depth
4. Spawn 3-5 parallel agents using Task tool for deep-dive investigations
Financial Search Decomposition Strategy:
[Single message with 8+ parallel tool calls]
WebSearch #1: Company fundamentals + recent filings
WebSearch #2: Earnings/financial performance
WebSearch #3: Industry/sector analysis
WebSearch #4: Competitive landscape
WebSearch #5: Regulatory/compliance news
WebSearch #6: Analyst ratings/price targets
WebSearch #7: Risk factors/bear case
WebSearch #8: Recent news + catalysts
Task agent #1: SEC filing deep dive (10-K, 10-Q analysis)
Task agent #2: Financial statement analysis
Task agent #3: Industry comparison/benchmarking---
4. Verify (Always Execute)
Step 1: Citation Verification (Catches Fabricated Sources)
python scripts/verify_citations.py --report [path]Financial-Specific Checks:
- SEC filing references (verify EDGAR links)
- Financial data accuracy (cross-check key metrics)
- Date accuracy (earnings dates, filing dates)
- Flags suspicious entries (future financials, impossible metrics)
If suspicious citations found:
- Review flagged entries manually
- Remove or replace fabricated sources
- Re-run until clean
Step 2: Structure & Quality Validation
python scripts/validate_report.py --report [path]9 automated checks (financial-enhanced): 1. Executive summary length (50-250 words) 2. Required sections present (+ recommended: Risk Factors, Valuation) 3. Citations formatted [1], [2], [3] 4. Bibliography matches citations 5. No placeholder text (TBD, TODO) 6. Word count reasonable (500-10000) 7. Minimum 10 sources 8. No broken internal links 9. Financial data consistency (dates, currencies, units)
If fails:
- Attempt 1: Auto-fix formatting/links
- Attempt 2: Manual review + correction
- After 2 failures: STOP > Report issues > Ask user
---
5. Report
CRITICAL: Generate COMPREHENSIVE, DETAILED financial markdown reports
File Organization (CRITICAL - Clean Accessibility):
1. Create Organized Folder in /code:
- ALWAYS create dedicated folder:
/code/[TickerOrTopic]_Financial_Research_[YYYYMMDD]/ - Extract clean topic name from research question
- Examples:
- "AAPL investment analysis" ->
/code/AAPL_Financial_Research_20251104/ - "compare cloud providers" ->
/code/Cloud_Sector_Analysis_20251104/ - "fintech due diligence" ->
/code/Fintech_Due_Diligence_20251104/ - If folder exists, use it; if not, create it
- This ensures clean organization and easy accessibility
2. Save All Formats to Same Folder:
Markdown (Primary Source):
- Save to:
[Documents folder]/financial_report_[YYYYMMDD]_[topic_slug].md - Also save copy to:
/code/research_output/(internal tracking) - Full detailed report with all findings
HTML (McKinsey Style - ALWAYS GENERATE):
- Save to:
[Documents folder]/financial_report_[YYYYMMDD]_[topic_slug].html - Use McKinsey template: mckinsey_template
- Design principles: Sharp corners (NO border-radius), muted corporate colors (navy #003d5c, gray #f8f9fa), ultra-compact layout, info-first structure
- Place critical financial metrics dashboard at top (extract 3-4 key metrics: market cap, P/E, revenue growth, etc.)
- Use data tables for dense financial information
- 14px base font, compact spacing, no decorative gradients or colors
- OPEN in browser automatically after generation
PDF (Professional Print - ALWAYS GENERATE):
- Save to:
[Documents folder]/financial_report_[YYYYMMDD]_[topic_slug].pdf - Use generating-pdf skill (via Task tool with general-purpose agent)
- Professional formatting with headers, page numbers
- OPEN in default PDF viewer after generation
3. File Naming Convention: All files use same base name for easy matching:
financial_report_20251104_aapl_analysis.mdfinancial_report_20251104_aapl_analysis.htmlfinancial_report_20251104_aapl_analysis.pdf
Length Requirements (UNLIMITED with Progressive Assembly):
- Quick mode: 2,000+ words (baseline quality threshold)
- Standard mode: 4,000+ words (comprehensive analysis)
- Deep mode: 6,000+ words (thorough investigation)
- UltraDeep mode: 10,000-50,000+ words (NO UPPER LIMIT)
How Unlimited Length Works: Progressive file assembly allows ANY report length by generating section-by-section. Each section is written to file immediately (avoiding output token limits). Complex analyses with many findings? Generate 20, 30, 50+ findings - no constraint!
Content Requirements:
- Use template as exact structure
- Generate each section to APPROPRIATE depth (determined by evidence, not word targets)
- Include specific financial data, statistics, dates, numbers
- Multiple paragraphs per finding with evidence
- Each section gets focused generation attention
- DO NOT write summaries - write FULL analysis
Writing Standards (Financial Precision):
- Data-driven: Every claim backed by specific numbers from sources
- Precision: Exact figures with currency, dates, and units
- Economy: No fluff, eliminate unnecessary modifiers
- Clarity: Financial terminology used correctly and consistently
- Directness: State findings without embellishment
- High signal-to-noise: Dense information, respect reader's time
- Examples:
- Bad: "revenue increased significantly" -> Good: "revenue grew 23% YoY to $94.8B in FY2024 [1]"
- Bad: "strong margins" -> Good: "gross margin of 43.2%, up 180bps YoY [2]"
- Bad: "expensive valuation" -> Good: "trades at 28x forward P/E vs sector median 22x [3]"
Source Attribution Standards (Critical for Financial Research):
- Immediate citation: Every financial claim followed by [N] citation in same sentence
- Quote sources directly: Use "According to [1]..." or "[1] reports..." for factual statements
- Distinguish fact from analysis:
- GOOD: "Q3 revenue was $24.9B, up 8% YoY [1]."
- BAD: "Revenue grew strongly last quarter."
- No vague attributions:
- NEVER: "Analysts believe...", "Market expects...", "Sources indicate..."
- ALWAYS: "Goldman Sachs estimates..." [1], "Per SEC 10-K filing..." [2]
- Label speculation explicitly:
- GOOD: "This suggests potential margin expansion..." (analysis, not fact)
- BAD: "Margins will expand..." (presented as fact without citation)
Deliver to user: 1. Executive summary with key investment thesis (inline in chat) 2. Organized folder path (e.g., "All files saved to: /code/AAPL_Financial_Research_20251104/") 3. Confirmation of all three formats generated:
- Markdown (source)
- HTML (McKinsey-style, opened in browser)
- PDF (professional print, opened in viewer)
4. Source quality assessment summary (source count, regulatory vs news mix) 5. Key financial metrics summary 6. Risk factors summary 7. Next steps (if relevant)
Generation Workflow: Progressive File Assembly (Unlimited Length)
[Same progressive assembly workflow as base skill - see deep-research SKILL.md]
---
Financial Data Sources (Priority Order)
Tier 1: Primary/Regulatory Sources (Highest Credibility)
- SEC EDGAR: 10-K, 10-Q, 8-K, proxy statements, insider filings
- Federal Reserve: FRED data, monetary policy, banking data
- FDIC/OCC: Banking regulation, call reports
- Treasury: Economic data, fiscal policy
- Company IR: Investor relations, earnings calls, presentations
- Exchange Filings: NYSE, NASDAQ company disclosures
Tier 2: Financial Data Providers (High Credibility)
- Bloomberg: Real-time data, analysis, news
- Reuters: News, data, analysis
- S&P Global: Ratings, research, Capital IQ data
- Moody's/Fitch: Credit ratings, research
- FactSet: Financial data, analytics
- Morningstar: Fund data, equity research
- PitchBook: Private market data, VC/PE
Tier 3: Financial News & Research (Moderate-High Credibility)
- Wall Street Journal: Business news, analysis
- Financial Times: Global finance news
- Barron's: Investment analysis
- Institutional research: Goldman, Morgan Stanley, JPM research
- Industry publications: American Banker, Insurance Journal
Tier 4: General Business Sources (Moderate Credibility)
- CNBC, Yahoo Finance: Market news (verify with primary sources)
- Seeking Alpha: Analysis (note: user-generated, verify claims)
- Industry blogs: Supplement only, not primary citation
Source Verification Requirements:
- Tier 1 sources: Can cite directly, highest trust
- Tier 2 sources: Reliable, cross-check major claims
- Tier 3 sources: Good for analysis, verify data with Tier 1-2
- Tier 4 sources: Use sparingly, always verify with higher tiers
---
Output Contract
Format: Comprehensive financial markdown report following template EXACTLY
Required sections (all must be detailed):
- Executive Summary with Investment Thesis (50-250 words)
- Company/Topic Overview (background, business model)
- Financial Analysis (revenue, margins, cash flow, balance sheet)
- Valuation Analysis (multiples, DCF if applicable, peer comparison)
- Competitive Position (market share, moat, competitive dynamics)
- Risk Factors (business, financial, regulatory, market risks)
- Investment Thesis / Recommendations
- Bibliography (CRITICAL - see rules below)
- Methodology Appendix
Financial-Specific Sections (include when relevant):
- Earnings Analysis (quarterly trends, guidance vs actual)
- Management Assessment (track record, insider activity)
- Regulatory Environment (compliance, pending regulation)
- ESG Considerations (if material to thesis)
- Catalyst Timeline (upcoming events, catalysts)
Bibliography Requirements (ZERO TOLERANCE):
- MUST include EVERY citation [N] used in report body
- Format: [N] Source (Date). "Title". Publication/Filing. URL (Retrieved: Date)
- Each entry on its own line, complete with all metadata
- NO placeholders, NO ranges, NO truncation
- Validation WILL FAIL if bibliography is incomplete
Strictly Prohibited:
- Placeholder text (TBD, TODO, [citation needed])
- Uncited financial claims
- Forward-looking statements presented as facts
- Broken links
- Missing required sections
- Short summaries instead of detailed analysis
- Vague statements without specific data
Quality gates (enforced by validator):
- Minimum 2,000 words (standard mode)
- Average credibility score >70/100 (higher bar for financial)
- 3+ sources per major financial claim
- Clear facts vs. analysis distinction
- All sections present and detailed
- Key financial metrics included with sources
---
Error Handling & Stop Rules
Stop immediately if:
- 2 validation failures on same error > Pause, report, ask user
- <5 sources after exhaustive search > Report limitation, request direction
- Critical financial data unavailable > Note gap, proceed with caveats
- User interrupts/changes scope > Confirm new direction
Graceful degradation:
- 5-10 sources > Note in limitations, proceed with extra verification
- Missing recent filing > Note, use most recent available
- Private company (limited data) > Acknowledge, use available sources
- Time constraint reached > Package partial results, document gaps
Error format:
Issue: [Description]
Context: [What was attempted]
Tried: [Resolution attempts]
Options:
1. [Option 1]
2. [Option 2]
3. [Option 3]---
Quality Standards (Always Enforce)
Every financial report must:
- 10+ sources (document if fewer)
- 3+ sources per major financial claim
- Executive summary <250 words with clear thesis
- Full citations with URLs to filings/sources
- Credibility assessment (source tier breakdown)
- Risk factors section
- Methodology documented
- Key metrics with sources
- No placeholders
Priority: Accuracy over speed. Financial data must be verified.
---
Inputs & Assumptions
Required:
- Financial research question (string)
Optional:
- Mode (quick/standard/deep/ultradeep)
- Time constraints
- Specific data requirements (valuation focus, risk focus, etc.)
- Output format preferences
- Jurisdiction (default: US)
Assumptions:
- User requires verified, citation-backed financial information
- Institutional-quality analysis expected
- 10-50 sources available on topic
- Time investment: 5-45 minutes
- USD unless otherwise specified
- US regulatory framework unless specified
---
When to Use / NOT Use
Use when:
- Investment analysis (buy/sell/hold thesis)
- Company due diligence
- Sector/industry deep dives
- M&A analysis
- Competitive benchmarking
- Earnings analysis
- Regulatory impact assessment
- Financial modeling research
Do NOT use:
- Simple stock quotes (use WebSearch)
- Basic company lookups (use WebSearch)
- Real-time trading decisions (need live data)
- Personal financial advice (not qualified)
- Tax/legal advice (not qualified)
---
Scripts (Offline, Python stdlib only)
Location: ./scripts/
- research_engine.py - Orchestration engine
- validate_report.py - Quality validation (9 checks, financial-enhanced)
- citation_manager.py - Citation tracking
- source_evaluator.py - Financial source credibility scoring (0-100)
- verify_citations.py - Citation verification with SEC filing checks
No external dependencies required.
---
Progressive References (Load On-Demand)
Do not inline these - reference only:
- Complete Methodology - 8-phase details with financial focus
- Report Template - Financial output structure
- README - Usage docs
- QUICK_START - Fast reference
Context Management: Load files on-demand for current phase only. Do not preload all content.
---
<!-- STATIC CONTEXT BLOCK END --> <!-- Above content is cacheable (>1024 tokens, static) --> <!-- Below: Dynamic content (user queries, retrieved data, generated reports) --> <!-- This structure enables 85% latency reduction via prompt caching -->
---
Dynamic Execution Zone
User Query Processing: [User financial research question will be inserted here during execution]
Retrieved Information: [Search results and sources will be accumulated here]
Generated Analysis: [Findings, synthesis, and report content generated here]
Note: This section remains empty in the skill definition. Content populated during runtime only.
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
*.egg-info/
.eggs/
*.egg
# Virtual environments
venv/
ENV/
env/
# IDE
.vscode/
.idea/
*.swp
*.swo
# OS
.DS_Store
Thumbs.db
# Research outputs (generated during runtime)
/research_output/
*.pdf
*.html
# Temporary files
*.tmp
*.temp
*.log
Financial Deep Research Skill for Claude Code
A comprehensive financial research engine that brings institutional-quality financial analysis capabilities to Claude Code terminal.
Overview
This skill is specialized for financial services research, building on the deep-research skill with:
- Financial data source prioritization: SEC filings, Bloomberg, Reuters, S&P, Morningstar
- Regulatory compliance awareness: SEC, FINRA, Federal Reserve, OCC sources
- Financial credibility scoring: Tiered source evaluation for financial data
- Investment-grade output: Professional reports suitable for institutional use
Features
Core Research Pipeline
- 8.5-Phase Financial Pipeline: Scope > Plan > Retrieve (Parallel) > Triangulate > Outline Refinement > Synthesize > Critique > Refine > Package
- Multiple Research Modes: Quick, Standard, Deep, and UltraDeep
- Financial-Specific Verification: SEC filing verification, financial data cross-checking
Financial Data Sources (Priority Order)
Tier 1 - Primary/Regulatory (Highest Credibility):
- SEC EDGAR (10-K, 10-Q, 8-K, proxy statements)
- Federal Reserve (FRED data, monetary policy)
- Company IR (investor relations, earnings calls)
- Exchange filings (NYSE, NASDAQ disclosures)
Tier 2 - Financial Data Providers:
- Bloomberg, Reuters, S&P Global
- Moody's, Fitch (credit ratings)
- FactSet, Morningstar, PitchBook
Tier 3 - Financial News & Research:
- Wall Street Journal, Financial Times, Barron's
- Institutional research (Goldman, Morgan Stanley)
Tier 4 - General Business Sources:
- CNBC, Yahoo Finance (verify with primary sources)
- Seeking Alpha (user-generated, verify claims)
2025 Enhancements
- Auto-Continuation System: TRUE UNLIMITED length via recursive agent spawning
- Progressive File Assembly: Section-by-section generation with quality safeguards
- Parallel Search Execution: 5-10 concurrent searches + parallel agents
- Financial Citation Validation: SEC filing verification, data accuracy checks
- McKinsey-Style HTML Reports: Professional financial dashboards
Installation
The skill should be installed in ~/.claude/skills/financial-deep-research/
No additional dependencies required for basic usage.
Usage
In Claude Code
Simply invoke the skill:
Use financial deep research to analyze Apple's investment thesisOr specify a mode:
Use financial deep research in ultradeep mode for M&A due diligence on NvidiaExample Queries
Company Analysis:
Use financial deep research to evaluate Tesla's financial health and valuationSector Analysis:
Use financial deep research to analyze the fintech sector landscape 2024-2025Competitive Analysis:
Use financial deep research to compare cloud providers: AWS vs Azure vs GCPDue Diligence:
Use financial deep research in deep mode for due diligence on Stripe pre-IPOEarnings Analysis:
Use financial deep research to analyze Microsoft's Q3 2024 earnings and outlookResearch Modes
| Mode | Phases | Duration | Best For |
|---|---|---|---|
| Quick | 3 phases | 2-5 min | Market snapshot, earnings preview |
| Standard | 6 phases | 5-10 min | Most financial analysis [DEFAULT] |
| Deep | 8 phases | 10-20 min | Investment decisions, detailed analysis |
| UltraDeep | 8+ phases | 20-45 min | M&A due diligence, comprehensive reports |
Output
Financial research reports are saved to organized folders in /code/[Topic]_Financial_Research_[Date]/
Each report includes:
- Executive Summary with Investment Thesis
- Company/Topic Overview
- Financial Analysis (revenue, margins, cash flow)
- Valuation Analysis (multiples, peer comparison)
- Competitive Position
- Risk Factors
- Investment Thesis / Recommendations
- Full Bibliography
- Methodology Appendix
Report Formats
1. Markdown - Primary source with full analysis 2. HTML - McKinsey-style with financial metrics dashboard 3. PDF - Professional print format
Quality Standards
Every financial research output:
- 10+ sources with tier breakdown
- Citations for all financial claims
- Cross-verified data (3+ sources for key metrics)
- SEC filing references when applicable
- Executive summary <250 words with clear thesis
- Risk factors section
- Full bibliography with source URLs
Financial Source Credibility Scoring
Sources are scored 0-100 based on:
- Domain authority (regulatory > data providers > news)
- Recency (recent filings > historical data)
- Expertise (institutional research > retail analysis)
- Bias potential (SEC filings > analyst opinions)
Minimum average credibility score: 70/100 (higher than general research)
Use Cases
Investment Analysis
- Buy/sell/hold thesis development
- Valuation analysis and peer comparison
- Earnings analysis and guidance assessment
Due Diligence
- Pre-acquisition research
- IPO analysis
- Private company assessment
Sector Research
- Industry landscape mapping
- Competitive dynamics analysis
- Regulatory environment assessment
Risk Assessment
- Financial health evaluation
- Regulatory risk analysis
- Market risk assessment
Architecture
financial-deep-research/
|-- SKILL.md # Main skill definition
|-- README.md # This file
|-- reference/
| +-- methodology.md # 8-phase financial methodology
|-- templates/
| |-- report_template.md # Financial report structure
| +-- mckinsey_report_template.html # HTML template with financial dashboard
|-- scripts/
| |-- research_engine.py # Core orchestration
| |-- validate_report.py # Financial report validation
| |-- citation_manager.py # Citation tracking
| |-- source_evaluator.py # Financial source credibility
| +-- verify_citations.py # SEC filing verification
+-- tests/
+-- fixtures/ # Test reportsComparison with Base Deep Research
| Feature | Deep Research | Financial Deep Research |
|---|---|---|
| Source priority | General web | Financial data providers |
| Credibility threshold | 60/100 | 70/100 |
| SEC filing verification | No | Yes |
| Financial metrics dashboard | No | Yes |
| Risk factors section | Optional | Required |
| Valuation analysis | Generic | Financial-specific |
| Regulatory awareness | Basic | Comprehensive |
Tips for Best Results
1. Be Specific: Include ticker symbols, time periods, specific metrics 2. Set Context: Specify if for investment decision, due diligence, or research 3. Choose Appropriate Mode: Quick for snapshots, Deep for decisions 4. Request Specific Analysis: Valuation focus, risk focus, competitive focus 5. Leverage Citations: Drill into SEC filings and primary sources
Limitations
- Not real-time trading advice (data may be delayed)
- Not personalized financial advice (consult professionals)
- Not tax or legal advice (consult professionals)
- Private company data may be limited
- International markets may have fewer sources
Version
1.0 (2025-01-06) - Initial release based on deep-research v2.2
License
User skill - modify as needed for your workflow
Financial Deep Research Methodology: 8-Phase Pipeline
Overview
This document contains the detailed methodology for conducting financial deep research. The 8 phases represent a comprehensive approach to gathering, verifying, and synthesizing financial information from multiple sources with institutional-quality standards.
---
Phase 1: SCOPE - Financial Research Framing
Objective: Define financial research boundaries and success criteria
Activities: 1. Decompose the financial question into core components
- Company/sector identification
- Time period scope
- Specific metrics of interest
- Investment thesis type (growth, value, income, etc.)
2. Identify stakeholder perspectives (investor, analyst, management, regulatory) 3. Define scope boundaries (what's in/out)
- Geographic scope (US, global, specific regions)
- Time horizon (near-term, long-term)
- Analysis type (fundamental, technical, both)
4. Establish success criteria
- Key questions to answer
- Required confidence level
- Specific deliverables
5. List key assumptions to validate
Financial-Specific Considerations:
- Jurisdiction for regulatory analysis (SEC for US, etc.)
- Currency for financial metrics
- Fiscal year vs calendar year
- GAAP vs non-GAAP metrics
Output: Structured scope document with financial research boundaries
---
Phase 2: PLAN - Financial Research Strategy
Objective: Create an intelligent financial research roadmap
Activities: 1. Identify primary and secondary financial sources
- Tier 1: SEC filings, company IR, regulatory sources
- Tier 2: Bloomberg, Reuters, S&P, Morningstar
- Tier 3: Financial news, institutional research
- Tier 4: General business sources
2. Map knowledge dependencies (what must be understood first)
- Business model before valuation
- Historical performance before projections
- Industry dynamics before competitive positioning
3. Create search query strategy with variants
- Company-specific searches
- Industry/sector searches
- Regulatory/compliance searches
- Competitive analysis searches
4. Plan triangulation approach for financial data 5. Estimate time/effort per phase 6. Define quality gates
Financial Search Strategy Template:
[Ticker] SEC 10-K filing 2024(annual report)[Ticker] SEC 10-Q filing Q3 2024(quarterly)[Ticker] earnings call transcript Q3 2024[Company] investor presentation 2024[Sector] market analysis 2024[Company] vs [Competitor] comparison[Company] analyst ratings price target[Company] risk factors regulatory
Output: Financial research plan with prioritized investigation paths
---
Phase 3: RETRIEVE - Parallel Financial Information Gathering
Objective: Systematically collect financial information using parallel execution for maximum speed
CRITICAL: Execute ALL searches in parallel using a single message with multiple tool calls
Financial Query Decomposition Strategy
Before launching searches, decompose the research question into 5-10 independent search angles:
1. Company fundamentals - 10-K/10-Q filings, financial statements 2. Recent performance - Earnings, revenue, margins, growth rates 3. Valuation data - Multiples, peer comparison, analyst targets 4. Competitive landscape - Market share, competitors, moat analysis 5. Industry dynamics - Sector trends, TAM, growth drivers 6. Regulatory environment - Compliance, pending regulation, risks 7. Management & governance - Insider activity, executive track record 8. Risk factors - Business risks, financial risks, market risks 9. Catalysts & events - Upcoming earnings, product launches, M&A 10. Bear case - Short thesis, criticisms, concerns
Parallel Execution Protocol
Step 1: Launch ALL financial searches concurrently (single message)
Choose ONE search approach per research session:
Using WebSearch (built-in):
[Single message with 8+ parallel tool calls]
- WebSearch(query="AAPL SEC 10-K 2024 annual report")
- WebSearch(query="Apple Q4 2024 earnings revenue margins")
- WebSearch(query="Apple stock valuation P/E ratio analysis 2024")
- WebSearch(query="Apple vs Samsung vs Google competitive analysis")
- WebSearch(query="smartphone market share trends 2024")
- WebSearch(query="Apple regulatory antitrust risk 2024")
- WebSearch(query="Apple analyst ratings price target 2024")
- WebSearch(query="Apple stock bear case risks concerns")Step 2: Spawn parallel deep-dive agents
Use Task tool with general-purpose agents (3-5 agents) for:
- SEC filing deep analysis (10-K, 10-Q sections)
- Financial statement analysis (income, balance sheet, cash flow)
- Peer comparison and valuation modeling
- Industry report analysis
Example parallel agent deployment:
Task(subagent_type="general-purpose", description="SEC 10-K analysis",
prompt="Analyze Apple's most recent 10-K filing. Extract: business description,
risk factors, MD&A highlights, segment breakdown, key financial metrics")
Task(subagent_type="general-purpose", description="Financial statement analysis",
prompt="Analyze Apple's financial statements from recent filings. Calculate:
revenue growth, margin trends, ROIC, FCF conversion, balance sheet strength")
Task(subagent_type="general-purpose", description="Competitive analysis",
prompt="Compare Apple's financial metrics and market position vs Samsung,
Google, Microsoft. Focus on: revenue mix, margins, growth rates, R&D spend")Step 3: Collect and organize financial results
As results arrive: 1. Extract key financial metrics with source metadata 2. Track information gaps that emerge 3. Follow promising tangents with targeted searches 4. Maintain source diversity (regulatory, data providers, news) 5. Monitor for quality threshold (see FFS pattern below)
First Finish Search (FFS) Pattern for Financial Research
Adaptive completion based on quality threshold:
Quality gate: Proceed to Phase 4 when FIRST threshold reached:
- Quick mode: 10+ sources with avg credibility >70/100 OR 2 minutes elapsed
- Standard mode: 15+ sources with avg credibility >70/100 OR 5 minutes elapsed
- Deep mode: 25+ sources with avg credibility >75/100 OR 10 minutes elapsed
- UltraDeep mode: 30+ sources with avg credibility >80/100 OR 15 minutes elapsed
Continue background searches:
- If threshold reached early, continue remaining parallel searches in background
- Additional sources used in Phase 5 (SYNTHESIZE) for depth
- Allows fast progression without sacrificing thoroughness
Financial Source Quality Standards
Source diversity requirements:
- Minimum 2 Tier 1 sources (SEC filings, company IR)
- At least 3 different source tiers represented
- Mix of quantitative (filings) and qualitative (analysis) sources
- Recent data (within 6 months for quarterly data)
Credibility tracking:
- Score each source 0-100 using financial source_evaluator.py
- Tier 1 sources: 90-100 baseline
- Tier 2 sources: 70-85 baseline
- Tier 3 sources: 60-75 baseline
- Tier 4 sources: 40-60 baseline
- Flag low-credibility sources (<60) for verification
- Prioritize high-credibility sources (>80) for core financial claims
Output: Organized financial information repository with source tracking, credibility scores, and coverage map
---
Phase 4: TRIANGULATE - Financial Cross-Reference Verification
Objective: Validate financial information across multiple independent sources
Activities: 1. Identify financial claims requiring verification
- Revenue/earnings figures
- Margin calculations
- Growth rates
- Valuation multiples
- Market share claims
2. Cross-reference facts across 3+ sources
- Primary source (SEC filing) vs data providers
- Multiple analyst estimates
- News reports vs company statements
3. Flag contradictions or uncertainties 4. Assess source credibility tier 5. Note consensus vs. debate areas 6. Document verification status per claim
Financial-Specific Verification:
- Cross-check key metrics against SEC filings
- Verify analyst estimates across multiple providers
- Confirm market data with exchange sources
- Validate regulatory claims with official sources
Quality Standards:
- Core financial claims must have 2+ independent sources (one being Tier 1)
- Flag any single-source financial information
- Note data recency (filing date, report date)
- Identify potential biases (sell-side vs buy-side)
Output: Verified financial fact base with confidence levels
---
Phase 4.5: OUTLINE REFINEMENT - Dynamic Evolution (WebWeaver 2025)
Objective: Adapt financial research direction based on evidence discovered
Problem Solved: Prevents "locked-in" research when evidence points to different conclusions or uncovers more important financial angles than initially planned.
When to Execute:
- Standard/Deep/UltraDeep modes only (Quick mode skips this)
- After Phase 4 (TRIANGULATE) completes
- Before Phase 5 (SYNTHESIZE)
Financial-Specific Adaptation Signals:
- Major risk factor not in original scope
- Valuation discrepancy requiring deeper analysis
- Regulatory issue more significant than expected
- Competitive threat underappreciated
- Financial health concerns emerged
- Management credibility issues surfaced
Activities:
1. Review Initial Scope vs. Actual Findings
- Compare Phase 1 scope with Phase 3-4 discoveries
- Identify unexpected financial patterns
- Note underexplored angles that emerged as critical
2. Evaluate Outline Adaptation Need
Signals for adaptation:
- Major financial risks not in original outline
- Valuation thesis challenged by evidence
- Competitive dynamics more complex than expected
- Regulatory environment more impactful
3. Refine Outline (if needed)
Example adaptation:
Original outline:
1. Company Overview
2. Financial Analysis
3. Valuation
4. Recommendation
Refined after Phase 4 (debt concerns emerged):
1. Company Overview
2. Financial Analysis
3. **Balance Sheet Deep Dive (NEW - debt concerns)**
4. **Liquidity Risk Assessment (NEW - material issue)**
5. Valuation (adjusted for risk)
6. Recommendation with Risk Caveats4. Targeted Gap Filling (if major gaps found)
- Launch 2-3 targeted searches for newly identified angles
- Quick retrieval only (don't restart full Phase 3)
- Time-box to 2-5 minutes
Output: Refined outline that accurately reflects financial evidence landscape
---
Phase 5: SYNTHESIZE - Financial Deep Analysis
Objective: Connect financial insights and generate investment understanding
Activities: 1. Identify patterns across financial sources
- Revenue trends and drivers
- Margin trajectory and sustainability
- Cash flow dynamics
- Balance sheet evolution
2. Map relationships between financial concepts
- Revenue growth vs profitability
- Capex vs FCF generation
- Leverage vs interest coverage
3. Generate insights beyond source material
- Investment thesis development
- Valuation framework
- Risk/reward assessment
4. Create financial frameworks
- Bull case / Base case / Bear case
- Key metrics dashboard
- Peer comparison matrix
5. Build argument structures
- Investment thesis support
- Counter-arguments addressed
6. Develop evidence hierarchies
- Primary evidence (filings, data)
- Supporting evidence (analysis, news)
Financial Synthesis Framework:
- Bull Case: Best-case scenario with supporting evidence
- Base Case: Most likely outcome with key assumptions
- Bear Case: Downside risks and worst-case scenario
- Key Metrics: 5-10 most important financial metrics
- Catalysts: Near-term and long-term value drivers
- Risks: Ranked by probability and impact
Output: Synthesized financial understanding with investment insight generation
---
Phase 6: CRITIQUE - Financial Quality Assurance
Objective: Rigorously evaluate financial research quality
Activities: 1. Review for logical consistency
- Financial calculations check
- Ratio consistency
- Growth rate plausibility
2. Check citation completeness
- Every financial claim cited
- Source tier documented
3. Identify gaps or weaknesses
- Missing data points
- Outdated information
- Single-source claims
4. Assess balance and objectivity
- Bull vs bear balance
- Bias identification
5. Verify claims against sources
- Spot-check key metrics
- Confirm SEC filing accuracy
6. Test alternative interpretations
- Consider counter-thesis
- Stress-test assumptions
Financial Red Team Questions:
- What's the strongest bear case?
- What could make this investment fail?
- What are management's incentives?
- What are we missing?
- What if growth slows?
- What if margins compress?
- What regulatory risks exist?
Output: Financial critique report with improvement recommendations
---
Phase 7: REFINE - Financial Iterative Improvement
Objective: Address gaps and strengthen financial analysis
Activities: 1. Conduct additional research for financial gaps 2. Strengthen weak investment arguments 3. Add missing financial perspectives 4. Resolve data contradictions 5. Enhance clarity of financial explanation 6. Verify revised financial content
Financial-Specific Refinement:
- Update with most recent filings if available
- Strengthen valuation analysis
- Add peer comparison depth
- Expand risk factor coverage
- Include management track record
Output: Strengthened financial research with addressed deficiencies
---
Phase 8: PACKAGE - Financial Report Generation
Objective: Deliver professional, institutional-quality financial research
Activities: 1. Structure report with financial hierarchy
- Executive summary with thesis
- Key metrics dashboard
- Detailed analysis sections
- Risk factors
- Recommendations
2. Write executive summary with clear investment thesis 3. Develop detailed financial sections 4. Create financial visualizations (tables, charts) 5. Compile full bibliography with source tiers 6. Add methodology appendix
Financial Report Structure: 1. Executive Summary (thesis, key metrics, recommendation) 2. Company Overview (business model, segments, management) 3. Financial Analysis (income, balance sheet, cash flow) 4. Valuation Analysis (multiples, DCF, peer comparison) 5. Competitive Position (market share, moat, dynamics) 6. Risk Factors (business, financial, regulatory, market) 7. Investment Thesis (bull/base/bear cases) 8. Recommendations (action items, catalysts to watch) 9. Bibliography (tiered, with URLs) 10. Methodology Appendix
Output: Complete financial research report ready for institutional use
---
Advanced Financial Features
Financial Source Prioritization
Automatic prioritization based on:
- Regulatory filings (highest priority for factual data)
- Data providers (high priority for analytics)
- Financial news (medium priority for context)
- General sources (lowest priority, verification required)
Parallel Agent Deployment for Financial Research
Use Task tool to spawn sub-agents for:
- SEC filing deep analysis
- Financial statement modeling
- Peer comparison analysis
- Industry research
- Regulatory impact assessment
Financial Citation Intelligence
Smart citation management:
- Track provenance to original filing
- Link to SEC EDGAR when available
- Assess source tier automatically
- Handle conflicting financial data
- Generate institutional-grade bibliographies
Valuation Framework Integration
Support for common valuation approaches:
- Comparable company analysis
- Precedent transactions
- DCF framework (when applicable)
- Sum-of-the-parts analysis
# Financial Deep Research Skill - Requirements
# All dependencies are Python standard library - no external packages needed
# The following are included with Python 3.8+:
# - argparse (CLI argument parsing)
# - re (regex for validation)
# - pathlib (file path handling)
# - dataclasses (data structures)
# - typing (type hints)
# - datetime (date handling)
# - urllib (HTTP requests for citation verification)
# - json (JSON parsing)
# - hashlib (citation ID generation)
# No pip install required!
#!/usr/bin/env python3
"""
Financial Citation Management System
Tracks sources, generates citations, and maintains bibliography with tier tracking
"""
from dataclasses import dataclass, field
from typing import List, Dict, Optional
from datetime import datetime
from urllib.parse import urlparse
import hashlib
@dataclass
class FinancialCitation:
"""Represents a single financial citation"""
id: str
title: str
url: str
tier: int # 1-4 (1 = highest credibility)
authors: Optional[List[str]] = None
publication_date: Optional[str] = None
retrieved_date: str = field(default_factory=lambda: datetime.now().strftime('%Y-%m-%d'))
source_type: str = "web" # sec_filing, data_provider, financial_news, general
filing_type: Optional[str] = None # 10-K, 10-Q, 8-K, etc.
ticker: Optional[str] = None
doi: Optional[str] = None
citation_count: int = 0
def to_markdown(self, index: int) -> str:
"""Generate markdown format citation"""
tier_label = f"[Tier {self.tier}]" if self.tier else ""
filing = f" ({self.filing_type})" if self.filing_type else ""
ticker = f" [{self.ticker}]" if self.ticker else ""
return f"[{index}]{ticker}{filing} [{self.title}]({self.url}) {tier_label} (Retrieved: {self.retrieved_date})"
def to_inline(self, index: int) -> str:
"""Generate inline citation [index]"""
return f"[{index}]"
def to_bibliography_entry(self, index: int) -> str:
"""Generate full bibliography entry"""
author_str = ""
if self.authors:
if len(self.authors) == 1:
author_str = f"{self.authors[0]}."
elif len(self.authors) == 2:
author_str = f"{self.authors[0]} & {self.authors[1]}."
else:
author_str = f"{self.authors[0]} et al."
date_str = f"({self.publication_date})" if self.publication_date else "(n.d.)"
filing = f" {self.filing_type}." if self.filing_type else ""
return f"[{index}] {author_str} {date_str}.{filing} \"{self.title}\". {self.url} (Retrieved: {self.retrieved_date})"
class FinancialCitationManager:
"""Manages financial citations and bibliography with tier organization"""
# Domain to tier mapping
TIER_MAPPING = {
# Tier 1: Regulatory/Primary
'sec.gov': 1, 'edgar.sec.gov': 1, 'federalreserve.gov': 1,
'treasury.gov': 1, 'fdic.gov': 1, 'finra.org': 1,
# Tier 2: Data Providers
'bloomberg.com': 2, 'reuters.com': 2, 'spglobal.com': 2,
'moodys.com': 2, 'fitchratings.com': 2, 'factset.com': 2,
'morningstar.com': 2, 'pitchbook.com': 2,
# Tier 3: Financial News
'wsj.com': 3, 'ft.com': 3, 'barrons.com': 3,
'cnbc.com': 3, 'marketwatch.com': 3,
# Tier 4: General
'seekingalpha.com': 4, 'finance.yahoo.com': 4,
}
def __init__(self):
self.citations: Dict[str, FinancialCitation] = {}
self.citation_order: List[str] = []
def add_source(
self,
url: str,
title: str,
authors: Optional[List[str]] = None,
publication_date: Optional[str] = None,
source_type: str = "web",
filing_type: Optional[str] = None,
ticker: Optional[str] = None,
doi: Optional[str] = None,
tier: Optional[int] = None
) -> str:
"""Add a financial source and return its citation ID"""
citation_id = hashlib.md5(url.encode()).hexdigest()[:8]
if citation_id not in self.citations:
# Auto-detect tier if not provided
if tier is None:
tier = self._detect_tier(url, source_type, filing_type)
citation = FinancialCitation(
id=citation_id,
title=title,
url=url,
tier=tier,
authors=authors,
publication_date=publication_date,
source_type=source_type,
filing_type=filing_type,
ticker=ticker,
doi=doi
)
self.citations[citation_id] = citation
self.citation_order.append(citation_id)
self.citations[citation_id].citation_count += 1
return citation_id
def _detect_tier(self, url: str, source_type: str, filing_type: Optional[str]) -> int:
"""Auto-detect source tier based on URL and type"""
# SEC filings are always Tier 1
if filing_type or 'sec.gov' in url.lower():
return 1
# Company IR sites are Tier 1
if any(pattern in url.lower() for pattern in ['ir.', 'investor.', 'investors.']):
return 1
# Check domain mapping
parsed = urlparse(url)
domain = parsed.netloc.lower().replace('www.', '')
for domain_pattern, tier in self.TIER_MAPPING.items():
if domain_pattern in domain:
return tier
# Default to Tier 4
return 4
def get_citation_number(self, citation_id: str) -> Optional[int]:
"""Get the citation number for a given ID"""
try:
return self.citation_order.index(citation_id) + 1
except ValueError:
return None
def get_inline_citation(self, citation_id: str) -> str:
"""Get inline citation marker [n]"""
num = self.get_citation_number(citation_id)
return f"[{num}]" if num else "[?]"
def generate_bibliography(self, organize_by_tier: bool = True) -> str:
"""Generate full bibliography, optionally organized by tier"""
if not organize_by_tier:
lines = ["## Bibliography\n"]
for i, citation_id in enumerate(self.citation_order, 1):
citation = self.citations[citation_id]
lines.append(citation.to_bibliography_entry(i))
return "\n\n".join(lines)
# Organize by tier
lines = ["## Bibliography\n"]
tier_names = {
1: "### Tier 1 Sources (Regulatory/Primary)",
2: "### Tier 2 Sources (Data Providers)",
3: "### Tier 3 Sources (Financial News/Research)",
4: "### Tier 4 Sources (General Business)"
}
# Group by tier
tier_citations = {1: [], 2: [], 3: [], 4: []}
for i, citation_id in enumerate(self.citation_order, 1):
citation = self.citations[citation_id]
tier_citations[citation.tier].append((i, citation))
# Generate by tier
for tier in [1, 2, 3, 4]:
if tier_citations[tier]:
lines.append(f"\n{tier_names[tier]}\n")
for i, citation in tier_citations[tier]:
lines.append(citation.to_bibliography_entry(i))
return "\n".join(lines)
def get_statistics(self) -> Dict[str, any]:
"""Get citation statistics"""
tier_counts = {1: 0, 2: 0, 3: 0, 4: 0}
for citation in self.citations.values():
tier_counts[citation.tier] += 1
return {
'total_sources': len(self.citations),
'total_citations': sum(c.citation_count for c in self.citations.values()),
'tier_breakdown': tier_counts,
'tier1_percentage': (tier_counts[1] / len(self.citations) * 100) if self.citations else 0,
'filing_types': self._count_filing_types(),
'most_cited': self._get_most_cited(5)
}
def _count_filing_types(self) -> Dict[str, int]:
"""Count SEC filing types"""
counts = {}
for citation in self.citations.values():
if citation.filing_type:
counts[citation.filing_type] = counts.get(citation.filing_type, 0) + 1
return counts
def _get_most_cited(self, n: int = 5) -> List[tuple]:
"""Get most cited sources"""
sorted_citations = sorted(
self.citations.items(),
key=lambda x: x[1].citation_count,
reverse=True
)
return [(self.get_citation_number(cid), c.title, c.citation_count)
for cid, c in sorted_citations[:n]]
# Example usage
if __name__ == '__main__':
manager = FinancialCitationManager()
# Add SEC filing
id1 = manager.add_source(
url="https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK=0000320193",
title="Apple Inc. Form 10-K Annual Report",
publication_date="2024",
source_type="sec_filing",
filing_type="10-K",
ticker="AAPL"
)
# Add data provider
id2 = manager.add_source(
url="https://www.bloomberg.com/quote/AAPL:US",
title="Apple Inc Stock Price",
source_type="data_provider"
)
# Add financial news
id3 = manager.add_source(
url="https://www.wsj.com/articles/apple-earnings-2024",
title="Apple Reports Q4 Earnings",
publication_date="2024-10-31",
source_type="financial_news"
)
print(f"Citation 1: {manager.get_inline_citation(id1)}")
print(f"Citation 2: {manager.get_inline_citation(id2)}")
print(f"\nBibliography:\n{manager.generate_bibliography()}")
print(f"\nStatistics:\n{manager.get_statistics()}")
#!/usr/bin/env python3
"""
Markdown to HTML converter for financial research reports
Properly converts markdown sections to HTML while preserving structure and formatting
"""
import re
from typing import Tuple
from pathlib import Path
def convert_markdown_to_html(markdown_text: str) -> Tuple[str, str]:
"""
Convert markdown to HTML in two parts: content and bibliography
Args:
markdown_text: Full markdown report text
Returns:
Tuple of (content_html, bibliography_html)
"""
# Split content and bibliography
parts = markdown_text.split('## Bibliography')
content_md = parts[0]
bibliography_md = parts[1] if len(parts) > 1 else ""
# Convert content (everything except bibliography)
content_html = _convert_content_section(content_md)
# Convert bibliography separately
bibliography_html = _convert_bibliography_section(bibliography_md)
return content_html, bibliography_html
def _convert_content_section(markdown: str) -> str:
"""Convert main content sections to HTML"""
html = markdown
# Remove title and front matter
lines = html.split('\n')
processed_lines = []
skip_until_first_section = True
for line in lines:
if skip_until_first_section:
if line.startswith('## ') and not line.startswith('### '):
skip_until_first_section = False
processed_lines.append(line)
continue
processed_lines.append(line)
html = '\n'.join(processed_lines)
# Convert headers
html = re.sub(
r'^## (.+)$',
r'<div class="section"><h2 class="section-title">\1</h2>',
html,
flags=re.MULTILINE
)
html = re.sub(
r'^### (.+)$',
r'<h3 class="subsection-title">\1</h3>',
html,
flags=re.MULTILINE
)
html = re.sub(
r'^#### (.+)$',
r'<h4 class="subsubsection-title">\1</h4>',
html,
flags=re.MULTILINE
)
# Convert **bold** text
html = re.sub(r'\*\*(.+?)\*\*', r'<strong>\1</strong>', html)
# Convert *italic* text
html = re.sub(r'\*(.+?)\*', r'<em>\1</em>', html)
# Convert inline code
html = re.sub(r'`(.+?)`', r'<code>\1</code>', html)
# Convert lists
html = _convert_lists(html)
# Convert tables
html = _convert_tables(html)
# Convert paragraphs
html = _convert_paragraphs(html)
# Close sections
html = _close_sections(html)
# Wrap executive summary
html = html.replace(
'<h2 class="section-title">Executive Summary</h2>',
'<div class="executive-summary"><h2 class="section-title">Executive Summary</h2>'
)
if '<div class="executive-summary">' in html:
html = html.replace(
'</h2>\n<div class="section">',
'</h2></div>\n<div class="section">',
1
)
return html
def _convert_bibliography_section(markdown: str) -> str:
"""Convert bibliography section to HTML with tier organization"""
if not markdown.strip():
return ""
html = markdown
# Convert tier headers
html = re.sub(
r'^### (Tier \d.+)$',
r'<div class="bib-tier"><div class="bib-tier-title">\1</div>',
html,
flags=re.MULTILINE
)
# Convert citation entries
html = re.sub(
r'\[(\d+)\]\s*(.+?)\s*(https?://[^\s\)]+)',
r'<div class="bib-entry"><span class="bib-number">[\1]</span> \2 <a href="\3" target="_blank">\3</a></div>',
html
)
# Convert bold
html = re.sub(r'\*\*(.+?)\*\*', r'<strong>\1</strong>', html)
html = f'<div class="bibliography-content">{html}</div>'
return html
def _convert_lists(html: str) -> str:
"""Convert markdown lists to HTML lists"""
lines = html.split('\n')
result = []
in_list = False
list_type = None
for line in lines:
stripped = line.strip()
if stripped.startswith('- ') or stripped.startswith('* '):
if not in_list:
result.append('<ul>')
in_list = True
list_type = 'ul'
content = stripped[2:]
result.append(f'<li>{content}</li>')
elif re.match(r'^\d+\.\s', stripped):
if not in_list:
result.append('<ol>')
in_list = True
list_type = 'ol'
content = re.sub(r'^\d+\.\s', '', stripped)
result.append(f'<li>{content}</li>')
else:
if in_list:
result.append(f'</{list_type}>')
in_list = False
list_type = None
result.append(line)
if in_list:
result.append(f'</{list_type}>')
return '\n'.join(result)
def _convert_tables(html: str) -> str:
"""Convert markdown tables to HTML tables"""
lines = html.split('\n')
result = []
in_table = False
is_header = False
for line in lines:
if '|' in line and line.strip().startswith('|'):
if not in_table:
result.append('<table class="data-table">')
in_table = True
is_header = True
cells = [cell.strip() for cell in line.split('|')[1:-1]]
result.append('<thead><tr>')
for cell in cells:
result.append(f'<th>{cell}</th>')
result.append('</tr></thead>')
result.append('<tbody>')
elif '---' in line:
continue
else:
cells = [cell.strip() for cell in line.split('|')[1:-1]]
result.append('<tr>')
for cell in cells:
# Add numeric class for numbers
css_class = 'numeric' if re.match(r'^[\$\d\.\,\%\+\-]+$', cell.replace('B', '').replace('M', '').replace('K', '')) else ''
# Add positive/negative class for changes
if cell.startswith('+'):
css_class += ' positive'
elif cell.startswith('-') and '%' in cell:
css_class += ' negative'
result.append(f'<td class="{css_class.strip()}">{cell}</td>')
result.append('</tr>')
else:
if in_table:
result.append('</tbody></table>')
in_table = False
result.append(line)
if in_table:
result.append('</tbody></table>')
return '\n'.join(result)
def _convert_paragraphs(html: str) -> str:
"""Wrap non-HTML lines in paragraph tags"""
lines = html.split('\n')
result = []
in_paragraph = False
for line in lines:
stripped = line.strip()
if not stripped:
if in_paragraph:
result.append('</p>')
in_paragraph = False
result.append(line)
continue
if (stripped.startswith('<') and stripped.endswith('>')) or \
stripped.startswith('</') or \
'<h' in stripped or '<div' in stripped or '<ul' in stripped or \
'<ol' in stripped or '<li' in stripped or '<table' in stripped:
if in_paragraph:
result.append('</p>')
in_paragraph = False
result.append(line)
continue
if not in_paragraph:
result.append('<p>' + line)
in_paragraph = True
else:
result.append(line)
if in_paragraph:
result.append('</p>')
return '\n'.join(result)
def _close_sections(html: str) -> str:
"""Close all open section divs"""
lines = html.split('\n')
result = []
section_open = False
for line in lines:
if '<div class="section">' in line:
if section_open:
result.append('</div>')
section_open = True
result.append(line)
if section_open:
result.append('</div>')
return '\n'.join(result)
def main():
"""Test the converter"""
import sys
if len(sys.argv) < 2:
print("Usage: python md_to_html.py <markdown_file>")
sys.exit(1)
md_file = Path(sys.argv[1])
if not md_file.exists():
print(f"Error: File {md_file} not found")
sys.exit(1)
markdown_text = md_file.read_text()
content_html, bib_html = convert_markdown_to_html(markdown_text)
print("=== CONTENT HTML ===")
print(content_html[:1500])
print("\n=== BIBLIOGRAPHY HTML ===")
print(bib_html[:500])
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Financial Research Engine
Core orchestration for financial deep research pipeline
Note: This is a placeholder for the research engine. The actual orchestration
is handled by Claude Code when the skill is invoked. This module provides
utility functions that can be called from the command line for testing.
"""
import argparse
import sys
from pathlib import Path
from datetime import datetime
def main():
"""Entry point for financial research engine"""
parser = argparse.ArgumentParser(
description="Financial Deep Research Engine",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Financial Research Modes:
quick - Market snapshot, 2-5 min, 10+ sources
standard - Most analysis, 5-10 min, 15-30 sources (default)
deep - Investment decisions, 10-20 min, 25-50 sources
ultradeep - M&A due diligence, 20-45 min, 30-100+ sources
Examples:
python research_engine.py --query "Analyze Apple investment thesis" --mode standard
python research_engine.py --query "NVDA vs AMD competitive analysis" --mode deep
python research_engine.py --query "Fintech sector due diligence" --mode ultradeep
Note: This engine is typically invoked through Claude Code's skill system.
Direct CLI usage is for testing and debugging.
"""
)
parser.add_argument(
'--query', '-q',
type=str,
required=True,
help='Financial research query'
)
parser.add_argument(
'--mode', '-m',
type=str,
choices=['quick', 'standard', 'deep', 'ultradeep'],
default='standard',
help='Research mode (default: standard)'
)
parser.add_argument(
'--output', '-o',
type=str,
default=None,
help='Output directory (default: /code/research_output/)'
)
args = parser.parse_args()
print(f"\n{'='*60}")
print(f"FINANCIAL DEEP RESEARCH ENGINE")
print(f"{'='*60}\n")
print(f"Query: {args.query}")
print(f"Mode: {args.mode}")
print(f"Output: {args.output or '/code/research_output/'}")
print()
# Mode configuration
mode_config = {
'quick': {
'phases': [1, 3, 8],
'min_sources': 10,
'target_time': '2-5 min',
'description': 'Market snapshot'
},
'standard': {
'phases': [1, 2, 3, 4, 4.5, 5, 8],
'min_sources': 15,
'target_time': '5-10 min',
'description': 'Standard analysis'
},
'deep': {
'phases': [1, 2, 3, 4, 4.5, 5, 6, 7, 8],
'min_sources': 25,
'target_time': '10-20 min',
'description': 'Investment decision'
},
'ultradeep': {
'phases': [1, 2, 3, 4, 4.5, 5, 6, 7, 8],
'min_sources': 30,
'target_time': '20-45 min',
'description': 'M&A due diligence'
}
}
config = mode_config[args.mode]
print(f"Configuration:")
print(f" Phases: {config['phases']}")
print(f" Min Sources: {config['min_sources']}")
print(f" Target Time: {config['target_time']}")
print(f" Description: {config['description']}")
print()
print("Note: Full research execution requires Claude Code skill invocation.")
print("This CLI provides configuration preview and testing utilities.")
print()
# Generate output directory name
timestamp = datetime.now().strftime('%Y%m%d')
topic_slug = args.query[:30].replace(' ', '_').replace('/', '_')
output_dir = f"/code/{topic_slug}_Financial_Research_{timestamp}/"
print(f"Recommended output directory: {output_dir}")
print()
return 0
if __name__ == '__main__':
sys.exit(main())
#!/usr/bin/env python3
"""
Financial Source Credibility Evaluator
Assesses source quality, credibility, and potential biases for financial research
"""
from dataclasses import dataclass
from typing import List, Dict, Optional
from urllib.parse import urlparse
from datetime import datetime, timedelta
import re
@dataclass
class CredibilityScore:
"""Represents financial source credibility assessment"""
overall_score: float # 0-100
domain_authority: float # 0-100
recency: float # 0-100
expertise: float # 0-100
bias_score: float # 0-100 (higher = more neutral)
tier: int # 1-4 (1 = highest credibility)
factors: Dict[str, str]
recommendation: str # "high_trust", "moderate_trust", "low_trust", "verify"
class FinancialSourceEvaluator:
"""Evaluates financial source credibility and quality with tiered system"""
# Tier 1: Primary/Regulatory Sources (Highest Credibility)
TIER_1_DOMAINS = {
# SEC & Regulatory
'sec.gov', 'edgar.sec.gov', 'investor.gov',
'federalreserve.gov', 'treasury.gov', 'fdic.gov',
'occ.gov', 'finra.org', 'cftc.gov', 'bis.org',
# Company IR (pattern-based, checked separately)
# ir.*, investor.*, investors.*
# Stock Exchanges
'nyse.com', 'nasdaq.com', 'ice.com', 'cmegroup.com',
# International Regulators
'fca.org.uk', 'esma.europa.eu', 'bafin.de',
}
# Tier 2: Financial Data Providers (High Credibility)
TIER_2_DOMAINS = {
# Major Data Providers
'bloomberg.com', 'reuters.com', 'refinitiv.com',
'spglobal.com', 'capitaliq.com', 'moodys.com',
'fitchratings.com', 'factset.com', 'morningstar.com',
'pitchbook.com', 'preqin.com', 'dealogic.com',
# Research Providers
'mckinsey.com', 'bcg.com', 'bain.com', 'deloitte.com',
'pwc.com', 'ey.com', 'kpmg.com',
}
# Tier 3: Financial News & Research (Moderate-High Credibility)
TIER_3_DOMAINS = {
# Established Financial News
'wsj.com', 'ft.com', 'barrons.com', 'economist.com',
'marketwatch.com', 'investopedia.com', 'thestreet.com',
# Business News
'cnbc.com', 'fortune.com', 'businessinsider.com',
'forbes.com', 'bloomberg.com', # News articles
# Industry Publications
'americanbanker.com', 'institutionalinvestor.com',
'privateequityinternational.com', 'pensions-investments.com',
}
# Tier 4: General Business Sources (Moderate Credibility)
TIER_4_DOMAINS = {
# General Finance
'finance.yahoo.com', 'google.com/finance',
'seekingalpha.com', 'fool.com', 'zacks.com',
'tipranks.com', 'gurufocus.com',
# General News
'nytimes.com', 'washingtonpost.com', 'bbc.com',
'cnn.com', 'theguardian.com',
# Tech/Business Blogs
'medium.com', 'substack.com', 'linkedin.com',
}
# Low credibility indicators
LOW_CREDIBILITY_INDICATORS = [
'blogspot.com', 'wordpress.com', 'wix.com',
'reddit.com', 'twitter.com', 'facebook.com',
'stocktwits.com', 'wallstreetbets',
]
def __init__(self):
pass
def evaluate_source(
self,
url: str,
title: str,
content: Optional[str] = None,
publication_date: Optional[str] = None,
author: Optional[str] = None
) -> CredibilityScore:
"""Evaluate financial source credibility"""
domain = self._extract_domain(url)
# Determine tier first
tier = self._determine_tier(domain, url)
# Calculate component scores
domain_score = self._evaluate_domain_authority(domain, tier)
recency_score = self._evaluate_recency(publication_date)
expertise_score = self._evaluate_expertise(domain, title, author, tier)
bias_score = self._evaluate_bias(domain, title, content, tier)
# Calculate overall score (weighted average)
overall = (
domain_score * 0.40 + # Higher weight for domain in financial
recency_score * 0.20 +
expertise_score * 0.25 +
bias_score * 0.15
)
# Determine factors
factors = self._identify_factors(
domain, tier, domain_score, recency_score, expertise_score, bias_score
)
# Generate recommendation
recommendation = self._generate_recommendation(overall, tier)
return CredibilityScore(
overall_score=round(overall, 2),
domain_authority=round(domain_score, 2),
recency=round(recency_score, 2),
expertise=round(expertise_score, 2),
bias_score=round(bias_score, 2),
tier=tier,
factors=factors,
recommendation=recommendation
)
def _extract_domain(self, url: str) -> str:
"""Extract domain from URL"""
parsed = urlparse(url)
domain = parsed.netloc.lower()
# Remove www prefix
domain = domain.replace('www.', '')
return domain
def _determine_tier(self, domain: str, url: str) -> int:
"""Determine source tier (1-4)"""
# Check Tier 1
if domain in self.TIER_1_DOMAINS:
return 1
# Check for company IR sites (Tier 1)
if any(pattern in domain for pattern in ['ir.', 'investor.', 'investors.']):
return 1
# SEC EDGAR links
if 'sec.gov' in url:
return 1
# Check Tier 2
if domain in self.TIER_2_DOMAINS:
return 2
# Check Tier 3
if domain in self.TIER_3_DOMAINS:
return 3
# Check Tier 4
if domain in self.TIER_4_DOMAINS:
return 4
# Check low credibility
if any(indicator in domain for indicator in self.LOW_CREDIBILITY_INDICATORS):
return 4 # Lowest tier
# Unknown domain - default to tier 4
return 4
def _evaluate_domain_authority(self, domain: str, tier: int) -> float:
"""Evaluate domain authority based on tier (0-100)"""
tier_scores = {
1: 95.0, # Regulatory/Primary
2: 82.0, # Data Providers
3: 68.0, # Financial News
4: 50.0, # General Business
}
base_score = tier_scores.get(tier, 50.0)
# Bonus for specific high-authority domains
if 'sec.gov' in domain:
base_score = 100.0
elif 'federalreserve.gov' in domain:
base_score = 98.0
elif domain in ['bloomberg.com', 'reuters.com']:
base_score = 88.0
# Penalty for low credibility indicators
if any(indicator in domain for indicator in self.LOW_CREDIBILITY_INDICATORS):
base_score = min(base_score, 35.0)
return base_score
def _evaluate_recency(self, publication_date: Optional[str]) -> float:
"""Evaluate information recency (0-100)"""
if not publication_date:
return 50.0 # Unknown date
try:
pub_date = datetime.fromisoformat(publication_date.replace('Z', '+00:00'))
age = datetime.now() - pub_date
# Financial data has stricter recency requirements
if age < timedelta(days=30): # < 1 month
return 100.0
elif age < timedelta(days=90): # < 3 months
return 90.0
elif age < timedelta(days=180): # < 6 months
return 75.0
elif age < timedelta(days=365): # < 1 year
return 60.0
elif age < timedelta(days=730): # < 2 years
return 45.0
else:
return 30.0
except Exception:
return 50.0
def _evaluate_expertise(
self,
domain: str,
title: str,
author: Optional[str],
tier: int
) -> float:
"""Evaluate source expertise (0-100)"""
base_score = 50.0
# Tier-based expertise
tier_expertise = {1: 40, 2: 30, 3: 20, 4: 10}
base_score += tier_expertise.get(tier, 0)
# SEC filings are authoritative
if 'sec.gov' in domain or '10-K' in title or '10-Q' in title:
base_score += 20
# Earnings/financial content
if any(term in title.lower() for term in ['earnings', 'quarterly', 'annual report', 'financial results']):
base_score += 10
# Analyst/research content
if any(term in title.lower() for term in ['analysis', 'research', 'rating', 'estimate']):
base_score += 5
# Author credentials
if author:
if any(title in author.lower() for title in ['cfa', 'cpa', 'phd', 'analyst', 'economist']):
base_score += 10
return min(base_score, 100.0)
def _evaluate_bias(
self,
domain: str,
title: str,
content: Optional[str],
tier: int
) -> float:
"""Evaluate potential bias (0-100, higher = more neutral)"""
base_score = 70.0
# Tier-based bias (regulatory sources are most neutral)
tier_bias = {1: 20, 2: 10, 3: 0, 4: -10}
base_score += tier_bias.get(tier, 0)
# Check for sensationalism in title
sensational_indicators = [
'!', 'shocking', 'crash', 'explode', 'moon', 'rocket',
'guaranteed', 'secret', 'you won\'t believe', 'millionaire'
]
title_lower = title.lower()
if any(indicator in title_lower for indicator in sensational_indicators):
base_score -= 25
# Promotional content indicators
promotional = ['buy now', 'limited time', 'act fast', 'don\'t miss']
if any(promo in title_lower for promo in promotional):
base_score -= 30
# Seeking Alpha, retail sources may have bias
if 'seekingalpha' in domain or 'fool.com' in domain:
base_score -= 10
# Check for balance in content
if content:
balanced_indicators = ['however', 'risk', 'downside', 'bear case', 'concerns']
if any(indicator in content.lower() for indicator in balanced_indicators):
base_score += 10
return min(max(base_score, 0), 100.0)
def _identify_factors(
self,
domain: str,
tier: int,
domain_score: float,
recency_score: float,
expertise_score: float,
bias_score: float
) -> Dict[str, str]:
"""Identify key credibility factors"""
factors = {}
# Tier factor
tier_names = {
1: "Tier 1: Primary/Regulatory source",
2: "Tier 2: Financial data provider",
3: "Tier 3: Financial news/research",
4: "Tier 4: General business source"
}
factors['tier'] = tier_names.get(tier, "Unknown tier")
if domain_score >= 90:
factors['domain'] = "Highest authority financial source"
elif domain_score >= 75:
factors['domain'] = "High authority financial source"
elif domain_score <= 45:
factors['domain'] = "Low authority - verify with primary sources"
if recency_score >= 90:
factors['recency'] = "Very recent financial data"
elif recency_score <= 50:
factors['recency'] = "Dated information - verify currency"
if expertise_score >= 80:
factors['expertise'] = "Expert financial source"
elif expertise_score <= 50:
factors['expertise'] = "Limited financial expertise"
if bias_score >= 80:
factors['bias'] = "Objective/neutral perspective"
elif bias_score <= 50:
factors['bias'] = "Potential bias detected"
return factors
def _generate_recommendation(self, overall_score: float, tier: int) -> str:
"""Generate trust recommendation"""
# Tier 1 sources get higher trust
if tier == 1 and overall_score >= 70:
return "high_trust"
elif tier == 1:
return "moderate_trust"
# Other tiers
if overall_score >= 80:
return "high_trust"
elif overall_score >= 65:
return "moderate_trust"
elif overall_score >= 50:
return "low_trust"
else:
return "verify"
# Example usage
if __name__ == '__main__':
evaluator = FinancialSourceEvaluator()
# Test sources
test_sources = [
{
'url': 'https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK=0000320193',
'title': 'Apple Inc. 10-K Annual Report 2024',
'publication_date': '2024-11-01'
},
{
'url': 'https://www.bloomberg.com/news/articles/2024-10-30/apple-earnings',
'title': 'Apple Reports Record Q4 Revenue',
'publication_date': '2024-10-30'
},
{
'url': 'https://seekingalpha.com/article/apple-buy-now',
'title': 'Apple: BUY NOW Before It Explodes!',
'publication_date': '2024-10-15'
},
{
'url': 'https://ir.apple.com/investor-relations',
'title': 'Apple Investor Relations - Q4 2024 Earnings Call',
'publication_date': '2024-10-31'
}
]
for source in test_sources:
score = evaluator.evaluate_source(**source)
print(f"\nSource: {source['title'][:50]}...")
print(f"URL: {source['url'][:60]}...")
print(f"Tier: {score.tier}")
print(f"Overall Score: {score.overall_score}/100")
print(f"Recommendation: {score.recommendation}")
print(f"Factors: {score.factors}")
#!/usr/bin/env python3
"""
Financial Report Validation Script
Ensures financial research reports meet quality standards before delivery
"""
import argparse
import re
import sys
from pathlib import Path
from typing import List, Tuple, Dict
class FinancialReportValidator:
"""Validates financial research report quality"""
def __init__(self, report_path: Path):
self.report_path = report_path
self.content = self._read_report()
self.errors: List[str] = []
self.warnings: List[str] = []
def _read_report(self) -> str:
"""Read report file"""
try:
with open(self.report_path, 'r', encoding='utf-8') as f:
return f.read()
except Exception as e:
print(f"ERROR: Cannot read report: {e}")
sys.exit(1)
def validate(self) -> bool:
"""Run all validation checks"""
print(f"\n{'='*60}")
print(f"VALIDATING FINANCIAL REPORT: {self.report_path.name}")
print(f"{'='*60}\n")
checks = [
("Executive Summary", self._check_executive_summary),
("Required Sections", self._check_required_sections),
("Financial Sections", self._check_financial_sections),
("Citations", self._check_citations),
("Bibliography", self._check_bibliography),
("Placeholder Text", self._check_placeholders),
("Content Truncation", self._check_content_truncation),
("Word Count", self._check_word_count),
("Source Count", self._check_source_count),
("Financial Data", self._check_financial_data),
("Broken Links", self._check_broken_references),
]
for check_name, check_func in checks:
print(f"Checking: {check_name}...", end=" ")
passed = check_func()
if passed:
print("PASS")
else:
print("FAIL")
self._print_summary()
return len(self.errors) == 0
def _check_executive_summary(self) -> bool:
"""Check executive summary exists and is under 250 words"""
pattern = r'## Executive Summary(.*?)(?=##|\Z)'
match = re.search(pattern, self.content, re.DOTALL | re.IGNORECASE)
if not match:
self.errors.append("Missing 'Executive Summary' section")
return False
summary = match.group(1).strip()
word_count = len(summary.split())
if word_count > 300:
self.warnings.append(f"Executive summary too long: {word_count} words (should be <=250)")
if word_count < 50:
self.warnings.append(f"Executive summary too short: {word_count} words (should be >=50)")
# Check for investment thesis
if 'thesis' not in summary.lower() and 'recommendation' not in summary.lower():
self.warnings.append("Executive summary missing clear investment thesis/recommendation")
return True
def _check_required_sections(self) -> bool:
"""Check all required sections are present"""
required = [
"Executive Summary",
"Overview", # Company/Topic Overview
"Financial Analysis",
"Valuation",
"Competitive", # Competitive Position
"Risk", # Risk Factors
"Recommendation",
"Bibliography",
"Methodology"
]
missing = []
for section in required:
if not re.search(rf'##.*{section}', self.content, re.IGNORECASE):
missing.append(section)
if missing:
self.errors.append(f"Missing required sections: {', '.join(missing)}")
return False
return True
def _check_financial_sections(self) -> bool:
"""Check financial-specific sections"""
recommended = [
"Revenue",
"Margin",
"Cash Flow",
"Balance Sheet",
"Bull Case",
"Bear Case"
]
missing_recommended = []
for section in recommended:
if section.lower() not in self.content.lower():
missing_recommended.append(section)
if len(missing_recommended) > 3:
self.warnings.append(f"Missing recommended financial content: {', '.join(missing_recommended)}")
return True
def _check_citations(self) -> bool:
"""Check citation format and presence"""
citations = re.findall(r'\[(\d+)\]', self.content)
if not citations:
self.errors.append("No citations found in report")
return False
unique_citations = set(citations)
if len(unique_citations) < 10:
self.warnings.append(f"Only {len(unique_citations)} unique sources cited (recommended: >=10)")
# Check for consecutive citation numbers
citation_nums = sorted([int(c) for c in unique_citations])
if citation_nums:
max_citation = max(citation_nums)
expected = set(range(1, max_citation + 1))
missing = expected - set(citation_nums)
if missing:
self.warnings.append(f"Non-consecutive citation numbers, missing: {sorted(missing)}")
return True
def _check_bibliography(self) -> bool:
"""Check bibliography exists, matches citations, and has no truncation placeholders"""
pattern = r'## Bibliography(.*?)(?=##|\Z)'
match = re.search(pattern, self.content, re.DOTALL | re.IGNORECASE)
if not match:
self.errors.append("Missing 'Bibliography' section")
return False
bib_section = match.group(1)
# Check for truncation placeholders
truncation_patterns = [
(r'\[\d+-\d+\]', 'Citation range (e.g., [8-75])'),
(r'Additional.*citations', 'Phrase "Additional citations"'),
(r'would be included', 'Phrase "would be included"'),
(r'\[\.\.\.continue', 'Pattern "[...continue"'),
(r'\[Continue with', 'Pattern "[Continue with"'),
(r'etc\.(?!\w)', 'Standalone "etc."'),
]
for pattern_re, description in truncation_patterns:
if re.search(pattern_re, bib_section, re.IGNORECASE):
self.errors.append(f"CRITICAL: Bibliography contains truncation placeholder: {description}")
return False
# Count bibliography entries
bib_entries = re.findall(r'^\[(\d+)\]', bib_section, re.MULTILINE)
if not bib_entries:
self.errors.append("Bibliography has no entries")
return False
# Check for tier organization (recommended for financial)
if 'Tier 1' not in bib_section and 'tier 1' not in bib_section.lower():
self.warnings.append("Bibliography not organized by source tier (recommended for financial reports)")
# Find citations in text
text_citations = set(re.findall(r'\[(\d+)\]', self.content))
bib_citations = set(bib_entries)
# Check all citations have bibliography entries
missing_in_bib = text_citations - bib_citations
if missing_in_bib:
self.errors.append(f"Citations missing from bibliography: {sorted(missing_in_bib)}")
return False
return True
def _check_placeholders(self) -> bool:
"""Check for placeholder text that shouldn't be in final report"""
placeholders = [
'TBD', 'TODO', 'FIXME', 'XXX',
'[citation needed]', '[needs citation]',
'[placeholder]', '[TODO]', '[TBD]',
'$X.XB', 'XX.X%', '[N]' # Template placeholders
]
found_placeholders = []
for placeholder in placeholders:
if placeholder in self.content:
found_placeholders.append(placeholder)
if found_placeholders:
self.errors.append(f"Found placeholder text: {', '.join(found_placeholders)}")
return False
return True
def _check_content_truncation(self) -> bool:
"""Check for content truncation patterns"""
truncation_patterns = [
(r'Content continues', 'Phrase "Content continues"'),
(r'Due to length', 'Phrase "Due to length"'),
(r'would continue', 'Phrase "would continue"'),
(r'\[Sections \d+-\d+', 'Pattern "[Sections X-Y"'),
(r'Additional sections', 'Phrase "Additional sections"'),
]
for pattern_re, description in truncation_patterns:
if re.search(pattern_re, self.content, re.IGNORECASE):
self.errors.append(f"CRITICAL: Content truncation detected: {description}")
return False
return True
def _check_word_count(self) -> bool:
"""Check overall report length"""
word_count = len(self.content.split())
if word_count < 1000:
self.warnings.append(f"Report is very short: {word_count} words (financial reports should be 2000+)")
print(f" (Word count: {word_count})")
return True
def _check_source_count(self) -> bool:
"""Check minimum source count"""
pattern = r'## Bibliography(.*?)(?=##|\Z)'
match = re.search(pattern, self.content, re.DOTALL | re.IGNORECASE)
if not match:
return True # Already caught in bibliography check
bib_section = match.group(1)
bib_entries = re.findall(r'^\[(\d+)\]', bib_section, re.MULTILINE)
source_count = len(set(bib_entries))
if source_count < 10:
self.warnings.append(f"Only {source_count} sources (recommended: >=10 for financial reports)")
# Check for Tier 1 sources (regulatory/primary)
tier1_indicators = ['sec.gov', 'SEC', '10-K', '10-Q', 'EDGAR', 'investor relations', 'IR']
tier1_count = sum(1 for indicator in tier1_indicators if indicator in bib_section)
if tier1_count < 2:
self.warnings.append("Limited Tier 1 (regulatory/primary) sources - consider adding SEC filings")
return True
def _check_financial_data(self) -> bool:
"""Check for presence of key financial data"""
required_metrics = [
(r'\$[\d,.]+[BMK]', 'Dollar amounts'),
(r'\d+\.?\d*%', 'Percentages'),
(r'FY\d{4}|Q[1-4]\s*\d{4}', 'Fiscal periods'),
]
for pattern, description in required_metrics:
if not re.search(pattern, self.content):
self.warnings.append(f"Missing financial data: {description}")
# Check for financial tables
if '|' not in self.content:
self.warnings.append("No data tables found (recommended for financial reports)")
return True
def _check_broken_references(self) -> bool:
"""Check for broken internal references"""
internal_links = re.findall(r'\[.*?\]\((\.\/.*?)\)', self.content)
broken = []
for link in internal_links:
link_path = link.split('#')[0]
full_path = self.report_path.parent / link_path
if not full_path.exists():
broken.append(link)
if broken:
self.errors.append(f"Broken internal links: {', '.join(broken)}")
return False
return True
def _print_summary(self):
"""Print validation summary"""
print(f"\n{'='*60}")
print(f"VALIDATION SUMMARY")
print(f"{'='*60}\n")
if self.errors:
print(f"ERRORS ({len(self.errors)}):")
for error in self.errors:
print(f" - {error}")
print()
if self.warnings:
print(f"WARNINGS ({len(self.warnings)}):")
for warning in self.warnings:
print(f" - {warning}")
print()
if not self.errors and not self.warnings:
print("ALL CHECKS PASSED - Report meets financial quality standards!\n")
elif not self.errors:
print("VALIDATION PASSED (with warnings)\n")
else:
print("VALIDATION FAILED - Please fix errors before delivery\n")
def main():
parser = argparse.ArgumentParser(
description="Validate financial research report quality",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
python validate_report.py --report report.md
python validate_report.py -r ~/research/financial_report_20251104.md
"""
)
parser.add_argument(
'--report', '-r',
type=str,
required=True,
help='Path to financial research report markdown file'
)
args = parser.parse_args()
report_path = Path(args.report)
if not report_path.exists():
print(f"ERROR: Report file not found: {report_path}")
sys.exit(1)
validator = FinancialReportValidator(report_path)
passed = validator.validate()
sys.exit(0 if passed else 1)
if __name__ == '__main__':
main()
#!/usr/bin/env python3
"""
Financial Citation Verification Script
Catches fabricated citations by checking:
1. SEC EDGAR filing verification
2. DOI resolution (via doi.org)
3. Basic metadata matching
4. URL accessibility verification
5. Financial data pattern detection
6. Flags suspicious entries for manual review
Usage:
python verify_citations.py --report [path]
python verify_citations.py --report [path] --strict
Does NOT require API keys - uses free DOI resolver and SEC EDGAR.
"""
import sys
import argparse
import re
from pathlib import Path
from typing import List, Dict, Tuple
from urllib import request, error
from urllib.parse import quote
import json
import time
class FinancialCitationVerifier:
"""Verify citations in financial research report"""
def __init__(self, report_path: Path, strict_mode: bool = False):
self.report_path = report_path
self.strict_mode = strict_mode
self.content = self._read_report()
self.suspicious = []
self.verified = []
self.errors = []
# Financial-specific hallucination patterns
self.suspicious_patterns = [
# Generic financial-sounding but potentially fake
(r'^(A |An |The )?(Comprehensive |Complete )?(Analysis|Review|Study) of',
"Generic financial title pattern"),
(r'^[A-Z][a-z]+ (Inc|Corp|Ltd)\.? (Financial|Earnings|Annual) (Report|Review)',
"Too generic company report title"),
# Future financial data (impossible)
(r'(Q[1-4]|FY)\s*202[6-9]',
"Future fiscal period reference"),
(r'(Q[1-4]|FY)\s*203\d',
"Future fiscal period reference"),
]
# SEC filing patterns for verification
self.sec_filing_patterns = [
r'10-K', r'10-Q', r'8-K', r'DEF 14A', r'S-1', r'424B',
r'Form 10-K', r'Form 10-Q', r'Form 8-K'
]
def _read_report(self) -> str:
"""Read report file"""
try:
with open(self.report_path, 'r', encoding='utf-8') as f:
return f.read()
except Exception as e:
print(f"ERROR: Cannot read report: {e}")
sys.exit(1)
def extract_bibliography(self) -> List[Dict]:
"""Extract bibliography entries from report"""
pattern = r'## Bibliography(.*?)(?=##|\Z)'
match = re.search(pattern, self.content, re.DOTALL | re.IGNORECASE)
if not match:
self.errors.append("No Bibliography section found")
return []
bib_section = match.group(1)
entries = []
lines = bib_section.strip().split('\n')
current_entry = None
for line in lines:
line = line.strip()
if not line or line.startswith('#'):
continue
match_num = re.match(r'^\[(\d+)\]\s+(.+)$', line)
if match_num:
if current_entry:
entries.append(current_entry)
num = match_num.group(1)
rest = match_num.group(2)
# Parse entry components
year_match = re.search(r'\((\d{4})\)', rest)
title_match = re.search(r'"([^"]+)"', rest)
doi_match = re.search(r'doi\.org/(10\.\S+)', rest)
url_match = re.search(r'https?://[^\s\)]+', rest)
sec_match = any(re.search(p, rest, re.IGNORECASE) for p in self.sec_filing_patterns)
current_entry = {
'num': num,
'raw': rest,
'year': year_match.group(1) if year_match else None,
'title': title_match.group(1) if title_match else None,
'doi': doi_match.group(1) if doi_match else None,
'url': url_match.group(0) if url_match else None,
'is_sec_filing': sec_match,
'is_tier1': sec_match or ('sec.gov' in rest.lower()) or ('ir.' in rest.lower())
}
elif current_entry:
current_entry['raw'] += ' ' + line
if current_entry:
entries.append(current_entry)
return entries
def verify_sec_edgar(self, url: str) -> Tuple[bool, str]:
"""Verify SEC EDGAR URL is accessible"""
if not url or 'sec.gov' not in url:
return False, "Not an SEC URL"
try:
req = request.Request(url)
req.add_header('User-Agent', 'Mozilla/5.0 (Financial Research Verifier)')
with request.urlopen(req, timeout=15) as response:
if response.status == 200:
return True, "SEC filing verified"
else:
return False, f"HTTP {response.status}"
except error.HTTPError as e:
return False, f"HTTP {e.code}"
except Exception as e:
return False, f"Connection error: {str(e)[:50]}"
def verify_doi(self, doi: str) -> Tuple[bool, Dict]:
"""Verify DOI exists and get metadata"""
if not doi:
return False, {}
try:
url = f"https://doi.org/{quote(doi)}"
req = request.Request(url)
req.add_header('Accept', 'application/vnd.citationstyles.csl+json')
with request.urlopen(req, timeout=10) as response:
data = json.loads(response.read().decode('utf-8'))
return True, {
'title': data.get('title', ''),
'year': data.get('issued', {}).get('date-parts', [[None]])[0][0],
}
except error.HTTPError as e:
if e.code == 404:
return False, {'error': 'DOI not found'}
return False, {'error': f'HTTP {e.code}'}
except Exception as e:
return False, {'error': str(e)}
def verify_url(self, url: str) -> Tuple[bool, str]:
"""Verify URL is accessible"""
if not url:
return False, "No URL"
try:
req = request.Request(url, method='HEAD')
req.add_header('User-Agent', 'Mozilla/5.0 (Financial Research Verifier)')
with request.urlopen(req, timeout=10) as response:
if response.status == 200:
return True, "URL accessible"
else:
return False, f"HTTP {response.status}"
except error.HTTPError as e:
# Some sites block HEAD, try GET
if e.code == 405:
try:
req = request.Request(url)
req.add_header('User-Agent', 'Mozilla/5.0')
with request.urlopen(req, timeout=10) as response:
return True, "URL accessible (GET)"
except:
pass
return False, f"HTTP {e.code}"
except Exception as e:
return False, f"Error: {str(e)[:50]}"
def detect_hallucination_patterns(self, entry: Dict) -> List[str]:
"""Detect common LLM hallucination patterns in financial citations"""
issues = []
title = entry.get('title', '')
raw = entry.get('raw', '')
if not title:
return issues
# Check suspicious patterns
for pattern, description in self.suspicious_patterns:
if re.match(pattern, title, re.IGNORECASE):
issues.append(f"Suspicious pattern: {description}")
# Check for future dates
if entry.get('year'):
year = int(entry['year'])
if year > 2025:
issues.append(f"Future year: {year}")
# Financial-specific: Check for impossible metrics
impossible_patterns = [
(r'\d{4,}%', "Implausible percentage (1000%+)"),
(r'\$\d{15,}', "Implausible dollar amount"),
]
for pattern, desc in impossible_patterns:
if re.search(pattern, raw):
issues.append(desc)
# Check for Tier 1 sources without verification method
if entry.get('is_tier1') and not entry.get('url') and not entry.get('doi'):
issues.append("Tier 1 source without verification URL")
return issues
def verify_entry(self, entry: Dict) -> Dict:
"""Verify a single bibliography entry"""
result = {
'num': entry['num'],
'status': 'unknown',
'issues': [],
'tier': 1 if entry.get('is_tier1') else 4,
'verification_methods': []
}
# Step 1: Hallucination detection
hallucination_issues = self.detect_hallucination_patterns(entry)
if hallucination_issues:
result['issues'].extend(hallucination_issues)
result['status'] = 'suspicious'
# Step 2: SEC filing verification (Tier 1)
if entry.get('is_sec_filing') and entry.get('url') and 'sec.gov' in entry['url']:
print(f" [{entry['num']}] Checking SEC EDGAR...", end=' ')
success, msg = self.verify_sec_edgar(entry['url'])
if success:
result['status'] = 'verified'
result['verification_methods'].append('SEC_EDGAR')
print("OK")
else:
result['issues'].append(f"SEC verification failed: {msg}")
print(f"FAIL: {msg}")
# Step 3: DOI verification
elif entry.get('doi'):
print(f" [{entry['num']}] Checking DOI...", end=' ')
success, metadata = self.verify_doi(entry['doi'])
if success:
result['status'] = 'verified'
result['verification_methods'].append('DOI')
print("OK")
else:
result['issues'].append(f"DOI failed: {metadata.get('error', 'unknown')}")
result['status'] = 'unverified'
print(f"FAIL")
# Step 4: URL verification
if entry.get('url') and result['status'] not in ['verified']:
url_ok, url_status = self.verify_url(entry['url'])
if url_ok:
result['verification_methods'].append('URL')
if result['status'] in ['unknown', 'unverified']:
result['status'] = 'url_verified'
print(f" [{entry['num']}] URL verified")
else:
result['issues'].append(f"URL check failed: {url_status}")
# Step 5: No verification method
if not entry.get('url') and not entry.get('doi'):
result['issues'].append("No verification method (URL or DOI)")
if result['status'] == 'unknown':
result['status'] = 'unverified'
return result
def verify_all(self):
"""Verify all bibliography entries"""
print(f"\n{'='*60}")
print(f"FINANCIAL CITATION VERIFICATION: {self.report_path.name}")
print(f"{'='*60}\n")
entries = self.extract_bibliography()
if not entries:
print("No bibliography entries found\n")
return False
# Count by tier
tier1_count = sum(1 for e in entries if e.get('is_tier1'))
print(f"Found {len(entries)} citations ({tier1_count} Tier 1 sources)\n")
results = []
for entry in entries:
result = self.verify_entry(entry)
results.append(result)
time.sleep(0.3) # Rate limiting
# Summarize
print(f"\n{'='*60}")
print(f"VERIFICATION SUMMARY")
print(f"{'='*60}\n")
verified = [r for r in results if r['status'] == 'verified']
url_verified = [r for r in results if r['status'] == 'url_verified']
suspicious = [r for r in results if r['status'] == 'suspicious']
unverified = [r for r in results if r['status'] in ['unverified', 'unknown']]
total_verified = len(verified) + len(url_verified)
print(f"Fully Verified: {len(verified)}/{len(results)}")
print(f"URL Verified: {len(url_verified)}/{len(results)}")
print(f"Suspicious: {len(suspicious)}/{len(results)}")
print(f"Unverified: {len(unverified)}/{len(results)}")
print()
if suspicious:
print("SUSPICIOUS CITATIONS (Manual Review Required):")
for r in suspicious:
print(f"\n [{r['num']}]")
for issue in r['issues']:
print(f" - {issue}")
print()
# Financial-specific: Check Tier 1 source ratio
tier1_verified = sum(1 for r in results if r['tier'] == 1 and r['status'] in ['verified', 'url_verified'])
if tier1_verified < 2:
print("WARNING: Less than 2 verified Tier 1 sources (SEC filings, company IR)")
print(" Financial reports should include primary sources\n")
# Decision
if suspicious and self.strict_mode:
print("STRICT MODE: Failing due to suspicious citations")
return False
if total_verified / len(results) < 0.5:
print("WARNING: Less than 50% citations verified")
return True # Pass with warning
print("CITATION VERIFICATION PASSED")
return True
def main():
parser = argparse.ArgumentParser(
description="Verify citations in financial research report"
)
parser.add_argument(
'--report', '-r',
type=str,
required=True,
help='Path to financial research report'
)
parser.add_argument(
'--strict',
action='store_true',
help='Strict mode: fail on suspicious citations'
)
args = parser.parse_args()
report_path = Path(args.report)
if not report_path.exists():
print(f"ERROR: Report not found: {report_path}")
sys.exit(1)
verifier = FinancialCitationVerifier(report_path, strict_mode=args.strict)
passed = verifier.verify_all()
sys.exit(0 if passed else 1)
if __name__ == '__main__':
main()
#!/usr/bin/env python3
"""
HTML Financial Report Verification Script
Validates that HTML reports are properly generated with all sections from MD
"""
import argparse
import re
from pathlib import Path
from typing import List
class FinancialHTMLVerifier:
"""Verify HTML financial research reports"""
def __init__(self, html_path: Path, md_path: Path):
self.html_path = html_path
self.md_path = md_path
self.errors = []
self.warnings = []
def verify(self) -> bool:
"""Run all verification checks"""
print(f"\n{'='*60}")
print(f"HTML FINANCIAL REPORT VERIFICATION")
print(f"{'='*60}\n")
print(f"HTML File: {self.html_path}")
print(f"MD File: {self.md_path}\n")
try:
html_content = self.html_path.read_text()
md_content = self.md_path.read_text()
except Exception as e:
self.errors.append(f"Failed to read files: {e}")
return False
# Run checks
self._check_sections(html_content, md_content)
self._check_no_placeholders(html_content)
self._check_no_emojis(html_content)
self._check_structure(html_content)
self._check_financial_elements(html_content)
self._check_citations(html_content, md_content)
self._check_bibliography(html_content, md_content)
self._print_results()
return len(self.errors) == 0
def _check_sections(self, html: str, md: str):
"""Verify all markdown sections are present in HTML"""
md_sections = re.findall(r'^## (.+)$', md, re.MULTILINE)
html_sections = re.findall(r'<h2 class="section-title">(.+?)</h2>', html)
if len(md_sections) > len(html_sections) + 1:
self.errors.append(
f"Section count mismatch: MD has {len(md_sections)}, HTML has {len(html_sections)}"
)
def _check_no_placeholders(self, html: str):
"""Check for unreplaced placeholders"""
placeholders = [
'{{TITLE}}', '{{DATE}}', '{{CONTENT}}', '{{BIBLIOGRAPHY}}',
'{{METRICS_DASHBOARD}}', '{{SOURCE_COUNT}}', '{{INVESTMENT_THESIS}}',
'TODO', 'TBD', 'PLACEHOLDER', '$X.XB', 'XX.X%'
]
found = [p for p in placeholders if p in html]
if found:
self.errors.append(f"Found unreplaced placeholders: {', '.join(found)}")
def _check_no_emojis(self, html: str):
"""Verify no emojis in HTML"""
emoji_pattern = re.compile(
"["
"\U0001F600-\U0001F64F"
"\U0001F300-\U0001F5FF"
"\U0001F680-\U0001F6FF"
"\U0001F1E0-\U0001F1FF"
"\U00002702-\U000027B0"
"\U000024C2-\U0001F251"
"]+",
flags=re.UNICODE
)
emojis = emoji_pattern.findall(html)
if emojis:
self.errors.append(f"Found {len(emojis)} emojis in HTML (should be none)")
def _check_structure(self, html: str):
"""Verify HTML has proper structure"""
required = [
('<html', 'HTML tag'),
('<head', 'head tag'),
('<body', 'body tag'),
('<title>', 'title tag'),
('class="header"', 'header section'),
('class="content"', 'content section'),
('class="bibliography"', 'bibliography section'),
]
for element, name in required:
if element not in html:
self.errors.append(f"Missing {name} in HTML")
def _check_financial_elements(self, html: str):
"""Check for financial-specific HTML elements"""
financial_elements = [
('class="metrics-dashboard"', 'Metrics dashboard'),
('class="data-table"', 'Data tables'),
]
for element, name in financial_elements:
if element not in html:
self.warnings.append(f"Missing {name} (recommended for financial reports)")
# Check for investment thesis
if 'investment-thesis' not in html and 'Investment Thesis' not in html:
self.warnings.append("Missing investment thesis section")
def _check_citations(self, html: str, md: str):
"""Verify citations are present"""
md_citations = set(re.findall(r'\[(\d+)\]', md))
html_content = html.split('class="bibliography"')[0] if 'class="bibliography"' in html else html
html_citations = set(re.findall(r'\[(\d+)\]', html_content))
if len(md_citations) > 0 and len(html_citations) == 0:
self.errors.append("No citations found in HTML content")
def _check_bibliography(self, html: str, md: str):
"""Verify bibliography is present"""
if '## Bibliography' in md:
if 'class="bibliography"' not in html:
self.errors.append("Bibliography section missing from HTML")
def _print_results(self):
"""Print verification results"""
print(f"\n{'-'*60}")
print("VERIFICATION RESULTS")
print(f"{'-'*60}\n")
if self.errors:
print(f"ERRORS ({len(self.errors)}):")
for error in self.errors:
print(f" - {error}")
print()
if self.warnings:
print(f"WARNINGS ({len(self.warnings)}):")
for warning in self.warnings:
print(f" - {warning}")
print()
if not self.errors and not self.warnings:
print("All checks passed! HTML report is valid.\n")
print(f"{'-'*60}\n")
def main():
parser = argparse.ArgumentParser(description='Verify HTML financial report')
parser.add_argument('--html', type=Path, required=True, help='Path to HTML report')
parser.add_argument('--md', type=Path, required=True, help='Path to markdown report')
args = parser.parse_args()
if not args.html.exists():
print(f"Error: HTML file not found: {args.html}")
return 1
if not args.md.exists():
print(f"Error: Markdown file not found: {args.md}")
return 1
verifier = FinancialHTMLVerifier(args.html, args.md)
success = verifier.verify()
return 0 if success else 1
if __name__ == "__main__":
exit(main())
Financial Research Report: [Topic/Company]
<!-- ============================================================================= PROGRESSIVE FILE ASSEMBLY STRATEGY (2025 - Unlimited Length):
This financial report is generated section-by-section using progressive file assembly. Each section is generated to APPROPRIATE depth and written to file immediately.
FINANCIAL PRECISION REQUIREMENTS:
- Every financial metric must include: exact number, currency, time period, source
- Examples: "Revenue of $94.8B in FY2024 [1]" not "strong revenue"
- Examples: "Gross margin of 43.2%, up 180bps YoY [2]" not "improving margins"
GENERATION WORKFLOW: 1. Executive Summary with Investment Thesis -> Write to file 2. Company/Topic Overview -> Edit/append to file 3. Financial Analysis -> Edit/append to file 4. Valuation Analysis -> Edit/append to file 5. Competitive Position -> Edit/append to file 6. Risk Factors -> Edit/append to file 7. Investment Thesis (Bull/Base/Bear) -> Edit/append to file 8. Recommendations -> Edit/append to file 9. Bibliography (ALL citations) -> Edit/append to file 10. Methodology Appendix -> Edit/append to file
CITATION TRACKING (CRITICAL):
- Maintain running list: citations_used = [1, 2, 3, ...]
- After each section: Add new citations to list
- In Bibliography: Generate entry for EVERY citation in final list
- NO gaps, NO ranges, NO placeholders
============================================================================= -->
Executive Summary
Investment Thesis: [One clear sentence stating the core investment thesis]
Key Metrics:
| Metric | Value | vs. Prior | Source |
|---|---|---|---|
| Market Cap | $X.XB | +X% YoY | [1] |
| Revenue (LTM) | $X.XB | +X% YoY | [1] |
| Net Income (LTM) | $X.XB | +X% YoY | [1] |
| P/E (Forward) | XX.Xx | vs XX.Xx sector | [2] |
Key Findings:
- Finding 1: [Major discovery with specific financial data]
- Finding 2: [Important insight with metrics]
- Finding 3: [Critical conclusion with implications]
Recommendation: [Buy/Hold/Sell or specific action] with [X]% confidence
Primary Risks: [Top 2-3 risks in brief]
---
Company/Topic Overview
Business Description
[2-3 paragraphs describing the company/topic]
- Business model and revenue drivers
- Key products/services and segments
- Geographic presence and customer base
Industry Context
[1-2 paragraphs on industry dynamics]
- Market size and growth rate
- Key trends affecting the industry
- Regulatory environment
Management Overview
[1 paragraph on leadership]
- CEO and key executives
- Track record and tenure
- Insider ownership and recent transactions
---
Financial Analysis
<!-- CRITICAL: Include specific numbers with sources for ALL metrics -->
Revenue Analysis
Revenue Performance:
| Period | Revenue | YoY Growth | Source |
|---|---|---|---|
| FY2024 | $X.XB | +X.X% | [1] |
| FY2023 | $X.XB | +X.X% | [1] |
| FY2022 | $X.XB | +X.X% | [1] |
[2-3 paragraphs analyzing revenue trends, drivers, and sustainability]
Segment Breakdown:
| Segment | Revenue | % of Total | Growth | Source |
|---|---|---|---|---|
| Segment A | $X.XB | XX% | +X% | [1] |
| Segment B | $X.XB | XX% | +X% | [1] |
Profitability Analysis
Margin Trends:
| Metric | Current | Prior Year | Change | Source |
|---|---|---|---|---|
| Gross Margin | XX.X% | XX.X% | +XXbps | [1] |
| Operating Margin | XX.X% | XX.X% | +XXbps | [1] |
| Net Margin | XX.X% | XX.X% | +XXbps | [1] |
[2-3 paragraphs analyzing margin trends, drivers, and outlook]
Cash Flow Analysis
Cash Flow Summary:
| Metric | FY2024 | FY2023 | Source |
|---|---|---|---|
| Operating Cash Flow | $X.XB | $X.XB | [1] |
| CapEx | $X.XB | $X.XB | [1] |
| Free Cash Flow | $X.XB | $X.XB | [1] |
| FCF Margin | XX.X% | XX.X% | Calculated |
[1-2 paragraphs on cash flow quality and capital allocation]
Balance Sheet Analysis
Financial Position:
| Metric | Current | Prior Year | Source |
|---|---|---|---|
| Cash & Equivalents | $X.XB | $X.XB | [1] |
| Total Debt | $X.XB | $X.XB | [1] |
| Net Debt | $X.XB | $X.XB | [1] |
| Debt/EBITDA | X.Xx | X.Xx | Calculated |
[1-2 paragraphs on balance sheet strength, liquidity, and leverage]
---
Valuation Analysis
Comparable Company Analysis
Peer Comparison:
| Company | Market Cap | P/E (Fwd) | EV/EBITDA | Rev Growth | Source |
|---|---|---|---|---|---|
| [Target] | $X.XB | XX.Xx | XX.Xx | +X.X% | [2] |
| Peer 1 | $X.XB | XX.Xx | XX.Xx | +X.X% | [2] |
| Peer 2 | $X.XB | XX.Xx | XX.Xx | +X.X% | [2] |
| Sector Median | - | XX.Xx | XX.Xx | +X.X% | [2] |
[2-3 paragraphs analyzing valuation relative to peers, premium/discount justification]
Historical Valuation
[1-2 paragraphs on historical valuation range and current positioning]
Analyst Consensus
Price Targets:
| Source | Rating | Price Target | Upside | Date | Source |
|---|---|---|---|---|---|
| Consensus | Buy | $XXX | +XX% | Current | [3] |
| High | - | $XXX | +XX% | - | [3] |
| Low | - | $XXX | -XX% | - | [3] |
[1 paragraph on analyst sentiment and recent rating changes]
---
Competitive Position
Market Position
[2-3 paragraphs on competitive positioning]
- Market share and ranking
- Competitive advantages (moat)
- Key differentiators
Competitive Dynamics
Competitive Landscape:
| Competitor | Market Share | Strengths | Weaknesses | Source |
|---|---|---|---|---|
| [Target] | XX% | [Key strength] | [Key weakness] | [4] |
| Competitor 1 | XX% | [Key strength] | [Key weakness] | [4] |
| Competitor 2 | XX% | [Key strength] | [Key weakness] | [4] |
[1-2 paragraphs on competitive threats and defensive positioning]
Competitive Moat Assessment
[1-2 paragraphs assessing durability of competitive advantages]
- Switching costs
- Network effects
- Cost advantages
- Intangible assets
- Efficient scale
---
Risk Factors
<!-- CRITICAL: Include specific, material risks with potential impact -->
Business Risks
Risk 1: [Specific Risk Name]
- Description: [What is the risk]
- Probability: [High/Medium/Low]
- Impact: [Potential financial impact]
- Mitigation: [How company addresses it]
- Source: [N]
Risk 2: [Specific Risk Name]
- [Same structure]
Financial Risks
Risk 1: [Specific Risk Name]
- [Same structure as above]
Regulatory Risks
Risk 1: [Specific Risk Name]
- [Same structure as above]
Market Risks
Risk 1: [Specific Risk Name]
- [Same structure as above]
Risk Summary Matrix
| Risk | Probability | Impact | Overall | Mitigation |
|---|---|---|---|---|
| [Risk 1] | High/Med/Low | High/Med/Low | [Score] | [Brief] |
| [Risk 2] | High/Med/Low | High/Med/Low | [Score] | [Brief] |
---
Investment Thesis
Bull Case
Thesis: [One sentence summary of bull case]
Key Assumptions: 1. [Assumption 1 with supporting evidence] 2. [Assumption 2 with supporting evidence] 3. [Assumption 3 with supporting evidence]
Implied Valuation: [Target price and upside]
Base Case
Thesis: [One sentence summary of base case]
Key Assumptions: 1. [Assumption 1] 2. [Assumption 2] 3. [Assumption 3]
Implied Valuation: [Target price and expected return]
Bear Case
Thesis: [One sentence summary of bear case]
Key Assumptions: 1. [Assumption 1] 2. [Assumption 2] 3. [Assumption 3]
Implied Valuation: [Target price and downside]
---
Recommendations
Immediate Actions
1. [Action Title]
- What: [Specific action]
- Why: [Rationale based on findings]
- Priority: [High/Medium/Low]
2. [Action Title]
- [Same structure]
Catalysts to Watch
| Catalyst | Expected Date | Potential Impact | Source |
|---|---|---|---|
| [Event 1] | [Date/Quarter] | [Impact description] | [N] |
| [Event 2] | [Date/Quarter] | [Impact description] | [N] |
Further Research Needs
1. [Research Topic]
- What to investigate: [Specific question]
- Why it matters: [Connection to thesis]
---
Bibliography
<!-- ============================================================================ --> <!-- CRITICAL: Generate COMPLETE bibliography with ALL sources cited in report --> <!-- DO NOT use placeholders like "[8-75] Additional citations" or "etc." --> <!-- EVERY citation [N] in report body MUST have corresponding entry here --> <!-- Format: [N] Source (Date). "Title". Publication/Filing. URL --> <!-- ============================================================================ -->
Tier 1 Sources (Regulatory/Primary)
[1] Company Name (2024). "Form 10-K Annual Report". SEC EDGAR. https://www.sec.gov/... (Retrieved: 2025-01-06)
[2] Company Name (2024). "Q3 2024 Earnings Release". Company IR. https://ir.company.com/... (Retrieved: 2025-01-06)
Tier 2 Sources (Data Providers)
[3] S&P Capital IQ (2024). "Company Financial Data". S&P Global. (Retrieved: 2025-01-06)
Tier 3 Sources (Financial News/Research)
[4] Author Name (2024). "Article Title". Wall Street Journal. https://wsj.com/... (Retrieved: 2025-01-06)
Tier 4 Sources (General Business)
[5] Author Name (2024). "Article Title". Source. https://... (Retrieved: 2025-01-06)
<!-- Continue with ALL remaining citations -->
---
Appendix: Methodology
Research Process
Phase Execution:
- Phase 1 (SCOPE): [What was done]
- Phase 2 (PLAN): [What was done]
- Phase 3 (RETRIEVE): [What was done]
- [Continue for all phases executed]
Sources Consulted
Total Sources: [Number]
Source Tier Breakdown:
- Tier 1 (Regulatory/Primary): [Number]
- Tier 2 (Data Providers): [Number]
- Tier 3 (Financial News): [Number]
- Tier 4 (General Business): [Number]
Average Credibility Score: [Number]/100
Verification Approach
Triangulation:
- Core financial claims verified across 2+ sources
- Primary source (SEC filing) used for all key metrics
- Analyst estimates cross-referenced
Quality Control:
- Validation checks performed
- Issues found and corrected
- Final quality metrics
Claims-Evidence Table
| Claim ID | Major Financial Claim | Evidence Type | Sources | Confidence |
|---|---|---|---|---|
| C1 | [First major claim] | SEC Filing | [1], [2] | High |
| C2 | [Second major claim] | Data Provider | [3], [4] | High |
| C3 | [Third major claim] | Analyst Research | [5] | Medium |
---
Report Metadata
Research Mode: [Quick/Standard/Deep/UltraDeep] Total Sources: [Number] Tier 1 Sources: [Number] Word Count: [Approximate count] Research Duration: [Time taken] Generated: [Date and time] Validation Status: [Passed with X warnings / Passed without warnings]
---
<!-- END OF TEMPLATE -->
Related skills
How it compares
Choose financial-deep-research over generic deep-research skills when regulatory filings and market-data source ranking matter more than broad topic exploration.
FAQ
What data sources does financial-deep-research prioritize?
financial-deep-research prioritizes institutional financial sources including SEC filings, Bloomberg, Reuters, S&P, and Morningstar before broader web results, giving developers regulatory-grade evidence for fintech and investment tooling.
What files does financial-deep-research generate?
financial-deep-research writes outputs into a research_output directory during runtime, producing PDF and HTML research artifacts that developers can version, share, or feed into downstream analysis pipelines.
Is Financial Deep Research safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.