Type/to search
2
Follow
484
Followers
多因子策略不是大厂专属:独立quant的研究框架
Discussions
Created 2026-03-27 15:05:12  Updated 2026-03-31 18:40:35
 0
 397

img

1. Tại sao cần khai thác yếu tố tự động

Nếu bạn đã từng tiếp xúc với giao dịch định lượng, chắc hẳn bạn đã nghe đến từ "yếu tố". Yếu tố là gì? Nói một cách đơn giản, đó là một tín hiệu thị trường được biểu diễn bằng dữ liệu. Ví dụ như động lượng giá, khối lượng giao dịch bất thường, vị trí Bollinger Bands – dùng để dự đoán trong khoảng thời gian tới một đồng coin nào đó sẽ tăng hay giảm.

Nghe thì có vẻ đơn giản, nhưng ai đã từng nghiên cứu yếu tố thực sự đều biết việc này khó đến mức nào:

Kiến thức tài chính vững chắcnền tảng thống kê toán học sâu rộng
Dữ liệu lịch sử sạch sẽ và đầy đủ
Khung backtest nghiêm ngặt

Và còn phải đối mặt với một vấn đề không thể tránh khỏi: yếu tố sẽ suy giảm

Tín hiệu hiệu quả hôm nay, vài ngày sau có thể trở nên vô dụng hoàn toàn – bởi vì những người tham gia thị trường sẽ học hỏi, thích nghi, và khai thác lợi nhuận từ quy luật này. Vì vậy, khai thác yếu tố không phải là công việc một lần, nó cần được cải tiến liên tục.

Bài viết này giới thiệu một hệ thống tự động hóa quy trình này: lặp lại hoàn chỉnh quy trình khai thác yếu tố theo chu kỳ cố định → xác minh → loại bỏ → tổng hợp tín hiệu → đặt lệnh giao dịch. Sử dụng máy móc để thay thế việc lặp lại thủ công, giúp chiến lược luôn theo kịp nhịp độ thay đổi của thị trường.

img


2. Kiến trúc tổng thể của hệ thống

Quy trình khai thác yếu tố truyền thống là: nhà nghiên cứu đưa ra giả thuyết → viết code → chạy backtest → sàng lọc → đưa vào vận hành → vài tháng sau phát hiện mất hiệu quả → làm lại từ đầu. Toàn bộ chu kỳ có thể mất vài tuần hoặc thậm chí vài tháng.

Hệ thống này nén toàn bộ vòng lặp thành một lần tự động thực thi theo khoảng thời gian cố định:

BướcMô-đunMô tả
Bước 1Lấy danh sách tài sản mục tiêuSàng lọc hợp đồng vĩnh viễn có thanh khoản cao theo khối lượng giao dịch, phát hiện trạng thái thị trường
Bước 2Kiểm tra danh sách yếu tốPhân tích sức khỏe hiện tại của các yếu tố, xác định hướng khám phá trong vòng này
Bước 3AI tạo yếu tốTrong khuôn khổ ràng buộc, để AI tạo ra các yếu tố ứng viên mới
Bước 4Xác minh ICTính toán hệ số thông tin (IC) bằng dữ liệu lịch sử, loại bỏ các yếu tố không hiệu quả
Bước 5Lọc tương quan & loại bỏ cuối cùngLoại bỏ các yếu tố trùng lặp thông tin, giữ cho danh sách yếu tố tinh gọn
Bước 6Tổng hợp tín hiệu & đặt lệnhTổng hợp điểm số có trọng số, khi tín hiệu vượt ngưỡng sẽ kích hoạt điều chỉnh danh mục

Hệ thống được điều khiển bởi hai bộ lập lịch: Bộ kích hoạt chậm thực thi một quy trình lặp yếu tố hoàn chỉnh ở cấp độ giờ; Bộ kích hoạt nhanh ở cấp độ giây kiểm tra trạng thái vị thế, xử lý chốt lời cắt lỗ và làm mới bảng điều khiển.


