Thông báo lệnh giao dịch Giá: 1000, // Giá đặt lệnh; lưu ý thuộc tính này của lệnh thị trường có thể là 0 hoặc -1 Số tiền: 10, // Đặt số tiền lệnh; lưu ý thuộc tính này của lệnh thị trường có thể là số tiền, không phải số tiền xu DealAmount : 10, // Khối lượng được thực thi; nếu giao diện nền tảng không cung cấp loại dữ liệu này, có thể sử dụng 0 để điền vào AvgPrice: 1000, // Giá trung bình được thực hiện; lưu ý một số nền tảng không cung cấp dữ liệu này. Tình trạng: 1, // Tình trạng lệnh; tham khảo tình trạng lệnh trong các hằng số, chẳng hạn như ORDER_STATE_CLOSED Loại: 0, // Loại lệnh; tham khảo loại lệnh trong các hằng số, chẳng hạn như ORDER_TYPE_BUY Offset: 0 // Hướng mở và đóng lệnh trong dữ liệu lệnh của tương lai tiền điện tử;ORDER_OFFSET_OPEN là vị trí mở, trong khi ORDER_OFFSET_CLOSE là hướng đóng ContractType : // Thuộc tính này là cho lệnh giao ngay, cụ thể là chuỗi không; Tài sản của lệnh tương lai là mã hợp đồng cụ thể }


##### MarketOrder

Market depth order, that is, ```exchange.GetDepth()``` returns the data structure of the elements in the **Bids** and **Asks** arrays in the data.

