Dữ liệu và tín hiệu
Mục lục
Nội dung trang này giữ nguyên từ bản v0.5.0, chưa viết riêng cho free: ví dụ chạy được nếu tên hàm không đổi. Bản gốc: /docs/vnstock_quant/backtest/du-lieu-va-tin-hieu.
Tính năng trên trang này đang trong giai đoạn phát triển thử nghiệm và chưa ổn định. Bạn dùng được để tìm hiểu và chạy thử, nhưng tên hàm hay công cụ, tham số và cấu trúc kết quả có thể còn đổi giữa các bản phát hành, cách tính và cách xử lý cũng có thể còn được hiệu chỉnh.
Hãy đối chiếu kết quả với một cách tính độc lập trước khi đưa vào quy trình nghiên cứu, và ghim phiên bản thư viện trong dự án để mã đang chạy không tự đổi theo bản mới.
Thư viện tách phần sinh tín hiệu khỏi phần khớp lệnh. Bạn quyết định khi nào vào và khi nào thoát; thư viện quyết định lệnh khớp ở giá nào, có khớp được không, và phí bao nhiêu.
Dữ liệu đầu vào
data là một pandas.DataFrame hoặc danh sách dict, mỗi dòng một phiên, xếp từ cũ tới mới.
| Cột | Bắt buộc | Ghi chú |
|---|---|---|
time / date / datetime | có | Ngày phiên, dạng YYYY-MM-DD hoặc kiểu ngày giờ. Nếu ngày nằm ở chỉ mục của DataFrame thì thư viện tự lấy ra |
open, high, low, close | có | Giá. Kết quả của vnstock (Market().equity(...).ohlcv(...)) dùng được ngay |
volume | không | Mặc định 0 |
reference_price | không | Giá tham chiếu của phiên. Không có thì lấy giá đóng cửa phiên trước để tính biên độ |
Thiếu cột ngày là lỗi QUANT_INPUT_DATA: thư viện không tự sinh ngày.
Ba cách đưa tín hiệu vào
1. Mảng [-1, 0, 1]
sigs = [0] * len(df)
sigs[20], sigs[45] = 1, -1 # vào ở tín hiệu phiên 20, thoát ở tín hiệu phiên 45
res = bt.run(df, sigs, symbol="FPT")1 là vào vị thế mua, -1 là thoát. Trên hồ sơ cho phép bán khống (vn_futures, crypto_perp), -1 còn mở vị thế bán và 1 đóng nó.
2. Cặp entries / exits
ma20 = df["close"].rolling(20).mean()
res = bt.run(
df,
entries=(df["close"] > ma20).tolist(),
exits=(df["close"] < ma20).tolist(),
symbol="FPT",
)Có thêm short_entries, short_exits cho hồ sơ cho phép bán khống. tags là danh sách nhãn theo phiên; nhãn được chép sang lệnh mở ở phiên đó. Khi đang giữ nhiều lô cùng mã (pyramiding > 1), exit_tags cho biết tín hiệu thoát ở một phiên chỉ nhắm vào lô mang nhãn nào — xem mục nhiều lô ở trang Chạy backtest và đọc kết quả.
Ba cách trên quyết định khi nào. Mức giá của lệnh giới hạn, lệnh dừng và mức dừng lỗ đổi theo từng phiên lại là tín hiệu riêng, theo phiên: entry_limit, entry_stop, exit_stop. Chi tiết ở trang Chạy backtest và đọc kết quả.
3. Bảng quy tắc rule_dsl
Bảng quy tắc là một dict phẳng, được tính trong lõi Rust với các chỉ báo của vnstock_quant. Đây là cách nên dùng khi bạn hay trợ lý AI mô tả chiến lược bằng lời.
dsl = {
"entry_logic": "all",
"entry_rules": [
{"left": {"ind": "rsi", "params": {"length": 14}}, "op": "cross_above", "right": 30},
{"left": "close", "op": "gt", "right": {"ind": "sma", "params": {"length": 200}}},
],
"exit_logic": "any",
"exit_rules": [
{"left": {"ind": "rsi", "params": {"length": 14}}, "op": "gt", "right": 70},
{"left": {"ind": "macd", "output": "MACDh"}, "op": "cross_below", "right": 0},
],
}
res = bt.run(df, rule_dsl=dsl, symbol="FPT")Toán hạng (left, right):
| Dạng | Ví dụ | Ý nghĩa |
|---|---|---|
| Số | 30 | Hằng số, theo đúng đơn vị dữ liệu bạn đưa vào (nghìn đồng nếu dữ liệu từ vnstock) |
| Tên cột | "close", "volume" | Một cột của dữ liệu, hoặc cột bạn thêm qua feature_columns |
| Cột lùi phiên | {"col": "close", "shift": 1} | Giá trị của cột ở shift phiên trước. shift không nhận số âm |
| Chỉ báo | {"ind": "sma", "params": {"length": 50}} | Một chỉ báo trong bt.list_indicators() |
| Chỉ báo nhiều cột | {"ind": "bbands", "params": {"length": 20}, "output": "BBU"} | Chọn một cột đầu ra theo tên hoặc tiền tố |
| Chỉ báo trên cột khác | {"ind": "sma", "params": {"length": 20}, "source": "volume"} | Tính chỉ báo trên volume thay cho close |
Chỉ báo cũng nhận shift, ví dụ {"ind": "rsi", "params": {"length": 14}, "shift": 1}.
Phép so sánh (op): gt, gte, lt, lte, eq, cross_above, cross_below. cross_above đúng ở phiên left vượt lên trên right, tức phiên trước left <= right và phiên này left > right.
Cách gộp điều kiện:
| Khoá | Mặc định | Giá trị |
|---|---|---|
entry_logic, short_entry_logic | "all" | "all", "any", hoặc {"vote_at_least": k} (ít nhất k điều kiện đúng) |
exit_logic, short_exit_logic | "any" | Như trên |
Bảng quy tắc cần ít nhất một điều kiện vào lệnh. short_entry_rules, short_exit_rules chỉ dùng trên hồ sơ cho phép bán khống. Trong giai đoạn chỉ báo chưa đủ dữ liệu khởi động, điều kiện được tính là sai.
Xem trước tín hiệu mà không chạy backtest:
sig = bt.eval_rule_dsl(dsl, df)
print(sum(sig["entries"]), sum(sig["exits"]))Danh sách chỉ báo
bt.list_indicators() trả 56 chỉ báo, mỗi mục có name, group, inputs, params (tên, kiểu, mặc định), title và access:
access: "bt_basic": dùng được ở mọi cấp, gồm 10 chỉ báosma,ema,rsi,macd,stoch,bbands,atr,obv,vwap,pivots;access: "bt": cần cấp Bronze trở lên.
Bảng quy tắc dùng một chỉ báo chưa mở cho cấp của bạn thì bị từ chối (QUANT_TIER_REQUIRED) trước khi chạy, không bị trừ lượt.
| Nhóm | Chỉ báo |
|---|---|
| Xu hướng | sma, ema, wma, hma, smma, alma, vwma, adx, psar, supertrend, dm, linreg, aroon |
| Động lượng | rsi, stoch, stochrsi, mom, roc, ao, cci, willr, tsi, cmo, uo, fisher, cg, kst, macd |
| Biến động | bbands, kc, atr, stdev, donchian, massi, ui, squeeze, squeeze_pro, true_range |
| Khối lượng | obv, cmf, ad, vwap, pvo, efi, eom, nvi, mfi |
| Thống kê | pivots, mad, variance, hl2, hlc3, ohlc4, midprice, decreasing, increasing |
Hai chỉ báo của vnstock_quant không dùng được trong bảng quy tắc:
ichimokudịch đường mây về phía trước, nên giá trị tại phiêntđọc dữ liệu saut;vpkhông trả một giá trị cho mỗi phiên.
Gọi chúng thì báo QUANT_CAUSALITY_VIOLATION.
Kiểm tra thiên lệch nhìn trước tương lai
Một tín hiệu tại phiên t chỉ được dùng dữ liệu tới hết phiên t. Cách kiểm của thư viện: tính tín hiệu trên toàn bộ dữ liệu, rồi tính lại trên dữ liệu đã cắt ở 5 điểm (50%, 62%, 75%, 87%, 95% số phiên). Nếu tín hiệu ở một phiên trước điểm cắt thay đổi, hàm tín hiệu đã đọc dữ liệu tương lai.
Hàm tín hiệu Python của bạn:
def signal_fn(d):
up_tomorrow = d["close"].shift(-1) > d["close"] # đọc giá ngày mai
return up_tomorrow.astype(int).where(up_tomorrow, -1).tolist()
report = bt.check_causality(signal_fn, df)
print(report["passed"], report["mismatch_bars"])signal_fn(data) trả mảng [-1, 0, 1], tuple (entries, exits) hoặc dict. Kết quả gồm passed, mismatch_bars (vị trí phiên bị đổi tín hiệu), cuts và message. Ví dụ trên báo không đạt. Lỗi hay gặp:
shift(-1);- cửa sổ trượt đặt giữa (
center=True); - chuẩn hoá trên toàn mẫu (trừ trung bình, chia độ lệch chuẩn của cả chuỗi).
Bảng quy tắc:
report = bt.check_rule_dsl_causality(dsl, df)Mặc định execution="vn_realistic": tín hiệu tính ở giá đóng cửa phiên t khớp ở giá mở cửa phiên t+1. Đổi sang khớp ở giá đóng cửa của chính phiên t (execution_timing="same_close") là giả định lạc quan; chỉ dùng khi bạn biết rõ mình đang mô phỏng điều gì.
