FMZ hướng dẫn trung gian

Tác giả:Cỏ nhỏ, Tạo: 2019-04-12 14:28:19, Cập nhật: 2024-02-05 20:07:56

[TOC]

img

Bài hướng dẫn này sẽ bao gồm thêm chi tiết về nền tảng FMZ, các kỹ năng thực tế hơn về việc sử dụng API. Bạn nên đọc qua hướng dẫn cho người mới bắt đầu và có một sự hiểu biết cơ bản về FMZ trước khi học hướng dẫn trung gian này.

Sau khi học toàn bộ hướng dẫn, bạn sẽ sử dụng đầy đủ FMZ và có thể viết các chiến lược tùy chỉnh hơn, hiệu quả hơn và phức tạp hơn.

1.Thêm nhiều sàn giao dịch và giao dịch nhiều biểu tượng

Bạn có thể giao dịch trên nhiều sàn giao dịch và nhiều biểu tượng trong một robot dễ dàng.

  • Thêm một trao đổi hoặc nhiều trao đổi khi khởi động robot.
  • API có thể được gọi nhưexchange.GetTicker()khi thêm một trao đổi
  • Khi nhiều trao đổi được thêm vào, API được gọi là nhưexchanges[0].GetTicker(), exchanges[1].GetTicker() img
  • Bạn có thể thêm cùng một giao dịch với các biểu tượng khác nhau.img
  • Bạn có thể thay đổi biểu tượng liên kết vớiexchangebằng cách sử dụngIOchức năng
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.TradeHợp đồng tương lai và hợp đồng đổi

Cho đến nay, FMZ hỗ trợ tất cả các sàn giao dịch tương lai lớn, chẳng hạn như OKEX, HuobiDM, BitMEX, GateIO và Deribit, và hợp đồng hoán đổi của họ.

Để giao dịch tương lai trên FMZ, bạn cần thêm một sàn giao dịch tương lai trước tiên, đặt biểu tượng khi khởi động bot và đặt loại hợp đồng trong mã của bạn.

Nếu một sàn giao dịch hỗ trợ cả giao dịch tức thời và tương lai, chúng nên được thêm vào FMZ riêng biệt.img

Hình dưới đây cho thấy cách đặt biểu tượng tương lai thành BTC khi khởi động bot.img

Dưới đây là cách thiết lập một loại hợp đồng cho mỗi sàn giao dịch.

  • Được rồi.
    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.Về backtest

Giới thiệu cơ bản

FMZ có hai chế độ backtesting:real ticksimulate tick. Mức độ tick thực sự chứa tất cả các dữ liệu lịch sử đã hoàn thành (một tick mỗi giây), do đó kết quả backtesting đáng tin cậy hơn. Mức độ mô phỏng sử dụng dữ liệu lịch sử klines ở khoảng thời gian được sử dụng bởi chiến lược của bạn. Các tick trong một kline được tạo ra bởi một thuật toán giống như MT4, bạn có thể tìm hiểu thêm chi tiết tạihttps://www.mql5.com/en/articles/75Trong khi đó, một khoảng thời gian ngắn hơn có thể được lựa chọn như cơ sở-klines để tạo ra bọ ve. Chế độ tick mô phỏng nhanh hơn nhiều nhưng kém chính xác hơn so với chế độ tick thực tế.

Cấu hình backtest

Đây là cài đặt mặc định:imgĐặt dấu vết:img

Kết quả kiểm tra ngược

img

4.Sự khoan dung với lỗi

Khi gọi bất kỳ chức năng nào truy cập vào API trao đổi (nhưGetTicker, Buy, CancelOrder, v.v...), bạn có thể nhận được sự cố truy cập do một vấn đề máy chủ trao đổi, tham số sai, vấn đề truyền mạng, v.v. Trong trường hợp này, chức năng sẽ trả vềnullVì vậy bạn cần phải biết cách xử lý lỗi.

Có lỗi gì không?

Bot sẽ trả về một thông báo lỗi khi một lỗi xảy ra. Chỉ cần tìm kiếm tên trao đổi + lỗi msg, bạn có thể tìm thấy vấn đề là gì. Ví dụ, Một lỗi{"result":false,"error_code":20049}được trả về khi gọiexchange.GetAccount()trên OKEX.OKEX 20049, đây là kết quả:imgBạn cũng có thể kiểm tra mã lỗi trên tài liệu API trao đổi, chẳng hạn nhưMã lỗi OKEX For Futures

Lỗi giao dịch

Bạn nên xem xét cách xử lý lỗi khi viết mã chiến lược.

 // 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.Giao tiếp trực tiếp với sàn giao dịch

Tuy nhiên, bạn không thể có được dữ liệu cụ thể của một API nhất định cung cấp thông tin thêm và không thể truy cập vào API mà FMZ không hỗ trợ. Có hai giải pháp cho vấn đề này.

GetRawJSON

Trả về nội dung gốc (dòng chuỗi) được trả về bởi yêu cầu API REST cuối cùng, có thể được sử dụng để phân tích thông tin thô của chính bạn.

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

