1070 lines
38 KiB
JavaScript
1070 lines
38 KiB
JavaScript
//general util functions all accross
|
|
|
|
|
|
API_KEY = localStorage.getItem("api-key")
|
|
var chart = null
|
|
|
|
//puvodni mene vyrazne barvy
|
|
// var colors = ["#8B1874","#B71375","#B46060","#61c740","#BE6DB7","#898121","#4389d9","#B5D5C5","#e61957","#7B0E60","#9B2888","#BD38A0","#A30F68","#6E0B50","#CA2183","#E6319B","#A04C54","#643848","#CA7474","#E68D8D","#4F9C34","#3B7128","#73DF4D","#95EF65","#A857A4","#824690","#D087CC","#FF3775","#E2A1DF","#79711B","#635D17","#99912B","#B1A73D","#3779C9","#A60F3B","#2B68B3","#5599ED","#77A9F7","#004C67","#00687D","#A1C6B5","#8CC6A5","#C9E6D5","#E4F6EA","#D2144A","#FA2463","#8B1874","#B71375","#B46060","#61c740","#BE6DB7","#898121","#4389d9","#B5D5C5","#e61957","#7B0E60","#9B2888","#BD38A0","#A30F68","#6E0B50","#CA2183","#E6319B","#A04C54","#643848","#CA7474","#E68D8D","#4F9C34","#3B7128","#73DF4D","#95EF65","#A857A4","#824690","#D087CC","#FF3775","#E2A1DF","#79711B","#635D17","#99912B","#B1A73D","#3779C9","#A60F3B","#2B68B3","#5599ED","#77A9F7","#004C67","#00687D","#A1C6B5","#8CC6A5","#C9E6D5","#E4F6EA","#D2144A","#FA2463"];
|
|
// var reset_colors = ["#8B1874","#B71375","#B46060","#61c740","#BE6DB7","#898121","#4389d9","#B5D5C5","#e61957","#7B0E60","#9B2888","#BD38A0","#A30F68","#6E0B50","#CA2183","#E6319B","#A04C54","#643848","#CA7474","#E68D8D","#4F9C34","#3B7128","#73DF4D","#95EF65","#A857A4","#824690","#D087CC","#FF3775","#E2A1DF","#79711B","#635D17","#99912B","#B1A73D","#3779C9","#A60F3B","#2B68B3","#5599ED","#77A9F7","#004C67","#00687D","#A1C6B5","#8CC6A5","#C9E6D5","#E4F6EA","#D2144A","#FA2463","#8B1874","#B71375","#B46060","#61c740","#BE6DB7","#898121","#4389d9","#B5D5C5","#e61957","#7B0E60","#9B2888","#BD38A0","#A30F68","#6E0B50","#CA2183","#E6319B","#A04C54","#643848","#CA7474","#E68D8D","#4F9C34","#3B7128","#73DF4D","#95EF65","#A857A4","#824690","#D087CC","#FF3775","#E2A1DF","#79711B","#635D17","#99912B","#B1A73D","#3779C9","#A60F3B","#2B68B3","#5599ED","#77A9F7","#004C67","#00687D","#A1C6B5","#8CC6A5","#C9E6D5","#E4F6EA","#D2144A","#FA2463"];
|
|
|
|
// function generateColorPalette(numColors) {
|
|
// const palette = [];
|
|
// let lastColor = null;
|
|
// for (let i = 0; i < numColors; i++) {
|
|
// let color = generateRandomColor();
|
|
// while (isColorDark(color) || areColorsTooSimilar(color, lastColor)) {
|
|
// color = generateRandomColor();
|
|
// }
|
|
// lastColor = color;
|
|
// palette.push(color);
|
|
// }
|
|
// return palette;
|
|
// }
|
|
|
|
// function generateRandomColor() {
|
|
// const letters = '0123456789ABCDEF';
|
|
// let color = '#';
|
|
// for (let i = 0; i < 6; i++) {
|
|
// color += letters[Math.floor(Math.random() * 16)];
|
|
// }
|
|
// return color;
|
|
// }
|
|
|
|
// function areColorsTooSimilar(color1, color2) {
|
|
// if (!color1 || !color2) {
|
|
// return false;
|
|
// }
|
|
// // Calculate the color difference
|
|
// const diff = parseInt(color1.substring(1), 16) - parseInt(color2.substring(1), 16);
|
|
// // Define a threshold for color difference (you can adjust this value)
|
|
// const threshold = 500;
|
|
// return Math.abs(diff) < threshold;
|
|
// }
|
|
|
|
// function isColorDark(color) {
|
|
// const hexColor = color.replace("#", "");
|
|
// const r = parseInt(hexColor.substr(0, 2), 16);
|
|
// const g = parseInt(hexColor.substr(2, 2), 16);
|
|
// const b = parseInt(hexColor.substr(4, 2), 16);
|
|
// const brightness = (r * 299 + g * 587 + b * 114) / 1000;
|
|
// return brightness < 128 || brightness > 140; // You can adjust the threshold for what you consider 'dark'
|
|
// }
|
|
|
|
// colors = generateColorPalette(255)
|
|
// reset_colors = colors
|
|
|
|
// console.log(`"${colors.join("\", \"")}"`);
|
|
|
|
// // pekne vygenrovane pomoci kodu vyse
|
|
var colors = ["#63AA57", "#8F8AB0", "#4CAA4E", "#E24AEE", "#D06AA6", "#7891BA", "#A39A34", "#8A94A2", "#8887A7", "#61BB2F", "#FD569D", "#1EB6E1",
|
|
"#379AC9", "#FD6F2E", "#8C9858", "#39A4A3", "#6D97F4", "#1ECB01", "#FA5B16", "#A6891C", "#48CF10", "#D27B26", "#D56B55", "#FE3AB8", "#E35C51",
|
|
"#EC4FE6", "#E250A3", "#BA618E", "#1BC074", "#C57784", "#888BC5", "#4FA452", "#80885C", "#B97272", "#33BF98", "#B7961D", "#A07284", "#02E54E",
|
|
"#AF7F35", "#F852EF", "#6D955B", "#E0676E", "#F73DEC", "#CE53FD", "#9773D3", "#649E81", "#D062CE", "#AB73E7", "#A4729C", "#E76A07", "#E85CCB",
|
|
"#A16FB1", "#4BB859", "#B25EE2", "#8580CE", "#A275EF", "#AC9245", "#4D988D", "#B672C9", "#4CA96E", "#C9873E", "#5BB147", "#10C783", "#D7647D",
|
|
"#CB893A", "#A586BA", "#28C0A2", "#61A755", "#0EB7C5", "#2DADBC", "#17BB71", "#2BC733", "#2BB890", "#F04EF8", "#699580", "#A88809", "#EB3FF6",
|
|
"#A75ED3", "#859171", "#BB6285", "#81A147", "#AD7CD2", "#65B630", "#C9616C", "#BD5EFA", "#7A9F30", "#2AB6AB", "#FC496A", "#687FC7", "#DB40E7",
|
|
"#07BCE9", "#509F63", "#EC4FDD", "#A079BE", "#C17297", "#E447C2", "#E95AD9", "#9FA01E", "#7E86CF", "#21E316", "#1CABF9", "#17C24F", "#9C9254",
|
|
"#C97994", "#4BA9DA", "#0DD595", "#13BEA8", "#C2855D", "#DF6C13", "#60B370", "#0FC3F6", "#C1830E", "#3AC917", "#0EBBB0", "#CC50B4", "#B768EC",
|
|
"#D47F49", "#B47BC5", "#38ADBD", "#05DC53", "#44CD4E", "#838E65", "#49D70F", "#2DADBE", "#2CB0C9", "#DA703E", "#06B5CA", "#7BAF3E", "#918E79",
|
|
"#2AA5E5", "#C37F5E", "#07B8C9", "#4CBA27", "#E752C6", "#7F93B2", "#4798CD", "#45AA4C", "#4DB666", "#7683A7", "#758685", "#4B9FAD", "#9280FD",
|
|
"#6682DD", "#42ACBE", "#C1609F", "#D850DB", "#649A62", "#54CC22", "#AD81C1", "#BF7A43", "#0FCEA5", "#D06DAF", "#87799B", "#4DA94E", "#2FD654",
|
|
"#07D587", "#21CF0C", "#03CF34", "#42C771", "#D563CD", "#6D9E9A", "#C76C59", "#68B368", "#11BCE5", "#0DCFB3", "#9266D8", "#BF67F6", "#88A04E",
|
|
"#73BE17", "#67B437", "#8586E4", "#9F8749", "#479CA5", "#CC777E", "#4FAF46", "#9D9836", "#918DAF", "#D167B8", "#6F9DA5", "#2BB167", "#16B8BC",
|
|
"#B4861F", "#A08487", "#67B357", "#5CAA5C", "#20CA49", "#D18813", "#15D63F", "#C8618F", "#887E92", "#21C457", "#4EA8CE", "#53BE49", "#5A86D5",
|
|
"#BD7E4E", "#27B0A1", "#33CF42", "#709083", "#38A8DE", "#4CA762", "#1EA4FF", "#DE3EE4", "#70A860", "#39A3C8", "#6BBB39", "#F053F4", "#8C7FB5",
|
|
"#969F21", "#B19841", "#E57148", "#C25DA7", "#6DA979", "#B27D73", "#7F9786", "#41AC99", "#C58848", "#948F9E", "#6BB620", "#81AB3B", "#09DE44",
|
|
"#43A9D2", "#41B0D7", "#20ACAA", "#649FCB", "#CD8345", "#A88669", "#3EA5E7", "#F36A19", "#E06B48", "#8388BD", "#EC6153", "#639082", "#52CA32",
|
|
"#878BAA", "#02BCDB", "#828FD9", "#3DC07F", "#29D46A", "#9C7CC1", "#EB7713", "#F95F6A", "#E25F4C", "#589994", "#D45AB7", "#DE66AB", "#B8715F",
|
|
"#E850F4", "#FB6420", "#C2832C", "#6383C5", "#D57A58", "#EF652C", "#02D71A", "#ED664D", "#60A526"]
|
|
|
|
var reset_colors = colors.slice()
|
|
|
|
var indList = []
|
|
var verticalSeries=null
|
|
var candlestickSeries = null
|
|
var volumeSeries = null
|
|
var vwapSeries = null
|
|
var statusBarConfig = JSON.parse(localStorage.getItem("statusBarConfig"));
|
|
if (statusBarConfig == null) {
|
|
statusBarConfig = {}
|
|
}
|
|
|
|
var index_ind = 0
|
|
|
|
|
|
const sorter = (a, b) => a.time > b.time ? 1 : -1;
|
|
var ind_editor = null
|
|
var indConfig = null
|
|
settings = {}
|
|
settings
|
|
//ostatni indicatory nez vwap, volume a bary
|
|
var indConfig_default = [ {name: "ema", titlevisible: false, embed: true, display: true, priceScaleId: "right", lastValueVisible: false},
|
|
{name: "ema20", titlevisible: false, embed: true, display: true, priceScaleId: "right", lastValueVisible: false},
|
|
{name: "tick_volume", histogram: true, titlevisible: true, embed: true, display: true, priceScaleId: '', lastValueVisible: false},
|
|
{name: "tick_price", titlevisible: true, embed: true, display: true, priceScaleId: "right", lastValueVisible: false},
|
|
{name: "ivwap", titlevisible: true, embed: true, display: false, priceScaleId: "right", lastValueVisible: false},
|
|
{name: "slope", titlevisible: true, embed: true, display: false, priceScaleId: "left", lastValueVisible: false},
|
|
{name: "slopeNEW", titlevisible: true, embed: true, display: false, priceScaleId: "left", lastValueVisible: false},
|
|
{name: "slope10", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
|
|
{name: "slope20", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
|
|
{name: "slope10MA", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
|
|
{name: "slope20MA", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
|
|
{name: "slope30", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
|
|
{name: "slope30MA", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
|
|
{name: "slopeLP", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
|
|
{name: "slopeMA", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
|
|
{name: "slope720", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
|
|
{name: "slope720MA", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
|
|
{name: "slow_slope", titlevisible: true, embed: true, display: false, priceScaleId: "left", lastValueVisible: false},
|
|
{name: "slow_slopeMA", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
|
|
{name: "emaSlow", titlevisible: true, embed: true, display: true, priceScaleId: "right", lastValueVisible: false},
|
|
{name: "emaFast", titlevisible: true, embed: true, display: true, priceScaleId: "right", lastValueVisible: false},
|
|
{name: "RSI14", titlevisible: true, embed: true, display: true, priceScaleId: "middle", lastValueVisible: false},
|
|
{name: "RSI14MA", titlevisible: true, embed: true, display: true, priceScaleId: "middle", lastValueVisible: false},
|
|
{name: "CRSI", titlevisible: true, embed: true, display: true, priceScaleId: "middle", lastValueVisible: false},
|
|
{name: "aroon", titlevisible: true, embed: true, display: true, priceScaleId: "middle", lastValueVisible: false},
|
|
{name: "apo", titlevisible: true, embed: true, display: true, priceScaleId: "middle", lastValueVisible: false},
|
|
{name: "ppo", titlevisible: true, embed: true, display: true, priceScaleId: "middle", lastValueVisible: false},
|
|
{name: "stoch2", titlevisible: true, embed: true, display: true, priceScaleId: "middle", lastValueVisible: false},
|
|
{name: "sec_price", titlevisible: true, embed: true, display: true, priceScaleId: "right", lastValueVisible: false},]
|
|
//console.log(JSON.stringify(indConfig_default, null,null, 2))
|
|
|
|
function initialize_statusheader() {
|
|
|
|
var rows = 2;
|
|
var columns = 4;
|
|
console.log("initialiting statusheader")
|
|
console.log(JSON.stringify(statusBarConfig))
|
|
|
|
// Create the grid table
|
|
var gridTable = document.getElementById('statusHeaderTool');
|
|
gridTable.style.display = 'flex';
|
|
|
|
var cntid = 0
|
|
|
|
for (var i = 0; i < rows; i++) {
|
|
var row = document.createElement('tr');
|
|
|
|
for (var j = 0; j < columns; j++) {
|
|
cntid++
|
|
var cell = document.createElement('td');
|
|
cell.className = "statustd";
|
|
var div = document.createElement('div');
|
|
var cellid = "status" + cntid
|
|
div.id = cellid;
|
|
|
|
|
|
var input = document.createElement('input');
|
|
input.id = cntid;
|
|
input.type = 'text';
|
|
input.style.display = "none";
|
|
if (statusBarConfig !== null && statusBarConfig[cntid]) {
|
|
//div.style.backgroundColor = 'red';
|
|
div.textContent = "set";
|
|
input.value = statusBarConfig[cntid];
|
|
}
|
|
|
|
cell.addEventListener('click', function() {
|
|
var inputValue = this.querySelector('input').value;
|
|
//this.querySelector('div').textContent = inputValue;
|
|
this.querySelector('div').style.display = 'none';
|
|
this.querySelector('input').style.display = 'block';
|
|
this.querySelector('input').focus();
|
|
});
|
|
|
|
input.addEventListener('blur', function() {
|
|
this.style.display = 'none';
|
|
//this.previousElementSibling.textContent = inputValue;
|
|
this.previousElementSibling.style.display = 'block';
|
|
if (this.value !== "") {
|
|
statusBarConfig[this.id] = this.value;
|
|
}
|
|
else {
|
|
delete statusBarConfig[this.id]
|
|
}
|
|
if (statusBarConfig[this.id]) {
|
|
this.previousElementSibling.textContent = "set"
|
|
//this.previousElementSibling.style.backgroundColor = 'red';
|
|
}
|
|
else {
|
|
this.previousElementSibling.style.backgroundColor = 'transparent';
|
|
}
|
|
console.log("potom", JSON.stringify(statusBarConfig))
|
|
localStorage.setItem("statusBarConfig", JSON.stringify(statusBarConfig));
|
|
});
|
|
|
|
cell.appendChild(div);
|
|
cell.appendChild(input);
|
|
row.appendChild(cell);
|
|
}
|
|
|
|
gridTable.appendChild(row);
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
//pokud neni v configuraci vracime default
|
|
function get_ind_config(indName) {
|
|
|
|
def = {name: "ema", titlevisible: false, embed: true, display: true, priceScaleId: "middle", lastValueVisible: false}
|
|
|
|
if (indConfig == null) {
|
|
indConfig = get_from_config("indConfig", indConfig_default)
|
|
}
|
|
|
|
const i = indConfig.findIndex(e => e.name === indName);
|
|
if (i>-1)
|
|
{
|
|
return indConfig[i]
|
|
}
|
|
return def
|
|
}
|
|
|
|
function toggle_vertical_line(time) {
|
|
if (verticalSeries) {
|
|
chart.removeSeries(verticalSeries)
|
|
}
|
|
verticalSeries = chart.addHistogramSeries({
|
|
priceScaleId: '',
|
|
color: 'rgba(128, 128, 255, 0.25)',
|
|
scaleMargins: { top: 0, bottom: 0 },
|
|
lastValueVisible: false,
|
|
})
|
|
verticalSeries.setData([{ time: time, value: 1 }])
|
|
}
|
|
|
|
//LEGEND INIT
|
|
var legendlist = document.getElementById('legend');
|
|
var firstRow = document.createElement('div');
|
|
firstRow.innerHTML = '-';
|
|
// firstRow.style.color = 'white';
|
|
legendlist.appendChild(firstRow);
|
|
|
|
function update_chart_legend(param) {
|
|
|
|
function name(val, color = null) {
|
|
color = (color)?' style="color: '+ color + ';"' : "";
|
|
return '<div class="legendItemName" ' + color + '>' + val + '</>'
|
|
}
|
|
function val(val, color = null) {
|
|
color = (color)?' style="color: '+ color + ';"' : "";
|
|
return '<div class="legendItemValue" ' + color + '>' + val + '</>'
|
|
}
|
|
|
|
if (param.time) {
|
|
firstRow.innerHTML = "";
|
|
//BASIC INDICATORS
|
|
const bars = param.seriesData.get(candlestickSeries);
|
|
if (bars !== undefined) {
|
|
//console.log(JSON.stringify(candlestickSeries.options()))
|
|
var color = candlestickSeries.options().upColor;
|
|
firstRow.innerHTML += name("O", color) + val(bars.open) + name("H", color) + val(bars.high) + name("L", color) + val(bars.low) + name("C") + val(bars.close)
|
|
}
|
|
|
|
const volumes = param.seriesData.get(volumeSeries);
|
|
if (volumes !== undefined) {
|
|
var color = volumeSeries.options().color;
|
|
firstRow.innerHTML += name("Vol", color) +val(volumes.value)
|
|
}
|
|
const data = param.seriesData.get(vwapSeries);
|
|
if (data !== undefined) {
|
|
var color = vwapSeries.options().color;
|
|
const vwap = data.value !== undefined ? data.value : data.close;
|
|
firstRow.innerHTML += name('vwap', color) + val(vwap.toFixed(2))
|
|
}
|
|
//ADDITIONAL CUSTOM INDICATORS
|
|
//iterate of custom indicators dictionary to get values of custom lines
|
|
// var customIndicator = {name: key, series: null}
|
|
indList.forEach(function (item) {
|
|
if (item.series) {
|
|
var ind = param.seriesData.get(item.series)
|
|
var color = item.series.options().color;
|
|
var visibility = item.series.options().visible;
|
|
if (ind !== undefined && visibility) { firstRow.innerHTML += name(item.name, color) + val(ind.value.toFixed(3), color)}
|
|
}
|
|
});
|
|
}
|
|
else {
|
|
firstRow.innerHTML = '';
|
|
}
|
|
}
|
|
|
|
function subtractMinutes(date, minutes) {
|
|
date.setMinutes(date.getMinutes() - minutes);
|
|
|
|
return date;
|
|
}
|
|
|
|
function addMinutes(date, minutes) {
|
|
date.setMinutes(date.getMinutes() + minutes);
|
|
|
|
return date;
|
|
}
|
|
|
|
//remove previous chart if exists and intiialize chart variables
|
|
function cleanup_chart() {
|
|
if (chart) {
|
|
console.log("cleanup")
|
|
chart.remove()
|
|
clear_status_header()
|
|
chart = null
|
|
indList = [];
|
|
slLine = []
|
|
markersLine = null
|
|
avgBuyLine = null
|
|
volumeSeries = null
|
|
vwapSeries = null
|
|
verticalSeries=null
|
|
if (toolTip) {
|
|
toolTip.style.display = 'none';
|
|
}
|
|
}
|
|
$( ".switcher" ).remove();
|
|
$('#button_clearlog').hide();
|
|
}
|
|
|
|
function initialize_chart() {
|
|
$('#chartContainerInner').addClass("show");
|
|
$('#button_clearlog').show();
|
|
//PUVODNI BILY MOD
|
|
//var chartOptions = { width: 1045, height: 600, leftPriceScale: {visible: true}}
|
|
|
|
//TMAVY MOD
|
|
var chartOptions = { width: 1024,
|
|
height: 480,
|
|
leftPriceScale: {visible: true},
|
|
layout: {
|
|
background: {
|
|
type: 'solid',
|
|
// color: '#2a2e39',
|
|
color: '#151824'
|
|
},
|
|
textColor: '#d1d4dc',
|
|
},
|
|
grid: {
|
|
vertLines: {
|
|
visible: true,
|
|
color: "#434651"
|
|
},
|
|
horzLines: {
|
|
color: "#434651",
|
|
visible:true
|
|
},
|
|
},
|
|
}
|
|
|
|
chart = LightweightCharts.createChart(document.getElementById('chart'), chartOptions);
|
|
chart.applyOptions({ timeScale: { visible: true, timeVisible: true, secondsVisible: true }, crosshair: {
|
|
mode: LightweightCharts.CrosshairMode.Normal, labelVisible: true
|
|
}})
|
|
}
|
|
|
|
//mozna atributy last value visible
|
|
function intitialize_candles() {
|
|
candlestickSeries = chart.addCandlestickSeries({ lastValueVisible: false, priceLineWidth:1, priceLineColor: "red", priceFormat: { type: 'price', precision: 3, minMove: 0.005 }});
|
|
candlestickSeries.priceScale().applyOptions({
|
|
scaleMargins: {
|
|
top: 0.1, // highest point of the series will be 10% away from the top
|
|
bottom: 0.4, // lowest point will be 40% away from the bottom
|
|
},
|
|
});
|
|
candlestickSeries.applyOptions({
|
|
lastValueVisible: true,
|
|
priceLineVisible: true,
|
|
});
|
|
|
|
}
|
|
|
|
function initialize_volume() {
|
|
volumeSeries = chart.addHistogramSeries({title: "Volume", color: '#26a69a', priceFormat: {type: 'volume'}, priceScaleId: ''});
|
|
volumeSeries.priceScale().applyOptions({
|
|
// set the positioning of the volume series
|
|
scaleMargins: {
|
|
top: 0.7, // highest point of the series will be 70% away from the top
|
|
bottom: 0,
|
|
},
|
|
});
|
|
}
|
|
|
|
function initialize_vwap() {
|
|
vwapSeries = chart.addLineSeries({
|
|
// title: "vwap",
|
|
color: '#2962FF',
|
|
lineWidth: 1,
|
|
lastValueVisible: false,
|
|
priceLineVisible: false
|
|
})
|
|
}
|
|
|
|
function remove_indicator_buttons() {
|
|
var elem1 = document.getElementById("indicatorsButtons");
|
|
elem1.remove()
|
|
}
|
|
|
|
//pomocna funkce pro vytvoreni buttonu indiaktoru
|
|
function create_indicator_button(item, index, def) {
|
|
// //div pro kazdy button
|
|
// var buttonContainer = document.createElement('div');
|
|
// buttonContainer.classList.add('button-container');
|
|
|
|
var itemEl = document.createElement('button');
|
|
itemEl.innerText = item.name;
|
|
itemEl.id = "IND"+index;
|
|
itemEl.title = item.cnf
|
|
itemEl.style.color = item.series.options().color;
|
|
//pokud jde o pridanou on the fly - vybarvime jinak
|
|
if (item.instant) {
|
|
itemEl.style.outline = "solid 1px"
|
|
}
|
|
itemEl.classList.add('switcher-item');
|
|
if (def) {
|
|
itemEl.classList.add('switcher-active-item');
|
|
}
|
|
|
|
// //jeste vytvorime pod tim overlay a nad to az dame linky
|
|
// // Create the overlay element.
|
|
// const overlay = document.createElement("div");
|
|
// overlay.id = "OVR"+index;
|
|
// overlay.classList.add("overlayLayer");
|
|
// overlay.classList.add("hidden");
|
|
|
|
// // Create the action buttons.
|
|
// const actionShow = document.createElement("div");
|
|
// actionShow.id = "actionShow";
|
|
// actionShow.textContent = "Show";
|
|
|
|
itemEl.addEventListener('click', function() {
|
|
onItemClickedToggle(index);
|
|
});
|
|
|
|
// const actionEdit = document.createElement("div");
|
|
// actionEdit.id = "actionEdit";
|
|
// actionEdit.textContent = "Edit";
|
|
|
|
itemEl.addEventListener('contextmenu', function(e) {
|
|
//edit modal zatim nemame
|
|
onItemClickedEdit(e, index);
|
|
});
|
|
|
|
// // Append the action buttons to the overlay.
|
|
// overlay.appendChild(actionShow);
|
|
// overlay.appendChild(actionEdit);
|
|
|
|
// // Add a hover listener to the button.
|
|
// itemEl.addEventListener("mouseover", toggleOverlay(index));
|
|
// itemEl.addEventListener("mouseout", toggleOverlay(index));
|
|
|
|
// buttonContainer.appendChild(itemEl)
|
|
// buttonContainer.appendChild(overlay)
|
|
return itemEl
|
|
}
|
|
|
|
//pomocne funkce
|
|
function onResetClicked() {
|
|
indList.forEach(function (item, index) {
|
|
vis = true;
|
|
const elem = document.getElementById("IND"+index);
|
|
if (elem.classList.contains("switcher-active-item")) {
|
|
vis = false;
|
|
}
|
|
elem.classList.toggle("switcher-active-item");
|
|
if (indList[index].series) {
|
|
indList[index].series.applyOptions({
|
|
visible: vis });
|
|
}
|
|
})
|
|
store_activated_buttons_state();
|
|
}
|
|
|
|
|
|
function generateIndicators(e) {
|
|
store_activated_buttons_state();
|
|
|
|
ind_tom = ""
|
|
indList.forEach(function (item, index) {
|
|
if (activatedButtons.includes(item.name)) {
|
|
console.log(item)
|
|
ind_tom += "\n[stratvars.indicators."+item.name+"]\n" + item.cnf
|
|
}
|
|
});
|
|
|
|
if (ind_editor) {
|
|
ind_editor.dispose()
|
|
}
|
|
require(["vs/editor/editor.main"], () => {
|
|
ind_editor = monaco.editor.create(document.getElementById('indicatorTOML_editor'), {
|
|
value: ind_tom,
|
|
language: 'toml',
|
|
theme: 'tomlTheme-dark',
|
|
automaticLayout: true
|
|
});
|
|
});
|
|
$('#deleteIndicatorButton').hide();
|
|
$('#saveIndicatorButton').hide();
|
|
window.$('#indicatorModal').modal('show');
|
|
}
|
|
|
|
//editace indikatoru, vcetne vytvoreni noveho
|
|
function onItemClickedEdit(e, index) {
|
|
if (ind_editor) {
|
|
ind_editor.dispose()
|
|
}
|
|
title = `#[stratvars.indicators.name]
|
|
`
|
|
const elem = document.getElementById("IND"+index);
|
|
//console.log("element",elem)
|
|
//jde o update
|
|
if (elem) {
|
|
elem.classList.replace('switcher-item', 'switcher-item-highlighted');
|
|
$('#indicatorName').val(elem.textContent)
|
|
$('#indicatorNameTitle').text(elem.textContent)
|
|
title = elem.title
|
|
}
|
|
//jde o novy zaznam - davame pryc delete
|
|
else {
|
|
$('#deleteIndicatorButton').hide();
|
|
}
|
|
e.preventDefault()
|
|
//$('#stratvar_id').val(row.id);
|
|
$('#indicatorId').val(index)
|
|
|
|
require(["vs/editor/editor.main"], () => {
|
|
ind_editor = monaco.editor.create(document.getElementById('indicatorTOML_editor'), {
|
|
value: title,
|
|
language: 'toml',
|
|
theme: 'tomlTheme-dark',
|
|
automaticLayout: true
|
|
});
|
|
});
|
|
window.$('#indicatorModal').modal('show');
|
|
}
|
|
|
|
//togle profit line
|
|
function profitLineToggle() {
|
|
vis = true;
|
|
const elem = document.getElementById("profitLine");
|
|
if (elem.classList.contains("switcher-active-item")) {
|
|
vis = false;
|
|
}
|
|
elem.classList.toggle("switcher-active-item");
|
|
//v ifu kvuli workaroundu
|
|
if (profitLine) {
|
|
profitLine.applyOptions({
|
|
visible: vis });
|
|
}
|
|
}
|
|
|
|
//togle go wide
|
|
function toggleWide() {
|
|
width = 1600;
|
|
const elem = document.getElementById("goWide");
|
|
const msgContainer = document.getElementById("msgContainer");
|
|
const msgContainerInner = document.getElementById("msgContainerInner");
|
|
const clrButton = document.getElementById("clrButton");
|
|
|
|
if (elem.classList.contains("switcher-active-item")) {
|
|
width = 1024;
|
|
msgContainer.removeAttribute("style");
|
|
msgContainerInner.removeAttribute("style");
|
|
clrButton.removeAttribute("style");
|
|
} else
|
|
{
|
|
msgContainer.style.display = "block"
|
|
msgContainerInner.style.display = "none"
|
|
clrButton.style.display = "none"
|
|
}
|
|
elem.classList.toggle("switcher-active-item");
|
|
|
|
if (chart) {
|
|
chart.applyOptions({ width: width});
|
|
chart.timeScale().fitContent();
|
|
}
|
|
}
|
|
|
|
//togle profit line
|
|
function toggleVolume() {
|
|
vis = true;
|
|
const elem = document.getElementById("volToggle");
|
|
if (elem.classList.contains("switcher-active-item")) {
|
|
vis = false;
|
|
}
|
|
elem.classList.toggle("switcher-active-item");
|
|
//v ifu kvuli workaroundu
|
|
if (volumeSeries) {
|
|
volumeSeries.applyOptions({
|
|
visible: vis });
|
|
}
|
|
}
|
|
|
|
//togle profit line
|
|
function mrkLineToggle() {
|
|
vis = true;
|
|
const elem = document.getElementById("mrkLine");
|
|
if (elem.classList.contains("switcher-active-item")) {
|
|
vis = false;
|
|
}
|
|
elem.classList.toggle("switcher-active-item");
|
|
//v ifu kvuli workaroundu
|
|
if (markersLine) {
|
|
markersLine.applyOptions({
|
|
visible: vis });
|
|
}
|
|
if (slLine) {
|
|
slLine.forEach((series, index, array) => {
|
|
series.applyOptions({
|
|
visible: vis });
|
|
})
|
|
}
|
|
}
|
|
|
|
|
|
//toggle indiktoru
|
|
function onItemClickedToggle(index) {
|
|
vis = true;
|
|
const elem = document.getElementById("IND"+index);
|
|
if (elem.classList.contains("switcher-active-item")) {
|
|
vis = false;
|
|
}
|
|
elem.classList.toggle("switcher-active-item");
|
|
//v ifu kvuli workaroundu
|
|
if (indList[index].series) {
|
|
//console.log(indList[index].name, indList[index].series)
|
|
indList[index].series.applyOptions({
|
|
visible: vis });
|
|
}
|
|
//zatim takto workaround, pak vymyslet systemove pro vsechny tickbased indikatory
|
|
tickIndicatorList = ["tick_price", "tick_volume"]
|
|
if (tickIndicatorList.includes(indList[index].name)) {
|
|
if (!vis && indList[index].series) {
|
|
//console.log("pred", indList[index].name, indList[index].series)
|
|
chart.removeSeries(indList[index].series)
|
|
chart.timeScale().fitContent();
|
|
indList[index].series = null
|
|
//console.log("po", indList[index].name, indList[index].series)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//funkce pro vytvoreni buttonku indikatoru
|
|
function populate_indicator_buttons(def) {
|
|
|
|
//vytvoreni outer button divu
|
|
var buttonElement = document.createElement('div');
|
|
buttonElement.id = "indicatorsButtons"
|
|
buttonElement.classList.add('switcher');
|
|
|
|
//iterace nad indikatory a vytvareni buttonků
|
|
indList.forEach(function (item, index) {
|
|
index_ind = index
|
|
active = false
|
|
|
|
//console.log("activatedButtons", activatedButtons)
|
|
//console.log("obsahuje item.name", activatedButtons.includes(item.name), item.name)
|
|
//pokud existuje v aktivnich pak
|
|
//console.log("vytvarime button",item.name,activatedButtons)
|
|
if ((activatedButtons) && (activatedButtons.includes(item.name))) {
|
|
active = true
|
|
}
|
|
//vytvoreni buttonku
|
|
itemEl = create_indicator_button(item, index, def||active);
|
|
//prirazeni do divu
|
|
buttonElement.appendChild(itemEl); ;
|
|
});
|
|
|
|
|
|
var funcButtonElement = document.createElement('div');
|
|
funcButtonElement.id = "funcIndicatorsButtons"
|
|
funcButtonElement.classList.add('funcButtons');
|
|
|
|
|
|
//create toggle all button
|
|
var itemEl = document.createElement('button');
|
|
itemEl.innerText = "all"
|
|
itemEl.classList.add('switcher-item');
|
|
if (def) {
|
|
itemEl.classList.add('switcher-active-item');
|
|
}
|
|
itemEl.addEventListener('click', function() {
|
|
onResetClicked();
|
|
});
|
|
funcButtonElement.appendChild(itemEl);
|
|
|
|
//button pro toggle profitu
|
|
var itemEl = document.createElement('button');
|
|
itemEl.innerText = "prof"
|
|
itemEl.classList.add('switcher-item');
|
|
itemEl.style.color = "#99912b"
|
|
itemEl.id = "profitLine"
|
|
itemEl.addEventListener('click', function(e) {
|
|
profitLineToggle();
|
|
});
|
|
funcButtonElement.appendChild(itemEl);
|
|
|
|
//button pro toggle fullscreenu
|
|
var itemEl = document.createElement('button');
|
|
itemEl.innerText = "wide"
|
|
itemEl.classList.add('switcher-item');
|
|
itemEl.style.color = "#99912b"
|
|
itemEl.id = "goWide"
|
|
itemEl.addEventListener('click', function(e) {
|
|
toggleWide();
|
|
});
|
|
funcButtonElement.appendChild(itemEl);
|
|
|
|
//button pro toggle fullscreenu
|
|
var itemEl = document.createElement('button');
|
|
itemEl.innerText = "vol"
|
|
itemEl.classList.add('switcher-item');
|
|
itemEl.classList.add('switcher-active-item');
|
|
itemEl.style.color = "#99912b"
|
|
itemEl.id = "volToggle"
|
|
itemEl.addEventListener('click', function(e) {
|
|
toggleVolume();
|
|
});
|
|
funcButtonElement.appendChild(itemEl);
|
|
|
|
// //button pro toggle markeru nakupu/prodeju
|
|
var itemEl = document.createElement('button');
|
|
itemEl.innerText = "mrk"
|
|
itemEl.classList.add('switcher-item');
|
|
itemEl.classList.add('switcher-active-item');
|
|
// if ((activatedButtons) && (!activatedButtons.includes("mrk"))) {
|
|
// }
|
|
// else {
|
|
|
|
// }
|
|
|
|
|
|
itemEl.style.color = "#99912b"
|
|
itemEl.id = "mrkLine"
|
|
|
|
// // Create an icon element
|
|
// const iconEl = document.createElement('i');
|
|
// // Set the icon class
|
|
// iconEl.classList.add('bi');
|
|
// iconEl.classList.add('bi-rainbow'); // Replace `icon-name` with the name of the icon you want to use
|
|
// // Append the icon element to the button element
|
|
// itemEl.appendChild(iconEl);
|
|
|
|
itemEl.addEventListener('click', function(e) {
|
|
mrkLineToggle();
|
|
});
|
|
|
|
funcButtonElement.appendChild(itemEl);
|
|
|
|
//create plus button to create new button
|
|
var itemEl = document.createElement('button');
|
|
itemEl.innerText = "+"
|
|
itemEl.classList.add('switcher-item');
|
|
//na tomto je navesena jquery pro otevreni modalu
|
|
itemEl.id = "button_addindicator"
|
|
itemEl.addEventListener('click', function(e) {
|
|
index_ind++
|
|
onItemClickedEdit(e, index_ind);
|
|
});
|
|
funcButtonElement.appendChild(itemEl);
|
|
|
|
//save indicator buttons - will generate indicators to stratvars
|
|
var itemEl = document.createElement('button');
|
|
itemEl.innerText = "generate"
|
|
itemEl.classList.add('switcher-item');
|
|
//na tomto je navesena jquery pro otevreni modalu
|
|
itemEl.id = "save_indicators"
|
|
itemEl.addEventListener('click', function(e) {
|
|
index_ind++
|
|
generateIndicators(e);
|
|
});
|
|
funcButtonElement.appendChild(itemEl);
|
|
|
|
buttonElement.appendChild(funcButtonElement)
|
|
|
|
return buttonElement;
|
|
}
|
|
|
|
|
|
//range switch pro chart https://jsfiddle.net/TradingView/qrb9a850/
|
|
function createSimpleSwitcher(items, activeItem, activeItemChangedCallback, data) {
|
|
var switcherElement = document.createElement('div');
|
|
switcherElement.classList.add('switcher');
|
|
|
|
var intervalElements = items.map(function(item) {
|
|
var itemEl = document.createElement('button');
|
|
itemEl.innerText = item;
|
|
itemEl.classList.add('switcher-item');
|
|
itemEl.classList.toggle('switcher-active-item', item === activeItem);
|
|
itemEl.addEventListener('click', function() {
|
|
onItemClicked(item);
|
|
});
|
|
switcherElement.appendChild(itemEl);
|
|
return itemEl;
|
|
});
|
|
|
|
function onItemClicked(item) {
|
|
if (item === activeItem) {
|
|
return;
|
|
}
|
|
|
|
intervalElements.forEach(function(element, index) {
|
|
element.classList.toggle('switcher-active-item', items[index] === item);
|
|
});
|
|
|
|
activeItem = item;
|
|
|
|
activeItemChangedCallback(item, data);
|
|
}
|
|
|
|
return switcherElement;
|
|
}
|
|
|
|
// safely handles circular references https://stackoverflow.com/questions/11616630/how-can-i-print-a-circular-structure-in-a-json-like-format
|
|
JSON.safeStringify = (obj, indent = 2) => {
|
|
let cache = [];
|
|
const retVal = JSON.stringify(
|
|
obj,
|
|
(key, value) =>
|
|
typeof value === "object" && value !== null
|
|
? cache.includes(value)
|
|
? undefined // Duplicate reference found, discard key
|
|
: cache.push(value) && value // Store value in our collection
|
|
: value,
|
|
indent
|
|
);
|
|
cache = null;
|
|
return retVal;
|
|
};
|
|
|
|
function isToday(someDate) {
|
|
const today = new Date()
|
|
return someDate.getDate() == today.getDate() &&
|
|
someDate.getMonth() == today.getMonth() &&
|
|
someDate.getFullYear() == today.getFullYear()
|
|
}
|
|
|
|
//https://www.w3schools.com/jsref/jsref_tolocalestring.asp
|
|
function format_date(datum, markettime = false, timeonly = false) {
|
|
//const options = { weekday: 'long', year: 'numeric', month: 'numeric', day: 'numeric', };
|
|
// date.toLocaleString('en-US', {
|
|
// timeZone: 'America/New_York',
|
|
// })
|
|
//'Europe/Berlin'
|
|
var options = {}
|
|
if (timeonly) {
|
|
options = {hour: '2-digit', hour12: false, minute: '2-digit'}
|
|
}
|
|
else {
|
|
options = {dateStyle: "short", timeStyle: "short"}
|
|
}
|
|
|
|
if (markettime) {
|
|
options["timeZone"] = 'America/New_York'
|
|
}
|
|
const date = new Date(datum);
|
|
return date.toLocaleString('cs-CZ', options);
|
|
}
|
|
|
|
function clear_status_header() {
|
|
$("#statusArchId").text("")
|
|
$("#statusRegime").text("")
|
|
$("#statusName").text("")
|
|
$("#statusMode").text("")
|
|
$("#statusAccount").text("")
|
|
$("#statusIlog").text("")
|
|
$("#statusStratvars").text("")
|
|
//clear previous logs from rt
|
|
$("#lines").empty()
|
|
}
|
|
|
|
// Iterate through each element in the
|
|
// first array and if some of them
|
|
// include the elements in the second
|
|
// array then return true.
|
|
function findCommonElements3(arr1, arr2) {
|
|
return arr1.some(item => arr2.includes(item))
|
|
}
|
|
|
|
function set_timestamp(timestamp) {
|
|
//console.log(timestamp);
|
|
$('#trade-timestamp').val(timestamp);
|
|
}
|
|
|
|
//KEY shortcuts
|
|
Mousetrap.bind('q', function() {
|
|
$( "#button_report" ).trigger( "click" );
|
|
});
|
|
|
|
Mousetrap.bind('e', function() {
|
|
$( "#button_edit" ).trigger( "click" );
|
|
});
|
|
// Mousetrap.bind('a', function() {
|
|
// $( "#button_add" ).trigger( "click" );
|
|
// });
|
|
Mousetrap.bind('d', function() {
|
|
$( "#button_delete_arch" ).trigger( "click" );
|
|
});
|
|
Mousetrap.bind('b', function() {
|
|
$( "#button_delete_batch" ).trigger( "click" );
|
|
});
|
|
Mousetrap.bind('c', function() {
|
|
$( "#button_copy" ).trigger( "click" );
|
|
});
|
|
Mousetrap.bind('y', function() {
|
|
$( "#button_run" ).trigger( "click" );
|
|
});
|
|
Mousetrap.bind('r', function() {
|
|
$( "#button_runagain_arch" ).trigger( "click" );
|
|
});
|
|
Mousetrap.bind('p', function() {
|
|
$( "#button_pause" ).trigger( "click" );
|
|
});
|
|
Mousetrap.bind('s', function() {
|
|
$( "#button_edit_stratvars" ).trigger( "click" );
|
|
});
|
|
Mousetrap.bind('a', function() {
|
|
$( "#button_edit_arch" ).trigger( "click" );
|
|
});
|
|
Mousetrap.bind('j', function() {
|
|
$( "#button_add_json" ).trigger( "click" );
|
|
});
|
|
Mousetrap.bind('x', function() {
|
|
$( "#button_delete" ).trigger( "click" );
|
|
});
|
|
Mousetrap.bind('w', function() {
|
|
$( "#button_show_arch" ).trigger( "click" );
|
|
});
|
|
|
|
//ENTERS
|
|
// Mousetrap.bind('enter', function() {
|
|
// $( "#deletearchive" ).trigger( "click" );
|
|
// });
|
|
// function compareObjects(obj1, obj2) {
|
|
// const diff = {};
|
|
|
|
// for (let key in obj1) {
|
|
// if (typeof obj1[key] === 'object' && typeof obj2[key] === 'object') {
|
|
// if (Array.isArray(obj1[key]) && Array.isArray(obj2[key])) {
|
|
// if (!arraysAreEqual(obj1[key], obj2[key])) {
|
|
// diff[key] = obj2[key];
|
|
// }
|
|
// } else {
|
|
// const nestedDiff = compareObjects(obj1[key], obj2[key]);
|
|
// if (Object.keys(nestedDiff).length > 0) {
|
|
// diff[key] = nestedDiff;
|
|
// }
|
|
// }
|
|
// } else if (obj1[key] !== obj2[key]) {
|
|
// diff[key] = obj2[key];
|
|
// }
|
|
// }
|
|
|
|
// return diff;
|
|
// }
|
|
|
|
function compareObjects(obj1, obj2) {
|
|
const diff = {};
|
|
|
|
for (let key in obj1) {
|
|
if (!(key in obj2)) {
|
|
diff[key] = obj1[key];
|
|
continue;
|
|
}
|
|
|
|
if (typeof obj1[key] === 'object' && typeof obj2[key] === 'object') {
|
|
if (Array.isArray(obj1[key]) && Array.isArray(obj2[key])) {
|
|
if (!arraysAreEqual(obj1[key], obj2[key])) {
|
|
diff[key] = obj2[key];
|
|
}
|
|
} else {
|
|
const nestedDiff = compareObjects(obj1[key], obj2[key]);
|
|
if (Object.keys(nestedDiff).length > 0) {
|
|
diff[key] = nestedDiff;
|
|
}
|
|
}
|
|
} else if (obj1[key] !== obj2[key]) {
|
|
diff[key] = obj2[key];
|
|
}
|
|
}
|
|
|
|
for (let key in obj2) {
|
|
if (!(key in obj1)) {
|
|
diff[key] = obj2[key];
|
|
}
|
|
}
|
|
|
|
return diff;
|
|
}
|
|
|
|
|
|
|
|
function arraysAreEqual(arr1, arr2) {
|
|
if (arr1.length !== arr2.length) {
|
|
return false;
|
|
}
|
|
|
|
for (let i = 0; i < arr1.length; i++) {
|
|
if (typeof arr1[i] === 'object' && typeof arr2[i] === 'object') {
|
|
const nestedDiff = compareObjects(arr1[i], arr2[i]);
|
|
if (Object.keys(nestedDiff).length > 0) {
|
|
return false;
|
|
}
|
|
} else if (arr1[i] !== arr2[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function generateHTML(obj, diff, indent = '') {
|
|
let html = '';
|
|
|
|
for (let key in obj) {
|
|
const value = obj[key];
|
|
|
|
if (typeof value === 'object' && value !== null) {
|
|
const nestedDiff = diff[key] || {};
|
|
const nestedIndent = indent + ' ';
|
|
if (Array.isArray(value)) {
|
|
html += `${indent}"${key}": [\n${generateHTMLArray(value, nestedDiff, nestedIndent)}${indent}],\n`;
|
|
} else {
|
|
html += `${indent}"${key}": {\n${generateHTML(value, nestedDiff, nestedIndent)}${indent}},\n`;
|
|
}
|
|
} else {
|
|
if (key in diff) {
|
|
html += `${indent}"${key}": <span style="background-color: yellow;">${JSON.stringify(value)}</span>,\n`;
|
|
} else {
|
|
html += `${indent}"${key}": ${JSON.stringify(value)},\n`;
|
|
}
|
|
}
|
|
}
|
|
|
|
return html;
|
|
}
|
|
|
|
function generateHTMLArray(arr, diff, indent) {
|
|
let html = '';
|
|
|
|
for (let i = 0; i < arr.length; i++) {
|
|
const value = arr[i];
|
|
if (typeof value === 'object' && value !== null) {
|
|
const nestedDiff = diff[i] || {};
|
|
const nestedIndent = indent + ' ';
|
|
if (Array.isArray(value)) {
|
|
html += `${indent}[\n${generateHTMLArray(value, nestedDiff, nestedIndent)}${indent}],\n`;
|
|
} else {
|
|
html += `${indent}{\n${generateHTML(value, nestedDiff, nestedIndent)}${indent}},\n`;
|
|
}
|
|
} else {
|
|
if (i in diff) {
|
|
html += `${indent}<span style="background-color: yellow;">${JSON.stringify(value)}</span>,\n`;
|
|
} else {
|
|
html += `${indent}${JSON.stringify(value)},\n`;
|
|
}
|
|
}
|
|
}
|
|
|
|
return html;
|
|
} |