InvestDayTip
A multi-factor scoring and analysis tool for long-term stock & ETF research in US, European, Asian, and Superinvestor-consensus markets, computed live from public market data — a decision-support tool, not investment advice.
🌐 See it live — investdaytip.com
The site runs on this project's scoring engine — the pure-Python core behind the CLI tool — and publishes quantitative ratings for the top 100 US stocks, refreshed daily: per-ticker deep-dive (Piotroski, Altman, risk signals), a time machine that diffs any past run against the one before it, and a methodology page whose full model documentation links right here.
The site is a separate project (proprietary code, third-party market data under its own terms) built on this engine; the engine itself stays MIT.
Features
- 📈 Multi-factor scoring — composite 0-100 score per asset
- 🔗 Multiple data sources — yfinance (default), yahooquery (batch), Financial Modeling Prep (FMP) or StockFit (US stocks, Starter plan), with automatic fallback
- 🏦 Stocks & ETFs — auto-detected and scored with dedicated models
- 🌍 US, European, Asian & Superinvestor markets — S&P 500, DAX, CAC 40, FTSE 100, Nikkei 225, Hang Seng, NSE, and superinvestor consensus holdings from DataRoma 13F filings
- 💱 Currency filter — narrow by native currency (
USD,EUR,JPY, …) - ⚡ Concurrent fetching — analyzes ~500 tickers in seconds
- 📊 Rich CLI output — price, 1M/1Y change, score breakdown and rationale
- 🧾 Self-contained HTML export — interactive report with filters and sortable columns
- 🧪 Pure scoring functions — testable without network
- 🧠 Interactive advisor — market pulse, portfolio review, and model-scored candidate lists via the
advisorsubcommand (decision support, not personal recommendations) - 🤖 AI-powered assistant — chat in natural language to analyze markets, review portfolios, and explore the model's top-rated candidates — powered by OpenCode agents
- 📊 Backtest validation — historical backtesting with automated before/after comparison script
- 🧾 StockFit integration (optional) — point-in-time SEC filing dates for backtests (
--pit-source stockfit, works offline from a local snapshot), a fundamentals insights section in the HTML report (--fundamental-insights), per-tickerdeep-divereports and a keyless devil's advocate layer (risk signals). Works on every StockFit plan — and without a key at all (stockfit-statusshows what yours unlocks)
Installation
From PyPI (recommended)
pip install investdaytip
Upgrade
pip install --upgrade investdaytip
Force reinstall if the version doesn't update (e.g. cached old wheel):
pip install --upgrade --no-cache-dir investdaytip
From source (for development)
git clone https://github.com/dfdezdom/investdaytip.git
cd investdaytip
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
Quick start
investdaytip
That's it. You'll see the top 5 highest-scoring candidates across the curated universes — ~490 US, EU, Asian & superinvestor tickers before the market-cap filter.
Usage
CLI
Subcommands:
| Command | What it does | Section |
|---|---|---|
investdaytip [flags] |
Top-scoring candidates from the curated universes | below |
investdaytip advisor |
Interactive market pulse, portfolio review, model candidates | Advisor |
investdaytip deep-dive |
Per-ticker deep report (score + research + diagnostics) | Deep-dive |
investdaytip backtest |
Historical validation of the scoring model | Backtest |
investdaytip stockfit-status |
Your StockFit plan + which features unlock | Tiers |
investdaytip # Top 5 from full universe (US + EU + Asia, stocks + ETFs)
investdaytip -n 10 # Top 10
investdaytip -a stocks # Only stocks
investdaytip -a etfs # Only ETFs
investdaytip -r us # Only US
investdaytip -r eu # Only Europe
investdaytip -r asia # Only Asia
investdaytip -r superinvestor # Only superinvestor consensus tickers
investdaytip -r us eu # US + Europe
investdaytip -r eu -a stocks # Only European stocks
investdaytip -r asia -a etfs # Only Asian ETFs
investdaytip -c USD # Only USD-denominated assets
investdaytip -c EUR # Only EUR-denominated assets
investdaytip -c USD EUR # USD + EUR assets
investdaytip -c JPY # Only JPY-denominated assets
investdaytip -r eu -c USD # EU region + USD post-filter
investdaytip -r us eu -c USD EUR # US + EU, USD + EUR assets
investdaytip -t AAPL MSFT VOO # Custom ticker list
investdaytip --tickers-file tickers.txt # Custom ticker file (lines, spaces, commas)
investdaytip --tickers-file tickers-files-examples/semiconductors_relevant_tickers.txt
investdaytip --export-html report.html # Export report with interactive filters
investdaytip --export-html # Uses investDayTip-aaaammdd-hhmm.html
# or investDayTip-<tag>-aaaammdd-hhmm.html
# when --tickers-file is set
investdaytip --superinvestor # Fetch DataRoma superinvestor data and display column
investdaytip --no-include-technical # Disable RSI + MACD (enabled by default for quant)
investdaytip --scoring-model classic # Use the classic Graham/Buffett model instead of quant
investdaytip --min-market-cap 1B # Raise min market cap to $1B
investdaytip --min-market-cap 0 # Disable market-cap filter
investdaytip --data-source yahooquery # Use yahooquery (batch-friendly yfinance backend)
# Falls back to yfinance automatically per ticker
investdaytip --data-source fmp # Use Financial Modeling Prep (requires FMP_API_KEY env var)
# Get a free key at https://financialmodelingprep.com/
investdaytip --data-source stockfit # Use StockFit (US stocks only; STOCKFIT_API_KEY + Starter)
# Falls back to yfinance per ticker on failure
investdaytip --no-cache # Bypass SQLite cache, fetch fresh data
investdaytip --cache-clear # Purge all cached data before running
investdaytip --workers 20 # More parallelism
investdaytip advisor # Interactive mode (asks for risk, region, etc.)
investdaytip deep-dive -t AAPL # Deep report: score + research + risk signals
investdaytip deep-dive -t NVDA --export-html nvda.html
investdaytip backtest -n 10 -r us # Backtest stock scoring on US market (stocks only)
investdaytip backtest -t AAPL MSFT VOO # Backtest on custom ticker list
investdaytip backtest --export-html # Export backtest results to HTML
investdaytip backtest --no-cache # Bypass cache in backtest
investdaytip backtest --cache-clear # Purge cache before backtest
investdaytip stockfit-status # Your StockFit plan and unlocked features
investdaytip --help
./preview.sh # Serve generated HTML files on localhost:8000
Options
| Flag | Description | Default |
|---|---|---|
-n, --top N |
Number of candidates to show (defaults to ticker count when -t is used) |
5 |
-t, --tickers ... |
Custom ticker list (overrides universe; quoted space-separated ok) | curated universe |
--tickers-file PATH |
Text file with custom tickers (merged with --tickers if both are used) |
disabled |
-a, --asset-class {all,stocks,etfs} |
Asset class filter | all |
-r, --region {all,us,eu,asia,superinvestor} nargs="+" |
Region filter(s) — e.g. -r us eu |
all |
-c, --currency {all,USD,EUR,GBP,…} nargs="+" |
Currency filter(s); narrows universe to matching regions when no -r is given |
all |
-s, --sector TEXT |
Sector/category prefix filter, case-insensitive (e.g. Financial matches Financial Services) |
disabled |
--export-html [PATH] |
Export the scoring results to self-contained HTML (investDayTip-aaaammdd-hhmm.html if omitted) |
disabled |
--superinvestor |
Include superinvestor ownership data from DataRoma (adds ~80 HTTP requests, shows column in HTML and CLI) | disabled |
--fundamental-insights |
Add a StockFit fundamentals section to the HTML report (margin trends, FCF/NI quality, balance-sheet health; US stocks only). Uses STOCKFIT_API_KEY when set and is omitted gracefully without it |
disabled |
--include-technical |
Include RSI + MACD technical indicators in the scoring. Default is True for quant and False for classic. Use --no-include-technical to force-disable. |
model-dependent |
--no-include-technical |
Force-disable RSI + MACD technical indicators | disabled |
--scoring-model {classic,quant} |
Stock/ETF scoring model | quant |
--data-source {yfinance,yahooquery,fmp,stockfit} |
Data source. fmp = stocks only, needs FMP_API_KEY; stockfit = US stocks only, needs STOCKFIT_API_KEY + Starter plan (TTM trailing fundamentals, same basis as yfinance) |
yfinance |
--min-market-cap VALUE |
Minimum market cap (1B, 500M, 0 to disable; see Market Cap Classification) |
0 with tickers, 2B otherwise |
--no-cache |
Skip SQLite cache, fetch all data live from the configured source | disabled |
--cache-clear |
Purge the SQLite cache before running | disabled |
--workers N |
Parallel fetch threads | 10 |
--version |
Show the installed version and exit | n/a |
-h, --help |
Print the usage help and exit | n/a |
🤖 OpenCode AI Agent
InvestDayTip includes an AI-powered analysis assistant that lets you explore markets and the model's output from your terminal — no memorizing CLI flags. Its answers are decision support built on the scoring model, not personal investment advice.
Prerequisites
# Install via the official installer (macOS / Linux)
curl -fsSL https://opencode.ai/install | bash
# Also available via npm, brew, bun, and more — see https://opencode.ai
What it can do
- Market pulse — Full macro analysis (VIX + yield curve + bond volatility + DXY) in ~30 seconds
- Portfolio review — Score your holdings and see the model's risk signals for the lowest-scoring positions
- Candidate scan — top-scoring tickers filtered by region, asset class, and risk profile
- Devil's advocate — Bear case + risk signals for specific tickers (see below)
- Full analysis — All of the above combined into a single comprehensive report
Quick example
@advisor what's the market pulse?
Expected output:
📊 Market Pulse
Macro Score: 58/100 (Neutral)
- VIX: 14.2 (calm)
- 10Y-2Y Spread: +0.85% (healthy)
- MOVE: 78 (normal)
- DXY: 102.3 (strong)
- Fear & Greed: 67/Greed
Macro posture: neutral — Mixed macro signals: some tailwinds alongside headwinds
The agent reports what the model reads — a score and a posture (
risk-on/neutral/defensive), never a buy/sell/hold signal. See the wording rules in.opencode/agents/advisor.md.
🩺 Devil's advocate — bear cases from SEC footnotes
Every portfolio review and candidate scan now ends with a bear case for the analyzed tickers, in two layers:
| Layer | Source | Needs |
|---|---|---|
| 1 — risk signals | investdaytip deep-dive (risk bullets, Piotroski checks, Altman zone) + StockFit footnotes bullets (Pro plan) |
nothing — works keyless |
| 2 — SEC footnotes | StockFit MCP tools: customer/supplier concentration trends, debt maturity walls, stock-comp dilution, insider summaries (0 buys vs N sells), governance flags | StockFit MCP connected |
@advisor devil's advocate on NVDA
Expected output: severity bullets (🔴/🟡/🔵) mixing both layers — e.g. "Customer One went from 14% → 25% of receivables in two years" next to "0 insider buys vs 318 sells ($2.18B) in 12 months" — plus the balanced view of what does not support the bear case (clean balance sheet, no hidden leverage). Never fabricated: every bullet comes from a tool call.
Connecting the StockFit MCP (layer 2): the server is registered in
opencode.json (OAuth 2.1 — no API key in config):
opencode mcp add stockfit --url https://api.stockfit.io/mcp # already registered
Then sign in once from the OpenCode TUI: run /mcps, select stockfit and
complete the browser flow. Tools appear as tools.stockfit.* (125 of them —
footnotes, governance, insider/ownership summaries, sector-aware metrics).
Without the MCP — or on lower plans — the advisor degrades to layer 1 and
says so explicitly.
AI Agent vs CLI advisor
| OpenCode AI Agent | investdaytip advisor CLI |
|
|---|---|---|
| Interface | Natural language chat | Interactive menu prompts |
| Flexibility | Ad-hoc questions, follow-ups | Predefined flow |
| Speed | ~30s for market pulse | ~1–2 min for full analysis |
| Output | Clean markdown tables | Rich colored tables (terminal) |
| Best for | Quick questions, exploration | Deep structured analysis |
Full documentation
See .opencode/agents/advisor.md for:
- VIX / macro regime interpretation rules
- Fear & Greed Index readings
- Bubble burst historical indicators (dot-com 2000, railroads 1845)
- Portfolio scoring thresholds and presentation format
- Devil's advocate rules (bear-case layers, StockFit tool map, never-fabricate)
- Execution methods (market pulse, portfolio review, devil's advocate, full analysis)
Advisor subcommand
Interactive market analysis with multi-indicator macro pulse (VIX, 10Y-2Y yield curve, MOVE bond volatility, DXY dollar strength), portfolio review, and model-scored candidate lists:
investdaytip advisor # Interactive mode (asks for risk, region, etc.)
investdaytip advisor --risk moderate # Non-interactive with risk preset
investdaytip advisor --risk aggressive -r us -a stocks # US stocks, aggressive, non-interactive
investdaytip advisor --risk moderate --portfolio portfolios/portfolio.txt # Custom portfolio
The advisor now displays a composite macro health score (0-100):
- 🟢 ≥70 — Macro healthy
- 🟡 ≥45 — Mixed signals
- 🟠 ≥25 — Macro warning
- 🔴 <25 — Macro danger
See investdaytip advisor --help for all options.
Market Indicators
The advisor fetches six live indicators to compute the composite macro health score (0-100):
| Indicator | Ticker | What it measures | Reference ranges | Score impact |
|---|---|---|---|---|
| VIX | ^VIX |
Expected S&P 500 volatility over the next 30 days | ≤15 calm, ≤25 neutral, ≤35 fear, >35 panic | ±20 |
| VXN | ^VXN |
Expected Nasdaq 100 volatility (tech-heavy complement to VIX) | (informational only) | — |
| 10Y-2Y Spread | ^TNX + 2YY=F |
US Treasury yield curve slope — inverted curve signals recession risk | >1% healthy, 0–1% neutral, <0% inverted | −20 / +5 |
| MOVE | ^MOVE |
Bond market volatility (Merrill Lynch Option Volatility Estimate) | <60 calm, 60–100 normal, 100–120 elevated, >120 panic | −15 / +5 |
| DXY | DX-Y.NYB |
US Dollar Index — strength against EUR, JPY, GBP, CAD, SEK, CHF | <95 weak, 95–100 neutral, 100–105 strong, >105 very strong | −10 / +5 |
| Fear & Greed | CNN API | Composite market sentiment from 7 sub-indicators (momentum, breadth, put/call, volatility, junk bonds, safe havens) | 0–100; <25 extreme fear, >75 extreme greed | ±10 (contrarian) |
The score starts at a neutral 50 and each indicator adjusts it up or down based on current readings. The final score determines the macro regime and the posture reported with it — a model output for decision support, not an instruction to trade:
- 🟢 ≥70 — Macro healthy → risk-on
- 🟡 ≥45 — Mixed signals → neutral
- 🟠 ≥25 — Macro warning → neutral
- 🔴 <25 — Macro danger → defensive
These are the postures the CLI prints (Macro posture: risk-on) — the model's
reading of the macro backdrop, never an instruction to trade.
All indicators are shown live in the 📈 Market Analysis table when running investdaytip advisor.
Deep-dive subcommand
Per-ticker deep report — this is where the detail lives: the InvestDayTip score, StockFit's research summary and keyless health diagnostics.
investdaytip deep-dive -t AAPL # Rich terminal report
investdaytip deep-dive -t "AAPL MSFT" --export-html # Self-contained HTML page
| Section | Source | Needs STOCKFIT_API_KEY? |
|---|---|---|
| Score + factor breakdown | live data + the scoring model | no |
| Earnings snapshot (margins, ROE/ROIC, FCF, growth, next dates) | StockFit company/research-summary |
yes (omitted gracefully otherwise) |
| Piotroski F-Score (9 checks) + Altman Z + zone | local computation from the ticker's own statements | no |
| Devil's advocate — risk signals | local heuristics (Altman zone, Piotroski failures, leverage, payout, losses) + StockFit footnotes/* bullets (concentration, debt maturities, pensions…) |
no — footnotes layer needs a Pro plan (omitted with a note otherwise) |
Piotroski/Altman are informative diagnostics — never scored (they were validated and rejected as scoring factors). The Altman Z-Score follows StockFit's variant of the 1968 model: X4 = book value of equity attributable to the parent ÷ total liabilities (not the 1968 market-value term), so the keyless diagnostic matches StockFit's precomputed value exactly.
| Flag | Description | Default |
|---|---|---|
-t, --tickers ... |
Ticker(s) to analyse (required) | — |
--export-html [PATH] |
Export the report to a self-contained HTML page | disabled |
--scoring-model {classic,quant} |
Scoring model for the displayed score | quant |
--no-cache |
Skip SQLite cache for the underlying fetches | disabled |
StockFit integration & tiers
InvestDayTip works on every StockFit plan — and without a key at all: features unlock more as the tier rises and degrade gracefully below it (omitted with the reason, never fabricated). See what your setup unlocks:
investdaytip stockfit-status
| Feature | Needs |
|---|---|
PIT backtests + snapshot (--pit-source stockfit) |
keyless (local snapshot) |
HTML fundamental insights (--fundamental-insights) |
any key (Free) |
| deep-dive earnings snapshot | Starter |
| Rich devil's advocate footnotes (roadmap) | Pro |
Backtest subcommand
Historical validation of the stock scoring model:
investdaytip backtest # Backtest US stocks (default)
investdaytip backtest -n 10 # Top 10 candidates per snapshot
investdaytip backtest -r us # US stocks
investdaytip backtest -r eu # European stocks
investdaytip backtest -r asia # Asian stocks
investdaytip backtest -r superinvestor # Superinvestor consensus stocks
investdaytip backtest -t AAPL MSFT # Custom ticker list
investdaytip backtest --benchmark SPY # Custom benchmark
investdaytip backtest --interval-months 6 # Semi-annual snapshots
investdaytip backtest --lag-days 90 # Reporting lag (default: 60)
investdaytip backtest --period 3y # Shorter price history
investdaytip backtest --export-html # Export to HTML
investdaytip backtest --pit-source stockfit # Point-in-time SEC filing dates (StockFit)
investdaytip backtest --no-cache # Bypass SQLite cache
investdaytip backtest --cache-clear # Purge cache before run
Backtest options
| Flag | Description | Default |
|---|---|---|
-n, --top N |
Top N candidates per snapshot | 10 |
-t, --tickers ... |
Custom ticker list | curated US universe |
-r, --region ... |
Region filter(s) | us |
-c, --currency ... |
Currency filter(s) | all |
--period PERIOD |
yfinance lookback period | 5y |
--interval-months N |
Months between snapshots | 3 |
--lag-days N |
Reporting lag in days | 60 |
--min-market-cap CAP |
Minimum market cap (0, 1B, …) |
0 with tickers, 2B otherwise |
--benchmark TICKER |
Benchmark for alpha/returns | SPY (per region) |
--export-html [PATH] |
Export results to HTML | disabled |
--scoring-model {classic,quant} |
Scoring model to validate | quant |
--pit-source {none,stockfit} |
Point-in-time fundamentals (exact SEC filing dates; needs key or local snapshot) | none |
--include-technical / --no-include-technical |
Force RSI/MACD in/out | model-dependent |
--max-workers N |
Parallel fetch threads | 10 |
--no-cache / --cache-clear |
Bypass / purge the SQLite cache | disabled |
Note: Backtest only supports stocks (no ETFs). It simulates quarterly snapshots with a configurable reporting lag, scores each stock, and measures forward returns against a benchmark.
Point-in-time fundamentals (StockFit, opt-in)
--pit-source stockfit replaces the fixed reporting-lag assumption with each
filing's actual SEC acceptance date (dateFiled) — every snapshot only sees
data that was public that day, so slow filers can't leak results back in time.
US stocks only. Validated on the full US universe: Sharpe 0.74→0.85, max
drawdown 24%→11%, 12M win rate 50%→56% (hypothetical backtests over
historical data — past performance is not indicative of future results).
It works without an API key when a local snapshot exists
(~/.investdaytip/pit/) — build one while your StockFit key is valid:
python scripts/pit_snapshot.py # full US stock universe (196 tickers)
python scripts/pit_snapshot.py --status # inspect saved files (offline)
Resolution order, per ticker: live StockFit (when STOCKFIT_API_KEY is set)
→ local snapshot → the classic fixed-lag path.
Backtest-Driven Scoring Validation
Use the included scripts/scoring_baseline.py to validate scoring changes objectively:
# Save baseline BEFORE your change
python scripts/scoring_baseline.py run \
--tag "before" -r us -n 10 \
-t "AAPL MSFT GOOGL META NVDA" \
--period 2y --interval-months 3 \
--min-market-cap 0
# Save baseline AFTER your change
python scripts/scoring_baseline.py run \
--tag "after" -r us -n 10 \
-t "AAPL MSFT GOOGL META NVDA" \
--period 2y --interval-months 3 \
--min-market-cap 0
# Compare two different scoring models on the same universe
python scripts/scoring_baseline.py run --tag classic -r us -n 10 \
-t "AAPL MSFT GOOGL META NVDA" --period 2y --interval-months 3 \
--min-market-cap 0 --scoring-model classic
python scripts/scoring_baseline.py run --tag quant -r us -n 10 \
-t "AAPL MSFT GOOGL META NVDA" --period 2y --interval-months 3 \
--min-market-cap 0 --scoring-model quant
python scripts/scoring_baseline.py compare baseline-classic.json baseline-quant.json
# Compare side-by-side with decision rules
python scripts/scoring_baseline.py compare baseline-before.json baseline-after.json
Decision rules:
- Ship it: Alpha ↑ AND Sharpe ↑ AND 12M win rate ↑
- Consider: Alpha ↑ OR Sharpe ↑ (mixed, review drawdown)
- Reject / iterate: Alpha ↓ AND Sharpe ↓
When to use technical indicators
The --include-technical flag adds RSI-14 and MACD histogram to the Momentum factor (15% weight, blended at 30%). Under the quant model this is now enabled by default; under classic it remains opt-in.
Backtest validation across four scenarios under the quant model shows the flag is generally additive for US screens but mixed for concentrated mega-caps and EU:
| Scenario | Without --include-technical |
With --include-technical |
Verdict |
|---|---|---|---|
US ($2B+) (134 tickers, -n 10) |
Alpha 21.94%, Sharpe 1.49 | Alpha 25.00%, Sharpe 1.68 | ✅ Improved — higher alpha (+3pp), Sharpe (+0.19), and lower drawdown (6.76% → 5.63%) |
US (no cap filter) (134 tickers, -n 10) |
Alpha 5.47%, Sharpe 0.54 | Alpha 11.53%, Sharpe 0.85 | ✅ Improved — alpha doubles, drawdown halves (34.3% → 16.2%), 12M win rate climbs (53% → 73%) |
US mega-caps ($200B+) (134 tickers, -n 2) |
Alpha 44.33%, Sharpe 1.31 | Alpha 42.35%, Sharpe 1.18 | ⚠️ Mixed — slightly lower alpha (−2pp) and Sharpe, but drawdown improves sharply (18.8% → 10.4%) |
EU ($2B+) (66 tickers, -n 10) |
Alpha 7.11%, Sharpe 1.71 | Alpha 3.93%, Sharpe 0.93 | ⚠️ Neutral/Mixed — lower alpha and Sharpe with tech, but 12M win rate climbs (42% → 60%) |
The backtest figures above are hypothetical simulations over historical data, under the assumptions modeled; past performance is not indicative of future results.
Guidelines:
- ✅ Default behavior —
quantenables technical indicators automatically;classickeeps them opt-in - ✅ Broad US screens benefit the most — higher alpha, Sharpe, and lower drawdown
- ⚠️ Concentrated mega-cap lists — mixed results; alpha and Sharpe may dip but drawdown improves
- ⚠️ EU screens — fundamental-only (no-tech) shows stronger risk-adjusted returns; verify on your specific ticker list
- ❌ Use
--no-include-technicalif you rely on theclassicmodel or want a pure fundamental signal
Market Cap Classification
The --min-market-cap filter controls the size of companies included in the analysis. Standard classification for reference:
| Category | Market Cap | Typical characteristics |
|---|---|---|
| Mega-cap | > $200B | Largest global companies (Apple, Microsoft, Google). Highest liquidity, most followed by analysts, technical indicators most reliable. |
| Large-cap | $10B – $200B | Established companies with stable fundamentals. Good balance of growth and stability. |
| Mid-cap | $2B – $10B | Growing companies, regional leaders. More volatile than large-caps but higher growth potential. |
| Small-cap | $300M – $2B | Niche players or regional companies. Higher volatility, less analyst coverage, fundamentals less reliable. |
| Micro-cap | < $300M | Early-stage or distressed companies. Very high risk, low liquidity. |
Why the default is $2B (mid-cap threshold):
The model is designed for long-term fundamental investing. Below $2B (small/micro-caps), companies tend to have:
- Incomplete or unreliable financial data in yfinance
- Higher volatility that overwhelms fundamental signals
- Lower liquidity, making technical indicators less meaningful
The $2B threshold strikes a balance: it includes mid-caps and above (where fundamentals are reliable) while filtering out the noisiest small/micro-caps. Use --min-market-cap 0 to include all tickers, or raise it to 10B/50B for a pure large/mega-cap focus.
Note: when explicit tickers are provided via -t or --tickers-file, the filter defaults to 0 (disabled) — the assumption is that you curated your own list.
HTML export
Generate an interactive report that works offline (single file with inline CSS/JS):
investdaytip -n 25 -a all -r all --export-html investdaytip-report.html
The generated report includes filters for:
- Text search (ticker/name/sector)
- Asset class (
stock/etf) - Region (
us/eu/asia) - Minimum score
- Minimum 1M return (%)
- Minimum 1Y return (%)
When --superinvestor is enabled, an additional "Superinvestors" sortable column appears between 1Y and Score showing the number of tracked managers holding each ticker.
When --include-technical is enabled, "RSI" and "MACD" columns appear between 1Y (or Superinvestors) and Score.
It also includes:
- Click-to-sort columns (ascending/descending)
- Full-width responsive layout (uses available browser width)
- Pre-rendered rows + client-side interactivity (works even if JS is restricted)
- Direct platform links in table columns:
Ticker(Google Finance),T(TradingView),Y(Yahoo Finance)
Direct platform links (Ticker → Google Finance, T → TradingView, Y → Yahoo Finance) use exchange suffix mapping. See _normalize_exchange_hint() and _exchange_mapping() in src/investdaytip/html_export.py for the full list of ~20 supported exchanges.
Programmatic API
from investdaytip import get_recommendations
# Get top 5 Asian stocks
results = get_recommendations(top_n=5, region="asia", asset_class="stocks")
for s in results:
print(f"{s.data.ticker} ({s.asset_type}) — score={s.total:.1f}")
print(f" Price: {s.data.current_price} {s.data.currency}")
print(f" 1M: {s.data.return_1m:.2%} 1Y: {s.data.return_12m:.2%}")
print(f" Why: {'; '.join(s.rationale[:3])}")
# Or filter by sector (prefix match, case-insensitive)
results = get_recommendations(top_n=5, sector="Financial") # Financial + Financial Services
# Or mix regions and asset classes
results = get_recommendations(top_n=10, region="all") # US + EU + Asia stocks & ETFs
# Choose the scoring model explicitly (quant is the default)
results = get_recommendations(top_n=5, region="us", scoring_model="classic")
# Use FMP data source (requires FMP_API_KEY env var)
results = get_recommendations(top_n=5, region="us", data_source="fmp")
Output
Each row includes:
| Column | Meaning |
|---|---|
| Type | STOCK or ETF |
| Ticker / Name / Sector | Identification |
| Ticker link | Opens Google Finance in a new tab |
| T / Y | Opens TradingView / Yahoo Finance in a new tab |
| Price | Close of the session named under the table, in native currency |
| 1D Δ | Daily change vs the previous close of that same session — not the live intraday move |
| P/E | Trailing price-to-earnings ratio (stocks; - when unavailable) |
| Yield | Dividend yield for stocks (TTM from raw dividends, fallback to dividendYield) or ETFs (yield_) — - when unavailable |
| 1M Δ | % change vs ~22 trading days ago |
| 1Y Δ | % change vs ~252 trading days ago |
| RSI | RSI-14 (when --include-technical is enabled) |
| MACD | MACD histogram % vs price (when --include-technical is enabled) |
| Superinvestors | Number of managers holding the stock (HTML only; - if not in DataRoma universe) |
| Score | Composite 0-100 weighted score |
| Breakdown | Four sub-scores (shown in a compact single line) |
| Why | Top 3 rationale notes |
Every figure in a row comes from that row's own price series, and a run built while the market is open describes the last session to have closed — a session in progress has no close yet, so it is not a bar (_drop_partial_session() drops it). The report says so instead of leaving the reader to infer it from a column called "today":
Session: 2026-10-08 (last closed) — every figure in the table comes from that session; the live quote is not scored.
That line is the table's caption in the CLI and the footer of an exported HTML report (… · Session: 2026-10-08 (last closed)); the report's own headers read 1D / 1M / 1Y, the CLI's add the Δ.
Scoring Model
InvestDayTip supports two stock-scoring models, selectable via --scoring-model {classic,quant}. The default is quant, a five-factor model inspired by Seeking Alpha Quant Ratings (a trademark of its owner; this project is not affiliated with, endorsed by, or connected to Seeking Alpha). The original classic model (Graham/Buffett + momentum) remains available for backwards compatibility.
Each metric is normalized to 0-100 via piecewise-linear functions over empirically reasonable ranges. Missing data contributes a neutral 50 so a ticker isn't penalized for lacking a metric.
Stocks — quant (default)
| Factor | Weight | Metrics |
|---|---|---|
| Value | 25% | trailing P/E, P/B, PEG (derived = P/E ÷ growth %, positive growth only), FCF yield |
| Growth | 20% | earnings growth, revenue growth |
| Profitability | 25% | ROE, ROA, profit margin + a YoY-improvement sub-score (Δgross margin + ΔROA vs last fiscal year; neutral when statements are unavailable) |
| Momentum | 15% | price vs SMA200, 12-month return, SMA200 slope (plus RSI-14 + MACD histogram by default; disable with --no-include-technical) |
| EPS Revisions | 15% | average EPS surprise (Reported EPS vs analyst Estimate) over the last four quarters |
The quant model uses disqualifying grades: if any high-impact factor falls into red-flag territory, the total score is capped at neutral (50). This prevents a strong showing in one area from masking a serious weakness elsewhere.
Stocks — classic
| Pillar | Weight | Metrics |
|---|---|---|
| Quality | 35% | ROE, profit margin, earnings & revenue growth |
| Value | 25% | trailing P/E, P/B, PEG |
| Health | 20% | Debt/Equity, current ratio, free cash flow |
| Trend | 20% | price vs SMA200, 12-month return, SMA200 slope (plus RSI-14 + MACD histogram when --include-technical is explicitly enabled) |
ETFs
ETF scoring also switches between two models via --scoring-model {classic,quant}. The default is quant, a momentum-first model.
quant (default for ETFs when --scoring-model quant):
| Factor | Weight | Metrics |
|---|---|---|
| Momentum | 65% | 1m (15%), 3m (25%), 6m (30%), 12m (30%) returns |
| Risk | 15% | volatility + beta (lower is better) |
| Cost | 12% | expense ratio (lower is better) |
| Liquidity | 8% | AUM (log scale) |
classic (used when --scoring-model classic):
| Pillar | Weight | Metrics |
|---|---|---|
| Returns | 40% | 3y avg, 5y avg, 12m return |
| RiskAdj | 25% | Sharpe proxy (r12 - rf) / σ, annualized volatility |
| Size | 15% | AUM (log scale) |
| Cost/Yield | 20% | expense ratio (lower=better), dividend yield |
Universes
When no -t is given, InvestDayTip uses curated universes:
- US stocks — 122 large-caps across all S&P sectors (
src/investdaytip/universe.py) - US ETFs — 41 broad-market, factor, sector and bond ETFs (
etf_universe.py) - EU stocks — 99 large-caps from DAX, CAC, FTSE 100, IBEX, AEX, SMI, FTSE MIB, Euronext Brussels and the Nordics (
eu_universe.py) - EU UCITS ETFs — 35 broad, sector and bond UCITS ETFs (
eu_etf_universe.py) - Asia stocks — 110 large-caps from Japan, Hong Kong, Singapore, India, South Korea, Taiwan, and Australia (
asia_universe.py) - Asia ETFs — 17 broad-market, country-specific, and sector ETFs with significant Asian exposure (
asia_etf_universe.py) - Superinvestor stocks — 101 consensus stocks held by ≥2 of ~82 top investors tracked by DataRoma 13F filings (
superinvestor_universe.py)
Merging the pools for a full scan (-r all -a all) yields 492 unique
tickers — overlapping tickers and cross-listings (e.g. TSM / 2330.TW,
VXUS in two ETF lists) are deduplicated before fetching.
Tickers use Yahoo Finance suffixes:
- US: no suffix (AAPL, MSFT)
- EU:
.DEXetra ·.PAParis ·.ASAmsterdam ·.LLondon ·.MCMadrid ·.MIMilan ·.SWSwiss ·.BRBrussels ·.STStockholm ·.COCopenhagen ·.OLOslo ·.HEHelsinki - Asia:
.TTokyo ·.HKHong Kong ·.SISingapore ·.NSNSE India ·.KSKorea ·.TWTaiwan ·.AXAustralia
Ticker File Examples
The repository includes ready-to-use ticker sets in tickers-files-examples/ for thematic analyses:
artificial_intelligence_relevant_tickers.txtbiotech_relevant_tickers.txtenergy_relevant_tickers.txteu_etfs_relevant_tickers.txtfinancial_relevant_tickers.txthealth_relevant_tickers.txtpharma_relevant_tickers.txtquantum_computing_relevant_tickers.txtsemiconductors_relevant_tickers.txtspace_relevant_tickers.txtspain_relevant_tickers.txttechnology_relevant_tickers.txt
Example:
investdaytip -n 15 --tickers-file tickers-files-examples/artificial_intelligence_relevant_tickers.txt --export-html
After export, preview the generated file in a browser by running:
./preview.sh
Then open the generated report from:
http://localhost:8000/<generated-file-name>.html
Shell tab completion
Requires the argcomplete package (installed automatically with pip install investdaytip):
# Enable for the current session:
eval "$(register-python-argcomplete investdaytip)"
# Make it permanent (add to ~/.zshrc or ~/.bashrc):
echo 'eval "$(register-python-argcomplete investdaytip)"' >> ~/.zshrc
Once enabled, try investdaytip -<TAB> or investdaytip --region <TAB>.
Data Source
Four interchangeable data sources, selected with --data-source (default yfinance). Every source falls back to yfinance automatically for the tickers it cannot serve, so a run degrades instead of failing:
| Source | What it is | Scope & requirements |
|---|---|---|
yfinance (default) |
Yahoo Finance via the yfinance library — fundamentals from Ticker.info, prices and trend metrics from Ticker.history(period="2y") |
stocks & ETFs, all regions; no key |
yahooquery |
Yahoo's internal API in batches of 10 (faster and more resilient to Yahoo HTML changes), mapped onto the same info shape |
stocks & ETFs, all regions; no key; per-ticker fallback to yfinance |
fmp |
Financial Modeling Prep REST API — 6 endpoints per ticker | stocks only (no ETFs); FMP_API_KEY; free tier is 250 req/day (~40 tickers), then auto-falls back to yfinance |
stockfit |
StockFit SEC-derived fundamentals and price history (TTM basis, as-filed YoY comparisons) | US stocks only; STOCKFIT_API_KEY + Starter plan; per-ticker fallback to yfinance |
StockFit also feeds features that are orthogonal to --data-source: point-in-time backtests (--pit-source stockfit), the HTML --fundamental-insights section, deep-dive research and the devil's-advocate footnotes. Each of those degrades gracefully by plan tier — see StockFit integration & tiers.
These libraries and endpoints are third-party services and remain subject to those providers' terms of use; generated reports therefore contain third-party data and are not covered by this repository's MIT license.
Dividend yield normalization: yfinance reports dividendYield inconsistently — most US tickers return a decimal (e.g. 0.054 = 5.4%) while some European tickers return an already-multiplied percentage (e.g. 4.05 = 4.05%). InvestDayTip normalizes any value greater than 1.0 by dividing by 100.
Reliable stock dividend yield: For stocks, the Yield column is computed directly from Ticker.dividends over the trailing twelve months divided by the current price, because yfinance's dividendYield field can be wildly wrong for some tickers (e.g. AAPL and V). When raw dividend history is unavailable, InvestDayTip falls back to the normalized dividendYield from Ticker.info.
Superinvestor data comes from DataRoma (https://www.dataroma.com), which aggregates publicly filed SEC Form 13F holdings for ~82 well-known investors. The data is fetched once and cached for 7 days. Use --superinvestor to enable this data and display the "Superinvestors" column in both the HTML report and the CLI table (disabled by default to avoid the extra requests).
Ticker normalization: When a company has multiple share classes (e.g., Alphabet's GOOGL and GOOG), DataRoma holdings are normalized to a single ticker (GOOGL) to avoid duplicate counting. This ensures the "Superinvestors" column reflects unique manager positions, not duplicated entries.
Local Cache
InvestDayTip includes an SQLite cache (~/.investdaytip/cache.db) created automatically on first fetch:
| Data | TTL |
|---|---|
| Prices & history | 15 minutes |
Fundamentals (info, FMP profile+ratios) |
1 day |
| Financial statements (balance sheet, income, cash flow) | 7 days |
| Dividends · earnings dates | 7 days |
| Fear & Greed Index | 1 hour |
| Superinvestor holdings | 7 days |
| StockFit profile + TTM facts, research summary, fundamental insights, footnotes, detected plan | 1 day |
The cache uses per-thread SQLite connections with a write lock to support concurrent fetches safely. Use --no-cache to bypass the cache for a single run, or --cache-clear to purge all entries. Both flags work on the main and backtest subcommands. Caching is automatically disabled when running tests.
Project Structure
preview.sh # Local static server for generated HTML reports
scripts/
├── scoring_baseline.py # Backtest before/after comparison tool
├── factor_ic.py # Factor IC analysis (which metrics predict returns)
├── pit_snapshot.py # StockFit PIT statement snapshot builder
├── compare_data_sources.py # yfinance vs yahooquery vs FMP field comparison
└── diagnose_fmp.py # FMP endpoint/field diagnostic helper
src/investdaytip/
├── __init__.py # Public API: get_recommendations
├── main.py # CLI entry point + rich table rendering
├── advisor.py # Interactive advisor: market pulse (VIX + macro), portfolio review, ranked candidates
├── backtest.py # Historical stock scoring validation (stocks only)
├── dataroma.py # DataRoma superinvestor holdings client (13F aggregation)
├── html_export.py # Self-contained HTML report exporter
├── recommender.py # Concurrent orchestration
├── cache.py # SQLite caching layer (per-thread connections, WAL mode)
├── data_source.py # yfinance wrapper + dataclasses (StockData / EtfData)
├── data_source_fmp.py # FMP wrapper (alternative data source, 6 endpoints/ticker)
├── data_source_yahooquery.py # Yahooquery batch data source
├── data_source_stockfit.py # StockFit client: PIT statements, insights, plan detection, live source
├── financial_health.py # Piotroski F-Score, Altman Z, YoY-improvement flags
├── deep_dive.py # Per-ticker deep report (score + research + diagnostics)
├── risk_signals.py # Keyless devil's advocate layer (bear-case bullets)
├── scoring.py # Pure scoring functions (score_stock, score_etf)
├── sentiment.py # CNN Fear & Greed Index fetch
├── universe.py # US stock universe
├── etf_universe.py # US ETF universe
├── superinvestor_universe.py # Superinvestor consensus universe (DataRoma 13F)
├── eu_universe.py # EU stock universe
├── eu_etf_universe.py # EU UCITS ETF universe
├── asia_universe.py # Asia stock universe
└── asia_etf_universe.py # Asia ETF universe
portfolios/ # Portfolio ticker files
advisor_recommendations/ # Advisor-generated HTML reports (git-ignored)
tests/
├── conftest.py # Global fixtures (cache off, network guard, temp snapshot dir)
├── test_integration.py # End-to-end integration tests (sorting, filters, CLI, export)
├── test_advisor.py # Advisor tests (VIX, macro regime, bubble risk)
├── test_backtest.py # Backtest engine tests (fetch, snapshots, scoring, cache, interpret)
├── test_recommender.py # Recommendation orchestration tests
├── test_main.py # CLI helper tests
├── test_html_export.py # HTML export tests
├── test_scoring.py # Stock scoring tests
├── test_scoring_quant.py # Quant model tests (five factors, improvement sub-score)
├── test_etf_scoring.py # ETF scoring tests
├── test_financial_health.py # Piotroski / Altman / improvement-flag tests
├── test_sentiment.py # Fear & Greed sentiment tests
├── test_cache.py # SQLite cache tests
├── test_universes.py # Universe integrity tests
├── test_data_source.py # yfinance data fetching tests
├── test_data_source_fmp.py # FMP data fetching tests
├── test_data_source_yahooquery.py # Yahooquery data source tests
├── test_data_source_stockfit_pit.py # StockFit PIT layer tests (mocked HTTP)
├── test_data_source_stockfit_live.py # StockFit live data source tests (mocked HTTP)
├── test_fundamental_insights.py # StockFit insights section tests
├── test_footnotes.py # StockFit footnotes parsing / bear-case bullets
├── test_risk_signals.py # Keyless devil's advocate risk-signal tests
├── test_stockfit_rate_limit.py # StockFit plan-aware rate limiter tests
├── test_pit_snapshot.py # PIT snapshot layer tests
├── test_deep_dive.py # Deep-dive report tests
├── test_stockfit_plan.py # StockFit tier detection & capability gating tests
└── test_dataroma.py # DataRoma client tests
tickers-files-examples/
├── semiconductors_relevant_tickers.txt
├── artificial_intelligence_relevant_tickers.txt
├── quantum_computing_relevant_tickers.txt
├── energy_relevant_tickers.txt
├── space_relevant_tickers.txt
├── technology_relevant_tickers.txt
├── spain_relevant_tickers.txt
├── eu_etfs_relevant_tickers.txt
├── pharma_relevant_tickers.txt
├── biotech_relevant_tickers.txt
├── health_relevant_tickers.txt
└── financial_relevant_tickers.txt
Limitations & Caveats
- No currency normalization — prices, market caps and AUM stay in native currency
- Currency filter (
-c) compares against yfinance's reported currency field; tickers with a missing/unknown currency are always kept (a missing field shouldn't silently drop a candidate) min_market_capfilter (--min-market-cap) is applied against raw native-currency figures; when active, tickers with a missing market cap are excluded- Some European tickers change Yahoo symbols over time; if a ticker is delisted in Yahoo it's silently skipped
- ETF expense ratios are sometimes missing in
yfinance— the scorer falls back to a slightly optimistic default (60) in that case - Long-term, fundamental-driven model: not suitable for short-term/day trading signals
Testing
pip install -e ".[dev]" # pytest, ruff, mypy
pytest -q # run the suite
ruff check src tests # lint
mypy # type-check
569 tests across 26 test files. The scoring engine is purely functional
and tested without network calls; an autouse guard in tests/conftest.py fails
fast if a test reaches yfinance unmocked. Integration tests mock the full
recommend() → main() → export pipeline.
Contributing
Contributions are welcome! See CONTRIBUTING.md.
Disclaimer
This is not financial advice. InvestDayTip is a research and decision-support tool that applies a deterministic scoring model to publicly available data. Scores, score bands and macro postures, and any AI-generated commentary are model outputs, not personal recommendations to buy or sell any security. Backtests are hypothetical simulations over historical data — past performance is not indicative of future results. Always do your own research and consult a licensed advisor before making investment decisions.
Third-party names (Yahoo Finance, DataRoma, Financial Modeling Prep, StockFit, Seeking Alpha, OpenCode, …) are used for identification only and imply no affiliation or endorsement.
License
The software is MIT-licensed. Generated output is not: reports and datasets produced by the tool contain third-party market data (Yahoo Finance via yfinance/yahooquery, DataRoma 13F aggregations, and FMP or StockFit when configured) and remain subject to those providers' terms of use.
Metadata
Release files for investdaytip 0.17.9
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| investdaytip-0.17.9.tar.gz | 524.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| investdaytip-0.17.9-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 690.8 kB
Release files / investdaytip-0.17.9.tar.gz
| Download URL | investdaytip-0.17.9.tar.gz |
|---|---|
| Size | 524.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
52ae4be00cc2fbb4a88300852475f8246faa02e03d6ec5fe2f5aef3cbedcabec
|
|
BLAKE2b-256 checksum How to use checksums |
b0c7b8097b39f81b33b79cf09830da08c87775a394d44a62a74113283cb854fd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.
Transparency logRelease files / investdaytip-0.17.9-py3-none-any.whl
| Download URL | investdaytip-0.17.9-py3-none-any.whl |
|---|---|
| Size | 166.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
161d5e0ee3f3c68a31089c66ef1fd803774987f0a98092823ccc17a75ddc3b35
|
|
BLAKE2b-256 checksum How to use checksums |
6f60852ec0b9ed42960c15a64c278694a2e938e92390757d2288f15341c1b78d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.
Transparency log