Удостоверение ордера на торговлю Цена: 1000, // Цена размещения ордера; обратите внимание, что этот атрибут рыночных ордеров может быть 0 или -1 Сумма: 10, // Сумма размещения ордера; обратите внимание, что этот атрибут рыночных ордеров может быть суммой денег, а не номером монеты DealAmount : 10, // Исполненный объем; если интерфейс платформы не предоставляет такого рода данные, вероятно, используйте 0 для заполнения Средняя цена: 1000, // Средняя цена исполнения; обратите внимание, что некоторые платформы не предоставляют эти данные. Статус: 1, // Статус заказа; ссылка на статус заказа в константах, например ORDER_STATE_CLOSED Тип: 0, // Тип заказа; укажите тип заказа в константах, например ORDER_TYPE_BUY Оффсет: 0 // направление открытия и закрытия ордера в данных ордера криптовалютных фьючерсов;ORDER_OFFSET_OPEN - это открытая позиция, а ORDER_OFFSET_CLOSE - направление закрытия ContractType : // Этот атрибут для спотовых ордеров, а именно нулевой строки; свойство фьючерсного ордера - это код конкретного контракта Я не знаю.


##### 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
}
Глубина

Глубина рынка возвращается функциейexchange.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
}
Счет

Информация о счете, возвращаемая функциейexchange.GetAccount()Данные, возвращаемые в структуру, относятся к в настоящее время установленным торговым парам и кодам контрактов.

{
    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
}
Положение

Для получения информации о позициях, удерживаемых в торговле фьючерсами,массивиз этогоPositionструктура возвращается функциейexchange.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
}

Для криптовалютных фьючерсов обратите внимание наPositionмассив структуры, возвращаемый функциейexchange.GetPosition()Что касается атрибутов в его структуре данных положения, такие какFrozenAmount, ProfitиMargin, различные определения данных могут быть возвращены различными объектами обмена, когда они вызываютexchange.GetPosition()Например, некоторые биржи не включают позиции замороженные данные, которые указывают,FrozenAmountЕсли вам нужно вычислить некоторые данные, вы можете использовать исходные данные в атрибутеInfoдля расчета и анализа.

Глобальные функции

