VN Pullback Screener — Sàng lọc mã pullback trong uptrend
Tổng quan
Tìm cổ phiếu đang trong uptrend rõ ràng nhưng vừa pullback về vùng hỗ trợ động (MA20 hoặc MA50). Đây là entry style ít rủi ro hơn breakout vì:
- Giá đã ở xa hơn điểm phá trần / sàn → setup chưa muộn
- Stop gần hơn (just below MA50 hoặc gần đáy pullback) → R-multiple tốt hơn
- Phù hợp với T+2.5 vì không cần intraday timing (chờ vài phiên xác nhận hỗ trợ)
5 tiêu chí pullback:
- Trend dài hạn còn nguyên — Price > MA200, MA50 > MA200, MA200 dốc lên
- Pullback từ đỉnh gần — Giá đã giảm 3-12% từ đỉnh 20 phiên
- Test hỗ trợ động — Giá touch / gần MA20 hoặc MA50
- RSI vào vùng oversold lành mạnh — RSI(14) trong khoảng 35-50
- Volume pullback dry-up — Volume tại đáy pullback < volume MA50
Khi nào dùng
- Tìm entry an toàn sau breakout / VCP đã chạy → đón cú test hỗ trợ
- Trong market regime tích cực (
vn-sector-analyst regime note = positive)
- Pair với
vn-sector-analyst để chọn pullback trong ngành dẫn dắt
- KHÔNG dùng khi market đang downtrend mạnh — pullback có thể là "broken trend"
Điều kiện tiên quyết
- Python 3.9+
- OHLCV ≥200 phiên (cần đủ tính MA200)
- Tham chiếu:
references/vn_pullback_methodology.md
Workflow
# 1. Fetch OHLCV cho universe
python skills/vn-data-fetcher/scripts/vn_data_fetcher.py ohlcv \
--symbols VCB,BID,VIC,VHM,HPG,FPT,MWG,VNM,SSI,GAS \
--start 2025-07-01 --end 2026-05-13 \
--output-dir reports/
# 2. Chạy pullback screener
python skills/vn-pullback-screener/scripts/vn_pullback_screener.py \
--ohlcv-glob 'reports/vn_ohlcv_*2026-05-13*.json' \
--min-pullback-pct 3 --max-pullback-pct 12 \
--rsi-low 35 --rsi-high 50 \
--output-dir reports/
# 3. Top candidates → build trade plan
python skills/vn-breakout-trade-planner/scripts/vn_breakout_planner.py \
--account-size 1000000000 \
--symbol <top candidate> \
--pivot <pivot from pullback output> \
--stop <stop suggested> \
--setup-type pullback \
--risk-pct 1.0 \
--output-dir reports/
Tiêu chí scoring (5 components)
| Component |
Weight |
Pass criteria |
| Long-term uptrend |
25 |
Price > MA200, MA50 > MA200, MA200 rising |
| Pullback magnitude |
20 |
-3% to -12% from 20-day high |
| Support test (MA20/MA50) |
20 |
Distance to MA20 < 3% OR distance to MA50 < 5% |
| RSI sweet spot |
20 |
RSI(14) in 35-50 range |
| Volume pullback dry-up |
15 |
Volume at low / MA50 vol ≤ 0.85 |
Grade
- A (80-100): All 5 criteria met; ideal pullback entry
- B (60-79): 4/5 criteria; viable but reduce size
- C (40-59): Setup weakening; monitor only
- <40: Reject
Output Format
{
"schema_version": "1.0",
"as_of": "2026-05-13T10:00:00+07:00",
"universe_size": 10,
"candidates_count": 3,
"candidates": [
{
"symbol": "FPT",
"exchange": "hose",
"grade": "A",
"score": 88,
"components": {
"long_term_uptrend": 25,
"pullback_magnitude": 18,
"support_test": 20,
"rsi_sweet_spot": 17,
"volume_dryup": 8
},
"current_price": 138500,
"high_20d": 145000,
"pullback_pct": -4.48,
"ma20": 139800,
"ma50": 136200,
"ma200": 122500,
"distance_to_ma20_pct": -0.93,
"distance_to_ma50_pct": 1.69,
"rsi_14": 42.3,
"volume_ratio_low_vs_ma50": 0.72,
"ma200_slope_pct_per_month": 1.8,
"suggested_entry": 139000,
"suggested_stop": 132000,
"stop_pct": 5.04,
"notes": ["Testing MA20 support", "RSI in healthy oversold zone"]
}
],
"rejected": [
{
"symbol": "VIC",
"score": 30,
"rejection_reasons": ["RSI 62 (above 50 — not in pullback)"]
}
]
}
Resources
references/vn_pullback_methodology.md — Full methodology
scripts/vn_pullback_screener.py — Main script
Nguyên tắc
- Pullback ≠ Reversal — Tránh mã đang phá MA200 hoặc MA50 dốc xuống. Đó là reversal, không phải pullback.
- RSI 35-50 là "sweet spot" — Dưới 35 quá oversold (có thể là free-fall); trên 50 không phải pullback nữa.
- Volume dry-up xác nhận — Pullback healthy: volume giảm. Pullback xấu: volume tăng (distribution).
- Combine với sector signal — Pullback trong ngành đang weak ít khi recover. Lọc qua
vn-sector-analyst.
- Stop dưới MA50 — Stop hợp lý: tại đáy pullback × 0.97 HOẶC MA50 × 0.97 (whichever is lower)
1---2name: vn-pullback-screener3description: Sàng lọc cổ phiếu Việt Nam đang pullback đẹp trong uptrend. Tìm mã giá điều chỉnh về MA20/MA50, RSI giảm về 35-50, nhưng vẫn giữ trên MA200 và uptrend dài hạn. Yêu cầu OHLCV 200+ phiên từ vn-data-fetcher. Kích hoạt khi user hỏi "tìm mã pullback", "cổ phiếu test MA20/MA50", "cổ phiếu test hỗ trợ", "buy the dip" cho cổ phiếu VN. Vietnam pullback screener — uptrending stocks pulling back to MA20 / MA50 with RSI 35-50, still above MA200. Lower-risk swing entry than breakout buying.4---56# VN Pullback Screener — Sàng lọc mã pullback trong uptrend78## Tổng quan910Tìm cổ phiếu **đang trong uptrend rõ ràng** nhưng **vừa pullback** về vùng hỗ trợ động (MA20 hoặc MA50). Đây là entry style ít rủi ro hơn breakout vì:1112- Giá đã ở **xa hơn** điểm phá trần / sàn → setup chưa muộn13- Stop **gần hơn** (just below MA50 hoặc gần đáy pullback) → R-multiple tốt hơn14- Phù hợp với **T+2.5** vì không cần intraday timing (chờ vài phiên xác nhận hỗ trợ)15165 tiêu chí pullback:171. **Trend dài hạn còn nguyên** — Price > MA200, MA50 > MA200, MA200 dốc lên182. **Pullback từ đỉnh gần** — Giá đã giảm 3-12% từ đỉnh 20 phiên193. **Test hỗ trợ động** — Giá touch / gần MA20 hoặc MA50204. **RSI vào vùng oversold lành mạnh** — RSI(14) trong khoảng 35-50215. **Volume pullback dry-up** — Volume tại đáy pullback < volume MA502223## Khi nào dùng2425- Tìm entry an toàn sau breakout / VCP đã chạy → đón cú test hỗ trợ26- Trong market regime tích cực (`vn-sector-analyst` regime note = positive)27- Pair với `vn-sector-analyst` để chọn pullback trong ngành dẫn dắt28- **KHÔNG** dùng khi market đang downtrend mạnh — pullback có thể là "broken trend"2930## Điều kiện tiên quyết3132- Python 3.9+33- OHLCV ≥200 phiên (cần đủ tính MA200)34- Tham chiếu: `references/vn_pullback_methodology.md`3536## Workflow3738```bash39# 1. Fetch OHLCV cho universe40python skills/vn-data-fetcher/scripts/vn_data_fetcher.py ohlcv \41 --symbols VCB,BID,VIC,VHM,HPG,FPT,MWG,VNM,SSI,GAS \42 --start 2025-07-01 --end 2026-05-13 \43 --output-dir reports/4445# 2. Chạy pullback screener46python skills/vn-pullback-screener/scripts/vn_pullback_screener.py \47 --ohlcv-glob 'reports/vn_ohlcv_*2026-05-13*.json' \48 --min-pullback-pct 3 --max-pullback-pct 12 \49 --rsi-low 35 --rsi-high 50 \50 --output-dir reports/5152# 3. Top candidates → build trade plan53python skills/vn-breakout-trade-planner/scripts/vn_breakout_planner.py \54 --account-size 1000000000 \55 --symbol <top candidate> \56 --pivot <pivot from pullback output> \57 --stop <stop suggested> \58 --setup-type pullback \59 --risk-pct 1.0 \60 --output-dir reports/61```6263## Tiêu chí scoring (5 components)6465| Component | Weight | Pass criteria |66| --- | --- | --- |67| **Long-term uptrend** | 25 | Price > MA200, MA50 > MA200, MA200 rising |68| **Pullback magnitude** | 20 | -3% to -12% from 20-day high |69| **Support test (MA20/MA50)** | 20 | Distance to MA20 < 3% OR distance to MA50 < 5% |70| **RSI sweet spot** | 20 | RSI(14) in 35-50 range |71| **Volume pullback dry-up** | 15 | Volume at low / MA50 vol ≤ 0.85 |7273### Grade7475- **A (80-100):** All 5 criteria met; ideal pullback entry76- **B (60-79):** 4/5 criteria; viable but reduce size77- **C (40-59):** Setup weakening; monitor only78- **<40:** Reject7980## Output Format8182```json83{84 "schema_version": "1.0",85 "as_of": "2026-05-13T10:00:00+07:00",86 "universe_size": 10,87 "candidates_count": 3,88 "candidates": [89 {90 "symbol": "FPT",91 "exchange": "hose",92 "grade": "A",93 "score": 88,94 "components": {95 "long_term_uptrend": 25,96 "pullback_magnitude": 18,97 "support_test": 20,98 "rsi_sweet_spot": 17,99 "volume_dryup": 8100 },101 "current_price": 138500,102 "high_20d": 145000,103 "pullback_pct": -4.48,104 "ma20": 139800,105 "ma50": 136200,106 "ma200": 122500,107 "distance_to_ma20_pct": -0.93,108 "distance_to_ma50_pct": 1.69,109 "rsi_14": 42.3,110 "volume_ratio_low_vs_ma50": 0.72,111 "ma200_slope_pct_per_month": 1.8,112 "suggested_entry": 139000,113 "suggested_stop": 132000,114 "stop_pct": 5.04,115 "notes": ["Testing MA20 support", "RSI in healthy oversold zone"]116 }117 ],118 "rejected": [119 {120 "symbol": "VIC",121 "score": 30,122 "rejection_reasons": ["RSI 62 (above 50 — not in pullback)"]123 }124 ]125}126```127128## Resources129130- `references/vn_pullback_methodology.md` — Full methodology131- `scripts/vn_pullback_screener.py` — Main script132133## Nguyên tắc1341351. **Pullback ≠ Reversal** — Tránh mã đang phá MA200 hoặc MA50 dốc xuống. Đó là reversal, không phải pullback.1362. **RSI 35-50 là "sweet spot"** — Dưới 35 quá oversold (có thể là free-fall); trên 50 không phải pullback nữa.1373. **Volume dry-up xác nhận** — Pullback healthy: volume giảm. Pullback xấu: volume tăng (distribution).1384. **Combine với sector signal** — Pullback trong ngành đang weak ít khi recover. Lọc qua `vn-sector-analyst`.1395. **Stop dưới MA50** — Stop hợp lý: tại đáy pullback × 0.97 HOẶC MA50 × 0.97 (whichever is lower)