[TOC]

Dengan pesatnya perkembangan teknologi kecerdasan buatan (AI), telah menunjukkan efisiensi dan kreativitas yang sangat tinggi di banyak bidang. Sebagai bidang yang sangat teknis, perdagangan kuantitatif secara alami juga secara aktif mengeksplorasi penerapan AI. Namun, dalam praktiknya, kita akan menemukan bahwa masih ada tantangan besar dalam mengandalkan AI semata-mata untuk secara langsung menghasilkan strategi perdagangan yang lengkap, stabil, dan menguntungkan secara berkelanjutan.
Khususnya bagi pengguna baru di platform, karena kemampuan pemrograman mereka yang lemah, sulit untuk menerapkan ide perdagangan mereka ke dalam kode strategi. Meskipun saat ini kita dapat memberi tahu AI ide-ide kita dan membiarkannya mengeluarkan strategi. Akan tetapi, efek implementasinya tidak sepenuhnya memenuhi harapan. Saya sering menjumpai pengguna yang datang untuk mengajukan pertanyaan dengan kode yang dihasilkan AI, dan terkadang saya dapat melihat strategi yang dihasilkan AI secara sekilas. Karena masih banyaknya masalah pada kode-kode strategi yang dihasilkan oleh AI pada tahap ini, penggunaan AI dengan cara ini bukan saja tidak akan menyelesaikan masalah apa pun, tetapi juga mendatangkan lebih banyak kebingungan dan masalah bagi para pemula. Semakin banyak yang saya pelajari, semakin bingung saya, dan akhirnya saya “menyerah untuk memulai”.
Saya pribadi berpendapat bahwa ada dua alasan utama untuk masalah saat ini dengan strategi keluaran langsung AI:
Jadi, apakah ada metode aplikasi lain yang lebih efisien? Artikel ini ingin berbagi cara berpikir baru: biarkan AI membantu kita mempelajari strategi yang ada, memahami desain strategi, mengekstrak detail dan teknik utama, serta menganalisis lebih lanjut efektivitasnya dan ruang untuk perbaikan. Metode ini tidak hanya membantu kita memahami esensi desain strategi lebih cepat, tetapi juga secara sistematis meningkatkan tingkat perdagangan kuantitatif kita.
Dengan memanfaatkan AI, AI dapat memiliki pemahaman yang relatif akurat tentang analisis kode tertentu, karena bagi AI, data kode adalah “1 adalah 1, 2 adalah 2” dan tidak akan ada kebingungan logis, ambiguitas, atau masalah lain yang disebabkan oleh persyaratan deskripsi bahasa alami. Jadi mengapa tidak memanfaatkan keunggulan AI untuk mengurangi beban kerja manual dan memanfaatkan sepenuhnya keunggulan pekerjaan manual.
Hal ini dapat dibagi menjadi beberapa langkah berikut:
Pilih strategi yang ada Ini dapat ditulis sendiri, sumber terbuka, atau contoh strategi yang sangat bagus pada platform kuantitatif penemu.
Biarkan AI membantu kami menjelaskan strateginya
Memahami ide keseluruhan
Urutkan modul fungsional setiap bagian
Memperjelas indikator, parameter, dan logika perdagangan yang digunakan
Dalam kondisi pasar apa strategi tersebut berkinerja lebih baik?
Apa saja titik risiko yang mungkin terjadi?
Area mana yang dapat dioptimalkan dan ditingkatkan?
Pengujian ulang pada produk yang berbeda dan periode yang berbeda
Tambahkan filter tambahan atau tindakan pengendalian risiko
Amati perubahan kinerja dan bentuk wawasan Anda sendiri
Mari kita biarkan AI mempelajari suatu strategi dan menjelaskannya kepada kita untuk melihat apakah itu memenuhi harapan kita. Ini dapat membantu kita mempelajari kuantifikasi.
Desain dan implementasi strategi perdagangan peningkatan posisi langkah demi langkah berdasarkan penyaringan tren EMA Alamat strategi: https://www.fmz.com/strategy/492116
/*backtest
start: 2024-10-01 00:00:00
end: 2025-04-23 00:00:00
period: 1h
basePeriod: 1m
exchanges: [{"eid":"Futures_Binance","currency":"ETH_USDT"}]
args: [["targetProfit",20],["amount",20],["amountPrecision",3],["isAmountForUSDT",true]]
*/
function getTotalEquity_OKEX_V5() {
var totalEquity = null
var ret = exchange.IO("api", "GET", "/api/v5/account/balance", "ccy=USDT")
if (ret) {
try {
totalEquity = parseFloat(ret.data[0].details[0].eq)
} catch(e) {
Log("获取账户总权益失败!")
return null
}
}
return totalEquity
}
function getTotalEquity_Binance() {
var totalEquity = null
var ret = exchange.GetAccount()
if (ret) {
try {
totalEquity = parseFloat(ret.Info.totalWalletBalance)
} catch(e) {
Log("获取账户总权益失败!")
return null
}
}
return totalEquity
}
function getTotalEquity() {
var exName = exchange.GetName()
if (exName == "Futures_OKCoin") {
return getTotalEquity_OKEX_V5()
} else if (exName == "Futures_Binance") {
return getTotalEquity_Binance()
} else {
throw "不支持该交易所"
}
}
function ceilToDecimals(value, decimals) {
const factor = Math.pow(10, decimals);
return Math.ceil(value * factor) / factor;
}
function cancelAll() {
while (1) {
var orders = _C(exchange.GetOrders)
if (orders.length == 0) {
break
}
for (var i = 0 ; i < orders.length ; i++) {
exchange.CancelOrder(orders[i].Id, orders[i])
Sleep(interval)
}
Sleep(interval)
}
}
function trade(distance, price, amount) {
var tradeFunc = null
if (distance == "buy") {
tradeFunc = exchange.Buy
} else if (distance == "sell") {
tradeFunc = exchange.Sell
} else if (distance == "closebuy") {
tradeFunc = exchange.Sell
} else {
tradeFunc = exchange.Buy
}
exchange.SetDirection(distance)
return tradeFunc(price, amount)
}
function openLong(price, amount) {
return trade("buy", price, amount)
}
function openShort(price, amount) {
return trade("sell", price, amount)
}
function coverLong(price, amount) {
return trade("closebuy", price, amount)
}
function coverShort(price, amount) {
return trade("closesell", price, amount)
}
function plotRecords(c, buyOrder, sellOrder, pos) {
var bars = _C(exchange.GetRecords)
if (bars.length == 0) {
return
}
bars.forEach(function(bar, index) {
c.begin(bar)
if (index == bars.length - 1) {
if (buyOrder) {
c.hline(buyOrder.Price, "buy", "rgba(255, 0, 0, 0.2)", "dotted")
}
if (sellOrder) {
c.hline(sellOrder.Price, "sell", "rgba(0, 255, 0, 0.2)", "dotted")
}
if (pos && pos.length == 1) {
c.hline(pos[0].Price, "pos", "rgba(0, 0, 255, 0.2)", "dashed")
}
}
c.close()
})
}
var buyOrderId = null
var sellOrderId = null
var logStatusMsgBuff = ""
function main() {
var exName = exchange.GetName()
if (isSimulate && exName == "Futures_OKCoin") {
exchange.IO("simulate", true)
}
if (isReset) {
_G(null)
LogReset(1)
LogProfitReset()
LogVacuum()
Log("重置所有数据", "#FF0000")
}
exchange.SetContractType(contractType)
exchange.SetPrecision(pricePrecision, amountPrecision)
Log("设置精度", pricePrecision, amountPrecision)
exchange.SetMarginLevel(marginLevel)
if (totalEq == -1 && !IsVirtual()) {
var recoverTotalEq = _G("totalEq")
if (!recoverTotalEq) {
var currTotalEq = getTotalEquity()
if (currTotalEq) {
totalEq = currTotalEq
_G("totalEq", currTotalEq)
} else {
throw "获取初始权益失败"
}
} else {
totalEq = recoverTotalEq
}
}
var addCounter = _G("addCounter")
if (!addCounter) {
addCounter = 1
if (setAddCounter != -1) {
addCounter = setAddCounter
}
_G("addCounter", addCounter)
} else {
addCounter -= 1
}
let c = KLineChart({
overlay: true
})
var isLock = false
while (true) {
var ticker = _C(exchange.GetTicker)
var pos = _C(exchange.GetPosition)
if (pos.length > 1) {
Log(pos)
throw "同时有多空持仓"
}
var r = _C(exchange.GetRecords, 60 * 60)
var ema = TA.EMA(r, 60)
if (Math.abs(ticker.Last - ema[ema.length - 2]) / ema[ema.length - 2] > 0.03) {
cancelAll()
isLock = true
}
if (Math.abs(ticker.Last - ema[ema.length - 2]) / ema[ema.length - 2] < 0.02) {
isLock = false
}
if (isLock) {
LogStatus(_D(), "暂停, 检测阈值:", _N(Math.abs(ticker.Last - ema[ema.length - 2]) / ema[ema.length - 2], 3), logStatusMsgBuff)
plotRecords(c, null, null, pos)
Sleep(interval)
continue
}
var currentAcc = _C(exchange.GetAccount)
if (currentAcc.Balance < totalEq * reserve) {
throw "no money, stop"
}
if (addCounter > maxAddCounter) {
LogStatus(_D(), "加仓已达到上限", logStatusMsgBuff)
if (isMaxAddCounterClear && pos.length >= 1) {
Log("加仓已达到上限,撤单,清仓")
cancelAll()
if (pos[0].Type == PD_LONG) {
var coverId = coverLong(-1, pos[0].Amount)
} else if (pos[0].Type == PD_SHORT) {
var coverId = coverShort(-1, pos[0].Amount)
}
addCounter = 1
}
continue
}
if (pos.length == 0) {
if (!IsVirtual()) {
var currTotalEq = getTotalEquity()
if (currTotalEq) {
LogProfit(currTotalEq - totalEq, "当前总权益:", currTotalEq)
}
}
var tradeAmountLong = amount
var tradeAmountShort = amount
if (isAmountForUSDT) {
tradeAmountLong = ceilToDecimals(tradeAmountLong * 1.01 / (ticker.Last - targetProfit / 5) / oneCtValue, amountPrecision)
tradeAmountShort = ceilToDecimals(tradeAmountShort * 1.01 / (ticker.Last + targetProfit / 5) / oneCtValue, amountPrecision)
}
buyOrderId = openLong(ticker.Last - targetProfit / 5, tradeAmountLong)
sellOrderId = openShort(ticker.Last + targetProfit / 5, tradeAmountShort)
addCounter = 1
_G("addCounter", addCounter)
} else if (pos[0].Type == PD_LONG) {
var n = ratio
var price = ticker.Last
var addAmount = isDoubling ? pos[0].Amount : (isAmountForUSDT ? (ceilToDecimals(amount * 1.01 / (price - targetProfit * n) / oneCtValue, amountPrecision)) : amount)
buyOrderId = openLong(price - targetProfit * n, addAmount)
sellOrderId = coverLong(pos[0].Price + targetProfit, pos[0].Amount)
addCounter++
_G("addCounter", addCounter)
} else if (pos[0].Type == PD_SHORT) {
var n = ratio
var price = ticker.Last
var addAmount = isDoubling ? pos[0].Amount : (isAmountForUSDT ? (ceilToDecimals(amount * 1.01 / (price + targetProfit * n) / oneCtValue, amountPrecision)) : amount)
buyOrderId = coverShort(pos[0].Price - targetProfit, pos[0].Amount)
sellOrderId = openShort(price + targetProfit * n, addAmount)
addCounter++
_G("addCounter", addCounter)
}
if (!sellOrderId || !buyOrderId) {
cancelAll()
buyOrderId = null
sellOrderId = null
continue
}
while (1) {
var isFindBuyId = false
var isFindSellId = false
var orders = _C(exchange.GetOrders)
var buyOrder = null
var sellOrder = null
for (var i = 0 ; i < orders.length ; i++) {
if (buyOrderId == orders[i].Id) {
isFindBuyId = true
buyOrder = orders[i]
}
if (sellOrderId == orders[i].Id) {
isFindSellId = true
sellOrder = orders[i]
}
}
if (!isFindSellId && !isFindBuyId) {
cancelAll()
break
} else if (!isFindBuyId) {
Log("买单成交")
cancelAll()
break
} else if (!isFindSellId) {
Log("卖单成交")
cancelAll()
break
}
var acc = _C(exchange.GetAccount)
var tbl = {"type": "table", "title": "data", "cols": ["data", "symbol", "type", "price", "amount"], "rows": []}
if (buyOrder) {
tbl.rows.push(["订单", buyOrder.Symbol, buyOrder.Type == ORDER_TYPE_BUY ? "买入" : "卖出", buyOrder.Price, buyOrder.Amount])
}
if (sellOrder) {
tbl.rows.push(["订单", sellOrder.Symbol, sellOrder.Type == ORDER_TYPE_BUY ? "买入" : "卖出", sellOrder.Price, sellOrder.Amount])
}
if (pos && pos.length == 1) {
tbl.rows.push(["持仓", pos[0].Symbol, pos[0].Type == PD_LONG ? "多" : "空", pos[0].Price, pos[0].Amount])
}
logStatusMsgBuff = "当前权益:" + acc.Equity + ", 初始权益:" + totalEq + (!IsVirtual() ? ", 浮动盈亏:" + (acc.Equity - totalEq) : "") + ", 加仓次数:" + addCounter + "\n`" + JSON.stringify(tbl) + "`"
LogStatus(_D(), "当前权益:", acc.Equity, ", 初始权益:", totalEq, !IsVirtual() ? ", 浮动盈亏:" + (acc.Equity - totalEq) : "", ", 加仓次数:" + addCounter, "\n`" + JSON.stringify(tbl) + "`")
plotRecords(c, buyOrder, sellOrder, pos)
Sleep(interval)
}
Sleep(interval)
}
}
function onexit() {
Log("扫尾,撤销所有挂单")
cancelAll()
}
Bagi siswa baru platform FMZ, melihat tumpukan kode seperti itu mungkin membuat Anda merasa bingung. Daripada mempelajari kode baris demi baris, kita mungkin juga (menjadi malas) dan menyerahkannya kepada AI, biarkan AI menjelaskannya kepada kita, dan meningkatkan efisiensi pembelajaran.
Saya menggunakan GPT di sini, dan konten berikut dijelaskan oleh AI:
I. Ringkasan Artikel ini akan memperkenalkan strategi perdagangan peningkatan posisi langkah demi langkah berdasarkan penyaringan tren EMA (rata-rata pergerakan eksponensial). Strategi ini terutama digunakan pada Binance Futures (Futures_Binance), mendukung pengujian ulang 1 jam, dan didasarkan pada agregasi data K-line 1 menit. Dengan memantau deviasi antara harga dan EMA secara real-time, strategi ini secara dinamis mengganti mode perdagangan (perdagangan normal/perdagangan ditangguhkan), secara bertahap meningkatkan posisi di pasar yang stabil, dan secara otomatis menangguhkan posisi dalam fluktuasi abnormal untuk menghindari risiko.
flowchart TD
开始 --> 初始化参数
初始化参数 --> 账户余额检查
账户余额检查 --> 计算EMA
计算EMA --> 判断是否锁仓
判断是否锁仓 -->|是| 暂停交易
判断是否锁仓 -->|否| 正常交易
正常交易 --> 是否有持仓
是否有持仓 -->|无| 首次挂单
是否有持仓 -->|有| 按持仓方向加仓与止盈挂单
首次挂单 --> 等待成交
按持仓方向加仓与止盈挂单 --> 等待成交
等待成交 --> 挂单成交检测
挂单成交检测 --> 成交后调整
成交后调整 --> 更新加仓次数
更新加仓次数 --> 是否超出最大加仓次数
是否超出最大加仓次数 -->|是| 平仓
是否超出最大加仓次数 -->|否| 继续交易
Kelima, Kesimpulan Strategi peningkatan posisi langkah demi langkah berdasarkan penyaringan EMA ini memperhitungkan pengembalian dan pengendalian risiko, dan cocok untuk beroperasi di pasar yang fluktuatif dan berfluktuasi lemah. Melalui metode penambahan posisi yang fleksibel dan mekanisme jeda tren, kemungkinan likuidasi dapat dikurangi secara efektif dan efisiensi penggunaan modal dapat ditingkatkan. Mendukung pengujian ulang dan perdagangan nyata, dan desain modularnya memudahkan perluasan. Misalnya, dapat lebih lanjut memperkenalkan penyesuaian dinamis targetProfit dan jumlah, atau menambahkan indikator teknis lainnya untuk meningkatkan efek penyaringan.
Mengenai pertanyaan GPT:

Konten berikut dijelaskan oleh AI:
Dalam strategi ini, penyaringan tren dicapai dengan:
var ema = TA.EMA(r, 60)
if (Math.abs(ticker.Last - ema[ema.length - 2]) / ema[ema.length - 2] > 0.03) {
cancelAll()
isLock = true
}
if (Math.abs(ticker.Last - ema[ema.length - 2]) / ema[ema.length - 2] < 0.02) {
isLock = false
}
if (isLock) {
LogStatus(_D(), "暂停, 检测阈值:", _N(Math.abs(ticker.Last - ema[ema.length - 2]) / ema[ema.length - 2], 3), logStatusMsgBuff)
plotRecords(c, null, null, pos)
Sleep(interval)
continue
}
Mengunci dan melepaskan tren: Dengan membandingkan perbedaan antara harga saat ini (ticker.Last) dan nilai EMA pada jam sebelumnya, persentase penyimpangan harga dari EMA dihitung. Math.abs(ticker.Last - ema[ema.length - 2]) / ema[ema.length - 2] menghitung persentase deviasi harga saat ini dari EMA jam sebelumnya. Jika deviasi melebihi 3% (> 0,03), tren pasar dianggap telah berubah secara signifikan, dan fungsi cancelAll() dipanggil untuk membatalkan semua pesanan yang tertunda, dan isLock ditetapkan ke true, yaitu posisi terkunci, mencegah perdagangan lebih lanjut. Jika harga menyimpang dari EMA kurang dari 2% (< 0,02), status kunci dilepaskan dan isLock ditetapkan ke salah.
Penghentian perdagangan: Jika isLock bernilai true (menunjukkan bahwa posisi saat ini terkunci), tidak akan ada lagi operasi perdagangan yang dilakukan. Program akan mengeluarkan catatan log dan memanggil plotRecords() untuk menggambar grafik guna menunjukkan tren terkini dan status posisi. Gunakan Tidur(interval) untuk berhenti selama periode waktu tertentu dan kemudian melanjutkan putaran.

