Tutorial menengah FMZ

Penulis:Rumput, Dibuat: 2019-04-12 14:28:19, Diperbarui: 2024-02-05 20:07:56

[TOC]

img

Tutorial ini akan mencakup lebih banyak detail tentang platform FMZ, lebih banyak keterampilan praktis tentang menggunakan API.

Setelah mempelajari seluruh tutorial, Anda akan memanfaatkan sepenuhnya FMZ dan dapat menulis strategi yang lebih disesuaikan, lebih efisien dan lebih kompleks.

1.Tambahkan beberapa bursa dan perdagangan beberapa simbol

Anda dapat berdagang di beberapa bursa dan beberapa simbol dalam satu robot dengan mudah.

  • Tambahkan satu pertukaran atau beberapa pertukaran ketika memulai robot.
  • API dapat disebut sepertiexchange.GetTicker()ketika satu pertukaran ditambahkan
  • Ketika beberapa pertukaran ditambahkan, API disebut sepertiexchanges[0].GetTicker(), exchanges[1].GetTicker() img
  • Anda dapat menambahkan pertukaran yang sama dengan simbol yang berbeda.img
  • Anda dapat mengubah simbol yang mengikat denganexchangedengan menggunakanIOfungsi
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.TradeKontrak berjangka dan swap

Sejauh ini, FMZ mendukung semua bursa berjangka utama, seperti OKEX, HuobiDM, BitMEX, GateIO dan Deribit, dan kontrak swap mereka.

Untuk perdagangan berjangka di FMZ, Anda perlu menambahkan bursa berjangka pertama, mengatur simbol ketika memulai bot dan mengatur jenis kontrak dalam kode Anda.

Jika sebuah bursa mendukung spot dan futures, mereka harus ditambahkan ke FMZ secara terpisah.img

Gambar di bawah ini menunjukkan cara mengatur simbol futures ke BTC saat memulai bot.img

Di bawah ini adalah cara mengatur jenis kontrak untuk setiap bursa.

  • Baiklah.
    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") 
  • Gerbang
    exchange.SetContractType("swap")    
  • Deribit
    exchange.SetContractType("BTC-PERPETUAL")  
    exchange.SetContractType("BTC-27APR18")

3.Tentang backtest

Pengantar dasar

FMZ memiliki dua mode backtesting:real tickdansimulate tick. Tingkat tik nyata berisi semua data historis yang selesai (satu tik per detik), sehingga hasil backtesting lebih dapat diandalkan. Tingkat simulasi menggunakan data klines sejarah pada interval yang digunakan oleh strategi Anda. Tik dalam satu kline dihasilkan oleh algoritma yang sama dengan MT4, Anda dapat menemukan lebih banyak detail dihttps://www.mql5.com/en/articles/75Sementara itu, interval yang lebih pendek dapat dipilih sebagai base-klines untuk menghasilkan kutu. Modus simulasi tik jauh lebih cepat tetapi kurang akurat daripada modus tik yang sebenarnya.

Konfigurasi Backtest

Ini adalah pengaturan default:imgTindik tersembunyi:img

Hasil tes balik

img

4.Toleransi kesalahan

Ketika memanggil fungsi yang mengakses API pertukaran (sepertiGetTicker, Buy, CancelOrder, dll...), Anda mungkin mendapatkan kegagalan akses karena masalah server pertukaran, parameter yang salah, masalah transmisi jaringan, dan sebagainya.nullJadi Anda perlu tahu bagaimana menangani kesalahan.

Apa yang salah?

bot akan mengembalikan pesan kesalahan ketika terjadi kesalahan. hanya mencari nama pertukaran + kesalahan msg, Anda dapat menemukan apa masalahnya. misalnya,{"result":false,"error_code":20049}dikembalikan saat panggilanexchange.GetAccount()di OKEX. GoogleOKEX 20049, inilah hasilnya:imgAnda juga dapat memeriksa kode kesalahan pada dokumen API pertukaran, sepertiKode Kesalahan OKEX Untuk Berjangka

Kesalahan transaksi

Anda harus mempertimbangkan bagaimana menangani kesalahan saat menulis kode strategi. Berikut adalah beberapa contoh:

 // 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.Sambungkan ke bursa secara langsung

FMZ membungkus semua data pertukaran yang berbeda ke dalam format yang sama, yang memudahkan untuk menulis strategi lintas platform. Namun, Anda tidak dapat mendapatkan data spesifik dari API tertentu yang memberikan informasi tambahan dan tidak dapat mengakses API yang tidak didukung FMZ. Ada dua solusi untuk masalah ini.