3. Chi tiết từng mô-đun và mã nguồn cốt lõi

3.1 Lấy danh sách tài sản mục tiêu

Mỗi vòng, hệ thống kéo dữ liệu thị trường thời gian thực của tất cả các hợp đồng vĩnh viễn từ sàn giao dịch, sắp xếp theo khối lượng giao dịch và lấy N hàng đầu. Tính thanh khoản là tiền đề cho hiệu quả của yếu tố – các đồng coin nhỏ có khối lượng giao dịch thưa thớt, mọi tín hiệu đều dễ bị méo mó.

Đồng thời, phát hiện phân vị biến động giá của BTC trên khung 4 giờ, đánh giá trạng thái tổng thể của thị trường (bình thường / biến động cao / biến động thấp / biến động mạnh), đánh giá này sẽ ảnh hưởng trực tiếp đến hướng ưu tiên của các yếu tố do AI tạo ra.

javascript
// Sàng lọc tài sản có thanh khoản cao theo khối lượng giao dịch const topN = $vars.topN || 150; const tickers = exchange.GetTickers(); const filtered = tickers .filter(t => t.Symbol.endsWith('USDT.swap')) .map(t => ({ symbol: t.Symbol, quoteVolume: t.Last * t.Volume })) .sort((a, b) => b.quoteVolume - a.quoteVolume) .slice(0, topN) .map(t => t.symbol); _G('afi_symbolPool', JSON.stringify(filtered)); // Phát hiện phân vị biến động BTC, đánh giá trạng thái thị trường const btcR = exchange.GetRecords('BTC_USDT.swap', PERIOD_H4); const n = btcR.length; const returns20 = []; for (let i = n - 20; i < n; i++) returns20.push(Math.abs((btcR[i].Close - btcR[i-1].Close) / btcR[i-1].Close)); const avgVol = returns20.reduce((a, b) => a + b, 0) / returns20.length; // So sánh với biến động toàn bộ lịch sử để xác định phân vị const allVols = []; for (let i = 1; i < n; i++) allVols.push(Math.abs((btcR[i].Close - btcR[i-1].Close) / btcR[i-1].Close)); allVols.sort((a, b) => a - b); let btcVolPercentile = allVols.findIndex(v => v >= avgVol) / allVols.length; let marketState = 'normal'; if (btcVolPercentile > 0.8) marketState = 'high_vol'; else if (btcVolPercentile < 0.3) marketState = 'low_vol'; _G('afi_marketState', marketState); _G('afi_btcVolPct', btcVolPercentile.toFixed(2));

3.2 Kiểm tra trạng thái danh sách yếu tố

Trước khi để AI tạo ra yếu tố mới, hệ thống trước tiên đánh giá tình trạng sức khỏe của danh sách yếu tố hiện tại: yếu tố nào có IC gần đây liên tục giảm (suy giảm), chiều hướng nào chưa được bao phủ. Những thông tin này sẽ được truyền trực tiếp dưới dạng điều kiện ràng buộc cho AI, tránh khám phá lại các hướng đã mất hiệu quả.

javascript
const factorPool = JSON.parse(_G('afi_factorPool') || '[]'); const icHistory = JSON.parse(_G('afi_icHistory') || '{}'); const icDecayWindow = $vars.icDecayWindow || 48; // Độ dài cửa sổ gần đây const icDecayThreshold = $vars.icDecayThreshold || -0.01; // Ngưỡng đánh giá suy giảm const targetFactorCount = $vars.targetFactorCount || 10; const degradedFactors = []; for (const factor of factorPool) { const icArr = icHistory[factor.name] || []; if (icArr.length >= 20) { const window = Math.min(icArr.length, icDecayWindow); const recentAvg = icArr.slice(-window).reduce((a, b) => a + b, 0) / window; if (recentAvg < icDecayThreshold) degradedFactors.push({ name: factor.name, recentIC: recentAvg.toFixed(4), rationale: factor.rationale }); } } // Xác định động số yếu tố mới cần khám phá trong vòng này const explorationBuffer = $vars.explorationBuffer || 3; const explorationCount = Math.max( explorationBuffer, targetFactorCount - validCount + explorationBuffer ); const action = factorPool.length === 0 ? 'generate_initial' : 'iterate_factors';

