brighter-trading/static/signals.js

295 lines
14 KiB
JavaScript

class Signals {
constructor(indicators) {
this.indicators = indicators;
this.signals=[];
}
// Call to display the 'Create new signal' dialog.
open_signal_Form() { document.getElementById("new_sig_form").style.display = "grid"; }
// Call to hide the 'Create new signal' dialog.
close_signal_Form() { document.getElementById("new_sig_form").style.display = "none"; }
request_signals(){
// Requests a list of all the signals from the server.
window.UI.data.comms.sendToApp('request', 'signals');
}
delete_signal(signal_name){
// Requests that the server remove a specific signal.
window.UI.data.comms.sendToApp('delete_signal', signal_name);
// Get the signal element from the UI
let child = document.getElementById(signal_name + '_item');
// Ask the parent of the signal element to remove its child(signal) from the document.
child.parentNode.removeChild(child);
}
i_update(updates){
// Check the indicator updates for updates that are use as signal sources.
// Update the signals about these changes.
// Update the html that displays that info.
// Loop through all the signals.
for (let signal in this.signals){
// Get the name of the 1st source.
let s1 = this.signals[signal].source1;
// Check the updates for a source 1 update.
if (s1 in updates){
// Get the property of that source.
let p1 = this.signals[signal].prop1;
// Get the value of that property.
let value1 = updates[s1].data[0][p1];
// Update the signals record of the value.
this.signals[signal].value1 = value1.toFixed(2);
}
else{
// If there is no update move onto the next signal.
console.log('!no update for: s1 maybe the indicator is disabled');
break;
}
// If the second source is an indicator and not just a value.
if (this.signals[signal].source2 != 'value'){
// Get the name of the second source.
let s2 = this.signals[signal].source2;
// Check is source 2 is in the updates.
if (s2 in updates) {
// Get the property of that source.
let p2 = this.signals[signal].prop2;
// Get the value of that property.
let value2 = updates[s2].data[0][p2];
// Update the signals record of the value.
this.signals[signal].value2 = value2.toFixed(2);
}
else{
// If there is no update move onto the next signal.
console.log('!no update for: s2 maybe the indicator is disabled');
break;
}
// loop to next signal.
}
// Update the html element that displays this information.
document.getElementById(this.signals[signal].name + '_value1').innerHTML = this.signals[signal].value1;
document.getElementById(this.signals[signal].name + '_value2').innerHTML = this.signals[signal].value2;
}
}
update_signal_states(s_updates){
for (name in s_updates){
let id = name + '_state'
let span = document.getElementById(id);
span.innerHTML = s_updates[name];
console.log('state change!');
console.log(name);
}
}
set_data(signals){
// Create a list item for every signal and add it to a UL element.
var ul = document.getElementById("signal_list");
// loop through a provided list of signals and attributes.
for (let sig in signals){
// Create a Json object from each signals.
// During initialization this receives the object in string form.
// when the object is created this function receives an object.
if (typeof(signals[sig]) == 'string'){
var obj = JSON.parse(signals[sig]);
}else {var obj=signals[sig];}
// Keep a local record of the signals.
this.signals.push(obj);
// Define the function that is called when deleting an individual signal.
let click_func = "window.UI.signals.delete_signal('" + obj.name + "')";
// create a delete button for every individual signal.
let delete_btn = '<button onclick="' + click_func + '" style="color:red;">&#10008;</button>';
// Put all the attributes into html elements.
let signal_name = " <span>" + obj.name + ": </span>";
let signal_state = "<span id='" + obj.name + "_state'>" + obj.state + "</span><br>";
let signal_source1 = "<span>" + obj.source1 + "(" + obj.prop1 + ") </span>";
let signal_val1 = "<span id='" + obj.name + "_value1'>" + obj.value1 + "</span>";
let operator = " " + obj.operator + " ";
let signal_source2 = "<span>" + obj.source2 + "(" + obj.prop2 + ") </span>";
let signal_val2 = "<span id='" + obj.name + "_value2'>" + obj.value2 + "</span>";
// Stick all the html together.
let html = delete_btn;
html += signal_name + signal_state;
html += signal_source1 + signal_val1;
html += operator;
html += signal_source2 + signal_val2;
// Create the list item.
let li = document.createElement("li");
// Give it an id.
li.id = obj.name + '_item';
// Inject the html.
li.innerHTML= html;
// And add it the the UL we created earlier.
ul.appendChild(li);
}
}
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 name = document.getElementById('signal_name').value; // The name of the New Signal.
var source1 = document.getElementById('sig_source').value; // The source(indicator) of the signal.
var prop1 = document.getElementById('sig_prop').value; // The property to evaluate.
var source2 = document.getElementById('sig2_source').value; // The second source if selected.
var prop2 = 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 state = false;
if (sigType == 'Comparison'){
var source2 = source2;
var prop2 = prop2;
}else{
var source2 = 'value';
var prop2 = value;
}
var value1 = null;
var value2 = null;
if (operator == "+/-" ){
var range = {range : range};
var data = {name, source1, prop1, operator, source2, prop2, range, state, value1, value2};
}else{
var data = {name, source1, prop1, operator, source2, prop2, state, value1, value2};
}
/* It may be more maintainable to configure the connection inside the different classes
than passing functions, references and callbacks around. */
window.UI.data.comms.sendToApp( "new_signal", data);
this.close_signal_Form();
}
}