任意のK線周期管理テンプレート (最近更新20180627) を変換する

作者: リン・ハーン中本, 日時: 2017-05-22 21:08:57
タグ:エクステント-API

2017年1114日に更新されました a. Open が検索できない問題,前回のK線に問題があるため,レコード配列へのアクセス・クロスボアリングが原因である. 更新日: 2017年11月13日 a. 開始時間の誤ったK線組み合わせをフィルタリングする b. 時間間隔の誤ったK線組み合わせをフィルタリングする 更新日:2017年6月22日 a. RecordsManagerでは,異なるK線を区別するためのName参数を追加しました. b. Fix 固定数K行の周期が1つの新しいK行の周期に満たないとき,Timeが計算が誤った問題

更新日:2017年5月31日 a. 修正 Volume 計算の誤り

  1. 小小夢から"任意のK線周期変換"のテンプレートを修正

原則:

  • 固定K線の周期を得て,任意の固定K線の整数の何倍もの新しいK線の周期を合成します.

機能:

  • 基本K線を任意のK線周期に変換する
  • 暫定的にサポートされていません 秒級

制限:

  • 新K线周期必须是固定K线周期的整数倍.
  • 固定K線周期は1min,3min,5min,15min,30min,新しいK線周期も分で<60でなければならない.
  • 固定K線周期は1時間であり,新しいK線周期も1時間で<24でなければならない.
  • 固定K線周期は1dayで,新しいK線周期も1dayでなければなりません.
  • 固定されたK線周期の数が >=2になる必要があります. 試行錯誤や問題がある場合はコメントを歓迎します.

