var color_list = ['#c23531','#2f4554', '#61a0a8', '#d48265', '#91c7ae','#749f83', '#ca8622', '#bda29a','#6e7074', '#546570', '#c4ccd3']; var colors = ['#5793f3', '#d14a61', '#675bba','#b62f46']; var close = GOOGLE['data'].map(function(el, idx) { return el[1]; }) var stocks = GOOGLE['data'].map(function(el, idx) { return [el[0],el[1],el[3],el[2]]; }) var stock_date = GOOGLE['date']; var volume = GOOGLE['volume']; var csv; var indeces = {}; var dataMA5, dataMA10, dataMA20, dataMA30; var total_investment, total_gain, stock_changes, stock_changes_percent function smoothing_line(scalars,weight){ last = scalars[0] smoothed = [] for(var i = 0; i < scalars.length;i++){ smoothed_val = last * weight + (1 - weight) * scalars[i] smoothed.push(smoothed_val) last = smoothed_val } return smoothed } function generate_investment(strings,values){ colors = ""; for(var i = 0; i < strings.length;i++){ if(values[i]>=0) colors += "
arrow_upward

"+strings[i]+values[i]+"

"; else colors += "
arrow_downward

"+strings[i]+values[i]+"

"; } $('#color-investment').html(colors); } function buildConfig() { return { delimiter: $('#delimiter').val(), header: $('#header').prop('checked'), dynamicTyping: $('#dynamicTyping').prop('checked'), skipEmptyLines: $('#skipEmptyLines').prop('checked'), preview: parseInt($('#preview').val() || 0), step: $('#stream').prop('checked') ? stepFn : undefined, encoding: $('#encoding').val(), worker: $('#worker').prop('checked'), comments: $('#comments').val(), complete: completeFn, error: errorFn } } function errorFn(err, file) { Materialize.toast("ERROR: " + err + file,3000) } function completeFn(results) { if (results && results.errors) { if (results.errors) { errorCount = results.errors.length; firstError = results.errors[0] } if (results.data && results.data.length > 0) rowCount = results.data.length } csv = results['data']; for(var i = 0;i1){ Materialize.toast('input dropout must bigger than 0 and less than 1', 4000) return } if(parseFloat($('#smooth').val())<0 || parseFloat($('#smooth').val())>1){ Materialize.toast('smoothing weights must bigger than 0 and less than 1', 4000) return } if(parseFloat($('#outputdropoutrate').val())<0 || parseFloat($('#outputdropoutrate').val())>1){ Materialize.toast('output dropout must bigger than 0 and less than 1', 4000) return } setTimeout(function(){ minmax_scaled = minmax_1d(close); timestamp = parseInt($('#timestamp').val()) epoch = parseInt($('#epoch').val()) future = parseInt($('#future').val()) X_scaled = minmax_scaled.scaled.slice([0],[Math.floor(minmax_scaled.scaled.shape[0]/timestamp)*timestamp+1]) cells = [tf.layers.lstmCell({units: parseInt($('#sizelayer').val())})]; rnn = tf.layers.rnn({cell: cells, returnSequences: true,returnState:true}); dense_layer = tf.layers.dense({units: 1, activation: 'linear'}); function f(x,states){ x = dropout_nn(x,parseFloat($('#inputdropoutrate').val())) forward = rnn.apply(x,{initialState:states}); last_sequences = dropout_nn(forward[0].reshape([x.shape[1],parseInt($('#sizelayer').val())]),parseFloat($('#outputdropoutrate').val())) return {'forward':dense_layer.apply(last_sequences),'states_1':forward[1],'states_2':forward[2]} } cost = (label, pred) => tf.square(tf.sub(label,pred)).mean(); optimizer = tf.train.adam(parseFloat($('#learningrate').val())); batch_states = [tf.zeros([1,parseInt($('#sizelayer').val())]),tf.zeros([1,parseInt($('#sizelayer').val())])]; arr_loss = [], arr_layer = [] function async_training_loop(callback) { (function loop(i) { var total_loss = 0 for(var k = 0; k < Math.floor(X_scaled.shape[0]/timestamp)*timestamp; k+=timestamp){ batch_x = X_scaled.slice([k],[timestamp]).reshape([1,-1,1]) batch_y = X_scaled.slice([k+1],[timestamp]).reshape([-1,1]) feed = f(batch_x,batch_states) optimizer.minimize(() => cost(batch_y,f(batch_x,batch_states)['forward'])); total_loss += parseFloat(cost(batch_y,f(batch_x,batch_states)['forward']).toString().slice(7)); batch_states = [feed.states_1,feed.states_2] } total_loss /= Math.floor(X_scaled.shape[0]/timestamp); arr_loss.push(total_loss) output_predict = nj.zeros([X_scaled.shape[0]+future, 1]) output_predict.slice([0,1],null).assign(tf_str_tolist(X_scaled.slice(0,1))[0],false) upper_b = Math.floor(X_scaled.shape[0]/timestamp)*timestamp distance_upper_b = X_scaled.shape[0] - upper_b batch_states = [tf.zeros([1,parseInt($('#sizelayer').val())]),tf.zeros([1,parseInt($('#sizelayer').val())])]; for(var k = 0; k < (Math.floor(X_scaled.shape[0]/timestamp)*timestamp); k+=timestamp){ batch_x = X_scaled.slice([k],[timestamp]).reshape([1,-1,1]) feed = f(batch_x,batch_states) state_forward = tf_nj_list(feed.forward) output_predict.slice([k+1,k+1+timestamp],null).assign(state_forward,false) batch_states = [feed.states_1,feed.states_2] } batch_x = X_scaled.slice([upper_b],[distance_upper_b]).reshape([1,-1,1]) feed = f(batch_x,batch_states) state_forward = tf_nj_list(feed.forward) output_predict.slice([upper_b+1,X_scaled.shape[0]+1],null).assign(state_forward,false) pointer = X_scaled.shape[0]+1 tensor_output_predict = output_predict.reshape([-1]).tolist() batch_states = [feed.states_1,feed.states_2] for(var k = 0; k < future-1; k+=1){ batch_x = tf.tensor(tensor_output_predict.slice(pointer-timestamp,pointer)).reshape([1,-1,1]) feed = f(batch_x,batch_states) state_forward = tf_nj_list(feed.forward.transpose()) tensor_output_predict[pointer] = state_forward[0][4] pointer += 1 batch_states = [feed.states_1,feed.states_2] } $('#log').append('Epoch: '+(i+1)+', avg loss: '+total_loss+'
'); predicted_val = tf_nj_list_flatten(reverse_minmax_1d(tf.tensor(tensor_output_predict),minmax_scaled['min'],minmax_scaled['max'])) predicted_val = smoothing_line(predicted_val,parseFloat($('#smooth').val())) $('#div_output').attr('style','height:450px;'); new_date = stock_date.slice() for(var k = 0; k < future; k+=1){ somedate = new Date(new_date[new_date.length-1]) somedate.setDate(somedate.getDate() + 1) dd = somedate.getDate() mm = somedate.getMonth() + 1 y = somedate.getFullYear() new_date.push(y.toString()+'-'+mm.toString()+'-'+dd.toString()) } option = { animation: false, color: color_list, title: { left: 'center' }, legend: { top: 30, data: ['STOCK', 'MA5', 'MA10', 'MA20', 'MA30','predicted close'] }, tooltip: { trigger: 'axis', position: function (pt) { return [pt[0], '10%']; } }, axisPointer: { link: [{ xAxisIndex: [0, 1] }] }, dataZoom: [{ type: 'slider', xAxisIndex: [0, 1], realtime: false, start: 0, end: 100, top: 65, height: 20, handleIcon: 'M10.7,11.9H9.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4h1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z', handleSize: '120%' }, { type: 'inside', xAxisIndex: [0, 1], start: 40, end: 70, top: 30, height: 20 }], xAxis: [{ type: 'category', data: new_date, boundaryGap : false, axisLine: { lineStyle: { color: '#777' } }, axisLabel: { formatter: function (value) { return echarts.format.formatTime('MM-dd', value); } }, min: 'dataMin', max: 'dataMax', axisPointer: { show: true } }, { type: 'category', gridIndex: 1, data: stock_date, scale: true, boundaryGap : false, splitLine: {show: false}, axisLabel: {show: false}, axisTick: {show: false}, axisLine: { lineStyle: { color: '#777' } }, splitNumber: 20, min: 'dataMin', max: 'dataMax', axisPointer: { type: 'shadow', label: {show: false}, triggerTooltip: true, handle: { show: true, margin: 30, color: '#B80C00' } } }], yAxis: [{ scale: true, splitNumber: 2, axisLine: { lineStyle: { color: '#777' } }, splitLine: { show: true }, axisTick: { show: false }, axisLabel: { inside: true, formatter: '{value}\n' } }, { scale: true, gridIndex: 1, splitNumber: 2, axisLabel: {show: false}, axisLine: {show: false}, axisTick: {show: false}, splitLine: {show: false} }], grid: [{ left: 20, right: 20, top: 110, }, { left: 20, right: 20, top: 400 }], graphic: [{ type: 'group', left: 'center', top: 70, width: 300, bounding: 'raw', children: [{ id: 'MA5', type: 'text', style: {fill: color_list[1]}, left: 0 }, { id: 'MA10', type: 'text', style: {fill: color_list[2]}, left: 'center' }, { id: 'MA20', type: 'text', style: {fill: color_list[3]}, right: 0 }] }], series: [{ name: 'Volume', type: 'bar', xAxisIndex: 1, yAxisIndex: 1, itemStyle: { normal: { color: '#7fbe9e' }, emphasis: { color: '#140' } }, data: volume }, { type: 'candlestick', name: 'STOCK', data: stocks, itemStyle: { normal: { color: '#ef232a', color0: '#14b143', borderColor: '#ef232a', borderColor0: '#14b143' }, emphasis: { color: 'black', color0: '#444', borderColor: 'black', borderColor0: '#444' } } }, { name: 'MA5', type: 'line', data: dataMA5, smooth: true, showSymbol: false, lineStyle: { normal: { width: 1 } } }, { name: 'MA10', type: 'line', data: dataMA10, smooth: true, showSymbol: false, lineStyle: { normal: { width: 1 } } }, { name: 'MA20', type: 'line', data: dataMA20, smooth: true, showSymbol: false, lineStyle: { normal: { width: 1 } } }, { name: 'MA30', type: 'line', data: dataMA30, smooth: true, showSymbol: false, lineStyle: { normal: { width: 1 } } }, { name: 'predicted close', type: 'line', data: predicted_val, smooth: false, showSymbol: false, lineStyle: { normal: { width: 2 } } }] }; var chart_stock = echarts.init(document.getElementById('div_output')); chart_stock.setOption(option,true); calculate_distribution(close,predicted_val) option = { title:{ text:'loss graph' }, xAxis: { type: 'category', data: arange(0,arr_loss.length,1) }, yAxis: { type: 'value' }, grid:{ bottom:'10%' }, series: [{ data: arr_loss, type: 'line' }] }; var chart_line = echarts.init(document.getElementById('div_loss')); chart_line.setOption(option,true); if (i < (epoch-1)) { setTimeout(function() {loop(++i)}, 2000); } else { callback(); } }(0)); } async_training_loop(function() { $('#log').append('Done training!'); my_investment = simple_investor(close,predicted_val,parseInt($('#history').val()), parseFloat($('#initialmoney').val()),parseInt($('#maxbuy').val()),parseInt($('#maxsell').val()),new_date) $('#table-body').html(''); for(var i = 0; i < my_investment['output'].length; i++) $('#table-body').append(my_investment['output'][i]); $('#log-invest').append("
Overall gain: "+my_investment['overall gain']+", Overall investment: "+my_investment['overall investment']+"%
") total_investment = my_investment['overall investment'] total_gain = my_investment['overall gain'] stock_changes = predicted_val[predicted_val.length-1] - close[0] stock_changes_percent = (stock_changes / close[0])*100 var markpoints = [] for (var i = 0; i < my_investment['buy_X'].length;i++){ ind = new_date.indexOf(my_investment['buy_X'][i]) markpoints.push({name: 'buy', value: 'buy', xAxis: ind, yAxis: my_investment['buy_Y'][i],itemStyle:{color:'#61a0a8'}}) } for (var i = 0; i < my_investment['sell_X'].length;i++){ ind = new_date.indexOf(my_investment['sell_X'][i]) markpoints.push({name: 'sell', value: 'sell', xAxis: ind, yAxis: my_investment['sell_Y'][i],itemStyle:{color:'#c23531'}}) } option = { animation: false, color: color_list, title: { left: 'center' }, legend: { top: 30, data: ['STOCK', 'MA5', 'MA10', 'MA20', 'MA30','predicted close','sell','buy'] }, tooltip: { trigger: 'axis', position: function (pt) { return [pt[0], '10%']; } }, axisPointer: { link: [{ xAxisIndex: [0, 1] }] }, dataZoom: [{ type: 'slider', xAxisIndex: [0, 1], realtime: false, start: 0, end: 100, top: 65, height: 20, handleIcon: 'M10.7,11.9H9.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4h1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z', handleSize: '120%' }, { type: 'inside', xAxisIndex: [0, 1], start: 40, end: 70, top: 30, height: 20 }], xAxis: [{ type: 'category', data: new_date, boundaryGap : false, axisLine: { lineStyle: { color: '#777' } }, axisLabel: { formatter: function (value) { return echarts.format.formatTime('MM-dd', value); } }, min: 'dataMin', max: 'dataMax', axisPointer: { show: true } }, { type: 'category', gridIndex: 1, data: stock_date, scale: true, boundaryGap : false, splitLine: {show: false}, axisLabel: {show: false}, axisTick: {show: false}, axisLine: { lineStyle: { color: '#777' } }, splitNumber: 20, min: 'dataMin', max: 'dataMax', axisPointer: { type: 'shadow', label: {show: false}, triggerTooltip: true, handle: { show: true, margin: 30, color: '#B80C00' } } }], yAxis: [{ scale: true, splitNumber: 2, axisLine: { lineStyle: { color: '#777' } }, splitLine: { show: true }, axisTick: { show: false }, axisLabel: { inside: true, formatter: '{value}\n' } }, { scale: true, gridIndex: 1, splitNumber: 2, axisLabel: {show: false}, axisLine: {show: false}, axisTick: {show: false}, splitLine: {show: false} }], grid: [{ left: 20, right: 20, top: 110, }, { left: 20, right: 20, top: 400 }], graphic: [{ type: 'group', left: 'center', top: 70, width: 300, bounding: 'raw', children: [{ id: 'MA5', type: 'text', style: {fill: color_list[1]}, left: 0 }, { id: 'MA10', type: 'text', style: {fill: color_list[2]}, left: 'center' }, { id: 'MA20', type: 'text', style: {fill: color_list[3]}, right: 0 }] }], series: [{ name: 'Volume', type: 'bar', xAxisIndex: 1, yAxisIndex: 1, itemStyle: { normal: { color: '#7fbe9e' }, emphasis: { color: '#140' } }, data: volume }, { type: 'candlestick', name: 'STOCK', data: stocks, markPoint: { data: markpoints }, itemStyle: { normal: { color: '#ef232a', color0: '#14b143', borderColor: '#ef232a', borderColor0: '#14b143' }, emphasis: { color: 'black', color0: '#444', borderColor: 'black', borderColor0: '#444' } } }, { name: 'MA5', type: 'line', data: dataMA5, smooth: true, showSymbol: false, lineStyle: { normal: { width: 1 } } }, { name: 'MA10', type: 'line', data: dataMA10, smooth: true, showSymbol: false, lineStyle: { normal: { width: 1 } } }, { name: 'MA20', type: 'line', data: dataMA20, smooth: true, showSymbol: false, lineStyle: { normal: { width: 1 } } }, { name: 'MA30', type: 'line', data: dataMA30, smooth: true, showSymbol: false, lineStyle: { normal: { width: 1 } } }, { name: 'predicted close', type: 'line', data: predicted_val, smooth: false, showSymbol: false, lineStyle: { normal: { width: 2 } } }] }; var chart_stock = echarts.init(document.getElementById('div_output')); chart_stock.setOption(option,true); // $('#after-hell').css('display','block'); // formData = new FormData(); // formData.append("date", JSON.stringify(stock_date)); // formData.append("close", JSON.stringify(close)); // formData.append("rolling", $('#history').val()); // // xmlhttp = new XMLHttpRequest(); // xmlhttp.onreadystatechange = function() { // if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { // try{ // data = JSON.parse(this.responseText); // plot_pairplot(data) // } // catch(err){ // Materialize.toast("error, unable to do post-processing, please try with different data",3000); // return; // } // if(data['error']){ // Materialize.toast("error, unable to do post-processing, please try with different data",3000); // return; // } // else{ // } // } // }; // xmlhttp.open("POST", "http://huseinhouse.com:8070/uploader", true); // xmlhttp.send(formData); }); }, 500); }) function plot_pairplot(val){ var chart = echarts.init(document.getElementById('pairplot')); var columns = ['Close','Crude Oil','Diesel', 'Gasoline', 'Gold', 'Heating Oil', 'Kerosene', 'Natural Gas', 'Propane']; var grids = []; var xAxes = []; var yAxes = []; var series = []; var titles = []; var count = 0; for(var k = 8; k >= 0;k--){ grids.push({ show: false, borderWidth: 0, backgroundColor: '#fff', shadowColor: 'rgba(0, 0, 0, 0.3)', shadowBlur: 2 }); if(k%9==0){ xAxes.push({ type: 'category', name:'sell', show:true, data: val['pairplot'][k][0][0], gridIndex: count }) xAxes.push({ type: 'category', name:'buy', show:false, data: val['pairplot'][k][1][0], gridIndex: count }) yAxes.push({ type: 'value', show:true, gridIndex: count }) series.push({ data: val['pairplot'][k][0][1], name:'sell', type: 'bar', xAxisIndex: count, yAxisIndex: count, }) series.push({ data: val['pairplot'][k][1][1], name:'buy', type: 'bar', xAxisIndex: count, yAxisIndex: count, }) titles.push({ textAlign: 'center', text: columns[k]+' histogram', textStyle: { fontSize: 12, fontWeight: 'normal' } }) } else{ titles.push({ textAlign: 'center', text: columns[0]+' vs '+columns[k], textStyle: { fontSize: 12, fontWeight: 'normal' } }) xAxes.push({ type: 'value', gridIndex: count, show: true, min:'dataMin', max:'dataMax' }) yAxes.push({ type: 'value', show: true, gridIndex: count, min:'dataMin', max:'dataMax' }) series.push({ data: val['pairplot'][k][0][0].map(function(el, idx) { return [el,val['pairplot'][k][0][1][idx]]; }), type: 'scatter', name:'sell', xAxisIndex: count, yAxisIndex: count, }) series.push({ data: val['pairplot'][k][1][0].map(function(el, idx) { return [el,val['pairplot'][k][1][1][idx]]; }), type: 'scatter', name:'buy', xAxisIndex: count, yAxisIndex: count, }) } count++; } var rowNumber = Math.ceil(Math.sqrt(count)); echarts.util.each(grids, function (grid, idx) { grid.left = ((idx % rowNumber) / rowNumber * 100 + 2) + '%'; grid.top = (Math.floor(idx / rowNumber) / rowNumber * 93 + 15) + '%'; grid.width = (1 / rowNumber * 100 - 5) + '%'; grid.height = (1 / rowNumber * 90 -11) + '%'; titles[idx].left = parseFloat(grid.left) + parseFloat(grid.width) / 2 + '%'; titles[idx].top = (parseFloat(grid.top)-5) + '%'; }); option = { color:['#c23531', '#61a0a8'], legend: { data:['sell','buy'], top:'5%' }, title: titles.concat([{ text: 'Pairplot Study', top: 'top', left: 'center' }]), tooltip: { trigger: 'axis', axisPointer: { animation: false } }, grid: grids, xAxis: xAxes, yAxis: yAxes, series: series }; chart.setOption(option) var chart_pi = echarts.init(document.getElementById('pi_correlation')); var seriesData = []; var selected = {}; for(var i = 0; i < val['pi'].length;i++){ seriesData.push({'name':columns[i+1],'value':val['pi'][i]}) selected[columns[i+1]]=true } option = { title : { text: 'Correlation Piechart', x:'center' }, tooltip : { trigger: 'item', formatter: "{a}
{b} : {c} ({d}%)" }, legend: { type: 'scroll', orient: 'vertical', right: 10, top: 20, bottom: 20, data: columns.slice(1), selected: selected }, series : [ { name: 'correlation', type: 'pie', radius : '55%', center: ['40%', '50%'], data: seriesData, itemStyle: { emphasis: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.5)' } } } ] }; chart_pi.setOption(option) option = { legend: {}, tooltip: { trigger: 'axis', showContent: false }, dataset: { source: val['data_stack'] }, xAxis: {type: 'category'}, yAxis: {gridIndex: 0}, grid: {top: '60%'}, series: [ {type: 'line', smooth: true, seriesLayoutBy: 'row'}, {type: 'line', smooth: true, seriesLayoutBy: 'row'}, {type: 'line', smooth: true, seriesLayoutBy: 'row'}, {type: 'line', smooth: true, seriesLayoutBy: 'row'}, { type: 'pie', id: 'pie', radius: '30%', center: ['50%', '35%'], label: { formatter: '{b}: {@2017-07-31} ({d}%)' }, encode: { itemName: 'data', value: '2017-07-31', tooltip: '2017-07-31' } } ] }; var chart_pie = echarts.init(document.getElementById('div_pie')); chart_pie.on('updateAxisPointer', function (event) { var xAxisInfo = event.axesInfo[0]; if (xAxisInfo) { var dimension = xAxisInfo.value + 1; chart_pie.setOption({ series: { id: 'pie', label: { formatter: '{b}: {@[' + dimension + ']} ({d}%)' }, encode: { value: dimension, tooltip: dimension } } }); } }); chart_pie.setOption(option); var grids = []; var xAxes = []; var yAxes = []; var series = []; var titles = []; var count = 0; for(var i = 0; i < val['movement_changes'].length; i++){ var data = []; for (var k = 0; k < val['movement_changes'][i]['movement'].length; k++) { data.push([val['movement_changes'][i]['date'][k],val['movement_changes'][i]['movement'][k]]) } grids.push({ show: true, borderWidth: 0, backgroundColor: '#fff', shadowColor: 'rgba(0, 0, 0, 0.3)', shadowBlur: 2 }); xAxes.push({ type: 'category', show: false, min:'dataMin', max:'dataMax', gridIndex: count }); yAxes.push({ type: 'value', show: false, min:'dataMin', max:'dataMax', gridIndex: count }); if(val['pct_changes'][i] < 0) color_graph = 'red'; else color_graph = 'green'; series.push({ type: 'line', xAxisIndex: count, yAxisIndex: count, data: data, itemStyle:{ color:color_graph }, showSymbol: false, animationDuration: 1000 }); titles.push({ textAlign: 'center', text: val['movement_changes'][i]['title']+' '+(val['pct_changes'][i]).toFixed(2)+'%', textStyle: { fontSize: 12, fontWeight: 'normal' } }); count++; } var rowNumber = Math.ceil(Math.sqrt(count)); echarts.util.each(grids, function (grid, idx) { grid.left = ((idx % rowNumber) / rowNumber * 100 + 0.5) + '%'; grid.top = (Math.floor(idx / rowNumber) / rowNumber * 120 + 10) + '%'; grid.width = (1 / rowNumber * 100 - 1) + '%'; grid.height = (1 / rowNumber * 120 - 1) + '%'; titles[idx].left = parseFloat(grid.left) + parseFloat(grid.width) / 2 + '%'; titles[idx].top = parseFloat(grid.top) + '%'; }); option = { title: titles.concat([{ text: 'Weekly % changes', top: 'top', left: 'center' }]), tooltip: { trigger: 'axis', axisPointer: { animation: false } }, grid: grids, xAxis: xAxes, yAxis: yAxes, series: series }; var chart_changes = echarts.init(document.getElementById('percent_changes')); chart_changes.setOption(option) generate_investment(['total investment(%): ','total gains: ','stock changes: ','stock changes (%): ','gold changes(%): ','crude oil changes(%): '], [total_investment.toFixed(2), total_gain.toFixed(2), stock_changes.toFixed(2), stock_changes_percent.toFixed(2),(val['gain_crude_oil']*100).toFixed(2),(val['gain_gold']*100).toFixed(2)]) }