Учебное пособие по FMZ

Автор:Трава, Создано: 2019-04-12 14:28:19, Обновлено: 2024-02-05 20:07:56

[TOC]

img

Этот учебник будет охватывать более подробную информацию о платформе FMZ, более практические навыки использования API.

После изучения всего учебника, вы будете в полной мере использовать FMZ и сможете писать более индивидуальные, более эффективные и более сложные стратегии.

1.Добавить несколько бирж и торговать несколькими символами

Вы можете легко торговать на нескольких биржах и с несколькими символами в одном роботе.

  • Добавьте один или несколько переключателей при запуске робота.
  • API можно назвать какexchange.GetTicker()когда добавляется один обмен
  • Когда несколько обменов добавляются, API называется какexchanges[0].GetTicker(), exchanges[1].GetTicker() img
  • Вы можете добавить тот же обмен с различными символами.img
  • Вы можете изменить символ, который связан сexchangeс помощьюIOФункция
var symbols = ["BTC_USDT", "LTC_USDT", "EOS_USDT", "ETH_USDT", "BCC_USDT"]
var buyValue = 1000
function main(){
  for(var i=0;i<symbols.length;i++){
      exchange.IO("currency", symbols[i]) // It is always valid until the next change
      var ticker = exchange.GetTicker()
      var amount = _N(buyValue/ticker.Sell, 3)
      exchange.Buy(ticker.Sell, amount)
      Sleep(1000)
  }
}

2.TradeФьючерсы и свопы

До сих пор FMZ поддерживает все основные фьючерсные биржи, такие как OKEX, HuobiDM, BitMEX, GateIO и Deribit, и их своп-контракты.

Чтобы торговать фьючерсами на FMZ, сначала нужно добавить фьючерсную биржу, установить символ при запуске бота и установить тип контракта в вашем коде.

если биржа поддерживает как спот, так и фьючерсы, они должны быть добавлены в FMZ отдельно.img

Изображение ниже показывает, как установить символ фьючерса на BTC при запуске бота.img

Ниже приведено, как установить тип контракта для каждой биржи.

  • ОКЕКС
    exchange.SetContractType("swap")        
    exchange.SetContractType("this_week")   
    exchange.SetContractType("next_week")  
    exchange.SetContractType("quarter")   
  • HuobiDM
    exchange.SetContractType("this_week")   
    exchange.SetContractType("next_week")  
    exchange.SetContractType("quarter")     
  • BitMEX
    exchange.SetContractType("XBTUSD")  
    exchange.SetContractType("XBTM19") 
  • Ворота
    exchange.SetContractType("swap")    
  • Дерибит
    exchange.SetContractType("BTC-PERPETUAL")  
    exchange.SetContractType("BTC-27APR18")

3.Об обратном тестировании

Основное введение

FMZ имеет два режима обратного тестирования:real tickиsimulate tick. Реальный уровень клинка содержит все завершенные исторические данные (один клинк в секунду), поэтому результаты бэкстестинга более надежные. Уровень симуляции использует данные истории клинков в интервале, используемом вашей стратегией. Клинки в пределах одного клина генерируются алгоритмом, который такой же, как MT4, вы можете найти более подробную информацию наhttps://www.mql5.com/en/articles/75Тем временем, более короткий интервал может быть выбран в качестве базовых клещей для генерации клещей. Симулирующий режим тика намного быстрее, но менее точен, чем реальный режим тика.

Конфигурация обратного теста

Вот настройки по умолчанию:imgСкрытые швы:img

Результат обратного теста

img

4.Допустимость ошибок

При вызове любых функций, которые имеют доступ к API обмена (например,GetTicker, Buy, CancelOrder, и т. д.), вы можете получить отказ в доступе из-за проблемы с обменным сервером, неправильных параметров, проблемы с сетевой передачей и т. д. В этом случае функция вернетсяnullТак что вам нужно знать, как справляться с ошибками.

В чём ошибка?

Бот вернет сообщение об ошибке, когда произойдет ошибка. Просто поиск обмена имя + ошибка msg, вы можете найти, в чем проблема. Например, ошибка{"result":false,"error_code":20049}возвращается при вызовеexchange.GetAccount()на OKEX.OKEX 20049Вот результат:imgВы также можете проверить код ошибки на обмен API документ, например,Код ошибки OKEX For Futures

Ошибки сделки

Вы должны рассмотреть, как справиться с ошибками при написании кода стратегии.

 // 1.Deal when the result is null
 var ticker = exchange.GetTicker()
 while(ticker == null){
     Log('GetTicker error')
     Sleep(100)
     ticker = exchange.GetTicker()
 }
 Log(ticker.Last);
 // 2.Refer when the result is not null
 var ticker = exchange.GetTicker()
 if(!ticker){
     Log(ticker.Last)
 }
 // 3._C() fucntion retry
 var ticker = _C(exchange.GetTicker) // can't  apply _C to CancelOrder, Why?
 Log(ticker.Last)
 // 4. try catch
 try{
     var ticker = exchange.GetTicker()
     Log(ticker.Last)
 }
 catch(err){
     Log('GetTicker error: ', err)
     Log(GetLastError()) //literal means, get last error
 } 

5.Прямое подключение к бирже

FMZ объединяет все данные различных бирж в одном формате, что облегчает написание кроссплатформенной стратегии. Однако вы не можете получить конкретные данные определенного API, которые предоставляют дополнительную информацию, и не можете получить доступ к API, которую не поддерживает FMZ. Есть два решения этой проблемы.

GetRawJSON

Вернуть исходное содержание (строку), которое было возвращено последним запросом REST API, который можно использовать для анализа сырой информации самостоятельно.

function main(){
    var account = exchange.GetAccount() //the account doesn't contain all data returned by the request
    var raw = JSON.parse(exchange.GetRawJSON())//raw data returned by GetAccount()
    Log(raw)
}

HttpQuery

Найдите все подробности оHttpQueryнаhttps://fmz-docs.readthedocs.io/en/latest/code_Instruction/Global Function.html#httpquery

HttpQueryвозвращает сырые данные этого запроса, которые должны быть сначала проанализированы.

//FMZ doesn't have a standard function for exchangeInfo that return the trading-information about all symbols. 
var exchangeInfo = JSON.parse(HttpQuery('https://api.binance.com/api/v1/exchangeInfo'))
Log(exchangeInfo) // FMZ doesn't have a standard function for this API
var ticker = JSON.parse(HttpQuery('https://api.binance.com/api/v1/ticker/24hr'))
Log(ticker)

Для этих публичных API,HttpQueryЭто очень полезная функция.HttpQueryподдерживает только JavaScript, для Python, используяurlib2илиrequestБиблиотека для отправки запросов HTTP напрямую.

ИО

Для этих частных API, используяHttpQueryбудет очень сложно, потому что вам нужно иметь дело с API-ключ, знак, хэш, и т.д.IOявляется удобной функцией для этого состояния, проверить его наhttps://fmz-docs.readthedocs.io/en/latest/code_Instruction/Extent API.html#io. IOВ этой части мы сосредоточены только на доступе к частным API.

Использование этой функции требует сначала понимания оригинального API биржи. Ниже приведены шаги для создания стоп-ордера, который не поддерживается FMZ на BitMEX.

  • Сначала найдите страницу документа BitMEX API:https://www.bitmex.com/api/explorer/
  • URL-адрес для заказа остановки:https://www.bitmex.com/api/v1/orderМетод:POSTПараметры включают символ, сторону, orderQty,stopPx,ordType, который должен быть расположен как "символ=XBTUSD&side=Buy&orderQty=1&stopPx=4000&ordType=Stop

Конечный код JavaScript:

var id = exchange.IO("api", "POST", "/api/v1/order", "symbol=XBTUSD&side=Buy&orderQty=1&stopPx=4000&ordType=Stop")

6.Использовать веб-сокет

По сути, все биржи цифровой валюты поддерживают отправку рыночных данных через websocket, а некоторые биржи даже поддерживают обновление информации об учетной записи. По сравнению с остальным API, websocket обычно имеет преимущества низкой задержки, высокой частоты и не ограничивается частотой запросов API остальной платформы. Недостатком является то, что он может быть прерван, и обработка не интуитивно понятна.

Для JavaScript, вы можете использоватьDialФункция для подключения к websocket, Для Python, вы можете использоватьDialилиwebsocket_client libray.