Tìm tất cả các chi tiết vềHttpQuerytrênhttps://fmz-docs.readthedocs.io/en/latest/code_Instruction/Global Function.html#

HttpQuerytrả về dữ liệu thô của yêu cầu này mà nên được phân tích đầu tiên.

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

Đối với những API công khai,HttpQuerylà một chức năng thực sự hữu ích.HttpQuerychỉ hỗ trợ JavaScript, cho Python, sử dụngurlib2hoặcrequestthư viện để gửi các yêu cầu HTTP trực tiếp.

IO

Đối với những API riêng, sử dụngHttpQuerysẽ rất phức tạp bởi vì bạn cần phải đối phó với API-key, ký hiệu, hash, vvIOlà một chức năng tiện lợi cho tình trạng này, kiểm tra nó trênhttps://fmz-docs.readthedocs.io/en/latest/code_Instruction/Extent API.html#io. IOTrong phần này, chúng tôi chỉ tập trung vào việc truy cập vào các API riêng.

Sử dụng chức năng này đòi hỏi phải hiểu API gốc của sàn giao dịch trước. Dưới đây là các bước để thực hiện lệnh dừng mà FMZ không hỗ trợ trên BitMEX.

Mã JavaScript cuối cùng:

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

6.Sử dụng websocket

Về cơ bản, tất cả các sàn giao dịch tiền kỹ thuật số đều hỗ trợ gửi dữ liệu thị trường qua websocket, và một số sàn giao dịch thậm chí hỗ trợ cập nhật thông tin tài khoản. So với phần còn lại của API, websocket thường có những lợi thế về độ trễ thấp, tần số cao và không bị giới hạn bởi tần số yêu cầu API nền tảng.

Đối với JavaScript, bạn có thể sử dụngDialchức năng để kết nối với websocket, Đối với Python, bạn có thể sử dụngDialhoặcwebsocket_client libray.

Bài hướng dẫn này sẽ tập trung vào kết nối websocket bằng JavaScript vàDialchức năng trên nền tảng định lượng FMZ. Để mở rộng các sử dụng khác nhau, chức năng Dial đã được cập nhật nhiều lần. hướng dẫn này sẽ chứng minh chiến lược dựa trên sự kiện dựa trên websocket và cách kết nối với nhiều sàn giao dịch.

Kết nối với websocket

  • 1. Trong hầu hết các trường hợp, bạn có thể kết nối trực tiếp.
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")
    
  • 2.Đối với dữ liệu trả về định dạng nén, nó cần phải được chỉ định tại thời điểm kết nối.compresscó nghĩa là dữ liệu ở định dạng nén, và tham sốmodeđại diện cho việc gửi hoặc nhận được nén. Một ví dụ về kết nối với OKEX
    var client = Dial("wss://real.okex.com:10441/websocket?compress=true|compress=gzip_raw&mode=recv")
    
  • 3. Chức năng Dial hỗ trợ kết nối lại tự động, được thực hiện bởi ngôn ngữ Go cơ bản. Đối với nội dung dữ liệu yêu cầu đã có trong url, chẳng hạn như ví dụ về Biannce, nó thuận tiện và được khuyến cáo. Đối với những người cần gửi tin nhắn đăng ký, bạn có thể duy trì kết nối lại một mình.
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr?reconnect=true")
    
  • 4. Một số sàn giao dịch kênh đăng ký được bao gồm trong url, chẳng hạn như Binance, nhưng một số yêu cầu người dùng gửi các kênh đăng ký, chẳng hạn như coinbase:
    var client = Dial("wss://ws-feed.pro.coinbase.com", 60)
    client.write('{"type": "subscribe","product_ids": ["BTC-USD"],"channels": ["ticker","heartbeat"]}')
    

Nhận dữ liệu

Thông thường, dữ liệu từ websocket có thể được đọc liên tục mà không cần ngủ trong một vòng lặp vô hạn.

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 đẩy dữ liệu rất nhanh. cơ bản của docker lưu trữ tất cả dữ liệu trong hàng đợi, và sau đó trả về đầu tiên khi chương trình gọireadCác hoạt động mạng của robot như:Buy,GetAccount,CancelOrdersẽ gây ra sự chậm trễ, có thể dẫn đến sự tích lũy dữ liệu. Đối với thông tin như đẩy giao dịch, đẩy tài khoản, đẩy sâu, vv, chúng tôi cần dữ liệu lịch sử. Đối với dữ liệu thị trường, chúng tôi thường chỉ quan tâm đến dữ liệu mới nhất.

Cácread()function trả về dữ liệu cũ nhất trong hàng đợi nếu không có đối số, và chặn khi không có dữ liệu (chương trình được tạm dừng ở đây).read(-2)để ngay lập tức trả lại dữ liệu mới nhất, và trả lạinullnếu không có dữ liệu trong hàng đợi (chương trình sẽ không tạm dừng).

Kết nối với nhiều websocket

Trong trường hợp này, rõ ràng là chương trình không thể sử dụng đơn giảnread()bởi vì một sàn giao dịch sẽ chặn và chờ dữ liệu mới, và sàn giao dịch khác sẽ không nhận được dữ liệu mới ngay lập tức.

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