3.3 Xây dựng Prompt, để AI phát minh yếu tố

AI không nhận được một nhiệm vụ mở, mà là một khuôn khổ có ràng buộc. Prompt bao gồm: trạng thái thị trường hiện tại, danh sách các yếu tố đã có (cấm trùng lặp), các yếu tố suy giảm gần đây (cấm tinh chỉnh), các chiều hướng đã bao phủ, các chiều hướng chưa được khám phá.

Các yếu tố ứng viên được tạo ra theo cách này mới thực sự là những nỗ lực hướng tới các hướng mới, chứ không phải chỉ chạy lại các tham số khác nhau trên các yếu tố đã có.

javascript
// 迭代模式 Prompt 关键片段 const usedDimensions = factorPool .map(f => f.name + '(' + (f.rationale || '') + ')') .join(', ') || '暂无'; const validSummary = validFactors.map(f => { const arr = icHistory[f.name] || []; const avg = arr.length > 0 ? (arr.reduce((a,b) => a+b, 0) / arr.length).toFixed(4) : 'N/A'; const recent = arr.length >= 20 ? (arr.slice(-20).reduce((a,b) => a+b, 0) / 20).toFixed(4) : 'N/A'; return f.name + ': 历史IC=' + avg + ' 近期IC=' + recent + ' | 逻辑: ' + f.rationale; }).join('\n') || '暂无'; const degradedSummary = degradedFactors.length > 0 ? degradedFactors.map(f => f.name + ': 近期IC=' + f.recentIC + ' | 原逻辑: ' + f.rationale ).join('\n') : '本轮无衰减因子'; prompt += '【当前有效因子(不需要生成变体)】\n' + validSummary + '\n\n'; prompt += '【近期衰减因子(禁止在这些维度上微调)】\n' + degradedSummary + '\n\n'; prompt += '【已覆盖维度(禁止重复)】\n' + usedDimensions + '\n\n'; prompt += '【尚未探索的维度(优先从这里选)】\n' + unusedSample + '\n\n'; prompt += '生成 ' + explorationCount + ' 个全新方向因子:\n'; prompt += '1. 必须与已覆盖维度完全不同,禁止微调失效因子\n'; prompt += '2. 优先从尚未探索的维度中选取\n'; prompt += '3. 优先设计非线性组合因子\n'; prompt += '4. 针对当前 ' + marketState + ' 市场状态设计\n';

System Prompt của AI được tích hợp sẵn toàn bộ đặc tả hàm TA của nền tảng Inventor, ràng buộc định dạng mã, kiến thức tiên nghiệm về thị trường tiền mã hóa, cũng như danh sách tất cả các chiều yếu tố có thể khám phá (nội dung đầy đủ xem mã nguồn chiến lược). Định dạng đầu ra nghiêm ngặt là JSON thuần (không có Markdown bao bọc):

json
{ "factors": [ { "name": "MomentumAcceleration", "rationale": "短期动量加速度,捕捉散户追涨惯性拐点", "code": "(records[n-1].Close - records[n-6].Close)/records[n-6].Close - (records[n-2].Close - records[n-7].Close)/(records[n-7].Close + 0.0001)", "direction": 1, "type": "exploration" } ] }

3.4 Xác thực IC: Dữ liệu lên tiếng, không dựa vào trực giác

IC (Information Coefficient) đo lường: mức độ tương quan giữa thứ hạng cắt ngang tính từ yếu tố và thứ hạng biến động thực tế của nến tiếp theo. IC càng cao, dự đoán của yếu tố càng chính xác.

