Documents de l'API de quantification par les inventeurs

Auteur:Le petit rêve, Créé: 2017-11-27 09:05:08, Mis à jour: 2023-07-12 16:47:31

void main() {
    Mail("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body");
}
  • MailVersion asynchrone de la fonctionMail_GoFonction: Utilisation etexchange.GoLes fonctions sont similaires.

    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)
    }
    
    # 不支持
    
    // 不支持
    

Attention: Le serveur Ali Cloud peut bloquer certains ports, ce qui empêche l'envoi d'e-mails. Si vous souhaitez modifier le port, vous pouvez ajouter le port directement dans le premier paramètre, par exemple:smtp.qq.com:587Le test de port est disponible. Si une erreur est signalée:unencryped connectionIl faut modifierMailLa fonctionsmtpServerLe format des paramètres est le suivant:ssl://xxx.com:xxxPar exemple, le QQ.SMTPLe code SSL est le suivant:ssl://smtp.qq.com:465Ou alorssmtp://xxx.com:xxx

- Je suis désolé.

SetErrorFilter(RegEx), filtrage des journaux d'erreurs↑ valeur de paramètre: type de chaîne↑ Les journaux d'erreurs correspondant à cette expression régulière ne seront pas téléchargés dans le système de journaux et plusieurs conditions de filtrage peuvent être appelées (les journaux filtrés ne sont pas écrits dans les fichiers de base de données correspondant à l'ID du disque dur dans le répertoire des hôtes, ce qui empêche les erreurs fréquentes de provoquer une expansion des fichiers de base de données).

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

Pour filtrer un message d'erreur d'interface:

function main() {
    // 随便查询一个不存在的订单,id为123,故意让接口报错
    var order = exchange.GetOrder("123")
    Log(order)
    // 过滤http502错误、GetOrder接口错误,设置错误过滤之后,第二次调用GetOrder不再报错
    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);
}

Je ne peux pas.

GetPid(), renvoie l'ID du processus de disque réel.

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

Obtenez la dernière erreur

GetLastError(), pour obtenir l'information d'erreur la plus récente. Il n'est généralement pas nécessaire de l'utiliser, car le programme télécharge automatiquement l'information d'erreur dans le système de journaux.GetLastError()La fonction efface ensuite le cache d'erreur et ne renvoie pas l'erreur de l'enregistrement précédent lorsqu'elle est appelée à nouveau.

function main(){
    // 因为不存在编号为123的订单,所以会出错
    exchange.GetOrder("123")
    var error = GetLastError()
    Log(error)
}
def main():
    exchange.GetOrder("123")
    error = GetLastError()
    Log(error)
void main() {
    // 订单ID类型:TId,所以不能传入字符串,我们下一个不符合交易所规范的订单来触发
    exchange.GetOrder(exchange.Buy(1, 1));
    auto error = GetLastError();
    Log(error);
}

Vous avez le commandement?

GetCommand(), obtient la chaîne de commande interactive ((utf-8)); obtient la commande envoyée par l'interface interactive de la stratégie et la cache vide, sans commande, retourne la chaîne vide; le format de commande retourné est按钮名称:参数Si le contrôle interactif n'a pas de paramètres (par exemple, un contrôle de bouton sans boîte d'entrée), la commande est le nom du bouton.

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

Le système sous-jacent a une structure de file d'attente pour enregistrer les commandes d'interaction lorsqueGetCommand()Lorsqu'une fonction est appelée, elle extrait la commande interactive qui est entrée en premier dans la file d'attente (et renvoie une chaîne vide si aucune commande interactive n'est utilisée).

Exemples d'utilisation des contrôles interactifs, l'interface de l'éditeur de stratégie pour configurer les contrôles interactifs.

img

La stratégie consiste à concevoir du code interactif:

function main() {
    while (true) {
        LogStatus(_D())
        var cmd = GetCommand()
        if (cmd) {
            Log("cmd:", cmd)    
            var arr = cmd.split(":")
            if (arr[0] == "buy") {
                Log("买入,该控件不带数量")
            } else if (arr[0] == "sell") {
                Log("卖出,该控件带数量:", arr[1])
            } else {
                Log("其它控件触发:", arr)
            }
        }
        Sleep(1000)
    } 
}
def main():
    while True:
        LogStatus(_D())
        cmd = GetCommand()
        if cmd:
            Log("cmd:", cmd)
            arr = cmd.split(":")
            if arr[0] == "buy":
                Log("买入,该控件不带数量")
            elif arr[0] == "sell":
                Log("卖出,该控件带数量:", arr[1])
            else:
                Log("其它控件触发:", 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("买入,该控件不带数量");
            } else if (arr[0] == "sell") {
                Log("卖出,该控件带数量:", arr[1]);
            } else {
                Log("其它控件触发:", arr);
            }
        }
        Sleep(1000);
    }
}

Je suis désolée.

GetMeta()La fonction renvoie le code de registre de génération de la politique.MetaLa valeur de cette fonction est la valeur de type de chaîne. Les scénarios d'application, par exemple la stratégie qui impose des restrictions de financement à différents locataires. Remarque: lorsque vous générez un code d'enregistrementMetaLa fonction ne peut pas dépasser 190 caractères de longueur, elle s'applique uniquement au disque virtuel et nécessite l'utilisation d'un hôte le plus récent.GetMeta()Retourne une valeur nulle.

Informations sur l'utilisation de la démonstration de scène

