Блог им. NektoFinkelmaer

Робот для торговли спреда внутри канала, пробоя или отбоя от уровня (с исходниками на Java Script)

Скрипт в руки — деньги в карман.

Инструкция:
1. Бери «Скрипт».
2. Пиши «Тикер» из фондовой секции ММВБ.
3. Жми «График».
Вуаля… ваш брокерский счет наливается прибылью.

Чем жирнее цена, тем жирнее уровень.
Пользуйся и твоя эквити будет гладкая и больше чем вчера.

Робот для торговли спреда внутри канала, пробоя или отбоя от уровня (с исходниками на Java Script)

ПС: График влево.
Данные ММВБ с задержкой 15 минут.

<!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>
690 | ★3
3 комментария
Если топик наберет хотя бы 8 лайков, добавлю валютный рынок и индексы, а может даже срочку. Ставь скорее не хватает только твоего… 🙂
avatar
С таким роботом можно все деньги с рынка выкачать
avatar
Tema ☑️, потом обратно закачать и опять выкачать, но уже побольше.
avatar

Читайте на SMART-LAB:
Фото
Встречаемся на Smart-Lab & Cbonds PRO облигации 2026
Встречаемся на Smart-Lab & Cbonds PRO облигации 2026 💼 Уже в эту субботу, 28 февраля , в Москве пройдёт конференция по вопросам...
Фото
Портфель с ежемесячными поступлениями. Февраль 2026
В сентябре прошлого года сформировали портфель облигаций с ежемесячными купонами. Посмотрим, как изменилась ситуация на рынке, и актуализируем...
Займер спас от мошенников почти миллиард рублей
🥷 За прошлый год служба безопасности Займера выявила и заблокировала более 165 тысяч заявок на займы от мошенников, что помогло компании...
Фото
Какие юаневые облигации можно приобрести на фоне ужесточения бюджетного правила?

теги блога Nekto Finkelmaer

....все тэги



UPDONW
Новый дизайн