[TOC] Anda harus belajar terlebih dahulu sebelum Anda bisa mempelajari tutorial ini.FMZ Inventor Menggunakan Platform KuantitatifdanFMZ Quantified Platform Strategi Menulis Tutorial Awal, dan mahir menggunakan bahasa pemrograman.Tutorial awal ini membahas fungsi yang paling umum digunakan, tetapi ada banyak fungsi dan fungsi lain yang tidak diuraikan dan tidak akan dicakup dalam tutorial ini. Anda harus melihat dokumentasi API platform untuk mengetahui sendiri.Setelah mempelajari tutorial ini, Anda akan dapat menulis strategi yang lebih bebas, lebih disesuaikan, dan platform FMZ hanyalah alat.
Platform FMZ digabungkan ke semua bursa yang didukung, untuk menjaga keseragaman, dukungan API untuk setiap bursa tidak lengkap. Sebagai contoh, mendapatkan K-line biasanya dapat mengirimkan jumlah atau waktu awal K-line, sedangkan platform FMZ tetap, beberapa platform mendukung pesanan dalam jumlah besar, FMZ tidak mendukung, dll.Untuk antarmuka terbuka (misalnya pasar),HttpQuery
, untuk menambahkan informasi akun, perlu menggunakanIO
。Untuk parameter input yang spesifik, lihat juga dokumen API bursa yang terkait.Info
Bidang ini mengembalikan informasi asli, tetapi masih tidak dapat menyelesaikan masalah tidak mendukung antarmuka.
Mengembalikan konten asli (string) yang dikembalikan pada permintaan REST API terakhir yang dapat digunakan untuk menganalisis informasi ekstensi 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)
}
Akses antarmuka publik, Js dapat digunakanHttpQuery
Python dapat menggunakan paket yang terkait sendiri, seperti:urllib
ataurequests
。
HttpQuery adalah metode GET secara default, dan mendukung lebih banyak fitur. Lihat dokumentasi API.
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 request
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()
Untuk antarmuka yang membutuhkan penandatanganan API-KEY, fungsi IO dapat digunakan, pengguna hanya perlu memperhatikan parameter input, dan proses penandatanganan khusus akan dilakukan oleh lapisan bawah.
FMZ platform saat ini tidak mendukung BitMEX stop loss order.
https://www.bitmex.com/api/explorer/
。https://www.bitmex.com/api/v1/order
Cara ini adalahPOST
Karena FMZ telah menetapkan alamat root secara internal, hanya perlu masukkan "/api/v1/order".symbol=XBTUSD&side=Buy&orderQty=1&stopPx=4000&ordType=Stop
Kode spesifik:
var id = exchange.IO("api", "POST", "/api/v1/order", "symbol=XBTUSD&side=Buy&orderQty=1&stopPx=4000&ordType=Stop")
//也可以直接传入对象
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
Pada dasarnya, semua pertukaran mata uang digital mendukung pasar pengiriman websocket, dan beberapa pertukaran mendukung pembaruan informasi akun websocket. Websocket umumnya memiliki keterlambatan rendah, frekuensi tinggi, dan tidak dibatasi oleh frekuensi API rest platform.
Artikel ini akan membahas tentang platform kuantifikasi FMZ inventor, menggunakan bahasa JavaScript, menggunakan fungsi Dial yang terbungkus platform untuk menghubungkan, penjelasan spesifik dan parameter dalam dokumen, mencari Dial, untuk mencapai berbagai fungsi, fungsi Dial telah melakukan beberapa pembaruan, dan ini akan mencakup strategi penggerak acara berbasis wss, dan masalah menghubungkan multi-exchange. Python juga dapat menggunakan fungsi Dial, dan Anda dapat menggunakan perpustakaan yang sesuai.
Pada umumnya, Anda dapat langsung terhubung, seperti mendapatkan ticker keamanan yang didorong:
var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")
Untuk data yang dikembalikan adalah format yang dikompresi, yang diperlukan pada koneksi yang ditentukan, compress menetapkan format yang dikompresi, mode mewakili pengiriman data yang dikembalikan yang perlu dikompresi, seperti koneksi OKEX:
var client = Dial("wss://real.okex.com:10441/websocket?compress=true|compress=gzip_raw&mode=recv")
Fungsi dial mendukung penyambungan ulang, yang dilakukan oleh bahasa Go yang mendasarinya, penyambungan yang terdeteksi terputus akan dihubungkan kembali, sangat mudah digunakan untuk konten data permintaan yang sudah ada di url, seperti contoh Binance yang baru-baru ini, sangat mudah digunakan. Untuk orang yang perlu mengirim pesan, Anda dapat mempertahankan mekanisme penyambungan ulang sendiri.
var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr|reconnect=true")
Subscribe to news.wss, beberapa permintaan dari bursa di url, dan beberapa saluran yang membutuhkan Anda untuk mengirim langganan sendiri, seperti Coinbase:
client = Dial("wss://ws-feed.pro.coinbase.com", 60)
client.write('{"type": "subscribe","product_ids": ["BTC-USD"],"channels": ["ticker","heartbeat"]}')
Websocket umumnya digunakan untuk membaca transaksi, tetapi juga dapat digunakan untuk mendapatkan pesanan, push akun, dan push data enkripsi semacam ini kadang-kadang sangat lama, perlu digunakan dengan hati-hati. Karena metode enkripsi lebih rumit, berikut adalah beberapa contoh referensi. Perhatikan bahwa hanya perlu AccessKey, yang dapat diatur sebagai parameter kebijakan, seperti yang diperlukan SecretKey, yang dapat digunakan untuk panggilan rahasia fungsi exchange.HMAC ((() untuk memastikan keamanan.
//火币期货推送例子
var ACCESSKEYID = '你的火币账户的accesskey'
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} }") //去掉}}之间的多余空格
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}))
}
}
//币安推送例子,注意需要定时更新listenKey
var APIKEY = '你的币安accesskey'
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()
}
//BitMEX推送例子
var APIKEY = "你的Bitmex API ID"
var expires = parseInt(Date.now() / 1000) + 10
var signature = exchange.HMAC("sha256", "hex", "GET/realtime" + expires, "{{secretkey} }")//secretkey在执行时自动替换,不用填写
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)
}
}
Pada umumnya, dalam siklus kematian, kode yang dapat dibaca terus menerus adalah sebagai berikut:
function main() {
var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr");
while (true) {
var msg = client.read()
var data = JSON.parse(msg) //把json字符串解析为可引用的object
// 处理data数据
}
}
WSS data push sangat cepat, lapisan bawah Go akan menunda semua data di antrian, sementara program memanggil read, dan kemudian kembali; sementara operasi daftar bawah pada disk akan menyebabkan penundaan, yang dapat menyebabkan akumulasi data. Untuk push transaksi, push akun, deep value push, dan lain-lain informasi seperti itu, kita membutuhkan data sejarah, untuk data pasar, sebagian besar kasus kita hanya peduli dengan data terbaru, tidak peduli dengan data sejarah.
read()
Jika tidak menambahkan parameter, akan mengembalikan data tertua, jika tidak ada data, akan diblokir untuk kembali. Jika Anda ingin data terbaru, Anda dapat menggunakanclient.read(-2)
Data yang paling baru dikembalikan dengan segera, tetapi data yang tidak ada lagi dikembalikan dengan nol, dan perlu diperhitungkan kembali.
Berdasarkan bagaimana data lama yang di-cache diperlakukan, dan apakah tidak ada data, read memiliki parameter yang berbeda, seperti yang ditunjukkan di bawah ini, yang terlihat rumit tetapi membuat program lebih fleksibel.
Untuk situasi ini, prosedur jelas tidak dapat menggunakan read sederhana (), karena satu pertukaran akan memblokir pesan yang menunggu, di mana pertukaran 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) // 参数-1代表无数据立即返回null,不会阻塞到有数据返回
var msgCoinbase = coinbase.read(-1)
if(msgBinance){
// 此时币安有数据返回
}
if(msgCoinbase){
// 此时coinbase有数据返回
}
Sleep(1) // 可以休眠1ms
}
}
Bagian ini lebih rumit karena data push dapat terganggu, atau waktu push sangat tinggi, bahkan jika menerima detak jantung tidak berarti data masih sedang dipindahkan, Anda dapat mengatur interval acara, jika melewati interval tidak menerima pembaruan, sambung kembali, dan sebaiknya perbandingan antara waktu dan hasil rest kembali untuk melihat apakah data tersebut akurat. Untuk kasus khusus seperti Bitcoin, Anda dapat langsung mengatur ulang otomatis.
Karena sudah menggunakan data push, program secara alami juga harus ditulis sebagai event driver, berhati-hatilah untuk mendorong data sering, agar tidak terlalu banyak permintaan menyebabkan tertutup, umumnya dapat ditulis sebagai:
var tradeTime = Date.now()
var accountTime = Date.now()
function trade(data){
if(Date.now() - tradeTime > 2000){//这里即限制了2s内只交易一次
tradeTime = Date.now()
//交易逻辑
}
}
function GetAccount(){
if(Date.now() - accountTime > 5000){//这里即限制了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)
}
}
Cara koneksi websocket, cara pengiriman data, konten yang dapat berlangganan, format data dari masing-masing bursa sering berbeda, sehingga platform tidak terbungkus, dan perlu terhubung sendiri dengan fungsi Dial. Artikel ini pada dasarnya mencakup beberapa pertimbangan dasar, dan jika ada pertanyaan, silakan bertanya.
PS. Beberapa bursa meskipun tidak menawarkan pasar websocket, tetapi sebenarnya menggunakan fitur penyampaian situs yang menggunakan fitur penyampaian websocket.
JavaScript dapat diimplementasikan secara paralel melalui fungsi Go, dan Python dapat menggunakan perpustakaan multi-threaded yang sesuai.
Dalam implementasi strategi kuantitatif, dalam banyak kasus, pelaksanaan bersamaan dapat mengurangi efisiensi peningkatan keterlambatan. Sebagai contoh, strategi hedging real-time membutuhkan kedalaman dua koin, kode yang dijalankan secara berurutan adalah sebagai berikut:
var depthA = exchanges[0].GetDepth()
var depthB = exchanges[1].GetDepth()
Permintaan satu kali rest API mengalami keterlambatan, misalkan 100 ms, maka waktu untuk mendapatkan kedalaman dua kali sebenarnya berbeda, dan masalah keterlambatan akan lebih menonjol jika diperlukan lebih banyak kunjungan, yang mempengaruhi pelaksanaan kebijakan.
Karena JavaScript tidak memiliki banyak thread, fungsi Go yang terbungkus di bagian bawah memecahkan masalah ini, fungsi Go dapat digunakan untuk API yang membutuhkan akses jaringan, sepertiGetDepth
,GetAccount
Dan sebagainya.IO
"Saya tidak tahu apa yang terjadi", katanya.exchange.Go("IO", "api", "POST", "/api/v1/contract_batchorder", "orders_data=" + JSON.stringify(orders))
Namun, karena mekanisme desain, implementasinya lebih rumit.
var a = exchanges[0].Go("GetDepth")
var b = exchanges[1].Go("GetDepth")
var depthA = a.wait() //调用wait方法等待返回异步获取depth结果
var depthB = b.wait()
Dalam kebanyakan kasus sederhana, menulis kebijakan dengan cara ini tidak masalah. Namun, perhatikan bahwa setiap siklus kebijakan harus mengulangi proses ini, dan variabel tengah a, b sebenarnya hanya bantuan sementara. Jika kita memiliki banyak tugas paralel, kita juga harus mencatat hubungan antara a dan depthA, b, dan depthB, dan situasinya lebih rumit ketika tugas paralel kita tidak pasti. Oleh karena itu, kita ingin menerapkan fungsi: ketika menulis Go secara bersamaan, mengikat variabel pada saat yang sama, dan ketika hasil dari operasi paralel dikembalikan, hasilnya secara otomatis memberikan nilai kepada variabel, sehingga menghilangkan variabel tengah, sehingga program menjadi lebih sederhana. Secara khusus, kita dapat menerapkan:
function G(t, ctx, f) {
return {run:function(){
f(t.wait(1000), ctx)
}}
}
Kita mendefinisikan sebuah fungsi G di mana parameter t adalah fungsi Go yang akan dijalankan, ctx adalah konteks pada program catatan, dan f adalah fungsi yang diberikan nilai tertentu.
Dalam hal ini, kerangka kerja program secara keseluruhan dapat ditulis sebagai mirip dengan model kerangka kerja produsen-konsumen (dengan beberapa perbedaan), di mana produsen terus-menerus mengeluarkan tugas, konsumen mengeksekusi mereka secara bersamaan, sementara kode hanya untuk demonstrasi dan tidak melibatkan logika eksekusi program.
var Info = [{depth:null, account:null}, {depth:null, account:null}] //加入我们需要获取两个交易所的深度和账户,跟多的信息也可以放入,如订单Id,状态等。
var tasks = [ ] //全局的任务列表
function produce(){ //下发各种并发任务
//这里省略了任务产生的逻辑,仅为演示
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 //这里的v就是并发Go函数wait()的返回值,可以仔细体会下
}))
}
_.each(jobs, function(t){
t.run() //在这里并发执行所有任务
})
tasks = []
}
function main() {
while(true){
produce() // 发出交易指令
worker() // 并发执行
Sleep(1000)
}
}
Sepertinya berputar-putar hanya mencapai fungsi sederhana, sebenarnya sangat menyederhanakan tingkat kompleksitas kode, kita hanya perlu peduli dengan tugas apa yang harus dihasilkan oleh program, dan program worker akan secara otomatis mengeksekusi mereka secara bersamaan dan mengembalikan hasil yang sesuai.
Tutorial awal tentang diagram adalah rekomendasi untuk perpustakaan diagram, yang sebagian besar dapat memenuhi kebutuhan. Jika perlu kustomisasi lebih lanjut, objek Chart dapat dioperasikan secara langsung.
Chart({…})
Parameter internal adalah objek HighStock dan HighCharts, hanya dengan menambahkan satu parameter tambahan__isStock
Untuk membedakan apakah itu adalah HighStock. HighStock lebih berfokus pada grafik urutan waktu, sehingga lebih sering digunakan. FMZ mendukung modul dasar dari HighCharts dan HighStock, tetapi tidak mendukung modul tambahan.
Contoh khusus HighCharts:https://www.highcharts.com/demoContoh HighStock:https://www.highcharts.com/stock/demo│ Menggunakan contoh-contoh ini, kode dapat dengan mudah dipindahkan ke FMZ│
Anda dapat memanggil add (([series index ((misalnya 0), data]) untuk menambahkan data ke dalam seri indeks yang ditentukan, memanggil reset (() data grafik kosong, reset dapat membawa parameter angka, yang menentukan catatan yang dilestarikan. Mendukung untuk menampilkan beberapa grafik, konfigurasi hanya membutuhkan parameter array seperti: var chart = Chart (([{...}, {...}, {...}), misalnya, grafik pertama memiliki dua seri, grafik memiliki satu seri, grafik memiliki tiga seri, maka ketika menambahkan satu seri dengan 01, seri ID mewakili data dari dua seri baru dari grafik 1, ketika menambahkan seri ID menunjukkan data dari seri pertama dari grafik 2, dan spesifikasi seri 3 menunjukkan data dari seri pertama dari grafik 3;
Salah satu contohnya adalah:
var chart = { // 这个 chart 在JS 语言中 是对象, 在使用Chart 函数之前我们需要声明一个配置图表的对象变量chart。
__isStock: true, // 标记是否为一般图表,有兴趣的可以改成 false 运行看看。
tooltip: {xDateFormat: '%Y-%m-%d %H:%M:%S, %A'}, // 缩放工具
title : { text : '差价分析图'}, // 标题
rangeSelector: { // 选择范围
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'}, // 坐标轴横轴 即:x轴, 当前设置的类型是 :时间
yAxis : { // 坐标轴纵轴 即:y轴, 默认数值随数据大小调整。
title: {text: '差价'}, // 标题
opposite: false, // 是否启用右边纵轴
},
series : [ // 数据系列,该属性保存的是 各个 数据系列(线, K线图, 标签等..)
{name : "line1", id : "线1,buy1Price", data : []}, // 索引为0, data 数组内存放的是该索引系列的 数据
{name : "line2", id : "线2,lastPrice", dashStyle : 'shortdash', data : []}, // 索引为1,设置了dashStyle : 'shortdash' 即:设置 虚线。
]
};
function main(){
var ObjChart = Chart(chart); // 调用 Chart 函数,初始化 图表。
ObjChart.reset(); // 清空
while(true){
var nowTime = new Date().getTime(); // 获取本次轮询的 时间戳, 即一个 毫秒 的时间戳。用来确定写入到图表的X轴的位置。
var ticker = _C(exchange.GetTicker); // 获取行情数据
var buy1Price = ticker.Buy; // 从行情数据的返回值取得 买一价
var lastPrice = ticker.Last + 1; // 取得最后成交价,为了2条线不重合在一起 ,我们加1
ObjChart.add([0, [nowTime, buy1Price]]); // 用时间戳作为X值, 买一价 作为Y值 传入 索引0 的数据序列。
ObjChart.add([1, [nowTime, lastPrice]]); // 同上。
Sleep(2000);
}
}
Contoh yang digunakan adalah tata letak grafik:https://www.fmz.com/strategy/136056
Alamat sumber terbuka khusus:https://github.com/fmzquant/backtest_python
Pemasangan
Pada baris perintah, masukkan perintah berikut:
pip install https://github.com/fmzquant/backtest_python/archive/master.zip
Contoh sederhana
Parameter retargeting diatur dalam bentuk komentar di awal kode kebijakan, lihat pengaturan retargeting yang disimpan di antarmuka editor kebijakan situs 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
Pengamatan
Karena strategi yang lengkap membutuhkan siklus mati, EOF yang tidak normal akan dibuang untuk mengakhiri prosedur setelah retesting selesai, sehingga kesalahan harus dilakukan.
# !/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__
# ------------------------------ 策略部分开始 --------------------------
print exchange.GetAccount() # 调用一些接口,打印其返回值。
print exchange.GetTicker()
def adjustFloat(v): # 策略中自定义的函数
v = math.floor(v * 1000)
return v / 1000
def onTick():
Log("onTick")
# 具体的策略代码
def main():
InitAccount = GetAccount()
while True:
onTick()
Sleep(1000)
# ------------------------------ 策略部分结束 --------------------------
try:
main() # 回测结束时会 raise EOFError() 抛出异常,来停止回测的循环。所以要对这个异常处理,在检测到抛出的异常后调用 task.Join() 打印回测结果。
except:
print task.Join()
exchange.SetData ((arr), beralih sumber data retest, menggunakan data baris K yang disesuaikan. Parameter arr, adalah sebuah elemen yang merupakan array data kolom baris K (yaitu: array data baris K, sementara hanya mendukung retest JavaScript).
Dalam array arr, format data untuk elemen tunggal adalah:
[
1530460800, // time 时间戳
2841.5795, // open 开盘价
2845.6801, // high 最高价
2756.815, // low 最低价
2775.557, // close 收盘价
137035034 // volume 成交量
]
Sumber data dapat diimpor ke dalam keranjang template.
function init() { // 模板中的 init 初始化函数会在加载模板时,首先执行,确保 exchange.SetData(arr) 函数先执行,初始化,设置数据给回测系统。
var arr = [ // 回测的时候需要使用的K线数据
[1530460800,2841.5795,2845.6801,2756.815,2775.557,137035034], // 时间最早的一根 K线柱 数据
... , // K线数据太长,用 ... 表示,数据此处省略。
[1542556800,2681.8988,2703.5116,2674.1781,2703.5116,231662827] // 时间最近的一根 K线柱 数据
]
exchange.SetData(arr) // 导入上述 自定义的数据
Log("导入数据成功")
}
Catatan: Anda harus menginisialisasi data kustom (misalnya, memanggil data pengaturan fungsi exchange.SetData) terlebih dahulu, dan siklus data K-line kustom harus sesuai dengan siklus K-line dasar yang ditetapkan pada halaman retargeting, yaitu: data K-line kustom, waktu satu K-line adalah 1 menit, maka siklus K-line dasar yang ditetapkan pada retargeting juga ditetapkan menjadi 1 menit.
Jika pertukaran yang tidak didukung dan API yang sudah didukung sama persis, hanya alamat basis yang berbeda, dapat didukung dengan cara menukar alamat basis. Khususnya untuk memilih pertukaran yang sudah didukung saat menambahkan pertukaran, tetapi API-KEY mengisi pertukaran yang tidak didukung, dalam kebijakan, gunakan IO untuk mengganti alamat basis, seperti:
exchange.IO("base", "http://api.huobi.pro")
//http://api.huobi.pro为为支持交易所API基地址,注意不用添加/api/v3之类的,会自动补全
Tidak semua bursa mendukung FMZ, tetapi platform ini menyediakan akses ke protokol umum.
Secara sederhana, protokol umum adalah seperti seorang perantara yang menugaskan permintaan dari host dan mengembalikan data sesuai dengan standar yang sesuai. Kode protokol umum perlu diselesaikan sendiri, menulis protokol umum sebenarnya mewakili bahwa Anda dapat mengakses pertukaran secara terpisah dan menyelesaikan kebijakan. FMZ resmi kadang-kadang merilis versi exe dari protokol umum. Protokol umum juga dapat digunakan untuk menyelesaikan Python, di mana itu dapat berjalan seperti sebuah hard drive biasa pada host.
Pernyataan ini disampaikan oleh seorang pejabat senior di Kementerian Luar Negeri.https://www.fmz.com/bbs-topic/1052Contoh Python menulis protokol umum:https://www.fmz.com/strategy/101399
Seperti halnya berbagai operasi yang dapat dilakukan melalui API, situs FMZ juga berbasis API, Anda dapat mengajukan aplikasi API-KEY situs FMZ Anda sendiri untuk mewujudkan berbagai fungsi seperti membuat, memulai kembali, menghapus cakram nyata, mengakses daftar cakram nyata, mengakses log cakram nyata, dan lain-lain.
Karena kemampuan yang kuat untuk memperluas platform FMZ, Anda dapat membuat platform kuantitatif Anda sendiri berdasarkan API ekstensi, memungkinkan pengguna untuk menjalankan real disk di platform Anda, dll.
Pasar perdagangan mata uang digital semakin menjadi perhatian para pedagang kuantitatif karena keunikannya. Pada kenyataannya, perdagangan terprogram sudah menjadi arus utama mata uang digital, dan strategi seperti hedging pasar tidak pernah aktif di pasar. Sementara pemula yang memiliki dasar pemrograman yang lemah ingin masuk ke bidang ini, menghadapi banyak pertukaran dan API yang bervariasi, kesulitan berat.www.fmz.comBitcoin (BTC) adalah komunitas dan platform kuantitatif mata uang digital terbesar saat ini dan telah membantu ribuan pemula untuk melakukan transaksi kuantitatif selama lebih dari empat tahun.
PemasaranPelatihan Quantitative Transaction Digital Currency di kelas cloud⇒ Masuk ke kelas cloud, bagikan link kursus Anda, dan jika orang lain mendaftar dan membeli kursus melalui tautan ini, Anda akan mendapatkan pembagian 50% sebesar 10 yuan.
Konsumen mengklik tautan promosi, dan dalam waktu enam bulan mendaftar untuk mengisi ulang, kami akan mengembalikan komisi sesuai dengan jumlah yang berlaku dalam pesanan yang berlaku. Komisi akan dikembalikan dalam bentuk poin ke akun pengiklan, pengguna dapat menukar saldo akun inventor dengan rasio 10:1, atau dapat menggantikan inventor dengan poin di kemudian hari.https://www.fmz.com/bbs-topic/3828
Situs FMZ lengkap dapat diimplementasikan ke server eksklusif perusahaan atau tim, untuk mencapai kontrol dan kustomisasi fungsionalitas yang lengkap. Situs FMZ telah digunakan dan diuji oleh sekitar 100.000 pengguna, mencapai ketersediaan dan keamanan yang tinggi, menghemat biaya waktu tim kuantitatif dan perusahaan. Versi perusahaan yang ditujukan untuk tim perdagangan kuantitatif ukuran menengah, pelayan berjangka komoditas, dll.
Sistem profesional yang menyediakan likuiditas pasar dan manajemen dana untuk bursa mungkin merupakan sistem pasar yang paling lengkap di pasar, yang digunakan oleh banyak bursa dan tim.
Sistem perdagangan teknologi penemu menggunakan teknologi pemotretan memori, pemrosesan pesanan dengan kecepatan hingga 2 juta pips/detik, yang dapat menjamin pemrosesan pesanan tidak terjadi penundaan dan karton; dapat menjaga operasi yang lancar dan stabil dari pertukaran dengan jumlah pengguna online lebih dari 20 juta pada saat yang sama. Arsitektur sistem multi-lapisan, multi-klompok menjamin keamanan, stabilitas, dan mudah dapat diperluas sistem; penyebaran fungsi, pembaruan versi tanpa henti dilakukan, yang memaksimalkan pengalaman pengoperasian pengguna akhir. Saat ini sistem ini dapat dialami di wex.app simulasi perdagangan.
bbbwwed2009Apakah Anda masih bisa bergabung?
MAIKEODewa Rumput, WWE!!!
Rumput`` // Contoh token futures push var ACCESSKEYID = 'kunci akses untuk akun token Anda' var apiClient = Dial (('wss://api.hbdm.com/notification in 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.toISOSstring (().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}}") ``
Brigade BeatJika websocket terhubung ke pasar langganan, maka data pasar akan diambil dengan fungsi read ((), kan? Jika menggunakan exchange.GetTicker ((), maka data tidak akan diambil dari cache lokal, tetapi permintaan rest akan dikembalikan, kan? Hanya satu token yang mendukung perubahan penerimaan pasar melalui exchange.IO ("websocket") dan kemudian menggunakan exchange.GetTicker (), dan exchange.GetDepth (), yang tidak akan meminta data dari rest pasar, dan mendapatkan data dari pasar langganan yang telah diterima yang ada di buffer lokal. Saya mengerti, kan?
RumputMengikuti petunjuk verifikasi
JyzliuyuSilahkan verifikasi informasi di bawah ini di FMZ Telegram Group adalah:
ShaltielBaiklah.
RumputYa, sebaiknya semua websocket menggunakan Dial, lebih mudah dikontrol.