function main() {
    // 策略允许的计价币最大资产数值
    var maxBaseCurrency = null
    
    // 获取创建注册码时的元数据
    var level = GetMeta()
    
    // 检测Meta对应的条件
    if (level == "level1") {
        // -1为不限制
        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()
        
        // 检测资产数值
        var acc = exchange.GetAccount()
        if (maxBaseCurrency != -1 && maxBaseCurrency < acc.Stocks + acc.FrozenStocks) {
            // 停止执行策略交易逻辑
            LogStatus(_D(), "level:", level, "持仓超过注册码的使用限定,不再执行策略交易逻辑!")
            continue
        }
        
        // 其它交易逻辑
        
        // 正常输出状态栏信息
        LogStatus(_D(), "level:", level, "策略正常运行!ticker数据:\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, "持仓超过注册码的使用限定,不再执行策略交易逻辑!")
            continue        
        
        # 其它交易逻辑
        
        # 正常输出状态栏信息
        LogStatus(_D(), "level:", level, "策略正常运行!ticker数据:\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) {
            // 停止执行策略交易逻辑
            LogStatus(_D(), "level:", level, "持仓超过注册码的使用限定,不再执行策略交易逻辑!");
            continue;
        }
        
        // 其它交易逻辑
        
        // 正常输出状态栏信息
        LogStatus(_D(), "level:", level, "策略正常运行!ticker数据:\n", ticker);
    }
}

Faites le numéro...

Dial(Address, Timeout)Je ne sais pas.SocketAccès et soutientcpudptlsunixLe protocole ⋅ valeur du paramètre:AddressPour le type de chaîne,TimeOutPour le type de valeur, l'unité de valeur est la seconde, si elle dépasse le tempsDial(...)La fonction renvoie une valeur nulle.

AddressLes paramètres sont détaillés:

Paramètres
ParamètresDialParamètres de fonction Il y a un autre site officiel:wss://ws.okx.com:8443/ws/v5/publicPlus tard|Si une chaîne de chiffres a un symbole séparé,|Les caractères sont||Utilisé comme symbole de séparation.&Les connexions de caractères. Par exemple, l'agent ss5 et les paramètres de compression sont configurés ensemble:Dial("wss://ws.okx.com:8443/ws/v5/public|proxy=socks5://xxx:9999&compress=gzip_raw&mode=recv")
Les paramètres liés à la compression des données utilisés dans le protocole ws sont:compress=参数值 compress est le mode de compression, les paramètres de compression sont optionnelsgzip_rawgzipSi le gzip n'est pas le gzip standard, vous pouvez utiliser l'extension suivante:gzip_rawC'est le point de séparation.|Ajouter des paramètres plus tardcompress=gzip_raw, avec&Le symbole et le paramètre mode suivant sont séparés.
Les paramètres liés à la compression des données utilisés dans le protocole ws sont:mode=参数值 mode à la mode, optionneldualsendrecvIl y en a trois.dualPour les deux sens, envoyer des données de compression et recevoir des données de compression.sendPour envoyer des données compressées.recvPour recevoir les données de compression, décompresser localement.
Les paramètres utilisés pour configurer un agent socks5 sont les suivants:proxy=参数值 Le proxy est configuré comme un proxy ss5 et sa valeur de paramètre est:socks5://name:pwd@192.168.0.1:1080,name est le nom d'utilisateur du serveur ss5, pwd est le mot de passe de connexion du serveur ss5, et 1080 est le port du service ss5.
Pour le protocole ws, les paramètres suivants sont définis pour les liaisons automatiques sous-jacentes:reconnect=参数值 reconnect indique si la connexion a été rétablie.reconnect=truePour activer le renvoi.
Pour le protocole ws, les paramètres suivants sont définis pour les liaisons automatiques sous-jacentes:interval=参数值 L'intervalle est un intervalle de temps de réessai en millisecondes.interval=10000Pour réessayer à l'intervalle de 10 secondes, la valeur par défaut n'est pas de 1 seconde.interval=1000
Pour le protocole ws, les paramètres suivants sont définis pour les liaisons automatiques sous-jacentes:payload=参数值 Les messages d'abonnement qui doivent être envoyés lorsque le payload se reconnecte à ws, par exemple:payload=okok
function main(){
    // Dial支持tcp://,udp://,tls://,unix://协议,可加一个参数指定超时的秒数
    var client = Dial("tls://www.baidu.com:443")  
    if (client) {
        // write可再跟一个数字参数指定超时,write返回成功发送的字节数
        client.write("GET / HTTP/1.1\nConnection: Closed\n\n")
        while (true) {
            // read可再跟一个数字参数指定超时,单位:毫秒。返回null指出错或者超时或者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();
    }
}

readLa fonction prend en charge les paramètres suivants:

  • Si aucun paramètre n'est transmis, le blocage est renvoyé lorsqu'il y a un message. Par exemple:ws.read()
  • Lors de la transmission des paramètres, l'unité est en millisecondes, spécifiant le temps d'attente du message au-delà du temps d'attente; par exemple:ws.read(2000)Le temps d'attente est de deux secondes (environ 2000 millisecondes).
  • Les deux paramètres suivants sont vrais.websocketEffectif: Paramètres d'entrée-1Une fonction retourne immédiatement, qu'il y ait ou non un message, par exemple:ws.read(-1)Je ne sais pas. Paramètres d'entrée-2Cela signifie que la fonction retourne immédiatement, qu'il n'y ait pas de message, mais qu'elle ne renvoie que les messages les plus récents, les messages dans la zone de sauvegarde étant abandonnés; par exemple:ws.read(-2)

read()Les zones de soutiens-gorge des fonctions indiquent: Les données envoyées par le protocole ws, si elles sont en ligneread()L'intervalle de temps entre les appels de fonctions est trop long, ce qui peut entraîner une accumulation de données. Ces données sont stockées dans une zone de sauvegarde, la structure de la zone de sauvegarde étant une file d'attente, avec un maximum de 2000 données. Après avoir dépassé 2000, les données les plus récentes entrent dans la zone de sauvegarde et les plus anciennes sont supprimées.

La scènereadParamètres de fonction Pas de paramètres Paramètres: -1 Paramètres: -2 Paramètres: 2000 est une unité de millisecondes
Les données de la zone tampon Retournez immédiatement aux données les plus anciennes Retournez immédiatement aux données les plus anciennes Retrouvez les données les plus récentes Retournez immédiatement aux données les plus anciennes
Aucune donnée sur la zone tampon Bloquer jusqu'à ce qu'il y ait des données Retournez immédiatement la valeur vide Retournez immédiatement la valeur vide Attendez 2000 millisecondes, aucune donnée ne renvoie rien, mais des données renvoient
ws connexion est coupée ou basse se reconnecte La fonction read (()) renvoie une chaîne vide, c'est-à-dire:"",write (()) renvoie 0, détecté dans ce cas. Vous pouvez utiliser la fonction close (()) pour fermer la connexion, si vous avez mis en place une reconnexion automatique, vous n'avez pas besoin de la fermer, le système de base se reconnecte automatiquement.
  • Prise en charge du protocole wss (WebSocket) Pour accéder à l'interface Websocket de Binance:

    function main() {
        LogStatus("正在连接...")
        // 访问币安的websocket接口
        var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")
        if (!client) {
            Log("连接失败, 程序退出")
            return
        }
        
        while (true) {
            // read只返回调用read之后获取的数据
            var buf = client.read()      
            if (!buf) {
                break
            }
            var table = {
                type: 'table',
                title: '行情图表',
                cols: ['币种', '最高', '最低', '买一', '卖一', '最后成交价', '成交量', '更新时间'],
                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("正在连接...")
        client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")
        if not client:
            Log("连接失败, 程序退出")
            return 
        
        while True:
            buf = client.read()
            if not buf:
                break
            table = {
                "type" : "table", 
                "title" : "行情图表", 
                "cols" : ["币种", "最高", "最低", "买一", "卖一", "最后成交价", "成交量", "更新时间"], 
                "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("正在连接...");
        auto client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr");
        if(!client.Valid) {
            Log("连接失败, 程序退出");
            return;
        }
        
        while(true) {
            auto buf = client.read();
            if(buf == "") {
                break;
            }
            json table = R"({
                "type" : "table", 
                "title" : "行情图表", 
                "cols" : ["币种", "最高", "最低", "买一", "卖一", "最后成交价", "成交量", "更新时间"], 
                "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();
    }
    

    Pour accéder à l'interface Websocket de OKX:

    var ws = null 
    function main(){
        var param = {
            "op": "subscribe",
            "args": [{
                "channel": "tickers",
                "instId": "BTC-USDT"
            }]
        }
        // 在调用Dial函数时,指定reconnect=true即设置为重连模式,指定payload即为重连时发送的消息。在websocket连接断开后,会自动重连,自动发送消息
        ws = Dial("wss://ws.okx.com:8443/ws/v5/public|compress=gzip_raw&mode=recv&reconnect=true&payload="+ JSON.stringify(param))
        if(ws){
            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("发送 :ping", "#FF0000")
                }
                LogStatus("当前时间:", _D())
                Sleep(1000)
            }
        }
    }  
    
    function onexit() {
        ws.close() 
        Log("退出")
    }
    
    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("发送:ping", "#FF0000")
                LogStatus("当前时间:", _D())
                Sleep(1000)  
    
    def onexit():
        ws.close()
        Log("退出")
    
    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": [{
                "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("发送:ping", "#FF0000");
                }
                LogStatus("当前时间:", _D());
                Sleep(1000);
            }
        }
    }  
    
    void onexit() {
        objWS.close();
        Log("退出");
    }
    

    L'interface utilisée par le websocket pour accéder aux jetons:

    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)
                // 响应心跳包操作
                try {
                    var jsonRet = JSON.parse(ret)
                    if(typeof(jsonRet.ping) == "number") {
                        var strPong = JSON.stringify({"pong" : jsonRet.ping})
                        ws.write(strPong)
                        Log("响应ping,发送pong:", strPong, "#FF0000")
                    }
                } catch(e) {
                    Log("e.name:", e.name, "e.stack:", e.stack, "e.message:", e.message)
                }
                
                LogStatus("当前时间:", _D())
                Sleep(1000)
            }
        }
    }  
    
    function onexit() {
        ws.close() 
        Log("执行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)              
                # 响应心跳包操作
                try:
                    jsonRet = json.loads(ret)
                    if "ping" in jsonRet and type(jsonRet["ping"]) == int:
                        strPong = json.dumps({"pong" : jsonRet["ping"]})
                        ws.write(strPong)
                        Log("响应ping,发送pong:", strPong, "#FF0000")
                except Exception as e:
                    Log("e:", e)
                    
                LogStatus("当前时间:", _D())
                Sleep(1000)
        
    def onexit():
        ws.close()
        Log("执行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);              
                // 响应心跳包操作
                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("响应ping,发送pong:", strPong, "#FF0000");
                    }
                } catch(exception &e) 
                {
                    Log("e:", e.what());
                }
                
                LogStatus("当前时间:", _D());
                Sleep(1000);
            }
        }
    }  
    
    void onexit() {
        // ws.close();
        Log("执行ws.close()函数");
    }
    

    Pour accéder à l'interface d'authentification du websocket OKX:

    function getLogin(pAccessKey, pSecretKey, pPassphrase) {
        // 签名函数,用于登录
        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() {
        // 因为read函数使用了超时设置,过滤超时的报错,否则会有冗余错误输出
        SetErrorFilter("timeout")
        
        // 持仓频道订阅信息
        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)  // 登录时,不能立即订阅私有频道,需要等待服务器反应
        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)
                }
                
                // 检测断开,重连
                if (buf == "" && client_private.write(JSON.stringify(posSubscribe)) == 0) {
                    Log("检测到断开,关闭连接,重连")
                    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))
                }
                
                // 发送心跳包
                var nowPingTS = new Date().getTime()
                if (nowPingTS - lastPingTS > 10 * 1000) {
                    client_private.write("ping")
                    lastPingTS = nowPingTS
                }            
            }        
        }
    }    
    
    function onexit() {    
        var ret = client_private.close()
        Log("关闭连接!", 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("检测到断开,关闭连接,重连")
                    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("关闭连接!", ret)
    
    auto client_private = Dial("wss://ws.okx.com:8443/ws/v5/private");      
    
    json getLogin(string pAccessKey, string pSecretKey, string pPassphrase) {
        auto ts = std::to_string(Unix());
        json login = R"({
            "op": "login",
            "args": [{
                "apiKey": "",
                "passphrase": "",
                "timestamp": "",
                "sign": ""
            }]
        })"_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);
        return login;
    }      
    
    void main() {
        SetErrorFilter("timeout");
        json posSubscribe = R"({
            "op": "subscribe",
            "args": [{
                "channel": "positions",
                "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("检测到断开,关闭连接,重连");
                        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;
                }
            }
        }
    }      
    
    void onexit() {
        client_private.close();
        Log("退出");
    }
    