Это обучение будет сосредоточено на подключении веб-сокетов с помощью JavaScript иDialФункция Dial была обновлена несколько раз для расширения использования. В этом учебном пособии будет продемонстрирована стратегия, основанная на событиях, и как подключиться к нескольким биржам.

Подключен к веб-сокету

  • 1.В большинстве случаев вы можете подключиться напрямую. Ниже приведен пример подключения к Binance all ticker.
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")
    
  • 2.Для возвращаемых данных сжатого формата они должны быть указаны во время подключения.compressозначает, что данные в сжатом формате, и параметрmodeпредставляет собой, если отправление или прием сжаты.
    var client = Dial("wss://real.okex.com:10441/websocket?compress=true|compress=gzip_raw&mode=recv")
    
  • 3.Функция Dial поддерживает автоматическое воссоединение, которое выполняется базовым языком Go. Для запроса содержание данных уже находится в URL-адресе, например, Biannce, это удобно и рекомендуется. Для тех, кому нужно отправить подписку сообщение, вы можете поддерживать воссоединение самостоятельно.
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr?reconnect=true")
    
  • 4.Некоторые биржи подписные каналы включены в URL-адрес, такие как Binance, но некоторые требуют от пользователей отправки подписных каналов, таких как coinbase:
    var client = Dial("wss://ws-feed.pro.coinbase.com", 60)
    client.write('{"type": "subscribe","product_ids": ["BTC-USD"],"channels": ["ticker","heartbeat"]}')
    

Получить данные

Как правило, данные из websocket могут читаться непрерывно без сна в бесконечной петле.

function main() {
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")
    while (true) {
        var msg = client.read() //receve data from client
        var data = JSON.parse(msg) //change raw string to js object
        // do something, don't need sleep. 
    }
}

Websocket перемещает данные очень быстро. Основа Docker кэширует все данные в очереди, а затем возвращает первый, когда программа вызываетreadРобот выполняет такие сетевые операции, как:Buy,GetAccount,CancelOrderДля информации, такой как транзакционный толчок, толчок учетной записи, глубокий толчок подмножества и т. Д., Нам нужны исторические данные. Для рыночных данных мы обычно заботимся только о последних.

Вread()функция возвращает старые данные в очереди, если нет аргументов, и блокирует, когда нет данных (программа здесь приостанавливается).read(-2)немедленно возвращать последние данные, и возвращатьnullесли в очереди нет данных (программа не будет останавливаться).

Подключение к нескольким веб-сокетам

В этом случае очевидно, что программа не может использовать простойread()потому что биржа будет блокировать и ждать новых данных, а другая биржа не будет получать свои собственные новые данные немедленно.

function main() {
    var binance = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")
    var coinbase = Dial("wss://ws-feed.pro.coinbase.com")
    coinbase.write('{"type": "subscribe","product_ids": ["BTC-USD"],"channels": ["ticker","heartbeat"]}')
    while (true) {
        var msgBinance = binance.read(-1)
        var msgCoinbase = coinbase.read(-1)
        if(msgBinance){
            // Binance has new data
        }
        if(msgCoinbase){
            // coinbase has new data
        }
        Sleep(1) // just sleep 1ms
    }
}

Общая база для использования веб-сокета

Поскольку push-данные уже были использованы, программа естественно написана как тип, управляемый событиями, обращая внимание на частоту запросов API.

var tradeTime = Date.now()
var accountTime = Date.now()
function trade(data){
    if(Date.now() - tradeTime > 2000){//only trade once within 2s
        tradeTime = Date.now()
        //trading code
    }
}
function GetAccount(){
    if(Date.now() - accountTime > 5000){//only get account once within 5s
        accountTime = Date.now()
        return exchange.GetAccount()
    }
}
function main() {
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr|reconnect=true")
    while (true) {
        var msg = client.read()
        var data = JSON.parse(msg)
        var account = GetAccount()
        trade(data)
    }
}

Все преметры

ПараметрыDial(Address, Timeout): TimeoutВремя отключения: За адресом могут следовать другие параметры, которые связаны с&. Адрес и параметры разделены|,

