| name | earnings-watch |
| description | Build and run a daily cross-market earnings and filing monitor for A-share, US, Hong Kong, Japan, and Korea companies. Use this skill whenever the user wants keyword-driven company pools, earnings-calendar reminders, automated filing downloads, daily email digests, free-first financial data sources, paid API fallbacks, or a local ~/.earnings_watch managed workflow. |
Earnings Watch
Use this skill to operate a local daily monitor for earnings dates, disclosure events, filing downloads, and digest generation across A-share, US, Hong Kong, Japan, and Korea markets.
The workflow is designed for research automation. It does not give investment advice and should preserve source links, data provenance, and missing-data warnings.
The user manages themes and keywords, not the final company pool. The skill resolves each theme into a frozen pool of leading upstream/downstream companies and reuses that frozen pool during daily runs. Refresh the pool only when the user explicitly asks, so daily monitoring does not drift because a provider returned different matches.
Runtime Layout
All user configuration and outputs live under:
~/.earnings_watch/
config.json
company_pool.json
watchlists/
resolved_pools/
snapshots/
cache/
filings/
outputs/
logs/
event_overrides.json
Skill scripts live under:
SKILL_ROOT="${CODEX_HOME:-$HOME/.codex}/skills/earnings-watch"
Data Source Priority
Prefer free sources first and keep paid sources as fallback ports.
| Market | Free-first sources | Paid/API fallback ports |
|---|
| A-share | AkShare, CNINFO/巨潮, exchange disclosures | Tushare Pro, Wind, Choice |
| US | SEC EDGAR, yfinance, Alpha Vantage free tier | FMP, Finnhub, EODHD |
| Hong Kong | HKEXnews, yfinance | FMP, Finnhub, EODHD |
| Japan | yfinance MVP, EDINET official filings | paid fundamentals vendors |
| Korea | yfinance MVP, OpenDART official filings | paid fundamentals vendors |
Use provider fallback order from config.json. If a provider fails, continue to the next provider and record warnings in the run output.
For A-share, Hong Kong, Japan, and Korea, if official disclosure calendars are still empty, a SerpAPI-backed search estimate layer may emit low-confidence serpapi_estimate events so the daily digest still carries a likely date. Recent filing detection supports HKEXnews search for Hong Kong, EDINET API for Japan, and OpenDART API for Korea when the required keys and identifiers are configured.
Operating Workflow
-
Bootstrap the runtime directory:
python "$SKILL_ROOT/scripts/bootstrap.py"
-
Edit ~/.earnings_watch/config.json and ~/.earnings_watch/company_pool.json.
Put provider secrets in:
~/.earnings_watch/.env
Supported names:
TUSHARE_TOKEN=
FMP_API_KEY=
FINNHUB_API_KEY=
EODHD_API_KEY=
ALPHA_VANTAGE_API_KEY=
OPENDART_API_KEY=
EDINET_API_KEY=
SERPAPI_API_KEY=
-
Add or update a keyword theme:
python "$SKILL_ROOT/scripts/watchlist.py" add --name 光模块 --markets CN HK US --keywords 光模块 CPO 800G 硅光 --supply-chain-keywords 光通信 光芯片 数据中心
-
Resolve leading companies and freeze the pool:
python "$SKILL_ROOT/scripts/discover_leaders.py" --watchlist 光模块 --top-n 10 --refresh
Daily runs then read:
~/.earnings_watch/resolved_pools/光模块.json
-
Optional: configure Tushare token for better A-share fallback:
"api_keys": {
"tushare": "YOUR_TOKEN"
}
Or set:
export TUSHARE_TOKEN="YOUR_TOKEN"
-
Run the daily monitor:
python "$SKILL_ROOT/scripts/run_daily.py" --lookahead-days 14 --since-yesterday
Run only one watchlist:
python "$SKILL_ROOT/scripts/run_daily.py" --watchlist 光模块 --lookahead-days 14 --since-yesterday
Run multiple watchlists in one daily digest:
python "$SKILL_ROOT/scripts/run_daily.py" --watchlist 光模块 存储 AI服务器 --lookahead-days 14 --since-yesterday
Or use the event discovery wrapper:
python "$SKILL_ROOT/scripts/event_discovery.py" --watchlist 光模块 存储 --lookahead-days 180
-
Review outputs:
~/.earnings_watch/outputs/YYYY-MM-DD/digest.md
~/.earnings_watch/outputs/YYYY-MM-DD/events.json
~/.earnings_watch/outputs/YYYY-MM-DD/provider_warnings.json
~/.earnings_watch/outputs/YYYY-MM-DD/source_coverage_report.json
-
If email is enabled in config.json, send or draft:
python "$SKILL_ROOT/scripts/send_email.py" --date YYYY-MM-DD --dry-run
Digest Structure
Daily digests should use this structure:
# Earnings Watch Daily Digest - YYYY-MM-DD
## Today
companies reporting today
## Next 7 Days
upcoming company earnings, fiscal period, expected date, source
## Newly Released Since Yesterday
filings detected, downloaded paths, source links
## Key Takeaways
LLM-generated summary of newly released filings, if any
## Data Quality Notes
provider failures, missing dates, uncertain fiscal periods
Company Pool Rules
Do not ask the user to manually maintain the final company pool. company_pool.json is now a legacy/manual override file. The normal source of truth for daily monitoring is the generated frozen pool:
~/.earnings_watch/resolved_pools/[watchlist].json
Each resolved company should have:
{
"ticker": "NVDA",
"name": "NVIDIA",
"market": "US",
"aliases": ["英伟达", "Nvidia"],
"keywords": ["AI", "GPU", "存储"],
"sector": "Semiconductors",
"ir_url": "https://investor.nvidia.com/",
"enabled": true
}
Ticker conventions:
- A-share:
600519.SH, 300308.SZ
- Hong Kong:
0700.HK
- Japan:
6758.T
- Korea:
005930.KS
- US:
NVDA
Leader Discovery Rules
Only include companies when a source provides evidence that they are leading companies for the theme. Prefer market-cap, liquidity, concept membership, repeated keyword hits, and supply-chain terms. Save the rationale in leader_basis and source fields.
Implemented discovery adapters:
- A-share: AkShare concept constituents, Tushare concept fallback.
- US/HK: FMP profile/search, EODHD search, Finnhub symbol search when keys are configured.
- Web evidence: SerpAPI query collection via
scripts/search_leaders.py when SERPAPI_API_KEY is configured.
Use search evidence before finalizing noisy themes:
python "$SKILL_ROOT/scripts/search_leaders.py" --watchlist 光模块 --num 10
python "$SKILL_ROOT/scripts/build_judge_packet.py" --watchlist 光模块
After building a judge packet, Codex should read it, act as the LLM judge, and write a reviewed JSON result. Use that reviewed result to update the frozen resolved_pools/[theme].json. Do not let keyword rules alone decide final inclusion.
For repeatability:
- Daily monitoring reads the existing frozen pool.
- If the frozen pool is missing,
run_daily.py automatically attempts leader discovery once.
- If automatic discovery fails, the theme is skipped and a warning is written; do not silently fall back to a manual company pool.
- Refresh only on explicit user request using
discover_leaders.py --refresh.
- Every refresh writes a dated snapshot under
~/.earnings_watch/snapshots/YYYY-MM-DD/.
- If discovery fails, keep using the last frozen pool rather than replacing it with an empty pool.
IR URL Discovery
Each frozen company should carry ir_url when available. Use SerpAPI-backed search to collect candidates:
python "$SKILL_ROOT/scripts/company_ir_search.py" --watchlist 光模块
Review:
~/.earnings_watch/ir_candidates/YYYY-MM-DD/[watchlist].json
To fill missing ir_url fields automatically only when the top result is high scoring:
python "$SKILL_ROOT/scripts/company_ir_search.py" --watchlist 光模块 --apply-best
Event Overrides
When a primary source misses a confirmed company IR event, add it to:
~/.earnings_watch/event_overrides.json
Example:
{
"events": [
{
"ticker": "AVGO",
"name": "Broadcom",
"market": "US",
"event_date": "2026-06-03",
"fiscal_period": "Q2 FY2026",
"time_bucket": "after market close",
"source": "company_ir",
"source_url": "https://investors.broadcom.com/news-releases/news-release-details/broadcom-inc-announce-second-quarter-fiscal-year-2026-financial",
"confidence": "high"
}
]
}
manual_events.json is a legacy filename. The daily runner still reads it for compatibility, but new overrides belong in event_overrides.json.
Source Coverage Report
Every daily run writes:
~/.earnings_watch/outputs/YYYY-MM-DD/source_coverage_report.json
The report lists every monitored company, its ir_url, observed event and filing sources, expected sources for that market, missing sources, companies covered by only one source, and source-level miss lists. Treat this as a data-quality audit: a missing source does not prove no event exists, it means that source did not provide usable coverage for that run window.
Summary Rules
When new filings are found, download the original document where possible, then produce a concise research summary:
- revenue, profit, EPS, margin, cash flow
- year-over-year and sequential changes when available
- guidance and management commentary
- investor focus points
- major risks and uncertainties
- source links and file paths
If the filing cannot be parsed, summarize only metadata and source links. Do not invent financial numbers.
Safety And Licensing
Respect each data source's rate limits and terms. Mark unofficial sources such as yfinance and scraped web endpoints as best-effort. For commercial deployment, review vendor licenses before sending automated emails to users.