HttpQuery (en anglais)

HttpQuery(Url, PostData, Cookies, Headers, IsReturnHeader), accès à l'URL du réseau↑ valeur de paramètre: toutes les types de chaîne↑

Attention:

  • HttpQuery(...)Les fonctions ne sont prises en charge queJavaScriptLa langue.
  • PythonLa langue peut être utiliséeurllibLe site Web de l'entreprise est actuellement en cours de développement.

HttpQuery(...)Il est principalement utilisé pour accéder à des interfaces qui ne nécessitent pas de signature, telles que les interfaces publiques telles que les informations de marché.

Exemple d'interface API qui n'a pas besoin d'être signée pour accéder à OKX et renvoie la valeurJSONJe ne sais pas.JavaScriptLes stratégies linguistiques sont utilesJSON.parse()Partage des fonctions.

function main(){
    // 一个GET访问不带参数的例子
    var info = JSON.parse(HttpQuery("https://www.okx.com/api/v5/public/time"))
    Log(info)
    // 一个GET访问带参数的例子
    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不支持Python,可以使用urllib/urllib2库代替
    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);
}

Retrouvez le contenu renvoyé d'une URL si le deuxième paramètrePostDataPour les chaînesa=1&b=2&c=abcLa forme est:POSTComment le soumettre.PUTIl y a aussi des articles sur les droits de l'homme.PostDataLe paramètre est{method:'PUT', data:'a=1&b=2&c=abc'}PostDataLes paramètres peuvent aussi êtreJSONJe ne peux pas le faire.

CookiesCe paramètre a la forme suivante:a=10; b=20Les paramètres sont notés.;Il y a une différence.HeadersCe paramètre a la forme suivante:User-Agent: Mobile\nContent-Type: text/htmlLes paramètres sont remplacés par des signes\nIl y a une différence.

Le deuxième paramètrePostDataIl est possible de personnaliser les méthodes suivantes:HttpQuery("http://www.abc.com", {method:'PUT', data:'a=1&b=2&c=abc'})Attention: si vous avez besoin deHttpQueryLes fonctions de temps d'arrêt peuvent être{method:'PUT', data:'a=1&b=2&c=abc'}À rejoindretimeoutAttribut ((60 secondes par défaut) ⇒

Pour mettre 1 seconde de retard:HttpQuery("http://www.abc.com", {method:'PUT', data:'a=1&b=2&c=abc', timeout:1000})

Le dépôtCookieLa chaîne a besoin d'un troisième paramètre, mais pasPOSTVeuillez laisser le deuxième paramètre vide. Lors du test d'analogie, la fonction renvoie une chaîne fixe car l'URL n'a pas pu être simulée.Dummy DataVous pouvez utiliser cette interface pour envoyer des SMS ou interagir avec d'autres interfaces API.

