Tutorial pertengahan FMZ

Penulis:Rumput, Dicipta: 2019-04-12 14:28:19, Dikemas kini: 2024-02-05 20:07:56

[TOC]

img

Tutorial ini akan merangkumi lebih banyak butiran mengenai platform FMZ, lebih banyak kemahiran praktikal tentang menggunakan API.

Selepas mempelajari keseluruhan tutorial, anda akan menggunakan sepenuhnya FMZ dan dapat menulis strategi yang lebih disesuaikan, lebih cekap dan lebih kompleks.

1.Tambah pelbagai pertukaran dan perdagangan pelbagai simbol

Anda boleh berdagang di pelbagai bursa dan pelbagai simbol dalam satu robot dengan mudah.

  • Tambah satu pertukaran atau pelbagai pertukaran apabila memulakan robot.
  • API boleh dipanggil sepertiexchange.GetTicker()apabila satu pertukaran ditambah
  • Apabila pelbagai pertukaran ditambahkan, API dipanggil sepertiexchanges[0].GetTicker(), exchanges[1].GetTicker() img
  • Anda boleh menambah pertukaran yang sama dengan simbol yang berbeza.img
  • Anda boleh menukar 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 niaga hadapan dan swap

Setakat ini, FMZ menyokong semua bursa niaga hadapan utama, seperti OKEX, HuobiDM, BitMEX, GateIO dan Deribit, dan kontrak swap mereka.

Untuk berdagang niaga hadapan di FMZ, anda perlu menambah pertukaran niaga hadapan terlebih dahulu, menetapkan simbol apabila memulakan bot dan menetapkan jenis kontrak dalam kod anda.

Jika bursa menyokong kedua-dua spot dan niaga hadapan, mereka harus ditambahkan kepada FMZ secara berasingan.img

Gambar di bawah menunjukkan cara menetapkan simbol niaga hadapan ke BTC apabila memulakan bot.img

Di bawah adalah bagaimana untuk menetapkan jenis kontrak untuk setiap pertukaran.

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

3.Mengenai backtest

Pengenalan asas

FMZ mempunyai dua mod backtesting:real tickdansimulate tick. Tahap tik sebenar mengandungi semua data sejarah yang telah selesai (satu tik setiap saat), jadi hasil backtesting lebih boleh dipercayai. Tahap simulasi menggunakan data klines sejarah pada selang yang digunakan oleh strategi anda. Tik dalam satu kline dihasilkan oleh algoritma yang sama dengan MT4, anda boleh mencari maklumat lanjut dihttps://www.mql5.com/en/articles/75Sementara itu, selang yang lebih pendek boleh dipilih sebagai pangkalan-klines untuk menjana kutu. Mod tik simulasi jauh lebih cepat tetapi kurang tepat daripada mod tik sebenar. Julat kline yang lebih pendek dalam mod tik simulasi adalah kompromi antara ketepatan dan kelajuan ujian.

Konfigurasi Backtest

Berikut adalah tetapan lalai:imgTitik tersembunyi:img

Hasil ujian belakang

img

4.Toleransi kesilapan

Apabila memanggil mana-mana fungsi yang mengakses API pertukaran (sepertiGetTicker, Buy, CancelOrder, dan lain-lain...), anda mungkin mendapat kegagalan akses kerana masalah pelayan pertukaran, parameter yang salah, masalah penghantaran rangkaian, dan sebagainya.nullJadi anda perlu tahu bagaimana untuk menangani kesilapan.

Apa yang salah?

Bot akan mengembalikan mesej ralat apabila ralat berlaku. Hanya mencari nama pertukaran + msg ralat, anda boleh mencari apa masalahnya. Sebagai contoh,{"result":false,"error_code":20049}dikembalikan apabila panggilanexchange.GetAccount()di OKEX.OKEX 20049Inilah hasilnya:imgAnda juga boleh menyemak kod ralat pada pertukaran API doc, sepertiKod ralat OKEX Untuk niaga hadapan

Kesalahan urus niaga

Anda harus mempertimbangkan bagaimana untuk menangani kesilapan apabila menulis kod strategi.

 // 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 berbeza ke dalam format yang sama, yang memudahkan untuk menulis strategi rentas platform. Walau bagaimanapun, anda tidak dapat mendapatkan data khusus API tertentu yang memberikan maklumat tambahan dan tidak dapat mengakses API yang tidak disokong FMZ. Terdapat dua penyelesaian untuk masalah ini.

