Блог им. NektoFinkelmaer
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> </head> <body> <form name="search"> <input type="text" name="key" placeholder="Тикер" id="key"/> <input type="button" name="buttonChart" value="График" /> </form> <div id="printBlock"></div> <canvas id="chart" width="4000" height="600"></canvas> <script> const keyBox = document.search.key; const keyButton = document.search.buttonChart; function DrawChart(prices,minPrice,maxPrice,maxVolume,ZZ,ZZDay){ var chart = document.getElementById("chart"); if (chart.getContext) { var ctx = chart.getContext("2d"); ctx.lineWidth=1; Point = 0; for (let i = prices. <a name="cut"></a> length-1; i >= 0; i--) { var K=600/(maxPrice-minPrice); var pOpen = Math.trunc((prices[i].Open-minPrice)*K); var pClose = Math.trunc((prices[i].Close-minPrice)*K); var pMin = Math.trunc((prices[i].Low-minPrice)*K); var pMax = Math.trunc((prices[i].High-minPrice)*K); var dStart = 600-Math.max(pOpen,pClose); var dFinish = 600-Math.min(pOpen,pClose); var dMin = 600-pMin; var dMax = 600-pMax; var pVolume = Math.trunc((prices[i].Volume)/maxVolume*100); var dVolume = 600-pVolume; var AA = prices[i].Close - prices[i].Open; //ctx.beginPath(); if (pOpen==pClose) { ctx.fillStyle = "rgb(0,0,0)"; dFinish = dStart+1; //console.log("-"+(Point*4)+" "+dStart+" "+dFinish + " "+AA+" "+pOpen+" "+pClose+" "+K); } else { if (prices[i].Open>prices[i].Close) { ctx.fillStyle = "rgb(200,0,0)"; } else{ ctx.fillStyle = "rgb(0,200,0)"; } } if (Point==0) { ctx.fillRect(Point, dStart, 40, 1); ctx.textBaseline = "bottom"; ctx.font = "bold 8px Arial"; ctx.fillText(prices[i].Close, Point, dStart-2); Point = Point+11; } //console.log(""+(Point*4)+" "+dStart+" "+dFinish + " "+AA+" "+pOpen+" "+pClose+" "+K); ctx.fillRect(Point*4, dStart, 3, dFinish-dStart); ctx.fillStyle = ctx.fillStyle.replace(")",",0.7)"); //console.log(""+prices[i].Volume+" "+maxVolume + " "+pVolume+" "+dVolume+" "+ctx.fillStyle); ctx.fillRect(Point*4, dVolume, 3, 600-dVolume); ctx.fillStyle = "rgb(0,0,0)"; ctx.fillRect(Point*4+1, dMax, 1, dStart-dMax); ctx.fillRect(Point*4+1, dFinish, 1, dMin-dFinish); Point ++; } DrawZZ(ZZ,ctx,prices,maxPrice,minPrice); ctx.lineWidth=2; DrawZZ(ZZDay,ctx,prices,maxPrice,minPrice); var priceLevel = []; ctx.lineWidth=1; ctx.strokeStyle = "rgb(0,0,200,0.3)"; DrawK(ZZ,ctx,prices,maxPrice,minPrice,1,3,priceLevel); DrawK(ZZ,ctx,prices,maxPrice,minPrice,3,5,priceLevel); DrawK(ZZ,ctx,prices,maxPrice,minPrice,1,5,priceLevel); DrawK(ZZ,ctx,prices,maxPrice,minPrice,2,4,priceLevel); DrawK(ZZ,ctx,prices,maxPrice,minPrice,4,6,priceLevel); DrawK(ZZ,ctx,prices,maxPrice,minPrice,2,6,priceLevel); ctx.lineWidth=2; DrawK(ZZDay,ctx,prices,maxPrice,minPrice,1,3,priceLevel); DrawK(ZZDay,ctx,prices,maxPrice,minPrice,3,5,priceLevel); DrawK(ZZDay,ctx,prices,maxPrice,minPrice,1,5,priceLevel); DrawK(ZZDay,ctx,prices,maxPrice,minPrice,2,4,priceLevel); DrawK(ZZDay,ctx,prices,maxPrice,minPrice,4,6,priceLevel); DrawK(ZZDay,ctx,prices,maxPrice,minPrice,2,6,priceLevel); priceLevel.sort(function(a,b){ if (a.Price<b.Price) return -1; else if (a.Price>b.Price) return 1; else return 0; }); priceLevelGroup = []; maxVolume = 0; for (let i = 0; i < priceLevel.length; i++) { console.log(""+priceLevel[i].Price+" "+priceLevel[i].Volume); if (i==0) { priceLevelGroup[0] = {Price:priceLevel[i].Price,Volume:priceLevel[i].Volume}; } else{ if (priceLevel[i].Price/priceLevelGroup[priceLevelGroup.length-1].Price-1<0.003) { priceLevelGroup[priceLevelGroup.length-1].Price = (priceLevel[i].Volume*priceLevel[i].Price +priceLevelGroup[priceLevelGroup.length-1].Volume*priceLevelGroup[priceLevelGroup.length-1].Price) /(priceLevel[i].Volume+priceLevelGroup[priceLevelGroup.length-1].Volume); priceLevelGroup[priceLevelGroup.length-1].Volume = priceLevelGroup[priceLevelGroup.length-1].Volume+priceLevel[i].Volume; } else{ priceLevelGroup[priceLevelGroup.length] = {Price:priceLevel[i].Price,Volume:priceLevel[i].Volume}; } }; if (priceLevelGroup[priceLevelGroup.length-1].Volume>maxVolume){ maxVolume = priceLevelGroup[priceLevelGroup.length-1].Volume; } } for (let i = 0; i < priceLevelGroup.length; i++) { pOpen = Math.trunc((priceLevelGroup[i].Price-minPrice)*K); dStart = 600-pOpen; ctx.fillRect(0, dStart, 40, 1); ctx.textBaseline = "bottom"; ctx.font = ""+(Math.trunc(priceLevelGroup[i].Volume/maxVolume*12)+6)+"px Arial"; console.log("g "+maxVolume+" "+priceLevelGroup[i].Volume+" "+ctx.font+" "+(Math.trunc(priceLevelGroup[i].Volume/maxVolume*12)+6)); //console.log("g "+priceLevelGroup[i].Price+" "+priceLevelGroup[i].Volume+" "+ctx.font+" "+(Math.trunc(priceLevelGroup[i].Volume/maxVolume*12)+6)); percent = Math.trunc((prices[prices.length-1].Close - priceLevelGroup[i].Price)/prices[prices.length-1].Close*10000)/100; if (percent<0) {percent=-percent;ctx.fillStyle = "rgb(100,150,100)";} else {ctx.fillStyle = "rgb(150,100,100)"}; ctx.fillText(""+Math.trunc(priceLevelGroup[i].Price*100)/100+" ("+percent+"%)", 0, dStart-1); } } } function DrawZZ(ZZ,ctx,prices,maxPrice,minPrice){ ctx.fillStyle = "rgb(0,0,0,0.7)"; ctx.beginPath(); for (let i = 0; i < ZZ.length; i++) { Point = (prices.length - ZZ[i].Point+10)*4+1; var K=600/(maxPrice-minPrice); pPrice = Math.trunc((ZZ[i].price-minPrice)*K); dStart = 600-pPrice; //console.log(""+ZZ[i].price+" "+dStart+ " "+ZZ[i].Point+" "+ZZ[i].T); if (i==0) { ctx.moveTo(Point,dStart); } else { ctx.lineTo(Point,dStart); } } ctx.stroke(); } function DrawK(ZZ,ctx,prices,maxPrice,minPrice,p1,p2,priceLevel){ if (ZZ.length-p1<0 || ZZ.length-p2<0) {return}; var K=600/(maxPrice-minPrice); first = ZZ.length - p1; second = ZZ.length - p2; //console.log(""+first+" "+second+" "+ZZ.length); fPoint = (prices.length-ZZ[first].Point+10)*4+1; sPoint = (prices.length-ZZ[second].Point+10)*4+1; ePrice=ZZ[second].price+(prices.length-ZZ[second].Point)*(ZZ[first].price-ZZ[second].price)/(ZZ[first].Point-ZZ[second].Point) priceLevel[priceLevel.length] = {Price:ePrice,Volume:(ZZ[second].Volume+ZZ[first].Volume)}; priceLevel[priceLevel.length] = {Price:ZZ[first].price,Volume:(ZZ[first].Volume)}; priceLevel[priceLevel.length] = {Price:ZZ[second].price,Volume:(ZZ[second].Volume)}; //console.log(""+ZZ[first].Point+" "+ZZ[second].Point+" "+" "+prices.length+" "+ZZ[first].price+" "+ZZ[second].price+" "+ePrice); fPrice = Math.trunc((ZZ[first].price-minPrice)*K); sPrice = Math.trunc((ZZ[second].price-minPrice)*K); ePrice = Math.trunc((ePrice-minPrice)*K); dStart = 600-sPrice; dFinish = 600-ePrice; //console.log(""+first+" "+second+" "+fPrice+" "+sPrice+" "+ePrice); //ctx.fillStyle = "rgb(0,0,255,0.7)"; //console.log(""+ctx.fillStyle); ctx.beginPath(); ctx.moveTo(sPoint,dStart); ctx.lineTo(40,dFinish); ctx.stroke(); ctx.beginPath(); ctx.moveTo(sPoint,dStart); ctx.lineTo(40,dStart); ctx.stroke(); ctx.beginPath(); ctx.moveTo(fPoint,600-fPrice); ctx.lineTo(40,600-fPrice); ctx.stroke(); } function FillArray (data){ var prices = []; var pricesDay = []; var ZZ = []; var ZZDay = []; var minPrice = 9999999; var maxPrice = 0; var maxVolume = 0; let md = data['candles']['data']; for (let i = 0; i < md.length; i++) { var cl = prices.length; prices[cl] = []; prices[cl] = {Period:md[i][6], Open:md[i][0], Close:md[i][1],Low:md[i][3], High:md[i][2], Volume:md[i][5], Period:md[i][6]} if (minPrice>prices[cl].Low) { minPrice = prices[cl].Low; } if (maxPrice<prices[cl].High) { maxPrice = prices[cl].High; } if (maxVolume<prices[cl].Volume) { maxVolume = prices[cl].Volume; } var cDay = prices[cl].Period; cDay = cDay.substring(0,10); PosDay=pricesDay.findIndex(item => item.Period == cDay); if (PosDay==-1) {PosDay=pricesDay.length; pricesDay[PosDay]={Period:cDay,High:prices[cl].High,Low:prices[cl].Low,PeriodHi:i,PeriodLow:i,Volume:prices[cl].Volume}} if (pricesDay[PosDay].High<prices[cl].High) {pricesDay[PosDay].High=prices[cl].High;pricesDay[PosDay].PeriodHi=cl;} if (pricesDay[PosDay].Low>prices[cl].Low) {pricesDay[PosDay].Low=prices[cl].Low;pricesDay[PosDay].PeriodLow=cl;} pricesDay[PosDay].Volume = pricesDay[PosDay].Volume+prices[cl].Volume; if (cl>1) { if (ZZ.length == 0) { ZZ[0] = {price:(prices[cl-2].Open>prices[cl].Close ? prices[cl-2].High:prices[cl-2].Low), Point:cl-2, T:(prices[cl-2].Open>prices[cl].Close ? -1:1), Volume:prices[cl-2].Volume} //console.log("f "+ZZ[ZZ.length-1].price+" "+" "+ZZ[ZZ.length-1].Point+" "+ZZ[ZZ.length-1].T); } else { if (ZZ[ZZ.length-1].T == 1) { //console.log("up "+ZZ[ZZ.length-1].price+" "+" "+ZZ[ZZ.length-1].Point+" "+ZZ[ZZ.length-1].T); if (prices[cl-2].High<prices[cl].High || prices[cl-1].High<prices[cl].High || prices[cl-2].Low<prices[cl].Low || prices[cl-1].Low<prices[cl].Low) {} else { ZZ[ZZ.length]={price:(Math.max(prices[cl-2].High,prices[cl-1].High)), Point:(prices[cl-2].High>prices[cl-1].High ? cl-2:cl-1), T:-1, Volume:(prices[cl-2].High>prices[cl-1].High ? prices[cl-2].Volume:prices[cl-1].Volume)} //console.log("up "+ZZ[ZZ.length-1].price+" "+" "+ZZ[ZZ.length-1].Point+" "+ZZ[ZZ.length-1].T); } } else { if (ZZ[ZZ.length-1].T == -1) { if (prices[cl-2].Low>prices[cl].Low || prices[cl-1].Low>prices[cl].Low || prices[cl-2].High>prices[cl].High || prices[cl-1].High>prices[cl].High) {} else { ZZ[ZZ.length]={price:(Math.min(prices[cl-2].Low,prices[cl-1].Low)), Point:(prices[cl-2].Low<prices[cl-1].Low ? cl-2:cl-1), T:1, Volume:(prices[cl-2].Low<prices[cl-1].Low ? prices[cl-2].Volume:prices[cl-1].Volume)} //console.log("dw "+ZZ[ZZ.length-1].price+" "+" "+ZZ[ZZ.length-1].Point+" "+ZZ[ZZ.length-1].T); } } } } } } for (let cl = 0; cl < pricesDay.length; cl++) { //console.log(""+pricesDay[cl].Period+" "+pricesDay[cl].High+" "+pricesDay[cl].Low+" "+pricesDay[cl].Volume+" "+pricesDay[cl].PeriodHi+" "+pricesDay[cl].PeriodLow); if (cl>1) { if (ZZDay.length == 0) { ZZDay[0] = {price:(pricesDay[cl-2].Open>pricesDay[cl].Close ? pricesDay[cl-2].High:pricesDay[cl-2].Low), Point:(pricesDay[cl-2].Open>pricesDay[cl].Close ? pricesDay[cl-2].PeriodHi:pricesDay[cl-2].PeriodLow), T:(pricesDay[cl-2].Open>pricesDay[cl].Close ? -1:1), Volume:prices[cl-2].Volume} //console.log("f "+ZZDay[ZZDay.length-1].price+" "+" "+ZZDay[ZZDay.length-1].Point+" "+ZZDay[ZZDay.length-1].T); } else { if (ZZDay[ZZDay.length-1].T == 1) { //console.log("up "+ZZDay[ZZDay.length-1].price+" "+" "+ZZDay[ZZDay.length-1].Point+" "+ZZDay[ZZDay.length-1].T); if (pricesDay[cl-2].High<pricesDay[cl].High || pricesDay[cl-1].High<pricesDay[cl].High || pricesDay[cl-2].Low<pricesDay[cl].Low || pricesDay[cl-1].Low<pricesDay[cl].Low) {} else { ZZDay[ZZDay.length]={price:(Math.max(pricesDay[cl-2].High,pricesDay[cl-1].High)), Point:(pricesDay[cl-2].High>pricesDay[cl-1].High ? pricesDay[cl-2].PeriodHi:pricesDay[cl-1].PeriodHi), T:-1, Volume:(pricesDay[cl-2].High>pricesDay[cl-1].High ? pricesDay[cl-2].Volume:pricesDay[cl-1].Volume)} //console.log("up "+ZZDay[ZZDay.length-1].price+" "+" "+ZZDay[ZZDay.length-1].Point+" "+ZZDay[ZZDay.length-1].T); } } else { if (ZZDay[ZZDay.length-1].T == -1) { if (pricesDay[cl-2].Low>pricesDay[cl].Low || pricesDay[cl-1].Low>pricesDay[cl].Low || pricesDay[cl-2].High>pricesDay[cl].High || pricesDay[cl-1].High>pricesDay[cl].High) {} else { ZZDay[ZZDay.length]={price:(Math.min(pricesDay[cl-2].Low,pricesDay[cl-1].Low)), Point:(pricesDay[cl-2].Low<pricesDay[cl-1].Low ? pricesDay[cl-2].PeriodLow:pricesDay[cl-1].PeriodLow), T:1, Volume:(pricesDay[cl-2].Low<pricesDay[cl-1].Low ? pricesDay[cl-2].Volume:pricesDay[cl-1].Volume)} //console.log("dw "+ZZDay[ZZDay.length-1].price+" "+" "+ZZDay[ZZDay.length-1].Point+" "+ZZDay[ZZDay.length-1].T); } } } } } } DrawChart(prices,minPrice,maxPrice,maxVolume,ZZ,ZZDay); return prices; } function strRight(n,str){ return str.substring(str.length-n,str.length); } // обработчик изменения текста function onchange(e){ // получаем элемент printBlock const printBlock = document.getElementById("printBlock"); const tiker = document.getElementById("key").value; // получаем новое значение const val = tiker; // установка значения printBlock.textContent = printBlock.textContent+" "+tiker; var URL = "https://iss.moex.com/iss/engines/stock/markets/shares/securities/<TIKER>/candles.json?from=<DateFrom>&interval=60"; URL = URL.replace("<TIKER>", val); var now = new Date(); now.setDate(now.getDate() - 45); console.log(now); var Month=now.getMonth()+1; var year=now.getFullYear(); //if (Month<0) {Month=12+Month+1; year--;}; var startdata = (year).toString()+"-"+strRight(2,"0"+Month.toString())+"-"+strRight(2,"0"+now.getDate().toString()); URL = URL.replace("<DateFrom>", startdata); console.log(URL); fetch(URL) .then(function (response) { return response.json(); }) .then(function (data) { FillArray(data); }) } //keyBox.addEventListener("change", onchange); keyButton.addEventListener("click", onchange); </script> </body> </html>