```javascript
{
    Price   : 1000,              // Price
    Amount  : 1                  // Volume
}
Độ sâu

Độ sâu thị trường được trả về bởi hàmexchange.GetDepth().

{
    Asks    : [...],             // The array of sell orders, namely MarketOrder array, sorted by price from low to high
    Bids    : [...],             // The array of buy orders, namely MarketOrder array, sorted by price from high to low
    Time    : 1567736576000      // Millisecond-level timestamp
}
Tài khoản

Thông tin tài khoản, được trả về bởi chức năngexchange.GetAccount()Dữ liệu được trả về trong cấu trúc liên quan đến các cặp giao dịch và mã hợp đồng được thiết lập hiện tại.

{
    Info            : {...},     // After requesting the platform interface, this attribute is not available in the raw data that the platform interface responds to, during the backtest
    Balance         : 1000,      // The available amount of quote currency; if the trading pair is BTC_USDT in the spot trading, "balance" refers to the current USDT amount. In the USDT-margined futures contract, "balance" refers to the available margin amount in USDT
    FrozenBalance   : 0,         // Here "balance" refers to the frozen amount of the assets for pending orders
    Stocks          : 1,         // The available amount of base currency; if the trading pair is BTC_USDT in the spot trading, "stocks" refers to the current BTC amount. In the crypto-margined futures contract, "stocks" refers to the available margin amount (base currency)
    FrozenStocks    : 0          // Here "stocks" refers to the frozen amount of the assets for pending orders
}
Vị trí

Đối với thông tin về các vị trí được nắm giữ trong giao dịch tương lai,mảngcủa nóPositioncấu trúc được trả về bởi hàmexchange.GetPosition() function.

{
    Info            : {...},     // After requesting the platform interface, this attribute is not available in the raw data that the platform interface responds to, during the backtest
    MarginLevel     : 10,        // The leverage size of positions; if this data is not provided by the platform interface, fill in the data by calculation, possibly with errors
    Amount          : 100,       // Position volume; the contract quantity of positions is normally positive integer. Notice every platform might have different contract specifications, such as contract multiplier and value, etc., so the rules for ordering might be different; for example, Binance contract might order by 0.1
    FrozenAmount    : 0,         // The quantity of frozen positions, used as the number of temporary position freeze when close positions and pending orders
    Price           : 10000,     // Average position price; in principle, the attribute is the average price of the entire position (which does not involve in the settlement); if the platform interface does not provide the data, use the existing average position price of the platform to fill in (which involves in the settlement)
    Profit          : 0,         // Position floating profit and loss, namely the failure of realizing position profit and loss. If the platform interface does not provide the data, use other profit and loss data from the interface to fill in; the unit of the profit and loss values is the same as the unit of the current contract margin 

    Type            : 0,         // PD_LONG is a long position, while PD_SHORT is a short position
    ContractType    : "quarter", // Contract code; for more details, refer to the transmitted parameters in the description of the function "SetContractType"
    Margin          : 1          // Margin occupied by positions; if the platform interface does not provide the data, use 0 to fill in
}

Đối với tương lai tiền điện tử, hãy chú ý đếnPositionMảng cấu trúc được trả về bởi hàmexchange.GetPosition()Đối với các thuộc tính trong cấu trúc dữ liệu vị trí của nó, nhưFrozenAmount, ProfitMargin, các định nghĩa dữ liệu khác nhau có thể được trả về bởi các đối tượng trao đổi khác nhau, khi họ gọiexchange.GetPosition()giao diện, cho các nền tảng khác nhau cung cấp dữ liệu khác nhau.FrozenAmountlà 0. Nếu cần tính toán một số dữ liệu, bạn có thể sử dụng dữ liệu nguồn trong thuộc tínhInfođể tính toán và phân tích.

Chức năng toàn cầu

Phiên bản

Version()trả về số phiên bản hiện tại của hệ thống; trả về giá trị: kiểu chuỗi.

Giấc ngủ ((Millisecond)

Sleep(Millisecond), chức năng ngủ, làm cho chương trình tạm dừng trong một khoảng thời gian. Giá trị tham số:Millisecondlà một loại số. Đơn vị tham số là millisecond, ví dụ:Sleep(1000)có nghĩa là ngủ một giây. Các hoạt động hỗ trợ với thời gian ngủ dưới 1 millisecond, chẳng hạn như cài đặtSleep (0.1). Các thông số tối thiểu được hỗ trợ là0.000001Một nanosecond bằng với1e-6 milliseconds.

Lưu ý: Khi bạn viết các chiến lược trongPythonngôn ngữ, chức năngSleep(Millisecond)không được khuyến cáo sử dụng chức năngtime.time(second)củatimethư việnPythonBởi vì khi sử dụng hàmtime.time(second)trong chiến lược, chương trình chiến lược sẽ thực sự chờ đợi trong một số giây nhất định (các tham sốsecondlà con số thứ hai của cài đặt tạm dừng), điều này sẽ dẫn đến một chiến lược rất chậm backtest.

IsVirtual ((()

IsVirtual(), để xác định xem nó có phải là một backtest mô phỏng. Trả về trạng thái backtest mô phỏngtrue, và robot thực sự trở lạifalse.

Bưu điện...

Mail(smtpServer, smtpUsername, smtpPassword, mailTo, title, body)là một chức năng gửi thư. Giá trị tham số: tất cả đều thuộc loại chuỗi. Giá trị trả về: loại bool;trueđược trả lại sau khi gửi thành công.smtpServerphục vụ cho hộp thư gửismtp; smtpUsernamelà tài khoản hộp thư;smtpPasswordlà mật khẩu STMP của hộp thư;mailTolà tài khoản hộp thư nhận;titlelà tiêu đề của thư được gửi;bodylà nội dung của thư được gửi, ví dụ:

function main(){
    Mail("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body")
}
def main():
    Mail("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body")
void main() {
    Mail("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body");
}
  • CácMail_Gohàm là một phiên bản không đồng bộ của hàmMail: Việc sử dụng của nó tương tự như chức năngexchange.Go.

    function main() {
        var r1 = Mail_Go("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body")
        var r2 = Mail_Go("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body")
        
        var ret1 = r1.wait()
        var ret2 = r2.wait()
        
        Log("ret1:", ret1)
        Log("ret2:", ret2)
    }
    
    # Not supported
    
    // Not supported
    

Lưu ý: Nếu bạn cần thay đổi cổng, bạn có thể thêm số cổng trong tham số đầu tiên trực tiếp, ví dụ:smtp.qq.com:587(QQmail), cổng đã sẵn sàng để thử nghiệm. Nếu xảy ra lỗi:unencrypted connection, bạn cần phải sửa đổi định dạng tham số củasmtpServertrong chức năngMailđến:ssl://xxxxx.com:xxxVí dụ, phương pháp SMTP ssl của QQmail:ssl://smtp.qq.com:465hoặcsmtp://xxxxx.com:xxx.

SetErrorFilter(...)

ErrorFilter(RegEx), lọc nhật ký lỗi. Giá trị tham số: loại chuỗi. Các lỗi phù hợp với biểu thức thông thường này sẽ không được tải lên hệ thống nhật ký, và nó có thể được gọi nhiều lần (lịch lọc sẽ không được ghi vào tệp cơ sở dữ liệu của ID bot tương ứng trong nhật ký / bot trong nội dung docker, để ngăn chặn việc mở rộng tệp cơ sở dữ liệu do báo cáo lỗi thường xuyên).

function main() {
    SetErrorFilter("502:|503:|tcp|character|unexpected|network|timeout|WSARecv|Connect|GetAddr|no such|reset|http|received|EOF|reused")
}
def main():
    SetErrorFilter("502:|503:|tcp|character|unexpected|network|timeout|WSARecv|Connect|GetAddr|no such|reset|http|received|EOF|reused")
void main() {
    SetErrorFilter("502:|503:|tcp|character|unexpected|network|timeout|WSARecv|Connect|GetAddr|no such|reset|http|received|EOF|reused");
}

lọc thông tin lỗi của giao diện:

function main() {
    // Randomly check a non-existent order with ID 123; intentionally make the interface report an error
    var order = exchange.GetOrder("123")
    Log(order)
    // Filter http502 errors and GetOrder interface errors; after set the error filter, the second time to call GetOrder no longer reports errors
    SetErrorFilter("502:|GetOrder")
    order = exchange.GetOrder("123")
    Log(order)
}
def main():
    order = exchange.GetOrder("123")
    Log(order)
    SetErrorFilter("502:|GetOrder")
    order = exchange.GetOrder("123")
    Log(order)
void main() {
    TId orderId;
    Order order = exchange.GetOrder(orderId);
    Log(order);
    SetErrorFilter("502:|GetOrder");
    order = exchange.GetOrder(orderId);
    Log(order);
}

GetPid ((()

GetPid()trả về ID quy trình bot. trả về giá trị: kiểu chuỗi.

function main(){
    var id = GetPid()
    Log(id)
}
def main():
    id = GetPid()
    Log(id)
void main() {
    auto id = GetPid();
    Log(id);
}

GetLastError()

GetLastError()lấy thông tin lỗi mới nhất; nói chung, nó không cần phải được sử dụng, bởi vì chương trình sẽ tải lên thông tin lỗi vào hệ thống nhật ký tự động.GetLastError(), bộ nhớ cache lỗi sẽ được xóa; khi nó được gọi lại, thông tin lỗi được ghi lại lần trước sẽ không được trả về.

function main(){
    // Because the order with ID number of 123 does not exist, an error is reported
    exchange.GetOrder("123")
    var error = GetLastError()
    Log(error)
}
def main():
    exchange.GetOrder("123")
    error = GetLastError()
    Log(error)
void main() {
    // The type of order ID: TId; so no string can be passed in, and we can trigger it by placing an order that does not meet the exchange specifications
    exchange.GetOrder(exchange.Buy(1, 1));
    auto error = GetLastError();
    Log(error);
}

GetCommand()

GetCommand()lấy lệnh tương tác (utf-8). Nó nhận lệnh được gửi bởi giao diện tương tác chiến lược và xóa bộ nhớ cache; nếu không có lệnh, nó trả về một chuỗi trống.button name: parameter; nếu không có tham số trong các điều khiển tương tác (ví dụ, điều khiển nút mà không có hộp đầu vào), lệnh là tên nút.

function main(){
    while(true) { 
        var cmd = GetCommand()
        if (cmd) { 
            Log(cmd)
        }
        Sleep(1000) 
    }
}
def main():
    while True:
        cmd = GetCommand()
        if cmd:
            Log(cmd)
        Sleep(1000)
void main() {
    while(true) {
        auto cmd = GetCommand();
        if(cmd != "") {
            Log(cmd);
        }
        Sleep(1000);
    }
}

Hệ thống cơ bản có một cấu trúc hàng đợi để ghi lại lệnh tương tác.GetCommand()được gọi, lệnh tương tác đầu tiên nhập vào hàng đợi sẽ được lấy ra (nếu không có lệnh tương tác, một chuỗi trống).

Ví dụ về sử dụng điều khiển tương tác; đặt điều khiển tương tác trên giao diện chỉnh sửa chiến lược:

img

Thiết kế các mã tương tác trong chiến lược:

function main() {
    while (true) {
        LogStatus(_D())
        var cmd = GetCommand()
        if (cmd) {
            Log("cmd:", cmd)    
            var arr = cmd.split(":")
            if (arr[0] == "buy") {
                Log("Buy, the control without quantity")
            } else if (arr[0] == "sell") {
                Log("Sell, the control with quantity: ", arr[1])
            } else {
                Log("Other controls trigger:", arr)
            }
        }
        Sleep(1000)
    } 
}
def main():
    while True:
        LogStatus(_D())
        cmd = GetCommand()
        if cmd:
            Log("cmd:", cmd)
            arr = cmd.split(":")
            if arr[0] == "buy":
                Log("Buy, the control without quantity")
            elif arr[0] == "sell":
                Log("Sell, the control with quantity:", arr[1])
            else:
                Log("Other controls trigger:", arr)
        Sleep(1000)
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
void split(const string& s,vector<string>& sv,const char flag = ' ') {
    sv.clear();
    istringstream iss(s);
    string temp;

    while (getline(iss, temp, flag)) {
        sv.push_back(temp);
    }
    return;
}

void main() {
    while(true) {
        LogStatus(_D());
        auto cmd = GetCommand();
        if (cmd != "") {
            vector<string> arr;
            split(cmd, arr, ':');
            if(arr[0] == "buy") {
                Log("Buy, the control without quantity");
            } else if (arr[0] == "sell") {
                Log("Sell, the control with quantity:", arr[1]);
            } else {
                Log("Other controls trigger:", arr);
            }
        }
        Sleep(1000);
    }
}

GetMeta()

Chức năngGetMeta()trả về giá trị củaMetađược viết khi mã thông báo chiến lược được tạo ra, giá trị trả về của hàm là kiểu chuỗi. Ứng dụng: ví dụ, chiến lược cần phải làm cho tài sản giới hạn cho người thuê khác nhau. Lưu ý: khi mã thông báo chiến lược được tạo ra, độ dài củaMetakhông thể vượt quá 190 chuỗi; chức năng, chỉ áp dụng cho giao dịch thực tế và yêu cầu docker mới nhất. Nếu dữ liệu nguồn không được đặt khi mã thông báo chiến lược được tạo,GetMeta()trả về null.

Thông tin liên quan được chứng minh bằng các ứng dụng

function main() {
    // The largest assets value of quote currency allowed by the strategy
    
    // Get the metadata generated when the strategy token is established
    var level = GetMeta()
    
    // Check the corresponding conditions of "Meta"
    if (level == "level1") {
        // "-1" indicates no limitation 
        maxBaseCurrency = -1       
    } else if (level == "level2") {
        maxBaseCurrency = 10     
    } else if (level == "level3") {
        maxBaseCurrency = 1
    } else {
        maxBaseCurrency = 0.5
    }
    
    while(1) {
        Sleep(1000)
        var ticker = exchange.GetTicker()
        
        // Check the assets value
        var acc = exchange.GetAccount()
        if (maxBaseCurrency != -1 && maxBaseCurrency < acc.Stocks + acc.FrozenStocks) {
            // Stop the execution of the strategy trading logic 
            LogStatus(_D(), "level:", level, "The position exceeds the strategy token's using limitation, and stop the execution of the strategy trading logic!")
            continue
        }
        
        // Other trading logic
        
        // Export the information of status bar normally
        LogStatus(_D(), "level:", level, "The strategy runs normally! Ticker data: \n", ticker)
    }
}
def main():
    maxBaseCurrency = null
    level = GetMeta()
    
    if level == "level1":
        maxBaseCurrency = -1       
    elif level == "level2":
        maxBaseCurrency = 10     
    elif level == "level3":
        maxBaseCurrency = 1
    else:
        maxBaseCurrency = 0.5
    
    while True:
        Sleep(1000)
        ticker = exchange.GetTicker()        
        acc = exchange.GetAccount()
        if maxBaseCurrency != -1 and maxBaseCurrency < acc["Stocks"] + acc["FrozenStocks"]:
            LogStatus(_D(), "level:", level, "The position exceeds the strategy token's using limitation, and stop the execution of the strategy trading logic!")
            continue        
        
        # Other trading logic
        
        # Export the information of status bar normally
        LogStatus(_D(), "level:", level, "The strategy runs normally! Ticker data: \n", ticker)
void main() {
    auto maxBaseCurrency = 0.0;
    auto level = GetMeta();
    
    if (level == "level1") {
        maxBaseCurrency = -1;  
    } else if (level == "level2") {
        maxBaseCurrency = 10;
    } else if (level == "level3") {
        maxBaseCurrency = 1;
    } else {
        maxBaseCurrency = 0.5;
    }
    
    while(1) {
        Sleep(1000);
        auto ticker = exchange.GetTicker();  
        auto acc = exchange.GetAccount();
        if (maxBaseCurrency != -1 && maxBaseCurrency < acc.Stocks + acc.FrozenStocks) {
            // Stop the execution of the strategy trading logic
            LogStatus(_D(), "level:", level, "The position exceeds the strategy token's using limitation, and stop the execution of the strategy trading logic!");
            continue;
        }
        
        // Other trading logic
        
        // Export the information of status bar normally
        LogStatus(_D(), "level:", level, "The strategy runs normally! Ticker data: \n", ticker);
    }
}

Nhập số...

Dial(Address, Timeout), truy cập ổ cắm gốc, hỗ trợtcp, udp, tlsunixGiá trị tham số:Addresslà một kiểu chuỗi; đơn vị là thứ hai; nếu thời gian ra, hàmDial(...)trả về một giá trị trống.

Mô tả chi tiết vềAddresstham số:

Chi tiết thông số
Các thông số để thiết lập chức năngDial Phân biệt bằng cách thêm|ký hiệu sau địa chỉ thông thường:wss://ws.okx.com:8443/ws/v5/public; nếu có|ký tự trong chuỗi tham số, sử dụng||Kết nối mỗi tham số với&Ví dụ, các tham số thay thế và nén ss5 được đặt cùng nhau:Dial("wss://ws.okx.com:8443/ws/v5/public|proxy=socks5://xxx:9999&compress=gzip_raw&mode=recv").
Trong giao thức ws, các tham số liên quan của nén dữ liệu:compress=parameter value nén là phương pháp nén; các thông số nén có thể được chọn từgzip_rawgzip, v.v. Nếu phương thức gzip là gzip không chuẩn, bạn có thể sử dụng phương thức mở rộng:gzip_raw, đó là, thêm cài đặtcompress=gzip_rawsau bộ tách|, và sử dụng&biểu tượng và tham số chế độ tiếp theo để tách.
Trong giao thức ws, các tham số liên quan của nén dữ liệu:mode=parameter value chế độ là chế độ, bao gồm ba tùy chọn, cụ thể làdual, sendrecv. duallà hai chiều, gửi và nhận dữ liệu nén.sendlà gửi dữ liệu nén.recvlà nhận dữ liệu nén và giải nén nó tại địa phương.
Các thông số liên quan để cài đặt vớ5 thay thế:proxy=parameter value proxy là cài đặt proxy ss5; định dạng giá trị tham số:socks5://name:pwd@192.168.0.1:1080; name là tên người dùng máy chủ ss5; pwd là mật khẩu đăng nhập máy chủ ss5; 1080 là cổng của máy chủ ss5
Trong giao thức ws, các thông số liên quan để thiết lập tự động kết nối lại cơ bản:reconnect=parameter value reconnect có nghĩa là thiết lập reconnect hay không;reconnect=truelà gọi kết nối lại; cài đặt mặc định là không kết nối lại.
Trong giao thức ws, các thông số liên quan để thiết lập tự động kết nối lại cơ bản:interval=parameter value Interval là khoảng thời gian thử lại bằng millisecond,interval=10000là khoảng thời gian thử lại 10 giây, và cài đặt mặc định là 1 giây, tức là,interval=1000.
Trong giao thức ws, các thông số liên quan để thiết lập tự động kết nối lại cơ bản:payload= parameter value Lượng hữu ích là thông báo đăng ký được gửi khi ws kết nối lại, ví dụ:payload=okok.
function main(){
    // Dial supports tcp://, udp://, tls://, unix:// protocol, so you can add a parameter to specify the number of seconds to timeout
    var client = Dial("tls://www.baidu.com:443")  
    if (client) {
        // "Write" can be followed by a numeric parameter to specify the timeout, and "write" returns the number of bytes successfully sent
        client.write("GET / HTTP/1.1\nConnection: Closed\n\n")
        while (true) {
            // "Read" can be followed by a numeric parameter to specify the timeout, in millisecond. Return null to indicate error, timeout or closed socket
            var buf = client.read()
            if (!buf) {
                 break
            }
            Log(buf)
        }
        client.close()
    }
}
def main():
    client = Dial("tls://www.baidu.com:443")
    if client:
        client.write("GET / HTTP/1.1\nConnection: Closed\n\n")
        while True:
            buf = client.read()
            if not buf:
                break
            Log(buf)
        client.close()
void main() {
    auto client = Dial("tls://www.baidu.com:443");
    if(client.Valid) {
        client.write("GET / HTTP/1.1\nConnection: Closed\n\n");
        while(true) {
            auto buf = client.read();
            if(buf == "") {
                break;
            }
            Log(buf);
        }
        client.close();
    }
}

Chức năngreadhỗ trợ các thông số sau:

  • Khi không có tham số được truyền, nó chặn cho đến khi có một thông báo, chẳng hạn nhưws.read().
  • Khi truyền các tham số, chỉ định thời gian hết hạn cho các thông báo chờ trong đơn vị millisecond; ví dụ:ws.read(2000)chỉ định thời gian nghỉ là hai giây (2000 millisecond).
  • Hai thông số sau đây chỉ có giá trị chowebsocket: Đưa thông số-1có nghĩa là quay trở lại ngay lập tức bất kể có bất kỳ thông báo nào, chẳng hạn nhưws.read(-1). Đưa thông số-2có nghĩa là trả về ngay lập tức bất kể có bất kỳ tin nhắn nào, nhưng chỉ có tin nhắn mới nhất được trả về, và tin nhắn trong bộ đệm sẽ bị loại bỏ, chẳng hạn nhưws.read(-2).

Chức năngread()mô tả bộ đệm: Nếu dữ liệu được đẩy bởi giao thức ws là khoảng thời gian dài giữa các chiến lượcread()cấu trúc dữ liệu của bộ đệm là một hàng đợi, với giới hạn trên của 2000. sau khi vượt quá 2000, dữ liệu mới nhất được nhập vào bộ đệm, và dữ liệu cũ nhất được xóa.

Các kịch bản \ReadParameter chức năng Không có tham số Parameter: -1 Parameter: -2 Parameter: 2000 (đơn vị: ms)
Buffer đã có dữ liệu Trả lại dữ liệu cũ nhất ngay lập tức Trả lại dữ liệu cũ nhất ngay lập tức Trả lại dữ liệu mới nhất ngay. Trả lại dữ liệu cũ nhất ngay lập tức
Không có dữ liệu trong bộ đệm Trả lại dữ liệu khi có dữ liệu bị chặn Trả về null ngay lập tức Trả về null ngay lập tức Chờ cho 2000ms, trả về null nếu không có dữ liệu, trả lại dữ liệu nếu có dữ liệu
Ws kết nối được ngắt kết nối hoặc lớp dưới được kết nối lại Chức năng read() trả về null, đó là: , và chức năng write() trả về 0. Nếu tình huống này được phát hiện, chức năng close() có thể được sử dụng để đóng kết nối. Nếu thiết lập kết nối lại tự động, nó sẽ không cần phải đóng, và lớp dưới cùng của hệ thống sẽ tự động kết nối lại.
  • Hỗ trợ giao thức wss (WebSocket) Truy cập giao diện thị trường websocket Binance:

    function main() {
        LogStatus("connecting...")
        // Access Binance websocket interface
        var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")
        if (!client) {
            Log("connection failed, program exited")
            return
        }
        
        while (true) {
            // "read" only returns the obtained data after call "read" 
            var buf = client.read()      
            if (!buf) {
                break
            }
            var table = {
                type: 'table',
                title: 'Quote Chart',
                cols: ['Currency', 'Highest', 'Lowest', 'Buy One', 'Sell One', 'Last Executed Price', 'Volume', 'Update Time'],
                rows: []
            }
            var obj = JSON.parse(buf)
            _.each(obj, function(ticker) {
                table.rows.push([ticker.s, ticker.h, ticker.l, ticker.b, ticker.a, ticker.c, ticker.q, _D(ticker.E)])
            })
            LogStatus('`' + JSON.stringify(table) + '`')
        }
        client.close()
    }
    
    import json
    def main():
        LogStatus("connecting...")
        client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")
        if not client:
            Log("Connection failed, program exited")
            return 
        
        while True:
            buf = client.read()
            if not buf:
                break
            table = {
                "type" : "table", 
                "title" : "Quote Chart", 
                "cols" : ['Currency', 'Highest', 'Lowest', 'Buy One', 'Sell One', 'Last Executed Price', 'Volume', 'Update Time'], 
                "rows" : [] 
            }
            obj = json.loads(buf)
            for i in range(len(obj)):
                table["rows"].append([obj[i]["s"], obj[i]["h"], obj[i]["l"], obj[i]["b"], obj[i]["a"], obj[i]["c"], obj[i]["q"], _D(int(obj[i]["E"]))])
            LogStatus('`' + json.dumps(table) + '`')
        client.close()
    
    void main() {
        LogStatus("connecting...");
        auto client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr");
        if(!client.Valid) {
            Log("Connection failed, program exited");
            return;
        }
        
        while(true) {
            auto buf = client.read();
            if(buf == "") {
                break;
            }
            json table = R"({
                "type" : "table", 
                "title" : "Quote Chart", 
                "cols" : ['Currency', 'Highest', 'Lowest', 'Buy One', 'Sell One', 'Last Executed Price', 'Volume', 'Update Time'], 
                "rows" : []
            })"_json;
            json obj = json::parse(buf);
            for(auto& ele : obj.items()) {
                table["rows"].push_back({ele.value()["s"], ele.value()["h"], ele.value()["l"], ele.value()["b"], ele.value()["a"], ele.value()["c"], 
                    ele.value()["q"], _D(ele.value()["E"])});
            }
            LogStatus("`" + table.dump() + "`");
        }
        client.close();
    }
    

    Truy cập OKX giao diện thị trường websocket

    var ws = null 
    function main(){
          var param = {
            "op": "subscribe",
            "args": [{
                "channel": "tickers",
                "instId": "BTC-USDT"
            }]
        }
        // When call the function "Dial", specify "reconnect=true" and set to reconnect; specify "payload" as the message to be sent when reconnect. When websocket closes the connection, it will automatically reconnect and send the message
        ws = Dial("wss://ws.okx.com:8443/ws/v5/public|compress=gzip_raw&mode=recv&reconnect=true&payload="+ JSON.stringify(param))
        if(ws){
            ws.write(JSON.stringify(param))
            var pingCyc = 1000 * 20
            var lastPingTime = new Date().getTime()
            while(true){
                var nowTime = new Date().getTime()
                var ret = ws.read()
                Log("ret:", ret)
                if(nowTime - lastPingTime > pingCyc){
                    var retPing = ws.write("ping")
                    lastPingTime = nowTime
                    Log("send: ping", "#FF0000")
                }
                LogStatus("current time:", _D())
                Sleep(1000)
            }
        }
    }
    
    function onexit() {
        ws.close() 
        Log("exit")
    }
    
    import json
    import time
    
    ws = None
    def main():
        global ws 
        param = {
            "op": "subscribe",
            "args": [{
                "channel": "tickers",
                "instId": "BTC-USDT"
            }]
        }
        ws = Dial("wss://ws.okx.com:8443/ws/v5/public|compress=gzip_raw&mode=recv&reconnect=true&payload=" + json.dumps(param))
        if ws:
            pingCyc = 1000 * 20
            lastPingTime = time.time() * 1000
            while True:
                nowTime = time.time() * 1000
                ret = ws.read()
                Log("ret:", ret)
                if nowTime - lastPingTime > pingCyc:
                    retPing = ws.write("ping")
                    lastPingTime = nowTime
                    Log("send: ping", "#FF0000")
                LogStatus("current time:", _D())
                Sleep(1000)
    
    def onexit():
        ws.close()
        Log("exit")
    
    auto objWS = Dial("wss://ws.okx.com:8443/ws/v5/public|compress=gzip_raw&mode=recv&reconnect=true");  
    
    void main() {
            json param = R"({"op": "subscribe", "args": ["spot/ticker:ETH-USDT"]})"_json;
             "op": "subscribe",
            "args": [{
                "channel": "tickers",
                "instId": "BTC-USDT"
            }]
        })"_json;
        
        objWS.write(param.dump());
        if(objWS.Valid) {
            uint64_t pingCyc = 1000 * 20;
            uint64_t lastPingTime = Unix() * 1000;
            while(true) {
                uint64_t nowTime = Unix() * 1000;
                auto ret = objWS.read();
                Log("ret:", ret);
                if(nowTime - lastPingTime > pingCyc) {
                    auto retPing = objWS.write("ping");
                    lastPingTime = nowTime;
                    Log("send: ping", "#FF0000");
                }
                LogStatus("current time:", _D());
                Sleep(1000);
            }
        }
    }  
    
    void onexit() {
        objWS.close();
        Log("exit");
    }
    

    Truy cập giao diện thị trường websocket Huobi:

    var ws = null   
    
    function main(){
        var param = {"sub": "market.btcusdt.detail", "id": "id1"}
        ws = Dial("wss://api.huobi.pro/ws|compress=gzip&mode=recv&reconnect=true&payload="+ JSON.stringify(param))
        if(ws){
            while(1){
                var ret = ws.read()
                Log("ret:", ret)
                // Respond to heartbeat
                try {
                    var jsonRet = JSON.parse(ret)
                    if(typeof(jsonRet.ping) == "number") {
                        var strPong = JSON.stringify({"pong" : jsonRet.ping})
                        ws.write(strPong)
                        Log("respond ping, send pong:", strPong, "#FF0000")
                    }
                } catch(e) {
                    Log("e.name:", e.name, "e.stack:", e.stack, "e.message:", e.message)
                }
                
                LogStatus("current time:", _D())
                Sleep(1000)
            }
        }
    }  
    
    function onexit() {
        ws.close() 
        Log("execute function ws.close()")
    }
    
    import json
    ws = None  
    
    def main():
        global ws
        param = {"sub" : "market.btcusdt.detail", "id" : "id1"}
        ws = Dial("wss://api.huobi.pro/ws|compress=gzip&mode=recv&reconnect=true&payload=" + json.dumps(param))
        if ws:
            while True:
                ret = ws.read()
                Log("ret:", ret)              
                # Respond to heartbeat 
                try:
                    jsonRet = json.loads(ret)
                    if "ping" in jsonRet and type(jsonRet["ping"]) == int:
                        strPong = json.dumps({"pong" : jsonRet["ping"]})
                        ws.write(strPong)
                        Log("respond ping, send pong:", strPong, "#FF0000")
                except Exception as e:
                    Log("e:", e)
                    
                LogStatus("current time: ", _D())
                Sleep(1000)
        
    def onexit():
        ws.close()
        Log("execute function ws.close()")  
    
    using namespace std;
    void main() {
        json param = R"({"sub" : "market.btcusdt.detail", "id" : "id1"})"_json;
        auto ws = Dial("wss://api.huobi.pro/ws|compress=gzip&mode=recv&reconnect=true&payload=" + param.dump());
        if(ws.Valid) {
            while(true) {
                auto ret = ws.read();
                Log("ret:", ret);              
                // Respond to heartbeat
                try 
                {
                    auto jsonRet = json::parse(ret);
                    if(jsonRet["ping"].is_number()) {
                        json pong = R"({"pong" : 0})"_json;
                        pong["pong"] = jsonRet["ping"];
                        auto strPong = pong.dump();
                        ws.write(strPong);
                        Log("respond ping, send pong:", strPong, "#FF0000");
                    }
                } catch(exception &e) 
                {
                    Log("e:", e.what());
                }
                
                LogStatus("current time:", _D());
                Sleep(1000);
            }
        }
    }  
    
    void onexit() {
        // ws.close();
        Log("execute function ws.close()");
    }
    

    Giao diện xác minh giao diện websocket truy cập OKX:

      function getLogin(pAccessKey, pSecretKey, pPassphrase) {
        // Signature function for login
        var ts = (new Date().getTime() / 1000).toString()
        var login = {
            "op": "login",
            "args":[{
                "apiKey"    : pAccessKey,
                "passphrase" : pPassphrase,
                "timestamp" : ts,
                "sign" : exchange.HMAC("sha256", "base64", ts + "GET" + "/users/self/verify", pSecretKey)
            }]
        }    
        return login
    }    
    
    var client_private = null 
    function main() {
        // Because the read function adopts the timeout setting, the timeout error is filtered, otherwise there will be redundant error output
        SetErrorFilter("timeout")
        
        // Position channel subscription information
        var posSubscribe = {
            "op": "subscribe",
            "args": [{
                "channel": "positions",
                "instType": "ANY"
            }]
        }    
    
        var accessKey = "xxx"
        var secretKey = "xxx"
        var passphrase = "xxx"
    
        client_private = Dial("wss://ws.okx.com:8443/ws/v5/private")
        client_private.write(JSON.stringify(getLogin(accessKey, secretKey, passphrase)))
        Sleep(3000)  // When logging in, we cannot subscribe to private channels immediately, we need to wait for server response
        client_private.write(JSON.stringify(posSubscribe))
        if (client_private) {
            var lastPingTS = new Date().getTime()
            while (true) {
                var buf = client_private.read(-1)
                if (buf) {
                    Log(buf)
                }
                
                // Detect disconnection, reconnect
                if (buf == "" && client_private.write(JSON.stringify(posSubscribe)) == 0) {
                    Log("Disconnection detected, connection closed, reconnect")
                    client_private.close()
                    client_private = Dial("wss://ws.okx.com:8443/ws/v5/private")
                    client_private.write(JSON.stringify(getLogin(accessKey, secretKey, passphrase)))
                    Sleep(3000)
                    client_private.write(JSON.stringify(posSubscribe))
                }
                
                // Send heartbeat packets
                var nowPingTS = new Date().getTime()
                if (nowPingTS - lastPingTS > 10 * 1000) {
                    client_private.write("ping")
                    lastPingTS = nowPingTS
                }            
            }        
        }
    }    
    
    function onexit() {    
        var ret = client_private.close()
        Log("Close the connection!", ret)
    }
    
    import json
    import time
        
    def getLogin(pAccessKey, pSecretKey, pPassphrase):
        ts = str(time.time())
        login = {
            "op": "login",
            "args":[{
                "apiKey"    : pAccessKey,
                "passphrase" : pPassphrase,
                "timestamp" : ts,
                "sign" : exchange.HMAC("sha256", "base64", ts + "GET" + "/users/self/verify", pSecretKey)
            }]
        }
        return login     
    
    client_private = None 
    def main():
        global client_private
        SetErrorFilter("timeout")
        
        posSubscribe = {
            "op": "subscribe",
            "args": [{
                "channel": "positions",
                "instType": "ANY"
            }]
        }      
    
        accessKey = "xxx"
        secretKey = "xxx"
        passphrase = "xxx"
        
        client_private = Dial("wss://ws.okx.com:8443/ws/v5/private")
        client_private.write(json.dumps(getLogin(accessKey, secretKey, passphrase)))
        Sleep(3000)
        client_private.write(json.dumps(posSubscribe))
        if client_private:
            lastPingTS = time.time() * 1000
            while True:
                buf = client_private.read(-1)
                if buf:
                    Log(buf)
                
                if buf == "" and client_private.write(json.dumps(posSubscribe)) == 0:
                    Log("Disconnection detected, connection closed, reconnect")
                    ret = client_private.close()
                    client_private = Dial("wss://ws.okx.com:8443/ws/v5/private")
                    client_private.write(json.dumps(getLogin(accessKey, secretKey, passphrase)))
                    Sleep(3000)
                    client_private.write(json.dumps(posSubscribe))
                
                nowPingTS = time.time() * 1000
                if nowPingTS - lastPingTS > 10 * 1000:
                    client_private.write("ping")
                    lastPingTS = nowPingTS    
    
    def onexit():
        ret = client_private.close()
        Log("Close the connection!", ret)
    

auto client_private = Dial ((wss://ws.okx.com:8443/ws/v5/private);

json getLogin ((string pAccessKey, string pSecretKey, string pPassphrase) { tự động ts = std::to_string(Unix()); json login = R"({ op: login args: [{ apiKey: phrase mật khẩu: , thời gian: , dấu hiệu: ♪ }) "_json; login[args][0][apiKey] = pAccessKey; login[args][0][passphrase] = pPassphrase login[args][0][timestamp] = ts; login[args][0][sign] = exchange.HMAC(sha256, base64, ts + GET + /users/self/verify, pSecretKey); trả lại đăng nhập; }

Không có chính SetErrorFilter ((timeout); Json posSubscribe = R"({ op: đăng ký, args: [{ kênh: vị trí, instType: any ♪ }) "_json;

auto accessKey = "xxx";
auto secretKey = "xxx";
auto passphrase = "xxx";

client_private.write(getLogin(accessKey, secretKey, passphrase).dump());
Sleep(3000);
client_private.write(posSubscribe.dump());  

if (client_private.Valid) {
    uint64_t lastPingTS = Unix() * 1000;    

    while (true) {
        auto buf = client_private.read(-1);
        if (buf != "") {
            Log(buf);
        }
        if (buf == "") {
            if (client_private.write(posSubscribe.dump()) == 0) {
                Log("Disconnection detected, connection closed, reconnect");
                client_private.close();
                client_private = Dial("wss://ws.okx.com:8443/ws/v5/private");
                client_private.write(getLogin(accessKey, secretKey, passphrase).dump());
                Sleep(3000);
                client_private.write(posSubscribe.dump());
            }
        }
        
        uint64_t nowPingTS = Unix() * 1000;
        if (nowPingTS - lastPingTS > 10 * 1000) {
            client_private.write("ping");
            lastPingTS = nowPingTS;
        }
    }
}

}

không hợp lệ. client_private.close ((); Đăng ký (đăng ký xuất cảnh); }


#### HttpQuery(...)

```HttpQuery(Url, PostData, Cookies, Headers, IsReturnHeader)``` is an access of web URL. Parameter value: all are of string types.

Note:
* The ```HttpQuery(...)``` function only supports ```JavaScript``` language.
* For the ```Python``` language, you can use ```urllib``` to send http requests directly.

```HttpQuery(...)``` is mainly used to access the exchange interfaces that do not require signatures, such as public interfaces including market information.
An example of an API that does not require a signature to access OKX: the return value is a ```JSON``` string, which can be parsed by using the function ```JSON.parse()``` in JavaScript language strategies.

```js
function main(){
  // An example of GET access without parameters
  var info = JSON.parse(HttpQuery("https://www.okx.com/api/v5/public/time"))
  Log(info)
  // An example of GET access with parameters
  var ticker = JSON.parse(HttpQuery("https://www.okx.com/api/v5/market/books?instId=BTC-USDT"))
  Log(ticker)
}
import json
import urllib.request
def main():
    # HttpQuery does not support Python, you can use urllib/urllib2 instead
    info = json.loads(urllib.request.urlopen("https://www.okx.com/api/v5/public/time").read().decode('utf-8'))
    Log(info)
    ticker = json.loads(urllib.request.urlopen("https://www.okx.com/api/v5/market/books?instId=BTC-USDT").read().decode('utf-8'))
    Log(ticker)
