Hướng dẫn nâng cao cho nền tảng FMZ Quant viết chiến lược

Tác giả:Ninabadass, Tạo: 2022-03-22 09:00:57, Cập nhật: 2022-03-29 10:02:52

[TOC] Trước khi học hướng dẫn này, bạn cần phải nghiên cứuBắt đầu với nền tảng FMZ QuantHướng dẫn cơ bản cho nền tảng FMZ Quant Strategy Writing, và trở nên thành thạo ngôn ngữ lập trình.Hướng dẫn cơ bản bao gồm các chức năng được sử dụng phổ biến nhất, nhưng có nhiều chức năng và tính năng chưa được giới thiệu, và chúng sẽ không được đề cập trong hướng dẫn này.Sau khi học hướng dẫn này, bạn sẽ có thể viết nhiều chiến lược miễn phí và tùy chỉnh hơn, và nền tảng FMZ Quant chỉ là một công cụ.

Truy cập dữ liệu thô của nền tảng

Nền tảng FMZ Quant bao gồm tất cả các nền tảng được hỗ trợ. Để duy trì sự đồng nhất, hỗ trợ của chúng tôi cho một API nền tảng duy nhất vẫn chưa hoàn chỉnh. Ví dụ, GetRecords có thể truyền số K-line hoặc thời gian bắt đầu, trong khi nó được cố định trên nền tảng FMZ; một số nền tảng hỗ trợ đặt hàng hàng loạt, trong khi FMZ không hỗ trợ điều đó, v.v. Vì vậy, cần có một cách để truy cập trực tiếp dữ liệu nền tảng.Đối với giao diện công khai (như báo giá thị trường), bạn có thể sử dụngHttpQuery, và đối với giao diện được mã hóa (bao gồm thông tin tài khoản), bạn cần sử dụngIO.Đối với các thông số nhập cụ thể, vui lòng tham khảo các tài liệu API nền tảng tương ứng.Infotrường trả về thông tin thô, nhưng nó vẫn không có sự khác biệt về vấn đề không hỗ trợ giao diện.

