Working and relatively glitch free. Classes implemented in javascript. Python is basically one big class with no separation.
This commit is contained in:
parent
626fa9a1a6
commit
958ad4d4a5
14
config.yml
14
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
|
||||
|
|
|
|||
2
data.py
2
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)
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
/* 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 : 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
|
||||
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
|
||||
}
|
||||
this.charts = new Charts(chart_init_data);
|
||||
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: this.data.indicators,
|
||||
indicator_data: this.data.indicator_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.*/
|
||||
this.indicators = new Indicators(this.charts, ind_init_data);
|
||||
this.data.set_i_updates(this.indicators.update);
|
||||
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 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();
|
||||
|
|
|
|||
|
|
@ -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 <input> 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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -16,10 +16,8 @@
|
|||
<script src="{{ url_for('static', filename='charts.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='communication.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='controls.js') }}"></script>
|
||||
|
||||
<script>function fill_prop(){let a=1;}</script>
|
||||
|
||||
|
||||
<script src="{{ url_for('static', filename='signals.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='general.js') }}"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
|
@ -37,7 +35,7 @@
|
|||
</div>
|
||||
<!-- Source Input field (row 3/5)-->
|
||||
<label for="sig_source" style="grid-column: 1; grid-row: 3;"><b>Signal source</b></label>
|
||||
<select name="sig_source" id="sig_source" style="grid-column: 2; grid-row: 3;" onchange= "fill_prop('sig_prop', this.value)">
|
||||
<select name="sig_source" id="sig_source" style="grid-column: 2; grid-row: 3;" onchange= "UI.signals.fill_prop('sig_prop', this.value)">
|
||||
<!-- Jinja2 loop through and populate the options -->
|
||||
<!-- Uses namespace to set a var in global scope, so we can pass info to javascript later. -->
|
||||
{% set ns = namespace(optonVal=0) %}
|
||||
|
|
@ -52,11 +50,11 @@
|
|||
<label style="grid-column: 1; grid-row: 4;" for="sig_prop"><b>Property</b></label>
|
||||
<select style="grid-column: 2; grid-row: 4;" id="sig_prop" name="sig_prop" >
|
||||
</select>
|
||||
<script>fill_prop('sig_prop', '{{ns.optonVal}}')</script>
|
||||
<script>UI.signals.fill_prop('sig_prop', '{{ns.optonVal}}')</script>
|
||||
<!-- Input controls (row 5/5)-->
|
||||
<div style="grid-column: 1 / span 2; grid-row: 5;">
|
||||
<button type="button" class="btn cancel" onclick="close_signal_Form()">Close</button>
|
||||
<button type="button" class="btn next" onclick="ns_next(1)">Next</button>
|
||||
<button type="button" class="btn cancel" onclick="UI.signals.close_signal_Form()">Close</button>
|
||||
<button type="button" class="btn next" onclick="UI.signals.ns_next(1)">Next</button>
|
||||
</div>
|
||||
</div><!----End panel 1--------->
|
||||
<!-- Panel 2 of 3 (6 rows, 2 columns) -->
|
||||
|
|
@ -66,7 +64,7 @@
|
|||
<!-- Type Input field (row 2/6) -->
|
||||
<div id = "Signal_type" style="grid-column: 1 / span 2; grid_row:2;">
|
||||
<label for="signal_type"><b>Signal Type:</b></label>
|
||||
<select name="signal_type" id="select_s_type" onchange="hideIfTrue(this.value,'Value','subpanel_1');hideIfTrue(this.value,'Comparison','subpanel_2');">
|
||||
<select name="signal_type" id="select_s_type" onchange="UI.signals.hideIfTrue(this.value,'Value','subpanel_1');UI.signals.hideIfTrue(this.value,'Comparison','subpanel_2');">
|
||||
<option>Value</option>
|
||||
<option>Comparison</option>
|
||||
</select>
|
||||
|
|
@ -99,7 +97,7 @@
|
|||
<div id="subpanel_1" style="grid-column: 1 / span 2; grid_row: 5 / span 3;">
|
||||
<!-- Source Input field -->
|
||||
<label for="sig2_source" ><b>Signal source</b></label>
|
||||
<select name="sig2_source" id="sig2_source" onchange= "fill_prop('sig2_prop', this.value)">
|
||||
<select name="sig2_source" id="sig2_source" onchange= "UI.signals.fill_prop('sig2_prop', this.value)">
|
||||
<!-- Jinja2 loop through and populate the options -->
|
||||
<!-- Uses namespace to set a var in global scope, so we can pass info to javascript later. -->
|
||||
{% set ns = namespace(optonVal=0) %}
|
||||
|
|
@ -114,12 +112,12 @@
|
|||
<label for="sig2_prop"><b>Property</b></label>
|
||||
<select id="sig2_prop" name="sig2_prop" >
|
||||
</select>
|
||||
<script>fill_prop('sig2_prop', '{{ns.optonVal}}')</script>
|
||||
<script>UI.signals.fill_prop('sig2_prop', '{{ns.optonVal}}')</script>
|
||||
</div>
|
||||
<!-- Input controls (row 6/6) -->
|
||||
<div class="padDiv" style="grid-column: 1/3; grid-row: 6;">
|
||||
<button type="button" class="btn" onclick="switch_panel('panel_2','panel_1')">Back</button>
|
||||
<button type="button" class="btn submit" onclick="ns_next(2)">Next</button>
|
||||
<button type="button" class="btn" onclick="UI.signals.switch_panel('panel_2','panel_1')">Back</button>
|
||||
<button type="button" class="btn submit" onclick="UI.signals.ns_next(2)">Next</button>
|
||||
</div>
|
||||
</div><!----End panel 2--------->
|
||||
<!-- Panel 3 of 3 (6 rows, 2 columns) -->
|
||||
|
|
@ -138,8 +136,8 @@
|
|||
|
||||
<!-- Input controls (row 6/6) -->
|
||||
<div class="padDiv" style="grid-column: 1/3; grid-row: 6;">
|
||||
<button type="button" class="btn" onclick="switch_panel('panel_3','panel_2')">Back</button>
|
||||
<button type="button" class="btn submit" onclick="submitNewSignal()">Next</button>
|
||||
<button type="button" class="btn" onclick="UI.signals.switch_panel('panel_3','panel_2')">Back</button>
|
||||
<button type="button" class="btn submit" onclick="UI.signals.submitNewSignal()">Next</button>
|
||||
</div>
|
||||
</div><!----End panel 3--------->
|
||||
</form>
|
||||
|
|
@ -236,7 +234,7 @@
|
|||
</div>
|
||||
<button class="collapsible bg_blue">Signals</button>
|
||||
<div class="content">
|
||||
<button class="new_btn" id="new_signal" onclick="open_signal_Form()">New Signal</button>
|
||||
<button class="new_btn" id="new_signal" onclick="UI.signals.open_signal_Form()">New Signal</button>
|
||||
<hr>
|
||||
<h3>Signals</h3>
|
||||
</div>
|
||||
|
|
@ -396,10 +394,5 @@
|
|||
</div><!-- End of Edit Indicator Panel -->
|
||||
</div><!-- End Master Panel --->
|
||||
|
||||
<!-- TODO ANY REASON THIS IS IN LINE WITH HTML?
|
||||
<script src="{{ url_for('static', filename='chart.js') }}"></script>
|
||||
<script type="module" >set_websocket( "{{interval_state}}" );</script>-->
|
||||
<script src="{{ url_for('static', filename='general.js') }}"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue