Exemple de stratégie
// 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); } }
les garde-corpsSi la synthèse de la ligne K de 3 heures est bonne, la synthèse de la ligne 18 heures est mauvaise.
les garde-corpsLa logique de getDHM semble avoir un petit problème, avec un total d'erreurs: les cycles cibles ne correspondent pas aux cycles de base!
Je ne sais pas.Bonjour, pourquoi n'avez-vous pas intégré une ligne de contour dans l'API?
- Je ne sais pas.Bonjour, est-ce que vous pouvez résoudre ma stratégie parce que cela ne peut plus être retesté
- Je ne sais pas.Pourquoi le cycle de la ligne K a été sélectionné en 1 minute pour la récupération des données d'okex, mais n'a pas renvoyé l'erreur de l'objectif?
super888Dans le code, il y a une ligne K de 4 heures qui est normale à 30 minutes (la ligne K du graphique est à 4 minutes d'intervalle) et une ligne K qui est anormale à 5 minutes (elle devient une ligne K d'une heure après 12 heures de temps de répétition).
L'inventeur de la quantification - un petit rêveOui, cette synthèse a été écrite plus tôt, vous pouvez lire ceci: https://www.fmz.com/digest-topic/4154.
les garde-corpsMerci, j'utilise cette synthèse non pas parce que j'ai besoin d'utiliser des cycles de ligne k qui ne sont pas fournis par l'échange, mais parce que la stratégie nécessite des cycles de ligne d'heure et de ligne de jour en même temps, si vous appelez deux fois la fonction GetRecords pour obtenir une ligne d'heure et une ligne de jour respectivement, est-ce que la couche inférieure de fmz envoie deux requêtes réseau?
L'inventeur de la quantification - un petit rêveMaintenant, la plate-forme prend en charge directement les cycles personnalisés de la ligne K, et vous pouvez utiliser directement les fonctionnalités de la plate-forme.
L'inventeur de la quantification - un petit rêveCertains échanges prennent en charge les données de la courbe, d'autres non, généralement enveloppés dans des cycles unifiés. D'autres cycles peuvent être synthétisés avec des cycles plus petits.
L'inventeur de la quantification - un petit rêveJ'ai testé le paramètre inférieur de la ligne K pour définir un cycle de 1 minute, et le paramètre inférieur pour définir 1000*60*4 qui signifie 4 minutes, peut être synthétisé.
- Je ne sais pas.Si vous essayez de faire une recherche de données vous-même, sélectionnez les OKEX futures, puis réglez la ligne K de base sur 1 minute, puis sur 4 minutes, et vous obtiendrez une erreur comme la mienne. Les cycles de 240000 tonnes ne sont pas des cycles de base, les multiples entiers de 180000 tonnes ne peuvent pas être synthétisés.
- Je ne sais pas.Ceci est mon code while (true) { records = Call ((exchange.GetRecords, PERIOD_M1)); //Log ((" données de ligne K initiales: longueur", records.length, " données:", records); records = AssembleRecords ((records, Num_UI_NewCycleForMS); // le premier paramètre est la ligne K de base, le second paramètre est le nombre de millisecondes de cycles à convertir, 1000 * 60 * 20 c'est à dire la conversion en 20 minutes // Log ((" après conversion de données de ligne K: longueur, " records.length, " données:", records); Le site officiel de Bitcoin est le site officiel de Bitcoin.com. Je ne sais pas. Sleep ((1000); Je ne sais pas. Ceci est le paramètre de configuration https://dn-filebox.qbox.me/e0f51cd46827d68f42cbeffadba1c7a842fb0fb1.jpg Il y a une définition claire de 1 minute, mais il y a une suggestion de 3 minutes pour le cycle de base de la ligne K, ce qui n'était pas le cas avant.
L'inventeur de la quantification - un petit rêveLes paramètres que vous avez définis lors de votre réévaluation.
L'inventeur de la quantification - un petit rêveMaintenant, il est mis à jour, un traitement exige que le cycle de base soit conforme au cycle de cible, par exemple, le cycle de cible doit être synthétisé de 6 heures, le cycle de base doit être utilisé d'une heure, avec moins de tracas, et il faut collecter beaucoup de talents.
L'inventeur de la quantification - un petit rêveMerci d'avoir posé la question, je vais vérifier le code.