1. Mengapa Perlunya Pengekstrakan Faktor Automatik
Jika anda pernah terlibat dalam perdagangan kuantitatif, pasti anda pernah mendengar istilah "faktor". Apa itu faktor? Secara mudahnya, ia adalah isyarat pasaran yang dinyatakan melalui data. Contohnya, momentum harga, volum dagangan tidak normal, kedudukan Bollinger Band — digunakan untuk meramalkan sama ada sesuatu syiling akan naik atau turun dalam tempoh masa akan datang.
Kedengaran mudah, tetapi mereka yang benar-benar menjalankan penyelidikan faktor tahu betapa sukarnya perkara ini:
Pengetahuan kewangan yang kukuh dan latar belakang statistik matematik yang mendalam
Data sejarah yang bersih dan banyak
Rangka kerja ujian semula yang ketat
Dan juga perlu menghadapi satu masalah yang tidak boleh dielakkan: Faktor akan mereput
Isyarat yang berkesan hari ini mungkin akan tidak berfungsi sepenuhnya beberapa hari kemudian — kerana peserta pasaran akan belajar, menyesuaikan diri, dan mengeksploitasi corak ini. Oleh itu, pengekstrakan faktor bukanlah tugas sekali sahaja, ia memerlukan lelaran berterusan.
Apa yang diperkenalkan dalam artikel ini adalah satu sistem yang mengautomasikan proses ini: melakukan kitaran lengkap pada selang masa tetap → pengekstrakan faktor → pengesahan → penyingkiran → sintesis isyarat → pesanan dagangan. Menggantikan ulangan manual dengan lelaran mesin, memastikan strategi sentiasa mengikuti rentak perubahan pasaran.
2. Rangka Kerja Keseluruhan Sistem
Proses pengekstrakan faktor tradisional adalah: penyelidik mengemukakan hipotesis → menulis kod → menjalankan ujian semula → penapisan → pelaksanaan → beberapa bulan kemudian mendapati ia tidak berkesan → ulang semula. Keseluruhan kitaran mungkin mengambil masa beberapa minggu atau bulan.
Sistem ini memampatkan keseluruhan kitaran untuk dilaksanakan secara automatik pada selang masa tetap:
| Langkah | Modul | Penerangan |
|---|---|---|
| Langkah 1 | Dapatkan kolam sasaran | Tapis kontrak kekal dengan kecairan tinggi mengikut volum dagangan, mengesan keadaan pasaran |
| Langkah 2 | Periksa kolam faktor | Analisis kesihatan faktor semasa, tentukan arah penerokaan pusingan ini |
| Langkah 3 | AI jana faktor | Dalam rangka kerja kekangan, biarkan AI jana calon faktor dimensi baharu |
| Langkah 4 | Pengesahan IC | Gunakan data sejarah untuk mengira pekali maklumat, singkirkan faktor tidak berkesan |
| Langkah 5 | Penapisan korelasi & penyingkiran terbawah | Buang faktor yang bertindih maklumat, pastikan kolam faktor tepat dan tidak terlalu banyak |
| Langkah 6 | Sintesis isyarat & pesanan | Sintesis skor wajaran, isyarat melebihi ambang mencetuskan pelaksanaan penyusunan semula |
Sistem ini digerakkan oleh dua penjadual: Pencetus perlahan melaksanakan satu kitaran lengkap lelaran faktor pada tahap jam; Pencetus pantas meninjau status pegangan pada tahap saat, mengendalikan ambil untung henti rugi dan muat semula papan pemuka.
3. Perincian Setiap Modul & Kod Teras
3.1 Dapatkan Kolam Sasaran
Pada permulaan setiap pusingan, sistem mengambil data pasaran masa nyata semua kontrak kekal dari bursa, menyusun mengikut volum dagangan dan mengambil N teratas. Kecairan adalah prasyarat untuk keberkesanan faktor — syiling kecil dengan volum dagangan jarang, sebarang isyarat mudah diherotkan.
Pada masa yang sama, mengesan persentil volatiliti sejarah baris 4 jam BTC, menentukan keadaan pasaran keseluruhan (normal / high_vol / low_vol / volatile). Penentuan ini akan secara langsung mempengaruhi kecenderungan arah AI dalam menjana faktor.
javascript
// Tapis sasaran kecairan tinggi mengikut volum dagangan
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));
// Kesan persentil volatiliti BTC, tentukan keadaan pasaran
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;
// Bandingkan dengan volatiliti sejarah penuh, tentukan kuantil
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 Periksa Status Kolam Faktor
Sebelum membiarkan AI menjana faktor baharu, sistem terlebih dahulu memeriksa status kesihatan kolam faktor semasa: faktor mana yang baru-baru ini IC menurun secara berterusan (mereput), dimensi mana yang belum diliputi. Maklumat ini akan dihantar terus sebagai kekangan kepada AI, mengelakkan penerokaan berulang arah yang sudah tidak berkesan.
javascript
const factorPool = JSON.parse(_G('afi_factorPool') || '[]');
const icHistory = JSON.parse(_G('afi_icHistory') || '{}');
const icDecayWindow = $vars.icDecayWindow || 48; // Panjang tetingkap terkini
const icDecayThreshold = $vars.icDecayThreshold || -0.01; // Ambang penentuan reputan
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
});
}
}
// Tentukan secara dinamik bilangan faktor baharu yang perlu diterokai dalam pusingan ini
const explorationBuffer = $vars.explorationBuffer || 3;
const explorationCount = Math.max(
explorationBuffer,
targetFactorCount - validCount + explorationBuffer
);
const action = factorPool.length === 0 ? 'generate_initial' : 'iterate_factors';
3.3 Bina Prompt, Biarkan AI Cipta Faktor
AI tidak menerima tugasan terbuka, tetapi rangka kerja dengan kekangan. Prompt mengandungi: keadaan pasaran semasa, senarai faktor sedia ada (larangan ulangan), faktor reput terkini (larangan penalaan halus), dimensi yang telah diliputi, dimensi yang belum diterokai.
Calon faktor yang dijana dengan cara ini adalah percubaan sebenar ke arah dimensi baharu, bukan semata-mata menjalankan semula faktor sedia ada dengan parameter berbeza.
javascript
// Coreg segmen Prompt corak lelaran
const usedDimensions = factorPool
.map(f => f.name + '(' + (f.rationale || '') + ')')
.join(', ') || 'Tiada buat masa ini';
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 sejarah=' + avg + ' IC terkini=' + recent + ' | Logik: ' + f.rationale;
}).join('\n') || 'Tiada buat masa ini';
const degradedSummary = degradedFactors.length > 0
? degradedFactors.map(f =>
f.name + ': IC terkini=' + f.recentIC + ' | Logik asal: ' + f.rationale
).join('\n')
: 'Tiada faktor penurunan dalam pusingan ini';
prompt += '【Faktor Sah Semasa (tidak perlu hasilkan varian)】\n' + validSummary + '\n\n';
prompt += '【Faktor Penurunan Terkini (dilarang tweak pada dimensi ini)】\n' + degradedSummary + '\n\n';
prompt += '【Dimensi Telah Diliputi (dilarang ulang)】\n' + usedDimensions + '\n\n';
prompt += '【Dimensi Belum Diterokai (utamakan pilih dari sini)】\n' + unusedSample + '\n\n';
prompt += 'Hasilkan ' + explorationCount + ' faktor arah baharu sepenuhnya:\n';
prompt += '1. Mestilah berbeza sama sekali dengan dimensi yang telah diliputi, dilarang tweak faktor yang telah gagal\n';
prompt += '2. Utamakan pilih dari dimensi yang belum diterokai\n';
prompt += '3. Utamakan reka bentuk faktor gabungan bukan linear\n';
prompt += '4. Reka bentuk untuk keadaan pasaran ' + marketState + ' semasa\n';
System Prompt AI telah menyertakan spesifikasi fungsi platform Inventor TA yang lengkap, kekangan format kod, pengetahuan awal pasaran kripto, serta senarai semua dimensi faktor yang boleh diterokai (kandungan penuh dalam kod sumber strategi). Format output adalah JSON tulen secara ketat (tanpa pembalut Markdown):
json
{
"factors": [
{
"name": "MomentumAcceleration",
"rationale": "Pecutan momentum jangka pendek, menangkap titik perubahan inersia mengejar kenaikan pelabur runcit",
"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 Pengesahan IC: Data Bercakap, Bukan Gerak Hati
IC (Pekali Maklumat, Information Coefficient) mengukur: korelasi antara kedudukan keratan rentas yang dikira menggunakan faktor dan kedudukan peratus perubahan harga sebenar bar K seterusnya. Semakin tinggi IC, semakin tepat ramalan faktor tersebut.
Kaedah pengesahan adalah Walk-Forward: gunakan beberapa ratus bar K lepas, pada setiap titik masa t, kira nilai faktor menggunakan data pada masa t-1 untuk meramalkan kenaikan/penurunan bar K ke-t. Penjajaran masa adalah ketat, tiada fungsi masa depan.
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];
// guna data tempoh t-1 untuk kira faktor (slice(0, t) tidak termasuk bar K ke-t)
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 });
// ramal pulangan sebenar bar K ke-t
nRets.push({
sym,
ret: (fullRecords[t].Close - fullRecords[t-1].Close) / fullRecords[t-1].Close
});
}
if (fVals.length < 8) continue;
// Kira Rank IC (Pekali Korelasi 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 };
}
Ambang IC dikawal oleh pembolehubah
$vars.icThreshold, lalai 0.02. Ini adalah ambang permulaan yang agak longgar, sesuai untuk menapis dengan cepat faktor yang jelas tidak berkesan; jika kawalan signifikan statistik yang lebih ketat diperlukan, nilai ini boleh dinaikkan berdasarkan situasi sebenar. Faktor yang tidak melepasi ambang, tidak kira betapa sempurnanya logik, akan ditolak terus.
3.5 Penapisan Korelasi & Penyingkiran Terbawah
Faktor yang lulus pengesahan IC masih perlu melalui dua peringkat:
Peringkat pertama: Penapisan Korelasi. Jika skor keratan rentas dua faktor adalah sangat serupa (|corr| > ambang), simpan faktor dengan IC yang lebih tinggi, buang yang satu lagi. Seperti dua undi yang mewakili idea orang yang sama, gabungkan menjadi satu undi sudah memadai, lebih satu undi tidak bermakna lebih satu pandangan.
Peringkat kedua: Penyingkiran Terbawah. Kolam faktor mempunyai had kapasiti maksimum, bahagian yang melebihi had akan disusun mengikut prestasi, yang paling teruk akan disingkirkan. Faktor yang IC terkini terus menurun akan mengambil bahagian dalam kedudukan menggunakan IC terkini dan bukannya purata IC sejarah, menanggung tekanan penyingkiran yang lebih besar.
javascript
// 相关性过滤(保留 IC 最高的,丢弃高度相关的冗余因子)
const corrThreshold = $vars.corrThreshold || 0.7;
survivedFactors.sort((a, b) => b.icAvg - a.icAvg); // 先按 IC 降序排列
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) {
// 记录被吸收的相关因子(仪表板展示用)
selected.corrGroup = (selected.corrGroup ? selected.corrGroup + ',' : '')
+ factor.name;
isRedundant = true;
break;
}
}
if (!isRedundant) decorrelatedFactors.push({ ...factor, corrGroup: '' });
}
// 末位淘汰:衰减因子用近期 IC 而非历史均值参与排名
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));
Catatan: Pengiraan korelasi adalah berdasarkan skor faktor keratan rentas semasa, yang kadangkala boleh menyebabkan tersalah nilai secara tidak sengaja. Amalan yang lebih mantap ialah mengambil purata korelasi dari pelbagai keratan rentas sejarah, dan ini adalah arah penambahbaikan yang boleh dilakukan pada masa hadapan.
3.6 Sintesis Isyarat dan Pelaksanaan Pelarasan Portfolio
Selepas kumpulan faktor stabil, sistem mengira skor komposit untuk setiap aset: menormalisasikan nilai keratan rentas setiap faktor menggunakan Z-score, kemudian menggabungkan dengan pemberat berdasarkan IC terkini masing-masing – faktor yang menunjukkan prestasi lebih baik mendapat bahagian yang lebih besar, dan faktor dengan IC terkini negatif akan ditetapkan pemberatnya kepada sifar.
javascript
// 因子权重:近期 IC 加权(负 IC 因子权重置零)
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 → 权重为 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);
// 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;
}
// 合成评分
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;
}
// 阈值过滤:信号模糊的直接跳过,不入场
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);
Semasa melaksanakan pelarasan portfolio, terlebih dahulu tutup kedudukan lama yang tidak berada dalam senarai pusingan ini, kemudian buka isyarat baru secara berkadar dengan ekuiti akaun:
javascript
const positionRatio = $vars.positionRatio || 0.8; // 总权益使用比例
const maxLeverage = $vars.maxLeverage || 3;
const account = exchange.GetAccount();
const equity = account.Equity || account.Balance;
const perAmt = (equity * positionRatio) / (longList.length + shortList.length);
// 平掉不在目标集合里的旧仓位
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));
// 清除止盈追踪状态
const cm = sym.match(/^(.+)_USDT/);
if (cm) { _G(cm[1] + '_maxpnl', null); _G(cm[1] + '_trail', null); }
}
}
// 开入新信号仓位(使用市价单,-1 表示市价)
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 Pemantauan Kedudukan: Henti Rugi / Ambil Untung / Ambil Untung Bergerak Dinamik
Pencetus cepat berjalan setiap saat, memantau status untung rugi terapung semua kedudukan secara masa nyata, dan melaksanakan tiga logik keluar:
- Henti rugi tetap: rugi terapung melebihi
STOP_LOSS_PCT(lalai 5%) ditutup secara automatik - Ambil untung tetap: untung terapung melebihi
TAKE_PROFIT_PCT(lalai 10%) ditutup secara automatik - Ambil untung bergerak dinamik: diaktifkan selepas untung terapung mencapai
TRAIL_TRIGGER(3%), ambang pengunduran diselaraskan secara dinamik mengikut untung terapung maksimum
javascript
const STOP_LOSS_PCT = $vars.stopLossPct || 5;
const TAKE_PROFIT_PCT = $vars.takeProfitPct || 10;
const TRAIL_TRIGGER = 3; // 浮盈达到 3% 后启动移动止盈
// 动态回撤阈值:最高浮盈越高,允许的回撤空间越大
function getDynamicTrailDrawdown(maxPnl) {
if (maxPnl >= 7) return 3; // 最高盈利 ≥7%,允许回撤 3%
if (maxPnl >= 4) return 2; // 最高盈利 ≥4%,允许回撤 2%
return 1.5; // 其他情况,回撤 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;
// 追踪最高浮盈
let maxPnl = _G(coin + '_maxpnl');
if (maxPnl === null) { maxPnl = pnlPct; _G(coin + '_maxpnl', maxPnl); }
else if (pnlPct > maxPnl) { maxPnl = pnlPct; _G(coin + '_maxpnl', maxPnl); }
// 启动移动止盈
if (!_G(coin + '_trail') && maxPnl >= TRAIL_TRIGGER) {
_G(coin + '_trail', true);
Log(coin + ' 启动移动止盈,浮盈: +' + pnlPct.toFixed(2) + '%');
}
const trailDrawdown = getDynamicTrailDrawdown(maxPnl);
let reason = null;
if (_G(coin + '_trail') && (maxPnl - pnlPct) >= trailDrawdown)
reason = '移动止盈(回撤 ' + (maxPnl - pnlPct).toFixed(2) + '%, 阈值 ' + trailDrawdown + '%)';
if (!reason && pnlPct <= -STOP_LOSS_PCT) reason = '止损(' + pnlPct.toFixed(2) + '%)';
if (!reason && pnlPct >= TAKE_PROFIT_PCT) reason = '止盈(' + pnlPct.toFixed(2) + '%)';
if (reason) {
exchange.CreateOrder(pos.Symbol, isLong ? 'closebuy' : 'closesell', -1, amt);
Log(coin, '触发', reason);
_G(coin + '_maxpnl', null); _G(coin + '_trail', null);
}
}
}
4. Keputusan Reka Bentuk Utama
4.1 Mengapa Menggunakan Rank IC (bukan Pearson IC)
Rank IC menggunakan kedudukan dan bukannya nilai asal untuk mengira korelasi, secara semula jadi teguh terhadap nilai ekstrem (pencilan) dalam faktor. Taburan harga pasaran kripto mempunyai ekor tebal yang teruk, Pearson IC mudah diputarbelitkan oleh beberapa lilin K yang ekstrem, manakala Rank IC lebih stabil.
4.2 Penjajaran Masa Tegas, Menghapuskan Fungsi Masa Depan
Pengesahan IC dan pengiraan isyarat dalam talian kedua-duanya menggunakan nilai faktor tempoh t-1 untuk meramalkan pulangan tempoh t: semasa pengesahan, records dihantar sebagai fullRecords.slice(0, t), memotong data masa hadapan pada peringkat fizikal, supaya kod faktor yang dijana AI, walau bagaimanapun ia merujuk records[n], hanya mengakses sejarah sehingga t-1; dalam talian, lilin K terakhir dikeluarkan (slice(0, n-1)) untuk mengira nilai faktor, meramalkan kenaikan atau penurunan lilin K seterusnya. Kedua-dua logik adalah sama sepenuhnya, mengelakkan IC yang terlalu tinggi akibat melihat data masa hadapan.
4.3 Pemberat IC Terkini, Pemberat Menyesuaikan Diri dengan Pasaran
Pemberat faktor tidak tetap, tetapi akan dilaraskan secara dinamik berdasarkan IC terkini. Apabila sesuatu faktor mula gagal (penurunan IC terkini), pemberatnya dalam penggabungan isyarat akan berkurangan secara automatik sehingga menjadi sifar. Sistem dapat melaksanakan pengimbangan semula pemberat tanpa campur tangan manusia.
4.4 Seni Bina Pencetus Berganda
Iterasi faktor adalah tugas pengiraan semula yang berat (pengambilan K-line + backtest IC + panggilan AI), cukup untuk dilaksanakan sekali setiap jam; perlindungan pegangan adalah tugas yang sensitif terhadap masa dan memerlukan respons dalam beberapa saat. Membahagikan kedua-duanya kepada pencetus dengan kekerapan berbeza mengelakkan penyekatan bersama.
5. Pemerhatian Dagangan Sebenar: Proses Iterasi Faktor
Selepas dua hari dagangan sebenar, fenomena berikut diperhatikan:
- Faktor yang dimasukkan ke dalam kumpulan pada peringkat awal secara amnya mempunyai IC sejarah antara 0.04 hingga 0.07, melepasi ambang asas.
- Apabila lelaran berjalan, IC terkini hampir semua faktor menurun, ada yang jatuh dari 0.06 ke 0.008, ada yang jatuh ke nilai negatif. Ini menunjukkan bahawa isyarat yang ditangkap oleh faktor-faktor ini sedang gagal dalam persekitaran pasaran semasa.
- Selepas sistem mengesan kemerosotan, dalam pusingan seterusnya ia mengutamakan penerokaan dimensi yang belum diliputi untuk mencari faktor calon baharu untuk menggantikannya. Keseluruhan proses tidak memerlukan campur tangan manusia.
Tempoh dua hari terlalu singkat untuk mengesahkan sepenuhnya sama ada keupayaan penyesuaian sistem adalah benar dan berkesan. Di sini hanya direkodkan bahawa sistem melaksanakan tindakan lelaran seperti yang dijangkakan. Kesimpulan yang lebih bermakna memerlukan pemerhatian berterusan dalam tempoh yang lebih panjang. Walau bagaimanapun, proses itu sendiri telah menunjukkan logik asas reka bentuk sistem berfungsi: ia tidak akan bertahan dengan isyarat yang gagal, tetapi akan terus mencuba dimensi baharu.
6. Penutup
Membina sistem ini bukan untuk membuktikan bahawa AI dapat mengatasi pasaran. Sebaliknya, ia untuk mengatakan bahawa dalam era AI ini, banyak perkara yang pada masa lalu hanya boleh dicapai oleh institusi terkemuka, kini orang biasa juga berpeluang mencuba.
Perlombongan faktor, lelaran strategi, pelaksanaan automatik – perkara yang dahulunya memerlukan satu pasukan, infrastruktur data yang besar dan pengalaman bertahun-tahun untuk dibina, kini boleh dijalankan dengan aliran kerja.
Ini tidak bermakna ia akan menjana keuntungan yang stabil. Pasaran sentiasa lebih kompleks daripada mana-mana sistem. Tetapi ia bermakna halangan semakin rendah, alatan semakin kuat, dan kemungkinan bagi orang biasa untuk mengambil bahagian semakin besar.
⚠️ Amaran Risiko: Mana-mana strategi mempunyai risiko kerugian. Kandungan artikel ini hanya untuk rujukan pembelajaran teknikal dan tidak membentuk nasihat pelaburan. Sila pastikan ujian menyeluruh sebelum dagangan sebenar.
Kod Sumber Strategi: Versi Ujian Strategi Kuantitatif Perlombongan Faktor Adaptif
- 1


