Giá trực tiếp với watch() và cảnh báo với alert().
import { vn } from "vnstock-js";
const stop = vn.watch(["FPT", "VCB"], (t) => {
console.log(t.symbol, t.price, t.changePct, t.time);
});
const stopHpg = vn.stock("HPG").watch((t) => console.log(t.price));
// Dừng khi không cần nữa, nếu không tiến trình sẽ chạy mãi
setTimeout(() => {
stop();
stopHpg();
}, 60000);
Callback nhận một Tick mỗi khi có lệnh khớp mới: giá bằng đồng, changePct là phần trăm, khối lượng và giá trị luỹ kế của phiên, ba bước giá mua bán.
onError (mặc định in ra console.warn) và không theo dõi gì.npm install ws.const stop = vn.watch(["FPT"], (t) => console.log(t.price), {
mode: "poll",
interval: 5000, // ms, tối thiểu 1000, mặc định 5000
onError: (e) => console.error(e.message),
});
poll hỏi bảng giá định kỳ và chỉ gọi callback khi giá hoặc khối lượng đổi. Dùng trên serverless và trên trình duyệt đi qua proxy, nơi không giữ được WebSocket lâu. Tick từ poll có side: null và source: "poll".
const stopBreakout = vn.stock("FPT").alert({ when: "breakout" }, (e) => {
console.log(e.time, e.price, e.level);
});
const stopPrice = vn.stock("HPG").alert({ when: (t) => t.price >= 30000, mode: "poll" }, (e) => {
console.log("HPG chạm 30.000 đồng", e.price);
});
when: "breakout": báo một lần mỗi phiên khi giá khớp vượt đỉnh cao nhất của lookback phiên trước (mặc định 20, từ 2 tới 200, không tính phiên hôm nay). Không lọc khối lượng, vì khối lượng giữa phiên không so được với cả ngày. Cảnh báo chạy qua đêm tự tính lại mức đỉnh khi sang phiên mới.when: (tick) => boolean: chạy mỗi tick, báo khi hàm đổi từ false sang true. Hàm ném lỗi thì lỗi đi vào onError.{ symbol, rule, time, price, level, tick }; level là mức đỉnh với breakout, null với hàm tự viết.watch(): mode, interval, onError.Mức breakout dùng chung với preset breakout của Backtest: cảnh báo báo khi giá khớp vượt đỉnh trong phiên, còn backtest xét giá đóng cửa.
"use client";
import { useEffect, useState } from "react";
import { createClient, type Tick } from "vnstock-js";
const vn = createClient({ proxy: "/api/vnstock" });
export function LivePrice({ symbol }: { symbol: string }) {
const [tick, setTick] = useState<Tick | null>(null);
useEffect(() => vn.stock(symbol).watch(setTick), [symbol]);
return <span>{tick ? (tick.price / 1000).toFixed(2) : "–"}</span>;
}
watch() trả hàm dừng, nên trả thẳng nó từ useEffect là đủ để dọn dẹp khi component unmount.