GetRawJSON ((()

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

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() Truy cập giao diện công cộng

Để truy cập giao diện công cộng, Js có thể sử dụngHttpQuery, và Python có thể sử dụng các gói liên quan, chẳng hạn nhưurllibhoặcrequests.

HttpQuery mặc định cho phương thức GET, và hỗ trợ nhiều chức năng hơn; hãy xem tài liệu API để biết thêm chi tiết.

var exchangeInfo = JSON.parse(HttpQuery('https://api.binance.com/api/v1/exchangeInfo'))
Log(exchangeInfo)
var ticker = JSON.parse(HttpQuery('https://api.binance.com/api/v1/ticker/24hr'))
var kline = JSON.parse(HttpQuery("https://www.quantinfo.com/API/m/chart/history?symbol=BTC_USD_BITFINEX&resolution=60&from=1525622626&to=1561607596"))

Ví dụ về Python sử dụng yêu cầu:

import requests
resp = requests.get('https://www.quantinfo.com/API/m/chart/history?symbol=BTC_USD_BITFINEX&resolution=60&from=1525622626&to=1561607596')
data = resp.json()

IO truy cập giao diện được mã hóa

Đối với các giao diện đòi hỏi chữ ký API-KEY, chức năng IO có thể được sử dụng, và người dùng chỉ cần quan tâm đến các thông số đến, và quá trình ký hiệu cụ thể sẽ được hoàn thành bởi lớp dưới.

Nền tảng FMZ hiện không hỗ trợ lệnh dừng lỗ BitMEX, có thể được thực hiện thông qua IO, theo các bước sau:

  • đầu tiên, tìm trang hướng dẫn của BitMEX API:https://www.bitmex.com/api/explorer/;
  • sau đó, tìm địa chỉ đặt hàng của BitMEX tại:https://www.bitmex.com/api/v1/order, với phương phápPOST; cho FMZ đã xác định nội bộ địa chỉ cơ sở, bạn chỉ cần đi vào /api/v1/order.
  • Các thông số tương ứng:symbol=XBTUSD&side=Buy&orderQty=1&stopPx=4000&ordType=Stop.

Mã cụ thể:

var id = exchange.IO("api", "POST", "/api/v1/order", "symbol=XBTUSD&side=Buy&orderQty=1&stopPx=4000&ordType=Stop")
// You can also pass in the object 
var id = exchange.IO("api", "POST", "/api/v1/order", "", JSON.stringify({symbol:"XBTUSD",side:"Buy",orderQty:1,stopPx:4000,ordType:"Stop"}))

Ví dụ về IO:https://www.fmz.com/bbs-topic/3683

Sử dụng websocket

Về cơ bản, tất cả các nền tảng tiền điện tử đều hỗ trợ websocket để gửi báo giá thị trường, và một số nền tảng hỗ trợ websocket để cập nhật thông tin tài khoản. So với API nghỉ, websocket thường có những lợi thế, chẳng hạn như độ trễ thấp, tần số cao và không bị giới hạn bởi tần số API nghỉ nền tảng, v.v. Nhược điểm là có một vấn đề gián đoạn, xử lý không trực quan.

Bài viết này chủ yếu sẽ giới thiệu cách sử dụng ngôn ngữ JavaScript và cách sử dụng chức năng Dial được đóng gói bởi nền tảng để kết nối, trên nền tảng FMZ Quant; cho các hướng dẫn và tham số cụ thể có trong tài liệu, bạn có thể tìm kiếm Dial; để thực hiện các chức năng khác nhau, chức năng Dial đã được cập nhật nhiều lần. Bài viết này sẽ đề cập đến điều đó và giới thiệu các chiến lược dựa trên sự kiện dựa trên wss, cũng như vấn đề kết nối nhiều nền tảng. Python cũng có thể sử dụng chức năng Dial hoặc thư viện tương ứng.

1. Websocket kết nối

Nói chung, kết nối trực tiếp qua Websocket; ví dụ để nhận Binance tricker push:

var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")

Nếu dữ liệu được trả về trong định dạng nén, thì cần phải xác định khi kết nối; compress đề cập đến định dạng nén, và mode đại diện cho dữ liệu được trả về cần phải nén; ví dụ: khi kết nối với OKEX:

var client = Dial("wss://real.okex.com:10441/websocket?compress=true|compress=gzip_raw&mode=recv")

Chức năng Dial hỗ trợ kết nối lại, được thực hiện bởi Golang cơ bản. Nếu kết nối được phát hiện bị hỏng, nó sẽ được kết nối lại. Đối với dữ liệu yêu cầu đã có trong url, chẳng hạn như ví dụ của Binance ngay bây giờ, nó rất 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ý, họ có thể tự duy trì cơ chế kết nối lại.

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

Để đăng ký các tin nhắn wss, một số yêu cầu nền tảng nằm trong url, và một số cần phải gửi các kênh đăng ký, chẳng hạn như coinbase:

client = Dial("wss://ws-feed.pro.coinbase.com", 60)
client.write('{"type": "subscribe","product_ids": ["BTC-USD"],"channels": ["ticker","heartbeat"]}')

2. Kết nối giao diện được mã hóa

Thông thường, websocket được sử dụng để đọc báo giá thị trường, nhưng nó cũng có thể được sử dụng để nhận lệnh và đẩy tài khoản. Việc đẩy dữ liệu được mã hóa như vậy đôi khi có sự chậm trễ lâu và nên được sử dụng cẩn thận. Vì phương pháp mã hóa phức tạp hơn, đây là một vài ví dụ được đưa ra để tham khảo. Lưu ý rằng chỉ cần AccessKey, có thể được đặt như một tham số chiến lược. Nếu SecretKey là cần thiết, nó có thể được gọi ngụ ý bởi chức năng trao đổi.HMAC() để đảm bảo an ninh.

    //Push example of Huobi Futures
    var ACCESSKEYID = 'accesskey of your Huobi account'
    var apiClient = Dial('wss://api.hbdm.com/notification|compress=gzip&mode=recv')
    var date = new Date(); 
    var now_utc =  Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(),date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
    var utc_date = new Date(now_utc)
    var Timestamp = utc_date.toISOString().substring(0,19)
    var quest = 'GET\napi.hbdm.com\n/notification\n'+'AccessKeyId='+ACCESSKEYID+'&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=' + encodeURIComponent(Timestamp)
    var signature = exchange.HMAC("sha256", "base64", quest, "{{secretkey} }") // Remove the extra blank spaces between }}
    auth = {op: "auth",type: "api",AccessKeyId: ACCESSKEYID, SignatureMethod: "HmacSHA256",SignatureVersion: "2", Timestamp: Timestamp, Signature:encodeURI(signature)}
    apiClient.write(JSON.stringify(auth))
    apiClient.write('{"op": "sub","cid": "orders","topic": "orders.btc'}')
    while (true){
        var data = datastream.read()
        if('op' in data && data.op == 'ping'){
            apiClient.write(JSON.stringify({op:'pong', ts:data.ts}))
        }
    }
    
    // Push example of Binance; pay attention that listenKey needs to be updated regularly   
    var APIKEY = 'accesskey of your Binance account'
    var req = HttpQuery('https://api.binance.com/api/v3/userDataStream',{method: 'POST',data: ''},null,'X-MBX-APIKEY:'+APIKEY);
    var listenKey = JSON.parse(req).listenKey;
    HttpQuery('https://api.binance.com/api/v3/userDataStream', {method:'DELETE',data:'listenKey='+listenKey}, null,'X-MBX-APIKEY:'+APIKEY);
    listenKey = JSON.parse(HttpQuery('https://api.binance.com/api/v3/userDataStream','',null,'X-MBX-APIKEY:'+APIKEY)).listenKey;
    var datastream = Dial("wss://stream.binance.com:9443/ws/"+listenKey+'|reconnect=true',60);
    var update_listenKey_time =  Date.now()/1000;
    while (true){
        if (Date.now()/1000 - update_listenKey_time > 1800){
            update_listenKey_time = Date.now()/1000;
            HttpQuery('https://api.binance.com/api/v3/userDataStream', {method:'PUT',data:'listenKey='+listenKey}, null,'X-MBX-APIKEY:'+APIKEY);
        }
        var data = datastream.read()
    }

    // push example of BitMEX
    var APIKEY = "your Bitmex API ID"
    var expires = parseInt(Date.now() / 1000) + 10
    var signature = exchange.HMAC("sha256", "hex", "GET/realtime" + expires, "{{secretkey} }")// secretkey is automatically replaced during execution, so no need to fill in
    var client = Dial("wss://www.bitmex.com/realtime", 60)
    var auth = JSON.stringify({args: [APIKEY, expires, signature], op: "authKeyExpires"})
    var pos = 0
    client.write(auth)
    client.write('{"op": "subscribe", "args": "position"}')
    while (true) {
        bitmexData = client.read()
        if(bitmexData.table == 'position' && pos != parseInt(bitmexData.data[0].currentQty)){
            Log('position change', pos, parseInt(bitmexData.data[0].currentQty), '@')
            pos = parseInt(bitmexData.data[0].currentQty)
        }
    }

3. Websocket đọc

Nói chung, nó có thể được đọc liên tục 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()
        var data = JSON.parse(msg) // Parse json strings into quotable objects 
// Process data 
    }
}

