[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 QuantvàHướ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ụ.
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.Info
trườ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.
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)
}
Để 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ưurllib
hoặ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()
Đố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:
https://www.bitmex.com/api/explorer/
;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 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
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.
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;
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"]}')
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)
}
}
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,
Trong trường hợp này, rõ ràng rằng chỉ cần sử dụng
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
}
}
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
Đố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)
}
}
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.
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
, GetAccount
và như vậy.IO
cũ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ạ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
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
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
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__isStock
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; 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
Đị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
'''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()
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
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
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.
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.
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
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ư
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 .
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
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
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 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.
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.