Параметр описание
компресс Способ сжатия, может бытьgzip_raw, gzip. Использование OKEXgzip_raw
режим может бытьdualозначает, что и отправление, и прием должны быть сжаты,sendозначает отправлять необходимость быть сжатым иrecvозначает получать.
прокси Настройки прокси для ss5.socks5://name:pwd@192.168.0.1:1080
перезагрузить Reconnect=trueчтобы обеспечить повторное подключение
интервал intervalэто интервал повторной попытки, по умолчанию 1000 мс
полезная нагрузка Сообщение подписки, которое нужно отправить при повторном подключении wss

Параметрыread(): Когда сетевой сокет отключился,read()вернет пустую строку.

Параметр Никаких. -1 -2 2000
очередь не пуста немедленно вернуть старые данные немедленно вернуть старые данные немедленно вернуть последние данные немедленно вернуть старые данные
очередь пуста Блокировать до возвращения новых данных возвращениеnullнемедленно возвращениеnullнемедленно подождать менее 2000 мс до возвращения новых данных, в противном случае, возвращениеnull

Использованиеclose(): Закройте соединение веб-сокета.

function main() {
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr|reconnect=true")
    client.close()
}
    

7.Асинхронные или многопоточные

Вы, возможно, заметили, что все коды, которые у нас сейчас есть, являются однополосными, последовательными.GOЭто очень ограничено. ИспользованиеGoкогда вы действительно заботитесь о задержке и времени потребления каждого запроса API.

обмен.Go (Метод, Args)

Метод: название функции. Аргс: аргументы метода.

Список поддерживаемых функцийGetTicker, GetDepth, GetTrades, GetRecords, GetAccount, GetOrders, GetOrder, CancelOrder, Buy, Sell, GetPosition.

Пример JavaScript:

function main(){
    var a = exchange.Go("GetTicker"); //GetTicker Asynchronous multithreaded execution
    var b = exchange.Go("GetDepth");
    var c = exchange.Go("Buy", 1000, 0.1);
    var d = exchange.Go("GetRecords", PERIOD_H1);
    // The above four operations are concurrent multi-threaded asynchronous execution, will not block and immediately return
    var ticker = a.wait(); // Call wait method wait for return to asynchronous get ticker result
    var depth = b.wait(); // Return depth, it is also possible to return null if it fails
    var orderId = c.wait(1000); // Return the order number, 1 second timeout, timeout returns undefined, this object can continue to call wait until the last wait timeout
    var records = d.wait(); // Wait for K-line result
    var ret = d.wait();  // Here waits for an asynchronous operation that has waited and ended, returns null, and logs an error message.
}

wait()Функция должна быть вызвана послеGoВ противном случае ресурс потока будет накапливаться до 2000 и возвращает ошибку.

8.Таблицы и графики

LogStatusи Таблицы

LogStatus будет регистрировать сообщение или таблицы в строке состояния ботов, обновляется каждый раз.

//Normal uses of LogStatus
LogStatus(" This is a normal status prompt")
LogStatus(" This is a red font status prompt #ff0000")
LogStatus(" This is a multi-line status message\n I'm the second line")

LogStatus может регистрировать таблицы на странице робота. Добавить`символов с обеих сторон и рассматривать его как сложный формат сообщения (в настоящее время поддерживается таблица).

var table = {type: 'table', title: ' Account information support color #ff0000', cols: ['BTC', 'ETH', 'USDT'], rows: [ ['free', 1, 2000], ['frozen', 0, 3000]]}
LogStatus('`' + JSON.stringify(table)+'`')
//Another example, information can also appear in multiple lines:
LogStatus("First line message\n" + JSON.stringify(table)+"`\n third line message")
//Log multiple tables in a group, switching by TAB:
var table1 = {type: 'table', title: ' Account information 1', cols: ['BTC', 'ETH', 'USDT'], rows: [ ['free', 1, 2000], ['frozen', 0, 3000]]}
var table2 = {type: 'table', title: ' Account information 2', cols: ['BTC', 'ETH', 'USDT'], rows: [ ['free', 1, 2000], ['frozen', 0, 3000]]}
LogStatus('`' + JSON.stringify([table1, table2])+'`')

Диаграмма