Tốc độ đẩy dữ liệu wss rất nhanh. Lớp dưới của Golang sẽ lưu trữ tất cả dữ liệu trong hàng đợi, và khi các cuộc gọi của chương trình được đọc, dữ liệu sẽ được trả về. Tuy nhiên, các hoạt động như đặt lệnh trên bot sẽ gây chậm trễ, có thể dẫn đến sự tích lũy dữ liệu. Đối với thông tin như đẩy thực thi giao dịch, đẩy tài khoản và đẩy can thiệp chiều sâu, chúng tôi cần dữ liệu lịch sử. Đối với dữ liệu thị trường báo giá, trong hầu hết các trường hợp, chúng tôi chỉ quan tâm đến dữ liệu mới nhất, không phải dữ liệu lịch sử.

Nếuread()thêm không tham số, nó sẽ trả về dữ liệu cũ nhất, và chặn cho đến khi trả về khi không có dữ liệu.client.read(-2)để trả về dữ liệu mới nhất ngay lập tức, nhưng khi không có dữ liệu, nó sẽ trả về null, cần phải được đánh giá trước khi tham khảo.

Tùy thuộc vào cách xử lý dữ liệu lưu trữ tạm thời cũ và liệu nó có bị chặn khi không có dữ liệu, read có các tham số khác nhau, như được hiển thị trong bảng bên dưới, trông phức tạp, nhưng làm cho chương trình linh hoạt hơn.img

4. Kết nối với nhiều nền tảng bằng Websocket

Trong trường hợp này, rõ ràng rằng chỉ cần sử dụng read() không hoạt động trong chương trình, bởi vì một nền tảng sẽ chặn các tin nhắn đang chờ, và nền tảng khác sẽ không nhận ngay cả khi có tin nhắn mới.

    function main() {
        var binance = Dial("wss://stream.binance.com:9443/ws/!ticker@arr");
        var coinbase = Dial("wss://ws-feed.pro.coinbase.com", 60)
        coinbase.write('{"type": "subscribe","product_ids": ["BTC-USD"],"channels": ["ticker","heartbeat"]}')
        while (true) {
            var msgBinance = binance.read(-1) // Parameter -1 represents no data and return null immediately; it will not occur that being blocked before there is data to be returned 
            var msgCoinbase = coinbase.read(-1)
            if(msgBinance){
                // at this time, Binance has data to return 
            }
            if(msgCoinbase){
                // at this time, coinbase has data to return 
            }
            Sleep(1) // Sleep for 1 millisecond
        }
    }

5.Vấn đề ngắt kết nối và kết nối lại

