Удостоверение ордера на торговлю
Цена: 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
.
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()
возвращает идентификатор процесса бота. Возвращает значение: тип строки.
function main(){
var id = GetPid()
Log(id)
}
def main():
id = GetPid()
Log(id)
void main() {
auto id = GetPid();
Log(id);
}
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()
будет вызвана, интерактивная команда, которая первая входит в очередь, будет выведена (если нет интерактивной команды, пустая строка).
Примеры использования интерактивных элементов управления; установка интерактивных элементов управления на интерфейсе редактирования стратегии:
Разработка интерактивных кодов в стратегии:
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()
возвращает значение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 ; |
В протоколе 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 соединение отключено или нижний слой повторно подключен | Функция |
Поддержка протокола 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)
авто-клиент_приват = Диалог ((
json getLogin ((строка pAccessKey, строка pSecretKey, строка pPassphrase) {
авто ts = std::to_string ((Unix)));
json login = R"({
Главный пустой ((()
SetErrorFilter ((
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());
}
Он поддерживает транскодирование данных ответа в запросе, а также поддерживает общее кодирование.
УточнениеPostData
параметр:{method: "GET", charset: "GB18030"}
может реализовать транскодирование данных ответа (GB18030).
Encode(algo, inputFormat, outputFormat, data, keyFormat, key string)
, функция кодирует данные в соответствии с прошедшими параметрами и возвращает значение строки.
Параметрalgo
является алгоритмом, используемым для расчета кодирования, который может быть установлен на: data
Это и есть данные, которые должны быть обработаны.inputFormat
/outputFormat
/keyFormat
параметры поддерживают методы кодирования, такие какraw
, hex
, base64
иstring
- Да.
ЕслиkeyFormat
параметр не пустой,key
параметр используется для шифрования (HMAC), в противном случае по умолчаниюkey
Когда ```alg