GetRawJSON

Kembalikan kandungan asal (string) yang dikembalikan oleh permintaan API REST terakhir, yang boleh digunakan untuk menganalisis maklumat 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 butiran tentangHttpQuerypadahttps://fmz-docs.readthedocs.io/en/latest/code_Instruction/Global Function.html#

HttpQuerymengembalikan data mentah 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 awam,HttpQueryadalah fungsi yang sangat berguna.HttpQueryhanya menyokong JavaScript, untuk Python, menggunakanurlib2ataurequestperpustakaan untuk menghantar permintaan http secara langsung.

IO

Untuk API peribadi, menggunakanHttpQueryakan menjadi sangat rumit kerana anda perlu berurusan dengan API-kunci, tanda, hash, dllIOadalah fungsi berguna untuk keadaan ini, semak padahttps://fmz-docs.readthedocs.io/en/latest/code_Instruction/Extent API.html#io. IOPada bahagian ini, kami hanya memberi tumpuan kepada akses kepada API peribadi.

Menggunakan fungsi ini memerlukan pemahaman API asal bursa terlebih dahulu. Di bawah adalah langkah untuk membuat pesanan berhenti yang tidak disokong oleh FMZ di BitMEX.

Kod JavaScript akhir:

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

6.Penggunaan websocket

Pada asasnya semua pertukaran mata wang digital menyokong menghantar data pasaran melalui websocket, dan beberapa pertukaran bahkan menyokong mengemas kini maklumat akaun. Berbanding dengan API selebihnya, websocket umumnya mempunyai kelebihan latensi rendah, frekuensi tinggi, dan tidak terhad oleh frekuensi permintaan API platform. Kelemahannya adalah bahawa ia mungkin terganggu dan pemprosesannya tidak intuitif.

Untuk JavaScript, anda boleh menggunakanDialfungsi untuk menyambung ke websocket, Untuk Python, anda boleh menggunakanDialatauwebsocket_client libray.

Tutorial ini akan memberi tumpuan kepada menyambungkan websocket menggunakan JavaScript danDialfungsi di FMZ Quantization Platform. Untuk memperluaskan pelbagai kegunaan, fungsi Dial telah dikemas kini beberapa kali. Tutorial ini akan menunjukkan strategi yang didorong oleh peristiwa berasaskan websocket dan cara menyambung ke pelbagai pertukaran.

Disambungkan ke websocket

  • 1.Sebahagian besar kes, anda boleh menyambung secara langsung.Di bawah ini adalah contoh menyambung ke Binance all ticker.
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")
    
  • 2.Bagi data balik format tertekan, ia perlu ditentukan pada masa sambungan.compressbermaksud bahawa data adalah dalam format mampat, dan parametermodemewakili sama ada penghantaran atau penerimaan dimampatkan. Contoh menyambung ke OKEX
    var client = Dial("wss://real.okex.com:10441/websocket?compress=true|compress=gzip_raw&mode=recv")
    
  • 3.Fungsi Dial menyokong sambungan semula automatik, yang dilakukan oleh bahasa Go yang mendasari. Untuk kandungan data permintaan sudah berada di url, seperti contoh Biannce, ia mudah dan disyorkan. Bagi mereka yang perlu menghantar mesej langganan, anda boleh mengekalkan sambungan semula sendiri.
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr?reconnect=true")
    
  • 4.Sebahagian pertukaran saluran langganan termasuk dalam url, seperti Binance, tetapi ada yang memerlukan pengguna untuk menghantar 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 amnya, data dari websocket boleh dibaca secara berterusan tanpa tidur dalam gelung tanpa akhir.

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 docker cache semua data dalam antrian, dan kemudian mengembalikan yang pertama apabila program memanggilread. Operasi rangkaian robot sepertiBuy,GetAccount,CancelOrderuntuk maklumat seperti dorongan transaksi, dorongan akaun, dorongan mendalam subset, dll, kita memerlukan data sejarah. untuk data pasaran, kita biasanya hanya peduli dengan yang terbaru.

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

Sambungkan ke pelbagai websocket