Khung chung cho việc sử dụng websocket

Vì dữ liệu đẩy đã được sử dụng, chương trình tự nhiên được viết như một loại điều khiển sự kiện, chú ý đến tần suất yêu cầu 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)
    }
}

Tất cả các Prameter

Các thông số củaDial(Address, Timeout): Timeout: thời gian ngừng kết nối Địa chỉ có thể được theo sau bởi các tham số khác được kết nối với&. Địa chỉ và tham số được tách bởi|,

Parameter mô tả
nén Phương pháp nén, có thểgzip_raw, gzip. OKEX sử dụnggzip_raw
chế độ có thểdualcó nghĩa là cả hai gửi và nhận cần phải được nén,sendcó nghĩa là gửi cần phải được nén vàrecvcó nghĩa là nhận.
đại diện cài đặt proxy cho ss5.socks5://name:pwd@192.168.0.1:1080
kết nối lại Reconnect=trueđể cho phép kết nối lại
khoảng thời gian intervallà khoảng thời gian thử lại, mặc định là 1000ms
tải trọng Tin nhắn đăng ký cần được gửi khi wss kết nối lại

Các thông số củaread(): Khi mạng bị ngắt kết nối,read()sẽ trả về một chuỗi trống.

Parameter Không có -1 -2 2000
hàng đợi không trống trả lại dữ liệu cũ nhất ngay lập tức trả lại dữ liệu cũ nhất ngay lập tức trả lại dữ liệu mới nhất ngay lập tức trả lại dữ liệu cũ nhất ngay lập tức
hàng đợi trống chặn cho đến khi dữ liệu mới trở lại trở lạinullngay lập tức trở lạinullngay lập tức chờ ít hơn 2000ms cho đến khi dữ liệu mới trở lại, nếu không, trở lạinull

Việc sử dụngclose(): Khép kết nối websocket.

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

7.Asynchronous hoặc Multithreading

Bạn có thể đã nhận thấy tất cả các mã mà chúng tôi có bây giờ là chuỗi đơn, trình tự thực thi. JavaScript thô không hỗ trợ đồng bộ, tuy nhiên, FMZ cung cấp một chức năngGOđể làm điều đó, mà rất hạn chế.Gokhi bạn thực sự quan tâm đến sự chậm trễ và thời gian tiêu thụ của mỗi yêu cầu API.

trao đổi.Go ((Phương pháp, Args)

Phương pháp: tên hàm. Args: các args của phương pháp.

Danh sách các chức năng được hỗ trợ:GetTicker, GetDepth, GetTrades, GetRecords, GetAccount, GetOrders, GetOrder, CancelOrder, Buy, Sell, GetPosition.

Ví dụ về 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()hàm phải được gọi sauGochức năng, nếu không, các tài nguyên chủ đề sẽ tích lũy đến năm 2000 và trả về một lỗi.

8.Bảng và biểu đồ

LogStatusvà Bảng

LogStatus sẽ đăng một tin nhắn hoặc bảng trên thanh trạng thái của bot, sẽ làm mới mỗi lần.

//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 có thể đăng bảng trên trang robot của bạn. Thêm`ký tự ở cả hai bên và coi nó như một định dạng thông điệp phức tạp (hiện tại hỗ trợ bảng).

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

Biểu đồ

Vẽ số trên trang quản lý robot. Hỗ trợ biểu đồ HighStocks và HighCharts, kiểm trahttps://www.highcharts.com/demohttps://www.highcharts.com/stock/democho nhiều ví dụ hơn. Đối tượng Chart có một__isStockthuộc tính không tồn tại trong bản gốc.__isStocklà false, biểu đồ sẽ được hiển thị như HighCharts.__isStocklà đúng, biểu đồ sẽ được hiển thị như HighStocks.reset()để xóa dữ liệu biểu đồ.

Một ví dụ về JavaScript sử dụng Chart để vẽ giá của hai biểu tượng:

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

Hỗ trợ hiển thị nhiều hình ảnh, một ví dụ đầy đủ:https://www.fmz.com/strategy/136056 img

9.Mẫu chiến lược

Template là một thư viện bao gồm nhiều tính năng tiên tiến, giúp bạn dễ dàng viết chiến lược của mình. Để sử dụng một mẫu, bạn nên sao chép mẫu bạn cần đầu tiên.https://www.fmz.com/strategy/27293và lưu. Sau đó chọn nó trên trang chỉnh sửa chiến lược.imgCác hàm được gọi theo$.trong mẫu JavaScript và sau đóext.trong mẫu 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)
    }
}

Dưới đây là một ví dụ đơn giản khác sử dụng mẫu phác thảo:https://www.fmz.com/strategy/121917


Thêm nữa

q25459768Cảm ơn.

Cỏ nhỏTôi đang làm bài hướng dẫn này. Sẽ mất vài ngày để hoàn thành. cảm thấy miễn phí để hỏi bất kỳ câu hỏi nào.