Sumber daya yang dimuat... Pemuatan...

Tutorial lanjutan untuk FMZ Quant platform Strategy Writing

Penulis:Ninabadass, Dibuat: 2022-03-22 09:00:57, Diperbarui: 2022-03-29 10:02:52

[TOC] Sebelum belajar tutorial ini, Anda perlu belajarMulailah dengan FMZ Quant PlatformdanTutorial dasar untuk FMZ Quant platform Strategy Writing, dan menjadi mahir dalam bahasa pemrograman.Tutorial dasar mencakup fungsi yang paling umum digunakan, tetapi ada banyak fungsi dan fitur yang belum diperkenalkan, dan mereka tidak akan dibahas dalam tutorial ini.Setelah mempelajari tutorial ini, Anda akan dapat menulis lebih banyak strategi gratis dan disesuaikan, dan platform FMZ Quant hanyalah alat.

Akses ke Data mentah Platform

Platform FMZ Quant merangkum semua platform yang didukung. Untuk menjaga keseragaman, dukungan kami untuk satu platform API masih belum lengkap. Misalnya, GetRecords dapat melewati jumlah K-line atau waktu awal, sementara itu tetap pada platform FMZ; beberapa platform mendukung batch ordering, sementara FMZ tidak mendukung itu, dan sebagainya. Jadi ada kebutuhan untuk cara untuk mengakses data platform secara langsung.Untuk antarmuka publik (seperti penawaran pasar), Anda dapat menggunakanHttpQuery, dan untuk antarmuka terenkripsi (yang melibatkan informasi akun), Anda perlu menggunakanIO.Untuk parameter masuk tertentu, silakan lihat dokumen API platform yang sesuai.Infolapangan mengembalikan informasi mentah, tapi masih tidak membuat perbedaan pada masalah tidak mendukung antarmuka.

