Files
v2realbot/v2realbot/static/js/utils.js
David Brazda 3810fbe87b bugfix
2023-10-10 13:53:16 +02:00

678 lines
24 KiB
JavaScript

API_KEY = localStorage.getItem("api-key")
var chart = null
// var colors = ["#8B1874","#B71375","#B46060","#61c740","#BE6DB7","#898121","#4389d9","#00425A","#B5D5C5","#e61957","#8B1874","#B71375","#B46060","#61c740","#BE6DB7","#898121","#4389d9","#00425A","#B5D5C5","#e61957"]
// var reset_colors = ["#8B1874","#B71375","#B46060","#61c740","#BE6DB7","#898121","#4389d9","#00425A","#B5D5C5","#e61957","#8B1874","#B71375","#B46060","#61c740","#BE6DB7","#898121","#4389d9","#00425A","#B5D5C5","#e61957"]
var colors = ["#8B1874","#B71375","#B46060","#61c740","#BE6DB7","#898121","#4389d9","#00425A","#B5D5C5","#e61957","#7B0E60","#9B2888","#BD38A0","#A30F68","#6E0B50","#CA2183","#E6319B","#A04C54","#643848","#CA7474","#E68D8D","#4F9C34","#3B7128","#73DF4D","#95EF65","#A857A4","#824690","#D087CC","#E2A1DF","#79711B","#635D17","#99912B","#B1A73D","#3779C9","#2B68B3","#5599ED","#77A9F7","#004C67","#00687D","#A1C6B5","#8CC6A5","#C9E6D5","#E4F6EA","#D2144A","#A60F3B","#FA2463","#FF3775"];
var reset_colors = ["#8B1874","#B71375","#B46060","#61c740","#BE6DB7","#898121","#4389d9","#00425A","#B5D5C5","#e61957","#7B0E60","#9B2888","#BD38A0","#A30F68","#6E0B50","#CA2183","#E6319B","#A04C54","#643848","#CA7474","#E68D8D","#4F9C34","#3B7128","#73DF4D","#95EF65","#A857A4","#824690","#D087CC","#E2A1DF","#79711B","#635D17","#99912B","#B1A73D","#3779C9","#2B68B3","#5599ED","#77A9F7","#004C67","#00687D","#A1C6B5","#8CC6A5","#C9E6D5","#E4F6EA","#D2144A","#A60F3B","#FA2463","#FF3775"];
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 = {}
}
const sorter = (a, b) => a.time > b.time ? 1 : -1;
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(JSON.stringify(statusBarConfig))
// Create the grid table
var gridTable = document.getElementById('statusHeaderTool');
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);
}
}
function get_ind_config(indName) {
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 null
}
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: 1080,
height: 600,
leftPriceScale: {visible: true},
layout: {
background: {
type: 'solid',
color: '#2a2e39',
},
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()
}
function populate_indicator_buttons(def) {
var buttonElement = document.createElement('div');
buttonElement.id = "indicatorsButtons"
buttonElement.classList.add('switcher');
indList.forEach(function (item, index) {
var itemEl = document.createElement('button');
itemEl.innerText = item.name;
itemEl.id = "IND"+index;
itemEl.title = item.cnf
itemEl.style.color = item.series.options().color;
itemEl.classList.add('switcher-item');
if (def) {
itemEl.classList.add('switcher-active-item');
}
itemEl.addEventListener('click', function() {
onItemClicked1(index);
});
buttonElement.appendChild(itemEl);
});
//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();
});
buttonElement.appendChild(itemEl);
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 });
}
})
}
function onItemClicked1(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) {
indList[index].series.applyOptions({
visible: vis });
}
//zatim takto workaround, pak vymyslet systemove pro vsechny tickbased indikatory
if (indList[index].name == "tick_price") {
if (!vis && indList[index].series) {
chart.removeSeries(indList[index].series)
chart.timeScale().fitContent();
indList[index].series = null
}
}
}
return buttonElement;
}
//range switch pro chart https://jsfiddle.net/TradingView/qrb9a850/
function createSimpleSwitcher(items, activeItem, activeItemChangedCallback) {
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);
}
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() {
$("#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('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('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;
}