Convertissez le modèle de gestion de cycles de ligne K aléatoire ((récemment mis à jour 20180627)

Auteur:Le moteur, Date: 22 mai 2017 à 21h08
Les étiquettes:Extent API

Mise à jour en 2017 1114 a. Résoudre le problème Open ne trouve pas, causé par l'accès à la frontière de l'arithmétique des records, causé par un problème avec l'accès à la frontière de la ligne K précédente. Mise à jour en 20171113 a. Filtre les combinaisons de lignes K dont la date de début est incorrecte b. Filtrer les combinaisons de K-strings incorrectes avec des intervalles de temps Mise à jour en 2017622 a. RecordsManager ajoute le paramètre NAME pour distinguer les différentes lignes K b. Correction d'un problème de calcul incorrect du temps lorsque le nombre de lignes K fixes ne remplit pas un nouveau cycle de lignes K

Mise à jour en 2017531 a. correction d'erreur de calcul du volume

  1. Modifier le modèle de conversion des cycles de lignes K aléatoires de Little Dream

Le principe:

  • On obtient un cycle de K lignes fixes, puis on synthétise un nouveau cycle de K lignes de plusieurs fois l'intégralité de K lignes fixes

Fonction:

  • Conversion de la ligne K de base en une ligne K de cycle aléatoire
  • Temporairement non pris en charge

Restrictions:

  • 新K线周期必须是固定K线周期的整数倍.
  • Les cycles de ligne K fixes sont de 1min, 3min, 5min, 15min, 30min, les cycles de ligne K nouveaux doivent également être de minutes et <60
  • Le cycle fixe de la ligne K est de 1 heure, le nouveau cycle de la ligne K doit également être d'une heure et < 24
  • Le cycle fixe de la ligne K est de 1 jour, le nouveau cycle de la ligne K doit également être de jour.
  • Le nombre de cycles de la ligne fixe K obtenu chaque fois doit être > = 2 La version d'essai, si vous avez des bugs, des problèmes, merci de nous laisser un commentaire.

La fonction de sortie est: $.RecordsManager ((NewCycleMS, Name) crée un nouveau gestionnaire de cycles NewCycleMS compte les millisecondes pour les cycles de la nouvelle ligne K. Par défaut ((10006060 fois 2) 2 heures. Name: Donner un nom pour gérer la ligne K Retourner à l'administrateur de ligne K Le code de l'appareil est le même que celui de l'appareil. records: les enregistrements originaux obtenus BaseCycleMS pour les millisecondes de cycles fixes de lignes K, calculé par défaut avec des enregistrements fixes Retourne les records pour le nouveau cycle de ligne K $.GetRecordsTable ((n) obtient les N entrées les plus récentes de la nouvelle ligne K. Par défaut, toutes les entrées sont exportées. Pour obtenir des informations de base, cliquez sur le lien suivant.


/*backtest
  period: 60
 */
/*
20180627
    修改了天无法整合的bug
20180118
    屏蔽掉一些log输出
更新于20171114
    a. 解决Open找不到问题,是record数组访问越界造成的,访问越界是之前的K线有问题导致的。
更新于20171113
    a. 过滤掉起始时间不正确的k线组合
    b. 过滤掉时间间隔不正确的k线组合
更新于20170622
     a. RecordsManager 增加Name参数,便于区分不同的K线
     b. Fix 当固定K线数目不满一根新K线周期时,Time计算不正确的问题

更新于20170531
    a. fix Volume计算错误

1. 修改自小小梦的"转换任意K线周期" 模板

原理:
  - 获得固定K线的周期,然后合成任意固定K线整数倍的新K线周期

功能:
  - 转换基础K线为任意K线周期
  - 暂时不支持 秒级别

限制:
   - 新K线周期必须是固定K线周期的整数倍.
   - 固定K线周期为1min, 3min, 5min, 15min, 30min, 新K线周期也必须是分钟且<60
   - 固定K线周期为1hour, 新K线周期也必须是小时且<24
   - 固定K线周期为1day, 新K线周期也必须是天
   - 每次获得的固定K线周期数目必须>=2
测试版本,如有BUG ,问题 欢迎留言。

输出函数:
    $.RecordsManager(NewCycleMS, Name) 生成新周期管理器
        NewCycleMS 为新K线周期毫秒数. 默认(1000*60*60*2) 2hour.
        Name: 为该K线管理指定名字
        返回K线管理器
    $.AssembleRecords(records, BaseCycleMS) 
        records: 拿到的原始records
        BaseCycleMS 为固定K线周期毫秒,默认用固定records进行计算
        返回新K线周期的records 
    $.GetRecordsTable(n) 得到新K线最新的N个条目, 默认输出所有条目, 输出为table类型,便于LogStatus输出
    $.Get***** 获得一些基本信息
*/
function EasyReadTime(millseconds) {
    if (typeof millseconds == 'undefined' ||
        !millseconds) {
        millseconds = new Date().getTime();
    }
    var newDate = new Date();
    newDate.setTime(millseconds);
    return newDate.toLocaleString();
}

var cloneObj = function(obj) {                             // 深拷贝 对象函数
    var str, newobj = obj.constructor === Array ? [] : {};
    if (typeof obj !== 'object') {
        return;
    } else if (JSON) {
        str = JSON.stringify(obj);                         //系列化对象
            newobj = JSON.parse(str);                      //还原
    } else {
        for (var i in obj) {
            newobj[i] = typeof obj[i] === 'object' ?
                cloneObj(obj[i]) : obj[i];
        }
    }
    return newobj;
};

var DAY = 0;
var HOURS = 1;
var MINUTES = 2;

function GetDHM(objTime, BaseCycle, NewCycleForMS){
    var ret = [];
    if(BaseCycle % (1000 * 60 * 60 * 24) === 0){
        ret[0] = objTime.getDate();
        ret[1] = DAY;
    }else if(BaseCycle % (1000 * 60 * 60) === 0){
        ret[0] = objTime.getHours();
        ret[1] = HOURS;
    }else if(BaseCycle % (1000 * 60) === 0){
        ret[0] = objTime.getMinutes();
        ret[1] = MINUTES;
    }
    if(NewCycleForMS % (1000 * 60 * 60 * 24) === 0){
        ret[2] = DAY;
    }else if(NewCycleForMS % (1000 * 60 * 60) === 0){
        ret[2] = HOURS;
    }else if(NewCycleForMS % (1000 * 60) === 0){
        ret[2] = MINUTES;
    }
    return ret;
}

function SearchFirstTime(ret, BaseCycle, NewCycleForMS){
    if(ret[1] === DAY && ret[2] === DAY){ 
        var array_day = [];
        for(var i = 1 ; i < 29; i += (NewCycleForMS / BaseCycle)){
            array_day.push(i);
        }
        for(var j = 0 ; j < array_day.length; j++ ){
            if(ret[0] === array_day[j]){
                return true;
            }
        }
    }else if(ret[1] === HOURS && ret[2] === HOURS){
        var array_hours = [];
        for(var i = 0 ; i < 24; i += (NewCycleForMS / BaseCycle)){
            array_hours.push(i);
        }
        for(var j = 0 ; j < array_hours.length ; j++){
            if(ret[0] === array_hours[j]){
                return true;
            }
        }
    }else if(ret[1] === MINUTES && ret[2] === MINUTES){
        var array_minutes = [];
        for(var i = 0; i < 60; i += (NewCycleForMS / BaseCycle)){
            array_minutes.push(i);
        }
        for(var j = 0; j < array_minutes.length; j++){
            if(ret[0] === array_minutes[j]){
                return true;
            }
        }
    }else{
        throw "目标周期与基础周期不匹配!目标周期毫秒数:" + NewCycleForMS + " 基础周期毫秒数: " + BaseCycle;
    }
}

function Calc_High(AssRecords, n, BaseCycle, NewCycleForMS){
    var max = AssRecords[n].High;
    for(var i = 1 ; i < NewCycleForMS / BaseCycle; i++){
        max = Math.max(AssRecords[n + i].High, max);
    }
    return max;
}

function Calc_Low(AssRecords, n, BaseCycle, NewCycleForMS){
    var min = AssRecords[n].Low;
    for(var i = 1 ; i < NewCycleForMS / BaseCycle; i++){
        min = Math.min(AssRecords[n + i].Low, min);
    }
    return min;
}

function _RecordsManager(NewCycleForMS, Name) {
    if (typeof NewCycleForMS == 'string') {
        this._NewCycleForMS = 1;
        var arrayNum = NewCycleForMS.split("*");
        for(var indexNum = 0 ; indexNum < arrayNum.length ; indexNum++){
            this._NewCycleForMS = this._NewCycleForMS * Number(arrayNum[indexNum]);
        }
    } else {
        this._NewCycleForMS = NewCycleForMS;
    }
    this._Name = "";
    if (Name) {
        this._Name = Name;
    }
    this._Records = new Array();

    this.GetNewCycleForMS = function() {
        return this._NewCycleForMS;
    };
    
    this.GetRecords = function() {
        return this._Records;
    }

    this.AssembleRecords = function(records, BaseCycle) {
        var NewCycleForMS = this._NewCycleForMS;
        var AssRecords = records.slice(0); // 深拷贝
        var AfterAssRecords = [];
        
        if (!records || records.length == 0) {
            Log("record 为空@!");
            return records;
        }
        if(records.length < 2){
            throw (!records) ? "传入的records参数为 错误" + records : "基础K线长度小于2";
        }
        if (typeof BaseCycle === 'undefined') {
            BaseCycle = records[records.length - 1].Time - records[records.length - 2].Time;
        }
        if(NewCycleForMS % BaseCycle !== 0){
            //Log(EasyReadTime(records[records.length - 1].Time), EasyReadTime(records[records.length - 2].Time));
            //Log("目标周期‘", NewCycleForMS, "’不是 基础周期 ‘", BaseCycle, "’ 的整倍数,无法合成!");
            return null;
        }
        if(NewCycleForMS / BaseCycle > records.length){
            Log("records: ", records, "NewCycleForMS: ", NewCycleForMS, ", BaseCycle: ", BaseCycle);
            throw "基础K线数量不足,请检查是否基础K线周期过小!";
        }
    
        // 判断时间戳, 找到 基础K线  相对于 目标K线的起始时间。
        var objTime = new Date();
        var isFirstFind = true;
        var FirstStamp = null;
        for (var i = 0; i < AssRecords.length; i++) {
            objTime.setTime(AssRecords[i].Time);
            var ret = GetDHM(objTime, BaseCycle, NewCycleForMS); 
            
            if (isFirstFind === true && SearchFirstTime(ret, BaseCycle, NewCycleForMS) === true) {
                FirstStamp = AssRecords[i].Time;
                for (j = 0; j < i; j++) {
                    AssRecords.shift();        // 把目标K线周期前不满足合成的数据排除。
                }
                isFirstFind = false;
                break;                         // 排除后跳出
            }else if(isFirstFind === false){
                if((AssRecords[i].Time - FirstStamp) % NewCycleForMS === 0){
                    for (j = 0; j < i; j++) {
                        AssRecords.shift();    // 把目标K线周期前不满足合成的数据排除。
                    }
                    break;
                }
            }
        }
        var BarObj = {                         // 定义一个 K线柱结构
            Time: 0,
            Open: 0,
            High: 0,
            Low: 0,
            Close: 0,
            Volume: 0,
        };
        var n = 0;
        for (n = 0; n < AssRecords.length - (NewCycleForMS / BaseCycle);) {     // 合成
            /*
            {
            Time    :一个时间戳, 精确到毫秒,与Javascript的 new Date().getTime() 得到的结果格式一样
            Open    :开盘价
            High    :最高价
            Low :最低价
            Close   :收盘价
            Volume  :交易量
            }
            */
            //时间判断
            var is_bad = false;
            var start_time = AssRecords[n].Time;
            var stop_time = AssRecords[n + (NewCycleForMS / BaseCycle) - 1].Time + BaseCycle;
            if (ret[2] != DAY && start_time % NewCycleForMS != 0) {
                //Log("过滤起始时间不正确的k线组合", EasyReadTime(start_time));
                is_bad = true;
            }
            if (stop_time - start_time != NewCycleForMS) {
                //Log("过滤时间间隔不正确的k线组合", EasyReadTime(start_time), EasyReadTime(stop_time));
                is_bad=true;
            }
            if (is_bad) {
                n++;
                continue;
            }
            BarObj.Time = AssRecords[n].Time;
            BarObj.Open = AssRecords[n].Open;
            BarObj.High = Calc_High(AssRecords, n, BaseCycle, NewCycleForMS); 
            BarObj.Low =  Calc_Low(AssRecords, n, BaseCycle, NewCycleForMS); 
            BarObj.Close = AssRecords[n + (NewCycleForMS / BaseCycle) - 1].Close;
            BarObj.Volume = 0;
            for (var j = n; j < n + (NewCycleForMS / BaseCycle); j++) {
                BarObj.Volume += AssRecords[j].Volume;
            }
            AfterAssRecords.push(cloneObj(BarObj));
            n += (NewCycleForMS / BaseCycle)
        }
        
        if (n == 0) {
            BarObj.Time = AssRecords[0].Time;
        } else {
            BarObj.Time = AssRecords[n - (NewCycleForMS / BaseCycle)].Time + NewCycleForMS;  // 最后一根时间不能变,
        }
        BarObj.Open = AssRecords[n].Open;
        BarObj.Close = AssRecords[AssRecords.length - 1].Close;
        BarObj.Volume = AssRecords[n].Volume;
        //BarObj.Volume = 0;
        var max = AssRecords[n].High;
        var min = AssRecords[n].Low;
        for(var index_n = n + 1 ;index_n < AssRecords.length; index_n++){
            max = Math.max(max, AssRecords[index_n].High);
            min = Math.min(min, AssRecords[index_n].Low);
            BarObj.Volume += AssRecords[index_n].Volume;
        }
        BarObj.High = max;
        BarObj.Low = min;
        AfterAssRecords.push(cloneObj(BarObj));
    
        this._Records = AfterAssRecords;
        return AfterAssRecords;
    };

    this.GetKlineName = function () {
        return " " + this._NewCycleForMS / 60 / 1000 + " 分钟K线";
    };

    /* 获得records数据表格*/
    this.GetRecordsTable = function (n) {
        if (typeof n !== 'undefined' && n >=0 ) {
            var records = this._Records.slice(-n);
        } else {
            var records = this._Records.slice(0);
        }
        
        var record_array = new Array();
        for (var i = records.length - 1; i >= 0; i--) {
            var newDate = new Date();
            newDate.setTime(records[i].Time);
            var time_str = newDate.toLocaleString();
            record_array.push([time_str, records[i].Open, records[i].Close,
                               records[i].High, records[i].Low, records[i].Volume]);
        }
        var title = this._Name + " " + this.GetKlineName() + "(" + records.length + "根)";
        var table = {type: 'table', title: title,
                     cols: ['Time', 'Open','Close', 'High', 'Low', 'Volume'],
                     rows: record_array};
        return table;
    }
}

$.RecordsManager = function (NewCycleForMS, Name) {

    if (typeof NewCycleForMS === 'undefined') {
        NewCycleForMS = UI_NewCycleForMS;
    }
    var RecordsManager = new _RecordsManager(NewCycleForMS, Name);
    return RecordsManager;
}
    
function main() {
    var records = exchange.GetRecords();
    while (!records || records.length < 24) {
        records = exchange.GetRecords();
        Sleep(1000);
    }
    
    while (true) {
        records = _C(exchange.GetRecords);
        record_manager0 = $.RecordsManager(UI_NewCycleForMS, "Hello World");
        new_records0 = record_manager0.AssembleRecords(records);
        var table0 = record_manager0.GetRecordsTable();
        
        var BaseCycle = records[records.length - 1].Time - records[records.length - 2].Time;
        record_manager1 = $.RecordsManager(BaseCycle);
        new_records1 = record_manager1.AssembleRecords(records);
        var table1 = record_manager1.GetRecordsTable();
        LogStatus('`' + JSON.stringify([table0, table1, ""]) +'`');
        records = record_manager1.GetRecords();
        //Log(records[records.length-1]);
        Sleep(60000);
    }
}


Relationnée

Plus de

Je ne sais pas.C'est le mauvais temps de la ligne K. Je ne sais pas. Les données obtenues sont les suivantes: Je ne sais pas. 2018-07-30 19:00:00.000+08:00 8162.42 8187.69 8200 8156.84 681.53875929 Le nom de l'équipe a été modifié. 2018-07-30 12:00:00.000+08:00 8192.91 8185.3 8209.35 8151 902.81758958 Le nombre de personnes qui ont été arrêtées pour avoir été violées par un autre policier 2018-07-30 08:00:00.000+08:00 8213.11 8154.49 8225.18 8051 899.96507317 Le nom de famille de la personne concernée 2018-07-30 04:00:00.000+08:00 8214.25 8191.52 8229.08 8190.03 879.26269857 Le nombre de personnes qui ont été arrêtées pour avoir été violées par un autre policier a augmenté. 2018-07-30 00:00:00.000+08:00 8234.88 8185.32 8247.36 8170.04 817.78392428 Le nombre de personnes qui ont été tuées est de 8234.88 Je ne sais pas. Les chiffres sont les suivants: Je ne sais pas. 2018-08-05 08:00:00.000+08:00 8213.11 8186.16 8278.23 8051 7869.96734215 Le nom de l'équipe est le suivant: 2018-07-29 08:00:00.000+08:00 8235.84 8213.63 8301.2 8116.8 20943.43495 Le nom de famille de la personne concernée est 2018-07-28 08:00:00.000+08:00 8187.47 8236.39 8245.23 8070 21465.51463651 Nom du groupe 2018-07-27 08:00:00.000+08:00 7930.92 8188.83 8278 7800.44 22985.16836742 Le nom de l'équipe est le suivant: 2018-07-26 08:00:00.000+08:00 8171.44 7936.88 8316.49 7850.88 22644.64610719 Le nom de l'équipe est le suivant: 2018-07-25 08:00:00.000+08:00 8404.91 8171.44 8485 8050 22036.92873654 Le nom de famille de la personne concernée est 2018-07-24 08:00:00.000+08:00 7715.53 8404.95 8498.04 7695.05 23595.19928712 Le nom de l'entreprise est désigné par le nom de l'entreprise. 2018-07-23 08:00:00.000+08:00 7395.57 7716.12 7813 7370.26 27205.92883481 Le nom de l'équipe est le suivant: 2018-07-22 08:00:00.000+08:00 7402.1 7395.14 7585.15 7330.64 26186.61248972 Nom du groupe 2018-07-21 08:00:00.000+08:00 7326.6 7404 7450 7210 28545.21532011 Le nom de l'équipe est le suivant: 2018-07-20 08:00:00.000+08:00 7472.61 7326.59 7691.67 7265.14 28703.79798543 Nom du groupe Je ne sais pas. Le code: Je ne sais pas. fonction main (() { Il y a cinq minutes. const période_M5 = 1000 fois 60 fois 5 Il y a 4 heures. const période_H4 = 1000 fois 60 fois 60 fois 4 // périphérie const period_D7 = 1000 fois 60 fois 60 fois 24 fois 7 const périodes = [ période_M5, période_H4, période_D7, Je ne sais pas. pendant (true) { const tables = périodes.map ((période=>{ laissez les enregistrements = null si (période>période_D1) { records = exchange.GetRecords ((PERIOD_D1)) est un fichier qui est en cours d'échange. Log (en anglais seulement) } autre si (période>période_H1) { records = exchange.GetRecords ((PERIOD_H1)) est un fichier enregistré qui est un fichier enregistré. Log (Le niveau de la ligne horaire, records.length) Je ne sais pas. records = exchange.GetRecords ((PERIOD_M1)) est un fichier enregistré qui est un fichier enregistré. Log (Le niveau de la ligne de minutes, records.length) Je ne sais pas. const recordManager = $.RecordsManager (en anglais seulement) const newRecords = recordManager.AssembleRecords (enregistrements, période) const table = recordManager.GetRecordsTable (en anglais seulement) table de retour Je ne sais pas. LogStatus (en anglais seulement) Sleep ((60*1000) est un nombre de nombres. Je ne sais pas. Je ne sais pas. Je ne sais pas.

- Je ne sais pas.La partie "else" après la déclaration "isFirstFind" peut être supprimée si elle est faite dans la fonction, car chaque fois que l'on fait "isFirstFind" c'est vrai, et chaque fois que l'on fait "isFirstFind" c'est la première branche.

JiaozhengTypeError: ne peut pas lire la propriété 'Time' de undefined à main (__FILE__:525) En fait, le jour de l'exécution, un tel arrêt d'erreur se produit, la ligne K générée ne trouve parfois pas Time.

Le moteurconst newRecords = recordManager.AssembleRecords (enregistrements, période) Ce n'est pas une phrase mal utilisée. Ce n'est pas une période. On ne peut pas écrire (s'il ne l'est pas, le programme calcule l'intervalle de K lignes avec des enregistrements) ou écrire le nombre de millisecondes d'intervalle de K lignes dans des enregistrements.

Le moteurconst newRecords = recordManager.AssembleRecords (enregistrements, période) Ce n'est pas une période, c'est un nombre de millisecondes d'intervalle de temps dans la ligne K des records.

ZrcahyxJ'ai moi-même confirmé que c'était causé par un démarrage trop précoce de la rétroaction, et je suggère de loger dans le code.

- Je ne sais pas.Est-ce qu'il est possible d'éviter des calculs répétitifs? Mais si on les mettait dehors, si on n'avait pas de nouvelles données pendant un certain temps, cela provoquerait des erreurs de calcul?

Le moteurPourriez-vous m'expliquer quels sont les paramètres donnés dans le RecordsManager et dans l'AssembleRecords, que je peux déboguer?

Le moteurIl est vrai que je n'ai toujours pas compris la logique de Little Dream à l'époque, et j'ai fait des recherches et des modifications.

Zrcahyxmain:98:14 - TypeError: Cannot read property 'length' of null / main:242:57 TypeError: ne peut pas lire la propriété 'Time' de non défini C'est le même problème.

Le moteurEh bien, j'ai le temps de revoir les modifications du code, et si vous avez encore des problèmes, dites la ligne K originale et la ligne K nouvelle, et je vais voir si je peux reproduire.

JiaozhengJe ne sais pas, la plupart du code ne sait pas ce qui ne va pas, mais le modèle synthétique original de Dream Dream fonctionne bien.

Le moteurJe l'ai utilisé pendant des mois et ça marche sans problème.