GetRawJSON

Kembalikan konten asli (string) yang dikembalikan oleh permintaan API REST terakhir, yang dapat digunakan untuk menganalisis informasi mentah sendiri.

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

Cari semua rincian tentangHttpQuerypadahttps://fmz-docs.readthedocs.io/en/latest/code_Instruction/Global Function.html#

HttpQuerymengembalikan data mentah dari permintaan ini yang harus dianalisis terlebih dahulu.

//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)

Untuk API publik,HttpQueryadalah fungsi yang sangat berguna.HttpQueryhanya mendukung JavaScript, untuk Python, menggunakanurlib2ataurequestperpustakaan untuk mengirim permintaan http langsung.

IO

Untuk API pribadi, menggunakanHttpQueryakan sangat rumit karena Anda perlu menangani API-kunci, tanda, hash, dllIOadalah fungsi yang berguna untuk kondisi ini, periksa padahttps://fmz-docs.readthedocs.io/en/latest/code_Instruction/Extent API.html#io. IODi bagian ini, kami hanya fokus pada akses ke API pribadi.

Menggunakan fungsi ini membutuhkan pemahaman API asli bursa terlebih dahulu. Di bawah ini adalah langkah-langkah untuk membuat stop order yang tidak didukung oleh FMZ di BitMEX.

Kode JavaScript akhir:

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

6.Menggunakan websocket

Pada dasarnya semua bursa mata uang digital mendukung pengiriman data pasar melalui websocket, dan beberapa bursa bahkan mendukung pembaruan informasi akun. Dibandingkan dengan sisa API, websocket umumnya memiliki keuntungan latensi rendah, frekuensi tinggi, dan tidak dibatasi oleh frekuensi permintaan API platform. Kelemahannya adalah bahwa hal itu dapat terganggu dan pemrosesan tidak intuitif.

Untuk JavaScript, Anda dapat menggunakanDialfungsi untuk terhubung ke websocket, Untuk Python, Anda dapat menggunakanDialatauwebsocket_client libray.

Tutorial ini akan berfokus pada menghubungkan websocket menggunakan JavaScript danDialUntuk memperluas berbagai kegunaan, fungsi Dial telah diperbarui beberapa kali. Tutorial ini akan menunjukkan strategi event-driven berbasis websocket dan cara terhubung ke beberapa pertukaran.

Terhubung ke websocket

  • 1.Sebagian besar kasus, Anda dapat terhubung secara langsung.Di bawah ini adalah contoh koneksi ke Binance all ticker.
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")
    
  • 2.Untuk data yang dikembalikan dari format terkompresi, data tersebut harus ditentukan pada saat koneksi.compressberarti bahwa data dalam format terkompresi, dan parametermodemewakili apakah mengirim atau menerima dikompresi. Contoh koneksi ke OKEX
    var client = Dial("wss://real.okex.com:10441/websocket?compress=true|compress=gzip_raw&mode=recv")
    
  • 3.Fungsi Dial mendukung koneksi ulang otomatis, yang dilakukan oleh bahasa Go yang mendasarinya. Untuk konten data permintaan sudah ada di url, seperti contoh Biannce, ini nyaman dan disarankan. Bagi mereka yang perlu mengirim pesan langganan, Anda dapat mempertahankan koneksi ulang sendiri.
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr?reconnect=true")
    
  • 4.Beberapa bursa saluran langganan disertakan dalam url, seperti Binance, tetapi beberapa mengharuskan pengguna untuk mengirim saluran langganan, seperti coinbase:
    var client = Dial("wss://ws-feed.pro.coinbase.com", 60)
    client.write('{"type": "subscribe","product_ids": ["BTC-USD"],"channels": ["ticker","heartbeat"]}')
    

Menerima data

Secara umum, data dari websocket dapat dibaca secara terus menerus tanpa tidur dalam loop tak terbatas.

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 mendorong data dengan sangat cepat. yang mendasari dari docker cache semua data dalam antrian, dan kemudian mengembalikan yang pertama ketika program memanggilread. Operasi jaringan robot sepertiBuy,GetAccount,CancelOrderUntuk informasi seperti push transaksi, push akun, subset deep push, dll, kita membutuhkan data historis. untuk data pasar, kita biasanya hanya peduli dengan yang terbaru.

Peraturanread()fungsi mengembalikan data tertua dalam antrian jika tidak ada argumen, dan blok ketika tidak ada data (program dihentikan di sini).read(-2)untuk segera mengembalikan data terbaru, dan kembalinulljika tidak ada data dalam antrian (program tidak akan berhenti).