Phương pháp xác thực là Walk-Forward: lấy vài trăm nến trong quá khứ, tại mỗi điểm thời gian t, tính giá trị yếu tố bằng dữ liệu thời điểm t-1 để dự đoán biến động của nến thứ t. Thứ tự thời gian được căn chỉnh nghiêm ngặt, loại bỏ hoàn toàn future function.

javascript
function calcRankICFull(code, symRecords, factorName) { const syms = Object.keys(symRecords); const icList = []; const minLen = 30; const allLengths = syms.map(s => symRecords[s].length); const minSymLen = Math.min(...allLengths); const testLen = Math.min(500, minSymLen - 1); for (let t = minLen; t < testLen; t++) { const fVals = [], nRets = []; for (const sym of syms) { const fullRecords = symRecords[sym]; // 用 t-1 期数据计算因子(slice(0, t) 不包含第 t 根 K 线) const records = fullRecords.slice(0, t); const n = records.length; const v = (function() { return eval(code); })(); if (isNaN(v) || !isFinite(v)) continue; fVals.push({ sym, val: v }); // 预测第 t 根 K 线的真实收益 nRets.push({ sym, ret: (fullRecords[t].Close - fullRecords[t-1].Close) / fullRecords[t-1].Close }); } if (fVals.length < 8) continue; // 计算 Rank IC(Spearman 相关系数) const fRank = {}, rRank = {}; [...fVals].sort((a,b) => a.val - b.val).forEach((x,i) => fRank[x.sym] = i); [...nRets].sort((a,b) => a.ret - b.ret).forEach((x,i) => rRank[x.sym] = i); const ss = fVals.map(x => x.sym); const fr = ss.map(s => fRank[s]); const rr = ss.map(s => rRank[s]); const n2 = ss.length; const fm = fr.reduce((a,b) => a+b, 0) / n2; const rm = rr.reduce((a,b) => a+b, 0) / n2; const num = fr.map((f,i) => (f-fm) * (rr[i]-rm)).reduce((a,b) => a+b, 0); const den = Math.sqrt( fr.map(f => (f-fm)**2).reduce((a,b) => a+b, 0) * rr.map(r => (r-rm)**2).reduce((a,b) => a+b, 0) ); if (den > 0) icList.push(num / den); } const avgIC = icList.length > 0 ? icList.reduce((a,b) => a+b, 0) / icList.length : 0; return { avgIC, icList }; }

Ngưỡng IC được kiểm soát bởi biến $vars.icThreshold, mặc định là 0.02. Đây là ngưỡng đầu vào tương đối lỏng, phù hợp để nhanh chóng loại bỏ các yếu tố rõ ràng không hiệu quả; nếu cần kiểm soát ý nghĩa thống kê chặt chẽ hơn, có thể điều chỉnh tăng giá trị này tùy theo tình huống thực tế. Các yếu tố không đạt ngưỡng, dù logic có hoàn hảo đến đâu, cũng bị loại trực tiếp.


3.5 Lọc tương quan & Loại trừ cuối bảng

Các yếu tố vượt qua xác thực IC vẫn phải trải qua hai bước kiểm tra:

Bước thứ nhất: Lọc tương quan. Nếu điểm số cắt ngang của hai yếu tố có độ tương đồng cao (|corr| > ngưỡng), giữ lại yếu tố có IC cao hơn, loại bỏ yếu tố kia. Giống như hai phiếu bầu thực chất là cùng một ý tưởng, chỉ cần gộp thành một phiếu, thêm một phiếu không thêm một quan điểm.

Bước thứ hai: Loại trừ cuối bảng. Nhóm yếu tố có giới hạn sức chứa, nếu vượt quá sẽ sắp xếp theo hiệu suất, yếu tố kém nhất bị loại. Các yếu tố có IC gần đây liên tục suy giảm sẽ tham gia xếp hạng với IC gần đây thay vì IC trung bình lịch sử, chịu áp lực loại trừ lớn hơn.

javascript
// Lọc tương quan (giữ lại yếu tố có IC cao nhất, loại bỏ các yếu tố dư thừa có tương quan cao) const corrThreshold = $vars.corrThreshold || 0.7; survivedFactors.sort((a, b) => b.icAvg - a.icAvg); // Sắp xếp giảm dần theo IC trước const decorrelatedFactors = []; for (const factor of survivedFactors) { let isRedundant = false; for (const selected of decorrelatedFactors) { const corr = Math.abs(calcCorrelation( factorScoresMap[factor.name], factorScoresMap[selected.name] )); if (corr > corrThreshold) { // Ghi lại các yếu tố tương quan bị hấp thụ (dành cho bảng điều khiển) selected.corrGroup = (selected.corrGroup ? selected.corrGroup + ',' : '') + factor.name; isRedundant = true; break; } } if (!isRedundant) decorrelatedFactors.push({ ...factor, corrGroup: '' }); } // Loại bỏ cuối cùng: yếu tố suy giảm dùng IC gần đây thay vì trung bình lịch sử để xếp hạng const targetFactorCount = $vars.targetFactorCount || 10; decorrelatedFactors.sort((a, b) => { const scoreA = a.isDecaying ? a.recentIC : a.icAvg; const scoreB = b.isDecaying ? b.recentIC : b.icAvg; return scoreB - scoreA; }); const finalPool = decorrelatedFactors.slice(0, targetFactorCount); _G('afi_factorPool', JSON.stringify(finalPool));

Lưu ý: Tính toán tương quan dựa trên điểm số yếu tố của mặt cắt hiện tại, đôi khi có thể có sai sót ngẫu nhiên. Cách ổn định hơn là lấy trung bình tương quan của nhiều mặt cắt lịch sử, đây là hướng cải thiện trong tương lai.


3.6 Tổng hợp tín hiệu và thực hiện điều chỉnh vị thế

Sau khi nhóm yếu tố ổn định, hệ thống tính điểm tổng hợp cho mỗi mã chứng khoán: chuẩn hóa Z-score giá trị mặt cắt của từng yếu tố, sau đó kết hợp trọng số theo IC gần đây của chúng – yếu tố hoạt động tốt hơn có tỷ trọng lớn hơn, yếu tố có IC gần đây âm sẽ có trọng số bằng 0.

javascript
// Trọng số yếu tố: trọng số IC gần đây (yếu tố IC âm có trọng số bằng 0) const weights = {}; let totalW = 0; for (const f of factorPool) { const arr = icHistory[f.name] || []; const recentArr = arr.slice(-48); const recentIC = recentArr.length > 0 ? recentArr.reduce((a,b) => a+b, 0) / recentArr.length : 0; const w = Math.max(0, recentIC); // IC âm → trọng số = 0 weights[f.name] = w; totalW += w; } if (totalW > 0) Object.keys(weights).forEach(k => weights[k] /= totalW); else factorPool.forEach(f => weights[f.name] = 1 / factorPool.length); // Chuẩn hóa Z-score function zscore(fname) { const vals = validSyms .map(s => ({ sym: s, val: rawMatrix[s][fname] })) .filter(x => x.val !== null); if (vals.length < 5) return {}; const mean = vals.reduce((a,b) => a + b.val, 0) / vals.length; const std = Math.sqrt(vals.reduce((a,b) => a + (b.val - mean)**2, 0) / vals.length); const r = {}; vals.forEach(x => r[x.sym] = std > 0 ? (x.val - mean) / std : 0); return r; } // Tổng hợp điểm số const scores = {}; for (const sym of validSyms) { let score = 0; for (const f of factorPool) { const z = zscore(f.name)[sym]; if (z !== undefined) score += weights[f.name] * f.direction * z; } scores[sym] = score; } // Lọc ngưỡng: tín hiệu mờ nhạt bỏ qua, không vào lệnh const longShortN = $vars.longShortN || 5; const longThreshold = $vars.longThreshold || 0.3; const shortThreshold = $vars.shortThreshold || -0.3; const sorted = Object.keys(scores).sort((a,b) => scores[b] - scores[a]); const longList = sorted.filter(s => scores[s] >= longThreshold).slice(0, longShortN); const shortList = sorted.slice().reverse() .filter(s => scores[s] <= shortThreshold).slice(0, longShortN);

Khi thực hiện điều chỉnh vị thế, trước tiên đóng các vị thế cũ không nằm trong danh sách hiện tại, sau đó mở vị thế mới theo tỷ lệ bằng nhau trên vốn chủ sở hữu tài khoản:

javascript
const positionRatio = $vars.positionRatio || 0.8; // Tỷ lệ sử dụng vốn chủ sở hữu const maxLeverage = $vars.maxLeverage || 3; const account = exchange.GetAccount(); const equity = account.Equity || account.Balance; const perAmt = (equity * positionRatio) / (longList.length + shortList.length); // Đóng các vị thế cũ không nằm trong tập mục tiêu const targetSet = new Set([...longList, ...shortList]); for (const sym of Object.keys(currentHoldings)) { if (!targetSet.has(sym)) { const pos = currentHoldings[sym]; const isLong = pos.Type === PD_LONG || pos.Type === 0; exchange.CreateOrder(sym, isLong ? 'closebuy' : 'closesell', -1, Math.abs(pos.Amount)); // Xóa trạng thái theo dõi chốt lời const cm = sym.match(/^(.+)_USDT/); if (cm) { _G(cm[1] + '_maxpnl', null); _G(cm[1] + '_trail', null); } } } // Mở vị thế mới theo tín hiệu (sử dụng lệnh thị trường, -1 là thị trường) function openPos(sym, isLong) { exchange.SetMarginLevel(sym, maxLeverage); const market = allMarkets[sym]; const price = exchange.GetTicker(sym).Last; const ctVal = (market.CtVal && market.CtVal > 0) ? market.CtVal : 1; const amtPrec = market.AmountPrecision !== undefined ? market.AmountPrecision : 0; const minQty = (market.MinQty && market.MinQty > 0) ? market.MinQty : 1; const maxQty = (market.MaxQty && market.MaxQty > 0) ? market.MaxQty : 999999; let qty = _N(perAmt / price / ctVal, amtPrec); qty = Math.min(Math.max(qty, minQty), maxQty); exchange.CreateOrder(sym, isLong ? 'buy' : 'sell', -1, qty); }

3.7 Giám sát vị thế: Cắt lỗ / Chốt lời / Chốt lời động di chuyển

Bộ kích hoạt nhanh chạy mỗi giây một lần, giám sát thời gian thực lợi nhuận thả nổi của tất cả vị thế, thực thi ba logic thoát lệnh:

  • Cắt lỗ cố định: Lỗ thả nổi vượt quá STOP_LOSS_PCT (mặc định 5%) tự động đóng vị thế
  • Chốt lời cố định: Lời thả nổi vượt quá TAKE_PROFIT_PCT (mặc định 10%) tự động đóng vị thế
  • Chốt lời động di chuyển: Kích hoạt sau khi lời thả nổi đạt TRAIL_TRIGGER (3%), ngưỡng rút lui được điều chỉnh động theo lời thả nổi tối đa
javascript
const STOP_LOSS_PCT = $vars.stopLossPct || 5; const TAKE_PROFIT_PCT = $vars.takeProfitPct || 10; const TRAIL_TRIGGER = 3; // Khởi động chốt lời động khi lời thả nổi đạt 3% // Ngưỡng rút lui động: lời tối đa càng cao, khoảng rút lui cho phép càng lớn function getDynamicTrailDrawdown(maxPnl) { if (maxPnl >= 7) return 3; // Lời tối đa ≥7%, cho phép rút lui 3% if (maxPnl >= 4) return 2; // Lời tối đa ≥4%, cho phép rút lui 2% return 1.5; // Các trường hợp khác, rút lui 1.5% } function monitorTPSL(positions, tickers) { for (const pos of (positions || [])) { if (Math.abs(pos.Amount) === 0) continue; const cm = pos.Symbol.match(/^(.+)_USDT/); if (!cm) continue; const coin = cm[1]; const ticker = tickers[coin + '_USDT.swap']; if (!ticker) continue; const isLong = pos.Type === PD_LONG || pos.Type === 0; const cur = ticker.Last; const ent = pos.Price; const amt = Math.abs(pos.Amount); const pnlPct = (cur - ent) * (isLong ? 1 : -1) / ent * 100; // Theo dõi lời thả nổi tối đa let maxPnl = _G(coin + '_maxpnl'); if (maxPnl === null) { maxPnl = pnlPct; _G(coin + '_maxpnl', maxPnl); } else if (pnlPct > maxPnl) { maxPnl = pnlPct; _G(coin + '_maxpnl', maxPnl); } // Khởi động chốt lời động if (!_G(coin + '_trail') && maxPnl >= TRAIL_TRIGGER) { _G(coin + '_trail', true); Log(coin + ' Khởi động chốt lời động, lời thả nổi: +' + pnlPct.toFixed(2) + '%'); } const trailDrawdown = getDynamicTrailDrawdown(maxPnl); let reason = null; if (_G(coin + '_trail') && (maxPnl - pnlPct) >= trailDrawdown) reason = 'Chốt lời động (rút lui ' + (maxPnl - pnlPct).toFixed(2) + '%, ngưỡng ' + trailDrawdown + '%)'; if (!reason && pnlPct <= -STOP_LOSS_PCT) reason = 'Cắt lỗ (' + pnlPct.toFixed(2) + '%)'; if (!reason && pnlPct >= TAKE_PROFIT_PCT) reason = 'Chốt lời (' + pnlPct.toFixed(2) + '%)'; if (reason) { exchange.CreateOrder(pos.Symbol, isLong ? 'closebuy' : 'closesell', -1, amt); Log(coin, 'Kích hoạt', reason); _G(coin + '_maxpnl', null); _G(coin + '_trail', null); } } }

4. Các quyết định thiết kế chính

4.1 Tại sao sử dụng Rank IC (thay vì Pearson IC)

Rank IC sử dụng thứ hạng thay vì giá trị gốc để tính tương quan, vốn có độ mạnh mẽ tự nhiên đối với các giá trị ngoại lai (điểm dị biệt) trong yếu tố. Phân phối giá thị trường tiền điện tử có đuôi dày nghiêm trọng, Pearson IC dễ bị bóp méo bởi một vài nến K cực đoan, trong khi Rank IC có tính ổn định cao hơn.

4.2 Căn chỉnh thời gian chặt chẽ, loại bỏ hàm tương lai

Cả xác minh IC và tính toán tín hiệu trực tuyến đều thống nhất sử dụng giá trị yếu tố kỳ t-1 để dự đoán lợi nhuận kỳ t: khi xác minh, records truyền vào fullRecords.slice(0, t), cắt bỏ dữ liệu tương lai ở cấp độ vật lý, dù mã yếu tố do AI tạo ra có tham chiếu records[n] thế nào thì dữ liệu truy cập được cũng chỉ là lịch sử tính đến t-1; khi trực tuyến, loại bỏ nến K cuối cùng (slice(0, n-1)) để tính giá trị yếu tố, dự đoán sự tăng giảm của nến K tiếp theo. Logic của cả hai hoàn toàn nhất quán, tránh tình trạng IC bị thổi phồng do nhìn thấy dữ liệu tương lai.

4.3 Trọng số IC gần đây, trọng số tự thích ứng với thị trường

Trọng số yếu tố không cố định mà được điều chỉnh động theo IC gần đây. Khi một yếu tố bắt đầu mất hiệu lực (IC gần đây giảm), trọng số của nó trong tổng hợp tín hiệu tự động giảm dần cho đến khi về 0, hệ thống có thể hoàn tất việc tái cân bằng trọng số mà không cần can thiệp thủ công.

4.4 Kiến trúc kích hoạt kép

Vòng lặp yếu tố là tác vụ tính toán nặng (kéo nến K + hồi quy IC + gọi AI), chỉ cần thực thi mỗi giờ một lần là đủ; bảo vệ vị thế là tác vụ nhạy cảm với thời gian, cần phản hồi ở mức giây. Tách hai tác vụ này thành các bộ kích hoạt với tần suất khác nhau để tránh xung đột lẫn nhau.


Năm, Quan sát thực chiến: Quá trình lặp yếu tố

Sau hai ngày chạy thực chiến, quan sát thấy hiện tượng sau:

  • Các yếu tố vào pool sớm, IC lịch sử thường nằm trong khoảng 0.04 đến 0.07, vượt qua ngưỡng cơ bản.
  • Khi quá trình lặp tiến triển, IC gần đây của hầu hết các yếu tố đều giảm, có cái từ 0.06 xuống 0.008, có cái rơi vào giá trị âm. Điều này cho thấy tín hiệu mà các yếu tố này bắt được đang mất hiệu lực trong môi trường thị trường hiện tại.
  • Sau khi hệ thống phát hiện sự suy giảm, vòng lặp tiếp theo ưu tiên khám phá các chiều chưa được bao phủ, tìm yếu tố ứng viên mới để thay thế. Toàn bộ quá trình không cần can thiệp thủ công.

img

Hai ngày là quá ngắn, chưa đủ để kiểm chứng đầy đủ khả năng thích ứng của hệ thống có thực sự hiệu quả hay không. Ở đây chỉ ghi nhận hệ thống đã thực hiện hành động lặp theo đúng kỳ vọng, kết luận có ý nghĩa hơn cần quan sát liên tục trong thời gian dài hơn. Nhưng bản thân quá trình này đã cho thấy logic thiết kế cơ bản của hệ thống đang vận hành: nó không bám chấp vào các tín hiệu mất hiệu lực, mà liên tục thử nghiệm các chiều mới.


Sáu, Lời kết

Xây dựng hệ thống này, không phải để chứng minh AI có thể đánh bại thị trường. Mà muốn nói rằng, trong thời đại AI này, nhiều điều trước đây chỉ có các tổ chức hàng đầu mới làm được, giờ đây người bình thường cũng có cơ hội thử nghiệm.

Khai thác yếu tố, lặp chiến lược, thực thi tự động – những thứ trước đây cần một đội ngũ, nhiều cơ sở hạ tầng dữ liệu và tích lũy vài năm mới dựng nổi, hôm nay có thể chạy chỉ với một quy trình làm việc.

Điều này không có nghĩa là nó sẽ tạo ra lợi nhuận ổn định. Thị trường luôn phức tạp hơn bất kỳ hệ thống nào. Nhưng nó có nghĩa là, rào cản đang giảm, công cụ đang mạnh lên, khả năng người bình thường tham gia vào việc này đang tăng lên.

⚠️ Cảnh báo rủi ro: Bất kỳ chiến lược nào cũng có rủi ro thua lỗ, nội dung bài viết này chỉ mang tính tham khảo kỹ thuật học tập, không cấu thành lời khuyên đầu tư. Trước khi giao dịch thực tế, hãy đảm bảo kiểm tra đầy đủ.

Mã nguồn chiến lược: Phiên bản thử nghiệm chiến lược định lượng khai thác yếu tố thích ứng

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