Converter qualquer ciclo de linha K

Autora:Sonhos pequenos, Data: 16 de fevereiro de 2017
Tags:Extent-API

Exemplos de estratégias

  • Converte a linha K básica para qualquer ciclo de linha K
  • Temporariamente não suportado Nível de segundos A versão de teste, se houver bugs e problemas, é bem-vinda para comentários.

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

Relacionados

Mais.

BamsmenSe a síntese da linha de 18 horas não é um problema, a síntese da linha de dia é um erro.

BamsmenA lógica do getDHM parece ter um pouco de problemas, com um total de erros: os ciclos de destino não correspondem aos ciclos de base!

qunxiang_wangOlá, por que você não está integrando um circuito no API?

JiaozhengOlá, você pode resolver isso? Minha estratégia porque isso já não pode ser rastreado

JiaozhengPor que o ciclo da linha K foi selecionado em 1 minuto quando o teste foi feito com o OKEX, mas não retornou o objetivo? O ciclo é de 240000 toneladas, não é o ciclo base. O ciclo é de 180000 toneladas, não é possível sintetizar!

super888O código é uma linha K de 4 horas, que se repete normal em 30 minutos (a linha K do gráfico é de 4 minutos de intervalo) e não normal em 5 minutos (de 12 horas de tempo de repetição para 1 hora de linha K)

Sonhos pequenosSim, esse código sintético foi escrito muito antes, você pode ler este: https://www.fmz.com/digest-topic/4154.

BamsmenObrigado, eu estou usando esta função de síntese não porque eu preciso usar o k-line cycle que não é fornecido pela bolsa, mas porque a política precisa usar o ciclo de horas e dia ao mesmo tempo, então, se você chamar duas vezes a função GetRecords para obter 3 horas e dias, respectivamente, será que o fundo do fmz vai enviar duas solicitações de rede?

Sonhos pequenosAgora, a plataforma suporta diretamente os ciclos de linha K personalizados e você pode usar diretamente as funcionalidades da plataforma.

Sonhos pequenosAlgumas trocas suportam dados de circunferência, algumas não, geralmente são feitas em pacotes para ciclos unificados. Outros ciclos podem ser sintetizados com ciclos menores.

Sonhos pequenosEu testei a linha K para definir um ciclo de 1 minuto, e o parâmetro inferior para definir 1000 * 60 * 4 é 4 minutos, o que significa que é possível sintetizar a linha K.

JiaozhengVocê pode experimentar o teste de dados, selecionar o OKEX e definir a linha K básica para 1 minuto, e depois para 4 minutos, e você receberá um erro como o meu. O ciclo de potássio de 240000 toneladas não é o ciclo de base. O ciclo de potássio de 180000 toneladas é um múltiplo inteiro, não pode ser sintetizado!

JiaozhengEste é o meu código while (true) { registros = Call ((exchange.GetRecords, PERIOD_M1); //Log (("Dados de linha K primários: comprimento", records.length, "Dados:", records); records = AssembleRecords ((records, Num_UI_NewCycleForMS); // O primeiro parâmetro é a linha base K, o segundo parâmetro é o milissegundo de ciclo a ser convertido, 1000 * 60 * 20 ou a conversão para 20 minutos // Log (("após a conversão de dados da linha K: comprimento", records.length, "data:", records); O site oficial da empresa é o.plotRecords. // throw "stop"; // ceshi Sleep ((1000); Não. Esta é a configuração do parâmetro https://dn-filebox.qbox.me/e0f51cd46827d68f42cbeffadba1c7a842fb0fb1.jpg A definição é de um minuto, mas sugere que o ciclo da linha K básica é de três minutos, o que não aconteceu antes.

Sonhos pequenosO que você pode fazer para rever os parâmetros definidos no screenshot abaixo ou diretamente no grupo QQ.

Sonhos pequenosAgora é atualizado, fazendo um processamento que requer um ciclo básico para ser consistente com o ciclo objetivo, por exemplo, o ciclo objetivo é para ser sintetizado em 6 horas, o ciclo básico é para ser usado em 1 hora, usando menos problemas, mas também para coletar muitos talentos. Você pode testar, ou se houver algum problema com o uso, sugiro que me deixe uma mensagem, ou pode me fazer um QQ.

Sonhos pequenosObrigado pela pergunta, eu verifiquei o código.