earnings-preview-beta
用 Kensho 和 kfinance 資料,產出單一公司的財報前瞻 HTML 報告
中文翻譯
---
name: earnings-preview-single
description: 為單一公司產生精簡的 4 到 5 頁股票研究財報前瞻。分析最近一次財報逐字稿、競爭對手格局、估值和近期新聞,產出專業的 HTML 報告。
---
# 單一公司財報前瞻
為單一公司產生精簡、專業的股票研究財報前瞻。輸出是一個獨立的 HTML 檔案,目標是列印成 4 到 5 頁。報告的圖表和數據密集,敘述緊湊、直奔重點。
**資料來源(零例外):** 唯一允許的資料來源是 **Kensho Grounding MCP**(`search`)和 **S&P Global MCP**(`kfinance`)。絕對不准使用任何其他工具、資料來源或任何形式的網路存取。具體來說:
- 不准使用 `WebSearch`、`WebFetch`、`web_search`、`brave_search`、`google_search`,或任何通用的網路/網際網路搜尋工具,即使 Kensho 很慢、沒有回傳結果、或暫時無法使用也一樣。
- 不准使用任何瀏覽器、URL 擷取或網頁爬取工具。
- 如果 Kensho Grounding 對某個查詢沒有回傳結果,就換個說法重新查詢,或在報告中註明「資料無法取得」。**絕對不准退而求其次改用網路搜尋。**
- 報告中的每一項資訊,都必須能追溯到一次 `kfinance` MCP 函式呼叫或一次 Kensho `search` 呼叫。如果無法溯源到這兩者之一,就不准出現在報告中。
**關鍵規則:** 在撰寫報告的任何部分「之前」,你「必須」完成所有研究和資料蒐集(階段 1 到 5)。
**中間檔案規則:** MCP 工具呼叫的所有原始資料,都「必須」在**每次工具呼叫回傳後立刻**寫入 `/tmp/earnings-preview/` 底下的檔案,之後才能進行下一次呼叫。這是為了保護資料不被 context window 壓縮弄丟。不要只把資料放在記憶體裡。在階段 1 開始時,執行 `mkdir -p /tmp/earnings-preview` 建立目錄。**在產生 HTML 報告(階段 7)之前,你「必須」用 `cat` 指令把所有中間檔案讀回 context。報告中每一個數字、引述和來源 URL 的唯一真實來源是這些檔案,不是你對先前對話的記憶。如果你跳過讀檔,報告一定會有錯誤。**
**會計季度規則:** 絕對不要從日曆上的報告日期去推斷會計季度。很多公司的會計年度不是標準的(例如 Walmart 的會計年度在 1 月 31 日結束,所以 2026 年 2 月的報告涵蓋的是 Q4 FY2026,不是 Q4 2025 或 Q1 2026)。一律使用 `get_next_earnings_from_identifiers` 或 `get_earnings_from_identifiers` 回傳的財報電話會議名稱中所載明的會計季度和會計年度(例如「Walmart Q4 FY2026 Earnings Call」代表這個季度是 Q4 FY2026)。在報告標題、標頭、表格和所有引用處,逐字使用它。如果電話會議名稱含糊,就用 `get_financial_line_item_from_identifiers` 的期間標籤交叉比對。
**篇幅規則:** 報告必須精簡。目標是列印成 4 到 5 頁。不要寫冗長的多段落敘述。用緊湊、有力的條列。每一句話都要有存在的價值。能用更少的字說完,就用更少的字。
**逐字引述規則:** 在 `<blockquote>` 標籤中引述管理層的話時,文字「必須」**一字不差地**從逐字稿複製,包括贅詞和不完整的句子片段。不要改寫、重新排列、把逐字稿不同位置的句子拼在一起,或「整理」引述。如果在逐字稿裡找不到確切的措辭,就不要把它當作直接引述呈現。改用你自己的敘述口吻轉述,不用 blockquote 格式(例如「Management noted that data center demand remains significant」)。每一個 blockquote 都必須是可以對照逐字稿驗證的逐字、複製貼上的摘錄。
**計算完整性規則:** 對任何多步驟的計算(從年度 guidance 推算的隱含季度數字、LTM P/E、年增率、分部年增變化),把每一步明確寫出來,並在用於下一步之前驗證中間結果。如果你寫 A + B + C = X,在後續公式使用 X 之前,先驗證 X 在算術上是正確的。如果附錄顯示的總和不等於它所陳述的各組成項,那份報告就是錯的。有疑慮時,從原始資料重新計算,不要重複使用先前算出的中間值。
**比率命名規則:** 所有估值比率都必須明確標示為 **LTM**(過去十二個月)或 **NTM**(未來十二個月)。絕對不要用「trailing」或「forward」,一律用 LTM 或 NTM。LTM 比率使用最近 4 個已申報季度的總和。NTM 比率使用 `get_consensus_estimates_from_identifiers` 中**未來 4 個季度共識平均 EPS 預估的總和**,不是單一的年度數字。LTM 和 NTM 的 P/E 都必須計算,並顯示在競爭對手比較表中。
**超連結規則(嚴格執行):** 報告中的每一項主張,不論是數字或非數字,「都必須」用指向附錄對應條目的 `<a href="#ref-N" class="data-ref">` 超連結包起來。**這不是選用的。報告中的每一個數字都必須是可點擊的連結。** 這包括:營收數字、EPS、利潤率、成長率、市值、P/E 比率、股票報酬、目標價、分部營收,以及任何其他財務指標。也包括來自逐字稿或 Kensho 搜尋的質化主張。如果你把它當作事實陳述,它就必須連結到來源。為每一個獨特的主張指派依序的參照 ID(`ref-1`、`ref-2` 等)。超連結樣式要低調:深藍色、沒有底線、hover 時顯示點狀底線。**報告內文中,不准有任何一個數字沒有被 `<a>` 標籤包起來。** 範例:寫成 `<a href="#ref-1" class="data-ref">$152.3B</a>`,絕對不要把 `$152.3B` 當純文字寫出來。
---
## 階段 1:公司概況與設定
1. 從 `$ARGUMENTS` 解析出單一公司股票代號(去除空白)。
2. 執行 `mkdir -p /tmp/earnings-preview` 建立工作目錄。
3. 呼叫 `get_latest()` 建立目前報告期間的背景。
4. 呼叫 `get_info_from_identifiers`,記錄市值、產業。
5. 呼叫 `get_company_summary_from_identifiers`,記錄業務描述。
6. 呼叫 `get_next_earnings_from_identifiers`,記錄即將到來的財報日期和會計季度名稱。
**立刻寫入** `/tmp/earnings-preview/company-info.txt`:
```
TICKER: [ticker]
COMPANY: [full name]
INDUSTRY: [industry]
MARKET_CAP: [value] (as of [date])
NEXT_EARNINGS_DATE: [date]
NEXT_EARNINGS_QUARTER: [Q# FY#### exactly as returned by API]
BUSINESS_DESCRIPTION: [2-3 sentence summary]
```
---
## 階段 2:財報逐字稿分析(必要:撰寫之前就要完成)
1. 呼叫 `get_latest_earnings_from_identifiers`,取得最近一次已完成財報電話會議的 `key_dev_id`。
2. 針對該逐字稿呼叫 `get_transcript_from_key_dev_id`。
3. **立刻寫入** `/tmp/earnings-preview/transcript-extracts.txt`,包含下列區段。趁逐字稿還在 context 裡就寫這個檔案,不要等:
```
TRANSCRIPT_SOURCE: [Call Name, e.g., "Q3 2025 Earnings Call"]
KEY_DEV_ID: [key_dev_id]
CALL_DATE: [date]
FISCAL_QUARTER: [Q# FY####]
=== VERBATIM QUOTES (copy-paste exactly — do NOT paraphrase) ===
QUOTE_1: "[exact text from transcript]"
SPEAKER_1: [Name], [Title]
CONTEXT_1: [1 sentence on where this appeared — prepared remarks or Q&A]
QUOTE_2: "[exact text from transcript]"
SPEAKER_2: [Name], [Title]
CONTEXT_2: [context]
QUOTE_3: "[exact text from transcript]"
SPEAKER_3: [Name], [Title]
CONTEXT_3: [context]
QUOTE_4: "[exact text from transcript]"
SPEAKER_4: [Name], [Title]
CONTEXT_4: [context]
=== GUIDANCE (quantitative only) ===
- [metric]: [range or point estimate as stated by management]
- [metric]: [range or point estimate]
=== KEY DRIVERS ===
- [driver 1 with supporting data point]
- [driver 2 with supporting data point]
- [driver 3 with supporting data point]
=== HEADWINDS & RISKS ===
- [risk 1 with quantification if available]
- [risk 2]
=== ANALYST Q&A THEMES ===
- [theme 1: what analysts pushed on]
- [theme 2]
- [theme 3]
=== SYNTHESIS: THEMES TO WATCH NEXT QUARTER ===
- [theme 1]
- [theme 2]
- [theme 3]
```
---
## 階段 3:競爭對手分析
1. 以 `competitor_source="all"` 呼叫 `get_competitors_from_identifiers`。
2. 選出**最相關的前 5 到 7 家上市競爭對手**。
3. 對該公司以及所有選出的競爭對手,蒐集:
- `get_prices_from_identifiers`,`periodicity="day"`,最近 12 個月
- `get_financial_line_item_from_identifiers`,取 `diluted_eps`,`period_type="quarterly"`,`num_periods=8`
- `get_capitalization_from_identifiers`,`capitalization="market_cap"`(最新)
- `get_consensus_estimates_from_identifiers`,`period_type="quarterly"`,`num_periods_forward=4`:這會回傳未來 4 個季度的共識平均 EPS 預估,加總後用來計算 NTM EPS
**每次工具呼叫回傳後,立刻把原始資料附加到對應的中間檔案:**
**寫入** `/tmp/earnings-preview/prices.csv`:每一列是一組 (ticker, date, close)。要包含 `source` 欄,填入確切的 MCP 函式呼叫。先寫主體公司的價格,再隨著取得依序寫入每個競爭對手的:
```
ticker,date,close,source
D,2025-02-19,55.67,get_prices_from_identifiers(identifier='D',periodicity='day')
D,2025-02-20,55.82,get_prices_from_identifiers(identifier='D',periodicity='day')
...
DUK,2025-02-19,111.79,get_prices_from_identifiers(identifier='DUK',periodicity='day')
...
```
注意:單次呼叫的所有列,`source` 的值都相同,每一列都要寫,確保隨時都能取得。
**寫入** `/tmp/earnings-preview/peer-eps.csv`:每一列是一組 (ticker, period, eps)。每次 `diluted_eps` 呼叫後立刻寫入:
```
ticker,period,diluted_eps,source
D,Q4 2024,1.09,get_financial_line_item_from_identifiers(identifier='D',line_item='diluted_eps',period_type='quarterly')
D,Q1 2025,-0.11,get_financial_line_item_from_identifiers(identifier='D',line_item='diluted_eps',period_type='quarterly')
...
DUK,Q4 2024,1.52,get_financial_line_item_from_identifiers(identifier='DUK',line_item='diluted_eps',period_type='quarterly')
...
```
**寫入** `/tmp/earnings-preview/peer-market-caps.csv`:每個 ticker 一列。每次 `market_cap` 呼叫後立刻寫入:
```
ticker,market_cap,retrieval_date,source
D,55900000000,2026-02-19,get_capitalization_from_identifiers(identifier='D',capitalization='market_cap')
DUK,98300000000,2026-02-19,get_capitalization_from_identifiers(identifier='DUK',capitalization='market_cap')
...
```
**寫入** `/tmp/earnings-preview/consensus-eps.csv`:每一列是一組 (ticker, period, consensus mean EPS)。每次 `get_consensus_estimates_from_identifiers` 呼叫後立刻寫入:
```
ticker,period,consensus_mean_eps,num_estimates,source
D,Q4 2025,0.88,12,get_consensus_estimates_from_identifiers(identifier='D',period_type='quarterly',num_periods_forward=4)
D,Q1 2026,0.72,10,get_consensus_estimates_from_identifiers(identifier='D',period_type='quarterly',num_periods_forward=4)
D,Q2 2026,0.91,9,get_consensus_estimates_from_identifiers(identifier='D',period_type='quarterly',num_periods_forward=4)
D,Q3 2026,1.05,8,get_consensus_estimates_from_identifiers(identifier='D',period_type='quarterly',num_periods_forward=4)
DUK,Q4 2025,1.48,14,get_consensus_estimates_from_identifiers(identifier='DUK',period_type='quarterly',num_periods_forward=4)
...
```
4. **現在不要計算 P/E 或報酬。** 原始資料現在已經在磁碟上了。計算在階段 6(驗證)進行,從這些檔案讀取。
**日期一致性規則(股票報酬):** 計算比較用的股票報酬(YTD %、1 年 %、30 天 %、90 天 %)時,所有 ticker「必須」使用**完全相同的起始和結束日期**。把所有價格資料寫入 `prices.csv` 後,找出所有 ticker 的資料中都有出現的第一個交易日,以它作為共同的基準日。不要對不同的 ticker 使用不同的基準日(例如主體公司從 2 月 19 日起算,同業從 2 月 28 日起算)。如果某個 ticker 的資料開始得比較晚,所有計算都使用第一個重疊的日期。每一項報酬計算,都要在附錄中載明共同的基準日。
**P/E 時效規則(LTM P/E):** 計算每間公司的 LTM P/E 時,使用該公司在 `peer-eps.csv` 中**最近 4 個已申報的季度**,不是對所有公司套用固定的日曆區間。如果某個同業已經申報了 Q4 2025,而主體公司只申報到 Q3 2025,該同業的 LTM EPS 應該包含 Q4 2025。檢查每間公司最新的已申報期間,並對每間公司使用最近的 4 個期間。在附錄中註明每個 P/E 計算使用了哪 4 個季度。
**市值日期標註:** 報告市值時,使用 `peer-market-caps.csv` 中的 `retrieval_date`。如果與報告日期不同,要在附錄中註明。
---
## 階段 4:新聞、預估與產業情報(透過 Kensho Grounding)
對下列**每一個**類別執行這些 `search` 查詢。不准跳過任何一個。
**關鍵:擷取來源 URL:** 每一個 Kensho `search` 結果都包含底層文章、報告或資料頁面的**來源 URL**。你「必須」把 URL 與每一項發現一起記錄。
**每次搜尋呼叫之後,立刻用下面的格式,把結果附加到** `/tmp/earnings-preview/kensho-findings.txt`。不要等所有搜尋都做完,每做完一個就寫:
```
=== SEARCH: "[query used]" ===
DATE_RUN: [today's date]
CATEGORY: [estimates|analyst_ratings|risks|news|sector]
FINDING_1: [key finding or excerpt]
URL_1: [source URL from search result]
SOURCE_1: [publication name, date if available]
FINDING_2: [key finding or excerpt]
URL_2: [source URL]
SOURCE_2: [publication name, date]
[...continue for all relevant results from this search...]
```
**財報預估與分析師情緒:**
1. `search` "[TICKER] earnings estimates consensus EPS revenue upcoming quarter"
- 記錄:共識 EPS、共識營收、過去 90 天預估修正的方向。
- **立刻附加到 kensho-findings.txt。**
2. `search` "[TICKER] analyst ratings price target upgrades downgrades"
- 記錄:近期升評/降評、目標價區間、多空論點摘要。
- **立刻附加到 kensho-findings.txt。**
3. `search` "[TICKER] risks bear case concerns investors"
- 記錄:主要爭論點、看空論點、這次財報的搖擺因素。
- **立刻附加到 kensho-findings.txt。**
**近期新聞(必要,不准跳過):**
4. `search` "[TICKER] [company name] recent news developments"
- 記錄:過去 60 天的重大新聞:併購、產品發布、高階主管異動、監管行動、合作夥伴關係、法律進展、關稅,或任何可能影響即將到來的財報或前瞻 guidance 的事件。
- 每一項都要註明日期、標題、對財報的潛在影響。
- **立刻附加到 kensho-findings.txt。**
**產業背景:**
5. `search` "[company industry/sector] sector outlook trends"
- 記錄:產業層級的順風/逆風、總經資料、競爭動態。
- **立刻附加到 kensho-findings.txt。**
---
## 階段 5:財務資料蒐集
**季度財務(最近 8 個季度):**
以 `period_type="quarterly"`、`num_periods=8` 呼叫 `get_financial_line_item_from_identifiers`,取得:
`revenue`、`gross_profit`、`operating_income`、`ebitda`、`net_income`、`diluted_eps`
**每次 line item 呼叫回傳後,立刻附加到** `/tmp/earnings-preview/financials.csv`。原始數值要寫成跟回傳的完全一樣,現在不要四捨五入或轉換。包含 `source` 欄,填入確切的 MCP 函式呼叫與參數:
```
ticker,period,line_item,value,source
D,Q4 2024,revenue,3941000000,get_financial_line_item_from_identifiers(identifier='D',line_item='revenue',period_type='quarterly')
D,Q1 2025,revenue,3400000000,get_financial_line_item_from_identifiers(identifier='D',line_item='revenue',period_type='quarterly')
D,Q2 2025,revenue,4076000000,get_financial_line_item_from_identifiers(identifier='D',line_item='revenue',period_type='quarterly')
D,Q3 2025,revenue,3810000000,get_financial_line_item_from_identifiers(identifier='D',line_item='revenue',period_type='quarterly')
D,Q4 2024,diluted_eps,1.09,get_financial_line_item_from_identifiers(identifier='D',line_item='diluted_eps',period_type='quarterly')
D,Q1 2025,diluted_eps,-0.11,get_financial_line_item_from_identifiers(identifier='D',line_item='diluted_eps',period_type='quarterly')
...
```
**現在不要計算利潤率或成長率。** 只寫原始資料。計算在階段 6 進行。
**分部資料:**
- `get_segments_from_identifiers`,`segment_type="business"`、`period_type="quarterly"`、`num_periods=8`
- 你需要 8 個季度(不是 4 個),這樣才有去年同期的季度可做年增比較。要計算 Q3 2025 的年增,你需要 Q3 2024,也就是往回數的第 5 個季度。**如果 API 回應中沒有前一年同期的分部資料,不准估計或捏造。在報告中寫明「y/y not available」。**
**立刻寫入** `/tmp/earnings-preview/segments.csv`:
```
ticker,period,segment_name,revenue,source
D,Q3 2024,Dominion Energy Virginia,2762000000,get_segments_from_identifiers(identifier='D',segment_type='business',period_type='quarterly')
D,Q3 2024,Dominion Energy South Carolina,848000000,get_segments_from_identifiers(identifier='D',segment_type='business',period_type='quarterly')
D,Q3 2024,Contracted Energy,260000000,get_segments_from_identifiers(identifier='D',segment_type='business',period_type='quarterly')
D,Q3 2025,Dominion Energy Virginia,3311000000,get_segments_from_identifiers(identifier='D',segment_type='business',period_type='quarterly')
D,Q3 2025,Dominion Energy South Carolina,945000000,get_segments_from_identifiers(identifier='D',segment_type='business',period_type='quarterly')
D,Q3 2025,Contracted Energy,297000000,get_segments_from_identifiers(identifier='D',segment_type='business',period_type='quarterly')
...
```
**財報歷史(用於股價圖表標註):**
- `get_earnings_from_identifiers`:收集 12 個月價格區間內的過往財報日期。
- **立刻寫入** `/tmp/earnings-preview/earnings-dates.csv`:
```
ticker,earnings_date,call_name,source
D,2025-05-02,Q1 2025 Earnings Call,get_earnings_from_identifiers(identifier='D')
D,2025-08-01,Q2 2025 Earnings Call,get_earnings_from_identifiers(identifier='D')
D,2025-10-31,Q3 2025 Earnings Call,get_earnings_from_identifiers(identifier='D')
...
```
---
## 階段 6:驗證與計算(必要:不准跳過)
產生報告之前,先讀回所有中間檔案,並從乾淨的資料進行計算。這個階段從檔案而不是被壓縮過的對話 context 來作業,以確保資料完整性。
1. **用 bash `cat` 指令讀取所有中間檔案:**
- `cat /tmp/earnings-preview/company-info.txt`
- `cat /tmp/earnings-preview/transcript-extracts.txt`
- `cat /tmp/earnings-preview/financials.csv`
- `cat /tmp/earnings-preview/segments.csv`
- `cat /tmp/earnings-preview/prices.csv`
- `cat /tmp/earnings-preview/peer-eps.csv`
- `cat /tmp/earnings-preview/peer-market-caps.csv`
- `cat /tmp/earnings-preview/consensus-eps.csv`
- `cat /tmp/earnings-preview/kensho-findings.txt`
- `cat /tmp/earnings-preview/earnings-dates.csv`
2. **從現在在 context 裡的原始資料計算衍生指標:**
- 毛利率 % = gross_profit / revenue(每季)
- 營業利益率 % = operating_income / revenue(每季)
- 營收年增 % = (當季營收 - 去年同期營收) / 去年同期營收
- EPS 年增 % = 同樣的邏輯;如果基期為負,用 "n.m."
- 分部年增 % = 依名稱比對去年同期的分部;如果缺少,註明 "y/y not available"
- 每間公司的 LTM P/E = 最新價格 / 最近 4 個季度 EPS 的總和(用 `peer-eps.csv` 檢查每個 ticker 有哪 4 個季度可用)
- 每間公司的 NTM P/E = 最新價格 / NTM EPS,其中 **NTM EPS = `consensus-eps.csv` 中未來 4 個季度共識平均 EPS 預估的總和**。把每個 ticker 4 個季度的 consensus_mean_eps 值加起來。如果某個同業可用的未來季度少於 4 個,把 NTM P/E 標為 "n/a"。在附錄中註明加總了哪 4 個季度。
- 股票報酬(YTD、1 年、30 天、90 天)= 在 `prices.csv` 中找出**所有 ticker 共同的第一個日期**,再從那個日期起算報酬
3. **交叉檢查**:
- 驗證每一個分部年增,在 `segments.csv` 中都有實際的前一年度列。如果沒有,標為 "y/y not available."
- 驗證所有股票報酬的基準日在各 ticker 之間都完全相同。
- 透過重新加總各組成項,驗證任何多步驟的計算(例如 LTM EPS 的總和與 4 個季度的值吻合)。
- 驗證 `transcript-extracts.txt` 中所有逐字引述都是精確的複製貼上(不是改寫)。
4. **寫入** `/tmp/earnings-preview/calculations.csv`,放入所有衍生值:
```
ticker,metric,value,formula,components
D,gross_margin_Q3_2025,32.5%,gross_profit/revenue,"gross_profit=1238100000,revenue=3810000000"
D,revenue_yoy_Q3_2025,+9.3%,(Q3_2025-Q3_2024)/Q3_2024,"Q3_2025=3810000000,Q3_2024=3486000000"
D,ltm_pe,24.2x,price/ltm_eps,"price=65.46,ltm_eps=2.70,quarters=Q4_2024+Q1_2025+Q2_2025+Q3_2025"
D,ntm_pe,18.5x,price/ntm_eps,"price=65.46,ntm_eps=3.56,quarters=Q4_2025(0.88)+Q1_2026(0.72)+Q2_2026(0.91)+Q3_2026(1.05),source=get_consensus_estimates_from_identifiers"
D,yoy_return,+17.6%,(end-start)/start,"end=65.46,start=55.67,base_date=2025-02-19"
DUK,yoy_return,+13.0%,(end-start)/start,"end=126.32,start=111.79,base_date=2025-02-19"
...
```
這個檔案是報告中所有數字的唯一真實來源。
---
## 階段 7:產生 HTML 報告
**停:在撰寫任何 HTML 之前,你「必須」先讀取所有中間檔案。這是會擋住後續動作的前置條件。**
這不是選用的。你「必須」把下面每一個 `cat` 指令,各自當作**獨立的 bash 工具呼叫**來執行(不要合併成一個)。這樣才能確保每個檔案的內容都被個別載入,並在對話中看得到。不要把它們合併成單一指令。不要跳過任何檔案。
**一次一個**執行這些指令,每個都是自己的 bash 呼叫:
1. `cat /tmp/earnings-preview/company-info.txt`
2. `cat /tmp/earnings-preview/transcript-extracts.txt`
3. `cat /tmp/earnings-preview/financials.csv`
4. `cat /tmp/earnings-preview/segments.csv`
5. `cat /tmp/earnings-preview/prices.csv`
6. `cat /tmp/earnings-preview/peer-eps.csv`
7. `cat /tmp/earnings-preview/peer-market-caps.csv`
8. `cat /tmp/earnings-preview/consensus-eps.csv`
9. `cat /tmp/earnings-preview/kensho-findings.txt`
10. `cat /tmp/earnings-preview/earnings-dates.csv`
11. `cat /tmp/earnings-preview/calculations.csv`
**讀完所有檔案之後,你「必須」向使用者印出一則摘要訊息**,列出每個檔案和它的狀態。完全使用這個格式:
```
--- DATA FILE VERIFICATION ---
1. company-info.txt ✓ loaded ([N] lines)
2. transcript-extracts.txt ✓ loaded ([N] lines)
3. financials.csv ✓ loaded ([N] rows)
4. segments.csv ✓ loaded ([N] rows)
5. prices.csv ✓ loaded ([N] rows)
6. peer-eps.csv ✓ loaded ([N] rows)
7. peer-market-caps.csv ✓ loaded ([N] rows)
8. consensus-eps.csv ✓ loaded ([N] rows)
9. kensho-findings.txt ✓ loaded ([N] lines)
10. earnings-dates.csv ✓ loaded ([N] rows)
11. calculations.csv ✓ loaded ([N] rows)
All intermediate data files loaded successfully.
Generating report using file data as the single source of truth.
---
```
如果任何檔案遺失或是空的,就停下來,告訴使用者是哪個檔案失敗。不要在資料缺漏的情況下繼續產生報告。
**HTML 報告中的每一個數字、引述、來源 URL 和 MCP 函式呼叫參照,都必須來自這些檔案,不是來自你對先前對話輪次的記憶。** 檔案是唯一的真實來源。先前的對話 context 可能已被壓縮或摘要,如果依賴它,就一定會有錯誤。如果某個資料點不在檔案裡,就不該出現在報告中。
完整的 HTML 範本、CSS 和 Chart.js 設定請見 [report-template.md](report-template.md)。
**必要:使用範本的輔助函式來畫圖表:**
report-template.md 提供了預先建好、已除錯的 Chart.js 輔助函式。你「必須」使用這些確切的函式來建立圖表。不要自己寫行內的 Chart.js 程式碼。這些輔助函式是:
- `createRevEpsChart(canvasId, labels, revenueData, epsData, revLabel)`:用於圖 1
- `createMarginChart(canvasId, labels, grossMargins, opMargins)`:用於圖 2
- `createRevGrowthChart(canvasId, labels, growthData)`:用於圖 3
- `createAnnotatedPriceChart(canvasId, labels, prices, earningsDates, ticker)`:用於圖 5
- `createCompPerfChart(canvasId, labels, datasets)`:用於圖 6
- `createPEChart(canvasId, companies)`:用於圖 7
每一個圖表呼叫「必須」放在自己的 `<script>` 標籤裡,並用 try-catch 區塊包起來。這樣可確保一個圖表的 bug 不會阻止其他圖表渲染。範例:
```html
<script>
try {
createRevEpsChart('chart-rev-eps', [...], [...], [...], 'Revenue ($B)');
} catch(e) { console.error('Figure 1 error:', e); }
</script>
<script>
try {
createMarginChart('chart-margins', [...], [...], [...]);
} catch(e) { console.error('Figure 2 error:', e); }
</script>
```
### 報告結構(總共 4 到 5 頁)
報告有兩個部分:**敘述**(第 1 到 2 頁)和**圖表**(第 3 到 5 頁)。要讓兩者緊密整合。
---
**AI 免責聲明(必要:必須出現在 3 個地方):**
你「必須」把下列免責聲明文字放進報告 HTML。這不是選用的,沒有它報告就不算完整:
> **"Analysis is AI-generated — please confirm all outputs"**
必須剛好出現在這 3 個位置:
1. **標頭橫幅**:緊接在封面標頭之前,用置中的黃色橫幅:`<div class="ai-disclaimer">Analysis is AI-generated — please confirm all outputs</div>`
2. **頁尾**:在 page-footer div 裡面,用醒目的黃色橫幅:`<div class="footer-disclaimer">Analysis is AI-generated — please confirm all outputs</div>`
3. **附錄**:作為附錄區段的第一行,放在表格之前:`<div class="ai-disclaimer">Analysis is AI-generated — please confirm all outputs</div>`
---
**第 1 頁:封面與論點**
- **AI 免責聲明橫幅**(黃色、置中,見上面的 AI 免責聲明規則)
- **標頭**:公司名稱(TICKER)| 產業 | 報告日期
- **標題**:主題式、針對該季度的具體標題(例如 "Walmart Inc. (WMT) Q4 FY2026 Earnings Preview: Holiday Harvest — Can Furner's First Print Confirm the $1T Thesis?")
- **執行論點**(最多 2 到 3 個短段落,搭配條列):
- 用 1 到 2 句話講我們預期這次財報會是什麼
- 4 到 6 個條列,涵蓋:我們的 EPS 預估 vs 共識、guidance 預期、要關注的關鍵指標、什麼會讓股價動起來、主要爭論點
- 要直接、有觀點,要表態,不要什麼都模稜兩可
- **關鍵管理層引述**,來自最近一次財報電話會議,在相關處穿插在敘述中。不要放在獨立的標題下。把它們自然地整合,作為你論點的佐證。格式為縮排的 blockquote。
---
**第 2 頁:預估、主題與新聞**
- **共識預估表**(單一表格,標為圖表):
- 欄位:Metric | Consensus | Our Estimate | y/y Change
- 列:Revenue、EPS、Gross Margin、Operating Income,以及 2 到 3 個重要的公司專屬 KPI(例如同店銷售、電商成長、會員營收,也就是市場對**這間**公司關心的東西)
- **顏色標示嚴格依機械規則:** 如果 y/y 變動值為負,用 `class="neg"`(紅色)。如果為正,用 `class="pos"`(綠色)。如果是零或 N/A,用 `class="neutral"`。數字的正負號決定 class,不要依解讀而覆寫。-1.1% 一律是紅色,即使下滑幅度很小。
- 這是唯一的 guidance/預估區段。不要在其他地方重複預估資料。
- **超越標題 EPS 的關鍵指標**(條列清單,3 到 5 項):
- 除了 EPS 數字之外,會決定這季是好是壞的具體指標
- 每一項要寫:這個指標是什麼、共識/管理層預期什麼、為什麼重要
- 要具體:"Walmart Connect ad revenue growth (consensus ~30% y/y, 3Q was 33%)"
- **要關注的主題**(3 到 5 點):
- 針對即將發布的報告的前瞻項目
- 管理層需要兌現什麼、什麼可能帶來驚喜、看空者關注什麼
- 每個主題:最多 1 到 2 句
- **近期新聞與發展**(3 到 5 點):
- 過去 60 天的重大新聞,每則一行
- 日期 + 標題 + 簡短的影響評估
- 只放可能影響即將到來的財報或 guidance 的項目
---
**第 3 到 5 頁:圖表(所有圖表和表格)**
所有圖表依序編號。每張圖都有標題和來源列。
- **圖 1:季度營收與稀釋 EPS**:長條/折線組合圖,8 個季度
- **圖 2:利潤率趨勢(毛利率與營業利益率 %)**:雙折線圖,8 個季度
- **圖 3:營收年增 %**:長條圖,依條件用綠/紅上色。**只納入當期與去年同期資料都存在的季度**(通常是取回的 8 個季度中最近的 4 個)。不要納入無法計算年增的季度,圖表應該有 4 根長條,不是 8 根。
- **圖 4:事業分部營收**:表格:Segment | Latest Q Rev ($M) | % of Total | y/y Change
- **圖 5:附財報日期的 1 年股價**:價格線,在財報日期畫垂直標註線,標示季度和財報後 1 天的漲跌
- **圖 6:相對競爭對手的股價表現(指數化到 100)**:多折線圖,主體公司用粗實線,競爭對手用較細的虛線
- **圖 7:LTM P/E vs. 競爭對手**:水平長條圖,主體公司用深藍色凸顯
- **圖 8:競爭對手比較表**:Ticker | Company | Mkt Cap | LTM P/E | NTM P/E | YTD % | 1-Yr %
---
**附錄:資料來源與計算(必要:不准跳過或縮寫)**
附錄「必須」以 AI 免責聲明橫幅開頭:`<div class="ai-disclaimer">Analysis is AI-generated — please confirm all outputs</div>`
報告最後的頁面「必須」包含一張附錄表格,記錄報告中引用的**每一項主張**,不論是數字或非數字。**報告內文中出現的每一個數字,在這個附錄都必須有對應的一列,而且報告內文中的每一個這類數字,都必須是可點擊的 `<a href="#ref-N">` 超連結,捲動到它的附錄列。** 如果報告中有數字沒有連到附錄的超連結,這份報告就不完整。
- **表格欄位**:Ref # | Fact | Value | Source & Derivation
- **Ref #**:與報告內文超連結錨點相符的依序 ID(`ref-1`、`ref-2` 等)。每一列都有 `id="ref-N"` 屬性,讓超連結能捲動到它。
- **Fact**:人類可讀的標籤(例如 "Q3 FY2026 Revenue"、"LTM P/E — WMT"、"Management flagged tariff headwinds"、"Barclays upgraded to Overweight")
- **Value**:報告中顯示的確切數字(例如 "$152.3B"、"24.5%"、"28.1x")。非數字的事實,留空或寫 "N/A"。
- **Source & Derivation**:這是關鍵的一欄。**每一列都必須有具體、詳細的來源,不能只是個標籤。** 嚴格遵循這些規則:
**來自 S&P Capital IQ 的原始財務資料(營收、EPS、毛利、營業利益、淨利、EBITDA、價格、市值等):**
- 註明所使用的 MCP 函式及其關鍵參數。格式:`S&P Capital IQ — [function_name](identifier='[TICKER]', line_item='[item]', period_type='[type]', period='[Q# FY####]')`
- 範例:
- `S&P Capital IQ — get_financial_line_item_from_identifiers(identifier='WMT', line_item='revenue', period_type='quarterly', period='Q3 FY2026')`
- `S&P Capital IQ — get_financial_line_item_from_identifiers(identifier='WMT', line_item='diluted_eps', period_type='quarterly', period='Q3 FY2026')`
- `S&P Capital IQ — get_prices_from_identifiers(identifier='WMT', periodicity='day')`
- `S&P Capital IQ — get_capitalization_from_identifiers(identifier='WMT', capitalization='market_cap')`
- **不要只寫 "S&P Capital IQ" 而沒有細節。** 讀者必須確切知道是哪一次工具呼叫的哪一個資料點產生了這個數字。
**計算出來的值(利潤率、成長率、P/E、報酬、年增變動):**
- 顯示完整公式,並讓**各組成項帶有超連結**:每一個組成項都必須是 `<a href="#ref-N">` 連結,連回該原始資料點的附錄列。這點很關鍵:讀者必須能從計算出的值點進它的每一個輸入。
- 範例:`Gross Margin = <a href='#ref-5'>Gross Profit $37.2B</a> / <a href='#ref-1'>Revenue $152.3B</a> = 24.4%. Source: S&P Capital IQ (calculated)`
- 範例:`LTM P/E = <a href='#ref-20'>Price $172.35</a> / (<a href='#ref-8'>Q1 EPS $1.47</a> + <a href='#ref-9'>Q2 EPS $1.84</a> + <a href='#ref-10'>Q3 EPS $1.53</a> + <a href='#ref-11'>Q4 EPS $1.80</a>) = $172.35 / $6.64 = 25.9x`
- 範例:`Revenue y/y growth = (<a href='#ref-12'>Q3 FY26 Rev $165.8B</a> - <a href='#ref-3'>Q3 FY25 Rev $160.8B</a>) / <a href='#ref-3'>Q3 FY25 Rev $160.8B</a> = +3.1%`
- **每一個公式組成項都必須是可點擊的超連結。** 不要把公式寫成純文字數字。
**來自逐字稿的主張(引述、管理層評論、guidance):**
- 寫出逐字稿中的**逐字摘錄句子**。
- 用完整名稱和取得它所用的 `key_dev_id` 來參照逐字稿。
- 格式:`"[verbatim quote]" — [Speaker], [Title]. Source: [Q# FY#### Earnings Call Transcript] (key_dev_id: [ID])`
- 範例:`"We expect comp sales growth of 3-4% in Q4" — CEO John Furner. Source: Q3 FY2026 Earnings Call Transcript (key_dev_id: 12345678)`
**來自 Kensho Grounding 搜尋結果的主張(新聞、分析師評等、共識預估):**
- 寫出搜尋結果中的關鍵發現或摘錄。
- **必要:包含** Kensho `search` 工具回傳的來源 URL,作為可點擊的 `<a href="[URL]" target="_blank">` 超連結。這是最重要的部分,讀者必須能點進原始來源。
- 格式:`"[finding/excerpt]" — <a href="[URL]" target="_blank">[Source Title or Publication]</a>. Query: search("[query used]")`
- 範例:`"Barclays upgraded WMT to Overweight with $210 price target on Jan 15, 2026." — <a href="https://www.investing.com/news/barclays-upgrades-wmt" target="_blank">Investing.com, Jan 15 2026</a>. Query: search("WMT analyst ratings price target upgrades downgrades")`
- 如果某個結果沒有回傳 URL,寫 "Source URL not available",並仍然附上搜尋查詢。
**完整性檢查:** 定稿報告之前,掃描報告內文的每一個數字。如果有任何數字沒有被 `<a href="#ref-N" class="data-ref">` 包起來,就修正。如果有任何附錄列的 Source & Derivation 只是像 "S&P Capital IQ" 這種沒有函式呼叫細節的空標籤,就修正。如果有任何計算值的公式缺少帶超連結的組成項,就修正。如果有任何來自 Kensho 的主張缺少來源 URL,就修正。
把附錄列依區段(Financials、Valuation、Estimates & Consensus、Transcript Claims、News & Analyst Commentary、Stock Performance)分組,並加上小標題。使用較小的字級(10 到 11px)。
---
## 階段 8:輸出
1. 把完整的 HTML 檔案寫到目前工作目錄的 `earnings-preview-[TICKER]-YYYY-MM-DD.html`。
2. 在瀏覽器中開啟:`open earnings-preview-[TICKER]-YYYY-MM-DD.html`
3. 告訴使用者檔案已建立,並摘要重點發現。
---
## 寫作準則
- **不准用表情符號**:報告中任何地方都不准使用表情符號。這是專業的研究文件。
- **精簡**:目標是列印 4 到 5 頁。每一句話都要有份量。盡可能用條列,不要用段落。如果某個區段感覺太長,就砍掉。
- **數字要具體**:寫「$52.4B revenue, up 5.2% y/y」,不要寫「strong revenue growth」。
- **要有觀點**:這是財報前瞻,不是摘要。說明你預期什麼、什麼重要、為什麼。要有主見,但要用資料支撐。
- **管理層引述不加標題**:把最近一次電話會議中的 3 到 4 則關鍵管理層引述,以 blockquote 方式直接穿插在敘述中。不要建立「Key Management Quotes」區段標題,讓它們自然地作為佐證流動。
- **專業語氣**:賣方股票研究風格:分析性、直接、以資料為本。
- **圖表必須使用真實資料**:每個圖表都用實際的 MCP 資料填入。絕對不准捏造。
- **競爭對手脈絡**:估值要相對同業來框定。不知道同業是 20 倍還是 35 倍,25 倍 P/E 就沒有意義。
- **主張都要有超連結**:每一項事實主張,不論數字或質化,都必須是連到其附錄條目的 `<a class="data-ref">` 標籤。數字:`<a href="#ref-1" class="data-ref">$152.3B</a>`。質化:`<a href="#ref-25" class="data-ref">management flagged tariff headwinds as the primary margin risk</a>`。不該有任何事實在附錄中沒有可追溯的來源。英文原文
---
name: earnings-preview-single
description: Generate a concise 4-5 page equity research earnings preview for a single company. Analyzes the most recent earnings transcript, competitor landscape, valuation, and recent news to produce a professional HTML report.
---
# Single-Company Earnings Preview
Generate a concise, professional equity research earnings preview for a single company. The output is a self-contained HTML file targeting 4-5 printed pages. The report is dense with figures and data, with tight narrative that gets straight to the point.
**Data Sources (ZERO EXCEPTIONS):** The ONLY permitted data sources are **Kensho Grounding MCP** (`search`) and **S&P Global MCP** (`kfinance`). Absolutely NO other tools, data sources, or web access of any kind. Specifically:
- Do NOT use `WebSearch`, `WebFetch`, `web_search`, `brave_search`, `google_search`, or ANY generic web/internet search tool — even if Kensho is slow, returns no results, or is temporarily unavailable.
- Do NOT use any browser, URL fetch, or web scraping tool.
- If Kensho Grounding returns no results for a query, try rephrasing the query or note "data not available" in the report. **NEVER fall back to web search as an alternative.**
- Every piece of information in the report must be traceable to either a `kfinance` MCP function call or a Kensho `search` call. If it cannot be sourced to one of these two, it must not appear in the report.
**Critical Rule:** You MUST complete ALL research and data collection (Phases 1-5) BEFORE writing any part of the report.
**Intermediate File Rule:** All raw data from MCP tool calls MUST be written to files in `/tmp/earnings-preview/` **immediately after each tool call returns** — before moving to the next call. This protects data from context window compression. Do NOT hold data only in memory. At the start of Phase 1, run `mkdir -p /tmp/earnings-preview` to create the directory. **Before generating the HTML report (Phase 7), you MUST read ALL intermediate files back into context using `cat` commands. The files — not your memory of earlier conversation — are the single source of truth for every number, quote, and source URL in the report. If you skip reading the files, the report WILL contain errors.**
**Fiscal Quarter Rule:** NEVER infer the fiscal quarter from the calendar report date. Many companies have non-standard fiscal years (e.g., Walmart's FY ends Jan 31, so a Feb 2026 report covers Q4 FY2026, not Q4 2025 or Q1 2026). Always use the fiscal quarter and fiscal year exactly as stated in the earnings call name returned by `get_next_earnings_from_identifiers` or `get_earnings_from_identifiers` (e.g., "Walmart Q4 FY2026 Earnings Call" means the quarter is Q4 FY2026). Use that verbatim in the report title, headers, tables, and all references. If the call name is ambiguous, cross-reference with `get_financial_line_item_from_identifiers` period labels.
**Length Rule:** The report must be concise. Target 4-5 pages when printed. Do NOT write long multi-paragraph narratives. Use tight, punchy bullet points. Every sentence must earn its place. If you can say it in fewer words, do so.
**Verbatim Quote Rule:** When quoting management in `<blockquote>` tags, the text MUST be copied **exactly** from the transcript — word for word, including filler words and sentence fragments. Do NOT paraphrase, rearrange, combine sentences from different parts of the transcript, or "clean up" quotes. If you cannot find the exact phrase in the transcript, do NOT present it as a direct quote. Instead, paraphrase in your own narrative voice without blockquote formatting (e.g., "Management noted that data center demand remains significant"). Every blockquote must be a verbatim, copy-paste excerpt that can be verified against the transcript.
**Calculation Integrity Rule:** For any multi-step calculation (implied quarterly figures from annual guidance, LTM P/E, y/y growth rates, segment y/y changes), write out each step explicitly and verify intermediate results before using them in the next step. If you state A + B + C = X, verify X is arithmetically correct before using X in a subsequent formula. If the appendix shows a sum that does not equal its stated components, the report is wrong. When in doubt, recompute from raw data rather than reusing a previously calculated intermediate.
**Ratio Nomenclature Rule:** All valuation ratios must be explicitly labeled as **LTM** (Last Twelve Months) or **NTM** (Next Twelve Months). Never use "trailing" or "forward" — always use LTM or NTM. LTM ratios use the sum of the most recent 4 reported quarters. NTM ratios use the **sum of the next 4 quarterly consensus mean EPS estimates** from `get_consensus_estimates_from_identifiers` — NOT a single annual figure. Both LTM and NTM P/E must be computed and displayed in the competitor comparison table.
**Hyperlink Rule (STRICTLY ENFORCED):** Every claim in the report — numeric AND non-numeric — MUST be wrapped in an `<a href="#ref-N" class="data-ref">` hyperlink pointing to the corresponding entry in the Appendix. **This is not optional. Every single number in the report must be a clickable link.** This includes: revenue figures, EPS, margins, growth rates, market caps, P/E ratios, stock returns, price targets, segment revenue, and any other financial metric. It also includes qualitative claims from transcripts or Kensho searches. If you state it as fact, it must link to a source. Assign each unique claim a sequential reference ID (`ref-1`, `ref-2`, etc.). The hyperlink style is subtle — navy color, no underline, dotted underline on hover. **Do NOT write any number in the report body without wrapping it in an `<a>` tag.** Example: write `<a href="#ref-1" class="data-ref">$152.3B</a>`, NEVER write `$152.3B` as plain text.
---
## Phase 1: Company Profile & Setup
1. Parse the single company ticker from `$ARGUMENTS` (strip whitespace).
2. Run `mkdir -p /tmp/earnings-preview` to create the working directory.
3. Call `get_latest()` to establish current reporting period context.
4. Call `get_info_from_identifiers` — record market cap, industry.
5. Call `get_company_summary_from_identifiers` — record business description.
6. Call `get_next_earnings_from_identifiers` — record upcoming earnings date and fiscal quarter name.
**Immediately write** `/tmp/earnings-preview/company-info.txt`:
```
TICKER: [ticker]
COMPANY: [full name]
INDUSTRY: [industry]
MARKET_CAP: [value] (as of [date])
NEXT_EARNINGS_DATE: [date]
NEXT_EARNINGS_QUARTER: [Q# FY#### exactly as returned by API]
BUSINESS_DESCRIPTION: [2-3 sentence summary]
```
---
## Phase 2: Earnings Transcript Analysis (MANDATORY — COMPLETE BEFORE WRITING)
1. Call `get_latest_earnings_from_identifiers` to get the most recent completed earnings call `key_dev_id`.
2. Call `get_transcript_from_key_dev_id` for that transcript.
3. **Immediately write** `/tmp/earnings-preview/transcript-extracts.txt` with the following sections. Write this file WHILE you still have the transcript in context — do not wait:
```
TRANSCRIPT_SOURCE: [Call Name, e.g., "Q3 2025 Earnings Call"]
KEY_DEV_ID: [key_dev_id]
CALL_DATE: [date]
FISCAL_QUARTER: [Q# FY####]
=== VERBATIM QUOTES (copy-paste exactly — do NOT paraphrase) ===
QUOTE_1: "[exact text from transcript]"
SPEAKER_1: [Name], [Title]
CONTEXT_1: [1 sentence on where this appeared — prepared remarks or Q&A]
QUOTE_2: "[exact text from transcript]"
SPEAKER_2: [Name], [Title]
CONTEXT_2: [context]
QUOTE_3: "[exact text from transcript]"
SPEAKER_3: [Name], [Title]
CONTEXT_3: [context]
QUOTE_4: "[exact text from transcript]"
SPEAKER_4: [Name], [Title]
CONTEXT_4: [context]
=== GUIDANCE (quantitative only) ===
- [metric]: [range or point estimate as stated by management]
- [metric]: [range or point estimate]
=== KEY DRIVERS ===
- [driver 1 with supporting data point]
- [driver 2 with supporting data point]
- [driver 3 with supporting data point]
=== HEADWINDS & RISKS ===
- [risk 1 with quantification if available]
- [risk 2]
=== ANALYST Q&A THEMES ===
- [theme 1: what analysts pushed on]
- [theme 2]
- [theme 3]
=== SYNTHESIS: THEMES TO WATCH NEXT QUARTER ===
- [theme 1]
- [theme 2]
- [theme 3]
```
---
## Phase 3: Competitor Analysis
1. Call `get_competitors_from_identifiers` with `competitor_source="all"`.
2. Select **top 5-7 most relevant public competitors**.
3. For the company AND all selected competitors, gather:
- `get_prices_from_identifiers` with `periodicity="day"`, last 12 months
- `get_financial_line_item_from_identifiers` for `diluted_eps`, `period_type="quarterly"`, `num_periods=8`
- `get_capitalization_from_identifiers` with `capitalization="market_cap"` (latest)
- `get_consensus_estimates_from_identifiers` with `period_type="quarterly"`, `num_periods_forward=4` — this returns consensus mean EPS estimates for the next 4 quarters, which are summed to compute NTM EPS
**After each tool call returns, immediately append the raw data to the appropriate intermediate file:**
**Write** `/tmp/earnings-preview/prices.csv` — one row per (ticker, date, close). Include the `source` column with the exact MCP function call. Write the subject company's prices first, then each competitor's as you fetch them:
```
ticker,date,close,source
D,2025-02-19,55.67,get_prices_from_identifiers(identifier='D',periodicity='day')
D,2025-02-20,55.82,get_prices_from_identifiers(identifier='D',periodicity='day')
...
DUK,2025-02-19,111.79,get_prices_from_identifiers(identifier='DUK',periodicity='day')
...
```
Note: the `source` value is the same for all rows from a single call — write it on every row so it's always available.
**Write** `/tmp/earnings-preview/peer-eps.csv` — one row per (ticker, period, eps). Write immediately after each `diluted_eps` call:
```
ticker,period,diluted_eps,source
D,Q4 2024,1.09,get_financial_line_item_from_identifiers(identifier='D',line_item='diluted_eps',period_type='quarterly')
D,Q1 2025,-0.11,get_financial_line_item_from_identifiers(identifier='D',line_item='diluted_eps',period_type='quarterly')
...
DUK,Q4 2024,1.52,get_financial_line_item_from_identifiers(identifier='DUK',line_item='diluted_eps',period_type='quarterly')
...
```
**Write** `/tmp/earnings-preview/peer-market-caps.csv` — one row per ticker. Write immediately after each `market_cap` call:
```
ticker,market_cap,retrieval_date,source
D,55900000000,2026-02-19,get_capitalization_from_identifiers(identifier='D',capitalization='market_cap')
DUK,98300000000,2026-02-19,get_capitalization_from_identifiers(identifier='DUK',capitalization='market_cap')
...
```
**Write** `/tmp/earnings-preview/consensus-eps.csv` — one row per (ticker, period, consensus mean EPS). Write immediately after each `get_consensus_estimates_from_identifiers` call:
```
ticker,period,consensus_mean_eps,num_estimates,source
D,Q4 2025,0.88,12,get_consensus_estimates_from_identifiers(identifier='D',period_type='quarterly',num_periods_forward=4)
D,Q1 2026,0.72,10,get_consensus_estimates_from_identifiers(identifier='D',period_type='quarterly',num_periods_forward=4)
D,Q2 2026,0.91,9,get_consensus_estimates_from_identifiers(identifier='D',period_type='quarterly',num_periods_forward=4)
D,Q3 2026,1.05,8,get_consensus_estimates_from_identifiers(identifier='D',period_type='quarterly',num_periods_forward=4)
DUK,Q4 2025,1.48,14,get_consensus_estimates_from_identifiers(identifier='DUK',period_type='quarterly',num_periods_forward=4)
...
```
4. **Do NOT calculate P/E or returns yet.** The raw data is now on disk. Calculations happen in Phase 6 (Verification), reading from these files.
**Date Consistency Rule (stock returns):** When computing comparative stock returns (YTD %, 1-yr %, 30d %, 90d %), ALL tickers MUST use the **exact same start and end dates**. After writing all price data to `prices.csv`, identify the first trading date that appears in ALL tickers' data and use that as the common base date. Do NOT use different base dates for different tickers (e.g., the subject from Feb 19 and peers from Feb 28). If a ticker's data starts later than others, use the first overlapping date for ALL calculations. State the common base date in the appendix for every return calculation.
**P/E Currency Rule (LTM P/E):** When computing LTM P/E for each company, use that company's **most recent 4 reported quarters** from `peer-eps.csv` — not a fixed calendar window applied to all. If a peer has already reported Q4 2025 while the subject company has only reported through Q3 2025, the peer's LTM EPS should include Q4 2025. Check the latest reported period for each company and use the 4 most recent periods per company. Note in the appendix which 4 quarters were used for each P/E calculation.
**Market Cap Date-Stamp:** When reporting market cap, use the `retrieval_date` from `peer-market-caps.csv`. If it differs from the report date, note this in the appendix.
---
## Phase 4: News, Estimates & Sector Intelligence (via Kensho Grounding)
Run these `search` queries for **each** category below. Do NOT skip any.
**CRITICAL — Capture Source URLs:** Every Kensho `search` result includes a **source URL** for the underlying article, report, or data page. You MUST record the URL alongside each finding.
**After EACH search call, immediately append the results to** `/tmp/earnings-preview/kensho-findings.txt` using the format below. Do NOT wait until all searches are done — write after each one:
```
=== SEARCH: "[query used]" ===
DATE_RUN: [today's date]
CATEGORY: [estimates|analyst_ratings|risks|news|sector]
FINDING_1: [key finding or excerpt]
URL_1: [source URL from search result]
SOURCE_1: [publication name, date if available]
FINDING_2: [key finding or excerpt]
URL_2: [source URL]
SOURCE_2: [publication name, date]
[...continue for all relevant results from this search...]
```
**Earnings estimates & analyst sentiment:**
1. `search` for "[TICKER] earnings estimates consensus EPS revenue upcoming quarter"
- Record: consensus EPS, consensus revenue, estimate revision direction over last 90 days.
- **Append to kensho-findings.txt immediately.**
2. `search` for "[TICKER] analyst ratings price target upgrades downgrades"
- Record: recent upgrades/downgrades, price target range, bull/bear thesis summaries.
- **Append to kensho-findings.txt immediately.**
3. `search` for "[TICKER] risks bear case concerns investors"
- Record: key debates, bear arguments, swing factors for the upcoming print.
- **Append to kensho-findings.txt immediately.**
**Recent news (MANDATORY — do not skip):**
4. `search` for "[TICKER] [company name] recent news developments"
- Record: material news from the last 60 days — M&A, product launches, executive changes, regulatory actions, partnerships, legal developments, tariffs, or any event that could affect the upcoming earnings print or forward guidance.
- For each item, note the date, headline, potential earnings impact.
- **Append to kensho-findings.txt immediately.**
**Sector context:**
5. `search` for "[company industry/sector] sector outlook trends"
- Record: sector-level tailwinds/headwinds, macro data, competitive dynamics.
- **Append to kensho-findings.txt immediately.**
---
## Phase 5: Financial Data Collection
**Quarterly financials (last 8 quarters):**
`get_financial_line_item_from_identifiers` with `period_type="quarterly"`, `num_periods=8` for:
`revenue`, `gross_profit`, `operating_income`, `ebitda`, `net_income`, `diluted_eps`
**After each line item call returns, immediately append to** `/tmp/earnings-preview/financials.csv`. Write the raw values exactly as returned — do NOT round or convert yet. Include the `source` column with the exact MCP function call and parameters:
```
ticker,period,line_item,value,source
D,Q4 2024,revenue,3941000000,get_financial_line_item_from_identifiers(identifier='D',line_item='revenue',period_type='quarterly')
D,Q1 2025,revenue,3400000000,get_financial_line_item_from_identifiers(identifier='D',line_item='revenue',period_type='quarterly')
D,Q2 2025,revenue,4076000000,get_financial_line_item_from_identifiers(identifier='D',line_item='revenue',period_type='quarterly')
D,Q3 2025,revenue,3810000000,get_financial_line_item_from_identifiers(identifier='D',line_item='revenue',period_type='quarterly')
D,Q4 2024,diluted_eps,1.09,get_financial_line_item_from_identifiers(identifier='D',line_item='diluted_eps',period_type='quarterly')
D,Q1 2025,diluted_eps,-0.11,get_financial_line_item_from_identifiers(identifier='D',line_item='diluted_eps',period_type='quarterly')
...
```
**Do NOT calculate margins or growth rates yet.** Write raw data only. Calculations happen in Phase 6.
**Segment data:**
- `get_segments_from_identifiers` with `segment_type="business"`, `period_type="quarterly"`, `num_periods=8`
- You need 8 quarters (not 4) so you have the year-ago quarter for y/y comparisons. To calculate y/y for Q3 2025, you need Q3 2024 — which is the 5th quarter back. **If the prior-year quarter's segment data is not available in the API response, do NOT estimate or fabricate it. State "y/y not available" in the report.**
**Immediately write** `/tmp/earnings-preview/segments.csv`:
```
ticker,period,segment_name,revenue,source
D,Q3 2024,Dominion Energy Virginia,2762000000,get_segments_from_identifiers(identifier='D',segment_type='business',period_type='quarterly')
D,Q3 2024,Dominion Energy South Carolina,848000000,get_segments_from_identifiers(identifier='D',segment_type='business',period_type='quarterly')
D,Q3 2024,Contracted Energy,260000000,get_segments_from_identifiers(identifier='D',segment_type='business',period_type='quarterly')
D,Q3 2025,Dominion Energy Virginia,3311000000,get_segments_from_identifiers(identifier='D',segment_type='business',period_type='quarterly')
D,Q3 2025,Dominion Energy South Carolina,945000000,get_segments_from_identifiers(identifier='D',segment_type='business',period_type='quarterly')
D,Q3 2025,Contracted Energy,297000000,get_segments_from_identifiers(identifier='D',segment_type='business',period_type='quarterly')
...
```
**Earnings history (for stock chart annotations):**
- `get_earnings_from_identifiers` — collect past earnings dates within the 12-month price window.
- **Immediately write** `/tmp/earnings-preview/earnings-dates.csv`:
```
ticker,earnings_date,call_name,source
D,2025-05-02,Q1 2025 Earnings Call,get_earnings_from_identifiers(identifier='D')
D,2025-08-01,Q2 2025 Earnings Call,get_earnings_from_identifiers(identifier='D')
D,2025-10-31,Q3 2025 Earnings Call,get_earnings_from_identifiers(identifier='D')
...
```
---
## Phase 6: Verification & Calculations (MANDATORY — DO NOT SKIP)
Before generating the report, read back ALL intermediate files and perform calculations from the clean data. This phase ensures data integrity by working from files rather than compressed conversation context.
1. **Read all intermediate files** using bash `cat` commands:
- `cat /tmp/earnings-preview/company-info.txt`
- `cat /tmp/earnings-preview/transcript-extracts.txt`
- `cat /tmp/earnings-preview/financials.csv`
- `cat /tmp/earnings-preview/segments.csv`
- `cat /tmp/earnings-preview/prices.csv`
- `cat /tmp/earnings-preview/peer-eps.csv`
- `cat /tmp/earnings-preview/peer-market-caps.csv`
- `cat /tmp/earnings-preview/consensus-eps.csv`
- `cat /tmp/earnings-preview/kensho-findings.txt`
- `cat /tmp/earnings-preview/earnings-dates.csv`
2. **Calculate derived metrics** from the raw data now in context:
- Gross margin % = gross_profit / revenue (per quarter)
- Operating margin % = operating_income / revenue (per quarter)
- Revenue y/y growth % = (current Q revenue - year-ago Q revenue) / year-ago Q revenue
- EPS y/y growth % = same logic; use "n.m." if base is negative
- Segment y/y growth % = match segment by name to year-ago Q; if missing, note "y/y not available"
- LTM P/E per company = latest price / sum of most recent 4 quarterly EPS (check which 4 quarters are available per ticker using `peer-eps.csv`)
- NTM P/E per company = latest price / NTM EPS, where **NTM EPS = sum of the next 4 quarterly consensus mean EPS estimates** from `consensus-eps.csv`. Add all 4 quarters' consensus_mean_eps values for each ticker. If fewer than 4 forward quarters are available for a peer, mark NTM P/E as "n/a". Note in the appendix which 4 quarters were summed.
- Stock returns (YTD, 1-yr, 30d, 90d) = find the **common first date across all tickers** in `prices.csv`, then compute returns from that date
3. **Cross-check**:
- Verify every segment y/y has the actual prior-year row in `segments.csv`. If not, mark "y/y not available."
- Verify all stock return base dates are identical across tickers.
- Verify any multi-step calculation by re-summing components (e.g., LTM EPS sum matches the 4 quarterly values).
- Verify all verbatim quotes in `transcript-extracts.txt` are exact copy-pastes (not paraphrases).
4. **Write** `/tmp/earnings-preview/calculations.csv` with all derived values:
```
ticker,metric,value,formula,components
D,gross_margin_Q3_2025,32.5%,gross_profit/revenue,"gross_profit=1238100000,revenue=3810000000"
D,revenue_yoy_Q3_2025,+9.3%,(Q3_2025-Q3_2024)/Q3_2024,"Q3_2025=3810000000,Q3_2024=3486000000"
D,ltm_pe,24.2x,price/ltm_eps,"price=65.46,ltm_eps=2.70,quarters=Q4_2024+Q1_2025+Q2_2025+Q3_2025"
D,ntm_pe,18.5x,price/ntm_eps,"price=65.46,ntm_eps=3.56,quarters=Q4_2025(0.88)+Q1_2026(0.72)+Q2_2026(0.91)+Q3_2026(1.05),source=get_consensus_estimates_from_identifiers"
D,yoy_return,+17.6%,(end-start)/start,"end=65.46,start=55.67,base_date=2025-02-19"
DUK,yoy_return,+13.0%,(end-start)/start,"end=126.32,start=111.79,base_date=2025-02-19"
...
```
This file becomes the single source of truth for all numbers in the report.
---
## Phase 7: Generate the HTML Report
**STOP — BEFORE WRITING ANY HTML, YOU MUST READ ALL INTERMEDIATE FILES. THIS IS A BLOCKING PREREQUISITE.**
This is not optional. You MUST run each `cat` command below as a **separate bash tool call** (not combined into one). This ensures each file's contents are individually loaded and visible in the conversation. Do NOT combine them into a single command. Do NOT skip any file.
Run these commands **one at a time, each as its own bash call**:
1. `cat /tmp/earnings-preview/company-info.txt`
2. `cat /tmp/earnings-preview/transcript-extracts.txt`
3. `cat /tmp/earnings-preview/financials.csv`
4. `cat /tmp/earnings-preview/segments.csv`
5. `cat /tmp/earnings-preview/prices.csv`
6. `cat /tmp/earnings-preview/peer-eps.csv`
7. `cat /tmp/earnings-preview/peer-market-caps.csv`
8. `cat /tmp/earnings-preview/consensus-eps.csv`
9. `cat /tmp/earnings-preview/kensho-findings.txt`
10. `cat /tmp/earnings-preview/earnings-dates.csv`
11. `cat /tmp/earnings-preview/calculations.csv`
**After reading ALL files, you MUST print a summary message to the user** that lists every file and its status. Use exactly this format:
```
--- DATA FILE VERIFICATION ---
1. company-info.txt ✓ loaded ([N] lines)
2. transcript-extracts.txt ✓ loaded ([N] lines)
3. financials.csv ✓ loaded ([N] rows)
4. segments.csv ✓ loaded ([N] rows)
5. prices.csv ✓ loaded ([N] rows)
6. peer-eps.csv ✓ loaded ([N] rows)
7. peer-market-caps.csv ✓ loaded ([N] rows)
8. consensus-eps.csv ✓ loaded ([N] rows)
9. kensho-findings.txt ✓ loaded ([N] lines)
10. earnings-dates.csv ✓ loaded ([N] rows)
11. calculations.csv ✓ loaded ([N] rows)
All intermediate data files loaded successfully.
Generating report using file data as the single source of truth.
---
```
If any file is missing or empty, STOP and tell the user which file failed. Do NOT proceed to generate the report with missing data.
**Every number, quote, source URL, and MCP function call reference in the HTML report must come from these files — not from your memory of earlier conversation turns.** The files are the single source of truth. Earlier conversation context may have been compressed or summarized and WILL contain errors if relied upon. If a data point is not in the files, it should not appear in the report.
See [report-template.md](report-template.md) for the complete HTML template, CSS, and Chart.js configuration.
**MANDATORY — Use Template Helper Functions for Charts:**
The report-template.md provides pre-built, debugged Chart.js helper functions. You MUST use these exact functions to create charts. Do NOT write custom inline Chart.js code. The helpers are:
- `createRevEpsChart(canvasId, labels, revenueData, epsData, revLabel)` — for Figure 1
- `createMarginChart(canvasId, labels, grossMargins, opMargins)` — for Figure 2
- `createRevGrowthChart(canvasId, labels, growthData)` — for Figure 3
- `createAnnotatedPriceChart(canvasId, labels, prices, earningsDates, ticker)` — for Figure 5
- `createCompPerfChart(canvasId, labels, datasets)` — for Figure 6
- `createPEChart(canvasId, companies)` — for Figure 7
Each chart call MUST be in its own `<script>` tag wrapped in a try-catch block. This ensures a bug in one chart does not prevent other charts from rendering. Example:
```html
<script>
try {
createRevEpsChart('chart-rev-eps', [...], [...], [...], 'Revenue ($B)');
} catch(e) { console.error('Figure 1 error:', e); }
</script>
<script>
try {
createMarginChart('chart-margins', [...], [...], [...]);
} catch(e) { console.error('Figure 2 error:', e); }
</script>
```
### Report Structure (4-5 pages total)
The report has two halves: **narrative** (pages 1-2) and **figures** (pages 3-5). Keep these tightly integrated.
---
**AI DISCLAIMER (MANDATORY — must appear in 3 places):**
You MUST include the following disclaimer text in the report HTML. This is not optional — the report is incomplete without it:
> **"Analysis is AI-generated — please confirm all outputs"**
It must appear in exactly these 3 locations:
1. **Header banner** — immediately before the cover header, as a centered yellow banner: `<div class="ai-disclaimer">Analysis is AI-generated — please confirm all outputs</div>`
2. **Footer** — inside the page-footer div, as a prominent yellow banner: `<div class="footer-disclaimer">Analysis is AI-generated — please confirm all outputs</div>`
3. **Appendix** — as the first line of the appendix section, before the table: `<div class="ai-disclaimer">Analysis is AI-generated — please confirm all outputs</div>`
---
**PAGE 1: Cover & Thesis**
- **AI disclaimer banner** (yellow, centered — see AI DISCLAIMER rule above)
- **Header**: Company name (TICKER) | Industry | Report date
- **Title**: Thematic, specific to the quarter (e.g., "Walmart Inc. (WMT) Q4 FY2026 Earnings Preview: Holiday Harvest — Can Furner's First Print Confirm the $1T Thesis?")
- **Executive thesis** (2-3 short paragraphs max with bullet points):
- What we expect from this print in 1-2 sentences
- 4-6 bullet points covering: our EPS estimate vs consensus, guidance expectations, key metrics to watch, what would move the stock, key debates
- Keep it direct and opinionated — take a view, don't hedge everything
- **Key management quotes** from the most recent earnings call woven into the narrative where relevant. Do NOT put these under a separate heading. Integrate them naturally as supporting evidence for your thesis points. Format as indented blockquotes.
---
**PAGE 2: Estimates, Themes & News**
- **Consensus Estimates Table** (single table, labeled as a figure):
- Columns: Metric | Consensus | Our Estimate | y/y Change
- Rows: Revenue, EPS, Gross Margin, Operating Income, and 2-3 company-specific KPIs that matter (e.g., comp sales, eComm growth, membership revenue — whatever the Street cares about for THIS company)
- **Color-coding is strictly mechanical:** If the y/y change value is negative, use `class="neg"` (red). If positive, use `class="pos"` (green). If zero or N/A, use `class="neutral"`. The sign of the number determines the class — do NOT override based on interpretation. A -1.1% is ALWAYS red, even if the decline is small.
- This is the ONLY guidance/estimates section. Do not repeat estimate data elsewhere.
- **Key Metrics Beyond Headline EPS** (bulleted list, 3-5 items):
- The specific metrics that will determine if this is a good or bad quarter beyond the EPS number
- For each: what the metric is, what consensus/management expects, why it matters
- Be specific: "Walmart Connect ad revenue growth (consensus ~30% y/y, 3Q was 33%)"
- **Themes to Watch** (3-5 bullets):
- Forward-looking items for the upcoming report
- What management needs to deliver on, what could surprise, what the bears are focused on
- Each theme: 1-2 sentences max
- **Recent News & Developments** (3-5 bullets):
- Material news from the last 60 days, one line each
- Date + headline + brief impact assessment
- Only include items that could affect the upcoming print or guidance
---
**PAGES 3-5: Figures (all charts and tables)**
All figures are numbered sequentially. Every figure has a title and source line.
- **Figure 1: Quarterly Revenue & Diluted EPS** — Bar/line combo, 8 quarters
- **Figure 2: Margin Trends (Gross & Operating %)** — Dual line chart, 8 quarters
- **Figure 3: Revenue Growth y/y %** — Bar chart with green/red conditional coloring. **Only include quarters where both current and year-ago data exist** (typically the most recent 4 quarters from the 8 fetched). Do NOT include quarters where y/y cannot be computed — the chart should have 4 bars, not 8.
- **Figure 4: Business Segment Revenue** — Table: Segment | Latest Q Rev ($M) | % of Total | y/y Change
- **Figure 5: 1-Year Stock Price with Earnings Dates** — Price line with vertical annotation lines at earnings dates, labeled with quarter and 1-day post-earnings move
- **Figure 6: Stock Performance vs. Competitors (Indexed to 100)** — Multi-line chart, subject company as thick solid line, competitors as thinner dashed lines
- **Figure 7: LTM P/E vs. Competitors** — Horizontal bar chart, subject company highlighted in navy
- **Figure 8: Competitor Comparison Table** — Ticker | Company | Mkt Cap | LTM P/E | NTM P/E | YTD % | 1-Yr %
---
**APPENDIX: Data Sources & Calculations (MANDATORY — DO NOT SKIP OR ABBREVIATE)**
The appendix MUST begin with the AI disclaimer banner: `<div class="ai-disclaimer">Analysis is AI-generated — please confirm all outputs</div>`
The final page(s) of the report MUST include an Appendix table that documents **every claim** — numeric and non-numeric — cited in the report. **Every number that appears in the report body must have a corresponding row in this appendix, and every such number in the report body must be a clickable `<a href="#ref-N">` hyperlink that scrolls to its appendix row.** If a number appears in the report without a hyperlink to the appendix, the report is incomplete.
- **Table columns**: Ref # | Fact | Value | Source & Derivation
- **Ref #**: Sequential ID matching the hyperlink anchors in the report body (`ref-1`, `ref-2`, etc.). Each row has an `id="ref-N"` attribute so hyperlinks scroll to it.
- **Fact**: Human-readable label (e.g., "Q3 FY2026 Revenue", "LTM P/E — WMT", "Management flagged tariff headwinds", "Barclays upgraded to Overweight")
- **Value**: The exact figure as displayed in the report (e.g., "$152.3B", "24.5%", "28.1x"). For non-numeric facts, leave blank or write "N/A".
- **Source & Derivation**: This is the critical column. **Every row must have a specific, detailed source — not just a label.** Follow these rules strictly:
**For raw financial data from S&P Capital IQ (revenue, EPS, gross profit, operating income, net income, EBITDA, prices, market cap, etc.):**
- State the MCP function used and its key parameters. Format: `S&P Capital IQ — [function_name](identifier='[TICKER]', line_item='[item]', period_type='[type]', period='[Q# FY####]')`
- Examples:
- `S&P Capital IQ — get_financial_line_item_from_identifiers(identifier='WMT', line_item='revenue', period_type='quarterly', period='Q3 FY2026')`
- `S&P Capital IQ — get_financial_line_item_from_identifiers(identifier='WMT', line_item='diluted_eps', period_type='quarterly', period='Q3 FY2026')`
- `S&P Capital IQ — get_prices_from_identifiers(identifier='WMT', periodicity='day')`
- `S&P Capital IQ — get_capitalization_from_identifiers(identifier='WMT', capitalization='market_cap')`
- **Do NOT just write "S&P Capital IQ" with no detail.** The reader must know exactly which data point from which tool call produced this number.
**For calculated values (margins, growth rates, P/E, returns, y/y changes):**
- Show the full formula with **hyperlinked components** — each component must be an `<a href="#ref-N">` link back to the appendix row for that raw data point. This is critical: the reader must be able to click through from the calculated value to each of its inputs.
- Example: `Gross Margin = <a href='#ref-5'>Gross Profit $37.2B</a> / <a href='#ref-1'>Revenue $152.3B</a> = 24.4%. Source: S&P Capital IQ (calculated)`
- Example: `LTM P/E = <a href='#ref-20'>Price $172.35</a> / (<a href='#ref-8'>Q1 EPS $1.47</a> + <a href='#ref-9'>Q2 EPS $1.84</a> + <a href='#ref-10'>Q3 EPS $1.53</a> + <a href='#ref-11'>Q4 EPS $1.80</a>) = $172.35 / $6.64 = 25.9x`
- Example: `Revenue y/y growth = (<a href='#ref-12'>Q3 FY26 Rev $165.8B</a> - <a href='#ref-3'>Q3 FY25 Rev $160.8B</a>) / <a href='#ref-3'>Q3 FY25 Rev $160.8B</a> = +3.1%`
- **Every formula component must be a clickable hyperlink.** Do NOT write formulas with plain-text numbers.
**For transcript-sourced claims (quotes, management commentary, guidance):**
- Write the **verbatim excerpt sentence** from the transcript.
- Reference the transcript by its full name and the `key_dev_id` used to fetch it.
- Format: `"[verbatim quote]" — [Speaker], [Title]. Source: [Q# FY#### Earnings Call Transcript] (key_dev_id: [ID])`
- Example: `"We expect comp sales growth of 3-4% in Q4" — CEO John Furner. Source: Q3 FY2026 Earnings Call Transcript (key_dev_id: 12345678)`
**For Kensho Grounding search results (news, analyst ratings, consensus estimates):**
- Write the key finding or excerpt from the search result.
- **MANDATORY: Include the source URL** returned by the Kensho `search` tool as a clickable `<a href="[URL]" target="_blank">` hyperlink. This is the most important part — readers must be able to click through to the original source.
- Format: `"[finding/excerpt]" — <a href="[URL]" target="_blank">[Source Title or Publication]</a>. Query: search("[query used]")`
- Example: `"Barclays upgraded WMT to Overweight with $210 price target on Jan 15, 2026." — <a href="https://www.investing.com/news/barclays-upgrades-wmt" target="_blank">Investing.com, Jan 15 2026</a>. Query: search("WMT analyst ratings price target upgrades downgrades")`
- If no URL was returned for a particular result, write "Source URL not available" and still include the search query.
**Completeness check:** Before finalizing the report, scan every number in the report body. If any number is not wrapped in `<a href="#ref-N" class="data-ref">`, fix it. If any appendix row has a Source & Derivation that is just a bare label like "S&P Capital IQ" with no function call detail, fix it. If any calculated value's formula lacks hyperlinked components, fix it. If any Kensho-sourced claim lacks a source URL, fix it.
Group the appendix rows by section (Financials, Valuation, Estimates & Consensus, Transcript Claims, News & Analyst Commentary, Stock Performance) with subheadings. Use smaller font size (10-11px).
---
## Phase 8: Output
1. Write the complete HTML file to `earnings-preview-[TICKER]-YYYY-MM-DD.html` in the current working directory.
2. Open it in the browser: `open earnings-preview-[TICKER]-YYYY-MM-DD.html`
3. Tell the user the file has been created and summarize the key findings.
---
## Writing Guidelines
- **NO EMOJIS**: Do not use any emojis anywhere in the report. This is a professional research document.
- **CONCISE**: Target 4-5 printed pages. Every sentence must carry weight. Use bullets, not paragraphs, wherever possible. If a section feels long, cut it.
- **Be specific with numbers**: "$52.4B revenue, up 5.2% y/y" not "strong revenue growth."
- **Take a view**: This is an earnings preview, not a summary. State what you expect, what matters, and why. Be opinionated but back it with data.
- **Management quotes without headers**: Weave 3-4 key management quotes from the most recent call directly into the narrative as blockquotes. Do not create a "Key Management Quotes" section heading — let them flow naturally as supporting evidence.
- **Professional tone**: Sell-side equity research style — analytical, direct, data-driven.
- **Charts must use real data**: Every chart populated with actual MCP data. Never fabricate.
- **Competitor context**: Frame valuation relative to peers. A 25x P/E means nothing without knowing peers trade at 20x or 35x.
- **Hyperlinked claims**: Every factual claim — numeric or qualitative — must be an `<a class="data-ref">` tag linking to its appendix entry. Numbers: `<a href="#ref-1" class="data-ref">$152.3B</a>`. Qualitative: `<a href="#ref-25" class="data-ref">management flagged tariff headwinds as the primary margin risk</a>`. No fact should appear without a traceable source in the appendix.