GETExemples d'appels à la méthode:HttpQuery("http://www.baidu.com")POSTExemples d'appels à la méthode:HttpQuery("http://www.163.com", "a=1&b=2&c=abc")

RetourHeaderVoici quelques exemples de ces appels:

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}
  • HttpQueryLes fonctions utilisent les paramètres d'un agent:

    function main() {
        // 本次设置代理并发送http请求,无用户名,无密码,此次http请求会通过代理发送
        HttpQuery("socks5://127.0.0.1:8889/http://www.baidu.com/")
    
        // 本次设置代理并发送http请求,输入用户名和密码,仅HttpQuery当前调用生效,之后再次调用HttpQuery("http://www.baidu.com")这样不会使用代理
        HttpQuery("socks5://username:password@127.0.0.1:8889/http://www.baidu.com/")
    }
    
    # HttpQuery不支持Python,可以使用Python的urllib2库
    
    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/");
    }
    
  • HttpQueryVersion asynchrone de la fonctionHttpQuery_GoJe ne sais pas. Utilisation etexchange.GoLes fonctions sont similaires, par exemple l'accès asynchrone à l'interface publique de l'échange pour obtenir des données de marché agrégées.

    function main() {
        // 创建第一个异步线程
        var r1 = HttpQuery_Go("https://www.okx.com/api/v5/market/tickers?instType=SPOT")
        // 创建第二个异步线程
        var r2 = HttpQuery_Go("https://api.huobi.pro/market/tickers")
        
        // 获取第一个异步线程调用的返回值
        var tickers1 = r1.wait()
        // 获取第二个异步线程调用的返回值
        var tickers2 = r2.wait()
        
        // 打印结果
        Log("tickers1:", tickers1)
        Log("tickers2:", tickers2)
    }
    
    # 不支持
    
    // 不支持
    
  • Utilisation dans les systèmes de retoucheHttpQuery(...)Fonction: Il peut être utilisé dans les systèmes de retoucheHttpQuery(...)Envoyer une demande (supportée uniquement)GETLes requêtes) d'obtention de données.HttpQuery(...)L'accès cache les données, la même URL la deuxième foisHttpQuery(...)La fonction renvoie les données en cache (il n'y a plus de requêtes réelles sur le réseau).

    Nous pouvons exécuter un service sur un serveur ou un appareil pour répondre à un programme de stratégie.HttpQuery(...)Les requêtes envoyées et le programme de service Go utilisé pour les tests sont les suivants:

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

    Utilisé lors de la réévaluation de la stratégieHttpQuery(...)La fonction envoie une requête:

    function main() {
        // 可以写自己运行服务程序所在设备的IP地址
        Log(HttpQuery("http://xxx.xx.x.xxx:9090/data?msg=hello"));
        Log(exchange.GetAccount());
    }
    
    # HttpQuery不支持Python,可以使用Python的urllib2库
    
    void main() {
        // 可以写自己运行服务程序所在设备的IP地址
        Log(HttpQuery("http://xxx.xx.x.xxx:9090/data?msg=hello"));
        Log(exchange.GetAccount());
    }
    

    img

  • Prise en charge de la transcription des données de réponse aux demandes, prise en charge de l'encodage courant. DéfinitionPostDataParamètres:{method: "GET",charset:"GB18030"}Le code de transfert de données (GB18030) est utilisé pour la réponse.

Le code

Encode(algo, inputFormat, outputFormat, data, keyFormat, key string)Cette fonction encode les données en fonction des paramètres transmis. Elle renvoie la valeur: type de chaîne.

ParamètresalgoL'algorithme utilisé pour le calcul du codage est le suivant:??raw (sans algorithme),??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,??mdrip160,??blake2b.256,??blake2b.512,??blake2s.128,??blake2s.256.dataLes données à traiter.inputFormat/outputFormat/keyFormatPrise en charge par paramètresrawhexbase64stringLe code est écrit comme suit: SikeyFormatOn utilise des paramètres qui ne sont pas nuls.keyPour le chiffrement (HMAC), sinon par défautkeyParamètresalgoPour"sign"Ou alors"signTx"Il faut des paramètreskey

function main(){
    Log(Encode("md5", "raw", "hex", "hello"))
    Log(Encode("sha512", "raw", "base64", "hello"))
    Log(Encode("keccak256", "raw", "hex", "unwrapWETH9(uint256,address)"))

    Log(Encode("raw", "string", "hex", "example"))          // 6578616d706c65
    Log(Encode("raw", "hex", "string", "6578616d706c65"))   // example
}
def main():
    Log(Encode("md5", "raw", "hex", "hello", "", ""))
    Log(Encode("sha512", "raw", "base64", "hello", "", ""))
    Log(Encode("keccak256", "raw", "hex", "unwrapWETH9(uint256,address)", "", ""))

    Log(Encode("raw", "string", "hex", "example", "", ""))
    Log(Encode("raw", "hex", "string", "6578616d706c65", "", ""))
void main(){
    Log(Encode("md5", "raw", "hex", "hello"));
    Log(Encode("sha512", "raw", "base64", "hello"));
    Log(Encode("keccak256", "raw", "hex", "unwrapWETH9(uint256,address)"));
    
    Log(Encode("raw", "string", "hex", "example"));          // 6578616d706c65
    Log(Encode("raw", "hex", "string", "6578616d706c65"));   // example
}

ParamètresalgoIl a également soutenu:text.encoder.utf8text.decoder.utf8text.encoder.gbktext.decoder.gbkLe code de l'appareil est le code de l'appareil.

function main(){
    var ret1 = Encode("text.encoder.utf8", "raw", "hex", "你好")     // e4bda0e5a5bd
    Log(ret1)    
    var ret2 = Encode("text.decoder.utf8", "hex", "string", ret1)   
    Log(ret2)

    var ret3 = Encode("text.encoder.gbk", "raw", "hex", "你好")      // c4e3bac3
    Log(ret3)
    var ret4 = Encode("text.decoder.gbk", "hex", "string", ret3)
    Log(ret4)
}
def main():
    ret1 = Encode("text.encoder.utf8", "raw", "hex", "你好", "", "")     # e4bda0e5a5bd
    Log(ret1)    
    ret2 = Encode("text.decoder.utf8", "hex", "string", ret1, "", "")   
    Log(ret2)

    ret3 = Encode("text.encoder.gbk", "raw", "hex", "你好", "", "")      # c4e3bac3
    Log(ret3)
    ret4 = Encode("text.decoder.gbk", "hex", "string", ret3, "", "")
    Log(ret4)
void main(){
    auto ret1 = Encode("text.encoder.utf8", "raw", "hex", "你好");     // e4bda0e5a5bd
    Log(ret1);    
    auto ret2 = Encode("text.decoder.utf8", "hex", "string", ret1);   
    Log(ret2);

    auto ret3 = Encode("text.encoder.gbk", "raw", "hex", "你好");      // c4e3bac3
    Log(ret3);
    auto ret4 = Encode("text.decoder.gbk", "hex", "string", ret3);
    Log(ret4);
}

UnixNano (en anglais)

UnixNano()Si vous avez besoin d'obtenir un timestamp en millisecondes, vous pouvez utiliser le code suivant:

function main() {
    var time = UnixNano() / 1000000
    Log(_N(time, 0))
}
def main():
    time = UnixNano()
    Log(time)
void main() {
    auto time = UnixNano();
    Log(time);
}

Unix (()

Unix(), retourner le temps de la seconde à l'échelle du temps.

function main() {
    var t = Unix()
    Log(t)
}
def main():
    t = Unix()
    Log(t)
void main() {
    auto t = Unix();
    Log(t);
}

Je suis désolée.

GetOS()Les informations sont envoyées à l'administrateur et retournées au système.

function main() {
    Log("GetOS:", GetOS())
}
def main():
    Log("GetOS:", GetOS())
void main() {
    Log("GetOS:", GetOS());
}

Pour les ordinateurs AppleMac OSLes journaux des administrateurs fonctionnant sous le système d'exploitation sont sortis:

Je ne sais pas.

darwinJe veux dire,Mac OSLe nom du système.

MD5 ((String)

MD5(String), valeur de paramètre: type de chaîne.

function main() {
    Log("MD5", MD5("hello world"))
}
def main():
    Log("MD5", MD5("hello world"))
void main() {
    Log("MD5", MD5("hello world"));
}

Les journaux sont sortis:

Je suis désolé, je suis désolé.

Je suis désolé.

DBExec(), valeur de paramètre: peut être un type de chaîne, valeur numérique, valeur Boole, valeur vide etc.; valeur de retour: objet contenant le résultat de l'exécution d'une instruction SQLite. Fonction d'interface de base de donnéesDBExec()Les paramètres d'entrée permettent d'opérer une base de données en disque dur (base de données SQLite) ; des opérations d'ajout, de suppression, de vérification, de modification, etc. sont prises en charge.SQLiteSyntaxe. Une table de réservation de système dans une base de données de disque:kvdbcfglogprofitchartNe touchez pas à ces tables.DBExec()Les fonctions ne prennent en charge que les disques réels.

  • Prise en charge de la base de données en mémoire PourDBExecLes paramètres de la fonction sont les suivants:Le secteurLa phrase est:Au départ, il fonctionne dans une base de données en mémoire, sans écrire de fichiers, et est plus rapide. Il convient aux opérations de base de données qui ne nécessitent pas de sauvegarde permanente, par exemple:

    function main() {
        var strSql = [
            ":CREATE TABLE TEST_TABLE(", 
            "TS INT PRIMARY KEY NOT NULL,",
            "HIGH REAL NOT NULL,", 
            "OPEN REAL NOT NULL,", 
            "LOW REAL NOT NULL,", 
            "CLOSE REAL NOT NULL,", 
            "VOLUME REAL NOT NULL)"
        ].join("")
        var ret = DBExec(strSql)
        Log(ret)
        
        // 增加一条数据
        Log(DBExec(":INSERT INTO TEST_TABLE (TS, HIGH, OPEN, LOW, CLOSE, VOLUME) VALUES (1518970320000, 100, 99.1, 90, 100, 12345.6);"))
        
        // 查询数据
        Log(DBExec(":SELECT * FROM TEST_TABLE;"))
    }
    
    def main():
        arr = [
            ":CREATE TABLE TEST_TABLE(", 
            "TS INT PRIMARY KEY NOT NULL,",
            "HIGH REAL NOT NULL,", 
            "OPEN REAL NOT NULL,", 
            "LOW REAL NOT NULL,", 
            "CLOSE REAL NOT NULL,", 
            "VOLUME REAL NOT NULL)"
        ]
        strSql = ""
        for i in range(len(arr)):
            strSql += arr[i]
        ret = DBExec(strSql)
        Log(ret)
        
        # 增加一条数据
        Log(DBExec(":INSERT INTO TEST_TABLE (TS, HIGH, OPEN, LOW, CLOSE, VOLUME) VALUES (1518970320000, 100, 99.1, 90, 100, 12345.6);"))
        
        # 查询数据
        Log(DBExec(":SELECT * FROM TEST_TABLE;"))
    
    void main() {
        string strSql = ":CREATE TABLE TEST_TABLE(\
            TS INT PRIMARY KEY NOT NULL,\
            HIGH REAL NOT NULL,\
            OPEN REAL NOT NULL,\
            LOW REAL NOT NULL,\
            CLOSE REAL NOT NULL,\
            VOLUME REAL NOT NULL)";
        auto ret = DBExec(strSql);
        Log(ret);
        
        // 增加一条数据
        Log(DBExec(":INSERT INTO TEST_TABLE (TS, HIGH, OPEN, LOW, CLOSE, VOLUME) VALUES (1518970320000, 100, 99.1, 90, 100, 12345.6);"));
        
        // 查询数据
        Log(DBExec(":SELECT * FROM TEST_TABLE;"));
    }
    
  • Créer une table

function main() {
    var strSql = [
        "CREATE TABLE TEST_TABLE(", 
        "TS INT PRIMARY KEY NOT NULL,",
        "HIGH REAL NOT NULL,", 
        "OPEN REAL NOT NULL,", 
        "LOW REAL NOT NULL,", 
        "CLOSE REAL NOT NULL,", 
        "VOLUME REAL NOT NULL)"
    ].join("")
    var ret = DBExec(strSql)
    Log(ret)
}
def main():
    arr = [
        "CREATE TABLE TEST_TABLE(", 
        "TS INT PRIMARY KEY NOT NULL,",
        "HIGH REAL NOT NULL,", 
        "OPEN REAL NOT NULL,", 
        "LOW REAL NOT NULL,", 
        "CLOSE REAL NOT NULL,", 
        "VOLUME REAL NOT NULL)"
    ]
    strSql = ""
    for i in range(len(arr)):
        strSql += arr[i]
    ret = DBExec(strSql)
    Log(ret)
void main() {
    string strSql = "CREATE TABLE TEST_TABLE(\
        TS INT PRIMARY KEY NOT NULL,\
        HIGH REAL NOT NULL,\
        OPEN REAL NOT NULL,\
        LOW REAL NOT NULL,\
        CLOSE REAL NOT NULL,\
        VOLUME REAL NOT NULL)";
    auto ret = DBExec(strSql);
    Log(ret);
}
  • Opérations d'ajout, de suppression et de modification des enregistrements dans une table
function main() {
    var strSql = [
        "CREATE TABLE TEST_TABLE(", 
        "TS INT PRIMARY KEY NOT NULL,",
        "HIGH REAL NOT NULL,", 
        "OPEN REAL NOT NULL,", 
        "LOW REAL NOT NULL,", 
        "CLOSE REAL NOT NULL,", 
        "VOLUME REAL NOT NULL)"
    ].join("")
    Log(DBExec(strSql))
    
    // 增加一条数据
    Log(DBExec("INSERT INTO TEST_TABLE (TS, HIGH, OPEN, LOW, CLOSE, VOLUME) VALUES (1518970320000, 100, 99.1, 90, 100, 12345.6);"))
    
    // 查询数据
    Log(DBExec("SELECT * FROM TEST_TABLE;"))
    
    // 修改数据
    Log(DBExec("UPDATE TEST_TABLE SET HIGH=? WHERE TS=?", 110, 1518970320000))    
    
    // 删除数据
    Log(DBExec("DELETE FROM TEST_TABLE WHERE HIGH=?", 110))
}
def main():
    arr = [
        "CREATE TABLE TEST_TABLE(", 
        "TS INT PRIMARY KEY NOT NULL,",
        "HIGH REAL NOT NULL,", 
        "OPEN REAL NOT NULL,", 
        "LOW REAL NOT NULL,", 
        "CLOSE REAL NOT NULL,", 
        "VOLUME REAL NOT NULL)"
    ]
    strSql = ""
    for i in range(len(arr)):
        strSql += arr[i]
    Log(DBExec(strSql))
    
    # 增加一条数据
    Log(DBExec("INSERT INTO TEST_TABLE (TS, HIGH, OPEN, LOW, CLOSE, VOLUME) VALUES (1518970320000, 100, 99.1, 90, 100, 12345.6);"))
    
    # 查询数据
    Log(DBExec("SELECT * FROM TEST_TABLE;"))
    
    # 修改数据
    Log(DBExec("UPDATE TEST_TABLE SET HIGH=? WHERE TS=?", 110, 1518970320000))
    
    # 删除数据
    Log(DBExec("DELETE FROM TEST_TABLE WHERE HIGH=?", 110))
void main() {
    string strSql = "CREATE TABLE TEST_TABLE(\
        TS INT PRIMARY KEY NOT NULL,\
        HIGH REAL NOT NULL,\
        OPEN REAL NOT NULL,\
        LOW REAL NOT NULL,\
        CLOSE REAL NOT NULL,\
        VOLUME REAL NOT NULL)";
    Log(DBExec(strSql));

    // 增加一条数据
    Log(DBExec("INSERT INTO TEST_TABLE (TS, HIGH, OPEN, LOW, CLOSE, VOLUME) VALUES (1518970320000, 100, 99.1, 90, 100, 12345.6);"));
    
    // 查询数据
    Log(DBExec("SELECT * FROM TEST_TABLE;"));
    
    // 修改数据
    Log(DBExec("UPDATE TEST_TABLE SET HIGH=? WHERE TS=?", 110, 1518970320000));
    
    // 删除数据
    Log(DBExec("DELETE FROM TEST_TABLE WHERE HIGH=?", 110));
}

UUID (()

UUID(), qui renvoie un unique UUID de 32 bits, qui s'applique uniquement au disque dur.

function main() {
    var uuid1 = UUID()
    var uuid2 = UUID()
    Log(uuid1, uuid2)
}
def main():
    uuid1 = UUID()
    uuid2 = UUID()
    Log(uuid1, uuid2)
void main() {
    auto uuid1 = UUID();
    auto uuid2 = UUID();
    Log(uuid1, uuid2);
}

Le temps d'arrêt d'événement

EventLoop(timeout)Il y en awebsocketLisez ouexchange.GoHttpQuery_GoLes paramètres sont retournés après l'exécution de la tâche simultanée.timeoutSi le paramètre est de 0, il revient en attendant que l'événement se produise, si le paramètre est supérieur à 0, il revient immédiatement en attendant que l'événement se produise, si le paramètre est inférieur à 0, il revient immédiatement en attendant que l'événement se produise.nullIl est possible de modifier le contenu de l'application.EventType de déclenchement d'événement. Cette fonction s'applique uniquement au disque dur.

Le premier appel dans le codeEventLoopLe mécanisme d'initialization de l'événement de surveillance ne peut être effectué que si l'événement est déclenché pour la première fois après le rappel.EventLoopappels, qui manquent les événements précédents. La structure de file d'attente enveloppée par le système sous-jacent cache jusqu'à 500 appels d'événements si le programme n'est pas appelé en temps opportun pendant l'exécution.EventLoopSi vous supprimez le cache, vous perdez 500 appels d'événements plus récents.EventLoopL'appel d'une fonction n'affecte pas le fond du systèmewebsocketLa liste de sauvegarde de la cache n'est pas affectée.exchange.GoLes caches de fonctions parallèles, par exemple, nécessitent toujours d'utiliser leurs propres méthodes pour extraire les données.EventLoopLa fonction ne peut pas retourner les données qui ont déjà été extraites.EventLoopUne fonction produit un événement de retour.

EventLoopLa fonction est principalement utilisée pour informer la couche de stratégie lorsque la couche inférieure du système reçoit de nouvelles données réseau.EventLoopLorsque la fonction renvoie un événement, il suffit de parcourir toutes les sources de données.websocketLes réseaux sociauxexchange.GoLes objets créés tentent d'obtenir des données.Liens vers les bibliothèques

Dans la fonction principalemain()L'événement du fil principal est écouté lors de l'appel central.JavaScriptLes stratégies utilisées pour écrire des langues ne sont pas les mêmes.__Thread()Les fils créés par les fonctions peuvent également être appelés dans les fonctions d'exécution du fil pour écouter les événements du fil en cours.

function main() {
    var routine_getTicker = exchange.Go("GetTicker")
    var routine_getDepth = exchange.Go("GetDepth")
    var routine_getTrades = exchange.Go("GetTrades")
    
    // Sleep(2000),如果这里使用Sleep语句,会导致之后的EventLoop函数错过之前的事件,因为等待了2秒,并发的函数

Plus de

Je ne sais pas.Il y a un problème: est-ce que la fonction C doit être répétée ou seulement une fois?

Je vous en prie._C ((function, args...) est-ce le 3s par défaut? Est-ce que je peux modifier le paramètre par défaut en plaçant _CDelay ((1000) directement avant _C ((function, args...)?

Le repas?Cluster: si vous créez 1000 robots en même temps, et sans stress, vous pouvez créer plusieurs hôtes pour diviser les tâches. Y a-t-il des exemples de code pour créer des clusters? Comment créer plusieurs hôtes pour diviser les tâches

- Je suis désolée.Log ((talib.help (('MACD')); peut être utilisé uniquement sous js, il n'y a pas d'attribut talib.help sous python...

Cjz140La différence entre la fonction C (Args) et la fonction Sleep est que je pense que c'est la même chose.

3263243yComment effacer le filtre d'erreur après le filtre d'erreur?

Je ne sais pas.Si vous souhaitez utiliser une bibliothèque tierce, quelle est la solution?

Je ne sais pas.Qu'est-ce que la classe mère doit remplir si vous voulez hériter de la nouvelle classe définie par l'objet de l'échange?

ethanwuY a-t-il des outils de débogage locaux?

PénélopeJe ne sais pas si c'est le cas, mais j'aimerais savoir ce que c'est.

PénélopePourquoi la fonction sell est grise, est-ce que la fonction de représentation n'est plus disponible?

PénélopePourquoi la fonction sell est grise, est-ce que la fonction de représentation n'est plus disponible?

PénélopeJS n'est pas un langage, haha, mais je veux savoir si je peux supporter ES6.

PénélopeJS n'est pas un langage, haha, mais je veux savoir si je peux supporter ES6.

Don.Comment écrire la ligne médiane du volume?

la tortueSi vous achetez sur exchange.Buy.1000 au prix du marché, qu'est-ce qui vous revient si vous échouez?

Le fils de NingCette nouvelle police est superbe.

l'hippopotameLe réseau de test de Bitmex (testnet.bitmex.com) dispose également d'une interface API, mais actuellement, les échanges ne peuvent sélectionner que la station principale de Bitmex, dont l'adresse de documentation API est https://testnet.bitmex.com/app/apiOverview. Comment soutenir?

C'est pas vrai.Var ret1 = exchanges[0].IO (("api", "future_estimated_price", "symbol=btc_usd"); Log (('ok futures estimé prix de livraison', ret1); https://dn-filebox.qbox.me/d1ed268c1e75753c5d289447d279aa9d81e41b5f.png Pourquoi appeler les interfaces de fonctionnalités d'autres échanges et écrire une erreur?

allenefrostlineVous voulez savoir quelle est la différence entre realTicker et Ticker? Récemment, la stratégie de réécriture de l'appareil est apparue en même temps, mais il ne semble pas y avoir de mention dans la première API.

les visionsBonjour, en tant que développeur python, que pensez-vous que votre documentation API écrive? Certaines interfaces de champs fonctionnent bizarrement, pouvez-vous écrire un document comme githubpage et readdocs?

allenefrostlineGetAccount: [EAPI: Rate limit exceeded] Vous voulez savoir comment cela fonctionne?

Zjx2314Ne pas prendre en charge StochRSI, peut-on l'ajouter dès que possible?

YhfggLes scripts sont-ils sur leur propre serveur Ali Cloud ou sur le cluster botvs?

YhfggQuelle version de python utilisez-vous?

très bien.L'interprétation de GetFee devrait être de renvoyer une structure de Fee, en moins d'un composant.

Je suis désolée.Est-il possible d'appeler talib avec les méthodes de js?

YhfggRechercher une documentation python

Je suis désolé.Le fond de code de l'éditeur stratégique peut-il être noir?

Don.Comment configurer les résumés dans les messages WeChat des robots?

Numéro: fouEst-il possible d'ajouter un champ de prix égal à la structure des commandes?

Le petit.GetOrders: Retrouve tous les ordres en suspens, renvoie une structure d'arithmétique d'ordres, dans le commerce chinois de Bitcoin ETH, ne renvoie que les 10 articles les plus récents.

YhfggLes fonctions mathématiques nécessaires à la théorie de la probabilité statistique, où les utiliser?

Je vous en prie.Que signifie la valeur de retour de la fonction $.Cross ((x, y)?

Ma grand-mère l'appelaitLe LogReset efface tous les journaux et peut utiliser un paramètre numérique pour spécifier les entrées réservées. Comment faire pour supprimer les derniers logs?

- Je ne sais pas.La fonction CORRE dans talib ne semble pas avoir été transférée ou a-t-elle été oubliée?

La montagne pauvre de LiangyangIl semble qu'il n'y ait pas de fonctionnalité de référence d'indicateur!

Petite ou grandeComment le temps de lecture de la ligne k est-il traduit par le temps actuel oh, je ne comprends pas, trop long, résolu, merci

Petite ou grandeJe n'arrive pas à écrire les nombres dans les entrées avec records.remove (records[0])

le serpentLa ligne K horaire est la ligne habituelle, mais comment appeler ATR pour la ligne K journalier?

le serpentLa ligne K horaire est la ligne habituelle, mais comment appeler ATR pour la ligne K journalier?

57278863Apprenez comment les futures traditionnelles obtiennent des prix et des commandes, désolé, les racines sont minces

le cerveauL'exemple de la négociation traditionnelle de contrats à terme!

Petite ou grandeZero, peux-tu écrire un exemple de négociation traditionnelle de contrats à terme?

Petite ou grandeComment imprimer l'état de stockage de plusieurs objets blancs en même temps, comment imprimer mon [object object], comment obtenir l'état de stockage de plusieurs objets et des objets blancs, ainsi que GetTicker (), comment obtenir la semaine, la semaine suivante et le trimestre de la semaine.

C'est pas vrai.Est-ce que les échanges à terme peuvent obtenir des marchés avec GetTicker (??), et retourner des marchés de ce type de contrat (?? la semaine, la semaine suivante...)?

Ils vendentQuel est l'indicateur StochRSI que vous pouvez ajouter?

le momoxPour annuler une commande en fonction du numéro de commande, retournez true ou false, et demandez true= la cellule a été annulée avec succès, non?

le momoxCette méthode permet de stocker des variables globales qui peuvent être utilisées pour partager des données entre différentes stratégies.

- Je ne sais pas.Une vague de popularité

NulVous pouvez réinitialiser les journaux de revenus avec LogProfitReset.

- Je vous en prieEst-il possible de copier directement l'EA?

Je suis un homme.J'ai trouvé cette plateforme géniale, superbe, beaucoup de communication en groupe.

Petite ou grandeQuelle est cette langue, y a-t-il des ressources pour l'apprendre?

Jeux vidéoUne erreur de données pendant une semaine et je ne peux pas connecter le robot.

Je vous en prie.L'indicateur TA est-il seulement un calcul du prix de clôture?

- Je suis désolé.Salut, tout le monde.

Le petit rêveLa fonction _C essaie sans réfléchir jusqu'à ce que le résultat soit obtenu avec succès.

Le petit rêveLa bibliothèque talib de python doit être installée. https://www.botvs.com/bbs-topic/669 peut être consulté dans ce post.

Le petit rêveSleep est le nombre de millisecondes pendant lesquelles le programme ne fait rien et attend que le paramètre soit défini, _C est la fonction qui appelle à nouveau le paramètre une fois transmis.

Le petit rêveSans héritage, JS est directement enveloppé dans l'objet {name: "nouveau objet", old_exchange : exchange[0],...... }

Le petit rêveL'éditeur local, le plugin de synchronisation à distance, qui est essentiellement un éditeur local, le débogage à distance.

Le petit rêveVous pouvez venir sur le QQ, ^^, c'est facile à discuter~

Le petit rêveDans la documentation de l'API, grise signifie que cette fonction n'a pas trop d'explication étendue, elle est affichée en gris, la représentation en bleu a plus d'explications, c'est tout.

Le petit rêveL'ES6 n'est pas supporté pour le moment ^^

Le petit rêveJe peux aller au groupe QQ, vous pouvez me décrire le problème, je vais y répondre ^^

Le petit rêveLe message de retour est un message d'erreur, et la commande ne sera pas effectuée (en fait, c'est acheter, pas assez d'argent!).

la tortuePar exemple, OKCoin, si la quantité achetée est supérieure à celle détenue, que revient-il?

Le petit rêveJe suis en train d'essayer de trouver un numéro de commande sur lequel je peux retourner un numéro de commande sur OK Futures.

NulLes transactions sont déjà prises en charge lors de l'exécution, vous devez télécharger le dernier hôte. Prise en charge de la documentation API détaillée Bter/Poloniex. Description de la fonction de transaction dans la barre ci-dessous (en supprimant le cache du navigateur et en le rafraîchissant si vous ne le voyez pas)

Le petit rêveJe suis QQ, je vais vous aider à trouver votre problème.

Familles occupéesSi vous avez besoin d'une liste blanche, j'ai configuré l'adresse IP de l'hôte.

Le petit rêveC'est un lien sous-jacent qui n'a pas été créé. Le serveur n'a pas répondu.

Familles occupéesCe qui est embarrassant, c'est que les stratégies que j'ai pu exécuter ont échoué à l'époque des bitcoins et que GetAccount n'a pas pu accéder à GetAccount: Post http://api.btc38.com/v1/getMyBalance.php: read tcp 192.168.0.227:58596->211.149.148.144:80: wsarecv: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. 2017-05-23 21:08:24 L'ère des bitcoins Une erreur GetAccount: timeout 2017-05-23 21:08:02 L'ère des bitcoins Une erreur GetAccount: timeout 2017-05-23 21:07:40 L'ère des Bitcoins Une erreur s'est produite sur GetAccount: timeout 2017-05-23 21:07:20 Relancer le jeu Est-ce que c'est une question de liste blanche d'IP?

Le petit rêveLes serveurs de l'échange ne répondent pas et le protocole TCP n'a pas été mis en place.

Familles occupéesUne tentative de connexion a échoué parce que la partie connectée n'a pas correctement répondu après une période de temps.

Le petit rêveBonjour! Il s'agit de la fonction exchange.IO ((api, ApiName, Args) qui n'est pas prise en charge, voir https://www.botvs.com/bbs-topic/812

Familles occupéesUne tentative de connexion a échoué parce que la partie connectée n'a pas répondu correctement après une période de temps,

Familles occupéesL'ère des bitcoins ne le soutient-elle pas?

Le petit rêvePour les personnes qui ont besoin d'aide, veuillez cliquer sur le lien suivant: https://dn-filebox.qbox.me/a709b30c6cc0a3565234b9e0c99b073f7ba8b454.png Il est normal que ce soit le cas.

Le fils de NingPar exemple, je voulais faire une transaction en poloniex, mais il n'y a que quelques monnaies prises en charge par BOTvs, et exchange.IO ne semble pas prendre en charge le réseau P.

Le petit rêveVous pouvez appeler exchange.IO.

Le fils de NingQu'en est-il des API qui nécessitent une vérification de compte?

Le petit rêveSi l'API ne nécessite pas de vérification de compte, elle peut être utilisée avec httpQuery (voir la documentation BotVS pour plus de détails).

Le petit rêveLes paramètres de l'API HttpQuery peuvent être transmis: https://www.okcoin.com/api/v1/future_estimated_price.do?symbol=btc_usd, c'est tout. Pour les API d'échange qui ne nécessitent pas de vérification de compte, utilisez directement la fonction HttpQuery de la plate-forme. Le blogueur a également publié un article intitulé:

les visionsMerci beaucoup, j'espère que vous aurez une excellente documentation de l'API.

Le petit rêveSi vous voulez savoir où l'API de realTicker a été vue?

Le petit rêveIl est également possible de télécharger des fichiers sur le serveur de téléchargement. La documentation de l'API est en JavaScript. Les articles décrits dans la version python sont placés en haut de la page de la communauté de discussion sur le plugin.

NulBonjour, merci pour l'idée, la documentation de l'API est en cours de refonte.

Le petit rêveBonjour ~ il est indiqué que la fréquence d'accès est dépassée. Pour les personnes qui ont besoin d'aide, veuillez cliquer sur le lien suivant: https://dn-filebox.qbox.me/a09498920d04cac62624b7438a058d2098d8fb00.png La fonction Sleep (1000) est-elle utilisée dans la stratégie? Cette fonction 1000 permet à un programme de suspendre une seconde par tour, qui peut être réglée par lui-même, dans le but de contrôler la fréquence d'accès aux API du programme, car certaines plateformes de change ont fixé une limite d'accès maximale, une certaine durée au-delà d'une certaine fréquence d'accès sera refusée, bloquant l'adresse IP.

Le petit rêveIl est également possible de télécharger des fichiers sur les réseaux sociaux. J'ai écrit personnellement que les indicateurs de STOCHRSI qui ont été comparés à OK sont d'accord, c'est que la vitesse est un peu lente et doit être optimisée pour le moment.

NulVous pouvez choisir d'effectuer des réponses sur le serveur fourni par botvs ou sur le serveur de votre hôte, version 2.7.5.

Le petit rêveIl y a aussi des photos de l'événement.

Le petit rêveMaintenant, vous pouvez configurer votre propre style de fond.

Le petit rêveLa documentation python est en cours d'écriture.

Le petit rêveIl y a aussi une bibliothèque de supports talib.

Je ne sais pas. https://www.botvs.com/bbs-topic/276

Le petit rêveIl semble y avoir un exemple dans Strategy Square, https://www.botvs.com/strategy/15098

NulL'attribut AvgPrice d'Order peut être consulté par les échanges qui le supportent, les échanges qui ne le supportent pas seront toujours 0

YhfggComment les sources tierces sont-elles citées?

NulMathJS ne peut pas répondre à cette demande, il ne peut que rechercher des stratégies de copie et d'importation de bibliothèques tierces. Pour accélérer la compilation, le système n'a que quelques bibliothèques intégrées.

Le petit rêveIl y a un problème dans le groupe où vous pouvez m'envoyer un message - je suis en ligne.

Je vous en prie.Merci beaucoup.

Le petit rêveVous pouvez consulter les annotations de la bibliothèque de crypto-monnaie et analyser les annotations de la fonction $.Cross.

NulVous ne pouvez pas supprimer les derniers articles, vous ne pouvez que conserver les derniers articles, supprimer tous les anciens.

le cerveauPour obtenir chaque position en position[i], position est une matrice

Le fils de NingLes données de l'échange.GetRecords (Période_D1);

le cerveauMon futur traditionnel est toujours de répliquer GetAccount: not login, "pas de mot de passe, pas de connexion".

NulPar défaut, c'est la semaine. Pour obtenir le type de contrat spécifié, vous devez d'abord configurer le type de contrat.

NulComme vous pouvez le voir, cette valeur est la valeur de retour de l'action d'annulation de l'ordre retourné par l'échange, mais l'annulation réelle n'est pas annulée, cela dépend de la façon dont elle est traitée à l'intérieur de l'échange.

le momox3q

NulNon, c'est une séparation.

Je vous en prie.Bien sûr que non, c'est exclusif à MT4.

NulLes ressources JavaScript sont partout sur le web.

Ils vendentVotre problème a-t-il été résolu?

NulLa plupart du temps, les données transmises peuvent être directement des enregistrements ou une matrice de prix pur.