screen_canslim
Screen KR and/or US stocks against William O'Neil's CAN SLIM checklist (as taught by David Ryan), joining the nightly valuation_latest (earnings/sales growth, ROE, PER) and indicators_latest (relative strength, distance from the 52-week high) snapshots. Returns fundamentally strong momentum leaders, sorted by RS by default.
One of four named strategy screens (this one, screen_minervini, screen_kell, screen_schwartz), each a fixed published checklist. Not this tool for: thresholds you choose yourself (screen_technical), fundamentals (screen_companies) or funds (screen_etfs).
Only C, A, N, S, L are coded as filters — I (institutional sponsorship) and M (market direction) require fund-flow and index-level data that cannot be evaluated from a single stock's snapshot, so they are intentionally omitted:
C — Current quarterly earnings: latest-quarter diluted-EPS YoY >= c_min (default 25). Quarter codes compare like-for-like a year apart (1=Q1, 2=cumulative half, 3=Q3).
A — Annual earnings & quality: latest annual diluted-EPS YoY >= a_min (default 25) AND ROE >= roe_min (default 17)
N — New highs: price within near_high_pct% of the 52-week high (default 15)
S — Sales: latest annual revenue YoY > 0 when require_sales is true (default true)
L — Leader: RS rating (national percentile 1-99) >= rs_min (default 80)
A metric that is NULL (e.g. growth base was a loss, so the sign-flipped percentage is dropped) fails its comparison and the stock is excluded.
Args:
- market: 'kr' (DART/KOSPI+KOSDAQ), 'us' (EDGAR), or 'all' (default)
- c_min: min latest-quarter EPS YoY %, CAN SLIM C (default 25)
- a_min: min latest-annual EPS YoY %, CAN SLIM A (default 25)
- roe_min: min ROE %, quality gate under A (default 17)
- rs_min: min RS percentile 1-99, CAN SLIM L (default 80)
- near_high_pct: max % below the 52-week high, CAN SLIM N (default 15; smaller = closer to the high)
- require_sales: require positive annual revenue growth, CAN SLIM S (default true)
- min_vol_avg20: optional min 20-day average volume (liquidity filter for illiquid microcaps)
- min_price: optional min close price (O'Neil avoids low-priced stocks; e.g. 10 for US$, 5000 for KRW)
- sort_by: rs_pctile|eps_q_yoy|eps_a_yoy|sales_a_yoy|roe|pct_from_52w_hi|close (default rs_pctile)
- order: 'asc'|'desc' (default 'desc'); limit: 1-50 (default 20); response_format: 'markdown'|'json'
Returns: {count, market, criteria:{c_min, a_min, roe_min, rs_min, near_high_pct, require_sales}, rows:[{name, source, ticker|stock_code, as_of, close, eps_q_yoy, eps_a_yoy, sales_a_yoy, roe, rs_pctile, pct_from_52w_hi, per}]}. Growth/ROE values are percent; pct_from_52w_hi is <= 0.
Examples:
- US CAN SLIM leaders with liquidity: {market:'us', min_vol_avg20: 500000}
- Strict KR growth leaders near highs: {market:'kr', c_min: 40, a_min: 30, rs_min: 90, near_high_pct: 10}
Use when: finding CAN SLIM-style growth leaders combining earnings/sales acceleration with strong relative strength. Don't use for a single company's valuation detail (get_valuation), the Minervini price template (screen_minervini), or raw statements (get_dart_financials / get_edgar_financials).
Notes: CAN SLIM's I (institutional sponsorship) and M (market direction) cannot be screened from single-stock data — only C, A, N, S, L are applied. Growth uses diluted-EPS/revenue YoY; a company whose prior-period base is non-positive (loss->profit sign flip) has a null metric and is excluded. KR fundamentals follow K-IFRS and US follow US-GAAP, so cross-market growth/ROE comparisons are approximate. KR/US/TW prices are adjusted for corporate actions but not dividends (indicators around dividend events may be slightly distorted); US history starts 2023-03-28 (volume from 2024-07-01) so long-window figures are shallower there. Snapshot from the nightly ingest, not real-time, and not investment advice.
Errors: an empty result is not an error (count 0 = nothing passed today); 'database has not been built yet' -> the valuation/indicators ingest has not run.
screen_companies
Screen companies across five markets on annual fundamentals stored in the local finbridge database: Korea (DART), the US (SEC EDGAR), Taiwan (TWSE/TPEx), Japan (EDINET) and Europe (ESEF/IFRS). Filters and sorting run on standard metrics plus derived ratios; Annual rows (quarter=0) are the default. When a single market has no annual rows and fiscal_year is omitted, the screen falls back to that market's latest reported period. This fallback is not used for market='all'; do not compare a partial-year result with annual revenue. Base amounts are in each company's reporting currency — KRW, USD, TWD, JPY, or for Europe whatever the filer reports in (EUR, DKK, SEK, NOK, PLN, ...) — so absolute-value thresholds are market-dependent and cross-market (market='all') screens work best with ratio metrics (margins, roe, debt_ratio).
Not this tool for: price or technical signals (screen_technical and the four named strategy screens), funds (screen_etfs), one company in depth (get_valuation), or statements straight from the regulator (get_dart_financials / get_edgar_financials).
Coverage note: Taiwan carries only the latest reported period, because TWSE publishes a snapshot rather than history, and it has no annual row at all until an FY Q4 statement publishes — so roe, psr and the 3-year CAGRs are empty for every Taiwanese company, and cash / operating cash flow are unavailable there at any depth (the TWSE OpenAPI publishes no cash-flow statement and its balance sheet carries no cash line). Screen Taiwan on revenue, margins, EPS and the balance-sheet totals; use market='kr' or 'us' when the screen depends on a return, a multiple or a growth rate. Europe is still loading and is thinner than the others: about 1 in 8 rows has no operating_income (the filer tags it with a company extension rather than the IFRS concept) and about 1 in 5 has no revenue (banks and investment entities report interest revenue or fair-value gains, not a single IFRS revenue total — we leave the column empty rather than fill it with a component that would make margins mean different things per row). Germany and Ireland are largely absent from the ESEF index, and European rows use an ISIN in ticker where ESMA mapping is available; unmatched rows may have no ticker. European company pages are not available, so page_url remains null. Every market here has financial statements — none of them is master-only.
What 'eu' means: any issuer that files under ESEF, i.e. has securities admitted to an EU/EEA/UK regulated market. That is a listing venue, not a domicile, so foreign issuers listed in Europe appear here too (Samsung Electronics, Toyota Caetano Portugal, Kazatomprom) and amounts stay in the filer's own reporting currency. A company cross-listed in several of our markets appears once per market with that market's own filing, so market='all' can show it more than once — this is not new to Europe (Toyota is already under both 'us' as TOYOTA MOTOR CORP and 'jp' as トヨタ自動車株式会社). Screen one market at a time when you need each company exactly once.
Period fallback: a single-market screen normally uses each company's latest ANNUAL report. When a market has no annual rows yet (Taiwan today reports a half-year cumulative), the screen drops to that market's latest available period and the response says which one in the 'period' field — e.g. "FY2026 Q2 (year-to-date cumulative)". Within one market every row is then the same period, so the ranking holds. market='all' never does this: lining up a half-year revenue against a full-year one would be a silently wrong table.
Args:
- market: 'kr' (DART), 'us' (EDGAR), 'tw' (TWSE/TPEx), 'jp' (EDINET), 'eu' (ESEF), or 'all' (default)
- fiscal_year: specific fiscal year; omit to use each company's latest annual report
- filters: up to 5 of {metric, op, value}. op: gt|gte|lt|lte|eq. value is a number (ratios are in percent, e.g. 20 = 20%).
- sort_by: metric to sort on (default 'revenue'); order: 'asc'|'desc' (default 'desc')
- limit: 1-100 (default 20); response_format: 'markdown'|'json'
Metrics: revenue, gross_profit, operating_income, net_income, eps_diluted, assets, liabilities, equity, cash_and_equivalents, operating_cash_flow, plus derived operating_margin (operating_income/revenue*100), net_margin (net_income/revenue*100), roe (net_income/equity*100), debt_ratio (liabilities/equity*100).
Returns: {count, market, fiscal_year|'latest', sort_by, order, rows: [{name, source, ticker|stock_code, fiscal_year, currency, <each metric used>}]}. If a company reports under multiple accounting bases for the same year it may appear once per basis.
Examples:
- KR companies with operating margin > 20%: {market: 'kr', filters: [{metric: 'operating_margin', op: 'gt', value: 20}], sort_by: 'operating_margin'}
- US mega caps by revenue in FY2025: {market: 'us', fiscal_year: 2025, sort_by: 'revenue', limit: 10}
Use when: ranking or filtering many companies at once. Don't use for a single known company's statement detail (query_db or get_dart_financials / get_edgar_financials).
Errors: 'database has not been built yet' — ingest has not run; an empty result is not an error (count 0).
screen_etfs
Screen exchange-traded funds in the local finbridge database on the things that actually distinguish an ETF: premium/discount to NAV, fund size (AUM), the index it tracks, price momentum, and — for US funds — the audited calendar-year TOTAL return from the fund's own prospectus.
Funds only. Operating companies are screened by screen_companies (fundamentals) or screen_technical / the four named strategy screens (price signals).
⚠These funds are excluded from screen_companies by construction: that tool ranks on annual financial statements, which funds do not file.
Coverage differs by market and the response says so per row:
- KR (1,170 listed ETFs): NAV, AUM (net assets, KRW), listed units and the tracked index come from the same daily feed as prices, 2020-01-02 onward. premium_pct is close/NAV-1 computed on the SAME day (mixing dates would be meaningless).
- US (5,868 ETFs): no NAV or AUM source exists that we may redistribute, so those fields are null. Instead total_return_pct carries the fund's audited calendar-year total return (distributions reinvested) from SEC prospectus data — the only distribution-inclusive number available.
⚠ret_20d / ret_120d are PRICE returns in every market: ETF distributions are not in the daily bars, so income funds look worse than they were. For US funds compare against total_return_pct to see the gap.
⚠aum is in the listing currency (KRW today). Do not rank across markets on it.
⚠total_return_pct is pinned to ONE calendar year across all rows (reported as total_return_year), because prospectus refresh dates differ per fund — ranking a 2024 figure against a 2025 one would be a silently wrong table.
Args:
- market: 'kr', 'us', or 'all' (default)
- min_aum: minimum net assets in listing currency (KR only; e.g. 100000000000 = 1,000억)
- max_abs_premium_pct: keep funds trading within this |premium| of NAV, e.g. 0.5
- min_premium_pct: keep funds at or above this premium (negative values find discounts)
- min_price, min_volume: liquidity floors (vol_avg20 is the 20-session average)
- index_contains: substring of the tracked index name — 'TR' finds total-return index trackers, '코스피' finds KOSPI trackers
- name_contains: substring of the fund name or ticker
- total_return_year: calendar year for total_return_pct; omit for the best-covered year
- sort_by: aum | premium | abs_premium | ret_20d | ret_120d | ret_250d | volume | total_return (default aum); order: 'asc'|'desc' (default desc)
- limit: 1-100 (default 20); response_format: 'markdown'|'json'
Returns: {count, market, total_return_year, sort_by, order, rows: [{market, symbol, name, as_of, close, nav, premium_pct, aum, index_name, ret_20d, ret_120d, vol_avg20, total_return_pct, total_return_period}]}
Examples:
- Large KR ETFs trading close to fair value: {market:'kr', min_aum: 100000000000, max_abs_premium_pct: 0.3, sort_by:'aum'}
- KR ETFs at the deepest discount to NAV: {market:'kr', sort_by:'premium', order:'asc'}
- KR trackers of a total-return index: {market:'kr', index_contains:'TR', sort_by:'aum'}
- US ETFs by audited total return: {market:'us', sort_by:'total_return'}
Use when: choosing or comparing funds. Don't use for stocks (screen_companies) or for a single fund's price history (get_stock_prices).
Errors: 'database has not been built yet' — ingest has not run; an empty result is not an error (count 0).
screen_kell
Screen KR, US and/or TW stocks for an Oliver Kell "Cycle of Price Action" long setup, evaluated on the nightly indicators_latest snapshot (daily corporate-action-adjusted KR prices).
One of four named strategy screens (this one, screen_minervini, screen_canslim, screen_schwartz), each a fixed published checklist. Not this tool for: thresholds you choose yourself (screen_technical), fundamentals (screen_companies) or funds (screen_etfs).
APPROXIMATION: Oliver Kell's method is discretionary — his full cycle (reversal extension, EMA crossback, wedge pop, base-n-break, exhaustion) is a chart read, not a formula. This screener only proxies ONE phase: "a relative-strength leader in an uptrend, riding its short-term EMAs and not over-extended". It will miss real Kell setups and flag stocks that are not.
Conditions (all required):
- close > 20-day EMA (uptrend, holding the 20EMA)
- price is 0..'max_ext_pct'% above the 10-day EMA (above support but not exhausted)
- RS percentile >= 'rs_min' (a leader)
- if require_ema_stack: 10-day EMA > 20-day EMA (rising short-term stack)
Args:
- market: 'kr', 'us', or 'all' (default)
- rs_min: minimum RS percentile 1-99 (default 80; Kell trades leaders)
- max_ext_pct: max % above the 10-day EMA before treating it as over-extended (default 15)
- require_ema_stack: require 10EMA > 20EMA (default true)
- min_vol_avg20: optional minimum 20-day average volume (liquidity filter)
- min_price: optional minimum close price (avoid low-priced stocks; e.g. 10 for US$, 5000 for KRW)
- sort_by: rs_pctile|pct_from_ema10|ret_20d|ret_5d|macd_hist|close (default rs_pctile)
- order: 'asc'|'desc' (default 'desc'); limit: 1-50 (default 20); response_format: 'markdown'|'json'
Returns: {count, market, criteria:{rs_min, max_ext_pct, require_ema_stack}, rows:[{name, source, ticker|stock_code, as_of, close, ema10, ema20, pct_from_ema10, macd_hist, rs_pctile, ret_20d}]}.
Examples:
- US leaders on EMA support: {market:'us', min_vol_avg20: 500000}
- Tighter KR leaders near the 10EMA: {market:'kr', rs_min: 85, max_ext_pct: 8, min_vol_avg20: 100000}
Use when: shortlisting momentum leaders riding short-term EMAs (Kell style, approximate). Don't treat a pass as a Kell "buy" — the cycle phase and chart context are discretionary. For the 8-point trend template use screen_minervini; for arbitrary technicals use screen_technical.
How it differs from screen_schwartz (the other short-EMA screen): this one asks for an established LEADER in a trend — RS >= 80 by default, close above the 20-day EMA and a rising 10>20 EMA stack — so it favours names already trending. screen_schwartz asks only for a fresh momentum turn — close above the 10-day EMA with MACD histogram > 0 and RS >= 60 — so it surfaces earlier, looser, shorter-horizon candidates. Pick screen_kell for "leaders still riding the trend", screen_schwartz for "just turned up with momentum confirmation"; the two lists overlap but are not the same set.
Notes: KR/US/TW prices are adjusted for corporate actions but not dividends (indicators around dividend events may be slightly distorted); US history starts 2023-03-28 (volume from 2024-07-01) so long-window figures are shallower there. This is an approximation of a discretionary method, not a faithful reproduction. Market data, not investment advice.
Errors: an empty result is not an error (count 0 = nothing passed today); 'database has not been built yet' -> ingest/indicators has not run.
screen_schwartz
Screen KR, US and/or TW stocks for a Marty Schwartz short-term momentum setup, evaluated on the nightly indicators_latest snapshot (daily corporate-action-adjusted KR prices).
One of four named strategy screens (this one, screen_minervini, screen_canslim, screen_kell), each a fixed published checklist. Not this tool for: thresholds you choose yourself (screen_technical), fundamentals (screen_companies) or funds (screen_etfs).
APPROXIMATION: Marty Schwartz is a discretionary short-term trader; this screener only proxies his "10-day EMA green light + MACD momentum" principle. It is not his full method (which includes intraday timing, tape reading, and risk discretion). Expect false positives and misses.
Conditions (all required):
- close > 10-day EMA (Schwartz's "green light")
- if require_macd_bull: MACD histogram > 0 (momentum bullish)
- RS percentile >= 'rs_min'
- price <= 'max_ext_pct'% above the 10-day EMA (not over-extended)
Args:
- market: 'kr', 'us', or 'all' (default)
- rs_min: minimum RS percentile 1-99 (default 60)
- require_macd_bull: require MACD histogram > 0 (default true)
- max_ext_pct: max % above the 10-day EMA before over-extended (default 12)
- min_vol_avg20: optional minimum 20-day average volume (liquidity filter)
- min_price: optional minimum close price (avoid low-priced stocks; e.g. 10 for US$, 5000 for KRW)
- sort_by: rs_pctile|pct_from_ema10|ret_20d|ret_5d|macd_hist|close (default rs_pctile)
- order: 'asc'|'desc' (default 'desc'); limit: 1-50 (default 20); response_format: 'markdown'|'json'
Returns: {count, market, criteria:{rs_min, require_macd_bull, max_ext_pct}, rows:[{name, source, ticker|stock_code, as_of, close, ema10, ema20, pct_from_ema10, macd_hist, rs_pctile, ret_20d}]}.
Examples:
- US short-term momentum, liquid: {market:'us', min_vol_avg20: 500000}
- KR names on a fresh 10EMA green light, tight: {market:'kr', rs_min: 70, max_ext_pct: 6}
Use when: shortlisting short-term momentum names on a 10-EMA green light (Schwartz style, approximate). Don't treat a pass as a Schwartz buy — his method is discretionary. For the trend template use screen_minervini; for EMA-support leaders use screen_kell.
How it differs from screen_kell (the other short-EMA screen): this one wants a fresh momentum turn — close above the 10-day EMA, MACD histogram > 0, RS >= 60 by default — and does not require the 20-day EMA or a rising EMA stack, so it fires earlier and admits more names. screen_kell wants an established leader (RS >= 80, above the 20-day EMA, 10>20 EMA stack) already riding the trend. Pick screen_schwartz for "just turned up, momentum confirmed", screen_kell for "leaders still trending"; overlapping but different sets.
Notes: KR/US/TW prices are adjusted for corporate actions but not dividends (indicators around dividend events may be slightly distorted); US history starts 2023-03-28 (volume from 2024-07-01) so long-window figures are shallower there. This is an approximation of a discretionary method, not a faithful reproduction. Market data, not investment advice.
Errors: an empty result is not an error (count 0 = nothing passed today); 'database has not been built yet' -> ingest/indicators has not run.
screen_technical
Screen KR/US companies by technical signals over the latest indicator snapshots (v_indicators / indicators_latest, refreshed nightly). Signals and the sort key are fixed whitelists mapped to SQL predicates; every threshold is bound as a parameter, so inputs are never interpolated into SQL.
This is the open-ended technical screen: you pick the signals and thresholds. The four named strategies are fixed checklists instead (screen_minervini, screen_canslim, screen_kell, screen_schwartz). Not this tool for: fundamentals (screen_companies) or funds (screen_etfs).
Args:
- market: 'kr' (DART), 'us' (EDGAR), or 'all' (default)
- signals: any of golden_cross, dead_cross, rsi_oversold (RSI<30), rsi_overbought (RSI>70), near_52w_high (within 3% of high), near_52w_low, above_sma20, volume_surge (vol_ratio>=2), macd_bullish (macd_hist>0), rs_leader (RS rating >=80 vs home market), rs_outperform (RS rating >=60). ANDed together; omit for none.
- min_price: optional minimum close; min_vol_avg20: optional minimum 20-day average volume (liquidity filter)
- sort_by: ret_1d|ret_5d|ret_20d|ret_60d|ret_120d|ret_250d|rsi14|vol_ratio|pct_from_52w_hi|pct_from_52w_lo|close|atr14|rs_pctile|rs_120d (default ret_20d)
- order: 'asc'|'desc' (default 'desc'); limit: 1-100 (default 20); response_format: 'markdown'|'json'
Relative strength (rs_pctile 1-99, rs_120d) measures each stock vs its OWN national market (KR vs the KR universe, US vs the US universe): rs_pctile is the national percentile of blended 3/6/12-month momentum (IBD-style; 99=strongest); rs_120d is 6-month excess return in pp over the national median.
Returns: {count, market, signals, sort_by, order, rows:[{name, source, ticker|stock_code, as_of, close, rsi14, macd_hist, ret_5d, ret_20d, ret_60d, vol_ratio, pct_from_52w_hi, pct_from_52w_lo, golden_cross, dead_cross, above_sma20, rs_pctile, rs_120d}]}.
Examples:
- Oversold KR names by 20-day return: {market:'kr', signals:['rsi_oversold'], sort_by:'ret_20d', order:'asc'}
- US breakouts near highs on volume: {market:'us', signals:['near_52w_high','volume_surge'], min_vol_avg20: 1000000}
- Strongest KR leaders vs the KOSPI/KOSDAQ universe: {market:'kr', signals:['rs_leader'], sort_by:'rs_pctile', min_vol_avg20: 100000}
Use when: ranking/filtering many companies by momentum or trend signals. Don't use for one company's detail (get_technicals) or fundamentals (screen_companies).
Notes: KR/US/TW prices are adjusted for corporate actions but not dividends (indicators around dividend events may be slightly distorted); US history starts 2023-03-28 (volume from 2024-07-01) so long-window figures are shallower there. Market data, not investment advice.
Errors: an empty result is not an error (count 0); 'database has not been built yet' -> ingest/indicators has not run.