Нарисуйте цифры на странице управления роботами. Поддержка графиков HighStocks и HighCharts, проверкаhttps://www.highcharts.com/demoиhttps://www.highcharts.com/stock/demoдля дополнительных примеров. Объект График имеет__isStockатрибут, который не существует в оригинале.__isStockесли false, график будет отображаться как HighCharts.__isStockЕсли это правда, график будет отображаться как HighStocks.reset()чтобы очистить данные диаграммы.

Пример JavaScript использования диаграммы для вычисления цен двух символов:

// This chart is an object in the JS language. Before using the Chart function, we need to declare an object variable chart that configures the chart.
var chart = {
    // Whether the mark is a general chart, if you are interested, you can change it to false and run it.
    __isStock: true,
    tooltip: {xDateFormat: '%Y-%m-%d %H:%M:%S, %A'},    // Zoom tool
    title : { text : 'Spread Analysis Chart'},          // title
    rangeSelector: {                                    // Selection range
        buttons:  [{type: 'hour',count: 1, text: '1h'}, {type: 'hour',count: 3, text: '3h'}, {type: 'hour', count: 8, text: '8h'}, {type: 'all',text: 'All'}],
        selected: 0,
        inputEnabled: false
    },
    xAxis: { type: 'datetime'},                         // The horizontal axis of the coordinate axis is the x axis and the current setting type is :time
    yAxis : {                                           // The vertical axis of the axis is the y axis, and the default value is adjusted with the data size.
        title: {text: 'Spread'},                        // title
        opposite: false,                                // Whether to enable the right vertical axis
    },
    series : [                                          // Data series, this attribute is saved for each data series (line, K-line graph, label, etc...)
        {name : "line1", id : "Line 1,buy1Price", data : []},  // The index is 0, the data array is stored in the index series of data
        {name : "line2", id : "Line 2,lastPrice", dashStyle : 'shortdash', data : []},
        // The index is 1, dashStyle is set: 'shortdash' ie: Set the dotted line.
    ]
};
function main(){
    var ObjChart = Chart(chart);                      // Call the Chart function to initialize the chart.
    ObjChart.reset();                                 // Empty the chart
    while(true){
        var nowTime = new Date().getTime();           // Get the timestamp of this poll, which is a millisecond timestamp. Used to determine the position of the X axis written to the chart.
        var tickerOne = _C(exchanges[0].GetTicker);   // Get market data
        var tickerTwo = _C(exchanges[1].GetTicker);
        ObjChart.add([0, [nowTime, tickerOne.Last]]); // Use the timestamp as the X value and buy the price as the Y value to pass the index 0 data sequence.
        ObjChart.add([1, [nowTime, tickerTwo.Last]]); // Same as above
        ObjChart.update(chart);                       // Update the chart to show it.
        Sleep(2000);
    }
}

Поддерживает отображение нескольких фигур, полный пример:https://www.fmz.com/strategy/136056 img

9.Стандарт стратегии

Шаблон - это библиотека, которая включает в себя многие расширенные функции, которые облегчают написание вашей стратегии. Чтобы использовать шаблон, вы должны сначала скопировать шаблон, который вам нужен. Возьмите библиотеку JavaScript Plot в качестве примера, скопируйте его изhttps://www.fmz.com/strategy/27293и сохранить. Затем выберите его на странице редактирования стратегии.imgФункции называются после$.в шаблоне JavaScript и послеext.в шаблоне Python.

function main() {
    var isFirst = true
    while (true) {
        var records = exchange.GetRecords();
        if (records && records.length > 0) {
            $.PlotRecords(records, 'BTC')
            if (isFirst) {
                $.PlotFlag(records[records.length - 1].Time, 'Start', 'S')
                isFirst = false
                $.PlotHLine(records[records.length - 1].Close, 'Close')
            }
        }
        var ticker = exchange.GetTicker()
        if (ticker) {
            $.PlotLine('Last', ticker.Last)
            $.PlotTitle('Last ' + ticker.Last)
        }
        Sleep(60000)
    }
}

Вот еще один простой пример, который использует шаблон сюжета:https://www.fmz.com/strategy/121917


Больше

q25459768Спасибо.

ТраваЯ работаю над этим уроком. Это займет несколько дней. не стесняйтесь задавать любые вопросы.