Giải thích các khuyến nghị
API này trả về nội dung giải thích Nebula đã làm gì cho danh mục trong ngày và vì sao. Dùng để hiển thị màn hình "Giải thích khuyến nghị" cho người dùng cuối.
HTTP request
- URL:
/api/personalize/v1/partner/nebula-ultra/profiles/daily-explain - Method:
GET - Content Type: None
- Response Type: application/json
Tham số header
| Header | Mô tả | Kiểu dữ liệu | Bắt buộc |
|---|---|---|---|
| X-Api-Key | Khóa duy nhất. | string | có |
Tham Số Truy Vấn (Query Parameters)
| Tên Tham Số | Kiểu Dữ Liệu | Bắt buộc | Mô Tả |
|---|---|---|---|
| externalUserId | string | có | UserId của đối tác. |
| portfolioType | string | không | Loại portfolio: - paper: Giao dịch giả lập (default) - backtest: Hiệu suất quá khứ |
| recvWindow | string | không | Thời gian chấp nhận (ms), default: 5000. |
| timestamp | string | có | Unix timestamp (milliseconds). |
| signature | string | có | HMAC-SHA256 signature. |
Phản Hồi (Response)
Response Mẫu
{
"status": 200,
"message": "Success",
"data": {
"status": 200,
"message": "Success",
"data": {
"asOf": "2026-07-22",
"branch": "rebalance",
"model": {
"name": "horizon-3.3",
"family": "horizon",
"version": "3.3.1"
},
"portfolio": {
"sections": [
{
"key": "overview",
"title": "Tổng quan tài khoản",
"blocks": [
{
"children": [],
"content": [
{
"styles": {},
"text": "Tài khoản của bạn hiện có 54,6 triệu, lỗ 60,0 triệu (+0,0%) từ ngày bắt đầu.",
"type": "text"
}
],
"id": "blk-0",
"props": {},
"type": "paragraph"
},
{
"children": [],
"content": {
"rows": [
{
"cells": [
"Chỉ tiêu",
"Giá trị"
]
},
{
"cells": [
"NAV",
"54,6 triệu đồng"
]
},
{
"cells": [
"Tiền mặt",
"54,6 triệu đồng"
]
},
{
"cells": [
"Giá trị cổ phiếu",
"0 đồng"
]
},
{
"cells": [
"Lãi/lỗ từ đầu",
"-60,0 triệu đồng (+0,0%)"
]
},
{
"cells": [
"Khoảng cách so đỉnh",
"0,0%"
]
}
],
"type": "tableContent"
},
"id": "blk-1",
"props": {},
"type": "table"
}
]
},
{
"key": "positions",
"title": "Vị thế đang mở",
"blocks": [
{
"children": [],
"content": [
{
"styles": {},
"text": "Hiện không có vị thế đang mở.",
"type": "text"
}
],
"id": "blk-0",
"props": {},
"type": "paragraph"
}
]
},
{
"key": "allocation",
"title": "Phân bổ tài sản",
"blocks": [
{
"children": [],
"content": {
"rows": [
{
"cells": [
"Lớp tài sản",
"Giá trị",
"Tỷ trọng"
]
},
{
"cells": [
"Tiền mặt",
"54,6 triệu đồng",
"100,0%"
]
}
],
"type": "tableContent"
},
"id": "blk-0",
"props": {},
"type": "table"
}
]
}
]
},
"tickers": {
"lpb": {
"action": "buy",
"contentJson": {
"sections": [
{
"key": "summary",
"title": "Vì sao Nebula mua LPB (quyết định ngày 22/07/2026)",
"blocks": [
{
"id": "summary-0",
"type": "paragraph",
"props": {},
"content": [
{
"text": "Luận điểm:",
"type": "text",
"styles": {
"bold": true
}
},
{
"text": " ",
"type": "text",
"styles": {}
},
{
"text": "LPB",
"type": "text",
"styles": {
"bold": true
}
},
{
"text": " thuộc nhóm 10 cơ hội được đánh giá cao nhất trong 50 mã Nebula theo dõi, dẫn dắt bởi quan hệ dòng tiền liên thị trường và mức chênh lệch bất thường so với nhóm cổ phiếu liên hệ. Định giá tương đương ngành (P/E 10,96x so với bình quân ngành 10,12x), khối ngoại mua ròng 20,1 tỷ đồng trong 20 phiên gần nhất. Rủi ro chính: khoảng cách với nhóm cổ phiếu liên hệ đang rộng hơn 100,0% số quan sát gần đây - vị thế hưởng lợi nếu thu hẹp đúng chiều, chịu rủi ro nếu ngược lại.",
"type": "text",
"styles": {}
}
],
"children": []
}
]
},
{
"key": "analysis",
"title": "Động lực chính",
"blocks": [
{
"id": "analysis-0",
"type": "heading",
"props": {
"level": 3
},
"content": [
{
"text": "Quan hệ liên thị trường",
"type": "text",
"styles": {}
}
],
"children": []
},
{
"id": "analysis-1",
"type": "bulletListItem",
"props": {},
"content": [
{
"text": "Trong kỳ này, đánh giá LPB đặt trọng tâm vào diễn biến của THD, KDC, VGC, DGC, SAB - nhóm có ảnh hưởng lớn nhất đến kết luận",
"type": "text",
"styles": {}
}
],
"children": []
},
{
"id": "analysis-2",
"type": "bulletListItem",
"props": {},
"content": [
{
"text": "Nhìn dài hạn, LPB duy trì mối liên hệ ổn định với VPB, VIB, HDB, NVL, DGC; khoảng cách giá với nhóm này hiếm khi nới rộng kéo dài",
"type": "text",
"styles": {}
}
],
"children": []
},
{
"id": "analysis-3",
"type": "bulletListItem",
"props": {},
"content": [
{
"text": "Mối liên hệ này do Nebula tự học từ dữ liệu và được cập nhật lại mỗi khi Nebula được huấn luyện bổ sung - nhóm liên hệ của LPB hôm nay có thể khác với vài tháng trước",
"type": "text",
"styles": {}
}
],
"children": []
},
{
"id": "analysis-4",
"type": "bulletListItem",
"props": {},
"content": [
{
"text": "THD - mã gắn chặt nhất với LPB trong mạng lưới tương quan - hiện cũng thuộc nhóm được đánh giá cao nhất: chuyển động có nền rộng, không phải một mã đơn lẻ",
"type": "text",
"styles": {}
}
],
"children": []
},
{
"id": "analysis-5",
"type": "heading",
"props": {
"level": 3
},
"content": [
{
"text": "Giai đoạn dữ liệu ảnh hưởng nhất đến đánh giá",
"type": "text",
"styles": {}
}
],
"children": []
},
{
"id": "analysis-6",
"type": "bulletListItem",
"props": {},
"content": [
{
"text": "Diễn biến giá và thanh khoản tuần 22/06/2026 - 26/06/2026 là phần dữ liệu Nebula tập trung xem xét nhiều nhất, chiếm khoảng 8,4% tổng mức tập trung trên toàn giai đoạn phân tích - nổi bật hơn hẳn các tuần còn lại (tuần 02/02/2026 - 06/02/2026: 5,4%; tuần 23/03/2026 - 27/03/2026: 3,8%)",
"type": "text",
"styles": {}
}
],
"children": []
},
{
"id": "analysis-7",
"type": "bulletListItem",
"props": {},
"content": [
{
"text": "Nghĩa là: bằng chứng chính cho quyết định này đến từ giai đoạn đó, không phải chỉ vài phiên gần nhất",
"type": "text",
"styles": {}
}
],
"children": []
},
{
"id": "analysis-8",
"type": "heading",
"props": {
"level": 3
},
"content": [
{
"text": "Mức chênh lệch so với nhóm liên hệ",
"type": "text",
"styles": {}
}
],
"children": []
},
{
"id": "analysis-9",
"type": "bulletListItem",
"props": {},
"content": [
{
"text": "Khoảng cách giữa giá LPB và nhóm cổ phiếu liên hệ của nó hiện đang ở mức rộng nhất Nebula quan sát được trong những tháng gần đây - một điểm đáng chú ý khi so LPB với các cơ hội khác",
"type": "text",
"styles": {}
}
],
"children": []
}
]
},
{
"key": "price_trend",
"title": "Giá và xu hướng",
"blocks": [
{
"id": "price_trend-0",
"type": "table",
"props": {},
"content": {
"rows": [
{
"cells": [
"Chỉ tiêu",
"Giá trị",
"So VNINDEX"
]
},
{
"cells": [
"Giá tại ngày quyết định",
"54.400 đồng",
""
]
},
{
"cells": [
"Thay đổi 1 tháng",
"+10,6%",
"-8,6% (vượt trội)"
]
},
{
"cells": [
"Thay đổi 3 tháng",
"+22,5%",
"-9,0% (vượt trội)"
]
},
{
"cells": [
"Thay đổi 6 tháng",
"+33,0%",
"-11,5% (vượt trội)"
]
},
{
"cells": [
"Thay đổi 1 năm",
"+60,4%",
"+12,4% (vượt trội)"
]
},
{
"cells": [
"Giá so với bình quân 50 phiên",
"cao hơn 6,3%",
""
]
},
{
"cells": [
"Giá so với bình quân 200 phiên",
"cao hơn 20,2%",
""
]
},
{
"cells": [
"Vị trí trong biên độ 52 tuần",
"cách đỉnh 7,0% / cách đáy 72,6%",
""
]
},
{
"cells": [
"Độ biến động 3 tháng",
"2,3%/phiên",
""
]
}
],
"type": "tableContent"
},
"children": []
}
]
},
{
"key": "valuation",
"title": "Định giá và nền tảng doanh nghiệp",
"blocks": [
{
"id": "valuation-0",
"type": "paragraph",
"props": {},
"content": [
{
"text": "Ngành: Tài chính ngân hàng",
"type": "text",
"styles": {}
}
],
"children": []
},
{
"id": "valuation-1",
"type": "table",
"props": {},
"content": {
"rows": [
{
"cells": [
"Chỉ tiêu",
"Giá trị",
"So với ngành"
]
},
{
"cells": [
"P/E (LTM)",
"10,96x",
"10,12x"
]
},
{
"cells": [
"P/B",
"2,65x",
"1,06x"
]
},
{
"cells": [
"EV/EBITDA",
"Chưa có dữ liệu",
""
]
},
{
"cells": [
"ROE",
"23,43%",
"11,00%"
]
},
{
"cells": [
"Biên lợi nhuận ròng LTM",
"49,97%",
""
]
},
{
"cells": [
"Tăng trưởng doanh thu LTM",
"+10,94%",
""
]
},
{
"cells": [
"Tăng trưởng lợi nhuận ròng LTM",
"+12,17%",
""
]
},
{
"cells": [
"EPS (LTM)",
"3.738 đồng",
""
]
},
{
"cells": [
"Tăng trưởng EPS",
"-10,05%",
""
]
},
{
"cells": [
"Tỷ suất cổ tức",
"Chưa có dữ liệu",
""
]
},
{
"cells": [
"Vốn hóa",
"153.845,0 tỷ đồng",
""
]
},
{
"cells": [
"Biên lãi ròng (NIM)",
"3,15%",
""
]
},
{
"cells": [
"Tỷ lệ nợ xấu (NPL)",
"1,84%",
""
]
},
{
"cells": [
"Tỷ lệ CASA",
"6,49%",
""
]
},
{
"cells": [
"Tỷ lệ dư nợ trên tiền gửi (LDR)",
"79,15%",
""
]
},
{
"cells": [
"Chi phí trên thu nhập (CIR)",
"30,14%",
""
]
}
],
"type": "tableContent"
},
"children": []
},
{
"id": "valuation-2",
"type": "paragraph",
"props": {},
"content": [
{
"text": "Cột "So với ngành" là trung bình ngành 3 năm tính đến hiện tại, không neo theo ngày quyết định.",
"type": "text",
"styles": {}
}
],
"children": []
}
]
},
{
"key": "trading_flow",
"title": "Giao dịch và dòng tiền",
"blocks": [
{
"id": "trading_flow-0",
"type": "table",
"props": {},
"content": {
"rows": [
{
"cells": [
"Chỉ tiêu",
"Giá trị"
]
},
{
"cells": [
"Khối lượng bình quân 20 phiên",
"2.824.370 cổ phiếu/phiên (+42,5%)"
]
},
{
"cells": [
"Giá trị giao dịch bình quân 20 phiên",
"~150,4 tỷ đồng, thanh khoản tốt"
]
},
{
"cells": [
"Lệnh mua của danh mục trong khối lượng phiên",
"0,0%"
]
}
],
"type": "tableContent"
},
"children": []
},
{
"id": "trading_flow-1",
"type": "paragraph",
"props": {},
"content": [
{
"text": "Nước ngoài phiên: bán ròng 45,0 tỷ đồng; lũy kế 20 phiên: mua ròng 20,1 tỷ đồng (~0,7% tổng giá trị giao dịch 20 phiên)",
"type": "text",
"styles": {}
}
],
"children": []
}
]
},
{
"key": "risks",
"title": "Rủi ro và điều kiện xem xét lại",
"blocks": [
{
"id": "risks-0",
"type": "bulletListItem",
"props": {},
"content": [
{
"text": "Khoảng cách với nhóm cổ phiếu liên hệ đang rộng hơn 100,0% số quan sát gần đây - vị thế hưởng lợi nếu thu hẹp đúng chiều, chịu rủi ro nếu ngược lại",
"type": "text",
"styles": {}
}
],
"children": []
},
{
"id": "risks-1",
"type": "bulletListItem",
"props": {},
"content": [
{
"text": "P/B đang cao hơn đáng kể bình quân ngành (2,65x so với 1,06x) - nhạy cảm với kết quả kinh doanh không đạt kỳ vọng",
"type": "text",
"styles": {}
}
],
"children": []
},
{
"id": "risks-2",
"type": "bulletListItem",
"props": {},
"content": [
{
"text": "Nebula đánh giá lại liên tục; vị thế sẽ được thay khi ",
"type": "text",
"styles": {}
},
{
"text": "LPB",
"type": "text",
"styles": {
"bold": true
}
},
{
"text": " rời nhóm cơ hội được đánh giá cao nhất - thường do đà giá suy yếu hoặc dòng tiền rút ra",
"type": "text",
"styles": {}
}
],
"children": []
}
]
},
{
"key": "council",
"title": "Đánh giá của hội đồng Nebula",
"blocks": [
{
"id": "council-0",
"type": "table",
"props": {},
"content": {
"rows": [
{
"cells": [
"Chỉ tiêu",
"Giá trị"
]
},
{
"cells": [
"Mức đồng thuận",
"5/5 thành viên hội đồng xếp LPB trong nhóm 10 cổ phiếu ưa thích nhất của họ"
]
},
{
"cells": [
"Biến động so với lần đánh giá trước",
"-0,07, cao hơn 97,8% số lần biến động gần đây trong lịch sử"
]
},
{
"cells": [
"Vị trí tương đối các lần đánh giá gần nhất",
"giữ ổn định (2 → 2 → 2 → 2)"
]
},
{
"cells": [
"Cổ phiếu có quan hệ tương quan chặt nhất",
"THD, KDC, VGC, DGC, SAB"
]
}
],
"type": "tableContent"
},
"children": []
}
]
},
{
"key": "disclaimer",
"title": "Ghi chú",
"blocks": [
{
"id": "disclaimer-0",
"type": "paragraph",
"props": {},
"content": [
{
"text": "Nội dung giải thích ở trên phản ánh những dữ kiện có ảnh hưởng nổi bật nhất đến đánh giá của Nebula tại thời điểm phân tích, được trích xuất bằng công nghệ diễn giải mô hình - đây không phải quan hệ nhân quả trực tiếp, và không nên hiểu là nguyên nhân duy nhất khiến giá biến động.",
"type": "text",
"styles": {}
}
],
"children": []
},
{
"id": "disclaimer-1",
"type": "paragraph",
"props": {},
"content": [
{
"text": "KHÔNG đưa khuyến nghị mua/bán, dự báo giá, hay nhận định thị trường ngoài những dữ kiện được cung cấp.",
"type": "text",
"styles": {}
}
],
"children": []
}
]
}
]
}
}
}
}
}
}
Chi Tiết Tham Số Response
Response có hai lớp bao: lớp ngoài là chuẩn chung của gateway, lớp trong là kết quả nghiệp vụ. Nội dung giải thích thực sự nằm ở data.data.
| Tên Thuộc Tính | Kiểu Dữ Liệu | Mô Tả |
|---|---|---|
| status | number | Mã trạng thái HTTP. |
| message | string | Thông báo kết quả xử lý. |
| data | object (Xem chi tiết) | Lớp bao ngoài, chứa status, message và data của nghiệp vụ. |
| Tên Thuộc Tính | Kiểu Dữ Liệu | Mô Tả |
|---|---|---|
| status | number | Mã trạng thái của tầng nghiệp vụ. |
| message | string | Thông báo của tầng nghiệp vụ. |
| data | object (Xem chi tiết) | Ngữ cảnh giải thích cuối ngày. |
| Tên Thuộc Tính | Kiểu Dữ Liệu | Mô Tả |
|---|---|---|
| asOf | string | Ngày dữ liệu của bản giải thích (định dạng yyyy-MM-dd). Đây là ngày neo dữ liệu, có thể không phải ngày gọi API. |
| branch | string | Nhánh của ngày, xác định action của các mã: - rebalance: Ngày tái cân bằng, các mã có action là buy/sell - Nhánh theo dõi: các mã đang nắm giữ có action là hold Một ngày hoặc toàn bộ là buy/sell, hoặc toàn bộ là hold — không trộn lẫn. |
| model | object | null (Xem chi tiết) | Thông tin mô hình Nebula tạo ra bản giải thích. null nếu không có dữ liệu. |
| portfolio | object | null (Xem chi tiết) | Góc nhìn danh mục của người dùng trong ngày, dưới dạng sections. null nếu không có dữ liệu. |
| tickers | object (Xem chi tiết) | Quyết định theo từng mã cổ phiếu, được key theo mã viết thường (ví dụ lpb, hag). Chỉ gồm cổ phiếu; vàng/crypto/trái phiếu nằm trong portfolio. |
| Tên Thuộc Tính | Kiểu Dữ Liệu | Mô Tả |
|---|---|---|
| name | string | Tên mô hình (ví dụ horizon-3.3). |
| family | string | Họ mô hình (ví dụ horizon). |
| version | string | Phiên bản chi tiết của mô hình (ví dụ 3.3.1). |
| Tên Thuộc Tính | Kiểu Dữ Liệu | Mô Tả |
|---|---|---|
| action | string | Hành động của mã: - buy: Kế hoạch mua (ngày tái cân bằng) - sell: Kế hoạch bán (ngày tái cân bằng) - hold: Tiếp tục nắm giữ (ngày theo dõi) |
| contentJson | object (Xem chi tiết) | Nội dung giải thích của mã, dưới dạng sections. Với buy/sell là giải thích cho quyết định hôm nay; với hold là giải thích của lệnh mua ban đầu — số liệu trong đó là của ngày ra quyết định mua, không phải hôm nay. |
| Tên Thuộc Tính | Kiểu Dữ Liệu | Mô Tả |
|---|---|---|
| key | string | Khóa định danh section, dùng để nhận diện theo code (ví dụ để ẩn/hiện hoặc gắn icon riêng cho từng section). Xem danh sách key bên dưới. |
| title | string | Tiêu đề section hiển thị cho người dùng (tiếng Việt), đã sẵn sàng để render. |
| blocks | array (Xem chi tiết) | Danh sách block nội dung của section, hiển thị theo đúng thứ tự trong mảng. |
Các section của portfolio:
key | title (ví dụ) | Block trả về | Nội dung |
|---|---|---|---|
overview | Tổng quan tài khoản | paragraph + table | Đoạn tóm tắt bằng lời, kèm bảng 2 cột (Chỉ tiêu / Giá trị): NAV, tiền mặt, giá trị cổ phiếu, lãi/lỗ từ đầu, khoảng cách so đỉnh. |
positions | Vị thế đang mở | table hoặc paragraph | Bảng các vị thế đang nắm giữ. Nếu danh mục toàn tiền mặt thì không có bảng, thay bằng một paragraph báo "Hiện không có vị thế đang mở." — client cần xử lý được cả hai trường hợp. |
allocation | Phân bổ tài sản | table | Bảng 3 cột (Lớp tài sản / Giá trị / Tỷ trọng). Đây là nơi chứa vàng, crypto, trái phiếu — những tài sản không xuất hiện trong tickers. |
Các section của tickers.{ticker}.contentJson:
key | title (ví dụ) | Block trả về | Nội dung |
|---|---|---|---|
summary | Vì sao Nebula mua LPB… | paragraph | Luận điểm gói trong một đoạn: cơ sở của quyết định, định giá so với ngành, dòng tiền khối ngoại và rủi ro chính. Tiêu đề section đã chứa sẵn hành động, mã và ngày quyết định. Đây là phần nên hiển thị đầu tiên và nổi bật nhất. |
analysis | Động lực chính | heading + bulletListItem | Phần dài nhất, chia thành nhiều nhóm, mỗi nhóm là một heading (level 3) theo sau bởi các gạch đầu dòng: quan hệ liên thị trường, giai đoạn dữ liệu ảnh hưởng nhất, mức chênh lệch so với nhóm liên hệ. |
price_trend | Giá và xu hướng | table (3 cột) | Giá tại ngày quyết định, biến động 1/3/6 tháng và 1 năm, vị trí so với bình quân 50/200 phiên, biên độ 52 tuần, độ biến động. Cột 3 "So VNINDEX" chỉ có giá trị ở các dòng biến động, các dòng còn lại để trống. |
valuation | Định giá và nền tảng doanh nghiệp | paragraph + table + paragraph | Đoạn đầu là ngành của mã, giữa là bảng chỉ số (P/E, P/B, EV/EBITDA, ROE…), đoạn cuối là ghi chú về cách tính cột "So với ngành". Bộ chỉ số khác nhau theo ngành: mã ngân hàng có thêm NIM/NPL/CASA/LDR/CIR, mã phi ngân hàng có biên lợi nhuận gộp/thanh toán hiện hành/chi trả lãi vay. Client không nên dựng bảng theo danh sách chỉ tiêu cố định. |
trading_flow | Giao dịch và dòng tiền | table + paragraph | Bảng khối lượng và giá trị giao dịch bình quân 20 phiên, tỷ trọng lệnh của danh mục; theo sau là đoạn văn về giao dịch khối ngoại (trong phiên và lũy kế 20 phiên). |
risks | Rủi ro và điều kiện xem xét lại | bulletListItem | Các gạch đầu dòng về rủi ro của vị thế và điều kiện khiến Nebula đánh giá lại. |
council | Đánh giá của hội đồng Nebula | table (2 cột) | Mức đồng thuận giữa các thành viên hội đồng, biến động so với lần đánh giá trước, diễn biến thứ hạng gần nhất, nhóm mã tương quan chặt nhất. |
disclaimer | Ghi chú | paragraph | Miễn trừ trách nhiệm. Bắt buộc hiển thị, không được ẩn hay lược bỏ. |
| Tên Thuộc Tính | Kiểu Dữ Liệu | Mô Tả |
|---|---|---|
| id | string | Mã định danh block, duy nhất trong phạm vi section (ví dụ summary-0, blk-1). Dùng làm key khi render danh sách. |
| type | string | Loại block, quyết định cách kết xuất. Xem bảng bên dưới. |
| props | object | Thuộc tính kết xuất bổ sung. Chỉ heading dùng tới (props.level); các loại khác trả về object rỗng. |
| content | array | object (Xem chi tiết) | Nội dung block. Kiểu dữ liệu phụ thuộc vào type — mảng inline text hoặc object tableContent. |
| children | array | Các block con lồng bên trong. Hiện luôn là mảng rỗng, nhưng nên xử lý đệ quy để tương thích về sau. |
Bốn loại block và cách kết xuất:
type | Kiểu của content | Kết xuất thành | Ghi chú |
|---|---|---|---|
paragraph | array inline text | <p> | Đoạn văn thường. |
heading | array inline text | <h2>/<h3>… | Cấp tiêu đề lấy từ props.level (hiện dùng 3). Đây là tiêu đề phụ bên trong section, khác với section.title. |
bulletListItem | array inline text | <li> | Mỗi block là một gạch đầu dòng riêng lẻ, API không nhóm chúng lại. Client cần tự gom các bulletListItem liền nhau vào cùng một <ul>. |
table | object tableContent | <table> | Dòng đầu của rows là header. |
1. Block văn bản (paragraph, heading, bulletListItem)
content là mảng các đoạn inline text. Mỗi phần tử:
| Tên Thuộc Tính | Kiểu Dữ Liệu | Mô Tả |
|---|---|---|
| type | string | Luôn là text. |
| text | string | Chuỗi văn bản của đoạn này. |
| styles | object | Định dạng áp cho đoạn này: { "bold": true } hoặc {} nếu không định dạng. |
Một block được chia thành nhiều đoạn khi cần áp định dạng khác nhau trên từng phần câu. Client nối liền các đoạn theo thứ tự, không tự thêm khoảng trắng — dấu cách đã nằm sẵn trong text (xem đoạn thứ 2 trong ví dụ). Ví dụ block summary-0 của LPB gồm 4 đoạn:
"content": [
{ "type": "text", "text": "Luận điểm:", "styles": { "bold": true } },
{ "type": "text", "text": " ", "styles": {} },
{ "type": "text", "text": "LPB", "styles": { "bold": true } },
{ "type": "text", "text": " thuộc nhóm 10 cơ hội được đánh giá cao nhất...", "styles": {} }
]
Kết quả mong đợi: Luận điểm: LPB thuộc nhóm 10 cơ hội được đánh giá cao nhất…
2. Block bảng (table)
content là một object:
| Tên Thuộc Tính | Kiểu Dữ Liệu | Mô Tả |
|---|---|---|
| type | string | Luôn là tableContent. |
| rows | array | Danh sách dòng, mỗi dòng là object { "cells": string[] }. |
Trong đó rows:
- Dòng đầu tiên (
rows[0]) là dòng tiêu đề, render thành<th>; các dòng sau là dữ liệu. - Mọi ô đều là string đã định dạng sẵn, không phải số. Đơn vị đã nằm trong chuỗi (
"54.400 đồng","10,96x","+10,6%") — client không cần ghép thêm đơn vị. - Ô không có dữ liệu trả về chuỗi rỗng
""— render thành ô trống, không hiển thị chữ "null" hay "N/A". Riêng trường hợp chỉ tiêu không tính được, cột giá trị trả về chuỗi"Chưa có dữ liệu"(xem dòng EV/EBITDA trong response mẫu). - Số cột không cố định giữa các bảng (2 hoặc 3 cột tùy section). Lấy số cột từ
rows[0].cells.length. - Số dòng và tên chỉ tiêu cũng không cố định — duyệt
rowsđể render, đừng dò theo tên chỉ tiêu.
"content": {
"type": "tableContent",
"rows": [
{ "cells": ["Chỉ tiêu", "Giá trị", "So VNINDEX"] },
{ "cells": ["Giá tại ngày quyết định", "54.400 đồng", ""] },
{ "cells": ["Thay đổi 1 tháng", "+10,6%", "-8,6% (vượt trội)"] }
]
}