Type/to search
2
Follow
490
Followers
Ngòi nổ: Vẽ "tin tức" vào trong nến K, là một nỗ lực như thế nào?
Discussions
Created 2026-06-12 09:56:54  Updated 2026-06-16 14:26:06
 0
 159

img

1. Khởi đầu: "K-line do Trump vẽ"

Tính thời sự của tin tức là không thể nghi ngờ. Sau khi có tin Mỹ không kích Iran, giá dầu thô tăng mạnh trong thời gian ngắn. Trong quá trình đó, các yếu tố như phát ngôn của Trump và Iran liên tục đan xen và củng cố lẫn nhau, đẩy thị trường lên những vùng giá mới.

img

Chúng ta thường nói đùa rằng "Trump vẽ K-line" – phần lớn các biến động giá mạnh không phải do các chỉ báo kỹ thuật tạo ra, mà là do một dòng tweet, một bài phát biểu, hay một tuyên bố chính sách trực tiếp gây ra. Phân tích kỹ thuật cho bạn biết "hiện tại đang ở đâu", nhưng tin tức mới thường là yếu tố then chốt giải thích "tại sao lại ở đây và tiếp theo có thể đi đâu".

img

Tầm quan trọng của tin tức là không thể phủ nhận, nhưng vấn đề thực tế là: con người không thể 24 giờ theo dõi thị trường và tin tức, càng khó hơn trong dòng tin tức hỗn loạn để nắm bắt ngay lập tức thông tin thực sự có thể gây ra biến động thị trường. Do đó, một ý tưởng đơn giản nảy ra – liệu có thể "vẽ" tin tức trực tiếp lên biểu đồ K-line, để giá cả và tin tức được hiển thị đồng thời trong cùng một khung nhìn? Ít nhất trước tiên hãy giải quyết vấn đề "nhìn thấy".

img

2. Lựa chọn nguồn tin tức: Kết nối Jin10 qua MCP

Để đưa tin tức vào, bước đầu tiên là tìm một nguồn tin cập nhật đủ nhanh và có cấu trúc tương đối chuẩn. Lần này chúng tôi sử dụng dữ liệu Jin10 (金十数据), kết nối qua MCP (Model Context Protocol), gọi hai loại giao diện: list_flash (tin nhanh) và list_news (tin tức).

Tôi sẽ không dành nhiều thời gian để giới thiệu Jin10 – nó chỉ là một lựa chọn hiện tại của chúng tôi. Ý tưởng và nguồn tin cụ thể được tách rời; miễn là một nguồn nào đó có thể cung cấp tiêu đề/nội dung có dấu thời gian và có thể gọi theo cách chuẩn tương tự MCP, đều có thể thay thế. Trọng tâm là thiết kế của lớp kết nối này, không phải là ràng buộc vào một công cụ cụ thể.

Việc kết nối và quản lý phiên MCP là phần "cơ bản" nhưng cũng rất quan trọng của hệ thống này:

python
def _mcp_post(payload, is_notification=False): global _mcp_session_id, _mcp_req_id if not is_notification: _mcp_req_id += 1 payload["id"] = _mcp_req_id body = json.dumps(payload, ensure_ascii=False).encode() req = urllib.request.Request( JIN10_MCP_URL, data=body, headers=_mcp_headers(), method="POST" ) try: with urllib.request.urlopen(req, timeout=30) as resp: sid = resp.headers.get("Mcp-Session-Id") if sid: _mcp_session_id = sid if resp.status == 202: return {} text = resp.read().decode("utf-8", errors="replace") except urllib.error.HTTPError as e: raise RuntimeError("HTTP %d: %s" % (e.code, e.read().decode()[:400])) except urllib.error.URLError as e: raise RuntimeError("Network: " + str(e)) return _mcp_parse(text) def mcp_init(): global _mcp_ready mcp_rpc("initialize", { "protocolVersion": "2025-11-25", "capabilities": {}, "clientInfo": {"name": "fuse-fmz", "version": "1.0"}, }) mcp_notify("notifications/initialized") _mcp_ready = True Log("MCP ready session_id=" + (_mcp_session_id or "(none)"))

Sau khi phiên được thiết lập, việc kéo tin tức chỉ là hai lần gọi công cụ, sau đó chuẩn hóa định dạng và loại bỏ trùng lặp:

