임의의 K선 주기를 변환합니다

저자:작은 꿈, 2017-02-16 18:35:13
태그:Extent-API

예제 전략

  • 기본 K선을 임의의 K선 주기로 변환합니다.
  • 일시적으로 지원되지 않습니다 테스트 버전, 버그, 문제 등에 대한 의견은 환영합니다.

// K线周期合成  扩展为 根据基础K线 合成 为任意周期。
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;
var isFirstFind = true;
var FirstStamp = null;

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 AssembleRecords(records, NewCycleForMS) {
    var AssRecords = records.slice(0); // 深拷贝
    var AfterAssRecords = [];
    
    if(!records || records.length < 2){
        throw (!records) ? "传入的records参数为 错误" + records : "基础K线长度小于2";
    }
    var BaseCycle = records[records.length - 1].Time - records[records.length - 2].Time;
    if(NewCycleForMS % BaseCycle !== 0){
        throw "目标周期‘" + NewCycleForMS + "’不是 基础周期 ‘" + BaseCycle + "’ 的整倍数,无法合成!";
    }
    if(NewCycleForMS / BaseCycle > records.length){
        throw "基础K线数量不足,请检查是否基础K线周期过小!";
    }

    // 判断时间戳, 找到 基础K线  相对于 目标K线的起始时间。
    var objTime = new Date();
    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); n += (NewCycleForMS / BaseCycle)) {     // 合成
        /*
        {
        Time    :一个时间戳, 精确到毫秒,与Javascript的 new Date().getTime() 得到的结果格式一样
        Open    :开盘价
        High    :最高价
        Low :最低价
        Close   :收盘价
        Volume  :交易量
        }
        */
        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 = AssRecords[n + (NewCycleForMS / BaseCycle) - 1].Volume;
        AfterAssRecords.push(cloneObj(BarObj));
    }
    
    BarObj.Time = AssRecords[n - (NewCycleForMS / BaseCycle)].Time + NewCycleForMS;  // 最后一根时间不能变,
    BarObj.Open = AssRecords[n].Open;
    BarObj.Close = AssRecords[AssRecords.length - 1].Close;
    BarObj.Volume = AssRecords[AssRecords.length - 1].Volume;
    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.High = max;
    BarObj.Low = min;
    AfterAssRecords.push(cloneObj(BarObj));

    return AfterAssRecords;
}

function main() {                                                    // 测试代码
    var records = exchange.GetRecords();
    while (!records || records.length < 24) {
        records = exchange.GetRecords();
    }
    
    // 处理界面参数,  如果写到自己的策略里面 可以参考下
    var Num_UI_NewCycleForMS = 1;
    var arrayNum = UI_NewCycleForMS.split("*");
    for(var indexNum = 0 ; indexNum < arrayNum.length ; indexNum++){
        Num_UI_NewCycleForMS = Num_UI_NewCycleForMS * Number(arrayNum[indexNum]);
    }
    Log("自定义周期毫秒时间为:", Num_UI_NewCycleForMS);
    

    while(true){
        records = _C(exchange.GetRecords);
        // Log("原始K线数据:长度", records.length, "数据:", records);
        records = AssembleRecords(records, Num_UI_NewCycleForMS);        // 第一个参数是 基础K线, 第二个参数是 要转换的周期的 毫秒数, 1000 * 60 * 20 就是 转换为 20分钟
        // Log("转换后K线数据:长度", records.length, "数据:", records);
        $.PlotRecords(records, 'BTC');
        // throw "stop"; // ceshi
        Sleep(1000);
    }
}

관련

더 많은

만약 3시간 k선을 합쳐서 18시간 라인을 합쳐서 문제가 없다면, 일선을 합쳐서 오류가 발생합니다.

getDHM의 논리 작성에는 약간의 문제가 있고 전체 오류가 있습니다. 목표 주기는 기본 주기와 일치하지 않습니다!

qunxiang_wang안녕하세요, 왜 api에 둥지를 통합하지 않는거죠?

조오안녕하세요, 해결해 줄 수 있나요?

조오왜 OKEX 데이터 재검토를 할 때 K 라인 주기가 1 분을 선택하지만 목표값을 반환하지 않는가? 주기는 240000 톤이 아닙니다. 기본 주기는 180000 톤의 의 정수 배수가 아닙니다. 합성할 수 없습니다.

슈퍼888코드에는 4시간 K줄이 있고, 30분 동안 정상으로 반복된다 (그라프의 K줄은 4분의 시간 간격이다), 5분 동안 비정상적으로 반복된다 (반복시간이 12시 이후 1시간 K줄이 된다)

작은 꿈네, 이 합성 코드는 좀 더 오래 전에 쓰여졌는데, 이걸 보세요: https://www.fmz.com/digest-topic/4154

감사합니다, 저는 이 합성 함수를 사용해서 거래소가 제공하지 않는 k 라인 주기를 사용해야 하기 때문이 아니라, 이 정책은 시간선과 일선 주기를 동시에 사용해야 하기 때문에, 두 번 GetRecords 함수를 호출하면 각각 3 시간선과 일선을 얻을 수 있고, fmz 하층은 두 번의 네트워크 요청을 보내지 않을까요?

작은 꿈이제 플랫폼은 직접 사용자 정의 K 라인 사이클을 지원하여 플랫폼 기능을 직접 사용할 수 있습니다.

작은 꿈일부 거래소에서는 회전선 데이터를 지원하고, 일부는 그렇지 않으며, 일반적으로 통일 주기에 포장을 하고 있다. 다른 주기는 소주기로 합성할 수 있다.

작은 꿈K줄을 1분 주기로 설정하는 것을 테스트했습니다. 아래쪽의 매개변수는 1000*60*4를 설정하면 4분이라는 것을 의미합니다.

조오OKEX를 선택하고 기본 K 라인을 1분으로 설정하면 4분으로 더하면 이런 오류가 발생합니다. 주파수 240000톤은 기본 주파수 180000톤의 정수 배가 아닙니다. 합성할 수 없습니다.

조오이건 제 while (true) 코드입니다 records = Call ((exchange.GetRecords,PERIOD_M1)); //Log (("원본 K줄 데이터: 길이", records.length, "데이터:", records); records = AssembleRecords ((records, Num_UI_NewCycleForMS); // 첫 번째 매개 변수는 기본 K 라인, 두 번째 매개 변수는 변환하려는 주기의 밀리 초수, 1000 * 60 * 20 즉 20 분으로 변환 // Log (("변환 후 K줄 데이터: 길이", records.length, "데이터:", records); $PlotRecords ((records, 'BTC'); // throw "stop"; // ceshi Sleep ((1000); ♪ ♪ 이 것은 파리그램 설정입니다 https://dn-filebox.qbox.me/e0f51cd46827d68f42cbeffadba1c7a842fb0fb1.jpg 1분으로 정해져 있지만 기본 K선 주기가 3분이라는 것을 암시합니다.

작은 꿈당신이 재검토할 때 설정한 매개 변수 스크린샷을 보거나 직접 그룹에 QQ 작은 꿈.

작은 꿈이제 업데이트를 통해 기본 주기가 목표 주기와 일치하도록 처리하도록 요구합니다. 예를 들어 목표 주기는 6시간을 합쳐야하며 기본 주기는 1시간을 사용해야하며 더 적은 번거로움을 사용해야하며 많은 재능을 수집해야 합니다. 테스트 할 수 있습니다. 또는 사용에 문제가있는 버그가 있습니다.

작은 꿈질문 주셔서 감사합니다. 저는 코드를 확인했습니다.