diff --git a/config.yml b/config.yml index 576a234..e5dc007 100644 --- a/config.yml +++ b/config.yml @@ -1,5 +1,5 @@ chart_configuration: - chart_interval: 4h + chart_interval: 1m trading_pair: BTCUSDT indicator_list: ATR: @@ -39,7 +39,7 @@ indicator_list: period: 100 type: LREG value: '38139.51' - visible: 'True' + visible: true MACD: color_1: '#50d617' color_2: '#94f657' diff --git a/static/chart.js b/static/chart.js deleted file mode 100644 index f5901de..0000000 --- a/static/chart.js +++ /dev/null @@ -1,130 +0,0 @@ -var app_con; - -//*******************Chart********************* -//Reference the target div for the chart. Div was defined in index.html -var container = document.getElementById('chart'); -//Create a chart object -var chart = LightweightCharts.createChart(container, { - width: 1000, - height: 500, - crosshair: { - mode: LightweightCharts.CrosshairMode.Normal, - }, - priceScale: { - borderColor: 'rgba(197, 203, 206, 0.8)', - }, - timeScale: { - borderColor: 'rgba(197, 203, 206, 0.8)', - timeVisible: true, - secondsVisible: false, - barSpacing: 6 - }, - handleScroll: true -}); -bind_charts(chart); -chart.applyOptions({ - watermark: {visible: true, - color: '#DBC29E', - text: bt_data['trading_pair'], - fontSize: 30, - fontFamily: 'Roboto', - fontStyle: 'bold', - vertAlign: 'center' - } - }); -// - Create the candle stick series for our chart -var candleSeries = chart.addCandlestickSeries(); - -//Fetch price history -var price_history = fetch('http://localhost:5000/history') - .then((r) => r.json()) - .then((response) => { - return response; - }) - -//Initialise the candlestick series -price_history.then((ph) => { - //Initialise the candle data - candleSeries.setData(ph); - //Initialise indicators - indicator_init(); -}) - -/* Place functions here that need to -be run everytime a new msg is received */ -function update_on_msg(new_candle){ - // Update candlestick series - candleSeries.update(new_candle); - // Update javascript coded indicators - indicator_update_msg_received(new_candle); - // Send a copy of the data to the server - app_con.send( JSON.stringify({ message_type: "candle_data", data :new_candle })); -} - -/* Place functions that here that need to - be run everytime a candle is closed */ -function update_on_candle_close(new_candle){ - // Send a copy of the data to the server - app_con.send( JSON.stringify({ message_type: "candle_data", data :new_candle })); -} - -// Create a web socket connection to the exchange -function set_websocket(interval){ - // Connect to our app - app_con = new WebSocket('ws://localhost:5000/ws'); - app_con.onopen = () => app_con.send("Connection OK"); - - app_con.addEventListener('message', ev => { - if(ev.data){ - // Get the message received from server - msg = JSON.parse(ev.data) - // Handle a request from the server - if (msg.request) { - //handle request - console.log('Received a request from the server'); - console.log(msg.request); - } - // Handle a reply from the server - if (msg.reply) { - // Handle indicator updates - if (msg.reply == 'i_updates'){ - // console.log(msg.data); - indicator_update(msg.data) - } - } - } - }) - - - var ws = "wss://stream.binance.com:9443/ws/btcusdt@kline_" + interval; - var binanceSocket = new WebSocket(ws); - - // Set the on-message call-back for the socket - binanceSocket.onmessage = function (event) { - // Convert message to json obj - var message = JSON.parse(event.data); - // Isolate the candle data from message - var candlestick = message.k; - //console.log(message.k) - // Reformat data for lightweight charts - new_candle={ - time: candlestick.t / 1000, - open: candlestick.o, - high: candlestick.h, - low: candlestick.l, - close: candlestick.c, - vol: candlestick.V - }; - //Update frequently updated objects - update_on_msg(new_candle); - // Only call if the new candle received a new time stamp. - // Update the price history and per candle updated objects. - price_history.then((ph) => { - if ( new_candle.time > ph[ph.length-1].time) { - ph.push(new_candle); - update_on_candle_close(new_candle); - } - }); - } - -} \ No newline at end of file diff --git a/static/charts.js b/static/charts.js index c66f118..e3c4ab8 100644 --- a/static/charts.js +++ b/static/charts.js @@ -9,9 +9,8 @@ class Charts { this.trading_pair = idata.trading_pair; this.price_history = idata.price_history; /* A list of bound charts this is necessary for maintaining a dynamic - number of charts with their position and zoom factors bound. I had to - declare it global as it is accessed through a callback.*/ - window.bound_charts=[]; + number of charts with their position and zoom factors bound.*/ + this.bound_charts=[]; // Only the main chart is created by default. this.create_main_chart(); } @@ -36,6 +35,10 @@ class Charts { this.bind_charts(this.chart_1); } + update_main_chart(new_candle){ + // Update candlestick series + this.candleSeries.update(new_candle); + } create_RSI_chart(){ this.chart2 = this.create_chart(this.chart2_id, 100); @@ -111,7 +114,7 @@ class Charts { // Add (arg1) to bound_charts this.add_to_list(chart); // Get the number of objects in bound_charts - let bcl = Object.keys(window.bound_charts).length; + let bcl = Object.keys(this.bound_charts).length; // if bound_charts has two element in it bind them if (bcl == 2) { this.bind2charts(); } @@ -122,65 +125,66 @@ class Charts { } add_to_list(chart){ // If the chart isn't already included in the list, add it. - if ( !window.bound_charts.includes(chart) ){ - window.bound_charts.push(chart); + if ( !this.bound_charts.includes(chart) ){ + this.bound_charts.push(chart); } } bind2charts(){ //On change in chart 1 change chart 2 - window.bound_charts[0].timeScale().subscribeVisibleTimeRangeChange(syncHandler1); - function syncHandler1(e) { + let syncHandler1 = (e) => { // Get the barSpacing(zoom) and position of 1st chart. - let barSpacing1 = window.bound_charts[0].timeScale().getBarSpacing(); - let scrollPosition1 = window.bound_charts[0].timeScale().scrollPosition(); + let barSpacing1 = this.bound_charts[0].timeScale().getBarSpacing(); + let scrollPosition1 = this.bound_charts[0].timeScale().scrollPosition(); // Apply barSpacing(zoom) and position to 2nd chart. - window.bound_charts[1].timeScale().applyOptions({ rightOffset: scrollPosition1, barSpacing: barSpacing1 }); + this.bound_charts[1].timeScale().applyOptions({ rightOffset: scrollPosition1, barSpacing: barSpacing1 }); } + this.bound_charts[0].timeScale().subscribeVisibleTimeRangeChange(syncHandler1); + //On change in chart 2 change chart 1 - window.bound_charts[1].timeScale().subscribeVisibleTimeRangeChange(syncHandler2); - function syncHandler2(e) { + let syncHandler2 = (e) => { // Get the barSpacing(zoom) and position of chart 2 - let barSpacing2 = window.bound_charts[1].timeScale().getBarSpacing(); - let scrollPosition2 = window.bound_charts[1].timeScale().scrollPosition(); + let barSpacing2 = this.bound_charts[1].timeScale().getBarSpacing(); + let scrollPosition2 = this.bound_charts[1].timeScale().scrollPosition(); // Apply barSpacing(zoom) and position to chart 1 - window.bound_charts[0].timeScale().applyOptions({ rightOffset: scrollPosition2, barSpacing: barSpacing2 }); + this.bound_charts[0].timeScale().applyOptions({ rightOffset: scrollPosition2, barSpacing: barSpacing2 }); } + this.bound_charts[1].timeScale().subscribeVisibleTimeRangeChange(syncHandler2); } bind3charts(){ //On change to chart 1 change chart 2 and 3 - window.bound_charts[0].timeScale().subscribeVisibleTimeRangeChange(syncHandler); - function syncHandler(e) { + let syncHandler = (e) => { // Get the barSpacing(zoom) and position of chart 1 - let barSpacing1 = window.bound_charts[0].timeScale().getBarSpacing(); - let scrollPosition1 = window.bound_charts[0].timeScale().scrollPosition(); + let barSpacing1 = this.bound_charts[0].timeScale().getBarSpacing(); + let scrollPosition1 = this.bound_charts[0].timeScale().scrollPosition(); // Apply barSpacing(zoom) and position to new chart - window.bound_charts[1].timeScale().applyOptions({ rightOffset: scrollPosition1, barSpacing: barSpacing1 }); - window.bound_charts[2].timeScale().applyOptions({ rightOffset: scrollPosition1, barSpacing: barSpacing1 }); + this.bound_charts[1].timeScale().applyOptions({ rightOffset: scrollPosition1, barSpacing: barSpacing1 }); + this.bound_charts[2].timeScale().applyOptions({ rightOffset: scrollPosition1, barSpacing: barSpacing1 }); } + this.bound_charts[0].timeScale().subscribeVisibleTimeRangeChange(syncHandler); //On change to chart 2 change chart 1 and 3 - window.bound_charts[1].timeScale().subscribeVisibleTimeRangeChange(syncHandler2); - function syncHandler2(e) { + let syncHandler2 = (e) => { // Get the barSpacing(zoom) and position of chart 2 - let barSpacing2 = window.bound_charts[1].timeScale().getBarSpacing(); - let scrollPosition2 = window.bound_charts[1].timeScale().scrollPosition(); + let barSpacing2 = this.bound_charts[1].timeScale().getBarSpacing(); + let scrollPosition2 = this.bound_charts[1].timeScale().scrollPosition(); // Apply barSpacing(zoom) and position to chart 1 and 3 - window.bound_charts[0].timeScale().applyOptions({ rightOffset: scrollPosition2, barSpacing: barSpacing2 }); - window.bound_charts[2].timeScale().applyOptions({ rightOffset: scrollPosition2, barSpacing: barSpacing2 }); + this.bound_charts[0].timeScale().applyOptions({ rightOffset: scrollPosition2, barSpacing: barSpacing2 }); + this.bound_charts[2].timeScale().applyOptions({ rightOffset: scrollPosition2, barSpacing: barSpacing2 }); } + this.bound_charts[1].timeScale().subscribeVisibleTimeRangeChange(syncHandler2); //On change to chart 3 change chart 1 and 2 - window.bound_charts[2].timeScale().subscribeVisibleTimeRangeChange(syncHandler3); - function syncHandler3(e) { + let syncHandler3 = (e) => { // Get the barSpacing(zoom) and position of new chart - let barSpacing2 = window.bound_charts[2].timeScale().getBarSpacing(); - let scrollPosition2 = window.bound_charts[2].timeScale().scrollPosition(); + let barSpacing2 = this.bound_charts[2].timeScale().getBarSpacing(); + let scrollPosition2 = this.bound_charts[2].timeScale().scrollPosition(); // Apply barSpacing(zoom) and position to parent chart - window.bound_charts[0].timeScale().applyOptions({ rightOffset: scrollPosition2, barSpacing: barSpacing2 }); - window.bound_charts[1].timeScale().applyOptions({ rightOffset: scrollPosition2, barSpacing: barSpacing2 }); + this.bound_charts[0].timeScale().applyOptions({ rightOffset: scrollPosition2, barSpacing: barSpacing2 }); + this.bound_charts[1].timeScale().applyOptions({ rightOffset: scrollPosition2, barSpacing: barSpacing2 }); } + this.bound_charts[2].timeScale().subscribeVisibleTimeRangeChange(syncHandler3); } diff --git a/static/communication.js b/static/communication.js index 5565bf1..ffe1703 100644 --- a/static/communication.js +++ b/static/communication.js @@ -1,26 +1,35 @@ -class Communication { - constructor(interval, ocu, occ, oiu) { +class Comms { + constructor(ocu, occ, oiu) { // Register callbacks this.on_candle_update = ocu; this.on_candle_close = occ; this.on_indctr_update = oiu; - // Open connections. - this.set_app_con(); - this.set_exchange_con(interval); } candle_update(new_candle){ + // Call the callback provided. this.on_candle_update(new_candle); } candle_close(new_candle){ - // Send a copy of the data to the server + // Forward a copy of the new candle to the server. this.app_con.send( JSON.stringify({ message_type: "candle_data", data :new_candle })); + // Call the callback provided. this.on_candle_close(new_candle); } indicator_update(data){ - this.this.on_indctr_update(data); + // Call the callback provided. + this.on_indctr_update(data); + } + + getPriceHistory(){ + let ph = fetch('http://localhost:5000/history').then((r) => r.json()).then( (data) => { return data; } ); + return ph; + } + getIndicatorData(){ + let id = fetch('http://localhost:5000/indicator_init').then((r) => r.json()).then( (data) => { return data; } ); + return id; } set_app_con(){ @@ -42,7 +51,6 @@ class Communication { if (msg.reply) { // Handle indicator updates if (msg.reply == 'i_updates'){ - // console.log(msg.data); this.indicator_update(msg.data) } } @@ -60,7 +68,6 @@ class Communication { let message = JSON.parse(event.data); // Isolate the candle data from message let candlestick = message.k; - //console.log(message.k) // Reformat data for lightweight charts let new_candle={ time: candlestick.t / 1000, @@ -73,7 +80,7 @@ class Communication { // Update frequently updated objects this.candle_update(new_candle); // Update less frequently updated objects. - if (candlestick.x == true) { this.candle.close(new_candle); } + if (candlestick.x == true) { this.candle_close(new_candle); } } } } \ No newline at end of file diff --git a/static/controls.js b/static/controls.js new file mode 100644 index 0000000..071577f --- /dev/null +++ b/static/controls.js @@ -0,0 +1,30 @@ +class Controls { + constructor() { + this.name = 'controls'; + } + showAtPos(event, id) { + // Function to display popup output at curser. + // Used in the chart controls to enable/disable indicators. + var el, x, y; + + el = document.getElementById(id); + if (window.event) { + x = window.event.clientX + document.documentElement.scrollLeft + + document.body.scrollLeft; + y = window.event.clientY + document.documentElement.scrollTop + + + document.body.scrollTop; + } + else { + x = event.clientX + window.scrollX; + y = event.clientY + window.scrollY; + } + // The popup hides on mouse out so the element is moved back a little to + // ensure the mouse is still hovering over it when it gets displayed + y = y - (10); + x = x - (15); + el.style.left = x + "px"; + el.style.top = y + "px"; + el.style.display = "block"; + } + +} diff --git a/static/data.js b/static/data.js index 3d8daef..0d44c35 100644 --- a/static/data.js +++ b/static/data.js @@ -1,22 +1,55 @@ class Data { constructor() { - // Set the id's of the HTML elements that contain each section of the user interface. + + // The id's of the HTML elements that contain sections of the user interface. this.chart1_id = 'chart'; this.chart2_id = 'chart2'; this.chart3_id = 'chart3'; - // Get and set into memory configuration and historical data from the server. + + /* Set into memory configuration data from the server. */ + // The assets being traded. this.trading_pair = bt_data.trading_pair; + // The time period of the charts. this.interval = bt_data.interval; - this.price_history = fetch('http://localhost:5000/history').then((r) => r.json()).then( (data) => { return data; } ); + // All the indicators available. this.indicators = bt_data.indicators; - // Request initialization data for the indicators. - this.indicator_data = fetch('http://localhost:5000/indicator_init').then((r) => r.json()).then( (data) => { return data; } ); - } - candle_update(){ - console.log('candle update'); + + /* Comms handles communication with the servers. Pass it + a list of callbacks to handle various incoming messages.*/ + this.comms = new Comms(this.candle_update, this.candle_close, this.indicator_update); + // Open the connection to our local server. + this.comms.set_app_con(); + /* Open connection for streaming candle data wth the exchange. + Pass it the time period of candles to stream. */ + this.comms.set_exchange_con(this.interval); + + //Request historical price data from the server. + this.price_history = this.comms.getPriceHistory(); + + // Request from the server initialization data for the indicators. + this.indicator_data = this.comms.getIndicatorData(); + + // Call back for indicator updates. + this.i_updates = null; } - candle_close(){ - console.log('candle close'); + candle_update(new_candle){ + // This is called everytime a candle update comes from the local server. + window.UI.charts.update_main_chart(new_candle); + //console.log('Candle update:'); + //console.log(new_candle); + } + set_i_updates(call_back){ + this.i_updates = call_back; + } + indicator_update(data){ + // This is called everytime an indicator update come in. + window.UI.data.i_updates(data); + } + + candle_close(new_candle){ + // This is called everytime a candle closes. + //console.log('Candle close:'); + //console.log(new_candle); } } diff --git a/static/general.js b/static/general.js index f4246dd..28795e4 100644 --- a/static/general.js +++ b/static/general.js @@ -10,13 +10,6 @@ // this.height = height; // } //} -// -//class Controls { -// constructor() { -// this.height = height; -// } -//} -// //class Strategies { // constructor() { // this.height = height; @@ -53,19 +46,14 @@ // } //} // -//class Indicator_Output { -// constructor() { -// this.height = height; -// } -//} class User_Interface{ -/* This contains the entire User interface.*/ +/* This contains all the code for our User interface. + The code is separated into classes that maintain and + provide the data and functionality of each panel of + the UI. */ constructor() { - /* Create the objects that contain all the - data and scripts required for each section of - the User interface. */ /* Data object is responsible for fetching and maintaining up-to-date configurable and variable data for the UI */ @@ -82,9 +70,8 @@ class User_Interface{ } this.charts = new Charts(chart_init_data); - /* The Indicators object is responsible for maintaining and - interacting with the indicator section. As well as - updating the display on the charts.*/ + /* 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 @@ -92,12 +79,9 @@ class User_Interface{ /* 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.communicate = new Communication( - this.data.interval, - this.data.candle_update, - this.data.candle_close, - this.indicators.update); + this.data.set_i_updates(this.indicators.update); + /* The object that handles the interface controls.*/ + this.controls = new Controls(); } } UI = new User_Interface(); diff --git a/static/indicators.js b/static/indicators.js index 33823bb..87a55d5 100644 --- a/static/indicators.js +++ b/static/indicators.js @@ -1,3 +1,34 @@ +class Indicator_Output { + constructor(name) { + this.legend={}; + } + create_legend(name, chart, lineSeries){ + // Create legend div and append it to the output element + let target_div = document.getElementById('indicator_output'); + this.legend[name] = document.createElement('div'); + this.legend[name].className = 'legend'; + target_div.appendChild(this.legend[name]); + this.legend[name].style.display = 'block'; + this.legend[name].style.left = 3 + 'px'; + this.legend[name].style.top = 3 + 'px'; + // subscribe set legend text to crosshair moves + chart.subscribeCrosshairMove((param) => { + this.set_legend_text(param.seriesPrices.get(lineSeries),name); + }); + } + + + set_legend_text(priceValue,name) { + // Callback assigned to fire on crosshair movements. + let val = 'n/a'; + if (priceValue !== undefined) { + val = (Math.round(priceValue * 100) / 100).toFixed(2); + } + this.legend[name].innerHTML = name + ' ' + val + ''; + } +} +iOutput = new Indicator_Output(); + class Indicator { constructor(name) { // The name of the indicator. @@ -29,6 +60,9 @@ class Indicator { color: color, lineWidth: lineWidth }); + //Initialise the crosshair legend for the charts. + iOutput.create_legend(this.name, chart, this.lines[name]); + } setLine(name, data, value_name){ // Initialize the data with the data object provided. @@ -36,13 +70,13 @@ class Indicator { // Isolate the last value provided and round to 2 decimals places. let priceValue = data.at(-1).value; this.updateDisplay(name, priceValue, value_name); + // Update indicator output/crosshair legend. + iOutput.set_legend_text(data.at(-1).value, this.name); } updateDisplay(name, priceValue, value_name){ let rounded_value = (Math.round(priceValue * 100) / 100).toFixed(2); // Update the data in the edit and view indicators panel document.getElementById(this.name + '_' + value_name).value = rounded_value; - //Initialise the legend todo fix this - //set_legend_text(rounded_value, i); } setHist(name, data){ this.hist[name].setData(data); @@ -50,8 +84,10 @@ class Indicator { updateLine(name, data, value_name){ // Update the line-set data in the chart this.lines[name].update(data); + // Update indicator output/crosshair legend. + iOutput.set_legend_text(data.value, this.name); // Update the data in the edit and view indicators panel - this.updateDisplay(name, data, value_name); + this.updateDisplay(name, data.value, value_name); } updateHist(name,data){ this.hist[name].update(data); @@ -66,14 +102,12 @@ class SMA extends Indicator{ // Create a line series and append to the appropriate chart. this.addLine('line', chart, color, lineWidth); - // todo: pass in indicator output or something? Regiyhhster crosshair movements to the indicators output panel - //create_legend(name, chart); } init(data){ this.setLine('line',data, 'value'); } update(data){ - this.updateLine('line', data, 'value'); + this.updateLine('line', data[0], 'value'); } } @@ -87,20 +121,17 @@ class RSI extends Indicator{ constructor(name, charts, color, lineWidth = 2) { // Call the inherited constructor. super(name); - // If the chart doesn't exsist create one. + // If the chart doesn't exist create one. if( !charts.hasOwnProperty('chart2') ) { charts.create_RSI_chart(); } let chart = charts.chart2; // Create a line series and append to the appropriate chart. this.addLine('line', chart, color, lineWidth); - - // todo: pass in indicator output or somthing? Register crosshair movements to the indicators output panel - //create_legend(name, chart); } init(data){ this.setLine('line',data, 'value'); } update(data){ - this.updateLine('line', data, 'value'); + this.updateLine('line', data[0], 'value'); } } @@ -108,7 +139,7 @@ class MACD extends Indicator{ constructor(name, charts, color_m, color_s, lineWidth = 2) { // Call the inherited constructor. super(name); - // If the chart doesn't exsist create one. + // If the chart doesn't exist create one. if( !charts.hasOwnProperty('chart3') ) { charts.create_MACD_chart(); } let chart = charts.chart3; @@ -116,19 +147,18 @@ class MACD extends Indicator{ this.addLine('line_m', chart, color_m, lineWidth); this.addLine('line_s', chart, color_s, lineWidth); this.addHist(name, chart); - - // todo: pass in indicator output or somthing? Register crosshair movements to the indicators output panel - //create_legend(name, chart); } + init(data){ this.setLine('line_m',data[0], 'macd'); this.setLine('line_s',data[1], 'signal'); this.setHist(name, data[2]); } + update(data){ - this.updateLine('line_m', data[0], 'macd'); - this.updateLine('line_s', data[1], 'signal'); - this.addHist(name, data[3]); + this.updateLine('line_m', data[0][0], 'macd'); + this.updateLine('line_s', data[1][0], 'signal'); + this.updateHist(name, data[2][0]); } } @@ -137,7 +167,7 @@ class ATR extends Indicator{ this.updateDisplay(this.name, data.at(-1).value, 'value'); } update(data) { - this.updateDisplay(this.name, data.value, 'value'); + this.updateDisplay(this.name, data[0].value, 'value'); } } @@ -153,7 +183,7 @@ class Volume extends Indicator{ this.setHist(this.name, data); } update(data){ - this.updateHist(this.name, data); + this.updateHist(this.name, data[0]); } } @@ -177,11 +207,11 @@ class Bolenger extends Indicator{ update(data){ // Update the line-set data in the chart - this.line_u.update(data[0], 'value1'); + this.updateLine('line_u', data[0][0], 'value1'); // Update the line-set data in the chart - this.line_m.update(data[1]), 'value2'; + this.updateLine('line_m', data[1][0], 'value2'); // Update the line-set data in the chart - this.line_l.update(data[2], 'value3'); + this.updateLine('line_l', data[2][0], 'value3'); } } @@ -189,11 +219,11 @@ class Bolenger extends Indicator{ class Indicators { constructor(charts, idata) { // Create an array to hold all the created indicators. - this.indicators = []; - // Pass a list of indicators from received from the server + this.i_objs = {}; + // Pass a list of indicators that was received from the server // to a function that will create them. this.create_indicators(idata.indicators, charts); - // Pass the initial indicator data to an initialize function for the indicators. + // Pass the initial indicator data to a function to initialize the indicators. idata.indicator_data.then( (data) => { this.init_indicators(data); } ); @@ -213,36 +243,36 @@ class Indicators { if (i_type == 'SMA') { // The color of the line let color = indicators[name].color; - this.indicators[name] = new SMA(name, charts.chart_1, color); + this.i_objs[name] = new SMA(name, charts.chart_1, color); } if (i_type == 'BOLBands') { // The color of three lines let color_u = bt_data.indicators[name].color_1; let color_m = bt_data.indicators[name].color_2; let color_l = bt_data.indicators[name].color_3; - this.indicators[name] = new Bolenger(name, charts.chart_1, color_u, color_m, color_l); + this.i_objs[name] = new Bolenger(name, charts.chart_1, color_u, color_m, color_l); } if (i_type == 'MACD') { // The color of two lines let color_m = bt_data.indicators[name].color_1; let color_s = bt_data.indicators[name].color_2; - this.indicators[name] = new MACD(name, charts, color_m, color_s); + this.i_objs[name] = new MACD(name, charts, color_m, color_s); } - if (i_type == 'Volume') { this.indicators[name] = new Volume(name, charts.chart_1); } - if (i_type == 'ATR') { this.indicators[name] = new ATR(name); } + if (i_type == 'Volume') { this.i_objs[name] = new Volume(name, charts.chart_1); } + if (i_type == 'ATR') { this.i_objs[name] = new ATR(name); } if (i_type == 'LREG') { // The color of the line let color = indicators[name].color; - this.indicators[name] = new Linear_Regression(name, charts.chart_1, color); + this.i_objs[name] = new Linear_Regression(name, charts.chart_1, color); } if (i_type == 'RSI') { let color = indicators[name].color; - this.indicators[name] = new RSI(name, charts, color); + this.i_objs[name] = new RSI(name, charts, color); } if (i_type == 'EMA') { // The color of the line let color = indicators[name].color; - this.indicators[name] = new EMA(name, charts.chart_1, color); + this.i_objs[name] = new EMA(name, charts.chart_1, color); } } } @@ -250,9 +280,36 @@ class Indicators { // Loop through all the indicators. for (name in data){ // Call the initialization function for each indicator. - this.indicators[name].init(data[name]['data']); + this.i_objs[name].init(data[name]['data']); } - } + update(updates){ + for (name in updates){ + window.UI.indicators.i_objs[name].update(updates[name].data); + } + } + + 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={}; + p[n] = v; + if (document.getElementById("new_prop_list").innerHTML ==""){ + document.getElementById("new_prop_list").insertAdjacentHTML('beforeend', JSON.stringify(p)); + }else{ + document.getElementById("new_prop_list").insertAdjacentHTML('beforeend', ',' + JSON.stringify(p)); } + } + 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; + if(pl) { pl = '[' + pl + ']'; } + document.getElementById("new_prop_obj").value=pl; + document.getElementById("new_i_form").submit(); + } + + } diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..afb3d68 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,405 @@ + + + + + {{ title }} + + + + + + + + + + + + + + + + + + +
+
+ +
+ +