Sambungkan ke beberapa websocket

Dalam hal ini jelas bahwa program tidak dapat menggunakan sederhanaread()karena pertukaran akan memblokir dan menunggu data baru, dan pertukaran lain tidak akan menerima data barunya sendiri segera.

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
    }
}

Kerangka umum untuk menggunakan websocket

Karena data push telah digunakan, program secara alami ditulis sebagai tipe event-driven, memperhatikan frekuensi permintaan 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)
    }
}

Semua parameter

Parameter dariDial(Address, Timeout): Timeout: timeout dari koneksi Alamat dapat diikuti oleh parameter lain yang terkait dengan&. Alamat dan parameter dipisahkan oleh|,

Parameter deskripsi
mengompres Metode kompresi, dapatgzip_raw, gzip. Penggunaan OKEXgzip_raw
modus bisadualberarti baik mengirim dan menerima perlu dikompresi,sendberarti mengirim perlu dikompresi danrecvberarti menerima.
Proxy Pengaturan proxy untuk ss5.socks5://name:pwd@192.168.0.1:1080
Hubungkan kembali Reconnect=trueuntuk memungkinkan koneksi kembali
interval intervaladalah interval percobaan ulang, default adalah 1000ms
muatan Pesan langganan yang perlu dikirim ketika wss terhubung kembali

Parameter dariread(): Ketika websocket terputus,read()akan mengembalikan string kosong.

Parameter Tidak ada -1 -2 2000
antrian tidak kosong mengembalikan data tertua segera mengembalikan data tertua segera Kembali data terbaru segera mengembalikan data tertua segera
antrian kosong Blok sampai data baru kembali kembalinullsegera kembalinullsegera Tunggu kurang dari 2000ms sampai data baru kembali, jika tidak, kembalinull

Penggunaanclose(): Tutup koneksi websocket.

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

7.Asynchronous atau Multithreading

Anda mungkin telah memperhatikan semua kode yang kita miliki sekarang adalah single thread, eksekusi berurutan.GOuntuk melakukan itu, yang sangat terbatas.Goketika Anda benar-benar peduli tentang keterlambatan dan konsumsi waktu dari setiap permintaan API.

pertukaran.Go (Metode, Args)

Metode: nama fungsi. Args: args dari metode.

Daftar fungsi yang didukung:GetTicker, GetDepth, GetTrades, GetRecords, GetAccount, GetOrders, GetOrder, CancelOrder, Buy, Sell, GetPosition.

Contoh 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()fungsi harus dipanggil setelahGofungsi, jika tidak, sumber thread akan terakumulasi sampai tahun 2000 dan mengembalikan kesalahan.

8.Tabel dan grafik

LogStatusdan Tabel

LogStatus akan Log pesan atau tabel di bilah status bot, akan menyegarkan setiap kali.

//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 dapat mencatat tabel di halaman robot Anda.`karakter ke kedua sisi dan memperlakukannya sebagai format pesan yang kompleks (saat ini didukung tabel).

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])+'`')

Grafik

Menggambar angka di halaman manajemen robot. Dukungan grafik HighStocks dan HighCharts, cekhttps://www.highcharts.com/demodanhttps://www.highcharts.com/stock/demountuk lebih banyak contoh. Objek Chart memiliki__isStockAtribut yang tidak ada dalam yang asli.__isStockadalah false, grafik akan ditampilkan sebagai HighCharts.__isStockadalah benar, grafik akan ditampilkan sebagai HighStocks.reset()untuk membersihkan data grafik.

Contoh JavaScript menggunakan Chart untuk menggambar harga dua simbol:

// 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);
    }
}

Mendukung tampilan beberapa gambar, contoh lengkap:https://www.fmz.com/strategy/136056 img

9.Contoh strategi

Template adalah library yang menyertakan banyak fitur canggih, yang memudahkan menulis strategi Anda. Untuk menggunakan template, Anda harus menyalin template yang Anda butuhkan terlebih dahulu.https://www.fmz.com/strategy/27293Kemudian pilih di halaman edit strategi.imgFungsi disebut setelah$.dalam template JavaScript dan setelahext.dalam template 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)
    }
}

Berikut adalah contoh sederhana lainnya yang menggunakan template plot:https://www.fmz.com/strategy/121917


Lebih banyak

q25459768Terima kasih.

RumputAku sedang mengerjakan tutorial ini. akan memakan waktu beberapa hari untuk menyelesaikannya. jangan ragu untuk mengajukan pertanyaan.