Oracle3
Open-source trading engine and MCP server for prediction markets. Fee-aware no-arbitrage trading across related contracts, live on Kalshi, Polymarket and Solana or on paper.
แจ้งเตือนราคาหุ้น US แตะแนวรับผ่าน LINE
Translation pending
FinanceTypeScript · PLpgSQLGitHub @thakorntOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Loading the full README. The saved excerpt is shown below.
ระบบแจ้งเตือนราคาหุ้น US แตะ แนวรับ ผ่าน LINE OA — คำนวณแนวรับอัตโนมัติจากราคาย้อนหลัง (ไม่ต้องตั้งเอง) ออกแบบมาสำหรับติดตามพอร์ตส่วนตัว (เช่น AMD, NVDA, PLTR, TSM, AVGO) และรันบน free tier ทั้งหมด สารบัญ 1. สูตรคำนวณแนวรับ 2. กติกาการแจ้งเตือน 3. เหตุผลที่เลือก Data Source / Database 4. Setup ทีละขั้น 5. โครงสร้างโค้ด 6. Environment variables 7. Push ขึ้น GitHub ใช้ข้อมูลแท่งเทียนรายวัน (~260 แท่ง ≈ 1 ปี) เฉพาะ session ที่ปิดแล้ว (แท่งวันนี้ที่ยังไม่จบถูกตัดทิ้ง) แล้วรวบรวมแนวรับ เชิงโครงสร้าง 3 วิธี กรองเฉพาะระดับที่ ต่ำกว่าราคาปิดล่าสุด ก่อนจัดลำดับRead the full README ↗
ระบบแจ้งเตือนราคาหุ้น US แตะ แนวรับ ผ่าน LINE OA — คำนวณแนวรับอัตโนมัติจากราคาย้อนหลัง (ไม่ต้องตั้งเอง) ออกแบบมาสำหรับติดตามพอร์ตส่วนตัว (เช่น AMD, NVDA, PLTR, TSM, AVGO) และรันบน free tier ทั้งหมด
GitHub Actions (cron) ──POST──▶ Vercel (Next.js API) ──▶ Twelve Data (ราคา/OHLC)
│ ▲
▼ │
Postgres (Supabase) LINE Push API ──▶ มือถือคุณ
▲
LINE webhook (follow) ─┘ หน้าเว็บ: จัดการหุ้น / แนวรับ / ประวัติ
ใช้ข้อมูลแท่งเทียนรายวัน (~260 แท่ง ≈ 1 ปี) เฉพาะ session ที่ปิดแล้ว (แท่งวันนี้ที่ยังไม่จบถูกตัดทิ้ง) แล้วรวบรวมแนวรับ เชิงโครงสร้าง 3 วิธี กรองเฉพาะระดับที่ ต่ำกว่าราคาปิดล่าสุด ก่อนจัดลำดับ
| วิธี | สูตร | บทบาท |
|---|---|---|
| Swing Low (โซน) | จุด low ที่ต่ำกว่า low ของ 5 แท่งซ้าย-ขวา (fractal) ภายใน 250 แท่ง แล้วรวมจุดที่ห่างกันไม่เกิน 1.5% เป็นโซนเดียว นับว่าราคาเคยเด้งในโซนนั้นกี่ครั้ง · ระดับ = ขอบบนของโซน (ถ้าราคาอยู่ในโซนแล้ว ใช้ขอบล่าง) | ราคาที่ผู้ซื้อเคยเข้ามาจริง ยิ่งเด้งหลายครั้งยิ่งมีน้ำหนัก |
| Moving Average | SMA 50 และ SMA 200 ของราคาปิด | แนวรับเชิงแนวโน้มระยะกลาง/ยาว — MA200 คือเส้นที่สถาบันดู |
| Fibonacci Retracement | ขาขึ้นล่าสุด: high สูงสุดใน 120 แท่ง และ low ต่ำสุดก่อนหน้า high นั้น → level = High − r·(High−Low), r = 38.2%, 50%, 61.8% | จุดพักตัวมาตรฐานของแนวโน้มขาขึ้น (ข้ามไปถ้า range < 10% หรือไม่มีขาขึ้น) |
เอา Pivot Point รายวันออกแล้ว: Pivot คำนวณจากแท่งเทียนของเมื่อวานแท่งเดียว จึงเปลี่ยนทุกวันและเลื่อนตามราคาลงไปเรื่อย ๆ — ราคาวันนี้ก็คือ "แนวรับ" ของเมื่อวาน ซึ่งแปลว่าไม่มีแนวรับจริง และ backtest พบว่าการแตะ Pivot ไม่ได้ดีกว่าการซื้อวันสุ่ม
| ระดับ | วิธีที่เข้าเกณฑ์ | กติกาเลือก |
|---|---|---|
| แนวรับแรก (Minor) | Swing Low, MA50, Fib 38.2%, Fib 50% | อันที่ ใกล้ราคาปัจจุบันที่สุด |
| แนวรับถัดไป (Intermediate) | Swing Low, Fib 50%, MA50, Fib 38.2% | อันที่สูงสุดที่ยังต่ำกว่า Minor อย่างน้อย 1% |
| แนวรับสำคัญ (Major) | MA200, Fib 61.8% (สำรอง: โซน Swing Low ที่เด้ง ≥2 ครั้ง) | อันที่สูงสุดที่ยังต่ำกว่า Intermediate อย่างน้อย 1% |
ทำไมออกแบบแบบนี้
ทุกวันหลังคำนวณแนวรับ ระบบเล่นวิธีคำนวณปัจจุบันซ้ำกับราคาย้อนหลัง ~5 ปีของหุ้นตัวนั้น ทีละวันโดยไม่แอบดูอนาคต (src/lib/support/track.ts) ทุกครั้งที่ราคาแตะระดับ จะจำราคาระดับนั้นไว้ แล้วดูว่าเกิดอะไรก่อนภายใน 20 วันทำการ:
track.test.ts)โค้ดอยู่ที่ src/lib/support/ (pure functions มี unit test ครบ)
⚠️ แนวรับเป็นเครื่องมือประกอบการตัดสินใจ ไม่ใช่คำแนะนำการลงทุน
แจ้งเตือนเฉพาะ "แนวรับสำคัญ" (ค่าเริ่มต้น) เพื่อลดจำนวนข้อความ (≈ 1 ข้อความต่อเดือน) — backtest ยังไม่พบว่าระดับใดดีกว่าการซื้อวันสุ่มอย่างมีนัยสำคัญ ดูหัวข้อ Backtest — ตั้ง ALERT_TIERS=minor,intermediate,major ถ้าต้องการแจ้งทุกระดับ ระดับอื่นยังแสดงบนหน้าเว็บและในคำสั่ง "ขอแนวรับ" ตามปกติ
State machine แยกตาม (หุ้น, ระดับ) — ดู src/lib/alerts/evaluate.ts
src/lib/alerts/lateCheck.ts) ถ้าราคาแตะหลังรอบเช็กและยังไม่ได้แจ้ง จะส่ง "แตะ … หลังรอบเช็ก" ถ้าราคาปิดต่ำกว่าแนวรับ (หรือต่ำกว่าขอบล่างของโซน) จะส่ง "หลุด …" พร้อมบอกระดับใหม่ที่ใช้แทน แทนที่จะเปลี่ยนเงียบ ๆ ใช้ข้อมูลที่ดึงมาอยู่แล้ว ไม่เปลืองโควตา API เพิ่ม และส่งเฉพาะระดับใน ALERT_TIERSตัวอย่างข้อความ:
🔔 แจ้งเตือนแนวรับหุ้น US
NVDA แตะ "แนวรับสำคัญ"
• ราคาปัจจุบัน: $158.20
• แนวรับ: $158.50 (MA200)
• ห่างจากแนวรับ: -0.19%
ต่ำกว่า 1024px แถบบนมีแค่ไอคอน ชื่อ และปุ่มแฮมเบอร์เกอร์ (เส้นสามเส้นที่หมุนเป็นกากบาทตอนเปิด) กดแล้วเมนูเลื่อนออกมาเป็นลิ้นชักด้านซ้าย: ปิดได้ด้วยแตะพื้นหลัง กด Esc หรือเลือกเมนู (ลิ้นชักปิดเองหลังหน้าใหม่พร้อม ระหว่างรอมีวงกลมหมุนที่รายการที่กด) ตอนเปิดหน้าด้านหลังจะเลื่อนไม่ได้ และ Tab วนอยู่ในเมนู — src/components/Nav.tsx ตั้งแต่ 1024px ขึ้นไปเป็นเมนูแนวนอนเหมือนเดิม
npm run backtest เดินย้อนหลังทีละวัน (5.5 ปี, หุ้นที่ track) ด้วยโค้ดตัวจริงของระบบ แล้วเทียบผลหลังแตะแนวรับกับวันอื่น ๆ ของหุ้นตัวเดียวกัน (ปีเดียวกัน ที่เพิ่งลงใกล้เคียงกัน) — วิธีและข้อจำกัดเต็ม ๆ อยู่ที่ docs/backtest-report.md
set -a; source .env.local; set +a
npm run backtest # ใช้แคชข้อมูลราคาถ้ามี (ครั้งแรกใช้ ~1 credit ต่อหุ้น)
npm run backtest -- --refresh # ดาวน์โหลดราคาใหม่
รันบน GitHub ได้ที่ workflow Deploy steps (ติ๊กเฉพาะ backtest) — รายงานเต็มอยู่ในหน้าสรุปของรอบนั้นและไฟล์แนบ
สรุปจากการรันวันที่ 2026-09-30 (แนวรับเชิงโครงสร้าง, หุ้น 11 ตัว, 2,468 ครั้งที่แตะ, ธ.ค. 2021 – ก.ย. 2026):
ทั้งหมดนี้ไม่ใช่คำแนะนำการลงทุน ผลในอดีตไม่รับประกันอนาคต และมี survivorship bias (หุ้นที่ track คือตัวที่โตมาแล้ว)
กดปุ่มเดียว ระบบส่งหุ้นทุกตัวที่ track ไปให้ AI จัดอันดับ ตัวที่ควรดูต่อสูงสุด 5 ตัว ตามเป้าหมายที่เลือก (เติบโต · ปันผล · ราคาไม่แพง · ความเสี่ยงต่ำ · จังหวะใกล้แนวรับ เลือกได้หลายข้อ ไม่เลือกคือดูภาพรวมสมดุล) — src/lib/jobs/analysis.ts
AI_DAILY_LIMIT (ค่าเริ่มต้น 10) นับเฉพาะครั้งที่ได้ผลลัพธ์ ครั้งที่จบด้วย error ทุกแบบ (key/โมเดลผิด, โควตาหมด, ผู้ให้บริการขัดข้อง, หมดเวลา, อ่านคำตอบไม่ได้) ไม่ถูกนับ — ระบบจองสิทธิ์ไว้ก่อนเรียก (กดพร้อมกันหลายครั้งก็ไม่เกินเพดาน) แล้วคืนให้เมื่อ error · โควตาของผู้ให้บริการเองยังอาจถูกใช้ในบางกรณี (เช่นหมดเวลา) ดูได้ที่หน้า Usage ของผู้ให้บริการAI_MODEL ได้หลายตัวคั่นด้วยจุลภาค เช่น gemini-3.8-flash,gemini-3.5-flash-lite ตัวแรกคือโมเดลหลัก ถ้าใช้ไม่ได้ (โควตารายวันหมด 429, โมเดลถูกยกเลิก 404/400, ตอบว่างเปล่า) ระบบสลับไปตัวถัดไปเอง ถ้าเซิร์ฟเวอร์ขัดข้อง/คนใช้เยอะ (5xx) ลองซ้ำโมเดลเดิม 1 ครั้งหลังรอ 2 วินาทีก่อนสลับ ทั้งหมดใช้งบเวลาเดียวกัน (AI_TIMEOUT_SECONDS) และถ้า key ผิด (401/403) หยุดทันที เพราะทุกโมเดลจะล้มแบบเดียวกัน ผลลัพธ์จะบอกว่าใช้โมเดลไหนและตัวไหนถูกข้ามเพราะอะไร · ถ้ามีมากกว่า 1 โมเดล หน้าเว็บมีช่องเลือกโมเดล (เลือกได้เฉพาะที่อยู่ใน AI_MODEL) · Google แยกโควตาตามโมเดล การมีตัวสำรองจึงช่วยเมื่อตัวหลักหมดโควตาของวันsrc/lib/analysis/factors.ts) ให้ทุกตัว พร้อมอันดับในกลุ่ม (percentile 0–100): ผลตอบแทน 1/3/6/12 เดือน, ความผันผวนจริง, ห่างจุดสูง/ต่ำ 52 สัปดาห์, ลงลึกสุด, P/E, กำไรที่คาดว่าจะโต (P/E ÷ P/E ปีหน้า), รายได้โต, อัตรากำไร, ปันผล, Beta, ขนาดบริษัท, อัพไซด์ถึงราคาเป้า, สัดส่วนแนะนำซื้อ, จำนวนนักวิเคราะห์, ห่างแนวรับแรก, แนวรับดีกว่าระดับสุ่ม, ทิศทางข่าว — คำนวณจากข้อมูลในระบบ (ราคาย้อนหลัง price_history ฯลฯ) ไม่ใช้ API เพิ่มตั้งค่า (Vercel → Settings → Environment Variables, Production แล้ว Redeploy) — ใช้ผู้ให้บริการใดก็ได้ที่รองรับรูปแบบ OpenAI …/chat/completions:
| ตัวแปร | ชนิด | ค่า |
|---|---|---|
AI_API_KEY | Secret | key จากผู้ให้บริการ |
AI_MODEL | Config | ชื่อโมเดล หรือหลายชื่อคั่นด้วยจุลภาค (ตัวแรก = หลัก ที่เหลือ = สำรอง) |
AI_BASE_URL | Config (ไม่บังคับ) | ค่าเริ่มต้น https://openrouter.ai/api/v1 |
ตัวอย่างค่า (ชื่อโมเดล/โควตาฟรีเปลี่ยนบ่อย ตรวจที่หน้าของผู้ให้บริการก่อน):
| ผู้ให้บริการ | AI_BASE_URL | AI_MODEL (ตัวอย่าง) |
|---|---|---|
| OpenRouter (รวมหลายโมเดล มีตัวฟรี) | https://openrouter.ai/api/v1 | ชื่อจากหน้า Models เช่น …:free |
| Google Gemini (AI Studio) | https://generativelanguage.googleapis.com/v1beta/openai | เช่น gemini-3.8-flash, gemini-3.5-flash-lite (รุ่น 2.5 ปิดรับผู้ใช้ใหม่แล้ว) |
| Groq | https://api.groq.com/openai/v1 | โมเดล Llama ที่ Groq เปิดให้ |
| OpenAI | https://api.openai.com/v1 | ตามบัญชี |
ไม่บังคับ: AI_DAILY_LIMIT (ครั้ง/วัน) · AI_TIMEOUT_SECONDS (ค่าเริ่มต้นและสูงสุด 280 = เวลารวมของทุกโมเดลและการลองซ้ำ; ฟังก์ชันนี้ตั้งให้รันได้ 300 วินาทีตามเพดานของ Vercel แบบ Fluid compute โดยเผื่อเวลาดึงราคาและฐานข้อมูล — ตั้งน้อยกว่านี้ได้ถ้าไม่อยากรอนาน) · AI_TEMPERATURE (ส่งไปเฉพาะเมื่อตั้ง บางโมเดลไม่รับค่าอื่นนอกจากค่าเริ่มต้นของมัน)
⚠️ ข้อมูลหุ้นที่ติดตามจะถูกส่งไปผู้ให้บริการ AI — แพ็กเกจฟรีของบางเจ้าอาจนำข้อมูลไปปรับปรุงโมเดลได้ ตรวจเงื่อนไขก่อนใช้ (ข้อมูลนี้ไม่มีความลับ แต่บอกว่าคุณสนใจหุ้นอะไร) · โมเดลฟรีมักช้า ถูกจำกัดบ่อย และทำตามรูปแบบ JSON ไม่เสถียร ถ้าเจอ "อ่านคำตอบของ AI ไม่ได้" บ่อย ให้ลองโมเดลอื่น
src/components/PriceChart.tsx): ราคาปิดรายวัน (5Y เป็นรายสัปดาห์) + เส้นประแนวรับปัจจุบันตามสีระดับ + จุดที่ราคาเคยแตะแนวรับจาก backtest (จุดเขียว = รับได้, วงแดง = หลุด) · ช่วง 3M · 6M (เริ่มต้น) · 1Y · 5Y ผู้เยี่ยมชมเลือกช่วงได้ (เป็นการดูอย่างเดียว) · ช่วงยาวแสดงเฉพาะจุดของระดับที่สำคัญกว่า (1Y: แนวรับถัดไป+สำคัญ, 5Y: แนวรับสำคัญ) ไม่ให้จุดของแนวรับแรกที่แตะบ่อยบังหมด · วาดด้วย SVG เอง (ไม่มี library) ตามความกว้างจริงของการ์ด ตัวเลขจึงอ่านได้ทุกขนาดจอ · โหลดเมื่อกางรายละเอียดเท่านั้นsrc/components/AnalystPanel.tsx): แถบสีซื้อ/ถือ/ขาย (Finnhub ฟรี ทุก 3 วัน) และแถบช่วงราคาเป้าหมาย 12 เดือน ต่ำสุด–เฉลี่ย–สูงสุด พร้อมจุดราคาตอนนี้และขีดแนวรับในแถบเดียว (เห็นทั้งระยะลงถึงแนวรับและระยะขึ้นถึงเป้า) · ราคาเป้าหมายดึงจาก Nasdaq (api.nasdaq.com ไม่เป็นทางการ ฟรี ไม่ต้องมี key) เพราะ Finnhub แผนฟรีไม่ให้ · ถ้า Nasdaq ล้ม ค่าเดิมยังอยู่ แต่จะไม่แสดงเมื่อเก่ากว่า 14 วัน · ETF ไม่มีราคาเป้า · ไม่มีป้าย "แนะนำซื้อ" และมีคำเตือนว่าเป็นความเห็นที่มักมองบวกเกินจริงprice_history (ราคาปิดย้อนหลังประมาณ 5 ปี) บันทึกโดยงานคำนวณแนวรับรายวันจากราคาที่ดึงอยู่แล้ว ไม่ใช้เครดิต API เพิ่ม · API สาธารณะ GET /api/history/<SYMBOL>?range=6m (src/lib/chart/series.ts เลือกช่วง ย่อรายสัปดาห์ เลือกจุด) · เติมย้อนหลังทันทีโดยไม่รอรอบรายวัน: set -a; source .env.local; set +a; npm run backfill:prices (1 เครดิต Twelve Data ต่อหุ้น ไม่คำนวณแนวรับใหม่ ไม่ส่ง LINE)src/proxy.ts ให้ทุกคนใช้ได้แค่ GET/HEAD คำขอที่แก้ข้อมูล (POST/PUT/PATCH/DELETE) ต้องมีเซสชันเจ้าของ ไม่มีจะได้ 401 · ปุ่มรีเฟรชราคา (/api/prices?force=1) ข้าม cache ได้เฉพาะเจ้าของ ผู้เยี่ยมชมใช้ cache ร่วม 5 นาที จึงไม่ทำให้เรียก API ราคาถี่ขึ้น · หน้าแต่ละหน้าเช็กสิทธิ์ด้วย src/lib/viewer.tssrc/lib/recipients.ts): สำหรับผู้เยี่ยมชม server ตัด LINE user id (แสดง U••••••••) ชื่อจาก LINE และชื่อเรียกออกก่อนส่งไปเบราว์เซอร์ จึงไม่อยู่ใน HTML ด้วย แสดงเป็น "ผู้รับ #1" พร้อม "✓ ดึงชื่อและรูปโปรไฟล์จาก LINE แล้ว" เป็นหลักฐานว่าดึงข้อมูลได้จริง · รูปโปรไฟล์แสดงเฉพาะคนที่เจ้าของเปิดสวิตช์ "แสดงรูปบนหน้าสาธารณะ" ในหน้าผู้รับ (ตั้งใจไว้สำหรับบัญชีของเจ้าของเอง ค่าเริ่มต้นปิดทุกคน) คนอื่นเป็นไอคอนเงาให้ Google ค้นเจอ (SEO)
src/app/robots.ts → /robots.txt อนุญาตทุกหน้า ยกเว้น /api/ และ /login และชี้ไปที่ sitemapsrc/app/sitemap.ts → /sitemap.xml รายการหน้าสาธารณะทั้ง 6 หน้า (จาก PUBLIC_PAGES ใน src/lib/site.ts)src/app/layout.tsx → title/description, Open Graph (ตัวอย่างลิงก์เวลาแชร์), canonical URL · แต่ละหน้ามี metadata ของตัวเอง (ชื่อหน้า + คำอธิบาย) · หน้า login ตั้ง noindexSITE_URL ถ้าตั้ง (เช่นเมื่อมีโดเมนของตัวเอง) ไม่อย่างนั้นใช้ VERCEL_PROJECT_PRODUCTION_URL ที่ Vercel ให้มาเองhttps://stock-support-alert.vercel.app → ยืนยันด้วย HTML tag (คัดลอกค่า content มาใส่ verification: { google: "…" } ใน metadata ของ src/app/layout.tsx แล้ว deploy) → เมนู Sitemaps ใส่ sitemap.xml → Submitระบบเก็บข่าวฟรีทุกชั่วโมง แล้วให้ AI สรุปทุกวันทำการก่อนตลาดเปิด ว่าข่าวกระทบตลาดและหุ้นที่ track แต่ละตัวอย่างไร (หรือกด "สรุปข่าวตอนนี้" เองได้) — src/lib/jobs/news.ts
company-news ของหุ้นทุกตัว และ news?category=general (ข่าวตลาด ส่วนใหญ่เป็นพาดหัว Reuters) ใช้ FINNHUB_API_KEY ตัวเดิม ประมาณ 21 ครั้งต่อรอบ เว้นช่วง 1.2 วินาทีเพื่อไม่ชนเพดาน 60 ครั้ง/นาทีที่ใช้ร่วมกับราคาสดNEWS_PER_STOCK ข่าวต่อหุ้น (ค่าเริ่มต้น 6) + ข่าวตลาด 15 ข่าว · เนื้อหารวมไม่เกิน NEWS_PROMPT_MAX_CHARS ตัวอักษร (ค่าเริ่มต้น 160,000 ≈ 40k token)AI_API_KEY, AI_MODEL, สลับโมเดลสำรองเหมือนกัน) จำกัด NEWS_DAILY_LIMIT ครั้งต่อวัน (ค่าเริ่มต้น 3 รวมรอบอัตโนมัติ นับเฉพาะครั้งที่สำเร็จ) · prompt ใหญ่ (หลายหมื่น token) เหมาะกับ Gemini/OpenRouter ถ้าใช้ Groq แบบฟรีให้ลด NEWS_PROMPT_MAX_CHARSnews_articles (เนื้อข่าวเต็มเก็บแค่ 7 วันเพื่อใช้สรุป แถวทั้งหมดลบเมื่อครบ 30 วัน) และ news_briefs (สรุปที่ได้ เก็บเฉพาะพาดหัว แหล่ง และลิงก์ ไม่เก็บเนื้อข่าว)ทุกตัวเลขมีคำอธิบายภาษาคนต่อท้ายว่าหมายความว่าอะไร — src/lib/profile/describe.ts (เกณฑ์เป็นค่าประมาณทั่วไป ระบบไม่เขียนว่า "ควรซื้อ" หรือ "ราคาถูก")
| ข้อมูล | แปลว่า | ที่มา |
|---|---|---|
| P/E (และปีหน้า) | จ่ายกี่ดอลลาร์ต่อกำไร $1 ต่อปี เทียบช่วงทั่วไปของตลาดสหรัฐ (~15–25) และนักวิเคราะห์คาดว่ากำไรจะเพิ่ม/ลด | Finnhub |
| รายได้เทียบปีก่อน | ธุรกิจหด / โตช้า / ปานกลาง / เร็ว / เร็วมาก | Finnhub |
| อัตรากำไรสุทธิ | ขายได้ $100 เหลือกำไรเท่าไร | Finnhub |
| ผลตอบแทนปันผล | ถือหุ้นมูลค่า $100 ได้ปันผลกี่ดอลลาร์ต่อปี (ไม่แสดงถ้าไม่มีตัวเลข = ไม่จ่ายหรือไม่ทราบ) | Finnhub |
| Beta | ถ้าตลาดลง 10% หุ้นนี้ลงโดยเฉลี่ยกี่ % | Finnhub |
| เทียบจุดสูงสุด 52 สัปดาห์ | ราคาอยู่ตรงไหนของรอบปี (ใช้ราคาบนการ์ด) | ราคาย้อนหลัง |
| ลงลึกสุดในอดีต | ช่วง ~5 ปี เคยร่วงจากจุดสูงสุดกี่ % เมื่อไหร่ ถ้าซื้อที่จุดสูงสุดเงิน $100 จะเหลือเท่าไร และกลับมาได้หรือยัง | ราคาย้อนหลัง |
| ประกาศงบครั้งถัดไป | อีกกี่วัน (ภายใน 7 วันจะเตือนสีเหลือง เพราะราคามักแกว่งแรง) | Finnhub |
| คำแนะนำนักวิเคราะห์ | กี่คนแนะนำ ซื้อ/ถือ/ขาย (เดือนล่าสุด) — บอกด้วยว่าคำแนะนำ "ซื้อ" เป็นเรื่องปกติของโบรกเกอร์ จึงไม่ใช่สัญญาณแรง; เตือนเมื่อมีคนแนะนำขายมากผิดปกติ | Finnhub (ฟรี) |
| ราคาเป้าหมายนักวิเคราะห์ | ค่าเฉลี่ยเป้า 12 เดือน (ต่ำสุด–สูงสุด) เทียบราคาตอนนี้ — ราคาเป้าหมายมักมองบวกเกินจริง | Finnhub (อาจต้องแพ็กเกจจ่ายเงิน ถ้าไม่ได้จะไม่แสดง) |
stock_profiles หน้าเว็บอ่านจากฐานข้อมูลอย่างเดียว; หุ้นที่เพิ่มใหม่ได้ข้อมูลทันทีตอนเพิ่มset -a; source .env.local; set +a; npm run refresh:profilesดึง ครั้งเดียวตอนเพิ่มหุ้น แล้วเก็บ ตัวไฟล์รูปไว้ในฐานข้อมูลของเรา (คอลัมน์ symbols.logo_*) หน้าเว็บแสดงผ่าน /api/logo/<symbol> ของเราเอง จึงไม่ต่อเว็บอื่นตอนใช้งาน (ทั้งหน้าแนวรับและหน้าจัดการหุ้น) และไม่ขึ้นกับว่า Finnhub ตอบหรือไม่
FINNHUB_API_KEY) → Twelve Data (STOCK_API_KEY) → ถ้าไม่มีเลยแสดงตัวอักษรย่อของ tickerset -a; source .env.local; set +a
npm run seed:logos # เติมตัวที่ยังไม่มี (ข้ามตัวที่ลองไปไม่เกิน 7 วัน)
npm run seed:logos -- --retry # ลองตัวที่ยังไม่มีอีกครั้งทันที
src/lib/stock/logo.ts, src/lib/jobs/logos.tsMAX_PUSH_RECIPIENTS คน (ค่าเริ่มต้น 5) เพราะโควตาของ LINE นับ "ต่อผู้รับ" — ระบบตรวจเพดานฝั่งเซิร์ฟเวอร์ ไม่ให้เกินแม้กดพร้อมกันขอแนวรับ ถามได้ ซึ่งตอบด้วย reply message ที่ไม่นับโควตา pushLINE_ALLOWED_USER_IDS ที่เคยใช้ เลิกใช้แล้ว (ลบออกจาก Vercel ได้ ปล่อยไว้ก็ไม่มีผล)ตอนมีคนแอด OA ระบบส่งข้อความต้อนรับที่บอกวิธีใช้ทันที (พร้อมตัวอย่างจากหุ้นที่ติดตามอยู่จริง) และพิมพ์ วิธีใช้ (หรือ help, ช่วยเหลือ, เมนู) เพื่อขอดูอีกครั้งได้ทุกเมื่อ — src/lib/line/guide.ts
แนะนำให้ปิด Greeting message เริ่มต้นของ LINE ใน OA Manager (Settings → Response settings) ไม่ให้ซ้ำกับของระบบ
หน้า แนวรับปัจจุบัน ดึงราคาสดมาแสดงเมื่อเปิดหน้า และมีปุ่ม "รีเฟรชราคา" — ใช้ Finnhub (ตั้ง FINNHUB_API_KEY) → ถ้าไม่ได้ตั้ง key หรือดึงไม่ได้จะลอง Yahoo (ไม่เป็นทางการ อาจถูกบล็อก) → ถ้ายังไม่ได้จะใช้ราคาที่เก็บไว้ตอนรอบเช็ค Twelve Data
live_quotes) 5 นาที ใช้ร่วมกันทุกคนและทุกเซิร์ฟเวอร์ — โหลดหน้ารัว ๆ หรือหลายคนใช้พร้อมกัน ก็ยิง Finnhub/Yahoo ไม่เกิน 1 ครั้งต่อหุ้นต่อ 5 นาที (หุ้น 20 ตัว ≈ 4 ครั้ง/นาที เทียบเพดานฟรี 60 ครั้ง/นาที) ปรับได้ด้วย LIVE_PRICE_TTL_SECONDSLIVE_PRICE_MIN_REFRESH_SECONDS) และคำขอที่ซ้อนกันในเซิร์ฟเวอร์เดียวกันใช้การดึงเดียวกันLIVE_PRICE_DEADLINE_MS) ตัวที่ไม่ทันจะใช้ราคาเก่าล่าสุดของ live (ติดป้าย "ค่าเก่า") แล้วค่อยใช้ราคาจากรอบเช็ก Twelve Datasrc/lib/stock/live.ts, src/lib/jobs/livePrices.ts, /api/pricesSMOKE_USERNAME=<ชื่อผู้ใช้> SMOKE_PASSWORD=<รหัส> npm run smoke -- https://<โดเมน-vercel>
ทดสอบโหลดทุกหน้า/API พร้อมกัน 18 คำขอ × 3 รอบ (แบบเดียวกับที่เบราว์เซอร์โหลดเมนูล่วงหน้า) — เป็นการอ่านอย่างเดียวพิมพ์หา OA ได้เลย (ตอบด้วย reply message ฟรี ไม่กินโควตา push และอ่านจากข้อมูลที่ cache ไว้ ไม่เรียก Stock API):
ขอแนวรับ → แนวรับของ ทุกตัวที่ track ในหน้าเว็บขอแนวรับ NVDA, ขอแนวรับของ NVDA หรือ ขอแนวรับ nvda amd → เฉพาะตัวที่ระบุ (ตัวที่ไม่ได้ track จะแจ้งว่าไม่พบ)เพื่อนทุกคนสั่งได้ — src/lib/line/supportCommand.ts
หน้า แนวรับปัจจุบัน: กดค้างที่ปุ่มจุด 6 จุดมุมการ์ดแล้วลากเพื่อจัดลำดับ (ใช้ได้ทั้งเมาส์ ทัชสกรีน และคีย์บอร์ด: Space หยิบ → ลูกศรย้าย → Space วาง)
ลำดับถูกบันทึกในคอลัมน์ symbols.position และใช้ร่วมกันทั้งเว็บและคำตอบ ขอแนวรับ ใน LINE หุ้นที่เพิ่มใหม่จะต่อท้ายสุด ถ้ายังไม่เคยจัดลำดับจะเรียง A→Z
ส่วนหน้า ประวัติแจ้งเตือน เรียงตามเวลาล่าสุดก่อน
เพื่อประหยัดโควตา workflow เรียก /api/cron/check?mode=daily วันละ 2 รอบ: 10:30 น. นิวยอร์ก (1 ชม. หลังเปิด = 21:30 น. ไทยช่วง EDT / 22:30 น. ช่วง EST) และ 13:30 น. นิวยอร์ก (00:30 / 01:30 น. ไทย) รอบแรกให้ทันดูก่อนนอนและจับช่วงเปิดตลาดที่แกว่งแรงที่สุด ระดับที่แจ้งไปแล้วจะไม่แจ้งซ้ำในรอบที่สองจนกว่าราคาจะเด้งขึ้นก่อน
เหลือเวลาตัดสินใจซื้อทัน โหมดนี้ต่างจากโหมดถี่ตรงที่ นับ "ราคาต่ำสุดของวัน" เป็นการแตะด้วย (ไม่งั้นถ้าแตะตอนเช้าแล้วเด้งกลับจะพลาด) และข้อความแจ้งเตือนจะมีบรรทัด "ต่ำสุดวันนี้"
job_runs (แยกต่อรอบ) cron อีกตัวของรอบเดียวกัน (ที่ตั้งไว้เผื่อ EDT/EST) จึงข้ามเอง (ถ้าดึงราคาไม่ครบ จะไม่บันทึก และลองใหม่ได้ โดยไม่ส่งแจ้งเตือนซ้ำ)*/30 13-20 * * 1-5 + 0 21 * * 1-5 และเรียก /api/cron/check (ไม่ใส่ mode) — endpoint รองรับทั้งสองโหมดGitHub cron เป็น UTC และไม่รู้จัก DST จึงตั้งให้ครอบคลุมทั้งเวลา EDT/EST แล้วให้ endpoint ตัดสินเองด้วย
America/New_York ผ่าน Intl (ไม่ hardcode offset) รวมวันหยุด NYSE (Good Friday, Juneteenth ฯลฯ) และวัน early close 13:00
— src/lib/market/calendar.ts
| ตัวเลือก | ราคา real-time | OHLC ย้อนหลัง | ข้อสรุป |
|---|---|---|---|
| Twelve Data | ✅ /quote | ✅ /time_series 1day ได้ถึง 5,000 แท่ง | เลือก — ฟรี 800 credit/วัน, 8/นาที, batch หลาย symbol ในคำขอเดียว, ใช้ API key |
| Finnhub | ✅ ฟรี | ❌ candle ย้อนหลังเป็น premium | ใช้คำนวณแนวรับไม่ได้ |
| Alpha Vantage | ✅ | ⚠️ ฟรีแค่ 25 คำขอ/วัน และ full history เป็น premium | ไม่พอสำหรับ MA200 + เช็คทุก 30 นาที |
| Yahoo (unofficial) | ✅ | ✅ | ไม่มี SLA, มักบล็อก IP ของ Vercel/GitHub, ไม่มี key |
ออกแบบให้ประหยัด rate limit
/quote 1 คำขอ (5 credits) ต่อรอบ — โหมดวันละครั้ง ≈ 5 credits/วัน (โหมดทุก 30 นาที ≈ 70/วัน) จาก 800quotes (TTL 5 นาที) — รันซ้ำ/กดเรียกมือไม่ยิง API ซ้ำsupport_levels และคำนวณใหม่วันละครั้ง (ข้ามถ้าข้อมูลของ session ล่าสุดมีอยู่แล้ว)MAX_TRACKED_SYMBOLS, ค่าเริ่มต้น 20) ภายใต้ limit 8 credits/นาที โดยแต่ละงานดึงครั้งละไม่เกิน 8 ตัว (API_CREDITS_PER_MINUTE)
แล้ว workflow วนเรียกซ้ำโดยเว้น 61 วินาที จนครบ — 20 ตัว = 3 ชุด ใช้เวลาเพิ่มราว 2 นาทีต่อรอบ (ทำเป็นหลายการเรียกสั้น ๆ เพื่อไม่ชนเพดาน 60 วินาทีของ Vercel ฟรี)
/api/cron/quotes อุ่น cache ทีละชุด แล้ว /api/cron/check อ่านจาก cache ทั้งหมด (ไม่เรียก API)/api/cron/recalculate ทำทีละชุดและตอบ remaining กลับมาStockDataProvider (src/lib/stock/types.ts)เช็ค limit ล่าสุดของ free plan ที่ https://twelvedata.com/pricing
เป็น Postgres ธรรมดา ใช้ผ่าน DATABASE_URL เดียว (ไม่ผูก SDK) ย้ายไป Neon / Vercel Postgres ได้โดยเปลี่ยนแค่ connection string
ตาราง: symbols, support_levels, quotes, alert_state, alert_history, line_users — src/lib/db/schema.sql
git clone https://github.com/extratha/stock-support-alert.git
cd stock-support-alert
npm install
cp .env.example .env.local
สมัครฟรีที่ https://twelvedata.com → Dashboard → API Keys → ใส่ใน STOCK_API_KEY
DATABASE_URL
(ถ้ามี ?sslmode=require ก็ใส่ต่อท้าย)npm run db:migrate # อ่าน DATABASE_URL จาก environment
หรือ set -a; source .env.local; set +a; npm run db:migrate
หลังจากนั้น Vercel รัน migrate ให้เองทุกครั้งที่ deploy production (script vercel-build = db:migrate แล้ว next build) ใช้ DATABASE_URL จาก env ของ Vercel — schema เป็นแบบรันซ้ำได้ (เพิ่มเฉพาะที่ยังไม่มี) ถ้าต่อฐานข้อมูลไม่ได้ build จะล้มและเวอร์ชันเดิมยังออนไลน์อยู่ · preview deployment ไม่แตะฐานข้อมูล
เมื่อวิธีคำนวณแนวรับเปลี่ยน (SUPPORT_LOGIC_VERSION) รอบคำนวณถัดไปจะคำนวณใหม่ทุกตัวเอง ไม่ต้องรอวันทำการใหม่LINE_CHANNEL_SECRETLINE_CHANNEL_ACCESS_TOKENhttps://<โดเมน-vercel-ของคุณ>/api/line/webhook → Verify → เปิด Use webhook
(ทำหลัง deploy ข้อ 5)userId ของคุณอัตโนมัติ (event follow)⚠️ โควตา push: แผน Free ของ LINE OA ส่งได้จำกัด (ประมาณ 200 ข้อความ/เดือน ดูแผนล่าสุดในประเทศคุณ) ระบบจึงรวมหลายแจ้งเตือนในรอบเดียวเป็นข้อความเดียว
openssl rand -hex 32 # รันสองครั้ง: ผลแรกเป็น CRON_SECRET ผลที่สองเป็น SESSION_SECRET
ADMIN_USERNAME (ไม่ตั้ง = admin) และ ADMIN_PASSWORD (รหัสผ่านที่ยาวพอ) ใช้เข้าหน้าเว็บผ่านหน้า loginSESSION_SECRET ใช้เซ็น cookie เซสชัน (ยาวอย่างน้อย 16 ตัวอักษร) — ถ้าไม่ตั้งบน production เว็บจะตอบ 503 (ไม่เปิดโล่ง)การ login: เซสชันเป็น cookie ที่เซ็นลายเซ็น (HttpOnly, Secure, SameSite=Lax) อายุ 7 วัน ไม่เก็บอะไรใน DB กดปุ่ม "ออกจากระบบ" เพื่อล้าง cookie
เปลี่ยน ADMIN_USERNAME / ADMIN_PASSWORD / SESSION_SECRET อย่างใดอย่างหนึ่งแล้ว Redeploy = ทุกเครื่องถูกบังคับ login ใหม่
ข้อจำกัด: ไม่มีระบบล็อกเมื่อเดารหัสผิดหลายครั้ง (มีแค่หน่วง 0.5 วินาทีต่อครั้งที่ผิด) จึงควรตั้งรหัสให้ยาวและเดายาก
/api/cron/* (bearer CRON_SECRET) และ /api/line/webhook (ลายเซ็น LINE) ไม่ผ่านหน้า login
extratha/stock-support-alerthttps://stock-support-alert.vercel.appAMD, NVDA, PLTR, TSM, AVGO (ระบบคำนวณแนวรับให้ทันที และใช้ตรวจว่า symbol ถูกต้อง) → กด ส่งข้อความทดสอบทำไมไม่ใช้ GitHub Actions อย่างเดียว: งานตามเวลาของ GitHub เริ่มช้ากว่ากำหนด 5–7 ชั่วโมงเป็นประจำ (วัดจริงช่วง 30 ก.ย.–5 ต.ค. 2026: รอบเช็กระหว่างวันเกือบทุกรอบไปเริ่มหลังตลาดปิดแล้ว) จึงใช้ cron-job.org (ฟรี ตรงเวลาระดับนาที เลือก timezone ได้) เป็นตัวหลัก และเก็บ workflow ของ GitHub ไว้เป็นสำรอง — ส่งซ้ำไม่ได้ เพราะแต่ละรอบบันทึกไว้ใน job_runs และแจ้งเตือนถูก claim ไว้
endpoint ทำงานทั้งหมดในการเรียกครั้งเดียว (ดึงราคา/คำนวณทีละชุด 8 ตัว ห่างกัน 1 นาทีเอง) และ ?async=1 ตอบ 202 ทันทีแล้วทำงานต่อเบื้องหลัง (cron-job.org รอคำตอบได้ไม่นาน) ผลลัพธ์ดูได้ที่ Vercel → Logs
สมัคร cron-job.org แล้วสร้าง 3 งาน (Create cronjob) ทุกงานตั้ง:
POST · Headers: Authorization = Bearer <ค่า CRON_SECRET> (แท็บ Advanced)America/New_York (DST จัดการให้เอง ไม่ต้องมีรอบเผื่อ) · วัน: จันทร์–ศุกร์ (วันหยุดตลาด endpoint ข้ามเอง)| งาน | URL | เวลา (นิวยอร์ก) |
|---|---|---|
| เช็กรอบเช้า | https://<APP_URL>/api/cron/check?mode=daily&async=1 | 10:31 (= 21:31 / 22:31 น. ไทย) |
| เช็กรอบบ่าย | https://<APP_URL>/api/cron/check?mode=daily&async=1 | 13:31 (= 00:31 / 01:31 น. ไทย) |
| คำนวณแนวรับ + สรุปหลังปิด | https://<APP_URL>/api/cron/recalculate?async=1 | 18:05 |
| เก็บข่าว | https://<APP_URL>/api/cron/news?async=1 | ทุกชั่วโมง นาทีที่ 15 (ทุกวัน รวมเสาร์–อาทิตย์ เพื่อเก็บข่าวสุดสัปดาห์) |
| สรุปข่าวก่อนตลาดเปิด | https://<APP_URL>/api/cron/news?mode=brief&async=1 | 08:30 (= 19:30 / 20:30 น. ไทย) จันทร์–ศุกร์ |
ทดสอบ: กด "Test run" ในงานแรก ควรได้ 202 {"accepted":true} (ถ้าได้ 401 แปลว่า header ผิด) แล้วดูใน Vercel → Logs ว่ามีบรรทัด check (async)
ที่ repo → Settings → Secrets and variables → Actions → New repository secret
| Secret | ค่า |
|---|---|
APP_URL | https://stock-support-alert.vercel.app (ไม่ต้องมี / ท้าย) |
CRON_SECRET | ค่าเดียวกับที่ตั้งใน Vercel |
หรือใช้ CLI:
gh secret set APP_URL --repo extratha/stock-support-alert
gh secret set CRON_SECRET --repo extratha/stock-support-alert
| Workflow | เวลา (UTC) | ทำอะไร |
|---|---|---|
check-alerts.yml | 14:30, 15:30, 17:30, 18:30 จันทร์–ศุกร์ (= 10:30 และ 13:30 น. นิวยอร์ก ทั้งช่วง EDT/EST) | เช็คราคา วันละ 2 รอบ เทียบแนวรับ (รวมราคาต่ำสุดของวัน) ส่ง LINE — แต่ละรอบทำงานครั้งเดียว อีกตัวข้ามเอง |
recalculate-supports.yml | 22:00 จันทร์–ศุกร์ | คำนวณแนวรับใหม่หลังตลาดปิด |
maintenance.yml | กดรันเอง | ขั้นตอนหลังอัปเดต: (1) db:migrate (2) คำนวณแนวรับใหม่ทุกตัวทันที (3) backtest แล้วแนบรายงานไว้กับรอบนั้น — ต้องมี secret DATABASE_URL และ STOCK_API_KEY เพิ่มจาก APP_URL/CRON_SECRET |
ทดสอบมือ: แท็บ Actions → เลือก workflow → Run workflow (ติ๊กช่อง "Ignore the market-hours / time-window check" เพื่อข้ามการเช็คเวลาตลาด — ช่องนี้ข้ามแค่เรื่องเวลา ไม่ได้บังคับให้ส่งแจ้งเตือน)
หมายเหตุ GitHub: cron อาจล่าช้าได้หลายนาทีช่วงคนใช้เยอะ · และ workflow ตามเวลาจะถูกปิดอัตโนมัติถ้า repo ไม่มี activity 60 วัน (เข้าไปกด enable ใหม่ได้)
npm run dev # http://localhost:3000 (ไม่มี ADMIN_PASSWORD = ไม่ต้อง login ใน dev)
npm test # unit tests
npm run typecheck && npm run lint
# เรียก job มือ:
curl -X POST -H "Authorization: Bearer $CRON_SECRET" "http://localhost:3000/api/cron/recalculate?force=1"
curl -X POST -H "Authorization: Bearer $CRON_SECRET" "http://localhost:3000/api/cron/check?force=1"
ทดสอบ webhook ตอน dev ด้วย tunnel เช่น cloudflared tunnel --url http://localhost:3000
src/
lib/
support/ คำนวณแนวรับ (pure, มี test) movingAverage · swing (โซน) · fibonacci · calculate (จัดระดับ) · track (รับได้/หลุด ย้อนหลัง)
market/ ปฏิทิน NYSE + timezone/DST
alerts/ evaluate (state machine) · format (ข้อความ LINE)
ai/ ตัวเรียก AI (OpenAI-compatible, ไม่ retry)
analysis/ เป้าหมาย · prompt · ตรวจคำตอบ AI (หน้า "วิเคราะห์ด้วย AI")
viewer.ts เจ้าของหรือผู้เยี่ยมชม · recipients.ts ปิดข้อมูลผู้รับสำหรับผู้เยี่ยมชม · site.ts ที่อยู่เว็บ/หน้าสาธารณะ
news/ ข่าว Finnhub · อ่านเนื้อข่าว (Readability) · จับคู่ข่าวกับหุ้น · prompt · ตรวจคำตอบ AI (หน้า "ข่าว")
stock/ StockDataProvider interface + Twelve Data adapter
line/ signature verify · push/reply client
db/ postgres client · schema.sql · repositories
jobs/ recalculateSupports · checkAlerts · quotes cache · notify ← orchestration
auth.ts cron bearer / admin basic auth
app/
page.tsx, symbols/, history/ หน้าเว็บ
api/cron/* endpoint สำหรับ GitHub Actions
api/line/webhook รับ follow/unfollow
api/symbols เพิ่ม/ลบหุ้น
proxy.ts อ่านได้ทุกคน (GET) · แก้ข้อมูลต้องมีเซสชันเจ้าของ (cookie)
.github/workflows/ cron + CI
scripts/migrate.ts สร้างตาราง
ชั้น support/, market/, alerts/ ไม่แตะ DB/network เลย จึงเทสต์ง่ายและเปลี่ยนกติกาได้โดยไม่กระทบส่วนอื่น
| ตัวแปร | จำเป็น | คำอธิบาย |
|---|---|---|
LINE_CHANNEL_SECRET | ✅ | verify signature ของ webhook |
LINE_CHANNEL_ACCESS_TOKEN | ✅ | ส่ง push/reply |
STOCK_API_KEY | ✅ | Twelve Data API key |
DATABASE_URL | ✅ | Postgres connection string |
ADMIN_USERNAME | – | ชื่อผู้ใช้หน้าเว็บ ค่าเริ่มต้น admin |
ADMIN_PASSWORD | ✅ (production) | รหัสผ่านเจ้าของ (ผู้เยี่ยมชมดูได้โดยไม่ต้องมี) — ถ้าไม่ตั้งใน production เว็บจะตอบ 503 |
SITE_URL | – | ที่อยู่เว็บสำหรับ sitemap/ลิงก์แชร์ ตั้งเฉพาะเมื่อใช้โดเมนของตัวเอง (ไม่ตั้ง = ใช้ที่อยู่ production ของ Vercel) |
SESSION_SECRET | ✅ (production) | คีย์เซ็น cookie login (อย่างน้อย 16 ตัวอักษร) — ถ้าไม่ตั้งใน production เว็บจะตอบ 503 |
CRON_SECRET | ✅ | bearer token ของ /api/cron/* — ถ้าไม่ตั้งจะปฏิเสธทุกคำขอ |
MAX_PUSH_RECIPIENTS | – | จำนวนเพื่อนสูงสุดที่รับ push ค่าเริ่มต้น 5 (ดูหัวข้อ "ผู้รับแจ้งเตือน") |
ALERT_TIERS | – | ระดับที่ส่งแจ้งเตือน LINE ค่าเริ่มต้น major (แนวรับสำคัญ) · minor,intermediate,major = ทุกระดับ |
AI_API_KEY, AI_MODEL | – | แท็บ "วิเคราะห์ด้วย AI" (ดูหัวข้อ "วิเคราะห์ด้วย AI") — ถ้าไม่ตั้ง หน้านั้นบอกว่ายังไม่ได้ตั้งค่า ส่วนอื่นของระบบไม่กระทบ |
AI_BASE_URL, AI_DAILY_LIMIT, AI_TIMEOUT_SECONDS, AI_TEMPERATURE | – | ไม่บังคับ ดูหัวข้อ "วิเคราะห์ด้วย AI" |
NEWS_DAILY_LIMIT, NEWS_PER_STOCK, NEWS_PROMPT_MAX_CHARS | – | แท็บ "ข่าว": สรุปได้กี่ครั้ง/วัน (3) · ข่าวต่อหุ้น (6) · ขนาดเนื้อหาที่ส่งให้ AI (160000 ตัวอักษร) |
FINNHUB_API_KEY | – | key ฟรีจาก finnhub.io สำหรับราคาสดบนหน้าเว็บ (ไม่ตั้ง = ใช้ Yahoo แล้วราคาจากรอบเช็ก) |
Repo นี้ตั้ง origin = https://github.com/extratha/stock-support-alert.git ไว้แล้ว
# 1) login (ครั้งแรก) — ต้องเป็นบัญชีที่มีสิทธิ์เขียน repo ของ extratha
gh auth login # เลือก GitHub.com → HTTPS → Login with a web browser
gh auth status # ตรวจว่า active account ถูกต้อง
# 2) สร้าง public repo (ข้ามถ้ามีอยู่แล้ว)
gh repo create extratha/stock-support-alert --public --source=. --remote=origin --description "US stock support-level alerts via LINE"
# 3) push
git push -u origin main
ถ้า gh login เป็นบัญชีอื่น (ไม่ใช่ extratha) จะสร้าง/push ไม่ได้ ให้ gh auth login ใหม่ด้วยบัญชี extratha
หรือเพิ่มบัญชีนั้นเป็น collaborator ของ repo ก่อน
ai_analyses เปิดหน้าใหม่ก็ยังเห็นset -a; source .env.local; set +a; npm run news (เก็บข่าว) · npm run news -- brief (เก็บข่าว + สรุป ใช้ AI 1 ครั้ง)LIVE_PRICE_TTL_SECONDS / LIVE_PRICE_MIN_REFRESH_SECONDS / LIVE_PRICE_DEADLINE_MS | – | แคชราคาสด (300 วินาที) / ระยะห่างขั้นต่ำของปุ่มรีเฟรช (30 วินาที) / เพดานเวลาต่อคำขอ (12000 มิลลิวินาที) |
MAX_TRACKED_SYMBOLS | – | ค่าเริ่มต้น 20 |
API_CREDITS_PER_MINUTE | – | จำนวนหุ้นต่อการเรียก API หนึ่งครั้ง ค่าเริ่มต้น 8 (ตาม free plan ของ Twelve Data) |
QUOTE_CACHE_TTL_MINUTES | – | ค่าเริ่มต้น 5 |