← Files MorningstarARCHIVED FILE
skills/fund-summarizer/scripts/placeholder_defaults.py
9.2 KB · Oct 5, 2026 · 18:07 UTC
"""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