Stock Showdown: Compare Stocks with Python — ROIC, FCF Yield, and 5 Metrics yfinance Can't Provide
Compare any two stocks across Valuation and Quality panels — ROIC, FCF Margin, EV/EBIT, FCF Yield, and Total Shareholder Yield that yfinance cannot provide. One API call, no signup. Clone the repo and run it in 60 seconds.
Compare NVDA vs AMD. AAPL vs MSFT. Any two stocks, head-to-head, in your terminal.
Five of seven metrics — ROIC, FCF Margin, FCF Yield, EV/EBIT, Total Shareholder Yield — are not available through yfinance or any free alternative.
======================================================================
STOCK SHOWDOWN: AAPL vs MSFT
======================================================================
PANEL 1: VALUATION (Who's cheaper today?)
----------------------------------------------------------------------
AAPL MSFT Better Value
----------------------------------------------------------------------
PE Ratio 37.18 24.99 MSFT ->
EV/EBITDA 23.97 18.29 MSFT ->
EV/EBIT * 26.08 23.70 MSFT ->
FCF Yield * 2.7% 3.0% MSFT ->
Valuation: MSFT 4-0
PANEL 2: QUALITY (Who's the better business?)
----------------------------------------------------------------------
AAPL MSFT Better Quality
----------------------------------------------------------------------
ROIC * 52.3% 25.1% <- AAPL
FCF Margin * 26.4% 33.2% MSFT ->
Shareholder Yield * 3.8% 2.1% <- AAPL
Quality: AAPL 2-1
======================================================================
VERDICT
----------------------------------------------------------------------
Valuation: MSFT is clearly cheaper (4 of 4 metrics)
Quality: AAPL is stronger (2 of 3 metrics) -- ROIC 52.3% vs 25.1%
AAPL has higher quality, MSFT is cheaper.
Classic value-vs-quality tradeoff.
----------------------------------------------------------------------
* = MetricDuck exclusive (not available in yfinance)
======================================================================
This is Stock Showdown — a Python tool that compares any two stocks using SEC-filed data from the MetricDuck API.
No API key required. No signup. Guest access gives you all 70 metrics and all 12 statistical dimensions. Just clone, install, run.
Quick Start
Python 3.10+ required.
git clone https://github.com/metric-duck/build-with-metricduck.git
cd build-with-metricduck/labs/02-stock-showdown
pip install -r requirements.txt
python showdown.py NVDA AMD
That's it. Works immediately — no API key, no config file, no signup.
Default comparison (no arguments): python showdown.py runs AAPL vs MSFT.
Why Two Panels
Most stock comparison tools show a flat list of ratios. The Stock Showdown splits the question in two:
Panel 1 — Valuation: Who is cheaper today?
| Metric | What It Measures | Prefer |
|---|---|---|
| PE Ratio | Price per $1 of earnings | Lower |
| EV/EBITDA | Enterprise value per $1 of cash earnings | Lower |
EV/EBIT * | Enterprise value per $1 of operating income | Lower |
FCF Yield * | Free cash flow as % of market cap | Higher |
Panel 2 — Quality: Who is the better business?
| Metric | What It Measures | Prefer |
|---|---|---|
ROIC * | Return on Invested Capital — how efficiently the business uses capital | Higher |
FCF Margin * | Free cash flow as % of revenue — cash generation efficiency | Higher |
Total Shareholder Yield * | Dividends + buybacks + debt paydown as % of market cap | Higher |
* = MetricDuck exclusive — not available in yfinance.
How It Works
One API Call
The showdown fetches both tickers with all 7 metrics in a single request:
import httpx
response = httpx.get(
"https://api.metricduck.com/api/v1/data/metrics",
params={
"tickers": "NVDA,AMD",
"metrics": "pe_ratio,ev_ebitda,ev_ebit,fcf_yield,roic,fcf_margin,total_shareholder_yield",
"period": "ttm",
"price": "current",
},
)
data = response.json()
The price=current parameter recalculates valuation metrics at today's market price, not the stale price from the last SEC filing. One parameter — real-time valuations from SEC-filed fundamentals.
All data uses Trailing Twelve Months (TTM) — the sum of the last four quarters of SEC filings, giving you the most recent full-year picture.
The response is nested by ticker, then by metric:
{
"data": {
"NVDA": {
"company_name": "NVIDIA Corporation",
"metrics": {
"roic": {
"label": "Return on Invested Capital",
"values": [
{"period": "TTM", "end_date": "2025-01-26", "value": 0.8234, "dimension": null}
]
},
"pe_ratio": {
"label": "PE Ratio",
"values": [
{"period": "TTM", "end_date": "2025-01-26", "value": 48.31, "dimension": null}
]
}
}
},
"AMD": {
"company_name": "Advanced Micro Devices, Inc.",
"metrics": { ... }
}
},
"metadata": {
"tickers": ["NVDA", "AMD"],
"period": "ttm",
"price": "current"
}
}
Each metric's values array contains objects with dimension: null for the base value. When you add statistical dimensions later, additional entries appear with dimension: "Q.MED8" etc.
The Comparison Logic
Each metric has a "prefer" direction and an "exclusive" flag:
VALUATION_METRICS = [
("PE Ratio", "pe_ratio", "lower", False), # Available in yfinance
("EV/EBITDA", "ev_ebitda", "lower", False), # Available in yfinance
("EV/EBIT", "ev_ebit", "lower", True), # MetricDuck exclusive
("FCF Yield", "fcf_yield", "higher", True), # MetricDuck exclusive
]
QUALITY_METRICS = [
("ROIC", "roic", "higher", True), # Exclusive
("FCF Margin", "fcf_margin", "higher", True), # Exclusive
("Shareholder Yield", "total_shareholder_yield", "higher", True), # Exclusive
]
For each metric, the tool compares both stocks and awards a point to the winner within its panel. The verdict combines both panels: valuation winner, quality winner, and an overall synthesis.
The best outcomes are when one stock wins both panels. The most interesting outcomes are when the panels disagree — quality vs value tradeoffs that force you to think about what you're optimizing for.
Extracting Values from the API Response
The API returns a nested structure. Each metric's values array may contain multiple entries (base values and dimension values). The showdown extracts base values by filtering for dimension: null:
def extract_metric(api_data, ticker, metric_id):
company = api_data.get("data", {}).get(ticker, {})
metric = company.get("metrics", {}).get(metric_id, {})
for v in metric.get("values", []):
if v.get("dimension") is None and v.get("value") is not None:
return v["value"]
return None
This pattern is future-proof — it works even when you add statistical dimensions to the request later.
Optional: yfinance for Market Context
If yfinance is installed, the showdown adds a "Market Context" panel showing sector, beta, and 52-week range:
try:
import yfinance as yf
HAS_YFINANCE = True
except ImportError:
HAS_YFINANCE = False
If yfinance isn't installed, the tool works fine without it. All 7 comparison metrics come from MetricDuck. yfinance adds supplementary context only.
# Optional: adds sector, beta, 52-week range
pip install yfinance
Build It with Claude Code
The showdown is a single Python file with no frameworks. This makes it ideal for AI-assisted development.
Here are some real modifications you can ask Claude Code (or any AI assistant) to make:
Add a metric to the quality panel:
"Add gross_margin to QUALITY_METRICS. It should prefer higher and is a MetricDuck exclusive."
Generate a sector comparison:
"Modify showdown.py to accept a list of tickers and run round-robin comparisons for AAPL, MSFT, GOOGL, AMZN, META. Output a summary table of win/loss records."
Add CSV export:
"After displaying the comparison, write the results to a CSV file with columns: metric, ticker_a_value, ticker_b_value, winner."
Combine with Lab 03:
"After the showdown, run a Stock Pulse check on the winning stock to see if it's trading above or below its 2-year median."
The full showdown.py is a single self-contained file with no class hierarchies and no abstractions. AI coding assistants can read the entire file, understand it, and extend it in one pass.
Try It Yourself
| Matchup | Command | What You'll See |
|---|---|---|
| NVDA vs AMD | python showdown.py NVDA AMD | GPU rivals — who has better ROIC? |
| GOOGL vs META | python showdown.py GOOGL META | Ad tech — quality vs valuation |
| V vs MA | python showdown.py V MA | Payment duopoly — who returns more to shareholders? |
| COST vs WMT | python showdown.py COST WMT | Retail — membership model advantage |
| TSLA vs RIVN | python showdown.py TSLA RIVN | EV makers — profitability gap |
| JPM vs GS | python showdown.py JPM GS | Banks — ROIC may show N/A (financial companies) |
Cross-sector comparisons are interesting too. Compare a tech stock to a utility, a growth stock to a value stock. The two-panel design makes the tradeoff explicit.
What about missing data?
Some stocks don't report all metrics. Banks typically don't have meaningful ROIC or EBITDA. Growth stocks may have negative FCF Yield. The tool handles this — missing values show as N/A and don't count toward the score.
What's Next
The showdown tells you who's cheaper and who's the better business today. But is the cheaper stock actually cheap by its own standards?
Lab 03: Stock Pulse — Value Trap Detector answers this by comparing any stock to its own 2-year history using MetricDuck's statistical dimensions (Q.MED8, Q.TREND8). Is NVDA's ROIC improving or declining? Is the cheaper stock actually cheap, or a value trap?
cd ../03-stock-pulse
python pulse.py NVDA
Browse all 70 available metrics at metricduck.com/metrics.
Full Source Code
The complete showdown.py is on GitHub:
github.com/metric-duck/build-with-metricduck/labs/02-stock-showdown
Clone it, read it, modify it. The only dependency is httpx.
API Access
| Tier | Daily Limit | Max Tickers | Cost |
|---|---|---|---|
| Guest (no key) | 5 requests/day | 10 tickers | Free |
| Free (registered) | 500 credits/day | 200 tickers | Free |
| Builder | 200,000 credits/mo | 200 tickers | $29/mo |
| Production | 1,000,000 credits/mo | 200 tickers | $79/mo |
Guest access works immediately — no signup required. Each showdown costs 14 credits. Register free for 500 credits/day — enough for ~35 showdowns every day. Builder tier unlocks serious development.
MetricDuck Team
Building financial intelligence you can trust. Sourced directly from SEC Edgar.