vninvestcharts
v1.1.0
Published
Professional-grade Vietnamese stock charting library with real-time VN market data, 60+ indicators, 20+ drawing tools, and embeddable React widget
Readme
VNInvestCharts
Professional-grade Vietnamese stock charting widget — embed into any website, zero backend coupling. Widget biểu đồ chứng khoán chuyên nghiệp — nhúng vào bất kỳ website nào, hoàn toàn độc lập với backend.
🌐 Live demo / Bản dùng thử: https://vninvest.edusuccess.vn
Why VNInvestCharts? / Tại sao chọn VNInvestCharts?
EN: VNInvestCharts is a pure frontend charting widget with no backend dependency. It embeds into any website — React SPA, vanilla HTML, CMS, or third-party platform — via 3 delivery modes (ESM, IIFE, Iframe). The widget communicates with any backend through a pluggable data adapter, making frontend and backend completely independent.
VN: VNInvestCharts là widget biểu đồ thuần frontend, không phụ thuộc backend. Nhúng được vào mọi website — React SPA, HTML thuần, CMS, hoặc nền tảng bên thứ ba — qua 3 chế độ (ESM, IIFE, Iframe). Widget giao tiếp với backend qua data adapter cắm được, giúp frontend và backend hoàn toàn độc lập.
| Advantage / Ưu điểm | Description / Mô tả |
|---|---|
| Zero backend coupling / Không phụ thuộc backend | Widget is pure frontend. No server, no database, no API coupling required. / Widget thuần frontend. Không cần server, database, hay ràng buộc API. |
| Any website, any stack / Mọi website, mọi stack | Embed via React ESM, vanilla script tag (IIFE), or sandboxed iframe. / Nhúng qua React ESM, script tag (IIFE), hoặc iframe cách ly. |
| Pluggable data adapter / Adapter dữ liệu cắm được | Swap data sources via a typed StockDataAdapter interface — your backend, third-party API, or static data. / Đổi nguồn dữ liệu qua interface StockDataAdapter kiểu — backend của bạn, API bên thứ ba, hoặc dữ liệu tĩnh. |
| CSS isolation / Cô lập CSS | Shadow DOM built-in (IIFE) or manual injection — no style leaks. / Shadow DOM có sẵn (IIFE) hoặc inject thủ công — không lo xung đột CSS. |
| Auth-agnostic / Không ràng buộc xác thực | Token-based authHandler pattern — works with JWT, OAuth, session, or BFF proxy. / Pattern authHandler dạng token — hoạt động với JWT, OAuth, session, hoặc BFF proxy. |
| VN market native / Bản địa thị trường VN | Built for Vietnamese stocks, VN timezone, VND currency, vi/en i18n. / Xây dựng cho chứng khoán Việt Nam, múi giờ VN, tiền tệ VND, i18n vi/en. |
Quick Start / Bắt đầu nhanh
Script tag (IIFE) — any website / mọi website
<script src="https://cdn.jsdelivr.net/npm/vninvestcharts/dist/vninvestchart.iife.js"></script>
<script>
const { unmount, widgetRef } = window.VNInvestCharts.mount({
container: document.getElementById('chart'),
props: { symbol: 'VCB', timeframe: '1D', theme: 'dark' },
useShadowDOM: true,
});
// widgetRef.current?.setSymbol('FPT');
</script>No React, no build step required. Zero backend. / Không cần React, không cần build. Không cần backend.
ESM — React app / ứng dụng React
import { VNInvestCharts } from 'vninvestcharts';
import 'vninvestcharts/dist/index.css';
function App() {
return <VNInvestCharts symbol="VCB" timeframe="1D" theme="dark" />;
}Iframe — maximum isolation / cách ly tối đa
<iframe src="https://your-cdn.com/iframe/vninvestchart.iframe.html"
style="width:100%;height:600px;border:none;"></iframe>
<script type="module">
import { createVNInvestChartsHost } from 'vninvestcharts/iframe';
const sdk = await createVNInvestChartsHost({ iframe: document.querySelector('iframe') });
await sdk.getController().initialize({ symbol: 'VCB', timeframe: '1D' });
</script>Full sandbox isolation. Communication via typed Host SDK. / Cách ly sandbox hoàn toàn. Giao tiếp qua Host SDK kiểu.
Core Architecture / Kiến trúc cốt lõi
Frontend-Backend Separation / Tách biệt Frontend-Backend
┌─────────────────────────────────────────────────┐
│ Your Website (any stack / mọi nền tảng) │
│ │
│ ┌───────────────────────────────────────────┐ │
│ │ VNInvestCharts Widget (pure frontend) │ │
│ │ │ │
│ │ ┌──────┐ ┌──────────┐ ┌─────────────┐ │ │
│ │ │ ESM │ │ IIFE │ │ Iframe │ │ │
│ │ │ React│ │Vanilla JS│ │ Sandboxed │ │ │
│ │ └──┬───┘ └────┬─────┘ └──────┬──────┘ │ │
│ │ └───────────┼───────────────┘ │ │
│ │ │ (unified adapter layer) │ │
│ │ ┌──────┴──────┐ │ │
│ │ │ DataAdapter │ ← pluggable │ │
│ │ └──────┬──────┘ │ │
│ └─────────────────┼──────────────────────────┘ │
│ │ │
│ ┌─────────────────┼──────────────────────────┐ │
│ │ Your Backend (any language / bất kỳ) │ │
│ │ ┌──────────────┴──────────────┐ │ │
│ │ │ REST / GraphQL / WebSocket │ │ │
│ │ │ Python / Java / Go / PHP ⋯│ │ │
│ │ └─────────────────────────────┘ │ │
│ └────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘EN: The widget never talks directly to a backend. All data flows through a StockDataAdapter interface — your backend can be written in any language, use any protocol (REST, WS, gRPC), and change independently of the frontend. The widget doesn't care.
VN: Widget không bao giờ giao tiếp trực tiếp với backend. Toàn bộ dữ liệu chảy qua interface StockDataAdapter — backend của bạn viết bằng ngôn ngữ nào cũng được, dùng giao thức nào cũng được (REST, WS, gRPC), và có thể thay đổi độc lập với frontend. Widget không quan tâm.
// Your adapter — connect any backend / kết nối backend bất kỳ
import type { StockDataAdapter } from 'vninvestcharts';
const myAdapter: StockDataAdapter = {
fetchBarsBefore: async (symbol, tf, beforeDate, limit) => {
const res = await fetch(`/api/bars?symbol=${symbol}&tf=${tf}&before=${beforeDate.getTime()}&limit=${limit}`);
return res.json();
},
fetchBarsInRange: async (symbol, tf, from, to) => {
const res = await fetch(`/api/bars?symbol=${symbol}&tf=${tf}&from=${from.getTime()}&to=${to.getTime()}`);
return res.json();
},
};
<VNInvestCharts symbol="VCB" adapter={myAdapter} />SSOT Data Model / Mô hình dữ liệu SSOT
EN: Every indicator is computed once by the engine kernel and consumed by many layers — no redundant computation, no stale state. The widget maintains a canonical store that guarantees data consistency across panes, drawings, and replay.
VN: Mọi chỉ báo được engine kernel tính một lần và nhiều tầng cùng tiêu thụ — không tính toán dư thừa, không state lỗi thời. Widget duy trì canonical store đảm bảo dữ liệu nhất quán giữa các pane, drawing, và replay.
Multi-layer Isolation / Cô lập đa tầng
src/
├── lib/ ← Pure library — no external deps / *thuần thư viện*
│ ├── core/ ← Chart engine, calculators, registry, replay
│ ├── drawing/ ← Drawing tools + interaction FSM
│ ├── indicators/← Indicator compute registry
│ └── types/ ← Shared TypeScript definitions
├── widget/ ← Embeddable React widget — embeddable / *có thể nhúng*
└── demo/ ← Demo shell — never imported by lib/widget / *demo, không ảnh hưởng*Hard rules / Nguyên tắc cứng:
src/lib/never imports fromsrc/demo/— library is completely independent of the demo surface. / Thư viện hoàn toàn độc lập với demo.- The widget layer can be embedded without the demo layer — zero extra weight. / Lớp widget nhúng được mà không kéo theo demo.
- Presentation never affects data — UI is a pure projection of the canonical store. / UI là hình chiếu thuần của dữ liệu.
Delivery Matrix / Ma trận phân phối
| Mode / Chế độ | Bundle | CSS Isolation | React required | Use case / Ứng dụng |
|---|---|---|---|---|
| ESM (React) | dist/index.js | Manual Shadow DOM | Yes | React SPA |
| IIFE (script tag) | dist/vninvestchart.iife.js | Shadow DOM by default | No | Any website, CMS, static page |
| Iframe | dist/iframe/vninvestchart.iframe.html | Sandbox (absolute) | No | Third-party sites, strict CSP |
Embedding Guide / Hướng Dẫn Nhúng
Full bilingual guide → docs/WIDGET_EMBED_GUIDE.md
Hướng dẫn song ngữ đầy đủ → docs/WIDGET_EMBED_GUIDE.md
| Method / Phương thức | Lines of code | Backend needed | Best for / Phù hợp nhất | |---|---|---|---| | ESM React | 5–10 | No | React SPA | | IIFE script tag | 5–10 | No | WordPress, Shopify, static HTML | | Iframe + SDK | 10–15 | No | Third-party embedding, banking, enterprise |
Features / Tính năng
| Feature | Status | |---------|--------| | Candlestick / OHLC / Heikin-Ashi / Renko / Kagi / Point & Figure | ✅ | | 68 drawing tools (Trend Line, Fibonacci, Channel, Gann, Elliott Wave, Harmonic, ABCD, Pitchfork, Measurement) | ✅ | | 59 technical indicators (EMA, MACD, RSI, Bollinger, VWAP, Volume Profile, CVD, Ichimoku, SuperTrend, Market Profile) | ✅ | | Dark / Light theme | ✅ | | Bar replay & paper trading | ✅ | | Multi-symbol comparison | ✅ | | Dynamic pane layout with splitter resize | ✅ | | Workspace save/restore (localStorage) | ✅ | | VI / EN i18n | ✅ | | Bar backfill engine (lazy-load historical data) | ✅ | | Drawing export/import | ✅ | | VNInvest exclusive indicators (Whale Flow, CVD, Dark Flow, SMFI) | 🔄 In progress | | Visual DAG indicator builder | 📋 Planned | | Indicator sets & templates | 📋 Planned |
Widget API
interface VNInvestChartsProps {
symbol: string;
timeframe: Timeframe;
theme?: 'light' | 'dark';
locale?: 'vi' | 'en';
drawingUiEnabled?: boolean;
showHeader?: boolean;
showToolbar?: boolean;
showFooter?: boolean;
containerStyle?: React.CSSProperties;
onSymbolChange?: (symbol: string) => void;
onTimeframeChange?: (tf: Timeframe) => void;
}Imperative control (IIFE):
const { mount, unmount, widgetRef } = window.VNInvestCharts.mount({
container: document.getElementById('chart'),
props: { symbol: 'VCB', timeframe: '1D' },
useShadowDOM: true,
});
widgetRef.current?.setSymbol('VCB');
widgetRef.current?.setTimeframe('1H');
widgetRef.current?.toggleTheme();
const drawings = widgetRef.current?.exportDrawings();Full props reference → docs/WIDGET_EMBED_GUIDE.md
Subpath Exports / Đường dẫn phụ
// Data adapters
import { VNInvestDataAdapter, MultiSourceDataAdapter } from "vninvestcharts/adapters";
// Drawing controllers
import { createLocalStorageAdapter, type DrawingWorkspaceController } from "vninvestcharts/drawing";
// Types
import type { StockDataAdapter, Timeframe, OHLCVBar } from "vninvestcharts/types";Standalone Components / Components độc lập
import {
DrawingDock, DrawingInspector, DrawingListPanel,
ReplayControlBar, PaperTradePanel, SettingsModal, VNSymbolSearch,
WhalePanel, WidgetErrorBoundary, WidgetEmptyState, PremiumFeatureGate,
} from "vninvestcharts";Development / Phát triển
npm install
npm run watch # dev server → http://localhost:8080
npm run type-check # TypeScript strict check
npm test # 2600+ tests (Vitest)
npm run build # production build → dist/Packages / Gói
| Package | Description |
|---------|-------------|
| vninvestcharts | Main library — ESM + CJS + IIFE + iframe |
| vn-kline-engine-core | Canvas/WebGL rendering engine |
| vn-kline-engine-react | React bindings for engine |
License
Mozilla Public License 2.0 — © 2026 Phạm Việt Dũng