python
def refresh_news(): global _cached_news, _last_news_at, _mcp_ready if not JIN10_MCP_TOKEN: return now = int(time.time()) if now - _last_news_at < NEWS_REFRESH_SEC and _cached_news: return _last_news_at = now try: if not _mcp_ready: mcp_init() flash_raw = mcp_call_tool("list_flash") news_raw = mcp_call_tool("list_news") combined = ( _normalize(_extract_items(flash_raw), "flash") + _normalize(_extract_items(news_raw), "news") ) combined.sort(key=lambda x: x["ts"], reverse=True) _cached_news = combined[:80] Log("News updated: %d items" % len(_cached_news)) except Exception as e: Log("News refresh failed: " + str(e)) _mcp_ready = False

Các nguồn tin khác nhau trả về tên trường rất khác nhau (title/content/introduction, time/ts/created_at...), vì vậy chúng tôi thêm một lớp _extract_items + _normalize để chuẩn hóa tất cả thành cấu trúc {ts, time, title, source, full_text}, giúp logic biểu đồ và lọc sau này không cần quan tâm dữ liệu đến từ giao diện nào.

Lưu ý: Bạn cần xin API MCP để sử dụng.

img

3. Cách chơi cốt lõi: Để tin tức "mọc" trên K-line

Tiếp theo là phần thú vị của công cụ này – đặt tin tức và K-line trên cùng một biểu đồ.

img

Chúng tôi thêm một series thứ hai vào biểu đồ, loại flags, gắn trên series K-line, làm "lớp đánh dấu tin tức":

python
def init_chart(symbol): global _chart _chart = Chart({ "__isStock": True, "chart": {"style": {"fontFamily": "Microsoft YaHei, SimHei, Arial, sans-serif"}}, "title": {"text": "FUSE " + symbol}, "xAxis": {"type": "datetime"}, "series": [ { "id": "kline", "type": "candlestick", "name": symbol, "data": [], }, { "type": "flags", "name": "News", "onSeries": "kline", "shape": "circlepin", "color": "#F59E0B", "fillColor": "#F59E0B", "width": 16, "data": [], }, ], }) _chart.reset()

Mỗi lần làm mới, trước tiên cập nhật gia tăng dữ liệu nến, sau đó lọc ra các tin tức "quan trọng" dựa trên từ khóa, căn chỉnh chúng theo thời gian tương ứng với từng thanh nến:

python
def draw_chart(records): global _last_bar_time, _last_news_hash, _flagged_news_ts if not _chart or not records: return # 检测新闻是否有更新,有则重置图表重画 news_hash = hash(tuple(n.get("ts", 0) for n in _cached_news[:10])) news_changed = (news_hash != _last_news_hash) if news_changed: _chart.reset() _last_bar_time = 0 _last_news_hash = news_hash _flagged_news_ts = set() # series 0:K线,增量 add for r in records: t = r['Time'] bar = [t, r['Open'], r['High'], r['Low'], r['Close']] if t > _last_bar_time: _chart.add(0, bar) _last_bar_time = t elif t == _last_bar_time: _chart.add(0, bar, -1) # series 1:关键词新闻 flag,对应到K线 bar 时间 if not _cached_news: return kws = [k.strip() for k in NEWS_KEYWORD.split("|") if k.strip()] kw_news = [n for n in _cached_news if not kws or any(k in n.get("full_text", n["title"]) for k in kws)] if not kw_news: return p_ms = PERIOD_MS.get(KLINE_PERIOD, 60000) first = records[0]['Time'] last = records[-1]['Time'] by_bar = {} for n in kw_news: if not n.get("ts"): continue key = (n["ts"] // p_ms) * p_ms if key not in by_bar: by_bar[key] = n for ts, item in sorted(by_bar.items()): if not (first <= ts <= last): continue if ts in _flagged_news_ts: continue _chart.add(1, { "x": ts, "title": "📰", "text": item["title"][:100], }) _flagged_news_ts.add(ts)

Hiệu quả đạt được là: mỗi khi xuất hiện ký hiệu 📰 trên biểu đồ, di chuột vào đó sẽ thấy được tiêu đề tin tức tương ứng, và vị trí của nó chính là thanh nến tương ứng với thời điểm xảy ra tin tức đó. Các điểm ngoặt giá và thời điểm tin tức lần đầu tiên được đặt trong cùng một khung hình một cách trực quan — bạn không còn phải chuyển đổi giữa hai cửa sổ để xem "đoạn này là vì lý do gì".

NEWS_KEYWORD hỗ trợ phân cách nhiều từ khóa bằng | (ví dụ "Iran|tăng lãi suất|non-farm|thuế quan"), hệ thống sẽ ưu tiên đánh dấu các tin tức trúng từ khóa lên biểu đồ, tránh làm biểu đồ bị spam bởi các tin nhanh không liên quan.