void main() {
    auto info = json::parse(HttpQuery("https://www.okx.com/api/v5/public/time"));
    Log(info);
    auto ticker = json::parse(HttpQuery("https://www.okx.com/api/v5/market/books?instId=BTC-USDT"));
    Log(ticker);
}

Để có được nội dung trả về của một URL, nếu tham số thứ haiPostDatalà ở dạng chuỗia=1&b=2&c=abc, đệ trình bởiPOST, những người khác bởiPUT; tham số củaPostData{method:'PUT', data:'a=1&b=2&c=abc'}.

CácPostDatatham số cũng có thể là mộtJSON string.

Định dạng của tham sốCookieslà:a=10; b=20; với mỗi tham số được tách bằng dấu chấm chấm;. Định dạng của tham sốHeaderslà:User-Agent: Mobile\nContent-Type: text/html; với mỗi tham số được tách bởi một ký tự dòng mới\n.

Các thông số thứ hai,PostData, có thể được tùy chỉnh, ví dụ:HttpQuery("http://www.abc.com", {method:'PUT', data:'a=1&b=2&c=abc'}); lưu ý: nếu bạn cần thiết lập thời gian nghỉ choHttpQuerychức năng, bạn có thể thêmtimeoutthuộc tính trong{method:'put',data:'a=1&B=2&C=ABC'}(mặc định là 60 giây).