Add New Signal

+ +
+ + +
+ + + + + + + + +
+ + +
+
+ +
+ +

Signal Type

+ +
+ + +
+ + name:{property}(operator)name:{property} + +
+ + + + + +
+ + + + + + + + +
+ +
+ + +
+ +
+ + +
+ + + + +
+ +
+ + +
+
+ +
+ +

Create Signal

+ + + + Current values + + + + Currently evaluates to : + + + +
+ + +
+
+
+
+ + +
+
+ + {% for indicator in indicator_list %} + +
+ {% endfor %} + +
+
+ +
+ +
+

{{ title }}

+
+ + +
+
+ +
+ +
+ +
+ + +
+ + +
+
+
+ + +
+
+ + +
+ + +
+

No Alerts

+
+ +
+
+

Status

+ Not connected +
+
+

Balances

+
+
+ + {% for balance in my_balances %} + + + + + + + {% endfor %} +
AssetBalanceProfit&Loss
+ {{ balance['asset'] }} + + {{ balance['crossWalletBalance'] }} + + {{ balance['crossUnPnl'] }} +
+
+
+
+
+

Active Tades

+ None +
+
+

Open orders

+ None +
+
+ +
+ +
+

Signals

+
+ +
+ +
+

Strategies

+
+ +
+

Statistics

+
+ +
+

Back Testing

+
+ +
+
+
+ + + + +
+
+
+ + + +
+ + +
+ +
+
Indicator Name
+
Properties
+
+
+ + {% for indicator in indicator_list %} +
+ +
+
+ + +
+
{{indicator}}
+
+ {% for property in indicator_list[indicator] %} + + {% set list1 = property.split('_') %} +
+ + {% if property=='type' %} + + {% elif property=='ma' %} + + {% elif property=='color' or list1[0]=='color' %} + + {% elif property=='period' %} + + {% elif property=='visible' %} + + {% elif property=='value' %} + + {% else %} + + {%endif%} +
+ {% endfor %} +
+
+
+ {% endfor %} + +
+ +
+ +
+

Add Indicator

+ + + +

+ Properties: + + +

+
+ + +
+ + + + + +
+
+ + +
+
+
+
+ + + + + + \ No newline at end of file