4. Bảng trạng thái: Thị trường, vị thế, tin tức xem trong một màn hình

Ngoài biểu đồ, chúng tôi còn tạo một nhóm bảng trạng thái, xuất ra qua LogStatus, bao gồm thị trường thời gian thực, vốn chủ sở hữu và lãi lỗ tài khoản, vị thế hiện tại, tin tức trúng từ khóa, và tin nhanh toàn bộ mới nhất:

python
def make_status(symbol, ticker, positions, equity): # 4. 关键词新闻(显示命中的关键词,而不是来源) kws = [k.strip() for k in NEWS_KEYWORD.split("|") if k.strip()] kw_rows = [] for item in _cached_news[:40]: t = item.get("time") or (_D(item["ts"]) if item.get("ts") else "-") title = item["title"][:90] text = item.get("full_text", item["title"]) hit_kws = [k for k in kws if k in text] if hit_kws: kw_rows.append([t, "/".join(hit_kws), title]) if not kw_rows: kw_rows = [["-", "-", "暂无关键词相关新闻"]]

Thêm một giao diện lệnh thủ công đơn giản — mở long, mở short, đóng long, đóng short, đóng tất cả một nút, sửa số lượng đặt lệnh — tất cả đều được nhận qua GetCommand():

python
def handle_command(symbol): global _cur_amount, _last_news_at cmd = GetCommand() if not cmd: return Log("CMD: " + cmd) parts = cmd.split(":") key = parts[0] val = parts[1] if len(parts) > 1 else "" if key == "openLong": market_order(symbol, "openLong", _cur_amount) elif key == "openShort": market_order(symbol, "openShort", _cur_amount) elif key == "closeLong": market_order(symbol, "closeLong", _cur_amount) elif key == "closeShort": market_order(symbol, "closeShort", _cur_amount) elif key == "closeAll": close_all(symbol) elif key == "amount": _cur_amount = float(val) Log("Amount updated: " + str(_cur_amount))

Tổng thể, FUSE về bản chất là một bảng theo dõi "tích hợp thông tin + thực thi thủ công": nó hiển thị giá cả, tin tức, vị thế và tình trạng tài khoản trên cùng một màn hình, quyết định vẫn hoàn toàn thuộc về con người — nó không đưa ra phán đoán thay bạn, nhưng giúp bạn đỡ bỏ sót một số thứ khi đưa ra phán đoán.

5. Hạn chế: Con người vẫn là biến số lớn nhất

Những hạn chế của phiên bản này khá rõ ràng, chúng tôi cũng không muốn né tránh.

Thứ nhất, mối quan hệ giữa tin tức và giá cả là "thô" — chỉ gắn tin tức vào thanh K-line tương ứng theo dấu thời gian, không có giải thích ở cấp độ nội dung. Một tin tức là tích cực hay tiêu cực, có gây ra biến động giá hay không, hoàn toàn phụ thuộc vào con người đánh giá.

Thứ hai, bộ lọc từ khóa tự nó là một giải pháp khá đơn giản. Trúng từ khóa không có nghĩa là tin tức thực sự quan trọng, không trúng cũng không có nghĩa là không quan trọng. Ở giữa đó, nhận thức, kinh nghiệm cá nhân, thậm chí trạng thái trong ngày có thể chiếm trọng số lớn — cùng một tin tức, những người khác nhau nhìn vào cùng một biểu đồ có thể đưa ra kết luận hoàn toàn khác nhau.

Thứ ba, toàn bộ quy trình vẫn là "con người trong vòng lặp", tốc độ phản hồi bị giới hạn bởi tốc độ phản ứng của con người, và trong nhiều trường hợp, phản ứng của thị trường đối với tin tức chỉ diễn ra trong vài phút hoặc thậm chí vài giây.

Nếu mọi người quan tâm đến hướng đi này, chúng tôi sẽ thử xây dựng một phiên bản tự động hóa dựa trên mô hình lớn, cho phép mô hình thực hiện giải thích sơ bộ và đánh giá mức độ quan trọng của tin tức, hỗ trợ hoặc thậm chí thay thế cho quyết định thủ công. Nếu quan tâm, hãy theo dõi tiếp.

Mã nguồn chiến lược: Hệ thống ngòi nổ tin tức thời gian thực

Comment
All comments (0)
No data
No data
  • 1
Forums
PINE Language
Get the app
iPhone Download
© 2015 - ∞ INVENTOR PTE LTD (SG)