Phần này của quá trình xử lý khó khăn hơn, bởi vì dữ liệu đẩy có thể bị gián đoạn, hoặc thời gian trì hoãn đẩy cực kỳ dài. Ngay cả khi nhịp tim có thể được nhận, điều đó không có nghĩa là dữ liệu vẫn đang được đẩy. Bạn có thể đặt khoảng thời gian sự kiện; nếu không nhận được cập nhật sau khoảng thời gian, kết nối lại; tốt nhất là so sánh kết quả được trả về bởi rest sau một khoảng thời gian, để xem liệu dữ liệu có chính xác hay không. Đối với các trường hợp đặc biệt của Binance, bạn có thể trực tiếp thiết lập kết nối lại tự động.

6.Sử dụng khung chương trình chung của Websocket

Đối với dữ liệu đẩy đã được sử dụng, chương trình sẽ tự nhiên được viết như sự kiện kích hoạt; chú ý đến tần suất đẩy dữ liệu, bởi vì các yêu cầu tần số cao sẽ dẫn đến việc bị chặn; nói chung bạn có thể viết:

    var tradeTime = Date.now()
    var accountTime = Date.now()
    function trade(data){
        if(Date.now() - tradeTime > 2000){//Here it limits only one trade in 2 seconds 
            tradeTime = Date.now()
            // Trading logic
        }
    }
    function GetAccount(){
        if(Date.now() - accountTime > 5000){//Here it limits GetAccount only once in 5 seconds 
            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)
        }
    }

7.Conclusion

Phương pháp kết nối, phương pháp truyền dữ liệu, nội dung đăng ký và định dạng dữ liệu của websocket trên mỗi nền tảng thường khác nhau, vì vậy nền tảng không đóng gói nó và cần sử dụng chức năng Dial để kết nối một mình.

PS: Mặc dù một số nền tảng không cung cấp trích dẫn websocket, trên thực tế, khi bạn đăng nhập vào trang web để sử dụng chức năng gỡ lỗi, bạn sẽ thấy rằng tất cả chúng đều sử dụng websocket push. Sau khi nghiên cứu, bạn sẽ thấy rằng một số định dạng đăng ký và định dạng trả về dường như được mã hóa, có thể được nhìn thấy bằng cách giải mã và giải nén với base64.

Tương đương nhiều chủ đề

JavaScript có thể nhận ra sự đồng bộ bởi hàm Go, và Python có thể sử dụng thư viện đa luồng tương ứng.

Trong quá trình thực hiện các chiến lược định lượng, việc thực thi đồng thời có thể làm giảm thời gian trì hoãn và cải thiện hiệu quả. Hãy lấy bot chiến lược phòng ngừa rủi ro làm ví dụ. Nó cần có được độ sâu của hai đồng xu, và mã được thực thi theo thứ tự được hiển thị như sau:

var depthA = exchanges[0].GetDepth()
var depthB = exchanges[1].GetDepth()

Khi một yêu cầu về API nghỉ chậm trễ, ví dụ thời gian chậm trễ là 100 mili giây, Sau đó thời gian để có được độ sâu hai lần thực sự khác nhau; nếu cần nhiều truy cập hơn, các vấn đề chậm trễ sẽ rõ ràng hơn, điều này sẽ ảnh hưởng đến việc thực hiện chiến lược.

Vì JavaScript không có đa luồng, lớp dưới đóng gói hàm Go để giải quyết vấn đề này. hàm Go có thể được sử dụng cho các API đòi hỏi truy cập mạng, chẳng hạn nhưGetDepth, GetAccountvà như vậy.IOcũng được hỗ trợ như:exchange.Go("IO", "api", "POST", "/api/v1/contract_batchorder", "orders_data=" + JSON.stringify(orders)), nhưng do cơ chế thiết kế, nó khó thực hiện hơn.

var a = exchanges[0].Go("GetDepth")
var b = exchanges[1].Go("GetDepth")
var depthA = a.wait() // Call "wait" method to wait for the return of the asynchronous GetDepth result 
var depthB = b.wait()

Trong hầu hết các trường hợp đơn giản, viết các chiến lược theo cách này là tốt. Nhưng lưu ý rằng quá trình này được lặp lại mỗi khi các vòng lặp chiến lược, và các biến trung gian a và b thực sự chỉ tạm thời trợ giúp. Nếu chúng ta có nhiều nhiệm vụ đồng thời, chúng ta cần thêm ghi lại sự tương ứng giữa a và depthA, b và depthB. Khi các nhiệm vụ đồng thời của chúng ta không chắc chắn, tình hình phức tạp hơn. Do đó, chúng ta hy vọng sẽ nhận ra một hàm: khi viết hàm Go đồng thời, ràng buộc một biến cùng một lúc; khi kết quả chạy đồng thời trở lại, giá trị kết quả sẽ tự động được gán cho biến, do đó loại bỏ sự cần thiết của các biến trung gian và làm cho chương trình cụ thể ngắn gọn hơn. Việc thực hiện là như sau:

function G(t, ctx, f) {
    return {run:function(){
        f(t.wait(1000), ctx)
    }}
}

Chúng tôi đã xác định một hàm G, trong đó tham số t là hàm Go được thực thi, ctx là hàm ghi ngữ cảnh chương trình, và f là hàm gán một giá trị cụ thể.

Tại thời điểm này, khuôn khổ chương trình tổng thể có thể được viết dưới dạng mô hình, tương tự như mô hình sản xuất-người tiêu dùng (với một số khác biệt), nhà sản xuất liên tục gửi các nhiệm vụ và người tiêu dùng thực hiện chúng đồng thời.

var Info = [{depth:null, account:null}, {depth:null, account:null}] // If we need to obtain the depth and account of the two platforms, more information can also be put in, such as order ID and status, etc.
var tasks = [ ] // Global task list 

function produce(){ // Issue all kinds of concurrent tasks
  // Here the task producing logic has been omitted, only for demo
  tasks.push({exchange:0, ret:'depth', param:['GetDepth']})
  tasks.push({exchange:1, ret:'depth', param:['GetDepth']})
  tasks.push({exchange:0, ret:'sellID', param:['Buy', Info[0].depth.Asks[0].Price, 10]})
  tasks.push({exchange:1, ret:'buyID', param:['Sell', Info[1].depth.Bids[0].Price, 10]})
}
function worker(){
    var jobs = []
    for(var i=0;i<tasks.length;i++){
        var task = tasks[i]
        jobs.push(G(exchanges[task.exchange].Go.apply(this, task.param), task, function(v, task) {
                    Info[task.exchange][task.ret] = v // Here "v" is the return value of the concurrent Go function "wait()", and you can think about it 
                }))
    }
    _.each(jobs, function(t){
            t.run() // Here all tasks are executed concurrently 
        })
    tasks = []
}
function main() {
    while(true){
        produce()         // Give trading command
        worker()        // Concurrently execute
        Sleep(1000)
    }
}

Có vẻ như chỉ có một chức năng đơn giản đã được thực hiện trong các hoạt động trên. Trên thực tế, điều đó đã đơn giản hóa rất nhiều sự phức tạp của mã. Chúng ta chỉ cần quan tâm đến những nhiệm vụ mà chương trình cần tạo ra, và chương trình worker))) sẽ tự động thực hiện chúng đồng thời và trả về kết quả tương ứng. Tính linh hoạt đã được cải thiện rất nhiều.

Khai họa theo chức năng biểu đồ

Trong hướng dẫn cơ bản, thư viện lớp vẽ được khuyến cáo trong việc giới thiệu vẽ, có thể đáp ứng nhu cầu trong hầu hết các trường hợp. Nếu bạn cần tùy chỉnh thêm, bạn có thể trực tiếp vận hành đối tượng Chart.

Các thông số nội bộ củaChart({…})là các đối tượng của HighStock và HighCharts, nhưng một tham số bổ sung__isStockFMZ hỗ trợ các mô-đun cơ bản của HighCharts và HighStock, nhưng không hỗ trợ các mô-đun bổ sung.

Ví dụ cụ thể của HighCharts:https://www.highcharts.com/demo; HighStock ví dụ:https://www.highcharts.com/stock/demoBạn có thể tham khảo các mã trong những ví dụ, và cấy ghép chúng vào FMZ thuận tiện.

