← Files MorningstarARCHIVED FILE

skills/fund-summarizer/scripts/placeholder_defaults.py

9.2 KB · Sep 30, 2026 · 22:50 UTC

↓ Download file

"""Placeholder registry for fund summary reports.

This dict serves two purposes:
  1. Powers the --list-placeholders CLI output in render.py.
  2. Documents every {{PLACEHOLDER}} token in template.html.

The model is responsible for setting every key in the data package before
calling render_report. The renderer does not apply defaults — unset placeholders
will produce an unresolved token warning and an empty substitution.

Convention (applied by the model, not the renderer):
  Unavailable numeric value  →  "--"
  Unavailable text value     →  "N/A"
  Auto-generated by renderer →  do not set (marked below)
"""

PLACEHOLDERS: dict[str, str] = {
    # -------------------------------------------------------------------------
    # Identity
    # -------------------------------------------------------------------------
    "FUND_NAME": "Full fund name",
    "TICKER": "Primary ticker symbol",
    "FUND_STANDARD_NAME": "Morningstar standard name",
    "INVESTMENT_TYPE": "e.g. Open-End Fund, ETF",
    "BASE_CURRENCY": "e.g. USD",
    "ACTIVE_INDEX_LABEL": '"Active" or "Index"',
    "CATEGORY": "Morningstar Category",
    "INCEPTION_DATE": "Share class inception date",
    "OLDEST_SHARE_CLASS_INCEPTION": "Oldest share class inception date",
    "CLOSED_TO_NEW": '"Yes" or "No"',
    "PROSPECTUS_BENCHMARK": "Full benchmark name",
    "BENCHMARK_NAME": "Shortened benchmark display name (chart legend)",
    # -------------------------------------------------------------------------
    # Financials
    # -------------------------------------------------------------------------
    "FUND_SIZE": 'Compact string, e.g. "88.20B" or "456.00M"',
    "NAV": '2-decimal string, e.g. "123.46"',
    "MIN_INITIAL_PURCHASE": 'Comma-formatted integer string, e.g. "3,000"',
    "EXPENSE_RATIO": '"X.XX%"',
    "FEE_LEVEL": "Fee Level category",
    "FEE_LEVEL_DISTRIBUTION": "Fee Level across distribution channels",
    "TWELVE_MONTH_YIELD": '"X.XX%"',
    "SEC_YIELD": '"X.XX%"',
    "TURNOVER_RATIO": '"X.XX%"',
    "EST_NET_FLOW_1M": 'Compact string, e.g. "-3.40B" or "1.23M"',
    "EST_NET_FLOW_3M": "Compact string",
    "EST_NET_FLOW_1Y": "Compact string",
    "NUM_HOLDINGS": "Integer string",
    "OWNERSHIP_BREADTH": "Ownership breadth descriptor",
    "LIQUIDITY_INTERMITTENT": '"X.XX%"',
    # -------------------------------------------------------------------------
    # Ratings
    # -------------------------------------------------------------------------
    "MEDALIST_RATING": '"Gold", "Silver", "Bronze", "Neutral", or "Negative"',
    "MEDALIST_ANALYST_PCT": "Numeric string without % sign",
    "MEDALIST_DISCLOSURE_TYPE": "CNAXS value, passed as-is",
    "STAR_RATING": "Integer 1–5 (renderer derives STAR_RATING_DISPLAY)",
    "STAR_RATING_DISPLAY": "AUTO — star characters derived from STAR_RATING",
    "STAR_RATING_ICON": "AUTO — inline SVG (icon_embedder)",
    "MPRS": "Raw numeric; renderer rounds to whole number for dial SVG",
    "MPRS_VISUAL": "AUTO — inline SVG dial (icon_embedder)",
    # -------------------------------------------------------------------------
    # Pillars
    # -------------------------------------------------------------------------
    "PROCESS_RATING": "Pillar rating word",
    "PROCESS_SCORE_TYPE": "Quantitative / Not returned",
    "PROCESS_ICON": "AUTO — inline SVG (icon_embedder)",
    "PROCESS_SCORE_SCALE": "AUTO — inline SVG (icon_embedder)",
    "PROCESS_SUMMARY_HTML": "Model-built <p> HTML from PILLAR_SUMMARIES.process",
    "PEOPLE_RATING": "Pillar rating word",
    "PEOPLE_SCORE_TYPE": "Quantitative / Not returned",
    "PEOPLE_ICON": "AUTO — inline SVG (icon_embedder)",
    "PEOPLE_SCORE_SCALE": "AUTO — inline SVG (icon_embedder)",
    "PEOPLE_SUMMARY_HTML": "Model-built <p> HTML from PILLAR_SUMMARIES.people",
    "PARENT_RATING": "Pillar rating word",
    "PARENT_SCORE_TYPE": "Quantitative / Not returned",
    "PARENT_ICON": "AUTO — inline SVG (icon_embedder)",
    "PARENT_SCORE_SCALE": "AUTO — inline SVG (icon_embedder)",
    "PARENT_SUMMARY_HTML": "Model-built <p> HTML from PILLAR_SUMMARIES.parent",
    "PRICE_RATING": "Numeric price score from MMRGS",
    "PRICE_SCORE": "AUTO — inline SVG (icon_embedder)",
    "PRICE_SCORE_SCALE": "AUTO — inline SVG (icon_embedder)",
    "PRICE_SUMMARY_HTML": "Model-built <p> HTML from PILLAR_SUMMARIES.price",
    "MEDALIST_DISCLOSURE_TYPE_DISPLAY": "AUTO — div label built from MEDALIST_DISCLOSURE_TYPE (icon_embedder)",
    "MEDALIST_DISCLOSURE_FOOTNOTE": "AUTO — footnote div built from MEDALIST_DISCLOSURE_TYPE (icon_embedder)",
    # -------------------------------------------------------------------------
    # Analyst summary
    # -------------------------------------------------------------------------
    "ANALYST_SUMMARY": "Model-built <p>...</p> HTML from ANALYST_SUMMARY_PARAGRAPHS",
    # -------------------------------------------------------------------------
    # Managers
    # -------------------------------------------------------------------------
    "MANAGERS_HTML": "Model-built manager card HTML (see Workflow B)",
    # -------------------------------------------------------------------------
    # Returns tables
    # -------------------------------------------------------------------------
    "TRAILING_RETURNS_UNIT": 'Column header, e.g. "% Total Return"',
    "TRAILING_RETURNS_ROWS": "Model-built <tr> rows (see Workflow B)",
    "ANNUAL_RETURNS_HEADERS": "Model-built <th> elements for each calendar year",
    "ANNUAL_RETURNS_ROWS": "Model-built <tr> rows (see Workflow B)",
    # -------------------------------------------------------------------------
    # Benchmark
    # -------------------------------------------------------------------------
    "BENCHMARK_CURRENCY": "Benchmark base currency (LS05M on benchmark ID); renderer computes gate, legend, and note",
    "BENCHMARK_CURRENCY_MISMATCH": "AUTO — computed by renderer from BASE_CURRENCY vs BENCHMARK_CURRENCY",
    "BENCHMARK_LEGEND_ENTRY": "AUTO — generated by renderer; empty string when currencies differ",
    "BENCHMARK_CURRENCY_NOTE": "AUTO — generated by renderer; currency-mismatch note or empty string",
    # -------------------------------------------------------------------------
    # Portfolio
    # -------------------------------------------------------------------------
    "ALLOC_EQUITY_FUND": '"X.XX%"',
    "ALLOC_BOND_FUND": '"X.XX%"',
    "ALLOC_ALT_FUND": '"X.XX%"',
    "ALLOC_CASH_FUND": '"X.XX%"',
    "ALLOC_OTHER_FUND": '"X.XX%"',
    "STYLE_BOX_EQUITY": 'Text label, e.g. "Large Blend"',
    "STYLE_BOX_FIXED_INCOME": 'Text label, e.g. "Medium / Moderate"',
    "STYLE_BOX_ROWS": "Model-built <tr> rows for style box table",
    "STYLE_BOX_SECTION_CLASS": '"" (visible) or "is-empty" (hidden)',
    "FI_DURATION": 'Formatted string, e.g. "6.23 yrs"',
    "FI_CREDIT_QUALITY": 'Text, e.g. "A"',
    "FIXED_INCOME_SECTION_CLASS": '"" or "is-empty"',
    "FIXED_INCOME_STATS_SECTION_CLASS": '"" or "is-empty"',
    "FIXED_INCOME_REGION_SECTION_CLASS": '"" or "is-empty"',
    "FIXED_INCOME_REGION_HEADER": "Model-built <tr><th> header",
    "FIXED_INCOME_REGION_ROWS_HTML": "Model-built <tr> rows",
    "FIXED_INCOME_SECTION_NOTE": 'Note HTML or ""',
    "EQUITY_PROFILE_SECTION_CLASS": '"" or "is-empty"',
    "REGIONAL_EXPOSURE_SECTION_CLASS": '"" or "is-empty"',
    "REGIONAL_EXPOSURE_HEADER": "Model-built <tr><th> header",
    "REGIONAL_EXPOSURE_ROWS_HTML": "Model-built <tr> rows",
    "REGIONAL_EXPOSURE_SECTION_NOTE": 'Note HTML or ""',
    "MARKET_CAP_SECTION_CLASS": '"" or "is-empty"',
    "MARKET_CAP_HEADER": "Model-built <tr><th> header",
    "MARKET_CAP_ROWS_HTML": "Model-built <tr> rows",
    "MARKET_CAP_SECTION_NOTE": 'Note HTML or ""',
    "EQUITY_PORTFOLIO_STATS_SECTION_CLASS": '"" or "is-empty"',
    "EQUITY_PORTFOLIO_STATS_HEADER": "Model-built <tr><th> header",
    "EQUITY_PORTFOLIO_STATS_ROWS_HTML": "Model-built <tr> rows",
    "EQUITY_PORTFOLIO_STATS_SECTION_NOTE": 'Note HTML or ""',
    "TOP_HOLDINGS_ROWS": "Model-built <tr> rows (see Workflow B)",
    "PCT_TOP_10": '"X.XX%"',
    # -------------------------------------------------------------------------
    # Risk
    # -------------------------------------------------------------------------
    "RISK_SECTION_CLASS": '"" (visible) or "is-empty" (hidden)',
    "RISK_CAPTURE_ROWS": "Model-built <tr> rows (see Workflow B)",
    "RISK_STATS_ROWS": "Model-built <tr> rows (see Workflow B)",
    # -------------------------------------------------------------------------
    # Charts (AUTO — built by render.py from JSON inputs below)
    # -------------------------------------------------------------------------
    "RETURNS_CHART_SVG": "AUTO — inline SVG line chart",
    "DONUT_CHART_SVG": "AUTO — inline SVG donut chart",
    # -------------------------------------------------------------------------
    # Chart data inputs
    # -------------------------------------------------------------------------
    "MONTHLY_RETURNS_JSON": "JSON array of {date, fund_return, benchmark_return}",
    "ASSET_ALLOCATION_JSON": "JSON array of {label, value}",
    # -------------------------------------------------------------------------
    # Metadata
    # -------------------------------------------------------------------------
    "REPORT_DATE": "YYYY-MM-DD",
    "DATA_AS_OF_DATE": "YYYY-MM-DD",
}

SHA-256: 67325421ae83fe51cb406d5f21d80eaad65acabf84e1247f36f54ac12f1ca27c