Версия ((()

Version()возвращает номер текущей версии системы; возвращается значение: тип строки.

Сон ((миллисекунда)

Sleep(Millisecond), функция сна, заставляет программу остановиться на некоторое время.Millisecondявляется типом числа. Единицей параметра является миллисекунда, например:Sleep(1000)означает спать одну секунду. Операции поддержки с длительностью сна менее 1 миллисекунды, такие как установкаSleep (0.1). Минимальный поддерживаемый параметр0.000001Одна наносекунда равна1e-6 milliseconds.

Примечание: Когда вы пишете стратегии вPythonязык, функцияSleep(Millisecond)не рекомендуется использовать функциюtime.time(second)В соответствии сtimeБиблиотека вPythonПотому что при использовании функцииtime.time(second)в стратегии, программа стратегии фактически будет ждать определенное количество секунд (параметрsecondявляется вторым номером настройки паузы), что приведет к очень медленному обратному тесту стратегии.

Виртуальная?

IsVirtual(), чтобы определить, является ли это симулируемым обратным тестом. Симулируемый статус обратного теста возвращаетсяtrue, и настоящий бот возвращаетсяfalse.

Почта ((...)

Mail(smtpServer, smtpUsername, smtpPassword, mailTo, title, body)является функцией отправки почты. Значение параметра: все являются типа строки. Возвратное значение: тип bool;trueвозвращается после успешной отправки.smtpServerслужит для отправления почтового ящикаsmtp; smtpUsernameявляется учетной записью почтового ящика;smtpPasswordявляется паролем STMP почтового ящика;mailToявляется получающим почтовым ящиком;titleназвание отправленной почты;bodyСодержание отправленной почты, например:

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");
}
  • ВMail_Goфункция является асинхронной версией функцииMail: Его использование аналогично функцииexchange.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
    

Примечание: Сервер Alibaba Cloud может заблокировать некоторые порты, так что почта не может быть отправлена. Если вам нужно изменить порт, вы можете добавить номер порта в первом параметре непосредственно, например,smtp.qq.com:587(QQmail), порт доступен для тестирования. Если произойдет ошибка:unencrypted connection, вам нужно изменить формат параметровsmtpServerв функцииMailк:ssl://xxxxx.com:xxxНапример, SMTP ssl метод QQmail:ssl://smtp.qq.com:465илиsmtp://xxxxx.com:xxx.

SetErrorFilter ((...)

ErrorFilter(RegEx), фильтрация журналов ошибок. Значение параметра: тип строки. Ошибки, совпадающие с этим регулярным выражением, не будут загружаться в систему журналов, и она может быть вызвана несколько раз (фильтрованные журналы не будут записываться в файл базы данных соответствующего идентификатора бота в журналах / ботах в содержимом докера, чтобы предотвратить расширение файла базы данных, вызванное частыми сообщениями об ошибках).

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

Профильтровать информацию об ошибке интерфейса:

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()возвращает идентификатор процесса бота. Возвращает значение: тип строки.

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

ПолучитьLastError()

GetLastError()получает последнюю информацию об ошибке; как правило, это не нужно использовать, потому что программа будет загружать информацию об ошибке в систему журналов автоматически.GetLastError(), кэш ошибок будет очищен; при повторном вызове информация об ошибке, записанная в последний раз, не будет возвращена.

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()получает интерактивные команды (utf-8). Он получает команду, отправленную стратегическим интерактивным интерфейсом, и очищает кэш; если нет команды, он возвращает пустую строку. Формат команды, возвращенныйbutton name: parameter; если в интерактивных элементах управления нет параметра (например, кнопка управления без окна ввода), командой является имя кнопки.

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

В основной системе есть структура очереди для записи интерактивной команды.GetCommand()будет вызвана, интерактивная команда, которая первая входит в очередь, будет выведена (если нет интерактивной команды, пустая строка).

Примеры использования интерактивных элементов управления; установка интерактивных элементов управления на интерфейсе редактирования стратегии:

img

Разработка интерактивных кодов в стратегии:

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

ФункцияGetMeta()возвращает значениеMetaзаписанное при создании токену стратегии, возвращаемое значение функции имеет тип строки. Приложения: например, стратегия должна ограничивать активы для разных арендаторов. Примечание: когда генерируется токен стратегии, длинаMetaне может превышать 190 строк; функция, применима только к фактической торговле и требует новейшего докера.GetMeta()возвращает NULL.

соответствующую информацию, подтвержденную приложениями

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

Нажмите...

Dial(Address, Timeout), оригинальный доступ к розетке, поддержкиtcp, udp, tlsиunixЗначение параметра:Addressявляется типом строки; единица является вторым; если время вышло, функцияDial(...)возвращает пустое значение.

Подробное описаниеAddressпараметр:

Подробности параметров
Параметры настройки функцииDial Отделить, добавив|символ после обычного адреса:wss://ws.okx.com:8443/ws/v5/public; если есть|символы в строке параметров, использование||Соедините каждый параметр с&; например, параметры ss5 прокси и сжатия устанавливаются вместе:Dial("wss://ws.okx.com:8443/ws/v5/public|proxy=socks5://xxx:9999&compress=gzip_raw&mode=recv").
В протоколе ws соответствующие параметры сжатия данных:compress=parameter value компресс - это метод сжатия; параметры сжатия могут быть выбраны изgzip_rawиgzip, и т. д. Если метод gzip является нестандартным gzip, вы можете использовать метод расширения:gzip_raw, то есть, добавить настройкиcompress=gzip_rawпосле сепаратора|, и использовать&символ и следующий параметр режима для разделения.
В протоколе ws соответствующие параметры сжатия данных:mode=parameter value режим - это режим, включающий три варианта, а именно:dual, sendиrecv. dualявляется двунаправленным, отправляет и принимает сжатые данные.sendЭто отправка сжатых данных.recvПринимать сжатые данные и распечатывать их локально.
Сопутствующие параметры для установки носков5 прокси:proxy=parameter value прокси - это настройка прокси ss5; формат значения параметра:socks5://name:pwd@192.168.0.1:1080; name - имя пользователя сервера ss5; pwd - пароль входа на сервер ss5; 1080 - порт сервера ss5
В протоколе ws соответствующие параметры для настройки базового автопересоединения:reconnect=parameter value "заново подключить" означает, установить ли "заново подключить";reconnect=trueявляется вызовом повторного подключения; по умолчанию не подключается.
В протоколе ws соответствующие параметры для настройки базового автопересоединения:interval=parameter value интервал - интервал повторной попытки в миллисекундах;interval=10000интервал повторной попытки составляет 10 секунд, а настройка по умолчанию составляет 1 секунду, то естьinterval=1000.
В протоколе ws соответствующие параметры для настройки базового автопересоединения:payload= parameter value полезная нагрузка - это сообщение подписки, которое должно быть отправлено при повторном подключении ws, например: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();
    }
}

Функцияreadподдерживает следующие параметры:

  • Когда никаких параметров не передается, он блокирует, пока не будет сообщения, например:ws.read().
  • При передаче параметров указывают время ожидания сообщений в единице миллисекунд, например:ws.read(2000)указывает время задержки на две секунды (2000 миллисекунд).
  • Следующие два параметра важны только дляwebsocket: Передача параметра-1означает немедленное возвращение независимо от того, есть ли какое-либо сообщение, например:ws.read(-1)- Да. Передача параметра-2означает возвращение немедленно независимо от того, есть ли какое-либо сообщение, но возвращается только последнее сообщение, и сообщение в буфере будет отброшено, например:ws.read(-2).

Функцияread()описание буфера: Если данные, отправляемые протоколом ws, имеют длительные интервалы между стратегиейread()Поскольку в буфере хранятся данные, то в буфере хранятся данные, находящиеся в очереди, с верхним пределом 2000.

Сценарии \ReadПараметр функции Нет параметра Параметр: -1 Параметр: -2 Параметр: 2000 (единица: мс)
В буфере уже есть данные Немедленно верните старые данные. Немедленно верните старые данные. Немедленно верните последние данные. Немедленно верните старые данные.
Нет данных в буфере Возвращение данных при блокировке данных Немедленно верните нуль Немедленно верните нуль Подождите 2000 мс, верните нуль, если нет данных, верните данные, если есть данные
Ws соединение отключено или нижний слой повторно подключен Функция read() возвращает нуль, то есть: , а функция write() возвращает 0. Если эта ситуация обнаружена, функция close() может быть использована для закрытия соединения. Если установлено автоматическое повторное соединение, ему не нужно будет закрываться, и нижний слой системы автоматически воссоединится.
  • Поддержка протокола wss (WebSocket) Доступ к интерфейсу Binance websocket market:

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

    Интерфейс рынка веб-сокетов OKX:

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

    Доступ к интерфейсу рынка Huobi websocket:

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

    Интерфейс проверки интерфейса веб-сокета, получающего доступ к 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)
    

авто-клиент_приват = Диалог ((wss://ws.okx.com:8443/ws/v5/private);

json getLogin ((строка pAccessKey, строка pSecretKey, строка pPassphrase) { авто ts = std::to_string ((Unix))); json login = R"({ op: login, аргс: [{ apiKey: , пароль: , временная марка: , знак: {y: i} }) "_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); возвращение логина; Я не знаю.

Главный пустой ((() SetErrorFilter (( время выхода из строя ); json posSubscribe = R"({ op: подпишитесь, args: [{ канал: позиции, instType: ANY {y: i} }) "_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;
        }
    }
}

}

Недействительный onexit ((() { client_private.close ((); Регистр выхода; Я не знаю.


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

Чтобы получить обратный контент URL-адреса, если второй параметрPostDataимеет форму строкиa=1&b=2&c=abc, представленныйPOST, другиеPUT; параметрPostDataэто{method:'PUT', data:'a=1&b=2&c=abc'}.

ВPostDataПараметр также может бытьJSON string.

Формат параметраCookiesявляется:a=10; b=20; каждый из параметров разделен запятой;- Да. Формат параметраHeadersявляется:User-Agent: Mobile\nContent-Type: text/html; с каждым параметром, разделенным символом новой строки\n.

Второй параметр:PostData, могут быть настроены, например:HttpQuery("http://www.abc.com", {method:'PUT', data:'a=1&b=2&c=abc'}); примечание: если вам нужно установить время отключения дляHttpQueryфункция, вы можете добавитьtimeoutатрибут в{method:'put',data:'a=1&B=2&C=ABC'}(по умолчанию 60 секунд).

Установите 1 секунду таймаута:HttpQuery("http://www.abc.com", {method:'PUT', data:'a=1&b=2&c=abc', timeout:1000})

Третий параметр необходим для передачи строкиCookie, ноPOSTВо время симуляционного теста, поскольку URL не может быть симулирована, функция возвращает фиксированную строкуDummy Data. Вы можете использовать этот интерфейс для отправки текстовых сообщений или взаимодействия с другими интерфейсами API.

GETПример вызова метода:HttpQuery("http://www.baidu.com"). POSTПример вызова метода:HttpQuery("http://www.163.com", "a=1&b=2&c=abc").

Пример вызова возвращения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}
  • ФункцияHttpQueryиспользует настройки прокси:

    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/");
    }
    
  • ФункцияHttpQueryАсинхронная версияHttpQuery_Go: Метод использования аналогичен функцииexchange.Go, например, асинхронный доступ к общественному интерфейсу биржи для получения агрегированных рыночных данных.

    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
    
  • Использование функцииHttpQuery(...)в системе обратных испытаний: Данные могут быть получены с помощьюHttpQuery(...)для отправки запросов (только поддержка)GETВ системе обратного тестирования устанавливается ограничение в 20 раз в обратном тестировании иHttpQuery(...)доступ будет кэшировать данные, в то время как функцияHttpQuery(...)возвращает кэшированные данные при втором доступе к одному и тому же URL-адресу (больше нет фактических веб-запросов).

    Мы можем запустить сервисную программу на сервере или устройстве, которое отвечает на запросы, отправленныеHttpQuery(...)в программе стратегии, а сервисная программа на языке Go для тестирования показана следующим образом:

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

    Использовать функциюHttpQuery(...)для отправки запросов во время обратного тестирования стратегии:

    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

    Он поддерживает транскодирование данных ответа в запросе, а также поддерживает общее кодирование. УточнениеPostDataпараметр:{method: "GET", charset: "GB18030"}может реализовать транскодирование данных ответа (GB18030).

Кодировка ((...)

Encode(algo, inputFormat, outputFormat, data, keyFormat, key string), функция кодирует данные в соответствии с прошедшими параметрами и возвращает значение строки.

Параметрalgoявляется алгоритмом, используемым для расчета кодирования, который может быть установлен на: raw (без алгоритма), 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, ripke2b.256, blake2b.512, blake2s.1288, blake2s.256 параметров.dataЭто и есть данные, которые должны быть обработаны.inputFormat/outputFormat/keyFormatпараметры поддерживают методы кодирования, такие какraw, hex, base64иstring- Да. ЕслиkeyFormatпараметр не пустой,keyпараметр используется для шифрования (HMAC), в противном случае по умолчаниюkeyКогда ```alg