Tampaknya beberapa tren dapat disaring. Dengan membaca sendiri kodenya, saya menemukan bahwa penjelasan AI sangat jelas, bahkan lebih jelas daripada jika saya menjelaskannya sendiri.
Dengan membiarkan AI menganalisis dan menjelaskan strategi keseluruhan, dan kemudian berdasarkan penjelasan AI tentang strategi keseluruhan, secara bertahap menganalisis, membongkar, dan menjelaskan detail lokal dari strategi tersebut dan menjelaskan ide-ide desain. Penjelasan yang kami terima relatif akurat. AI mencantumkan hampir semua rincian yang dirancang dalam strategi tanpa ada yang terlewat, dan melakukan analisis terperinci melalui pertanyaan lebih lanjut. Cara mempelajari keseluruhan pemikiran strategi, detail desain kode, dan meningkatkan pengalaman desain strategi semuanya sangat membantu.
Di jalan perdagangan kuantitatif, AI dapat menjadi mitra pembelajaran dan pertumbuhan yang sangat kuat bagi kita. Daripada mengandalkan AI untuk menghasilkan strategi yang sudah selesai dengan satu klik, AI dapat:
Hanya jalur ini yang benar-benar dapat meningkatkan kemampuan perdagangan kuantitatif kita dan membangun sistem perdagangan sistematis kita sendiri. Pada Platform Perdagangan Kuantitatif Inventor, kita dapat memanfaatkan sepenuhnya kekuatan AI dan menggabungkannya dengan praktik kita sendiri untuk melangkah lebih jauh dan terbang lebih tinggi.