Files
market_screener/README.md
T
Kazuma cd74497de6 refactor: restructure to clean architecture
fix: restore ScoringConfig improvements lost in refactor commit

docs: rewrite README and CLAUDE.md to reflect current architecture

code-format

code fixes
2026-06-03 01:36:21 -04:00

6.3 KiB
Raw Blame History

Market Screener & Personal Finance Assistant

A Node.js CLI tool that screens stocks, ETFs, bonds, and crypto using live Yahoo Finance data. It scores each asset under two lenses — Market-Adjusted (what's acceptable in today's inflated market) and Fundamental (Graham-style strict value investing) — and gives you an honest signal by comparing both.

It also connects to your brokerage accounts via SimpleFIN to track net worth, spending, and give hold/sell/add advice on your actual portfolio.


Quick Start

npm install
cp .env.example .env     # add SIMPLEFIN_SETUP_TOKEN if you have SimpleFIN
npm start                # screen today's catalyst tickers from Yahoo news

Commands

Command What it does
npm start Fetches today's market news, extracts catalyst tickers, screens them
npm start -- watch Screens the default watchlist instead
npm start -- AAPL MSFT VOO Screens specific tickers
npm run finance Portfolio advice + SimpleFIN account data → finance-report.html
npm run import-portfolio -- file.csv Imports Robinhood/Vanguard/Fidelity CSV into portfolio.json
npm test Runs all unit tests (51 tests, zero external dependencies)
npm run test:watch Re-runs tests on file changes during development
npm run format Formats all source files with Prettier
npm run format:check Checks formatting without writing (useful in CI)

Both commands generate self-contained HTML reports that open in any browser.


How the Screener Works

Every asset is scored twice:

Market-Adjusted — gates derived from live Yahoo Finance benchmarks:

  • Stock P/E gate = S&P 500 P/E (via SPY) × 1.5
  • Tech P/E gate = XLK sector P/E × 1.3
  • REIT min yield = XLRE dividend yield × 0.85
  • Bond min spread = LQD TNX live spread × 0.80

Fundamental — strict Graham/value-investing gates from src/config/ScoringConfig.js:

  • Stock P/E < 20x, PEG < 1.5
  • Bond spread > 1.0% above risk-free rate

The comparison produces a Signal:

Signal Meaning
Strong Buy Passes both — genuinely good value
Momentum Passes market-adjusted, holds fundamentally
⚠️ Speculation Passes market-adjusted, fails fundamental — priced for perfection
🔄 Neutral Hold territory in one or both lenses
Avoid Fails both

Personal Finance

Edit portfolio.json with your holdings (or import from a broker CSV):

{
  "holdings": [
    { "ticker": "AAPL",    "shares": 10,   "costBasis": 150.00, "source": "Robinhood", "type": "stock"  },
    { "ticker": "VOO",     "shares": 8,    "costBasis": 380.00, "source": "Vanguard",  "type": "etf"    },
    { "ticker": "BTC-USD", "shares": 0.25, "costBasis": 45000,  "source": "Coinbase",  "type": "crypto" }
  ]
}

npm run finance screens your holdings, fetches crypto prices, and generates hold/sell/add advice based on the screener signal crossed with your gain/loss position.

SimpleFIN (optional)

Connects to your real bank and brokerage accounts for net worth, balances, and 30-day spending breakdown.

  1. Get your setup token from beta-bridge.simplefin.org
  2. Add to .env: SIMPLEFIN_SETUP_TOKEN=aHR0cHM6Ly...
  3. Run npm run finance — the Access URL is claimed and saved automatically

Importing broker holdings

npm run import-portfolio -- ~/Downloads/robinhood_holdings.csv
npm run import-portfolio -- ~/Downloads/vanguard_holdings.csv

Broker is auto-detected from CSV headers. Running multiple imports merges them into portfolio.json.


Project Structure

├── bin/
│   ├── screen.js              # Market screener entry point
│   ├── finance.js             # Personal finance entry point
│   └── import-portfolio.js    # Broker CSV importer
│
├── prompts/
│   └── catalyst-analysis.md   # Daily catalyst analysis playbook
│
├── src/
│   ├── config/
│   │   └── ScoringConfig.js   # All scoring gates, weights, thresholds
│   │
│   ├── market/                # Yahoo Finance data layer
│   │   ├── YahooClient.js
│   │   ├── BenchmarkProvider.js
│   │   └── MarketRegime.js    # Derives inflated gate overrides from live data
│   │
│   ├── screener/              # Core screening domain
│   │   ├── ScreenerEngine.js
│   │   ├── DataMapper.js
│   │   ├── RuleMerger.js
│   │   ├── Chunker.js
│   │   ├── assets/            # Stock, Etf, Bond data containers
│   │   └── scorers/           # StockScorer, EtfScorer, BondScorer
│   │
│   ├── analyst/
│   │   └── CatalystAnalyst.js # Extracts tickers from Yahoo Finance news
│   │
│   ├── finance/
│   │   ├── clients/
│   │   │   └── SimpleFINClient.js
│   │   ├── PersonalFinanceAnalyzer.js
│   │   ├── PortfolioAdvisor.js
│   │   └── PortfolioImporter.js
│   │
│   └── reporters/
│       ├── HtmlReporter.js    # screener-report.html
│       └── FinanceReporter.js # finance-report.html
│
├── portfolio.json             # Your holdings (edit this)
└── .env                       # SIMPLEFIN_SETUP_TOKEN / SIMPLEFIN_ACCESS_URL

Metrics Scored per Stock

Metric Source Why it matters
P/E ratio Yahoo forwardPE / trailingPE Valuation
PEG ratio Yahoo or computed (trailingPE ÷ earningsGrowth) Valuation vs growth
Price-to-Book Yahoo Graham's primary value metric
ROE Yahoo returnOnEquity Buffett's primary quality metric
Operating margin Yahoo operatingMargins Pricing power
Net profit margin Yahoo profitMargins Bottom-line profitability
Revenue growth Yahoo revenueGrowth Top-line momentum
FCF yield Computed (freeCashflow ÷ market cap) Cash generation quality
Debt/Equity Yahoo debtToEquity Balance sheet risk
Quick ratio Yahoo quickRatio (falls back to currentRatio) Liquidity
Beta Yahoo beta Market sensitivity
52-week position Yahoo fiftyTwoWeekHigh/Low Momentum / opportunity flag

Sector overrides apply: REIT scores on yield + P/FFO, FINANCIAL on ROE + P/B, TECHNOLOGY with realistic D/E tolerance.