
Baru-baru ini, ada banyak diskusi tentang strategi Martingale di grup resmi FMZ, tetapi tidak banyak strategi Martingale untuk kontrak mata uang digital di platform tersebut. Oleh karena itu, saya mengambil kesempatan ini untuk merancang strategi Martingale sederhana untuk kontrak berjangka mata uang kripto. Mengapa disebut strategi Martin? Karena potensi risiko strategi Martin memang tidak kecil, sehingga tidak dirancang sepenuhnya sesuai dengan strategi Martin. Namun, jenis strategi ini masih memiliki risiko yang cukup besar, dan pengaturan parameter strategi Martingale terkait erat dengan risiko, dan risiko tidak boleh diabaikan.
Artikel ini terutama menjelaskan dan belajar dari desain strategi tipe Martin. Ide strategi itu sendiri sangat jelas. Sebagai pengguna FMZ, kami lebih mempertimbangkan desain strategi.
Saat merancang strategi berjangka mata uang digital, data ekuitas total sering digunakan. Karena perlu menghitung laba, terutama bila laba mengambang perlu dihitung. Karena posisi terbuka menempati margin, maka pesanan yang tertunda juga menempati margin. Saat ini, panggil antarmuka API platform FMZexchange.GetAccount()Yang diperoleh adalah aset yang tersedia dan aset yang dibekukan berdasarkan pesanan yang tertunda. Faktanya, sebagian besar bursa berjangka mata uang digital menyediakan data tentang total ekuitas, tetapi FMZ tidak secara seragam merangkum atribut ini.
Oleh karena itu, kami merancang fungsi untuk memperoleh data ini berdasarkan pertukaran yang berbeda:
// OKEX V5 获取总权益
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
}
Dalam kodetotalEquityInilah total ekuitas yang kita butuhkan. Kemudian kita menulis fungsi sebagai entri pemanggil dan memanggil fungsi terkait sesuai dengan nama pertukaran.
function getTotalEquity() {
var exName = exchange.GetName()
if (exName == "Futures_OKCoin") {
return getTotalEquity_OKEX_V5()
} else if (exName == "Futures_Binance") {
return getTotalEquity_Binance()
} else {
throw "不支持该交易所"
}
}
Sebelum merancang fungsi utama dan logika utama. Kita masih perlu melakukan beberapa persiapan dan merancang beberapa fungsi tambahan.
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(500)
}
Sleep(500)
}
}
Saya yakin mereka yang sering melihat kode contoh strategi di FMZ Strategy Square sangat familiar dengan fungsi ini. Banyak strategi yang menggunakan desain serupa. Fungsinya adalah untuk mendapatkan daftar pesanan tertunda saat ini, lalu membatalkannya satu per satu.
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)
}
Ada empat arah dalam perdagangan berjangka: membuka posisi panjang (openLong), membuka posisi pendek (openShort), menutup posisi panjang (coverLong), dan menutup posisi pendek (coverShort). Jadi kami merancang empat fungsi perintah yang sesuai dengan operasi ini. Jika Anda hanya mempertimbangkan untuk melakukan pemesanan, ada beberapa faktor yang diperlukan: arah, harga pesanan, dan jumlah pesanan.
Jadi kami juga merancang sebuah program yang disebut:tradeFungsi untuk menangani方向(distance)、下单价格(price)、下单量(amount)Semua operasinya jelas.
Panggilan fungsi pembukaan posisi long (openLong), pembukaan posisi short (openShort), penutupan posisi long (coverLong), dan penutupan posisi short (coverShort) pada akhirnya dieksekusi olehtradeFungsi tersebut menjalankan fungsi sesungguhnya, yaitu menempatkan pesanan di bursa berjangka sesuai dengan arah, harga, dan kuantitas yang ditetapkan.
Strateginya sangat sederhana. Gunakan harga saat ini sebagai dasar dan tempatkan order jual (short) dan order beli (long) pada jarak tertentu di atas dan di bawah harga saat ini. Setelah satu sisi dieksekusi, semua order yang tersisa akan dibatalkan, dan kemudian order penutupan baru akan ditempatkan pada jarak tertentu berdasarkan harga posisi, dan order kenaikan akan ditempatkan pada harga terkini yang diperbarui, tetapi order kenaikan akan tidak menggandakan jumlah pesanan.
var buyOrderId = null
var sellOrderId = null
Kemudian opsi penggunaan disk simulasi OKEX_V5 dirancang dalam parameter antarmuka strategi, sehingga beberapa pemrosesan perlu dilakukan dalam kode:
var exName = exchange.GetName()
// 切换OKEX V5模拟盘
if (isSimulate && exName == "Futures_OKCoin") {
exchange.IO("simulate", true)
}
Parameter antarmuka juga menyertakan opsi untuk mengatur ulang semua informasi, sehingga kode tersebut juga harus memiliki pemrosesan yang sesuai:
if (isReset) {
_G(null)
LogReset(1)
LogProfitReset()
LogVacuum()
Log("重置所有数据", "#FF0000")
}
Kami hanya menjalankan kontrak abadi, jadi di sini sudah dikodekan secara keras dan hanya disetel ke kontrak abadi.
exchange.SetContractType("swap")
Kemudian kita juga perlu mempertimbangkan keakuratan harga pesanan dan jumlah pesanan. Jika keakuratan tidak diatur dengan benar, keakuratan akan hilang selama proses perhitungan strategi. Jika data memiliki banyak tempat desimal, itu akan dengan mudah menyebabkan pesanan menjadi ditolak oleh antarmuka pertukaran.
exchange.SetPrecision(pricePrecision, amountPrecision)
Log("设置精度", pricePrecision, amountPrecision)
Fungsi pemulihan data sederhana
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
}
}
Jika Anda ingin menentukan total ekuitas akun awal saat strategi dijalankan, Anda dapat mengatur parametertotalEqJika parameter ini ditetapkan ke -1, strategi akan membaca data ekuitas total yang tersimpan. Jika tidak ada data ekuitas total yang tersimpan, total ekuitas yang dibaca saat ini akan digunakan sebagai total ekuitas awal dari kemajuan strategi yang sedang berjalan. Jika total ekuitas bertambah, artinya jika anda menghasilkan uang, tetapi total ekuitas anda berkurang, artinya anda telah kehilangan uang. Jika data ekuitas total terbaca, lanjutkan menjalankan menggunakan data ini.
while (1) { // 策略主要逻辑设计为一个死循环
var ticker = _C(exchange.GetTicker) // 首先读取当前行情信息,主要用到最新成交价
var pos = _C(exchange.GetPosition) // 读取当前持仓数据
if (pos.length > 1) { // 判断持仓数据,由于这个策略的逻辑,是不太可能同时出现多空持仓的,所以发现同时出现多空持仓就抛出错误
Log(pos)
throw "同时有多空持仓" // 抛出错误,让策略停止
}
// 根据状态而定
if (pos.length == 0) { // 根据持仓状态做出不同操作,pos.length == 0是当没有持仓时
// 未持仓了,统计一次收益
if (!IsVirtual()) {
var currTotalEq = getTotalEquity()
if (currTotalEq) {
LogProfit(currTotalEq - totalEq, "当前总权益:", currTotalEq)
}
}
buyOrderId = openLong(ticker.Last - targetProfit, amount) // 挂开多仓的买单
sellOrderId = openShort(ticker.Last + targetProfit, amount) // 挂开空仓的卖单
} else if (pos[0].Type == PD_LONG) { // 有多头持仓,挂单位置、数量有所不同
var n = 1
var price = ticker.Last
buyOrderId = openLong(price - targetProfit * n, amount)
sellOrderId = coverLong(pos[0].Price + targetProfit, pos[0].Amount)
} else if (pos[0].Type == PD_SHORT) { // 有空头持仓,挂单位置、数量有所不同
var n = 1
var price = ticker.Last
buyOrderId = coverShort(pos[0].Price - targetProfit, pos[0].Amount)
sellOrderId = openShort(price + targetProfit * n, amount)
}
if (!sellOrderId || !buyOrderId) { // 如果有一边挂单失败就取消所有挂单,重来
cancelAll()
buyOrderId = null
sellOrderId = null
continue
}
while (1) { // 挂单完成,开始监控订单
var isFindBuyId = false
var isFindSellId = false
var orders = _C(exchange.GetOrders)
for (var i = 0 ; i < orders.length ; i++) {
if (buyOrderId == orders[i].Id) {
isFindBuyId = true
}
if (sellOrderId == orders[i].Id) {
isFindSellId = true
}
}
if (!isFindSellId && !isFindBuyId) { // 检测到买卖单都成交了
cancelAll()
break
} else if (!isFindBuyId) { // 检测到买单成交
Log("买单成交")
cancelAll()
break
} else if (!isFindSellId) { // 检测到卖单成交
Log("卖单成交")
cancelAll()
break
}
LogStatus(_D())
Sleep(3000)
}
Sleep(500)
}
Seluruh logika dan desain telah dijelaskan.
Biarkan strategi mengalami situasi pasar pada tanggal 19 Mei.


Dapat dilihat bahwa strategi Martingale masih memiliki risiko tertentu.

Alamat strategi: https://www.fmz.com/strategy/294957
Strategi terutama digunakan untuk pembelajaran, jadi gunakan uang sungguhan dengan hati-hati ~!