[TOC]
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.
Anda dapat berdagang di beberapa bursa dan beberapa simbol dalam satu robot dengan mudah.
exchange.GetTicker()
ketika satu pertukaran ditambahkanexchanges[0].GetTicker()
, exchanges[1].GetTicker()
exchange
dengan menggunakanIO
fungsivar 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)
}
}
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.
Gambar di bawah ini menunjukkan cara mengatur simbol futures ke BTC saat memulai bot.
Di bawah ini adalah cara mengatur jenis kontrak untuk setiap bursa.
exchange.SetContractType("swap")
exchange.SetContractType("this_week")
exchange.SetContractType("next_week")
exchange.SetContractType("quarter")
exchange.SetContractType("this_week")
exchange.SetContractType("next_week")
exchange.SetContractType("quarter")
exchange.SetContractType("XBTUSD")
exchange.SetContractType("XBTM19")
exchange.SetContractType("swap")
exchange.SetContractType("BTC-PERPETUAL")
exchange.SetContractType("BTC-27APR18")
Pengantar dasar
FMZ memiliki dua mode backtesting:real tick
dansimulate 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:Tindik tersembunyi:
Hasil tes balik
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.null
Jadi 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:Anda 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
}
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 tentangHttpQuery
padahttps://fmz-docs.readthedocs.io/en/latest/code_Instruction/Global Function.html#
HttpQuery
mengembalikan 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,HttpQuery
adalah fungsi yang sangat berguna.HttpQuery
hanya mendukung JavaScript, untuk Python, menggunakanurlib2
ataurequest
perpustakaan untuk mengirim permintaan http langsung.
IO
Untuk API pribadi, menggunakanHttpQuery
akan sangat rumit karena Anda perlu menangani API-kunci, tanda, hash, dllIO
adalah fungsi yang berguna untuk kondisi ini, periksa padahttps://fmz-docs.readthedocs.io/en/latest/code_Instruction/Extent API.html#io. IO
Di 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.
POST
, Parameter termasuk simbol,sisi, orderQty,stopPx,ordType,yang harus diatur seperti "simbol=XBTUSD&side=Buy&orderQty=1&stopPx=4000&ordType=StopKode JavaScript akhir:
var id = exchange.IO("api", "POST", "/api/v1/order", "symbol=XBTUSD&side=Buy&orderQty=1&stopPx=4000&ordType=Stop")
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 menggunakanDial
fungsi untuk terhubung ke websocket, Untuk Python, Anda dapat menggunakanDial
atauwebsocket_client
libray.
Tutorial ini akan berfokus pada menghubungkan websocket menggunakan JavaScript danDial
Untuk 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
var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")
compress
berarti bahwa data dalam format terkompresi, dan parametermode
mewakili apakah mengirim atau menerima dikompresi. Contoh koneksi ke OKEXvar client = Dial("wss://real.okex.com:10441/websocket?compress=true|compress=gzip_raw&mode=recv")
var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr?reconnect=true")
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
,CancelOrder
Untuk 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 kembalinull
jika 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 | bisadual berarti baik mengirim dan menerima perlu dikompresi,send berarti mengirim perlu dikompresi danrecv berarti menerima. |
Proxy | Pengaturan proxy untuk ss5.socks5://name:pwd@192.168.0.1:1080 |
Hubungkan kembali | Reconnect=true untuk memungkinkan koneksi kembali |
interval | interval adalah 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 | kembalinull segera |
kembalinull segera |
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()
}
Anda mungkin telah memperhatikan semua kode yang kita miliki sekarang adalah single thread, eksekusi berurutan.GO
untuk melakukan itu, yang sangat terbatas.Go
ketika 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 setelahGo
fungsi, jika tidak, sumber thread akan terakumulasi sampai tahun 2000 dan mengembalikan kesalahan.
LogStatus
dan 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__isStock
Atribut yang tidak ada dalam yang asli.__isStock
adalah false, grafik akan ditampilkan sebagai HighCharts.__isStock
adalah 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
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.Fungsi 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
q25459768Terima kasih.
RumputAku sedang mengerjakan tutorial ini. akan memakan waktu beberapa hari untuk menyelesaikannya. jangan ragu untuk mengajukan pertanyaan.