Convert arbitrary K-line cycle management templates ((most recently updated 20180627)

Author: In the Middle East, Date: 2017-05-22 21:08:57
Tags: Extent-API

Updated at 2017 1114 a. Resolves Open cannot find problem caused by record array access crossing boundary, access crossing boundary caused by previous K-line problem. Updated at 20171113 a. Filters out incorrect K-string combinations with start times b. Filter out incorrect K-line combinations with time intervals Updated at 20170622 a. RecordsManager adds Name parameters to distinguish between different K-lines b. Fix Time calculation incorrect problem when fixed number of K lines does not satisfy one new K line cycle

Updated at 20170531 a. fix Error in calculating the volume

  1. Modify the template for "Convert any K-line cycle" from Little Dream

The principle:

  • Obtain a cycle of fixed K lines and then synthesize a new cycle of K lines of arbitrary fixed K line integers

Features:

  • Convert the base K line to any K line cycle
  • Temporarily unsupported Second level

Restrictions:

  • 新K线周期必须是固定K线周期的整数倍.
  • Fixed K-line cycles are 1min, 3min, 5min, 15min, 30min, new K-line cycles must also be minutes and <60
  • The fixed K-line cycle is 1 hour, the new K-line cycle must also be 1 hour and < 24
  • The fixed K-line cycle is 1 day, the new K-line cycle must also be days.
  • The number of fixed K-line cycles obtained each time must be >=2. The test version, if there are bugs, problems welcome comments.

The output function is: $$.RecordsManager (NewCycleMS, Name) to create a new cycle manager NewCycleMS for millisecond counting of new K-line cycles. Default ((10006060 times 2) 2 hours. Name: Specify a name for this K-line manager Return to the K-line manager .AssembleRecords ((records, BaseCycleMS) is a free and open-source file format. records: Original records obtained BaseCycleMS for fixed K-line cycle milliseconds, computed by default with fixed records Returns records for new K-line cycles $.GetRecordsTable(n) gets the latest N entries in the new K line, outputting all entries by default, outputting as table type, which is easy to output in LogStatus We're going to get some basic information.


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


Related

More

zerozakiI got the K-line timing wrong. What do you think? The four-hour cycle results in: What's up? 2018-07-30 19:00:00.000+08:00 8162.42 8187.69 8200 8156.84 681.53875929 This is a list of all the episodes of the television series The Godfather. 2018-07-30 12:00:00.000+08:00 8192.91 8185.3 8209.35 8151 902.81758958 This is a list of characters who are or were born in the year 2018. 2018-07-30 08:00:00.000+08:00 8213.11 8154.49 8225.18 8051 899.96507317 This is a dynamic list and may never be able to satisfy particular standards for completeness. 2018-07-30 04:00:00.000+08:00 8214.25 8191.52 8229.08 8190.03 879.26269857 This is a list of people who have died as a result of climate change. 2018-07-30 00:00:00.000+08:00 8234.88 8185.32 8247.36 8170.04 817.78392428 This is a list of people who have been killed or died as a result of armed conflict. What's up? The seven-day cycle is as follows: What's up? 2018-08-05 08:00:00.000+08:00 8213.11 8186.16 8278.23 8051 7869.96734215 This is a dynamic list and may never be able to satisfy particular standards for completeness 2018-07-29 08:00:00.000+08:00 8235.84 8213.63 8301.2 8116.8 20943.43495 This is a list of characters who are or were born in the year 2018. 2018-07-28 08:00:00.000+08:00 8187.47 8236.39 8245.23 8070 21465.51463651 This is a dynamic list and may never be able to satisfy particular standards for completeness. 2018-07-27 08:00:00.000+08:00 7930.92 8188.83 8278 7800.44 22985.16836742 This is a dynamic list and may never be able to satisfy particular standards for completeness. 2018-07-26 08:00:00.000+08:00 8171.44 7936.88 8316.49 7850.88 22644.64610719 This is a dynamic list and may never be able to satisfy particular standards for completeness. 2018-07-25 08:00:00.000+08:00 8404.91 8171.44 8485 8050 22036.92873654 This is a dynamic list and may never be able to satisfy particular standards for completeness. 2018-07-24 08:00:00.000+08:00 7715.53 8404.95 8498.04 7695.05 23595.19928712 This is a list of all the episodes of the television series The Godfather. 2018-07-23 08:00:00.000+08:00 7395.57 7716.12 7813 7370.26 27205.92883481 This is a dynamic list and may never be able to satisfy particular standards for completeness. 2018-07-22 08:00:00.000+08:00 7402.1 7395.14 7585.15 7330.64 26186.61248972 This is a list of all the episodes of the television series The Godfather. 2018-07-21 08:00:00.000+08:00 7326.6 7404 7450 7210 28545.21532011 The following is a summary of the results of the poll: 2018-07-20 08:00:00.000+08:00 7472.61 7326.59 7691.67 7265.14 28703.79798543 This is a list of all the different ways 7472.61 7326.59 is credited in the database. What's up? The code is: What's up? function main (() { // five minutes const period_M5 = 1000 times 60 times 5 // 4 hours const period_H4 = 1000 times 60 times 60 times 4 // the circumference const period_D7 is equal to 1000 times 60 times 60 times 24 times 7 const periods = [ period_M5, period_H4, period_D7, I'm not sure. while (true) { const tables = periods.map ((period=>{ let records = null if (period>period_D1) { records = exchange.GetRecords ((PERIOD_D1))) Log (daylight level, records.length) } else if (period>period_H1) { records = exchange.GetRecords ((PERIOD_H1))) Log (("hourline level", records.length) } else { records = exchange.GetRecords ((PERIOD_M1)) is the name of the Log (minute line level, records.length) I'm not sure. Const recordManager = $.RecordsManager ((period) is the name of the file. const newRecords = recordManager.AssembleRecords ((records, period) is the name of the assembly. Const table = recordManager.GetRecordsTable is used return table I know. LogStatus is the name of the file system used by JSON. Sleep ((60 by 1000) I'm not sure. I'm not sure. What's up?

guigui17fIn line 211, if you declare isFirstFind inside the function, the else part can be removed, because every isFirstFind is true, and every entry is the first branch, so you can check Log.

jiaozhengTypeError: cannot read property 'Time' of undefined at main (__FILE__:525) Basically the day of the run, there is such an error message stop, the generated K-line sometimes can't find Time

In the Middle Eastconst newRecords = recordManager.AssembleRecords ((records, period) is the name of the assembly. It's not supposed to be period, it should be not write (if it doesn't, the program will use records to calculate the intervals of K lines), or write the time intervals of K lines in records as milliseconds.

In the Middle Eastconst newRecords = recordManager.AssembleRecords ((records, period) is the name of the assembly. It's not supposed to be period, it's supposed to be unwritten, or it's supposed to be the milliseconds of the time interval in the K line of records.

zrcahyxI've confirmed that this is caused by the retesting of the start time too early, so I suggest logging in the code.

guigui17fIs it to avoid repeated calculations? But if you leave it out if you don't get any new data in the middle of the process, will it cause a calculation error?

In the Middle EastCan you tell me what the parameters are in the RecordsManager and in the AssemblageRecords so I can debug them?

In the Middle EastIt's true that I still couldn't understand the logic of Little Dream at the time, so I did some research and modified it.

zrcahyxmain:98:14 - TypeError: Cannot read property 'length' of null / main:242:57 TypeError: cannot read property 'Time' of undefined The same thing happens.

In the Middle EastWell, I've got time to look at the code, and if there's a problem again, let's say the original K line and the new K line, and I'll see if I can replicate it.

jiaozhengI don't know, most of the code doesn't know what the problem is, but the original synthetic template of DreamWorks works fine.

In the Middle EastWhat's your native K-line and new K-line setup?