[TOC] Bạn cần phải học trước khi học bài này.Khởi nghiệp với nền tảng định lượng của FMZVàFMZ định lượng nền tảng chiến lược viết hướng dẫn ban đầuVà cũng có khả năng sử dụng ngôn ngữ lập trình.Hướng dẫn này đề cập đến các chức năng được sử dụng phổ biến nhất, nhưng có rất nhiều chức năng và tính năng không được giới thiệu trong hướng dẫn này. Bạn cần tự mình tìm hiểu bằng cách xem tài liệu API của nền tảng.Sau khi học xong bài này, bạn sẽ có thể viết một chiến lược tự do và được tùy chỉnh hơn, và FMZ chỉ là một công cụ.
Nền tảng FMZ được đóng gói cho tất cả các sàn giao dịch được hỗ trợ, để duy trì tính thống nhất, hỗ trợ API cho các sàn giao dịch đơn lẻ không hoàn chỉnh. Như lấy K-line thường có thể truyền vào số lượng K-line hoặc thời gian bắt đầu, trong khi nền tảng FMZ là cố định, một số nền tảng hỗ trợ đặt hàng hàng loạt, FMZ không hỗ trợ, v.v. Vì vậy, cần một phương pháp truy cập trực tiếp dữ liệu sàn giao dịch.Đối với các giao diện công khai (nếu có), có thể sử dụngHttpQueryCác tài khoản khác có thể được sử dụng để mở tài khoản.IO。Các tham số nhập cụ thể cũng được tham khảo trong tài liệu API của sàn giao dịch tương ứng.InfoCác trường trả về thông tin gốc, nhưng vẫn không thể giải quyết vấn đề không hỗ trợ giao diện.
Trả về nội dung ban đầu của yêu cầu REST API cuối cùng ((string), có thể được sử dụng để tự phân tích thông tin mở rộng.
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)
}
Truy cập giao diện công khai, Js có thể sử dụngHttpQueryPython có thể tự sử dụng các gói liên quan, chẳng hạn như:urllibhoặcrequests。
HttpQuery là phương thức GET theo mặc định và hỗ trợ nhiều tính năng hơn, xem tài liệu 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"))
Ví dụ sử dụng Python requests
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()
Đối với các giao diện yêu cầu chữ ký API-KEY, có thể sử dụng hàm IO, người dùng chỉ cần quan tâm đến tham số truyền, quá trình ký cụ thể sẽ được thực hiện bởi lớp dưới.
Hiện tại, FMZ không hỗ trợ lệnh dừng BitMEX, thực hiện theo các bước sau:
https://www.bitmex.com/api/explorer/。https://www.bitmex.com/api/v1/orderPhương pháp làPOST。 Vì FMZ đã chỉ định địa chỉ gốc trong nội bộ, chỉ cần nhập “/api/v1/order” thì đủ rồi。symbol=XBTUSD&side=Buy&orderQty=1&stopPx=4000&ordType=StopMã cụ thể:
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"}))
Thêm ví dụ về IO: https://www.fmz.com/bbs-topic/3683
Về cơ bản, tất cả các sàn giao dịch tiền kỹ thuật số đều hỗ trợ websocket gửi đi, một số sàn giao dịch hỗ trợ thông tin tài khoản cập nhật websocket. So với Rest API, websocket thường có độ trễ thấp, tần số cao, không bị giới hạn tần số Rest API của nền tảng, nhược điểm là có vấn đề gián đoạn, xử lý không trực quan.
Bài viết này sẽ chủ yếu giới thiệu về nền tảng định lượng của nhà phát minh FMZ, sử dụng ngôn ngữ JavaScript, sử dụng hàm Dial được đóng gói trong nền tảng để kết nối, chi tiết và tham số trong tài liệu, tìm kiếm Dial, hàm Dial đã được cập nhật một vài lần để thực hiện các chức năng khác nhau, bài viết này sẽ bao gồm điều này và giới thiệu về chiến lược điều khiển sự kiện dựa trên wss, và các vấn đề liên kết nhiều sàn giao dịch. Python cũng có thể sử dụng hàm Dial, cũng có thể sử dụng thư viện tương ứng.
Thông thường, bạn có thể kết nối trực tiếp, chẳng hạn như nhận được ticker bảo mật tiền tệ:
var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")
Đối với dữ liệu được trả về là định dạng nén, cần phải được chỉ định trong kết nối, compress chỉ định định dạng nén, mode đại diện cho gửi dữ liệu trở lại cần được nén, như kết nố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 ngôn ngữ Go cấp dưới, kết nối bị ngắt kết nối sẽ được kết nối lại, rất tiện lợi và được đề nghị sử dụng cho nội dung dữ liệu yêu cầu đã có trong url, như ví dụ của Binance vừa qua. Đối với những người cần gửi tin nhắn đặt hàng, bạn 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ý tin tức wss, một số sàn giao dịch yêu cầu trong url, và một số kênh cũng yêu cầu gửi đăng ký riêng, như coinbase:
client = Dial("wss://ws-feed.pro.coinbase.com", 60)
client.write('{"type": "subscribe","product_ids": ["BTC-USD"],"channels": ["ticker","heartbeat"]}')
Thông thường sử dụng websocket để đọc thông tin, nhưng cũng có thể được sử dụng để lấy lệnh, đẩy tài khoản, việc đẩy dữ liệu được mã hóa như vậy đôi khi có thời gian trì hoãn rất lớn, nên cần thận trọng. Vì phương pháp mã hóa phức tạp hơn, đây là một vài ví dụ tham khảo. Lưu ý rằng chỉ cần AccessKey, có thể được thiết lập thành tham số chính sách, nếu cần SecretKey, có thể sử dụng exchange.HMAC) hàm ẩn danh, đảm bảo an toàn.
//火币期货推送例子
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)
}
}
Có thể đọc liên tục trong vòng lặp chết, mã như sau:
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 dữ liệu đẩy tốc độ rất nhanh, Go cấp dưới sẽ lưu trữ tất cả dữ liệu trong hàng, các chương trình gọi read, và sau đó trở lại. Trong khi các hoạt động như đặt hàng của ổ cứng sẽ mang lại sự chậm trễ, có thể gây ra sự tích lũy của dữ liệu. Đối với chuyển giao đẩy, tài khoản đẩy, độ sâu đẩy giá trị, chúng tôi cần dữ liệu lịch sử, đối với dữ liệu thực tế, chúng tôi chỉ quan tâm đến dữ liệu mới nhất, không quan tâm đến dữ liệu lịch sử.
read()Nếu không thêm tham số, sẽ trả về dữ liệu cũ nhất, nếu không có dữ liệu thì sẽ bị chặn để trả về. Nếu muốn dữ liệu mới nhất, bạn có thể sử dụngclient.read(-2)Trả về dữ liệu mới nhất ngay lập tức, nhưng trả về null khi không còn dữ liệu, cần phải đánh giá và tham khảo.
Read có các tham số khác nhau, tùy thuộc vào cách xử lý dữ liệu cũ trong bộ nhớ cache và có bị tắc khi không có dữ liệu hay không, cụ thể như hình dưới đây, có vẻ phức tạp, nhưng cho phép chương trình linh hoạt hơn.

