Kevin Meneses González ทดลอง screen หุ้น US 3,000+ ตัวผ่าน EODHD API โดยให้ Claude เชื่อมตรงเข้ากับ Screener API — ไม่ใช่บทความสาย “AI แนะนำหุ้น” แบบ theater แต่เป็น pipeline จริงที่มีตัวเลขจาก live call ให้ตรวจสอบได้ทุกจุด
สรุปสั้น (TL;DR)
ผมสร้าง screening funnel 4 stage บน EODHD Screener API เริ่มจาก universe ของหุ้น US ที่ market cap มากกว่า $150M ประมาณ 3,000 ตัว หลังจาก filter profitability, liquidity และ price ที่ fair เทียบกับ earnings เหลือรอด 10 ชื่อ ไม่มี hype ไม่มี “ซื้อเลยตอนนี้” บทความยังคุมถึง 2 วิธีต่อยอด — เชื่อม EODHD MCP server อย่างเป็นทางการเพื่อให้ Claude รัน screen แบบ conversational และ script cron ที่รัน funnel ทั้งชุดทุกวันแล้ว flag การเปลี่ยนแปลง ลิสต์เต็ม, code, setup อยู่ด้านล่าง
ปัญหาของ “AI แนะนำหุ้น” ส่วนใหญ่
Content สาย AI Pick Stock ส่วนใหญ่คือ theater — มีคนถาม ChatGPT ให้ “แนะนำ 5 undervalued stocks”, model ก็ดึงจาก training data ที่ stale แล้วบทความเรียกสิ่งนั้นว่า analysis ไม่มี live data, ไม่มี filter ที่ verify ได้ และไม่มีทางให้ผู้อ่าน reproduce แม้แต่ตัวเลขเดียว
ผมอยากทำตรงข้ามกับสิ่งนั้น จึง build screening pipeline จริง — Claude เชื่อมตรงไปที่ EODHD Stock Screener API รัน live query กับ ticker เป็นพัน แล้วบีบให้แคบด้วย hard numeric filter ล้วน ๆ ทุก ticker ทุกราคา ทุกตัวเลข EPS ในบทความนี้มาจาก live call ที่ทำในวันเขียน
ปัญหาของ Stock Screener ทั่วไป
Screener ฟรีบนเว็บการเงินใหญ่ ๆ ให้ filter แค่ไม่กี่ตัว — market cap, sector, บางทีก็ P/E range พอไหว sunday afternoon แต่ใช้อะไรที่ programmatic ไม่ได้ Paid terminal แก้ปัญหาเรื่อง flexibility แต่ราคาเกินกว่าที่ independent investor ส่วนใหญ่ยอมจ่ายเพื่อ test idea
ส่วน “AI-powered” stock tool ส่วนใหญ่ก็ข้ามปัญหาเรื่อง data ไปเลย — generate ticker ที่ฟังดูน่าจะใช่จาก pattern matching ไม่ใช่ live query กับ market database จริง
Bottleneck ที่แท้จริงจึงไม่ใช่ intelligence แต่คือ access ต่อ structured filterable data ที่ AI model query ได้จริง
ให้ Claude มี Real Data Source
Screener API ของ EODHD เปิด endpoint ที่ pipeline filtering ต้องการอยู่แล้ว — market capitalization, EPS, dividend yield, trading volume, sector, price ครอบคลุมทุก ticker ทุก exchange ใน request เดียว
เมื่อ Claude สามารถ call endpoint นั้นได้โดยตรง คำว่า “screen the market” เลิกเป็น metaphor แล้วกลายเป็นลำดับ API call ที่ auditable ได้จริง
Funnel ที่ผมรัน:
Stage 1 — Universe: US-listed common stock, market cap > $150M
Stage 2 — Quality filter: profitable (EPS บวก), liquid (200K+ average daily volume), ราคาสูงกว่า $5
Stage 3 — Value zone: market cap ระหว่าง $1B ถึง $50B, จ่าย dividend, ยัง liquid
Stage 4 — Ranking: เรียงตาม earnings yield (EPS ÷ price) — หุ้นที่ราคาถูกที่สุดเทียบกับรายได้จริง
Stage 1 คนเดียว return match มากกว่า 1,000 ตัวต่อหน้าและยัง run ต่อจน pagination cap ยืนยันว่า universe จริงเกิน 3,000 ticker เมื่อรวมทุก exchange US ที่ EODHD ครอบคลุมที่ market cap floor นั้น จากนั้นแต่ละ stage ก็บีบ field ลงมาแรง ๆ
Build Screener
Setup คือ authenticated GET request เดียวต่อ stage ไม่ต้อง scrape ไม่ต้อง download ด้วยมือ
import requests
import pandas as pd
API_TOKEN = "YOUR_API_TOKEN"
BASE_URL = "https://eodhd.com/api/screener"
def run_screen(filters, sort="market_capitalization.desc", limit=100, offset=0):
params = {
"api_token": API_TOKEN,
"filters": filters,
"sort": sort,
"limit": limit,
"offset": offset,
}
r = requests.get(BASE_URL, params=params)
r.raise_for_status()
return pd.DataFrame(r.json()["data"])
# Stage 2 + 3 combined: profitable, liquid, mid/large-cap, dividend-paying
filters = (
'[["market_capitalization",">",1000000000],'
'["market_capitalization","<",50000000000],'
'["exchange","=","us"],'
'["earnings_share",">",0],'
'["avgvol_1d",">",300000],'
'["adjusted_close",">",5],'
'["dividend_yield",">",0]]'
)
df = run_screen(filters)
df["earnings_yield"] = df["earnings_share"] / df["adjusted_close"]
df["implied_pe"] = 1 / df["earnings_yield"]
top10 = df.sort_values("earnings_yield", ascending=False).head(10)
print(top10[["code", "name", "sector", "adjusted_close", "earnings_share",
"earnings_yield", "dividend_yield", "market_capitalization"]])
เท่านั้นก็คือ pipeline ทั้งหมด — ไม่มี manual screening ไม่มีท่ายิม spreadsheet ก็แค่ filter ต่อกันจนลิสต์สั้นพอที่จะอ่านได้จริง
สิ่งที่ Made the Cut
จาก universe 3,000+ ตัวเหลือ 10 ชื่อที่ผ่านทุก filter — profitable, liquid, mid-to-large cap และราคาถูกที่สุดเทียบกับ earnings ของตัวเองในวันที่รัน screen
สังเกตประเด็นได้หลายอย่าง:
ไม่มี mega-cap tech — ไม่มีชื่อ FAANG ตัวใดรอด เพราะไม่มีตัวไหนที่ clear earnings yield เกิน 5% ที่ราคา ณ ปัจจุบัน filter จะ mechanically exclude อะไรก็ตามที่ราคาสูงเทียบกับ profit ของตัวเอง
เอียงไปทาง energy, financials และ insurance — ไม่ใช่ bias ที่ผมเติมเข้าไป แต่คือสิ่งที่เกิดเมื่อเรียงด้วย EPS-to-price ล้วน ๆ ใน mid-2026 ที่ growth name ยัง carry premium multiple อยู่
Geographic spread จริง — meat producer ของ Brazil, gold miner ของ South Africa, state oil ของ Colombia, bank ของ South Korea และ insurer ของ UK ทั้งหมดผ่านการตัดที่วัดด้วย USD screener ไม่ care ว่า domicile อยู่ที่ไหน มันสนแค่ตัวเลข
ไม่ใช่ buy recommendation — ถูกเทียบกับ earnings ไม่ได้แปลว่าปลอดภัย และหลายชื่อในนี้ (EIX โดยเฉพาะเรื่อง wildfire litigation, JBS เรื่อง governance ในอดีต) มี company-specific risk ที่ pure numeric filter มองไม่เห็น นี่คือรายการเริ่มต้นสำหรับ research ต่อ ไม่ใช่ portfolio
ข้าม Code: EODHD Official MCP Server
ทุกอย่างข้างบนรันผ่าน raw HTTP call ซึ่งคือ approach ที่ถูกต้องเมื่อ build อะไรที่จะ productionize แต่มีอีกวิธีที่คุ้มค่ารู้ — โดยเฉพาะถ้าอยาก iterate filter idea แบบ conversational แทนที่จะเขียน Python ใหม่ทุกครั้ง
EODHD ship Model Context Protocol (MCP) server อย่างเป็นทางการ — standard ที่ยอมให้ AI client อย่าง Claude Desktop, Claude Code และ ChatGPT call external tool ได้โดยตรงโดยที่เราไม่ต้องเขียน code จัดการ request เอง Anthropic สร้าง MCP มาแก้ปัญหา “ทุก data source ต้องการ integration แยก” โดยเฉพาะ
Server ของ EODHD เปิดtool read-only 70+ ตัว ที่ครอบคลุมพื้นที่เดียวกับ REST API — screener, fundamentals, historical และ intraday price, news และ sentiment, technical indicator, macro indicator, US options และอื่น ๆ มีให้ 2 flavor:
- v2 (OAuth) — setup ง่ายกว่าสำหรับ Claude Desktop paste URL ของ server ลง Settings → Extensions, authorize ผ่าน consent flow เสร็จ ไม่ต้อง handle API key เอง
- v1 (API key) — สำหรับ client อย่าง ChatGPT หรือ Claude Code ที่คาดหวังว่า key จะถูกส่งตรง ๆ หรือสำหรับคนที่อยาก manage auth เอง
เมื่อ connect แล้ว เราไม่ต้องเขียน requests.get() เลย แค่ถาม:
“Screen US stocks with market cap between 1B and 50B, positive EPS, dividend yield above 0, and rank them by earnings yield. Show me the top 10.”
Claude จะ translate เป็น stock_screener tool call ตัวเดียวกับที่ผมใช้ build บทความนี้ — execute กับ EODHD data จริง แล้ว return table กลับมา นี่คือวิธีที่ผมดึงตัวเลขข้างบนจริง ๆ — ไม่มี manual API scripting ในช่วง exploratory แค่บทสนทนาตรงกับ data
ในทางปฏิบัติ: raw API approach ดีกว่าเมื่อรู้ชัดแล้วว่าจะ build อะไร — cron job, dashboard, backtest ส่วน MCP approach ดีกว่าเมื่อยังตัดสินใจอยู่ว่า funnel ควรมีหน้าตายังไง เพราะเราปรับ filter แล้ว re-run เห็น output ใหม่ในไม่กี่วินาทีโดยไม่ต้องแตะ code เลย ทั้งสองแตะ EODHD infrastructure เดียวกันและใช้ quota เดียวกัน จึงไม่มี data-quality tradeoff — เป็นแค่คำถามว่าเราอยากได้ script ที่ทำซ้ำได้หรือ loop conversational ที่เร็ว
สิ่งที่ Build ต่อได้จากตรงนี้
Funnel นี้ใช้ API call 4 ครั้งกับ code ประมาณ 30 บรรทัด จากตรงนี้ build ต่อได้:
- Automated weekly screener report ส่งไป Slack หรือ email
- Streamlit dashboard ที่ filter เป็น slider แทน hardcoded value
- Backtesting loop ที่ check ว่า “cheap earnings yield + dividend-paying + mid-cap” ทำผลงานได้ดีกว่าจริงไหมบน rolling 12-month window
- Signal layer เพิ่มด้วย
wallstreet_lo/wallstreet_hisignal ของ EODHD สำหรับ cross-check กับ analyst target
เปลี่ยนเป็น Daily Job
Screen ครั้งเดียวคือ snapshot Value ที่แท้จริงปรากฏเมื่อเรารันมันทุกวันเทรดแล้ว track ว่าอะไรเปลี่ยน — ชื่อไหนหลุดออกเพราะแพงเกิน และชื่อไหนเข้ามาใหม่เพราะราคาถูกลงหรือ earnings report ใหม่ shift EPS
ต่อไปนี้คือ script ที่รัน funnel 4 stage ทั้งชุด save ผลของวัน diff กับเมื่อวาน แล้วเขียน summary สั้น ๆ ชี้ไปที่ cron แล้วลืมได้เลย
import requests
import pandas as pd
from datetime import date
from pathlib import Path
API_TOKEN = "YOUR_API_TOKEN"
BASE_URL = "https://eodhd.com/api/screener"
OUTPUT_DIR = Path("screener_history")
OUTPUT_DIR.mkdir(exist_ok=True)
FILTERS = (
'[["market_capitalization",">",1000000000],'
'["market_capitalization","<",50000000000],'
'["exchange","=","us"],'
'["earnings_share",">",0],'
'["avgvol_1d",">",300000],'
'["adjusted_close",">",5],'
'["dividend_yield",">",0]]'
)
def run_screen():
params = {
"api_token": API_TOKEN,
"filters": FILTERS,
"sort": "market_capitalization.desc",
"limit": 100,
"offset": 0,
}
r = requests.get(BASE_URL, params=params)
r.raise_for_status()
df = pd.DataFrame(r.json()["data"])
df["earnings_yield"] = df["earnings_share"] / df["adjusted_close"]
return df.sort_values("earnings_yield", ascending=False).head(10)
def save_and_diff(today_df):
today_str = date.today().isoformat()
today_path = OUTPUT_DIR / f"{today_str}.csv"
today_df.to_csv(today_path, index=False)
history = sorted(OUTPUT_DIR.glob("*.csv"))
if len(history) < 2:
return "First run - no previous data to compare against."
yesterday_df = pd.read_csv(history[-2])
today_codes = set(today_df["code"])
yesterday_codes = set(yesterday_df["code"])
new_entries = today_codes - yesterday_codes
dropped = yesterday_codes - today_codes
summary = []
if new_entries:
summary.append(f"New in today's top 10: {', '.join(sorted(new_entries))}")
if dropped:
summary.append(f"Dropped out: {', '.join(sorted(dropped))}")
if not new_entries and not dropped:
summary.append("No changes in the top 10 today.")
return "\n".join(summary)
if __name__ == "__main__":
result = run_screen()
summary = save_and_diff(result)
print(summary)
Schedule ด้วย crontab entry บรรทัดเดียวเพื่อรันทุกวันเทรดหลังตลาดปิด:
0 22 * * 1-5 /usr/bin/python3 /path/to/daily_screener.py >> /path/to/screener.log 2>&1
จากตรงนี้ ตัว summary string routing ไปที่ไหนก็ได้ง่าย ๆ:
- Post ไป Slack channel ด้วย webhook:
requests.post(SLACK_WEBHOOK_URL, json={"text": summary}) - Email ให้ตัวเองด้วย pattern เดียวกับ transactional email script อื่น ๆ
- Append CSV ของแต่ละวันเข้า Google Sheet ที่รัน อยู่ เพื่อให้ได้ history ที่ queryable แทนโฟลเดอร์ของไฟล์
ส่วนที่น่าสนใจไม่ใช่ top 10 ในวันเดียว — มันคือการเห็นturnover ชื่อที่เข้าลิสต์มักแปลว่าราคามันตก หรือ earnings ก่อนหน้าเพิ่งดีขึ้นพอที่จะทำ yield น่าดึงดูด ชื่อที่ออกก็ตรงข้าม signal turnover แบบนี้เป็นสิ่งที่ screenshot ครั้งเดียวไม่มีวันให้ได้
Key Takeaways
- Numeric funnel 4 stage เปลี่ยน universe 3,000+ ตัวให้เหลือ 10 ชื่อภายใน code ไม่ถึง 30 บรรทัด
- Earnings yield (EPS ÷ price) คือ ranking metric ที่ตรงไปตรงมาและวัตถุวิสัย — ไม่มี sentiment, ไม่มี narrative, ไม่มี model hallucination
- Filter จะ mechanically กัด expensive growth name ออก และดัน cheap profitable dividend-paying company ขึ้นมาข้ามทั้ง sector และประเทศ นี่คือหัวใจของ rules-based screen — มันไม่รู้ว่าอะไร “ควรจะ” popular
- MCP server ของ EODHD ช่วยข้าม API scripting ในช่วงที่ยัง iterate filter logic อยู่ — data เดียวกัน แต่ interface เป็นบทสนทนา
- Value จริงไม่ใช่ list ของวันเดียว — เป็น cron ที่รัน funnel ทุกวันแล้วบอกว่ามีอะไรเข้าหรือออก top 10 เพราะ turnover คือ actual signal
FAQs
Q: Claude query live financial data ได้จริงหรือ นี่แค่ training data?
A: Claude call EODHD Screener API ตรงสำหรับบทความนี้ ทุกตัวเลขสะท้อน market ณ วันที่ query ไม่ใช่ snapshot จาก training ความต่างนี้สำคัญ — content สาย “AI stock pick” ส่วนใหญ่ใช้ data เก่าที่ memorize ไว้อย่างเงียบ ๆ
Q: Earnings yield reliable แค่ไหนในการหา undervalued stock?
A: เป็น starting filter ที่ useful และ transparent ไม่ใช่ complete valuation model High earnings yield อาจแปลว่ามี value จริง หรืออาจแปลว่า market pricing risk จริง (regulatory, legal, competitive) ที่ตัวเลขจับไม่ได้ ตาม qualitative research ต่อเสมอก่อนตัดสินใจ
Q: ต้อง plan EODHD ตัวไหนถึงรัน screener นี้ได้?
A: Screener API มีให้ใน plan All-In-One และ All World Extended แต่ละ screener request กิน 5 API call — funnel 4 stage นี้จึงกิน 20 call ทั้งหมด ซึ่ง trivial แม้ plan ระดับกลาง
Q: ต่างกันยังไงระหว่าง call EODHD API ตรงกับใช้ MCP server?
A: Data เหมือนกัน quota เหมือนกันทั้งสองทาง Direct API call มี sense เมื่อ build script ที่ทำซ้ำได้ อย่าง daily cron job ข้างบน ส่วน MCP server มี sense เมื่อยัง shape filter logic อยู่ — ปรับได้ด้วยภาษาปกติแล้วเห็นผลทันทีโดยไม่ต้องแตะ code
Q: จะให้ระบบ alert อัตโนมัติแทนต้องมา check screener เองยังไง?
A: รัน funnel ตาม schedule (cron, Task Scheduler หรือ serverless function), save output ของแต่ละวัน diff กับ run ก่อนหน้า แล้ว route diff ไป Slack, email หรือ spreadsheet script ในบทความนี้ทำได้ครบทั้งหมดใน 80 บรรทัด
Market ไม่ได้ reward นักลงทุนที่มี opinion ดีที่สุด แต่ reward คนที่มี process ที่ดีที่สุดในการ filter noise ออก
ที่มา: I Let Claude Screen 3,000 Stocks Using the EODHD API by Kevin Meneses González, DataDrivenInvestor — เผยแพร่ 9 ก.ค. 2026