diff --git a/config.yml b/config.yml index e5dc007..6f58486 100644 --- a/config.yml +++ b/config.yml @@ -1,5 +1,5 @@ chart_configuration: - chart_interval: 1m + chart_interval: 4h trading_pair: BTCUSDT indicator_list: ATR: @@ -45,13 +45,13 @@ indicator_list: color_2: '#94f657' fast_p: 12 hist: 0 - macd: 0 - signal: 0 + macd: '-2540.72' + signal: '-1775.26' signal_p: 9 slow_p: 26 type: MACD value: 0 - visible: true + visible: 'False' New Indicator: color: '#d5ed5e' period: 20 @@ -76,6 +76,12 @@ indicator_list: type: RSI value: 0 visible: true + RSI_21: + color: '#ea3ea2' + period: 21 + type: RSI + value: '29.78' + visible: 'True' SMA 200: color: '#1d545c' period: 200 diff --git a/data.py b/data.py index ff130f2..89e1079 100644 --- a/data.py +++ b/data.py @@ -791,7 +791,7 @@ class BrighterData: def received_new_signal(self, data): # Check the data. if 'sigName' not in data: - return 'No name provided' + return 'data.py:received_new_signal() - The new signal has no name. ' Signal print(data) diff --git a/static/communication.js b/static/communication.js index ffe1703..94b71c6 100644 --- a/static/communication.js +++ b/static/communication.js @@ -31,7 +31,9 @@ class Comms { let id = fetch('http://localhost:5000/indicator_init').then((r) => r.json()).then( (data) => { return data; } ); return id; } - + send_to_app(message_type, data){ + this.app_con.send( JSON.stringify({ message_type: message_type, data : data })); + } set_app_con(){ // Create a web socket connection to our app. this.app_con = new WebSocket('ws://localhost:5000/ws'); diff --git a/static/general.js b/static/general.js index 28795e4..e501bdd 100644 --- a/static/general.js +++ b/static/general.js @@ -15,13 +15,6 @@ // this.height = height; // } //} -// -//class Signals { -// constructor() { -// this.height = height; -// } -//} -// //class Exchange_Info { // constructor() { // this.height = height; @@ -59,29 +52,37 @@ class User_Interface{ up-to-date configurable and variable data for the UI */ this.data = new Data(); - /* Charts object is responsible for maintaining the - data visualisation area in the UI. */ - let chart_init_data = { - chart1_id : this.data.chart1_id, - chart2_id : this.data.chart2_id, - chart3_id : this.data.chart3_id, - trading_pair : this.data.trading_pair, - price_history : this.data.price_history - } - this.charts = new Charts(chart_init_data); + /* These classes interact with HTML elements that need to be parsed first */ + window.addEventListener('load', function () { + /* Charts object is responsible for maintaining the + data visualisation area in the UI. */ + let chart_init_data = { + chart1_id : window.UI.data.chart1_id, + chart2_id : window.UI.data.chart2_id, + chart3_id : window.UI.data.chart3_id, + trading_pair : window.UI.data.trading_pair, + price_history : window.UI.data.price_history + } + window.UI.charts = new Charts(chart_init_data); + + /* The Indicators object is responsible for interactions with + the edit indicator menu and updating the display on the charts.*/ + let ind_init_data = { + indicators: window.UI.data.indicators, + indicator_data: window.UI.data.indicator_data + } + /* Pass the initialization for the indicators and a reference to + the charts object so the indicators can update it directly.*/ + window.UI.indicators = new Indicators(window.UI.charts, ind_init_data); + /* Point the callback fired when indicator updates are received + to the indicator class object.*/ + window.UI.data.set_i_updates(window.UI.indicators.update); + }); - /* The Indicators object is responsible for interactions with - the edit indicator menu and updating the display on the charts.*/ - let ind_init_data = { - indicators: this.data.indicators, - indicator_data: this.data.indicator_data - } - /* Pass the initialization for the indicators and a reference to - the charts object so the indicators can update it directly.*/ - this.indicators = new Indicators(this.charts, ind_init_data); - this.data.set_i_updates(this.indicators.update); /* The object that handles the interface controls.*/ this.controls = new Controls(); + /* The object that handles the signals interface.*/ + this.signals = new Signals(this.data.indicators); } } UI = new User_Interface(); diff --git a/static/indicators.js b/static/indicators.js index 87a55d5..1f43fa5 100644 --- a/static/indicators.js +++ b/static/indicators.js @@ -285,6 +285,7 @@ class Indicators { } update(updates){ + console.log(updates); for (name in updates){ window.UI.indicators.i_objs[name].update(updates[name].data); } @@ -293,9 +294,9 @@ class Indicators { add_to_list(){ // Adds user input to a list and displays it in a HTML element. // Used in the Create indicator panel (!)Called from inline html. - var n = document.getElementById("new_prop_name").value; - var v = document.getElementById("new_prop_value").value; - p={}; + let n = document.getElementById("new_prop_name").value; + let v = document.getElementById("new_prop_value").value; + let p={}; p[n] = v; if (document.getElementById("new_prop_list").innerHTML ==""){ document.getElementById("new_prop_list").insertAdjacentHTML('beforeend', JSON.stringify(p)); @@ -305,7 +306,7 @@ class Indicators { submit_new_i(){ /* Populates a hidden with a value from another element then submits the form Used in the create indicator panel.*/ - pl=document.getElementById("new_prop_list").innerHTML; + let pl=document.getElementById("new_prop_list").innerHTML; if(pl) { pl = '[' + pl + ']'; } document.getElementById("new_prop_obj").value=pl; document.getElementById("new_i_form").submit(); diff --git a/static/signals.js b/static/signals.js new file mode 100644 index 0000000..f43eae9 --- /dev/null +++ b/static/signals.js @@ -0,0 +1,179 @@ +class Signals { + constructor(indicators) { + this.indicators = indicators; + } + // Call to display Create new signal dialog. + open_signal_Form() { document.getElementById("new_sig_form").style.display = "grid"; } + // Call to hide Create new signal dialog. + close_signal_Form() { document.getElementById("new_sig_form").style.display = "none"; } + + fill_prop(target_id, indctr){ + // arg1: Id of of a selection element. + // arg2: Name of an indicator + // Replace the options of an HTML select elements + // with the properties an indicator object. + + // Fetch the objects using name and id received. + var target = document.getElementById(target_id); + var properties = window.UI.data.indicators[indctr]; + + // Remove any previous options in the select tag. + removeOptions(target); + // Loop through each property in the object. + // Create an option element for each one. + // Append it to the selection element. + for(let prop in properties) + { + if (prop =='type'|| prop == 'visible' || prop == 'period'){continue;} + if (prop.substring(0,5) == 'color'){continue;} + var opt = document.createElement("option"); + opt.innerHTML = prop; + target.appendChild(opt); + } + return; + function removeOptions(selectElement) { + var i, L = selectElement.options.length - 1; + for(i = L; i >= 0; i--) { + selectElement.remove(i); + } + } + } + switch_panel(p1,p2){ + // Panel switcher for multi page forms + // arg1 = target from id + // arg2 = next target id + // This function is used in the New Signal dialog in signals + document.getElementById(p1).style.display='none'; + document.getElementById(p2).style.display='grid'; + } + + hideIfTrue(firstValue, scndValue, id){ + // Compare first two args and hides an element if they are equal. + // This function is used in the New Signal dialog in signals + if( firstValue == scndValue){ + document.getElementById(id).style.display='none'; + }else{ + document.getElementById(id).style.display='block' + } + } + ns_next(n){ + // This function is used in the New Signal dialog in signals + if (n==1){ + // Check input fields. + let sigName = document.getElementById('signal_name').value; + let sigSource = document.getElementById('sig_source').value; + let sigProp = document.getElementById('sig_prop').value; + if (sigName == '' ) { alert('Please give the signal a name.'); return; } + // Populate sig_display + document.getElementById('sig_display').innerHTML = (sigName + ': {' + sigSource + ':' + sigProp +'}'); + // Popilate Value input + let indctrVal = document.getElementById(sigSource + '_' + sigProp).value; + document.getElementById('value').value = indctrVal; + + this.switch_panel('panel_1','panel_2'); + } + if (n==2){ + + // Collect all the input fields. + + let sigName = document.getElementById('signal_name').value; // The name of the New Signal. + let sigSource = document.getElementById('sig_source').value; // The source(indicator) of the signal. + let sigProp = document.getElementById('sig_prop').value; // The property to evaluate. + let sig2Source = document.getElementById('sig2_source').value; // The second source if selected. + let sig2Prop = document.getElementById('sig2_prop').value; // The second property to evaluate. + let operator = document.querySelector('input[name="Operator"]:checked').value; // The operator this evaluation will use. + let range = document.getElementById('rangeVal').value; // The value of any range being evaluated. + let sigType = document.getElementById('select_s_type').value; // The type of signal value or indicator comparison. + let value = document.getElementById('value').value; // The input value if it is a value comparison. + + // Create a string to define the signal. + + // Include the first indicator source. + var sig1 = `${sigSource} : ${sigProp}`; + // If it is a comparison signal include the second indicator source. + if (sigType == 'Comparison') { + var sig2 = `${sig2Source} : ${sig2Prop}`; + } + // If it is a value signal include the value. + if (sigType == 'Value') {var sig2 = value;} + + // If the operator is set to range, include the range value in the string. + if (operator == '+/-') { + var operatorStr = `${operator} ${range}`; + } else{ + var operatorStr = operator; + } + + let sigDisplayStr = `(${sigName}) (${sig1}) (${operatorStr}) (${sig2})`; + + // Get the current realtime values of the sources. + let sig1_realtime = document.getElementById(sigSource + '_' + sigProp).value; + + if (sigType == 'Comparison') { + // If its a comparison get the second value from the second source. + var sig2_realtime = document.getElementById(sig2Source + '_' + sig2Prop).value; + }else { + // If not the second realtime value is literally the value. + var sig2_realtime = sig2; + } + // Populate the signal display field with the string. + document.getElementById('sig_display2').innerHTML = sigDisplayStr; + + // Populate the realtime values display. + let realtime_Str = `(${sigProp} : ${sig1_realtime}) (${operatorStr}) (${sig2_realtime})`; + document.getElementById('sig_realtime').innerHTML = realtime_Str; + // Evaluate the signal + var evalStr; + if (operator == '=') {evalStr = (sig1_realtime == sig2_realtime);console.log([sig1_realtime, sig2_realtime, operator,evalStr]);} + if (operator == '>') {evalStr = (sig1_realtime > sig2_realtime);} + if (operator == '<') {evalStr = (sig1_realtime < sig2_realtime);} + if (operator == '+/-') { + evalStr = (Math.abs(sig1_realtime - sig2_realtime) <= range); + } + + // Populate the signal eval field with the string. + document.getElementById('sig_eval').innerHTML = evalStr; + + // Show the panel + this.switch_panel('panel_2','panel_3'); + } + } + + submitNewSignal(){ + + // Collect all the input fields. + + var sigName = document.getElementById('signal_name').value; // The name of the New Signal. + var sigSource = document.getElementById('sig_source').value; // The source(indicator) of the signal. + var sigProp = document.getElementById('sig_prop').value; // The property to evaluate. + var sig2Source = document.getElementById('sig2_source').value; // The second source if selected. + var sig2Prop = document.getElementById('sig2_prop').value; // The second property to evaluate. + var operator = document.querySelector('input[name="Operator"]:checked').value; // The operator this evaluation will use. + var range = document.getElementById('rangeVal').value; // The value of any range being evaluated. + var sigType = document.getElementById('select_s_type').value; // The type of signal value or indicator comparison. + var value = document.getElementById('value').value; // The input value if it is a value comparison. + + var sigName = {sigName : sigName}; // Name_of_signal + var sigSource = {sigSource : sigSource}; // First_signal_indicator. + var sigProp = {sigProp : sigProp}; // First_signal_property. + var operator = {operator : operator}; // Operator. + + if (sigType == 'Comparison'){ + var sig2Source = {sig2Source: sig2Source}; + var sig2Prop = {sig2Prop : sig2Prop}; + }else{ + var sig2Source = {sig2Source: value}; + var sig2Prop = {value: value}; + } + if (operator == "'operator' : '+/-'" ){ + var range = {range : range}; + var data = [sigName, sigSource, sigProp, operator, sig2Source, sig2Prop, range]; + }else{ + var data = [sigName, sigSource, sigProp, operator, sig2Source, sig2Prop]; + } + /* It may be more maintainable to configure the connection inside the different classes + than passing functions, references and callbacks around. */ + + window.UI.data.comms.send_to_app( "new_signal", data); + } +} \ No newline at end of file diff --git a/templates/index.html b/templates/index.html index afb3d68..45a4c57 100644 --- a/templates/index.html +++ b/templates/index.html @@ -16,10 +16,8 @@ - - - - + +
@@ -37,7 +35,7 @@ -