# Chỉ Báo & Pattern

> Chỉ báo kỹ thuật, vùng hỗ trợ/kháng cự, mẫu nến, Turtle, breakout, sức khoẻ thị trường.

```ts
import { vn } from "vnstock-js";
import { sma, rsi, macd, supportResistance, candlePatterns } from "vnstock-js/indicators";

const bars = await vn.stock("FPT").history("1y");
const sma20 = sma(bars, { period: 20 });
```

`vnstock-js/indicators` là hàm thuần: nhận `Bar[]` (cũ trước mới sau), không gọi mạng, chạy được cả trong trình duyệt. Kết quả có cùng độ dài và thứ tự với `bars`, mỗi phần tử có `time`; giá trị là `null` cho tới khi đủ dữ liệu khởi động. Đơn vị theo đơn vị của nến: đồng với cổ phiếu, điểm với chỉ số.

## Chỉ báo xu hướng và động lượng

| Hàm | Kết quả mỗi phần tử | Mặc định |
|---|---|---|
| `sma(bars, { period, field? })` | `{ time, sma }` | `field: "close"` |
| `ema(bars, { period, field? })` | `{ time, ema }` | khởi tạo bằng SMA |
| `rsi(bars, { period? })` | `{ time, rsi }` (0 tới 100) | Wilder, 14 |
| `macd(bars, { fast?, slow?, signal? })` | `{ time, macd, signal, histogram }` | 12, 26, 9 |
| `bollinger(bars, { period?, stddev? })` | `{ time, upper, middle, lower, percentB }` | 20, 2 |
| `atr(bars, period?)` | `{ time, atr }` | Wilder, 14 |
| `superTrend(bars, { period?, multiplier? })` | `{ time, superTrend, direction, upperBand, lowerBand }` | 10, 3 |
| `ichimoku(bars, options?)` | `{ time, tenkanSen, kijunSen, senkouSpanA, senkouSpanB, chikouSpan, cloudTop, cloudBottom }` | 9, 26, 52 |
| `volumeZScore(bars, { period? })` | `{ time, z }` | 20 phiên trước, không tính phiên hiện tại |

```ts
const last = macd(bars).at(-1);           // { macd, signal, histogram }
const pctB = bollinger(bars).at(-1)?.percentB;
const trend = superTrend(bars).at(-1)?.direction; // "bullish" | "bearish"
```

## Vùng giá và pattern

| Hàm | Kết quả |
|---|---|
| `swingPivots(bars, window)` | Đỉnh, đáy xoay `{ index, time, price, kind: "high" \| "low" }` |
| `supportResistance(bars, { window?, maxZones?, tolerance?, minTouches? })` | Vùng `{ low, high, kind: "support" \| "resistance", touches, lastTouch }`, xếp theo số lần chạm |
| `extremeZones(bars, { rsiPeriod?, lower?, upper? })` | `{ time, zone: "bottom" \| "top" \| null }`: RSI dưới 30 kèm chạm Bollinger dưới, và ngược lại |
| `candlePatterns(bars, { trendLookback? })` | `{ time, pattern, bias }`: engulfing, hammer, shooting star, doji, morning/evening star |
| `breakouts(bars, { lookback?, volumeZ? })` | `{ time, direction, level, volumeZ }`: đóng cửa vượt đỉnh/đáy `lookback` phiên kèm khối lượng đột biến |
| `turtleSignals(bars, options?)` | `{ time, action: "buy" \| "sell", price, stop, reason }`: phá đỉnh 20 phiên mua, thủng đáy 10 phiên thoát, dừng lỗ 2 x ATR, lọc EMA200; chỉ mua |

```ts
const zones = supportResistance(bars);
const recentCandles = candlePatterns(bars).filter((p) => p.bias === "bullish").slice(-3);
const spikes = breakouts(bars, { lookback: 20, volumeZ: 2 });
```

`patternReport(bars, { recent })` gộp tất cả trong một lần; trên client là `vn.stock('FPT').patterns()`:

```ts
const report = await vn.stock("FPT").patterns({ recent: 10 });
console.log(report.zones, report.extreme, report.candles, report.turtle, report.breakouts);
```

## Sức khoẻ thị trường

```ts
const health = await vn.index("VNINDEX").health();
// hoặc: marketHealth(await vn.index("VNINDEX").history("1y"))
console.log(health.status, health.distributionCount, health.events.at(-1));
```

`status` là `"uptrend"`, `"pressure"` hoặc `"correction"`. Theo phương pháp của William O'Neil: đếm ngày phân phối (giảm điểm trên khối lượng lớn hơn phiên trước) trong 25 phiên gần nhất và tìm ngày bùng nổ xác nhận (follow-through day) sau một đáy.

> **Lưu ý:** Các pattern là quy tắc kỹ thuật tự động, có tỷ lệ báo nhầm. Dùng để tham khảo, không phải khuyến nghị đầu tư.
