Gần đây, có nhiều chiến lược Martingale được thảo luận trong nhóm chính thức FMZ, và không có nhiều chiến lược Martingale của hợp đồng tiền điện tử trên nền tảng. Do đó, tôi đã tận dụng cơ hội này để thiết kế một chiến lược Martingale đơn giản cho hợp đồng tương lai tiền điện tử. Tại sao nó được gọi là chiến lược Martingale? Bởi vì các rủi ro tiềm ẩn của chiến lược Martin thực sự không nhỏ, nó không được thiết kế chính xác theo chiến lược Martin. Tuy nhiên, loại chiến lược này vẫn có rất nhiều rủi ro, và các cài đặt tham số của chiến lược kiểu Martin có liên quan chặt chẽ đến rủi ro, và rủi ro không nên bị bỏ qua.
Bài viết này chủ yếu giải thích và học hỏi từ việc thiết kế các chiến lược kiểu Martin.
Tổng vốn chủ sở hữu thường được sử dụng khi thiết kế các chiến lược tương lai tiền điện tử. Điều này là bởi vì lợi nhuận phải được tính toán, đặc biệt là khi bạn cần tính toán lợi nhuận nổi. Vì vị trí được chiếm đóng với biên, lệnh đang chờ cũng được chiếm đóng.exchange.GetAccount()
Trong thực tế, hầu hết các sàn giao dịch tương lai tiền điện tử cung cấp dữ liệu tổng vốn chủ sở hữu, nhưng thuộc tính này không được đóng gói đồng nhất trên FMZ.
Vì vậy, chúng tôi thiết kế các hàm để lấy dữ liệu này theo các trao đổi khác nhau:
// OKEX V5 obtain total equity
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("failed to obtain the total equity of the account!")
return null
}
}
return totalEquity
}
// Binance futures
function getTotalEquity_Binance() {
var totalEquity = null
var ret = exchange.GetAccount()
if (ret) {
try {
totalEquity = parseFloat(ret.Info.totalWalletBalance)
} catch(e) {
Log("failed to obtain the total equity of the account!")
return null
}
}
return totalEquity
}
CáctotalEquity
Sau đó chúng ta viết một hàm như là mục nhập gọi, và gọi hàm tương ứng theo tên của sàn giao dịch.
function getTotalEquity() {
var exName = exchange.GetName()
if (exName == "Futures_OKCoin") {
return getTotalEquity_OKEX_V5()
} else if (exName == "Futures_Binance") {
return getTotalEquity_Binance()
} else {
throw "This exchange is not supported"
}
}
Trước khi thiết kế chức năng chính và logic chính, chúng ta cần thực hiện một số chuẩn bị và thiết kế một số chức năng phụ trợ.
Hủy tất cả các đơn đặt hàng đang chờ
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)
}
}
Chức năng này quen thuộc với những người thường đọc mã ví dụ chiến lược trên hình vuông chiến lược FMZ, và nhiều chiến lược đã sử dụng thiết kế tương tự.
Các giao dịch đặt hàng tương lai
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)
}
Có bốn hướng giao dịch tương lai: openLong, openShort, coverLong và coverShort. Vì vậy, chúng tôi đã thiết kế bốn chức năng lệnh tương ứng với các hoạt động này. Nếu bạn chỉ xem xét lệnh, thì có một số yếu tố cần thiết: hướng, giá lệnh và khối lượng lệnh.
Vì vậy, chúng tôi cũng thiết kế một hàm có tên:trade
để xử lý hoạt động khidistance
, price
, amount
được chỉ định.
Các cuộc gọi hàm để openLong, openShort, coverLong và coverShort cuối cùng được hoàn thành bởi cáctrade
chức năng, nghĩa là đặt lệnh trên một sàn giao dịch tương lai dựa trên khoảng cách, giá và số lượng đã thiết lập.
Ý tưởng chiến lược rất đơn giản, lấy giá hiện tại làm cơ sở và đặt lệnh bán (short) và mua (long) ở một khoảng cách nhất định lên hoặc xuống. Một khi giao dịch hoàn thành, tất cả các lệnh còn lại sẽ bị hủy bỏ, và sau đó một lệnh đóng mới sẽ được đặt ở một khoảng cách nhất định theo giá của vị trí, và một lệnh tăng sẽ được đặt ở mức giá hiện tại được cập nhật, nhưng khối lượng lệnh sẽ không tăng gấp đôi cho các vị trí bổ sung.
Công việc ban đầu Vì lệnh đang chờ, chúng tôi cần hai biến số toàn cầu để ghi lại ID lệnh.
var buyOrderId = null
var sellOrderId = null
Sau đó các tham số giao diện chiến lược được thiết kế để sử dụng tùy chọn bot mô phỏng OKEX_V5, vì vậy một số xử lý cần phải được thực hiện trong mã:
var exName = exchange.GetName()
// Switch OKEX V5 simulated bot
if (isSimulate && exName == "Futures_OKCoin") {
exchange.IO("simulate", true)
}
Ngoài ra còn có tùy chọn để đặt lại tất cả thông tin trong các thông số giao diện, vì vậy sẽ có xử lý tương ứng trong mã:
if (isReset) {
_G(null)
LogReset(1)
LogProfitReset()
LogVacuum()
Log("reset all data", "#FF0000")
}
Chúng tôi chỉ chạy các hợp đồng vĩnh cửu, vì vậy chữ viết được cố định ở đây và chỉ được thiết lập vĩnh cửu.
exchange.SetContractType("swap")
Sau đó, chúng ta cũng cần xem xét độ chính xác của giá lệnh và số tiền đặt hàng. Nếu độ chính xác không được đặt đúng, độ chính xác sẽ bị mất trong quá trình tính toán chiến lược. Nếu dữ liệu có số lượng lớn chữ số thập phân, rất dễ gây ra lệnh bị từ chối bởi giao diện trao đổi.
exchange.SetPrecision(pricePrecision, amountPrecision)
Log("set precision", pricePrecision, amountPrecision)
Khôi phục dữ liệu đơn giản theo thiết kế
if (totalEq == -1 && !IsVirtual()) {
var recoverTotalEq = _G("totalEq")
if (!recoverTotalEq) {
var currTotalEq = getTotalEquity()
if (currTotalEq) {
totalEq = currTotalEq
_G("totalEq", currTotalEq)
} else {
throw "failed to obtain initial equity"
}
} else {
totalEq = recoverTotalEq
}
}
Nếu bạn muốn xác định vốn chủ sở hữu ban đầu của tài khoản khi chiến lược đang chạy, bạn có thể thiết lập tham sốtotalEq
. Nếu tham số này được đặt thành -1, chiến lược sẽ đọc dữ liệu tổng vốn chủ sở hữu được lưu trữ. Nếu không có dữ liệu tổng vốn chủ sở hữu được lưu trữ, tổng vốn chủ sở hữu đọc hiện tại được sử dụng làm tổng vốn chủ sở hữu ban đầu của chiến lược đang tiến triển. Sau đó, sự gia tăng tổng vốn chủ sở hữu cho thấy lợi nhuận, và sự giảm tổng vốn chủ sở hữu cho thấy lỗ. Nếu dữ liệu tổng vốn chủ sở hữu được đọc, chiến lược sẽ tiếp tục chạy với dữ liệu này.
logic chính Sau khi hoàn thành công việc ban đầu, cuối cùng chúng tôi đã đến với phần logic chính của chiến lược.
while (1) { // The main logic of the strategy is designed as an infinite loop
var ticker = _C(exchange.GetTicker) // Read the current market information first, mainly using the latest transaction price
var pos = _C(exchange.GetPosition) // Read current position data
if (pos.length > 1) { // Judging the position data, because of the logic of this strategy, it is unlikely that long and short positions will appear at the same time, so if there are long and short positions at the same time, an error will be thrown
Log(pos)
throw "Simultaneous long and short positions" // Throw an error to stop the strategy
}
//Depends on status
if (pos.length == 0) { // Make different operations according to the position status, when there is no position, pos.length == 0
// If you have not held a position, count the profit once
if (!IsVirtual()) {
var currTotalEq = getTotalEquity()
if (currTotalEq) {
LogProfit(currTotalEq - totalEq, "current total equity:", currTotalEq)
}
}
buyOrderId = openLong(ticker.Last - targetProfit, amount) // Open a buy order for a long position
sellOrderId = openShort(ticker.Last + targetProfit, amount) // Open a short sell order
} else if (pos[0].Type == PD_LONG) { // For long positions, the position and quantity of pending orders are different
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) { // For short positions, the position and quantity of pending orders are different
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) { // If one side of the pending order fails, cancel all pending orders and start over
cancelAll()
buyOrderId = null
sellOrderId = null
continue
}
while (1) { // The pending order is completed, start monitoring the order
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) { // Detected that both buy and sell orders have been filled
cancelAll()
break
} else if (!isFindBuyId) { // Detected buy order closing
Log("buy order closing")
cancelAll()
break
} else if (!isFindSellId) { // Detected sell order closing
Log("sell order closing")
cancelAll()
break
}
LogStatus(_D())
Sleep(3000)
}
Sleep(500)
}
Toàn bộ logic và thiết kế được giải thích.
Hãy để chiến lược đi qua một thị trường ngày 19 tháng 5.
Có thể thấy rằng chiến lược Martingale vẫn có một số rủi ro.
Bot thực sự có thể chạy với OKEX V5 robot mô phỏng
Địa chỉ chiến lược:https://www.fmz.com/strategy/294957
Chiến lược chủ yếu được sử dụng để học, và tiền thật nên được sử dụng một cách thận trọng~!