Bạn có thể gọi add ([series index ((như 0), data]) để thêm dữ liệu vào chuỗi với chỉ số được chỉ định. Gọi reset() để xóa dữ liệu biểu đồ; reset có thể lấy tham số số và chỉ định số lượng được lưu. Hiển thị biểu đồ nhiều được hỗ trợ, chỉ cần truyền vào các tham số mảng trong quá trình cấu hình, chẳng hạn như: var chart = Chart([{...}, {...}, {...}]). Ví dụ: nếu Chart1 có hai chuỗi, Chart2 có một chuỗi, và Chart3 có một chuỗi, khi gọi add, ID chuỗi 0 và 1 được chỉ định để đại diện riêng cho dữ liệu của hai chuỗi trong Chart1 được cập nhật; ID chuỗi 2 được chỉ định để đại diện cho dữ liệu của chuỗi đầu tiên trong Chart2; ID chuỗi 3 được chỉ định để đại diện cho chuỗi dữ liệu đầu tiên trong Chart3.

Một ví dụ cụ thể:

var chart = { // This "chart" in JS is an object; before using the Chart function, we need to declare the object variable of a configured chart "chart" 
    __isStock: true,                                    // Mark whether it is a general chart; you can change it to false and try to operate it, if you are interested 
    tooltip: {xDateFormat: '%Y-%m-%d %H:%M:%S, %A'},    // Zoom tool
    title : { text : 'spread chart'},                       // Theme
    rangeSelector: {                                    // Choose the 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'},                         // Horizontal axis, namely X axis; currently set type: time
    yAxis : {                                           // Vertical axis, namely Y axis; the default changes according to the data 
        title: {text: 'spread'},                           // Theme
        opposite: false,                                // whether to enable the vertical axis on the right 
    },
    series : [                                          // Data series; the attribute saves all kinds of data series (lines, K-lines, labels, etc.)
        {name : "line1", id : "line1,buy1Price", data : []},  // The index is 0; the data stroed in the data array is the data of the index series 
        {name : "line2", id : "line2,lastPrice", dashStyle : 'shortdash', data : []}, // The index is 1; set  dashStyle: 'shortdash', namely: set  dashed line
    ]
};
function main(){
    var ObjChart = Chart(chart);  // Call the Chart function, and initialize the chart 
    ObjChart.reset();             // Empty 
    while(true){
        var nowTime = new Date().getTime();   // Obtain the timestamp of this polling, namely a millisecond tiemstamp, to ensure the location of writing to the X axis in the chart 
        var ticker = _C(exchange.GetTicker);  // Obtain the market quotes data
        var buy1Price = ticker.Buy;           // Get buy one price from the return value of the market quotes 
        var lastPrice = ticker.Last + 1;      // Get the final executed price, and we add 1 to split the 2 lines 
        ObjChart.add([0, [nowTime, buy1Price]]); // Use the timestamp as the value of X, and buy one price as the value of Y; pass in the data series of index 0  
        ObjChart.add([1, [nowTime, lastPrice]]); // Same as above. 
        Sleep(2000);
    }
}

Ví dụ sử dụng bố cục biểu đồ:https://www.fmz.com/strategy/136056

Kiểm tra phía sau nâng cao

Python Local Backtest

Địa chỉ nguồn mở cụ thể:https://github.com/fmzquant/backtest_python

Cài đặt

Nhập lệnh sau trong dòng lệnh:

pip install https://github.com/fmzquant/backtest_python/archive/master.zip

Một ví dụ đơn giản

Đặt các tham số backtest ở đầu mã chiến lược dưới dạng nhận xét, và các chi tiết sẽ được hiển thị ở nút Save Settings trên trang Edit Strategy của trang web FMZ.

'''backtest
start: 2018-02-19 00:00:00
end: 2018-03-22 12:00:00
period: 15m
exchanges: [{"eid":"OKEX","currency":"LTC_BTC","balance":3,"stocks":0}]
'''
from fmz import *
task = VCtx(__doc__) # initialize backtest engine from __doc__
print exchange.GetAccount()
print exchange.GetTicker()
print task.Join() # print backtest result

Kiểm tra hậu quả

Đối với các chiến lược hoàn chỉnh cần vòng lặp vô hạn, lỗi EOF sẽ được nâng lên sau khi kiểm tra lại kết thúc; do đó, chúng ta nên làm cho dung nạp lỗi tốt.

# !/usr/local/bin/python
# -*- coding: UTF-8 -*-

'''backtest
start: 2018-02-19 00:00:00
end: 2018-03-22 12:00:00
period: 15m
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD","balance":10000,"stocks":3}]
'''

from fmz import *
import math
import talib

task = VCtx(__doc__) # initialize backtest engine from __doc__

# ------------------------------ Start of the Strategy  --------------------------

print exchange.GetAccount()     # Call some interfaces, and print their return values 
print exchange.GetTicker()

def adjustFloat(v):             # the custom functions in the strategy 
    v = math.floor(v * 1000)
    return v / 1000

def onTick():
    Log("onTick")
    # Specific strategy code 


def main():
    InitAccount = GetAccount()
    while True:
        onTick()
        Sleep(1000)

# ------------------------------ End of the Strategy --------------------------

try:
    main()                     # The end of the backtest will raise EOFError() to stop stop the backtest loop. Therefore, we should handle with the error, and call task.Join() to print the backtest result, after the error is detected  
except:
    print task.Join()         

Dữ liệu kiểm tra ngược tùy chỉnh

exchange.SetData(arr) chuyển đổi nguồn dữ liệu backtest và sử dụng dữ liệu K-line tùy chỉnh. Parameter arr là một mảng, mà các phần tử là dữ liệu thanh K-line (tức là: mảng dữ liệu K-line, tạm thời chỉ hỗ trợ backtest JavaScript).

trong mảng arr, định dạng dữ liệu của một phần tử duy nhất:

[
    1530460800,    // time     Timestamp 
    2841.5795,     // open     Open Price 
    2845.6801,     // high     Highest Price
    2756.815,      // low      Lowest Price
    2775.557,      // close    Close Price
    137035034      // volume   Executed Volume 
]

Nguồn dữ liệu có thể được nhập vào Mẫu.

function init() {                                                          // The init function in the template will be executed first when the template is loaded; ensure the exchange.SetData(arr) function is executed first, initialized, and set the data to the backtest system
    var arr = [                                                            // The K-line data to be used during backtest
        [1530460800,2841.5795,2845.6801,2756.815,2775.557,137035034],      // The data of the earliest K-line bar
        ... ,                                                              // If the K-line data is too long, use "..." to represent the omitted data here
        [1542556800,2681.8988,2703.5116,2674.1781,2703.5116,231662827]     // The data of the latest K-line bar 
    ]
    exchange.SetData(arr)                                                  // Import the custom data mentioned above 
    Log("Import data successfully")
}

Lưu ý: hãy đảm bảo nhập dữ liệu tùy chỉnh trước (tức là gọi hàm exchange.SetData để đặt dữ liệu) trong quá trình khởi tạo. Thời gian dữ liệu đường K tùy chỉnh phải phù hợp với thời gian đường K dưới lớp được đặt trên trang backtest, tức là: dữ liệu đường K tùy chỉnh; thời gian của đường K là 1 phút, vì vậy thời gian đường K dưới lớp được đặt trong backtest cũng nên được đặt là 1 phút.

Sử dụng các nền tảng không được hỗ trợ bởi FMZ

Nếu API của một nền tảng không được hỗ trợ chính xác giống với nền tảng được hỗ trợ, ngoại trừ địa chỉ cơ sở, nền tảng không được hỗ trợ có thể được hỗ trợ bằng cách chuyển địa chỉ cơ sở. Để cụ thể hơn, hãy chọn một nền tảng được hỗ trợ khi thêm nền tảng, nhưng điền vào API-KEY của nền tảng không được hỗ trợ, và sử dụng IO để chuyển địa chỉ cơ sở trong chiến lược, chẳng hạn như:

exchange.IO("base", "http://api.huobi.pro") 
//http://api.huobi.pro is the base address of the unsupported platform API, and notice not to add api/v3 and so on, for the address will be automatically completed

Không phải tất cả các nền tảng đều được hỗ trợ bởi FMZ, nhưng nền tảng của chúng tôi đã cung cấp phương pháp truy cập của giao thức chung.

  • Khi bạn viết mã để truy cập một nền tảng, chương trình sẽ tạo ra một dịch vụ web.
  • Khi bạn thêm một nền tảng vào FMZ, hãy chỉ định địa chỉ và cổng của dịch vụ web.
  • Khi docker đang chạy bot nền tảng của giao thức chung, yêu cầu truy cập API trong chiến lược sẽ được gửi đến giao thức chung.
  • Giao thức chung sẽ truy cập nền tảng bằng yêu cầu, và trả lại kết quả cho docker.

Nói một cách đơn giản, giao thức chung giống như một trung gian, proxying yêu cầu của docker và trả lại dữ liệu, theo tiêu chuẩn tương ứng. Mã của giao thức chung cần phải được hoàn thành bởi chính bạn. Viết giao thức chung thực sự có nghĩa là bạn có thể truy cập nền tảng duy nhất và hoàn thành chiến lược. FMZ chính thức đôi khi phát hành phiên bản exe của giao thức chung của nền tảng.

Việc giới thiệu cụ thể của giao thức chung:https://www.fmz.com/bbs-topic/9120Ví dụ về viết giao thức chung trong Python:https://www.fmz.com/strategy/101399

Tạo nền tảng định lượng của riêng bạn

Cũng giống như các hoạt động khác nhau của một nền tảng có thể được thực hiện thông qua API, trang web FMZ cũng dựa trên API. Bạn có thể áp dụng API-KEY của trang web FMZ để thực hiện các chức năng, chẳng hạn như create, restart, DeleteRobot, GetRobotList GetRobotLogs, v.v. Vui lòng tham khảo phần API Extension of FMZ Platform trong tài liệu API để biết chi tiết.

Do khả năng mở rộng mạnh mẽ của nền tảng FMZ Quant, bạn có thể tạo nền tảng định lượng của riêng bạn dựa trên phần mở rộng API, cho phép người dùng của bạn chạy bot trên nền tảng của bạn, v.v.https://www.fmz.com/bbs-topic/1697 .

Trở thành đối tác của FMZ

Thúc đẩy lớp học NetEase

Thị trường giao dịch tiền điện tử đã thu hút ngày càng nhiều sự chú ý từ các nhà giao dịch định lượng do tính đặc biệt của nó. Trên thực tế, giao dịch chương trình đã trở thành dòng chính của tiền điện tử, và các chiến lược như phòng ngừa rủi ro và tạo thị trường luôn hoạt động trên thị trường. Những người mới bắt đầu với nền tảng lập trình yếu muốn bước vào lĩnh vực mới này, đối mặt với nhiều nền tảng và API thay đổi, đầy khó khăn.www.fmz.com) hiện là cộng đồng và nền tảng định lượng tiền điện tử lớn nhất, đã giúp hàng ngàn người mới bắt đầu trên con đường giao dịch định lượng trong hơn 4 năm. Để tham gia khóa học trên NetEase, bạn chỉ cần 20 nhân dân tệ và khóa học hoàn toàn dành cho người mới bắt đầu.

Thúc đẩyKhóa học giao dịch định lượng tiền điện tử trên NetEase Cloud Classroom. Đăng nhập vào NetEase Cloud Classroom và chia sẻ liên kết khóa học của bạn (liên kết có mã khóa học duy nhất). Những người khác, đăng ký và mua khóa học thông qua liên kết này, sẽ mang lại cho bạn 50% tổng số tiền như một khoản hoa hồng, cụ thể là 10 nhân dân tệ. Hãy theo dõi tài khoản công cộng WeChat của NetEase Cloud Classroom Premium Course Promotion để rút tiền mặt. Bạn cũng được chào đón để mời những người khác quảng bá khóa học trên Weibo hoặc nhóm QQ.

Liên kết

Người tiêu dùng nhấp vào liên kết khuyến mãi, đăng ký và sạc trong vòng nửa năm sẽ được hưởng chính sách mà công ty chúng tôi sẽ giảm giá theo số tiền có hiệu lực trong thứ tự hợp lệ. Phụ kiện sẽ được trả lại vào tài khoản của người quảng bá dưới dạng điểm. Người dùng có thể đổi điểm vào số dư tài khoản của nền tảng FMZ ở tỷ lệ 10: 1, và người dùng cũng có thể sử dụng điểm để đổi các sản phẩm liên quan của FMZ Quant trong tương lai. Liên kết cụ thể cho hoạt động:https://www.fmz.com/bbs-topic/3828

Nền tảng lượng tử FMZ cho doanh nghiệp

Trang web FMZ hoàn chỉnh có thể được triển khai vào máy chủ độc quyền của một doanh nghiệp hoặc một nhóm để kiểm soát hoàn chỉnh và tùy chỉnh chức năng. Trang web FMZ đã được sử dụng và thử nghiệm bởi khoảng 100.000 người dùng, và đạt được tính khả dụng và bảo mật cao, có thể tiết kiệm thời gian cho các nhóm và doanh nghiệp định lượng. Phiên bản doanh nghiệp dành cho các nhóm giao dịch định lượng vừa, các nhà cung cấp dịch vụ tương lai hàng hóa, v.v. Xin vui lòng liên hệ với người quản trị để có báo giá cụ thể.

Hệ thống tạo thị trường

Hệ thống chuyên nghiệp, cung cấp thanh khoản thị trường và quản lý quỹ cho các nền tảng, có thể là hệ thống tạo thị trường được cải tiến nhất trên thị trường. Nó được nhiều nền tảng và nhóm sử dụng rộng rãi.

Kế hoạch nền tảng

Hệ thống giao dịch công nghệ FMZ áp dụng công nghệ khớp bộ nhớ, và tốc độ xử lý đơn đặt hàng cao tới 2 triệu giao dịch mỗi giây, có thể đảm bảo rằng sẽ không có sự chậm trễ hoặc chậm trễ trong xử lý đơn đặt hàng. Nó có thể duy trì hoạt động trơn tru và ổn định của các nền tảng với hơn 20 triệu người dùng trực tuyến đồng thời. Khung hệ thống đa lớp và đa cụm đảm bảo an ninh, ổn định và khả năng mở rộng của hệ thống. Việc triển khai chức năng và cập nhật phiên bản có thể được thực hiện mà không cần thời gian ngừng hoạt động, đảm bảo tối đa trải nghiệm hoạt động của người dùng thiết bị đầu cuối. Hiện tại, hệ thống có thể được trải nghiệm trong nền tảng mô phỏng wex.app.


Thêm nữa