В последнее время в официальной группе FMZ обсуждается множество стратегий Мартингейла, и на платформе не так много стратегий Мартингейла контрактов криптовалют. Поэтому я воспользовался этой возможностью, чтобы разработать простую стратегию Мартингейла для фьючерсов криптовалют. Почему ее называют стратегией Мартингейл? Поскольку потенциальные риски стратегии Мартина действительно не малы, она не разработана точно в соответствии со стратегией Мартина. Однако этот тип стратегии все еще имеет много рисков, и параметры настройки стратегии типа Мартина тесно связаны с риском, и риск не должен игнорироваться.
Эта статья в основном объясняет и учится на разработке стратегий типа Мартина.
Общий капитал часто используется при разработке криптовалютных фьючерсных стратегий. Это связано с тем, что прибыль должна быть рассчитана, особенно когда вам нужно рассчитать плавающие доходы. Поскольку позиция занята маржой, ожидаемый ордер также занят.exchange.GetAccount()
Фактически, большинство криптовалютных фьючерсных бирж предоставляют данные об общем капитале, но этот атрибут не однородно упакован на FMZ.
Поэтому мы разрабатываем функции для получения этих данных в соответствии с различными обменами:
// 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
}
В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 "This exchange is not supported"
}
}
Перед тем, как разработать основную функцию и основную логику, нам нужно сделать некоторые приготовления и разработать некоторые вспомогательные функции.
Отменить все текущие заказы
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)
}
}
Эта функция знакома тем, кто часто читает примерный код стратегии на квадратной стратегии FMZ, и многие стратегии использовали аналогичные конструкции.
Операции по размещению фьючерсов
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)
}
Для торговли фьючерсами существует четыре направления: openLong, openShort, coverLong и coverShort. Поэтому мы разработали четыре функции ордера, соответствующие этим операциям. Если вы рассматриваете только ордер, то есть несколько необходимых факторов: направление, цена ордера и объем ордера.
Также мы разработали функцию под названием:trade
для обработки операции, когдаdistance
, price
, amount
Указываются.
Призывы к функции openLong, openShort, coverLong и coverShort в конечном итоге завершаютсяtrade
функция, то есть размещение ордера на бирже фьючерсов на основе установленного расстояния, цены и количества.
Идея стратегии очень проста, возьмите текущую цену в качестве базовой линии и разместите ордера на продажу (короткий) и покупку (длинный) на определенном расстоянии вверх или вниз. После завершения сделки все оставшиеся ордера будут отменены, а затем новый ордер на закрытие будет размещен на определенном расстоянии в соответствии с ценой позиции, и ордер на увеличение будет размещен по обновленной текущей цене, но объем ордера не будет удвоен для дополнительных позиций.
Первоначальные работы Из-за ожидания заказа, нам нужны две глобальные переменные для записи идентификатора заказа.
var buyOrderId = null
var sellOrderId = null
Затем параметры интерфейса стратегии предназначены для использования опции OKEX_V5 simulated bot, поэтому в коде необходимо провести некоторую обработку:
var exName = exchange.GetName()
// Switch OKEX V5 simulated bot
if (isSimulate && exName == "Futures_OKCoin") {
exchange.IO("simulate", true)
}
Существует также возможность сброса всей информации в параметрах интерфейса, поэтому в коде должна быть соответствующая обработка:
if (isReset) {
_G(null)
LogReset(1)
LogProfitReset()
LogVacuum()
Log("reset all data", "#FF0000")
}
У нас только постоянные контракты, так что запись фиксирована здесь и установлена только на постоянные.
exchange.SetContractType("swap")
В этом случае мы должны также учитывать точность цены заказа и суммы заказа. Если точность не установлена должным образом, то точность будет потеряна во время процесса расчета стратегии. Если данные имеют большое количество десятичных знаков, легко вызвать отказ заказа обменным интерфейсом.
exchange.SetPrecision(pricePrecision, amountPrecision)
Log("set precision", pricePrecision, amountPrecision)
Простое восстановление данных по конструкции
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
}
}
Если вы хотите указать начальный общий капитал счета, когда стратегия работает, вы можете установить параметрtotalEq
. Если этот параметр установлен на -1, стратегия будет читать сохраненные данные об общем капитале. Если нет сохраненных данных об общем капитале, текущий прочитанный общий капитал используется в качестве начального общего капитала стратегии. После этого увеличение общего капитала указывает на прибыль, а снижение общего капитала указывает на убыток. Если читаются данные об общем капитале, стратегия будет продолжать работать с этими данными.
Основная логика После того, как начальная работа будет сделана, наконец, мы пришли к основной логической части стратегии. Для удобства объяснения, я написал инструкции непосредственно на комментариях кода.
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)
}
Вся логика и дизайн объяснены.
Пусть стратегия пройдет через рынок 19 мая.
Видно, что стратегия Мартингейла по-прежнему несет определенные риски.
Настоящий бот можно запустить с OKEX V5 симулятор бота
Адрес стратегии:https://www.fmz.com/strategy/294957
Стратегии используются в основном для обучения, и реальные деньги должны использоваться с осторожностью~!