Dalam kes ini adalah jelas bahawa program tidak boleh menggunakan mudahread()kerana pertukaran akan menyekat dan menunggu data baru, dan pertukaran lain tidak akan menerima data baru sendiri dengan 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
    }
}

Rangka kerja umum untuk menggunakan websocket

Oleh kerana data push telah digunakan, program secara semula jadi ditulis sebagai jenis yang didorong oleh peristiwa, memberi perhatian kepada kekerapan 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

ParameterDial(Address, Timeout): Timeout: masa cuti sambungan Alamat boleh diikuti oleh parameter lain yang berkaitan dengan&. Alamat dan parameter dipisahkan oleh|,

Parameter Penerangan
memampatkan Kaedah mampatan, bolehgzip_raw, gzip. Penggunaan OKEXgzip_raw
mod bolehdualbermakna kedua-dua menghantar dan menerima perlu dimampatkan,sendbermakna menghantar perlu ditekan danrecvBermakna menerima.
penggantinya tetapan proksi untuk ss5.socks5://name:pwd@192.168.0.1:1080
sambung semula Reconnect=trueuntuk membolehkan sambungan semula
Jangkaan intervaladalah selang percubaan semula, lalai adalah 1000ms
muatan Mesej langganan yang perlu dihantar apabila wss menyambung semula

Parameterread(): Apabila websocket disconnected,read()akan mengembalikan rentetan kosong.

Parameter Tiada -1 -2 2000
barisan tidak kosong mengembalikan data tertua dengan segera mengembalikan data tertua dengan segera Kembalikan data terkini dengan segera mengembalikan data tertua dengan segera
barisan kosong Blokkan sehingga data baru kembali Kembalinullsegera Kembalinullsegera tunggu kurang daripada 2000ms sehingga data baru kembali, jika tidak, kembalinull

Penggunaanclose(): Tutup sambungan 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 melihat semua kod yang kita ada sekarang adalah satu benang, pelaksanaan berturut-turut. JavaScript mentah tidak menyokong asynchronous, bagaimanapun, FMZ menyediakan fungsiGOuntuk melakukan itu, yang sangat terhad.Goapabila anda benar-benar mengambil berat tentang kelewatan dan penggunaan masa setiap permintaan API.

pertukaran.Go ((Method, Args)

Kaedah: nama fungsi. Args: Args kaedah.

Senarai fungsi yang disokong: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 mesti dipanggil selepasGofungsi, jika tidak, sumber thread akan terkumpul sehingga tahun 2000 dan mengembalikan ralat.

8.Tabel dan carta

LogStatusdan Jadual

LogStatus akan Log mesej atau jadual pada bar 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 boleh log jadual pada halaman robot anda.`karakter ke kedua-dua belah pihak dan memperlakukannya sebagai format mesej yang kompleks (jadual yang kini disokong).

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

Jadual

Lukis angka pada halaman pengurusan robot. Sokongan carta HighStocks dan HighCharts, semakhttps://www.highcharts.com/demodanhttps://www.highcharts.com/stock/demountuk lebih banyak contoh. Objek Chart mempunyai__isStockatribut yang tidak wujud dalam yang asal. Jika__isStockadalah false, carta akan dipaparkan sebagai HighCharts.__isStockadalah benar, carta akan dipaparkan sebagai HighStocks.reset()untuk membersihkan data carta.

Contoh JavaScript menggunakan Carta untuk menarik 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);
    }
}

Menyokong paparan pelbagai angka, contoh lengkap:https://www.fmz.com/strategy/136056 img

9.Contoh Strategi

Template adalah perpustakaan yang merangkumi banyak ciri lanjutan, yang memudahkan menulis strategi anda. Untuk menggunakan templat, anda harus menyalin templat yang anda perlukan terlebih dahulu. Ambil perpustakaan JavaScript Plot sebagai contoh, salin darihttps://www.fmz.com/strategy/27293dan simpan. Kemudian pilih pada halaman edit strategi.imgFungsi dipanggil selepas$.dalam templat JavaScript dan selepasext.dalam templat 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 satu lagi contoh mudah yang menggunakan templat plot:https://www.fmz.com/strategy/121917


Lebih lanjut

q25459768Terima kasih.

RumputSaya sedang bekerja pada tutorial ini. Ia akan mengambil masa beberapa hari untuk menyelesaikan. berasa bebas untuk bertanya apa-apa soalan.