この関数は, $.RecordsManager ((NewCycleMS, Name) は,新しいサイクルマネージャーを作成しました. NewCycleMSは,新しいK線周期のミリ秒数.デフォルト ((1000)6060*2) 2時間 Name: このK線を管理する名前指定 K線管理者に戻る $.AssembleRecords (レコード,BaseCycleMS) records: 取得したオリジナルレコード BaseCycleMSは固定K線周期のミリ秒で,デフォルトで固定レコードで計算する. 新しいK線周期のレコードを返します. $.GetRecordsTable ((n) は,新しいK行の最新のN項目を取得し,すべての項目をデフォルトで出力します.出力はLogStatusの出力に便利な table型です. 基本的な情報を得るために,


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


関連性

もっと

ゼロザキK線のタイミングが間違っています ありがとうございました. この4時間の周期で得られるデータは以下の通りです. `` 2018-07-30 19:00:00.000+08:00 8162.42 8187.69 8200 8156.84 681.53875929 フォローする 2018-07-30 12:00:00.000+08:00 8192.91 8185.3 8209.35 8151 902.81758958 フォローする 2018-07-30 08:00:00.000+08:00 8213.11 8154.49 8225.18 8051 899.96507317 2018-07-30 04:00:00.000+08:00 8214.25 8191.52 8229.08 8190.03 879.26269857 フォローする 2018-07-30 00:00:00.000+08:00 8234.88 8185.32 8247.36 8170.04 817.78392428 フォローする `` 7日間周期で,次のデータが出ています: `` 2018-08-05 08:00:00.000+08:00 8213.11 8186.16 8278.23 8051 7869.96734215 公式サイト 2018-07-29 08:00:00.000+08:00 8235.84 8213.63 8301.2 8116.8 20943.43495 フォローする 2018-07-28 08:00:00.000+08:00 8187.47 8236.39 8245.23 8070 21465.51463651 フォローする 2018-07-27 08:00:00.000+08:00 7930.92 8188.83 8278 7800.44 22985.16836742 公式サイト 2018-07-26 08:00:00.000+08:00 8171.44 7936.88 8316.49 7850.88 22644.64610719 フォローする 2018-07-25 08:00:00.000+08:00 8404.91 8171.44 8485 8050 22036.92873654 フォローする 2018-07-24 08:00:00.000+08:00 7715.53 8404.95 8498.04 7695.05 23595.19928712 フォローする 2018-07-23 08:00:00.000+08:00 7395.57 7716.12 7813 7370.26 27205.92883481 フォローする 2018-07-22 08:00:00.000+08:00 7402.1 7395.14 7585.15 7330.64 26186.61248972 公式サイト 2018-07-21 08:00:00.000+08:00 7326.6 7404 7450 7210 28545.21532011 2018-07-20 08:00:00.000+08:00 7472.61 7326.59 7691.67 7265.14 28703.79798543 詳細はこちら `` コード: `` main ((() {の関数について これは5分です. const period_M5 = 1000*60*5 について この数値は, const period_H4 = 1000*60*60*4 この数値は, 周回線は const period_D7 = 1000*60*60*24*7 この数値は, const period = [ 変数について period_M5 は, period_H4 は, 周期_D7 ありがとうございました. 文字列を表示します. const tables = periods.map ((period=>{) について let records = ゼロです if (period>period_D1) { となるように records = exchange.GetRecords ((PERIOD_D1)) について ログ (日経レベル, records.length) } else if (period>period_H1) { 任意の時間帯に records = exchange.GetRecords ((PERIOD_H1)) について ログ (時間軸レベル, records.length) { else } { ほかに } records = exchange.GetRecords ((PERIOD_M1)) について Log (分行レベル, records.length) ありがとうございました. const recordManager = $.RecordsManager ((period) は,このリストのリストを表示しています. const newRecords = recordManager.AssembleRecords ((records, period) 記録,期間) 記録,記録,記録,記録,記録,記録,記録,記録,記録,記録 const table = recordManager.GetRecordsTable (コンストテーブル = レコードマネージャー.Getレコードテーブル) return table 返却テーブル (笑) LogStatus ((`\` ${JSON.stringify(tables) }\``) スリープ ((60*1000) ありがとうございました. ありがとうございました. ``

グイグイ17f211 行, isFirstFind を関数内に宣言した場合else の部分は削除できます. isFirstFind が true になるたびに,最初のブランチが入力されるたびに,Log で確認できます.

ジャオチェンTypeError: undefined at main (__FILE__:525) のプロパティ 'Time' を読み取れない 基本的には,実行した1日以内にエラーが表示され,生成されたK線がTimeを見つけられない場合もあります.

中本const newRecords = recordManager.AssembleRecords ((records, period) 記録,期間) 記録,記録,記録,記録,記録,記録,記録,記録,記録,記録 書き出せない (書き出さないと,プログラムがK行間をrekordsで計算する) または,recordsのK行間をミリ秒数で書き出せる.

中本const newRecords = recordManager.AssembleRecords ((records, period) 記録,期間) 記録,記録,記録,記録,記録,記録,記録,記録,記録,記録 記号の時間間隔をミリ秒数で書くことができます. 記号の時間間隔をミリ秒数で書くことができます.

ザルカヒックス復元が早期に開始されたことを確認したので,コードにログインしてみてください.

グイグイ17f計算の重複を避けるためでしょうか? しかし,外に出ると,間もなく新しいデータが得られなければ,計算の誤りが生じるのでしょうか?

中本記録管理者 (RecordsManager) とアセンブル記録 (AseembleRecords)) のパラメータを教えて下さい.

中本私は,その頃の論理を理解できず,研究や改変を重ねて研究した.

ザルカヒックスmain:98:14 - TypeError: Cannot read property 'length' of null / main:242:57 TypeError: cannot read property 'Time' of undefined 定義されていないプロパティの長さを読み取れない この問題も起こります

中本変えてみる時間があるので,次の問題を起こしたら,元のK線と新しいK線を,再現してみます.

ジャオチェン解りません.コードのほとんどは,何が問題なのかはわかりませんが,小夢の原稿の合成テンプレートは,うまく使えます.

中本固有のK線と新しいK線の設定は? 私はそれを使用し,何ヶ月も実行し,問題ありません.