Highcharts.setOptions({lang :{ rangeSelectorZoom : "", /*rangeSelectorFrom : "", rangeSelectorTo : "",*/ }}); $(document).ajaxStart(function() { $(productChart.loadingContainer).show(); $(".control-container").addClass("disabled"); }); $(document).ajaxStop(function() { $(productChart.loadingContainer).hide(); $(".control-container").removeClass("disabled"); }); $(window).on('resize.productChart', function(e) { if (isMobileView){ productChart.resize(e); } }); var productChart = { chart : null, cur_chart : null, data : null, period: 5, usedSlot : ["","","","",""], usedMASlot : ["","","","",""], //maColors : {10: "#F48B28", 20: "#FF68D3", 50: "#00DEBB", 100: "#9FA1F3",250:"#BC6BC6"}, maColors : ["#78c043","#865bbc","#da0c6f","#7a004c","#4c227c"], maIndex : {10: 0, 20: 1, 50: 2, 100:3, 250:4}, maIndex2 : [10,20,50,100,250], yAxisRange : [undefined,undefined], colors : {wntLine : "#003868",underlyingLine : "#0072ce"}, navigatorUpdated : null, toolTipMoved : null, selectedRange : [-1,-1], stockcode: "", ucode:'', comparecode : "", backgroundColor: "", selected_ts:0, loadingContainer:null, lastTooltipPoint:null, charttype: "candlestick", isMobile:false, init : function(code, callback, navUpdated, ttMoved){ var self = this; self.navigatorUpdated = (navUpdated!==undefined)?navUpdated:null; self.toolTipMoved = (ttMoved!==undefined)?ttMoved:null; self.isMobile = (isMobileView || $("body").attr("data-broswer-view") == "mobile")?true:false; if (self.isMobile){ self.options.subChartHeight = 75; self.options.chartHeight = 238; } $.getJSON('/'+lang+'/data/chart/productChart/code/'+code+'/period/'+self.period, function(_data) { $(".chartContainer").show(); noChart = 0; if (!_data.mainData.underlying || _data.mainData.underlying.length == 0){ $(".chartContainer").hide(); noChart = 1; return; } self.data = self.decode(_data); var htmlContainer = null; if ($('#productChartContainer .highcharts-html-container').length>0){ htmlContainer = $('#productChartContainer .highcharts-html-container'); } $(".chart-stime").html(_data.stime); $('#productChartContainer').highcharts('StockChart',self.getJSON(self.data), function (chart){ if ($(chart.renderTo).attr("id")){ if (!$('#productChartContainer').hasClass("noSetting")){ if (htmlContainer){ $('#productChartContainer').append(htmlContainer); }else{ $('#productChartContainer').append("
"); $('#productChartContainer .highcharts-html-container').append("
"); self.loadingContainer = $('#productChartContainer .highcharts-html-container .highcharts-loading'); } } self.chart = chart; self.cur_chart = chart; self.stockcode = code; self.drawBackground(); if (self.period == 0){ self.setPeriod(self.data.last[self.data.last.length-1][0]- (60*60*24*1000)*180,self.data.last[self.data.last.length-1][0]); }else if(self.data.last[0]){ self.setPeriod(self.data.last[Math.max(self.data.last.length-71,0)][0],self.data.last[self.data.last.length-1][0]); } //self.setPeriod(self.data.last[self.data.last.length-1][0]- (60*60*24*1000)*365,self.data.last[self.data.last.length-1][0]); self.changeChartType(self.charttype); if (callback){ callback(); } }else{ chart.reflow(); } }); }); }, decode : function(_data){ this.ucode = _data.mainData.ucode; var udata = _data.mainData.underlying; var uohlc = [], uvolume = [], uturnover = [],ulast = []; for (i = 0; i < udata.length; i++) { uohlc.push({ x: udata[i].ts, y: udata[i].last, high: udata[i].high, low: udata[i].low, open: udata[i].open, close: udata[i].last, }); ulast.push([ udata[i].ts, // the date udata[i].last // close ]); uvolume.push([ udata[i].ts, // the date udata[i].vol // the volume ]); uturnover.push([ udata[i].ts, // the date udata[i].turnover // the turnover ]); } var _max = 0; var _min = 99999; var data = _data.mainData.warrant; var ohlc = [], volume = [], turnover = [],last = [], os=[]; for (i = 0; i < data.length; i++) { // ohlc.push({ // x: data[i].ts, // y: data[i].last, // high: data[i].high, // low: data[i].low, // open: data[i].open, // close: data[i].last, // }); _max = Math.max(_max,data[i].last); _min = Math.min(_min,data[i].last); last.push([ data[i].ts, // the date data[i].last // close ]); volume.push([ data[i].ts, // the date data[i].vol // the volume ]); turnover.push([ data[i].ts, // the date data[i].turnover // the turnover ]); os.push([ data[i].ts, // the date data[i].os // the turnover ]); } if (_max == _min){ this.yAxisRange[0] = _max-0.01; this.yAxisRange[1] = _max+0.01; }else if (_min<=0.012){ this.yAxisRange[0] = _min-0.001; } return {vol:volume, turnover: turnover, last:last, os:os, uohlc : uohlc, uvol:uvolume, uturnover: uturnover, ulast:ulast}; }, options : { groupingUnits : [["minute",[5]],],//[['day',[1]],], chartHeight : 400, chartTitle : 45, subChartHeight : 100, subChartTitle : 23, dateBarHeight : 25, footerPadding : 5, /*chartTitle : 23,*/ }, resize: function(e){ var self = this; var chart = this.chart; var count = 0; //usedSlot for(var i=0;i1000)?80:60, marginRight: 50, marginTop: this.options.chartTitle, events: { load: function(){ if (this == self.chart){ //self.refreshSeries(); }else{ //console.log("load: copy"); self.cur_chart = this; //self.refreshSeries(); setTimeout(function(){ self.cur_chart = self.chart; }, 100); } }, redraw: function(event) { if ((self.selectedRange[0]!=event.target.xAxis[0].min || self.selectedRange[1]!=event.target.xAxis[0].max) || (self.selectedRange[0]==-1 && self.selectedRange[1]==-1)){ //console.log("redraw",self.navigatorUpdated); self.selectedRange[0] = event.target.xAxis[0].min; self.selectedRange[1] = event.target.xAxis[0].max; if (self.navigatorUpdated){ self.navigatorUpdated(event.target.xAxis[0].min,event.target.xAxis[0].max); } } } } }, annotationsOptions: { enabled: true, noButtons: true, /*buttonsElementId: "underlyingMasterTools",*/ }, exporting: { enabled: false, }, plotOptions: { candlestick: { oxymoronic: true, color: '#d91e19', lineColor: '#d91e19', upColor: '#003868', upLineColor: '#003868' }, area: { threshold: null, }, series: { //turboThreshold: 2000, states:{ hover: { enabled: false, }, inactive:{ opacity:1, } } } }, tooltip: { backgroundColor: "rgba(0,0,0,0)", borderWidth: 0, borderRadius: 0, useHTML: true, positioner: function(width, height, point){ var pos = this.getPosition(width, height, point); if (self.lastTooltipPoint && self.lastTooltipPoint.series.type == "line"){ var _point = self.lastTooltipPoint.point; pos.y = _point.plotY; } return pos; }, formatter : function(){ self.drawToolTip(this); return ""; }, shadow: false, }, rangeSelector : { enabled: false, selected: 1 }, xAxis:{ type: 'datetime', gridLineWidth: 0, lineWidth: 0, tickColor: '#00000000', crosshair: { width: 1, color: "#000", zIndex: 4, dashStyle: "Dash", }, tickPixelInterval:100, labels: { style:{"color": "#000"}, formatter: function () { if (Highcharts.dateFormat('%H:%M', this.value) != "00:00"){ if (Highcharts.dateFormat('%H%M', this.value)*1 < 920){ return Highcharts.dateFormat('09:20', this.value); } return Highcharts.dateFormat('%H:%M', this.value); }else{ return Highcharts.dateFormat('%d/%m', this.value); } } }, opposite: true, offset: this.options.chartHeight*-1-30, }, yAxis: [{ labels:{ style:{"color": "#000"}, formatter: function () { return formatPrice(this.value); }, align:"right", x: -3, y: 4, }, tickAmount : 7, height: this.options.chartHeight, top:this.options.chartTitle, opposite: false, showFirstLabel: false, showLastLabel: true, crosshair: { width: 1, color: "#000", snap:true, zIndex: 4, dashStyle: "Dash", label: { /*shape: "rect",*/ backgroundColor: "#0072ce", enabled: true, format: '{value:.2f}', style:{"color": "#fff"}, } }, gridLineWidth: (self.toolTipMoved !=null)?0:1, }, { labels:{ style:{"color": "#000"}, formatter: function () { return formatPrice(this.value); }, align:'left', x: 3, y: 4, }, min:this.yAxisRange[0], max:this.yAxisRange[1], tickAmount : 7, height: this.options.chartHeight, top:this.options.chartTitle, opposite: true, showFirstLabel: false, showLastLabel: true, crosshair: { width: 1, color: "#000", snap:true, zIndex: 4, dashStyle: "Dash", label: { /*shape: "rect",*/ backgroundColor: "#003868", enabled: true, format: '{value:.3f}', style:{"color": "#fff"}, } }, }, { top:-100,//this.options.chartHeight-43, height: 90, gridLineWidth: 0, labels:{ enabled: false, style:{"color": "#000"}, }, }, { top:-100,height: this.options.subChartHeight,title: {text: null,},offset: 0,tickAmount : 5,opposite: false,showFirstLabel: false,showLastLabel: false, labels:{formatter: this.subChartLabelFormatter,align:'right',x: -3,y: 4,style:{"color": "#000"}}, crosshair: {width: 0}, },{ top:-100,height: this.options.subChartHeight,title: {text: null,},offset: 0,tickAmount : 5,opposite: true,showFirstLabel: false,showLastLabel: false, labels:{formatter: this.subChartLabelFormatter,align:'left',x: 3,y: 4,style:{"color": "#000"}}, crosshair: {width: 0}, },{ top:-100,height: this.options.subChartHeight,title: {text: null,},offset: 0,tickAmount : 5,opposite: true,showFirstLabel: false,showLastLabel: false, labels:{formatter: this.subChartLabelFormatter,align:'left',x: 3,y: 4,style:{"color": "#000"}}, crosshair: {width: 0}, },{ top:-100,height: this.options.subChartHeight,title: {text: null,},offset: 0,tickAmount : 5,opposite: true,showFirstLabel: false,showLastLabel: false, labels:{formatter: this.subChartLabelFormatter,align:'left',x: 3,y: 4,style:{"color": "#000"}}, crosshair: {width: 0}, },{ top:-100,height: this.options.subChartHeight,title: {text: null,},offset: 0,tickAmount : 5,opposite: true,showFirstLabel: false,showLastLabel: false, labels:{formatter: this.subChartLabelFormatter,align:'left',x: 3,y: 4,style:{"color": "#000"}}, crosshair: {width: 0}, },{ top:-100,height: this.options.subChartHeight,title: {text: null,},offset: 0,tickAmount : 5,opposite: true,showFirstLabel: false,showLastLabel: false, labels:{formatter: this.subChartLabelFormatter,align:'left',x: 3,y: 4,style:{"color": "#000"}}, crosshair: {width: 0}, }], navigator : { enabled : (this.isMobile || this.period != 0)?false:true, height : 60, baseSeries: 0, outlineColor: '#00716C', maskFill: 'rgba(36, 130, 125, 0.1)', handles: { backgroundColor: "#a8d0ce", borderColor: "#00716C" }, xAxis: { gridLineWidth: 0, labels:{ enabled: false } }, yAxis: { gridLineWidth: 0, labels:{ enabled: false } }, series: { data: data.last, type: 'area', fillColor: 'rgba(237,237,237,1)', lineColor: '#00000000' } }, scrollbar : { enabled : false }, series : [{ id : "vol", type: 'column', name: 'vol', data: data.vol, yAxis: 2, color: "#cad3da", dataGrouping: { approximation: "sum", units: self.options.groupingUnits, groupPixelWidth: 1000 } },{ name: 'primary', type: 'candlestick', id: 'primary', data : data.uohlc, yAxis: 0, zIndex: 1, dataGrouping: { units: self.options.groupingUnits, groupPixelWidth: 1000 } },{ name: 'w_primary', type: 'line', id: 'w_primary', data : data.last, yAxis: 1, zIndex: 1, color: this.colors['wntLine'], dataGrouping: { units: self.options.groupingUnits, //groupPixelWidth: 1000 } }], }; }, refreshSeries : function(){ var chart = this.cur_chart; var _series = []; for (var i=0;i0 && this.cur_chart!=this.chart){ for (var j=0;j0){ chart.tooltip.refresh(_series); } }, setPeriod : function(_from,_to){ if (this.data.last[0][0]){ this.chart.xAxis[0].setExtremes(Math.max(_from,this.data.last[0][0]), _to); } }, drawToolTip: function(obj){ //console.log("start drawToolTip"); //console.log(obj); //var chart = this.chart; var chart = this.cur_chart; var fontstyle = {color: '#000', fontSize: '13px'}; var textattr = {zIndex: 7, class: "tooltipElement"}; var xoffset = 0; //if ($(".tooltipElement.s"+obj.points[0].x).length>0){ if ($(".tooltipElement.s"+obj.points[0].x).length>0 && this.cur_chart == this.chart){ return; } if (this.cur_chart == this.chart){ $(".tooltipElement").remove(); } if (this.toolTipMoved){ this.toolTipMoved(obj.points[0].x); } if (this.period!=0){ chart.renderer.text(Highcharts.dateFormat('%d/%m/%Y %H:%M',obj.points[0].x), 15, 18).css(fontstyle).attr(textattr).add(); xoffset = 50; }else{ chart.renderer.text(Highcharts.dateFormat('%d/%m/%Y',obj.points[0].x), 15, 18).css(fontstyle).attr(textattr).add(); } try { var _points = []; for(var j = 0; j b.series.name ? 1 : -1; }); for(var j = 0; j<_points.length;j++){ /*if (this.points[j].series.name.startsWith(self.usedMASlot[i])){ _index = j; break; }*/ this.selected_ts = _points[0].x; if (_points[j].series.name == "primary"){ }else if (_points[j].series.name == "vol"){ }else if (_points[j].series.name.indexOf("_sma")>0 || _points[j].series.name.indexOf("_ema")>0 ){ for(var i =0; i0){ chart.renderer.text("SMA("+days+"):"+formatPrice(_points[j].y), 145*_index+45+chart.margin[3]+xoffset, 18).css(fontstyle).attr(textattr).add(); }else{ chart.renderer.text("EMA("+days+"):"+formatPrice(_points[j].y), 145*_index+45+chart.margin[3]+xoffset, 18).css(fontstyle).attr(textattr).add(); } }else if (_points[j].series.name.indexOf("_compare")>0){ }else if (_points[j].series.name.indexOf("_bol")>0 && _points[j].point.high){ var _label1 = this.labels()[lang].toolTip.MASlot[5][0]+": "; //"("+_points[j].series.userOptions.p1+","+_points[j].series.userOptions.p2+"): "; var _label2 = this.labels()[lang].toolTip.MASlot[5][1]+": "; var _label3 = this.labels()[lang].toolTip.MASlot[5][2]+": "; _label1 += (_points[j-1].y).toFixed(2); _label2 += (_points[j].point.high).toFixed(2); _label3 += (_points[j].point.low).toFixed(2); chart.renderer.text(_label1, 25+chart.margin[3]+xoffset, 18).css(fontstyle).attr(textattr).add(); chart.renderer.text(_label2, 185+chart.margin[3]+xoffset, 18).css(fontstyle).attr(textattr).add(); chart.renderer.text(_label3, 345+chart.margin[3]+xoffset, 18).css(fontstyle).attr(textattr).add(); }else if (_points[j].series.name.indexOf("_sar")>0){ }else{ var segment = _points[j].series.name.split("_"); var days = ""; if (segment.length==2){ textattr.class = "tooltipElement text_subchart"; var index = segment[0].replace("s","")*1; var _top = (this.options.chartHeight+this.options.chartTitle)+((this.options.subChartHeight+this.options.subChartTitle)*index)+this.options.dateBarHeight; for(var i =0; i=0;i--){ if (chart.series[i].name && (chart.series[i].name == this.usedMASlot[_id[j]] || chart.series[i].name.startsWith(this.usedMASlot[_id[j]]+"_"))){ chart.series[i].remove(); } } } this.setUsedMASlot(_id[j], ""); } }, addMAline: function(type, id){ var chart = this.chart; var self = this; //return; if (type!=""){ var tempArr = type.split("-"); var _type = tempArr[0]; var _para = "?type="+_type; for (var i=1; i0){ self.setUsedMASlot(_index, series[i].name); } }else{ series[i].name = "t"+id+"_"+type; self.setUsedMASlot(id, "t"+id+"_"+type); for (var j=1; j=0;i--){ if (chart.series[i].name && (chart.series[i].name == this.usedSlot[id] || chart.series[i].name.startsWith(this.usedSlot[id]+"_"))){ chart.series[i].remove(); chart.yAxis[yAxisID].userOptions.top = -100; chart.yAxis[yAxisID].userOptions.min = null; chart.yAxis[yAxisID].userOptions.max = null; chart.yAxis[yAxisID].userOptions.togetherWith = null; } } } this.setUsedSlot(id, ""); }, addSeries: function(type, id){ var chart = this.chart; var yAxisID = id + 4; var self = this; $(".tooltipElement").remove(); if (id>=0 && type!="" && !(type == "vol" || type == "turnover" || type == "os" || type == "turnovers")){ var tempArr = type.split("-"); var _type = tempArr[0]; var _para = "?type="+_type; for (var i=1; i0){ return; } var chartWidth = $('#productChartContainer').width(); var sbox = '
'; var cbox = ''; container.append(sbox+cbox);*/ }, updateSeriesPosition: function(){ var chart = this.chart; var j=0; for (var i=0;i=0 && id=0 && id0 || self.usedMASlot[0].indexOf("_ema")>0 ){ // command = (self.usedMASlot[0].split("_"))[1]; // for(var i=1;i0){ var _value = (self.usedMASlot[i].split("-")); for(var j=1; j<_value.length;j++){ command += "-"+_value[j]; } }else{ if(self.usedMASlot[i]!=""){ command += "-"+(self.usedMASlot[i].split("-"))[1]; // self.addMAline(command, i); } } } if (command){ self.addMAline(command, -1); } /*for(var i=0;i0){ $("#confirm_btn").trigger("click"); }else if (typeof updateChartLayout == "function"){ updateChartLayout(); } }, getChartHeight : function(){ var height = this.options.chartHeight+this.options.chartTitle+this.options.dateBarHeight; if (!(this.isMobile || this.period != 0)){ height += 90; } for(var i = 0; i < this.usedSlot.length; i++) { if (this.usedSlot[i] != ""){ height += this.options.subChartHeight+this.options.subChartTitle; } } /*this.chart.xAxis[0].userOptions.top = height-70; this.chart.xAxis[0].update();*/ //return height-((this.isIntraday)?70:0); return height+this.options.footerPadding; }, labels : function (){ var _out = { tc :{ ucurrency: uunit, currency: "港元", unit:{ K:"千", M:"百萬", B:"十億", }, subTitle : { macd : "相關資產平滑異同移動平均線", rsi : "相關資產相對強弱指數", turnover : "輪證成交額", turnovers: "", os : "輪證街貨量", }, toolTip : { open:"O:", high:"H:", low:"L:", last : "輪證價格", /*last:"C:",*/ volume:"成交量:", uhigh: this.ucode + " 最高價", ulow: this.ucode + " 最低價", uopen: this.ucode + " 開市價", ulast: "相關資產價格", wlast: this.stockcode + " 價格", MASlot: ["10天移動平均線","20天移動平均線","50天移動平均線","100天移動平均線","250天移動平均線",["保力加平均線","保力加下限線","保力加上限線"],adddigit(this.comparecode) + " 價格"], TASlot: { os : "", turnover:"", turnovers:["輪證成交額","相關資產成交額"], rsi:"", macd:["MACD","MACD-訊號","MACD-差異"], }, }, calllv : "收回價", maturity : "到期日", strike : "行使價", gearing : "有效槓桿", egearing : "有效槓桿", x: "倍", call : "認購", put : "認沽", bull : "牛證", bear : "熊證", stime: "最後更新時間: " }, sc :{ ucurrency: uunit, currency: "港元", unit:{ K:"千", M:"百万", B:"十亿", }, subTitle : { macd : "相关资产平滑异同移动平均线", rsi : "相关资产相对强弱指数", turnover : "轮证成交额", turnovers: "", os : "轮证街货量", }, toolTip : { open:"O:", high:"H:", low:"L:", last : "轮证价格", /*last:"C:",*/ volume:"成交量:", uhigh: this.ucode + " 最高价", ulow: this.ucode + " 最低价", uopen: this.ucode + " 开市价", ulast: "相关资产价格", wlast: this.stockcode + " 价格", MASlot: ["10天移动平均线","20天移动平均线","50天移动平均线","100天移动平均线","250天移动平均线",["保力加平均线","保力加下限线","保力加上限线"],adddigit(this.comparecode) + " 价格"], TASlot: { os : "", turnover:"", turnovers:["轮证成交额","相关资产成交额"], rsi:"", macd:["MACD","MACD-讯号","MACD-差异"], }, }, calllv : "收回价", maturity : "到期日", strike : "行使价", gearing : "有效杠杆", egearing : "有效杠杆", x: "倍", call : "认购", put : "认沽", bull : "牛证", bear : "熊证", stime: "最後更新时间: " }, en :{ ucurrency: uunit, currency: "HKD", unit:{ K:"K", M:"M", B:"B", }, subTitle : { macd : "MACD", rsi : "RSI", turnover : "Product turnover", turnovers: "", os : "Outstanding", }, toolTip : { open:"O:", high:"H:", low:"L:", last : "Product last", /*last:"C:",*/ volume:"Volume:", uhigh: this.ucode + " high", ulow: this.ucode + " low", uopen: this.ucode + " open", ulast: "Underlying last", wlast: this.stockcode + " last", MASlot: ["SMA-10","SMA-20","SMA-50","SMA-100","SMA-250",["Moving average","Bollinger lower bound","Bollinger upper bound"],adddigit(this.comparecode) + " last"], TASlot: { os : "", turnover:"", turnovers:["Product turnover","Underlying turnover"], rsi:"RSI", macd:["MACD","MACD-signal","MACD-diff"], }, }, calllv : "Call level", maturity : "Maturity", strike : "Strike", gearing : "Gearing", egearing : "Eff.Gearing", x: "X", call : "Call", put : "Put", bull : "Bull", bear : "Bear", stime: "Last update: " }, }; if (typeof ucurrency == "string"){ _out[lang].ucurrency = ucurrency; } return _out; }, }