资源加载中... loading...

转换任意K线周期管理模板(最近更新20180627)

Author: 中本姜, Date: 2017-05-22 21:08:57
Tags: Extent-API

更新于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线周期毫秒数. 默认(10006060*2) 2hour. Name: 为该K线管理指定名字 返回K线管理器 $.AssembleRecords(records, BaseCycleMS) records: 拿到的原始records BaseCycleMS 为固定K线周期毫秒,默认用固定records进行计算 返回新K线周期的records $.GetRecordsTable(n) 得到新K线最新的N个条目, 默认输出所有条目, 输出为table类型,便于LogStatus输出 $.Get***** 获得一些基本信息


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

template: strategy.tpl:40:21: executing "strategy.tpl" at <.api.GetStrategyListByName>: wrong number of args for GetStrategyListByName: want 7 got 6