Đối với trường hợp này, rõ ràng là không thể sử dụng read () đơn giản trong quy trình, vì một sàn giao dịch sẽ chặn tin nhắn chờ đợi, trong khi sàn giao dịch khác sẽ không nhận được tin nhắn ngay cả khi có tin tức 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) // 参数-1代表无数据立即返回null,不会阻塞到有数据返回
var msgCoinbase = coinbase.read(-1)
if(msgBinance){
// 此时币安有数据返回
}
if(msgCoinbase){
// 此时coinbase有数据返回
}
Sleep(1) // 可以休眠1ms
}
}
Phần xử lý này khá rắc rối, vì dữ liệu đẩy có thể bị gián đoạn hoặc chậm trễ rất cao, ngay cả khi nhận được heartbeat không có nghĩa là dữ liệu vẫn đang được đẩy, bạn có thể thiết lập một khoảng thời gian sự kiện, nếu vượt quá khoảng thời gian không nhận được cập nhật, hãy kết nối lại, và tốt nhất là so sánh kết quả với rest trở lại sau một thời gian để xem dữ liệu có chính xác không. Đối với trường hợp đặc biệt này, bạn có thể thiết lập tự động kết nối lại trực tiếp.
Vì đã sử dụng dữ liệu đẩy, chương trình tự nhiên phải được viết thành ổ đĩa sự kiện, lưu ý rằng dữ liệu đẩy thường xuyên, không cần quá nhiều yêu cầu dẫn đến bị chặn, thường có thể được viết như sau:
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)
}
}
Cách kết nối websocket của các sàn giao dịch, cách gửi dữ liệu, nội dung có thể đăng ký và định dạng dữ liệu thường khác nhau, vì vậy nền tảng không được đóng gói và cần kết nối tự động bằng hàm Dial. Bài viết này về cơ bản bao gồm một số lưu ý cơ bản.
PS. Một số sàn giao dịch mặc dù không cung cấp websocket, nhưng thực sự truy cập trang web sử dụng chức năng định dạng, bạn sẽ thấy rằng tất cả đều sử dụng websocket push, nghiên cứu sẽ tìm thấy định dạng đăng ký và định dạng trả về.
JavaScript có thể thực hiện song song thông qua hàm Go, Python có thể sử dụng thư viện đa luồng tương ứng.
Trong thực hiện chiến lược định lượng, trong nhiều trường hợp, việc thực hiện đồng thời có thể làm giảm hiệu quả nâng cao độ trễ. Ví dụ, đối với ổ đĩa thực của chiến lược bảo hiểm, cần có được độ sâu hai đồng xu, mã được thực hiện theo thứ tự như sau:
var depthA = exchanges[0].GetDepth()
var depthB = exchanges[1].GetDepth()
Có sự chậm trễ khi yêu cầu API nghỉ ngơi. Giả sử là 100ms. Khi đó, thời gian để có được độ sâu hai lần thực sự khác nhau. Nếu cần nhiều quyền truy cập hơn, vấn đề chậm trễ sẽ nổi bật hơn, ảnh hưởng đến việc thực hiện chiến lược.
Vì JavaScript không có nhiều luồng, do đó hàm Go được đóng gói dưới nền để giải quyết vấn đề này. Chức năng Go có thể được sử dụng cho các API cần truy cập mạng, chẳng hạn nhưGetDepth,GetAccountThậm chí còn hỗ trợIOGọi như:exchange.Go("IO", "api", "POST", "/api/v1/contract_batchorder", "orders_data=" + JSON.stringify(orders))Tuy nhiên, vì cơ chế thiết kế, việc thực hiện nó khá phức tạp.
var a = exchanges[0].Go("GetDepth")
var b = exchanges[1].Go("GetDepth")
var depthA = a.wait() //调用wait方法等待返回异步获取depth结果
var depthB = b.wait()
Trong hầu hết các trường hợp đơn giản, không có gì sai khi viết chính sách theo cách này. Nhưng lưu ý rằng quá trình này phải được lặp lại mỗi lần chiến lược lặp lại và các biến trung gian a và b thực chất chỉ là giải pháp hỗ trợ tạm thời. Nếu chúng ta có nhiều tác vụ đồng thời, chúng ta cần ghi lại sự tương ứng giữa a và độ sâu A, và b và độ sâu B. Khi các tác vụ đồng thời của chúng ta không chắc chắn, tình hình trở nên phức tạp hơn. Do đó, chúng ta muốn triển khai một hàm: khi viết Go đồng thời, liên kết một biến cùng lúc và khi kết quả chạy đồng thời được trả về, kết quả sẽ tự động được gán cho biến, do đó loại bỏ các biến trung gian và làm cho chương trình dễ hiểu hơn. súc tích. Việc thực hiện cụ thể như sau:
function G(t, ctx, f) {
return {run:function(){
f(t.wait(1000), ctx)
}}
}
Chúng tôi định nghĩa hàm G, trong đó tham số t là hàm Go sẽ được thực thi, ctx là ngữ cảnh chương trình và f là hàm để gán cụ thể. Chúng ta sẽ sớm thấy chức năng này hoạt động.
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 “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 đưa ra các tác vụ và người tiêu dùng thực hiện chúng đồng thời. Mã sau đây chỉ để trình diễn và không liên quan đến chương trình. Thực hiện logic.
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)
}
}
Có vẻ như chúng ta chỉ triển khai một hàm đơn giản sau khi trải qua nhiều bước, nhưng thực tế, độ phức tạp của mã đã được đơn giản hóa rất nhiều. Chúng ta chỉ cần quan tâm đến những tác vụ mà chương trình cần tạo ra và worker( ) chương trình 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 đáng kể.
Hình vẽ được giới thiệu trong hướng dẫn ban đầu là thư viện đồ họa được đề xuất, trong hầu hết các trường hợp, nó có thể đáp ứng nhu cầu. Nếu cần tùy chỉnh thêm, bạn có thể điều khiển trực tiếp đối tượng Chart.
Chart({…})Các tham số nội bộ là đối tượng HighStock và HighCharts, chỉ thêm một tham số__isStockĐể phân biệt HighStock. HighStock chú ý nhiều hơn đến các biểu đồ theo trình tự thời gian, do đó nó được sử dụng thường xuyên hơn. FMZ 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 ; Ví dụ của HighStock: https://www.highcharts.com/stock/demo 。 tham khảo các mã của các ví dụ này, có thể dễ dàng chuyển sang FMZ。
Bạn có thể gọi add ().[series index ((như 0), dữ liệu]) thêm dữ liệu vào series được chỉ định, gọi reset ((() xóa dữ liệu biểu đồ, reset có thể có một tham số, chỉ định số mục được lưu giữ. Chữ liệu hỗ trợ hiển thị nhiều biểu đồ, khi cấu hình chỉ cần nhập tham số mảng như: var chart = Chart ((([{…}, {…}, {…}]), ví dụ như biểu đồ một có hai series, biểu đồ hai có một series, biểu đồ ba có một series, thì khi add chỉ định 0 và 1 trình tự ID đại diện cho dữ liệu của hai series của biểu đồ 1 được cập nhật, khi add chỉ định trình tự ID là 2 chỉ định dữ liệu của series đầu tiên của biểu đồ 2, và chỉ định trình tự 3 chỉ định dữ liệu của series đầu tiên của biểu đồ 3.
Một ví dụ cụ thể:
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);
}
}
Một ví dụ sử dụng bố cục biểu đồ: https://www.fmz.com/strategy/136056
Địa chỉ nguồn mở cụ thể: https://github.com/fmzquant/backtest_python
Cài đặt
Ghi lệnh sau vào dòng lệnh
pip install https://github.com/fmzquant/backtest_python/archive/master.zip
Ví dụ đơn giản
Các tham số phản hồi được thiết lập dưới dạng chú thích ở đầu mã chính sách, cụ thể xem FMZ trang web giao diện biên tập chính sách để lưu các thiết lập phản hồi.
'''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 ngược
Vì chiến lược hoàn chỉnh cần một vòng lặp chết, khi kết thúc phản hồi, một trường hợp ngoại lệ của EOF sẽ được ném ra để kết thúc quá trình, do đó cần phải có sự chấp nhận lỗi.
# !/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), chuyển đổi nguồn dữ liệu phản hồi, sử dụng dữ liệu K-đường tùy chỉnh. Parameter arr, một mảng dữ liệu K-đường là một mảng dữ liệu K-đường.
Trong mảng arr, định dạng dữ liệu của mỗi phần tử là:
[
1530460800, // time 时间戳
2841.5795, // open 开盘价
2845.6801, // high 最高价
2756.815, // low 最低价
2775.557, // close 收盘价
137035034 // volume 成交量
]
Nguồn dữ liệu có thể được nhập vào trong kho của lớp 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("导入数据成功")
}
Lưu ý: Khi khởi tạo, trước tiên phải nhập dữ liệu tùy chỉnh (tức là gọi dữ liệu thiết lập của hàm exchange.SetData), chu kỳ dữ liệu K-line tùy chỉnh phải phù hợp với chu kỳ K-line cơ bản được thiết lập trên trang đo lường, tức là: dữ liệu K-line tùy chỉnh, thời gian của một K-line là 1 phút, sau đó chu kỳ K-line cơ bản được thiết lập trong đo lường cũng được thiết lập là 1 phút.
Nếu giao dịch không được hỗ trợ và API của giao dịch được hỗ trợ giống hệt nhau, chỉ có địa chỉ cơ sở khác nhau, bạn có thể hỗ trợ bằng cách chuyển đổi địa chỉ cơ sở. Để thêm giao dịch cụ thể, hãy chọn giao dịch được hỗ trợ, nhưng hãy điền API-KEY vào giao dịch không được hỗ trợ, sử dụng IO để chuyển đổi đị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为为支持交易所API基地址,注意不用添加/api/v3之类的,会自动补全
Không phải tất cả các sàn giao dịch đều hỗ trợ FMZ, nhưng nền tảng này cung cấp cách truy cập vào các giao thức chung.
Nói một cách đơn giản, giao thức chung tương đương với một trung gian, đại diện cho yêu cầu của người quản lý 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 tự hoàn thành, viết giao thức chung thực sự đại diện cho việc bạn có thể truy cập vào sàn giao dịch một cách riêng biệt, hoàn thành chiến lược. FMZ chính thức đôi khi phát hành phiên bản giao thức chung exe của sàn giao dịch.
Một số người khác, trong số đó có cả người Việt Nam, cũng đã tham gia. Ví dụ về việc Python viết một giao thức chung: https://www.fmz.com/strategy/101399
Các hoạt động khác nhau có thể được thực hiện thông qua API giống như các sàn giao dịch, trang web FMZ cũng dựa trên API, bạn có thể yêu cầu thực hiện API-KEY của trang web FMZ của riêng bạn như tạo, khởi động lại, xóa ổ đĩa thực, truy cập danh sách ổ đĩa thực, truy cập nhật ký ổ đĩa thực và các chức năng khác nhau.
Với khả năng mở rộng mạnh mẽ của nền tảng FMZ, bạn có thể tạo nền tảng định lượng của riêng mình dựa trên API mở rộng, cho phép người dùng chạy máy chủ trên nền tảng của bạn.
Thị trường giao dịch tiền kỹ thuật số ngày càng được quan tâm bởi các nhà giao dịch định lượng vì tính đặc biệt của nó, thực tế giao dịch theo quy trình đã là dòng chính của tiền kỹ thuật số, các chiến lược như làm thị trường bảo hiểm luôn hoạt động trên thị trường. Những người mới bắt đầu có nền tảng lập trình yếu muốn vào lĩnh vực này, phải đối mặt với nhiều sàn giao dịch và nhiều API thay đổi, khó khăn nặng nề.
Tiếp tụcKhóa học giao dịch số lượng tiền kỹ thuật số trong lớp học NetEase Cloud│ Đăng nhập vào lớp học NetEase Cloud, chia sẻ liên kết khóa học của bạn ((liên kết có CourseId độc đáo), những người khác đăng ký và mua khóa học thông qua liên kết này, bạn sẽ nhận được 50% tổng cộng 10 yuan. │ Chú ý đến việc quảng bá các bài học đặc biệt của lớp học NetEase Cloud, số công cộng của Weibo có sẵn. │ Chào mừng mọi người mời người khác quảng bá trên nhóm Weibo QQ.
Người tiêu dùng nhấp vào liên kết quảng bá và đăng ký nạp tiền trong vòng sáu tháng, chúng tôi sẽ trả lại hoa hồng theo số tiền có hiệu lực trong đơn đặt hàng hợp lệ. Hóa đơn sẽ được trả lại dưới dạng tích lũy vào tài khoản của người quảng bá, người dùng có thể đổi số dư tài khoản của nhà phát minh bằng tỷ lệ 10: 1, cũng có thể đổi số dư tài khoản của nhà phát minh bằng tích lũy.
Trang web FMZ có thể được triển khai đầy đủ trên máy chủ độc quyền của doanh nghiệp hoặc nhóm, để thực hiện kiểm soát và tùy chỉnh chức năng hoàn toàn. Trang web FMZ đã được sử dụng và kiểm tra bởi khoảng 100.000 người dùng, đạt được khả năng sử dụng và bảo mật cao, có thể tiết kiệm chi phí thời gian của nhóm và doanh nghiệp. Phiên bản doanh nghiệp hướng đến nhóm giao dịch định lượng vừa và trung bình, các nhà cung cấp dịch vụ giao dịch hàng hóa tương lai, v.v.
Hệ thống chuyên nghiệp cung cấp cho các sàn giao dịch thanh khoản thị trường và quản lý vốn, có thể là hệ thống giao dịch hoàn hảo nhất trên thị trường, được sử dụng bởi nhiều sàn giao dịch và nhóm.
Hệ thống giao dịch công nghệ của nhà phát minh sử dụng công nghệ ghép bộ nhớ, tốc độ xử lý đơn đặt hàng lên đến 2 triệu pin / giây, có thể đảm bảo xử lý đơn đặt hàng sẽ không có bất kỳ sự chậm trễ và carton. Có thể duy trì hoạt động ổn định của các sàn giao dịch với số lượng người dùng trực tuyến vượt quá 20 triệu người. Kiến trúc hệ thống nhiều tầng, nhiều nhóm đảm bảo an toàn, ổn định và dễ mở rộng của hệ thống.