GetRawJSON ((()

Ini mengembalikan konten mentah (string) yang diminta oleh API REST terakhir, yang dapat digunakan untuk menganalisis informasi yang diperluas 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() Mengakses Antarmuka Publik

Untuk mengakses antarmuka publik, Js dapat menggunakanHttpQuery, dan Python dapat menggunakan paket terkait, sepertiurllibataurequests.

HttpQuery default untuk metode GET, dan mendukung lebih banyak fungsi; periksa dokumen API untuk lebih detail.

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

Contoh Python menggunakan permintaan:

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 mengakses antarmuka terenkripsi

Untuk antarmuka yang membutuhkan tanda tangan API-KEY, fungsi IO dapat digunakan, dan pengguna hanya perlu peduli tentang parameter masuk, dan proses tanda tangan tertentu akan diselesaikan oleh lapisan bawah.

Platform FMZ saat ini tidak mendukung perintah stop loss BitMEX, yang dapat diimplementasikan melalui IO, sesuai dengan langkah-langkah berikut:

  • Pertama, cari halaman instruksi BitMEX API:https://www.bitmex.com/api/explorer/;
  • maka, temukan alamat pesanan BitMEX di:https://www.bitmex.com/api/v1/order, dengan metodePOST; untuk FMZ telah secara internal menentukan alamat dasar, Anda hanya perlu memberikan di /api/v1/order.
  • parameter yang sesuai:symbol=XBTUSD&side=Buy&orderQty=1&stopPx=4000&ordType=Stop.

Kode khusus:

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

Lebih banyak contoh IO:https://www.fmz.com/bbs-topic/3683

Menggunakan websocket

Pada dasarnya, semua platform cryptocurrency mendukung websocket untuk mengirim penawaran pasar, dan beberapa platform mendukung websocket untuk memperbarui informasi akun. Dibandingkan dengan API istirahat, websocket umumnya memiliki keuntungan, seperti latensi rendah, frekuensi tinggi dan tidak dibatasi oleh frekuensi API istirahat platform, dll. Kelemahannya adalah bahwa ada masalah gangguan, yang pengolahannya tidak intuitif.

Artikel ini terutama akan memperkenalkan cara menggunakan bahasa JavaScript dan cara menggunakan fungsi Dial yang dikemas oleh platform untuk terhubung, pada platform FMZ Quant; untuk instruksi dan parameter tertentu ada dalam dokumen, Anda dapat mencari Dial; untuk mewujudkan berbagai fungsi, fungsi Dial telah diperbarui beberapa kali. Artikel ini akan membahas dan memperkenalkan strategi berbasis acara berdasarkan wss, serta masalah menghubungkan beberapa platform. Python juga dapat menggunakan fungsi Dial, atau perpustakaan yang sesuai.

1. Koneksi Websocket

Secara umum, langsung terhubung melalui Websocket; misalnya untuk mendapatkan Binance tricker push:

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

Jika data yang dikembalikan dalam format yang dikompresi, spesifikasi harus dibuat saat menghubungkan; compress mengacu pada format yang dikompresi, dan mode mewakili data yang dikembalikan yang perlu dikompresi; misalnya ketika menghubungkan dengan OKEX:

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

Fungsi Dial mendukung koneksi ulang, yang dilakukan oleh Golang yang mendasari. Jika koneksi yang terdeteksi rusak, itu akan dihubungkan kembali. Untuk data permintaan yang sudah ada di url, seperti contoh dari Binance sekarang, ini sangat nyaman dan disarankan. Bagi mereka yang perlu mengirim pesan langganan, mereka dapat mempertahankan mekanisme koneksi ulang sendiri.

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

Untuk berlangganan pesan wss, beberapa permintaan platform ada di url, dan beberapa perlu mengirim saluran yang berlangganan sendiri, seperti coinbase:

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

2. Koneksi antarmuka terenkripsi

Umumnya, websocket digunakan untuk membaca kutipan pasar, tetapi juga dapat digunakan untuk mendapatkan pesanan dan push akun. Push data terenkripsi semacam itu kadang-kadang memiliki keterlambatan yang panjang dan harus digunakan dengan hati-hati. Karena metode enkripsi lebih rumit, berikut adalah beberapa contoh yang diberikan untuk referensi. Perhatikan bahwa hanya AccessKey yang diperlukan, yang dapat ditetapkan sebagai parameter strategi. Jika SecretKey diperlukan, dapat dipanggil secara implisit oleh fungsi exchange.HMAC(() untuk memastikan keamanan.

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

Secara umum, dapat dibaca terus menerus dalam loop tak terbatas.

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

Kecepatan push data wss sangat cepat. Lapisan bawah Golang akan cache semua data dalam antrian, dan ketika panggilan program dibaca, data akan dikembalikan secara bergantian. Namun, operasi seperti menempatkan pesanan pada bot akan menyebabkan keterlambatan, yang dapat mengakibatkan akumulasi data. Untuk informasi seperti push eksekusi perdagangan, push akun, dan push interpolasi kedalaman, kita membutuhkan data riwayat. Untuk data pasar kutipan, dalam kebanyakan kasus, kita hanya peduli dengan data terbaru, bukan data riwayat.

Jikaread()menambahkan tidak ada parameter, itu akan mengembalikan data tertua, dan blok sampai kembali ketika tidak ada data.client.read(-2)untuk mengembalikan data terbaru segera, tetapi ketika tidak ada data, itu akan mengembalikan nol, yang perlu dinilai sebelum referensi.

Tergantung pada cara menangani data cache lama dan apakah itu diblokir ketika tidak ada data, read memiliki parameter yang berbeda, seperti yang ditunjukkan dalam tabel di bawah ini, yang terlihat rumit, tetapi membuat program lebih fleksibel.img

4.Menghubungkan dengan beberapa platform dengan Websocket

Dalam hal ini jelas bahwa hanya menggunakan read() tidak bekerja dalam program, karena satu platform akan memblokir pesan yang menunggu, dan platform lain tidak akan menerima bahkan jika ada pesan baru.

    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.Problem Putus & Rekoneksi

Bagian pemrosesan ini lebih merepotkan, karena data push dapat terganggu, atau penundaan push sangat lama. Bahkan jika detak jantung dapat diterima, itu tidak berarti data masih didorong. Anda dapat mengatur interval acara; jika tidak ada pembaruan yang diterima setelah interval, sambung kembali; yang terbaik adalah membandingkan hasil yang dikembalikan oleh rest setelah periode waktu, untuk melihat apakah data akurat. Untuk kasus khusus Binance, Anda dapat langsung mengatur koneksi ulang otomatis.

6.Menggunakan Framework Program Umum Websocket

Untuk data push telah digunakan, program secara alami akan ditulis sebagai event-triggered; perhatikan frekuensi data push, karena permintaan frekuensi tinggi akan menyebabkan diblokir; umumnya Anda dapat menulis:

    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

Metode koneksi, metode transmisi data, konten langganan dan format data websocket pada setiap platform sering berbeda, sehingga platform tidak mengkapsulkannya dan perlu menggunakan fungsi Dial untuk terhubung sendiri.

PS: Meskipun beberapa platform tidak menyediakan kutipan websocket, pada kenyataannya, ketika Anda masuk ke situs web untuk menggunakan fungsi debugging, Anda akan menemukan bahwa mereka semua menggunakan websocket push.

Konkurensi Multithread

JavaScript dapat mewujudkan konvergensi oleh fungsi Go, dan Python dapat menggunakan perpustakaan multithread yang sesuai.

Saat realisasi strategi kuantitatif, eksekusi bersamaan dapat mengurangi keterlambatan waktu dan meningkatkan efisiensi.

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

Ketika permintaan API istirahat tertunda, misalnya waktu penundaan adalah 100 milidetik, maka waktu untuk mendapatkan kedalaman dua kali sebenarnya berbeda; jika lebih banyak akses diperlukan, masalah penundaan akan lebih jelas, yang akan mempengaruhi pelaksanaan strategi.

Karena JavaScript tidak memiliki multithread, lapisan bawah mengkapsulkan fungsi Go untuk memecahkan masalah ini. fungsi Go dapat digunakan untuk API yang membutuhkan akses jaringan, sepertiGetDepth, GetAccountdan sebagainya.IOjuga didukung, seperti:exchange.Go("IO", "api", "POST", "/api/v1/contract_batchorder", "orders_data=" + JSON.stringify(orders)), tapi karena mekanisme desain, itu lebih membosankan untuk menerapkan.

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

Dalam kasus yang paling sederhana, menulis strategi dengan cara ini baik-baik saja. Tetapi perhatikan bahwa prosesnya diulang setiap kali strategi loop, dan variabel perantara a dan b sebenarnya hanya sementara bantu. Jika kita memiliki banyak tugas serentak, kita perlu tambahan mencatat korespondensi antara a dan depthA, b dan depthB. Ketika tugas serentak kita tidak pasti, situasinya lebih rumit. Oleh karena itu, kita berharap untuk mewujudkan fungsi: ketika menulis Go fungsi serentak, mengikat variabel pada saat yang sama; ketika hasil berjalan serentak kembali, nilai hasil secara otomatis diberikan kepada variabel, sehingga menghilangkan kebutuhan untuk membuat variabel perantara dan program lebih ringkas. Implementasi spesifik adalah sebagai berikut:

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

Kami mendefinisikan fungsi G, di mana parameter t adalah fungsi Go yang akan dijalankan, ctx adalah fungsi rekaman konteks program, dan f adalah fungsi yang menetapkan nilai tertentu.

Pada saat ini, kerangka kerja program secara keseluruhan dapat ditulis sebagai model, mirip dengan model produsen-konsumen (dengan beberapa perbedaan), produser terus-menerus mengirim tugas, dan konsumen mengeksekusi mereka secara bersamaan.

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

Tampaknya hanya fungsi sederhana yang telah diimplementasikan dalam operasi di atas. Sebenarnya, itu telah sangat menyederhanakan kompleksitas kode. Kita hanya perlu peduli tentang tugas apa yang perlu dihasilkan program, dan program worker() akan secara otomatis mengeksekusi mereka secara bersamaan dan mengembalikan hasil yang sesuai. Fleksibilitas telah meningkat banyak.

Menggambar dengan fungsi grafik

Dalam tutorial dasar, perpustakaan kelas gambar direkomendasikan dalam pengenalan gambar, yang dapat memenuhi kebutuhan dalam kebanyakan kasus.

Parameter internal dariChart({…})adalah objek dari HighStock dan HighCharts, tetapi parameter tambahan__isStockFMZ pada dasarnya mendukung modul dasar dari HighCharts dan HighStock, tetapi tidak mendukung modul tambahan.

Contoh khusus HighCharts:https://www.highcharts.com/demo; Contoh HighStock:https://www.highcharts.com/stock/demo. Anda dapat merujuk pada kode dalam contoh-contoh itu, dan mentransplantasinya ke FMZ nyaman.

Anda dapat memanggil add ([series index ((seperti 0), data]) untuk menambahkan data ke dalam seri dengan indeks yang ditentukan. Panggilan reset (() untuk membersihkan data grafik; reset dapat mengambil parameter angka dan menentukan jumlah yang akan disimpan. Tampilan grafik ganda didukung, yang hanya perlu dilewati dalam parameter array selama konfigurasi, seperti: var chart = Chart (([{...}, {...}, {...}]). Misalnya, jika Chart1 memiliki dua seri, Chart2 memiliki satu seri, dan Chart3 memiliki satu seri, ketika memanggil add, ID seri 0 dan 1 ditentukan untuk mewakili data dari dua seri secara terpisah dalam Chart1 yang diperbarui; ID seri 2 ditentukan untuk mewakili data dari seri pertama dalam Chart2; ID seri 3 ditentukan untuk mewakili data pertama dari seri dalam Chart3.

Contoh spesifik:

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

Contoh penggunaan tata letak grafik:https://www.fmz.com/strategy/136056

Tes Belakang Lanjutan

Python Local Backtest

Alamat sumber terbuka khusus:https://github.com/fmzquant/backtest_python

Pemasangan

Masukkan perintah berikut di baris perintah:

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

Contoh Sederhana

Tetapkan parameter backtest di awal kode strategi dalam bentuk komentar, dan rincian akan ditampilkan di tombol Save Settings di halaman Edit Strategy dari situs 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

Backtest

Untuk strategi lengkap membutuhkan loop tak terbatas, kesalahan EOF akan meningkat setelah backtest selesai; oleh karena itu, kita harus melakukan toleransi kesalahan dengan baik.

# !/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()         

Data Backtest Khusus

exchange.SetData(arr) beralih sumber data backtest dan menggunakan data K-line kustom. Parameter arr adalah array, yang elemen adalah data bar K-line (yaitu: K-line data array, yang sementara hanya mendukung backtest JavaScript.

dalam array arr, format data dari elemen tunggal:

[
    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 
]

Sumber data dapat diimpor ke Template.

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

Catatan: pastikan untuk mengimpor data kustom terlebih dahulu (yaitu, panggil fungsi exchange.SetData untuk mengatur data) selama inisialisasi. Periode data K-line kustom harus konsisten dengan periode K-line sublayer yang ditetapkan pada halaman backtest, yaitu: data K-line kustom; waktu K-line adalah 1 menit, jadi periode K-line sublayer yang ditetapkan dalam backtest juga harus ditetapkan menjadi 1 menit.

Menggunakan Platform yang Tidak Didukung oleh FMZ

Jika API platform yang tidak didukung persis sama dengan platform yang didukung, kecuali alamat dasar, platform yang tidak didukung dapat didukung dengan beralih alamat dasar. Untuk lebih spesifik, pilih platform yang didukung saat menambahkan platform, tetapi isi API-KEY dari platform yang tidak didukung, dan gunakan IO untuk mengubah alamat dasar dalam strategi, seperti:

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

Tidak semua platform didukung oleh FMZ, tetapi platform kami telah menyediakan metode akses protokol umum.

  • Ketika Anda menulis kode untuk mengakses platform, program akan membuat layanan web.
  • Ketika Anda menambahkan platform ke FMZ, tentukan alamat dan port layanan web.
  • Ketika docker menjalankan platform bot dari protokol umum, permintaan akses API dalam strategi akan dikirim ke protokol umum.
  • Protokol umum akan mengakses platform dengan permintaan, dan mengembalikan hasilnya ke docker.

Secara sederhana, protokol umum adalah seperti perantara, proxy permintaan docker dan mengembalikan data, sesuai dengan standar yang sesuai. Kode protokol umum perlu diselesaikan sendiri. Menulis protokol umum sebenarnya berarti bahwa Anda dapat mengakses platform saja dan menyelesaikan strategi. FMZ resmi kadang-kadang merilis versi exe dari protokol umum platform. Protokol umum juga dapat dilakukan di Python, yang kemudian dapat dijalankan di docker sebagai bot biasa.

Pengenalan khusus protokol umum:https://www.fmz.com/bbs-topic/9120Contoh menulis protokol umum dalam Python:https://www.fmz.com/strategy/101399

Membuat Platform Kuantitatif Anda Sendiri

Sama seperti berbagai operasi platform dapat diimplementasikan melalui API, situs web FMZ juga didasarkan pada API. Anda dapat mengajukan permohonan untuk API-KEY Anda sendiri dari situs web FMZ untuk mewujudkan fungsi, seperti create, restart, DeleteRobot, GetRobotList GetRobotLogs, dll. Silakan lihat bagian API Extension of FMZ Platform dalam dokumen API untuk rincian.

Karena ekstensibilitas kuat dari platform FMZ Quant, Anda dapat membuat platform kuantitatif Anda sendiri berdasarkan ekstensi API, memungkinkan pengguna Anda untuk menjalankan bot di platform Anda, dll. Referensi spesifik:https://www.fmz.com/bbs-topic/1697 .

Menjadi Mitra FMZ

Promosi Kelas NetEase

Pasar perdagangan cryptocurrency telah menarik lebih banyak perhatian dari pedagang kuantitatif karena keunikannya. Faktanya, perdagangan program telah menjadi arus utama cryptocurrency, dan strategi seperti lindung nilai dan pembuatan pasar selalu aktif di pasar. Pemula dengan dasar pemrograman yang lemah ingin memasuki bidang baru ini, berhadapan dengan banyak platform dan mengubah API, penuh dengan kesulitan.www.fmz.com) saat ini komunitas kuantitatif cryptocurrency terbesar dan platform, telah membantu ribuan pemula di jalan untuk perdagangan kuantitatif selama lebih dari 4 tahun.

PromosiKursus Perdagangan Kuantitatif Cryptocurrency di NetEase Cloud Classroom. Masuk ke NetEase Cloud Classroom dan bagikan link kursus Anda (linknya memiliki ID kursus yang unik). Yang lain, yang mendaftar dan membeli kursus melalui tautan ini, akan membawa Anda 50% dari total sebagai komisi, yaitu 10 yuan. Ikuti akun publik WeChat NetEase Cloud Classroom Premium Course Promotion untuk menarik uang tunai. Anda juga dipersilakan untuk mengundang orang lain untuk mempromosikan kursus di Weibo atau grup QQ.

Berkaitan

Konsumen yang mengklik tautan promosi, mendaftar dan mengisi ulang dalam waktu setengah tahun, akan menikmati kebijakan bahwa perusahaan kami akan memberikan potongan harga sesuai dengan jumlah yang efektif dalam urutan yang berlaku. Komisi akan dikembalikan ke akun promotor dalam bentuk poin. Pengguna dapat menukar poin ke saldo akun platform FMZ dengan rasio 10: 1, dan pengguna juga dapat menggunakan poin untuk menukar produk terkait FMZ Quant di masa depan. Tautan khusus untuk kegiatan:https://www.fmz.com/bbs-topic/3828

Platform Quant FMZ untuk Perusahaan

Situs web FMZ lengkap dapat dikerahkan ke server eksklusif perusahaan atau tim untuk kontrol lengkap dan kustomisasi fungsional. Situs web FMZ telah digunakan dan diuji oleh sekitar 100.000 pengguna, dan telah mencapai ketersediaan dan keamanan yang tinggi, yang dapat menghemat waktu untuk tim kuantitatif dan perusahaan. Versi perusahaan adalah untuk tim perdagangan kuantitatif berukuran sedang, penyedia layanan berjangka komoditas, dll. Silakan hubungi administrator untuk penawaran spesifik.

Sistem Pembuatan Pasar

Sistem profesional, menyediakan likuiditas pasar dan manajemen dana untuk platform, mungkin merupakan sistem pembuatan pasar yang paling ditingkatkan di pasar.

Skema Platform

Sistem perdagangan teknologi FMZ mengadopsi teknologi pencocokan memori, dan kecepatan pemrosesan pesanan setinggi 2 juta perdagangan per detik, yang dapat memastikan bahwa tidak akan ada penundaan atau lag dalam pemrosesan pesanan. Ini dapat menjaga operasi yang lancar dan stabil dari platform dengan lebih dari 20 juta pengguna online bersamaan. Kerangka sistem multi-lapisan dan multi-kluster memastikan keamanan, stabilitas dan ekstensibilitas sistem. Penyebaran fungsi dan pembaruan versi dapat dilakukan tanpa downtime, yang menjamin pengalaman operasi pengguna terminal maksimal. Saat ini, sistem dapat dialami di platform simulasi wex.app.


Lebih banyak