Thiết lập thời gian nghỉ 1 giây:HttpQuery("http://www.abc.com", {method:'PUT', data:'a=1&b=2&c=abc', timeout:1000})

Các tham số thứ ba là cần thiết để vượt qua chuỗiCookie, nhưngPOSTkhông cần thiết để thiết lập tham số thứ hai thành null. Trong thử nghiệm mô phỏng, vì URL không thể mô phỏng, hàm trả về một chuỗi cố địnhDummy DataBạn có thể sử dụng giao diện này để gửi tin nhắn văn bản hoặc tương tác với các giao diện API khác.

GETVí dụ gọi phương thức:HttpQuery("http://www.baidu.com"). POSTVí dụ gọi phương thức:HttpQuery("http://www.163.com", "a=1&b=2&c=abc").

Ví dụ triệu hồi trả vềHeader:

HttpQuery("http://www.baidu.com", null, "a=10; b=20", "User-Agent: Mobile\nContent-Type: text/html", true)  // will return {Header: HTTP Header, Body: HTML}
  • Chức năngHttpQuerysử dụng cài đặt proxy:

    function main() {
        // This time, set proxy and send http request; without username and password, this http request will be sent through the proxy
        HttpQuery("socks5://127.0.0.1:8889/http://www.baidu.com/")
    
        // Set the proxy and send http request this time, enter the user name and password, only the current call of HttpQuery takes effect, then call HttpQuery ("http://www.baidu.com") again so that the proxy will not be used
        HttpQuery("socks5://username:password@127.0.0.1:8889/http://www.baidu.com/")
    }
    
    # If HttpQuery does not support Python, you can use Python urllib2 library
    
    void main() {
        HttpQuery("socks5://127.0.0.1:8889/http://www.baidu.com/");
        HttpQuery("socks5://username:password@127.0.0.1:8889/http://www.baidu.com/");
    }
    
  • Chức năngHttpQuerylà phiên bản không đồng bộHttpQuery_Go: Phương pháp sử dụng tương tự như chức năngexchange.Go, chẳng hạn như truy cập giao diện công khai của sàn giao dịch không đồng bộ để có được dữ liệu thị trường tổng hợp.

    function main() {
        // Set up the first asyncthread
        var r1 = HttpQuery_Go("https://www.okx.com/api/v5/market/tickers?instType=SPOT")
        // Set up the second asyncthread
        var r2 = HttpQuery_Go("https://api.huobi.pro/market/tickers")
        
        // Get the return value of the first asyncthread
        var tickers1 = r1.wait()
        // Get the return value of the second asyncthread
        var tickers2 = r2.wait()
        
        // Print result
        Log("tickers1:", tickers1)
        Log("tickers2:", tickers2)
    }
    
    # Not supported
    
    // Not supported
    
  • Việc sử dụng chức năngHttpQuery(...)trong hệ thống backtest: Dữ liệu có thể được thu thập bằng cách sử dụngHttpQuery(...)để gửi yêu cầu (chỉ hỗ trợGETMột giới hạn 20 lần được áp dụng trong backtest vàHttpQuery(...)truy cập sẽ lưu trữ dữ liệu, trong khi chức năngHttpQuery(...)trả về dữ liệu được lưu trong bộ nhớ cache trên lần truy cập thứ hai đến cùng một URL (không có yêu cầu web thực tế nữa).

    Chúng ta có thể chạy một chương trình dịch vụ trên một máy chủ hoặc một thiết bị đáp ứng các yêu cầu được gửi bởiHttpQuery(...)trong chương trình chiến lược, và chương trình dịch vụ trong ngôn ngữ Go để thử nghiệm được hiển thị như sau:

    package main
    import (
        "fmt"
        "net/http"
        "encoding/json"
    )
    
    func Handle (w http.ResponseWriter, r *http.Request) {
        defer func() {
            fmt.Println("req:", *r)
            ret := map[string]interface{}{
                "schema" : []string{"time","open","high","low","close","vol"},
                "data" : []interface{}{
                    []int64{1564315200000,9531300,9531300,9497060,9497060,787},
                    []int64{1564316100000,9495160,9495160,9474260,9489460,338},
                },
            }
            b, _ := json.Marshal(ret)
            w.Write(b)
        }()
    }
    
    func main () {
        fmt.Println("listen http://localhost:9090")
        http.HandleFunc("/data", Handle)
        http.ListenAndServe(":9090", nil)
    }
    

    Sử dụng hàmHttpQuery(...)để gửi yêu cầu trong quá trình kiểm tra lại chiến lược:

    function main() {
        // You can write the IP address of the device where the service program is run
        Log(HttpQuery("http://xxx.xx.x.xxx:9090/data?msg=hello"));
        Log(exchange.GetAccount());
    }
    
    # If HttpQuery does not support Python, you can use Python urllib2 library
    
    void main() {
        //  You can write the IP address of the device where the service program is run
        Log(HttpQuery("http://xxx.xx.x.xxx:9090/data?msg=hello"));
        Log(exchange.GetAccount());
    }
    

    img

    Nó hỗ trợ chuyển mã dữ liệu phản hồi trong yêu cầu, và nó cũng hỗ trợ mã hóa chung. Xác địnhPostDatatham số:{method: "GET", charset: "GB18030"}có thể thực hiện chuyển mã dữ liệu phản hồi (GB18030).

Mã hóa...

Encode(algo, inputFormat, outputFormat, data, keyFormat, key string), hàm mã hóa dữ liệu theo các tham số được truyền và trả về một giá trị chuỗi.

Các thông sốalgolà thuật toán được sử dụng để tính toán mã hóa, có thể được đặt thành: raw (không có thuật toán), sign, signTx, md4, md5, sha256, sha512, sha1, keccak256, sha3.224, sha3.256, sha3.384, sha3.512, sha3.keccak256, sha3.keccak512, sha512.384, sha512.256, sha512.224, emd160, blake2rip2b.256, blake2b.512, blake2s.1288, blake2s.256datalà dữ liệu được xử lý.inputFormat/outputFormat/keyFormatCác tham số hỗ trợ các phương pháp mã hóa như:raw, hex, base64string. NếukeyFormattham số không trống, cáckeytham số được sử dụng cho mã hóa (HMAC), nếu không mặc địnhkeykhi `` `alg