Files
v2realbot/v2realbot/static/js/utils/utils.js
2024-02-27 12:03:57 +07:00

1237 lines
44 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, pro tickbased (1) vracime embed false pokud je globalni ()
function get_ind_config(indName, tick_based = 0) {
//def settings
def = {name: "ema", titlevisible: false, embed: true, display: true, priceScaleId: "middle", lastValueVisible: false}
//WORKAROUND to DISABLE TICK INDS - skip config
var hideTickIndicators = localStorage.getItem('hideTickIndicators');
console.log("jsme v IND CONFIG. hodnota hideTickIndicators =",hideTickIndicators)
//pokud jde tick_based a mam v local storage nastaveno hideTickInds pak nastavuju embed na false - coz nezobrazi tickindikatory
if ((tick_based == 1) && hideTickIndicators && hideTickIndicators == "true") {
def.embed = false
console.log("pro",indName,"vracime embed false")
return def
}
//END WORKAROUND
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, def, noaction = false) {
// //div pro kazdy button
// var buttonContainer = document.createElement('div');
// buttonContainer.classList.add('button-container');
index = item.indId
var itemEl = document.createElement('button');
itemEl.innerText = item.name;
itemEl.id = "IND"+item.indId;
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";
//nepouzivat pro urcite pripady (napr. u hlavnich multioutputu indikatoru) - pouze nese predpis(right click) a left clickem zobrazi outputy
if (!noaction) {
itemEl.addEventListener('click', function() {
onItemClickedToggle(item.indId);
});
}
// const actionEdit = document.createElement("div");
// actionEdit.id = "actionEdit";
// actionEdit.textContent = "Edit";
itemEl.addEventListener('contextmenu', function(e) {
//edit modal zatim nemame
onItemClickedEdit(e, item.indId);
});
// // 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"+item.indId);
if (elem.classList.contains("switcher-active-item")) {
vis = false;
}
elem.classList.toggle("switcher-active-item");
if (obj.series) {
obj.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 toggleTick() {
const elem = document.getElementById("tickToggle");
if (elem.classList.contains("switcher-active-item")) {
localStorage.setItem('hideTickIndicators', 'false');
}
else {
localStorage.setItem('hideTickIndicators', 'true');
}
elem.classList.toggle("switcher-active-item");
//toggle repaint - click on change resolution
var activeButton = document.querySelector('#changeResolution .switcher-active-item');
// Click the button programmatically
if (activeButton) {
activeButton.click();
}
}
//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 });
})
}
}
function get_ind_by_id(indId) {
return indList.find(obj => obj.indId === indId);
}
//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
obj = get_ind_by_id(index)
if (obj.series) {
//console.log(obj.name, obj.series)
obj.series.applyOptions({
visible: vis });
}
//zatim takto workaround, pak vymyslet systemove pro vsechny tickbased indikatory
tickIndicatorList = ["tick_price", "tick_volume"]
if (tickIndicatorList.includes(obj.name)) {
if (!vis && obj.series) {
//console.log("pred", obj.name, obj.series)
chart.removeSeries(obj.series)
chart.timeScale().fitContent();
obj.series = null
//console.log("po", obj.name, obj.series)
}
}
}
//obalka pro collapsovatelny multioutput indicator button
function create_multioutput_button(item, def, active) {
//encapsulating dic
var multiOutEl = document.createElement('div');
//multiOutEl.id = "tickIndicatorsButtons"
multiOutEl.classList.add('multiOut');
multiOutEl.classList.add('switcher-item');
//pouze def - u main indikatoru nepamatujeme stav a pozadujeme noaction pro leftclick
//def||active - ani def
itemEl = create_indicator_button(item, false, true);
//hlavni button ridi expand/collapse
itemEl.setAttribute('data-bs-toggle', 'collapse');
itemEl.setAttribute('data-bs-target', '.'+item.name);
itemEl.setAttribute('aria-expanded', 'true');
itemEl.setAttribute('role', 'button');
//itemEl.setAttribute('aria-controls', 'IND6 IND7 IND8');
//itemEl.style.outline = 'dotted';
itemEl.style.marginRight = '0px'
//prirazeni mainu do divu
multiOutEl.appendChild(itemEl);
//pokud nektery z multivstupu je aktivni, pak nastavuju vse expanded
const isAnyActive = activatedButtons.some(element => item.returns.includes(element));
item.returns.forEach(function (output_name,index) {
active = false
//find and process multioutput parameters
const foundObject = indList.find(obj => obj.name == output_name);
if (foundObject) {
//aplikujeme remembered state
if ((activatedButtons) && (activatedButtons.includes(output_name))) {
active = true
}
console.log(foundObject.content); // Access and use the content
itemEl = create_indicator_button(foundObject, def||active);
itemEl.classList.add('collapse')
//pokud je aktivni jakykoliv, expandujeme vsechny
if (active || isAnyActive) {
itemEl.classList.add('show')
}
itemEl.classList.add(item.name)
itemEl.style.marginRight = '0px'
multiOutEl.appendChild(itemEl);
}
});
return multiOutEl
}
//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');
//incializujeme i div pro cbar indikator sekci
var tickButtonElement = document.createElement('div');
tickButtonElement.id = "tickIndicatorsButtons"
tickButtonElement.classList.add('tickButtons');
already_processed = [];
//iterace nad indikatory a vytvareni buttonků
indList.forEach(function (item, index) {
index_ind = item.indId
if (!already_processed.includes(item.name)) {
active = false
if ((activatedButtons) && (activatedButtons.includes(item.name))) {
active = true
}
//bar indikatory jsou serazeny na zacarku
if (item.type == 0) {
//pokud jde o multiinput, pridame ihned souvisejici mutiinputy a vse dame do stejneho divu
//(Object.keys(data[0]).length > 0)
if (item.returns && item.returns.length > 0) {
//prirazeni multiOut do buttonu
multiOutEl = create_multioutput_button(item, def, active)
buttonElement.appendChild(multiOutEl);
already_processed = already_processed.concat(item.returns)
}
else {
//vytvoreni buttonku
itemEl = create_indicator_button(item, def||active);
//prirazeni do divu
buttonElement.appendChild(itemEl);
}
}
//ted zbyvaji tick barové a ty dáme do separátního divu
else
{
//oper nejdriv multiinput
if (item.returns && item.returns.length > 0) {
//prirazeni multiOut do buttonu
multiOutEl = create_multioutput_button(item, def, active)
tickButtonElement.appendChild(multiOutEl);
already_processed = already_processed.concat(item.returns)
}
//standardni non multiinput
else {
//vytvoreni buttonku
itemEl = create_indicator_button(item, def||active);
tickButtonElement.appendChild(itemEl)
}
}
}
});
//nakonec pripojime cely div s tick based indicatory
buttonElement.appendChild(tickButtonElement);
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 disable tickIndicatoru
var itemEl = document.createElement('button');
itemEl.innerText = "ticks off"
itemEl.classList.add('switcher-item');
var hideTickIndicators = localStorage.getItem('hideTickIndicators');
console.log("init button, hodnota hideTickIndicators", hideTickIndicators)
if (hideTickIndicators && hideTickIndicators == "true") {
itemEl.classList.add('switcher-active-item');
}
itemEl.style.color = "#e0676e"
itemEl.id = "tickToggle"
itemEl.addEventListener('click', function(e) {
toggleTick();
});
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');
switcherElement.id = "changeResolution"
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) {
// Convert input date to Eastern Time
var dateInEastern = new Date(someDate.toLocaleString('en-US', { timeZone: 'America/New_York' }));
//console.log("vstupuje ",someDate)
//console.log("americky ",dateInEastern)
// Get today's date in Eastern Time
var todayInEastern = new Date(new Date().toLocaleString('en-US', { timeZone: 'America/New_York' }));
return dateInEastern.getDate() === todayInEastern.getDate() &&
dateInEastern.getMonth() === todayInEastern.getMonth() &&
dateInEastern.getFullYear() === todayInEastern.getFullYear();
}
// 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;
}