var volatilityChart = { chart : null, data : null, recomm : null, tickPositions : [], tickPositions_all : [], startDate : "", view: "", dataShift: 2, init : function(code,wtype,period,inout,active,callback){ var self = this; this.view = $("body").attr("data-broswer-view"); this.dataShift = (this.view == "desktop")?1:2; $.getJSON('/'+lang+'/data/chart/volatilityChart/code/'+code+'/wtype/'+wtype+'/period/'+(period*1)+'/inout/'+(inout*1)+'/active/'+(active*1), function(_data) { var data = self.decode(_data); self.data = data; self.emptyRecord(self.dataShift); self.recomm = _data.furtherData.recomm; if (typeof callback == "function"){ callback(_data); } $('#volatilityChartContainer').highcharts('StockChart',self.getJSON(data), function(chart){ self.chart = chart; volatilityChart.chart.series[0].update({visible : $("#a1").prop("checked")}); volatilityChart.chart.series[1].update({visible : $("#a2").prop("checked")}); volatilityChart.chart.series[2].update({visible : $("#a3").prop("checked")}); volatilityChart.chart.series[3].update({visible : $("#a4").prop("checked")}); if (data.last.length>0){ self.setPeriod(data.last[Math.max(data.last.length-10-self.dataShift,0)].x, data.last[data.last.length-1].x); } }); }); }, setDays : function(_day){ var data = this.data; if (_day == 5){ this.dataShift = 1; this.emptyRecord(0); this.emptyRecord(this.dataShift); this.chart.xAxis[0].update({tickPositions:this.tickPositions_all}); this.setPeriod(data.last[Math.max(data.last.length-5-this.dataShift,0)].x, data.last[data.last.length-1].x); this.startDate = data.sdate[Math.max(data.last.length-1-5,0)][1]; }else{ this.dataShift = (this.view == "desktop")?1:2; this.emptyRecord(0); this.emptyRecord(this.dataShift); this.chart.xAxis[0].update({tickPositions:this.tickPositions}); this.setPeriod(data.last[Math.max(data.last.length-10-this.dataShift,0)].x, data.last[data.last.length-1].x); this.startDate = data.sdate[Math.max(data.last.length-1-10,0)][1]; } }, setPeriod : function(_from,_to){ if (this.data.last.length>0){ this.chart.xAxis[0].setExtremes(Math.max(_from,this.data.last[0].x), _to); } }, decode : function(data){ var _data = data.mainData.slice(0); _data = _data.reverse(); var iv_avg = []; var iv_max = []; var oiv = []; var hv = []; var last = []; var sdate = []; this.tickPositions = [] for (var i = 0; i < _data.length; i++) { last.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, }); iv_avg.push({x:_data[i].ts, y:_data[i].iv_avg*1}); iv_max.push({x:_data[i].ts, y:_data[i].iv_max*1}); oiv.push({x:_data[i].ts, y:_data[i].oiv*1}); hv.push({x:_data[i].ts, y:_data[i].hv*1}); sdate.push([_data[i].ts, _data[i].sdate]); if (this.view == "mobile"){ if (this.view == "mobile" && i%2==1){ this.tickPositions.push(_data[i].ts); } this.tickPositions_all.push(_data[i].ts); }else{ this.tickPositions.push(_data[i].ts); this.tickPositions_all.push(_data[i].ts); } } return {last:last,hv:hv,oiv:oiv,iv_max:iv_max,iv_avg:iv_avg,sdate:sdate}; }, emptyRecord: function(shift){ var self = this; var data = self.data; var _ts = data.last[data.last.length-1].x; var _last = data.last[data.last.length-1].high; if (shift>0){ for(i = 0; i < shift; i++){ /*data.last.push([ (_ts+60*60*24*(i+1)*1000), // the date null // close ]);*/ data.last.push({ x: (_ts+60*60*24*(i+1)*1000), y: null,high: _last,low: _last,open: _last,close: null, }); data.iv_avg.push({ x: (_ts+60*60*24*(i+1)*1000), y: null, }); data.iv_max.push({ x: (_ts+60*60*24*(i+1)*1000), y: null, }); data.oiv.push({ x: (_ts+60*60*24*(i+1)*1000), y: null, }); data.hv.push({ x: (_ts+60*60*24*(i+1)*1000), y: null, }); } }else if (shift<0){ for(i = 0; i < shift*-1; i++){ if (data.last[data.last.length-1].y == null){ data.last.pop(); data.iv_avg.pop(); data.iv_max.pop(); data.oiv.pop(); data.hv.pop(); } } }else{ while(true){ if (data.last[data.last.length-1].y == null){ data.last.pop(); data.iv_avg.pop(); data.iv_max.pop(); data.oiv.pop(); data.hv.pop(); }else{ break; } } } }, refreshSeries : function(){ var chart = this.chart; var _series = []; for (var i=0;i0){ chart.tooltip.refresh(_series); } }, redraw: function(){ $(".chartBackgroundLine").remove(); $(".chartLegend").remove(); var self = this; var chart = this.chart; //var chart = (chart2)?chart2:this.chart; var fontstyle = {color: '#000', fontSize: ((this.view == "mobile"))?'11px':'14px', "font-weight": "bold"}; chart.renderer.path(['M', chart.margin[3]+chart.plotWidth, 0+5 ,'L', chart.margin[3]+chart.plotWidth, chart.margin[0]+chart.plotHeight]).attr({ stroke: '#000', 'stroke-width': 1, opacity: 1, class :'chartBackgroundLine', zIndex: 2, }).add(); chart.renderer.path(['M', chart.margin[3], chart.margin[0]+ chart.plotHeight,'L', chart.plotWidth+chart.margin[3], chart.margin[0]+ chart.plotHeight]).attr({ stroke: '#000', 'stroke-width': 1, opacity: 1, class :'chartBackgroundLine', zIndex: 2, }).add(); chart.renderer.path(['M', chart.margin[3], chart.margin[0] + chart.plotHeight - self.options.chart2Height-1,'L', chart.plotWidth+chart.margin[3], chart.margin[0]+ chart.plotHeight - self.options.chart2Height-1]).attr({ stroke: '#000', 'stroke-width': 1, opacity: 1, class :'chartBackgroundLine', zIndex: 2, }).add(); var labeloffset = chart.renderer.text(this.labels()[lang].title.iv, 0, -100).css(fontstyle).attr({class :'chartLegend'}).add().element.getBoundingClientRect().width; chart.renderer.text(this.labels()[lang].title.iv, chart.margin[3]+chart.plotWidth-labeloffset-10, 20).css(fontstyle).attr({ class :'chartLegend', zIndex: 2, }).add(); labeloffset = chart.renderer.text(this.labels()[lang].title.last, 0, -100).css(fontstyle).attr({class :'chartLegend'}).add().element.getBoundingClientRect().width; chart.renderer.text(this.labels()[lang].title.last, chart.margin[3]+chart.plotWidth-labeloffset-10, 20+this.options.chart1Height+chart.margin[0]).css(fontstyle).attr({ class :'chartLegend', zIndex: 2, }).add(); var _recommClass = ["",""]; if (this.recomm.length==2){ var py1 = chart.yAxis[0].toPixels(this.recomm[0].iv); var py2 = chart.yAxis[0].toPixels(this.recomm[1].iv); if (Math.abs(py1-py2)<16){ if (py1_tickPos[_tickPos.length-1]){ _recommClass = ["",""]; }else if (this.recomm[i].iv*1<_tickPos[0]){ _recommClass = ["",""]; } } for(var i = 0; i_tickPos[_tickPos.length-1]) || (this.recomm[i].iv*1<_tickPos[0])){ continue; } var py = chart.yAxis[0].toPixels(this.recomm[i].iv); chart.renderer.text("
"+this.recomm[i].iv+"%
",chart.margin[3]+chart.plotWidth, py,true).css(fontstyle).attr({ class :'chartLegend', zIndex: 2, }).add(); } }, options : { chartHeight : 430, marginLeft : 30, marginRight : 70, marginTop : 30, chart1Height : 230, chart2Height : 130, }, getJSON : function(_data){ var self = this; var fontSize = (self.view == "desktop")?13:12; if (self.view == "pad"){ this.options.marginLeft = 30; this.options.marginRight = 50; this.options.chart1Height = 180; this.options.chart2Height = 100; this.options.chartHeight = 350; }else if (self.view == "mobile"){ this.options.marginLeft = 2; this.options.marginRight = 50; this.options.chart1Height = 150; this.options.chart2Height = 80; this.options.chartHeight = 300; }else{ this.options.marginLeft = 30; this.options.marginRight = 70; this.options.chart1Height = 230; this.options.chart2Height = 130; this.options.chartHeight = 430; } return { chart: { marginLeft: this.options.marginLeft, marginRight: this.options.marginRight, marginTop: this.options.marginTop, animation: false, height: this.options.chartHeight, events: { redraw: function(event) { self.redraw(); self.refreshSeries(); } }, }, rangeSelector: { enabled: false, selected: 1 }, tooltip:{ enabled: true, shadow: false, borderWidth: 0, positioner: function () { return { x: 0, y: -100 }; }, formatter: function () { if (typeof drawToolTip == "function"){ drawToolTip(this.points); } return ""; }, }, plotOptions: { line:{ lineWidth: 2, color: '#00716C', }, series: { dataGrouping: { enabled : false }, states: { hover: { enabled: false } } }, }, xAxis: { type: 'datetime', gridLineWidth: 0, tickColor: '#e6e6e6', labels: { style:{"color": "#000", "fontSize": "13px"}, formatter: function () { return Highcharts.dateFormat('%d/%m', this.value); } }, opposite: false, tickPositions: this.tickPositions, crosshair: { width: 1, color: "#000", snap:true, zIndex: 4, dashStyle: "Dash", label: { enabled: false, } }, //showFirstLabel: (self.view == "desktop")?true:false, }, yAxis: [{ labels:{ style:{"color": "#000", "fontSize": fontSize+"px"}, align:'left', x:5, y:5, formatter: function () { return (this.value.toFixed(2))+"%"; } }, opposite: true, height: this.options.chart1Height, showFirstLabel: false, tickPixelInterval: 50, },{ title: { text: null, }, labels:{ style:{"color": "#000", "fontSize": "13px"}, align:'left', x:5, y:5, formatter: function () { return formatPrice(this.value); } }, offset: 0, top: this.options.chart1Height+this.options.marginTop+1, opposite: true, height: this.options.chart2Height, showFirstLabel: false, showLastLabel: false, tickPixelInterval: 50, crosshair: { width: 1, color: "#000", snap:true, zIndex: 4, dashStyle: "Dash", label: { /*shape: "rect",*/ backgroundColor: "#575757", enabled: true, format: '{value:.2f}', style:{"color": "#fff"}, } } } ], navigator : { enabled : false, }, scrollbar : { enabled : false }, series : [{ type : "line", name : "iv_avg", data : _data.iv_avg, yAxis: 0, color: "#003868", marker: { radius:1, symbol:"circle", enabled: true } }, { type : "line", name : "iv_max", data : _data.iv_max, yAxis: 0, color: "#00b2ac", marker: { radius:1, symbol:"circle", enabled: true } }, { type : "line", name : "oiv", data : _data.oiv, yAxis: 0, color: "#78c043", }, { type : "line", name : "hv", data : _data.hv, yAxis: 0, color: "#865bbc", }, { type : "ohlc", name : "last", data : _data.last, yAxis: 1, color: "#0072ce", lineWidth: 2, }], exporting: { enabled: false } }; }, labels : function (){ return { tc :{ title : { iv : "引伸波幅(%)", last : "股價 ("+unit+")", } }, sc :{ title : { iv : "引伸波幅(%)", last : "股价 ("+unit+")", } }, en :{ title : { iv : "IV(%)", last : "Last ("+unit+")", } }, } }, }