瀏覽代碼

new chart types

larry 10 年之前
父節點
當前提交
22d7f5af67

+ 12 - 3
config/app.cfg

@@ -28,8 +28,12 @@ tools.staticdir.root : '/home/larry-13.04/workspace/finopt/src/'
 
 [/static]
 tools.staticdir.on : True
-#tools.staticdir.dir : './public'
 tools.staticdir.tmpl : './html'
+#tools.staticdir : './html'
+
+[/public]
+tools.staticdir.on: True
+tools.staticdir.dir : './html/public'
 
 
 [options_data]
@@ -54,7 +58,8 @@ ib.subscription.fileloc: '/home/larry-13.04/workspace/finopt/data/subscription.t
 
 [market]
 hkex.openhours: '{"morning":[915,1200], "afternoon":[1300,1615]}'
-ib.gateway: '127.0.0.1'
+#ib.gateway: '127.0.0.1'
+ib.gateway: 'vsu-01'
 ib.port: 7496
 #gw port
 #ib.port:4001
@@ -62,7 +67,7 @@ ib.appid.portfolio: 9922
 
 ib.appid: 9911
 option.underlying = "('HSI', 'FUT', 'HKFE', 'HKD', '', 0, '')"
-option.underlying.month_price = "[['20150929', 22817.0, '^HSI'], ['20151029', 22715.0, '^HSI']]"
+option.underlying.month_price = "[['20151029', 22817.0, '^HSI'], ['20151127', 22715.0, '^HSI']]"
 option.underlying.yahoo_ws = "{'use_yahoo': True, 'func': 'ystockquote.get_price'}"
 option.underlying.tick_size = 200
 option.greeks.recal = "{'use_last_if_no_bidask': True, 'rate':0.005, 'div':0.005, 'vol':0.2}"
@@ -103,3 +108,7 @@ ib_heartbeat.gateway: 'localhost'
 #ib_heartbeat.gateway: '192.168.1.118'
 ib_heartbeat.try_interval: 3
 ib_heartbeat.suppress_msg_interval: 60
+
+[smart_order]
+smart_order.logconfig: "{'filename': '/home/larry-13.04/workspace/finopt/log/smart_order.log', 'filemode': 'w','level': logging.INFO}"
+

+ 4 - 4
config/mds.cfg

@@ -28,8 +28,8 @@ ib_mds.logconfig: "{'filename': '/home/larry-13.04/workspace/finopt/log/ib_mds.l
 ib_mds.ib_port: 7496
 #ib_mds.ib_port: 4001
 ib_mds.appid.id: 9800
-ib_mds.gateway: 'localhost'
-#ib_mds.gateway: '192.168.1.118'
+#ib_mds.gateway: 'localhost'
+ib_mds.gateway: '192.168.1.118'
 ib_mds.is_persist: 1
 ib_mds.persist_dir: '/home/larry-13.04/workspace/finopt/data/mds_files'
 ib_mds.subscription.fileloc: '/home/larry-13.04/workspace/finopt/data/subscription-hsio.txt'
@@ -40,7 +40,7 @@ ib_heartbeat.logconfig: "{'filename': '/home/larry-13.04/workspace/finopt/log/ib
 #ib_heartbeat.ib_port: 4001
 ib_heartbeat.ib_port: 7496
 ib_heartbeat.appid.id: 9911
-ib_heartbeat.gateway: 'localhost'
-#ib_heartbeat.gateway: '192.168.1.118'
+#ib_heartbeat.gateway: 'localhost'
+ib_heartbeat.gateway: '192.168.1.118'
 ib_heartbeat.try_interval: 90
 ib_heartbeat.suppress_msg_interval: 60

+ 18 - 4
finopt/opt_serve.py

@@ -51,7 +51,8 @@ class QServer(object):
        
         impl_link = "<a href='./opt_implv'>options implied vol curves</a>"
         pos_link = "<a href=./ws_position_chart>Positions</a>" 
-        return """<html><body><li>%s</li><li>%s</li><br><dl>%s</dl></br>%s</body></html>""" % (impl_link, pos_link, html, s_line)
+        bubble_link = "<a href=./port_bubble_chart>Risk Distributions</a>"
+        return """<html><body><li>%s</li><li>%s</li><li>%s</li><br><dl>%s</dl></br>%s</body></html>""" % (bubble_link, impl_link, pos_link, html, s_line)
  
  
     @cherrypy.expose
@@ -367,6 +368,9 @@ class QServer(object):
         return s
     
     
+
+    
+    
     @cherrypy.expose
     def ws_port_summary(self):    
         
@@ -424,15 +428,25 @@ class QServer(object):
         colnames = "[['contract', 'strike', 'unreal PL', 'theta', 'delta'],"
         print '----------------------'
         s_data = colnames + ''.join('["%s",%s,%s,%s,%s],' % (lcontract[i], lstrike[i], lupl[i], ltheta[i], lpos_delta[i]) for i in range(len(lcontract)))+ ']'
+
+
+        bubble_chart_tmpl = '%s%s/bubble-port.html' % (cherrypy.request.app.config['/']['tools.staticdir.root'], cherrypy.request.app.config['/static']['tools.staticdir.tmpl'])
+        f = open(bubble_chart_tmpl)
+        html_tmpl = f.read()
+        html_tmpl = html_tmpl.replace('{{{bubble_data}}}', s_data)
         
-        print s_data
-        return s_data
+        contract_month = eval(cherrypy.request.app.config['market']['option.underlying.month_price'])[0][0]
+        html_tmpl = html_tmpl.replace('{{{FUT_CONTRACT}}}', 'HSI-%s-FUT-' % (contract_month))
+        return html_tmpl
         
     
     @cherrypy.expose
     def ws_msg_bot(self, msg):
         a = AlertHelper(self.config)
-        a.post_msg(msg)      
+        a.post_msg(msg)  
+        
+        
+            
          
 if __name__ == '__main__':
             

二進制
finopt/opt_serve.pyc


+ 3 - 3
finopt/options_data.py

@@ -495,9 +495,9 @@ class ContractHelper():
       
     @staticmethod
     def makeRedisKeyEx(contract, old=False):
-        # this routine is to circumvent a problem in makeRedisKey for which 
-        # the key's position 3 have different meanings
-        # according to a particular m_secType, which is not right. 
+        # this routine is to circumvent a problem in makeRedisKey with 
+        # the key in position 3 having different meanings under different conditions.
+        #  
         # 
         # to differentiate the keys generated by the old and new functions, 
         # contract keys created using this routine have their last slot

二進制
finopt/options_data.pyc


+ 0 - 18
finopt/portfolio.py

@@ -85,7 +85,6 @@ class PortfolioManager():
         
         self.con = ibConnection(host, port, appid)
         self.con.registerAll(self.on_ib_message)
-        #self.con.registerAll(self.xyz)
         
         
         self.tlock = Lock()
@@ -531,17 +530,6 @@ class PortfolioManager():
 
 if __name__ == '__main__':
            
-#     logging.basicConfig(#filename = "log/port.log", filemode = 'w', 
-#                         level=logging.DEBUG,
-#                         format='%(asctime)s %(levelname)-8s %(message)s')      
-#     
-#     config = ConfigParser.ConfigParser()
-#     config.read("config/app.cfg")
-#     p = PortfolioManager(config)
-#     p.retrieve_position()
-#     print p.get_portfolio_summary()
-#     print p.get_tbl_pos_csv()
-
     if len(sys.argv) != 2:
         print("Usage: %s <config file>" % sys.argv[0])
         exit(-1)    
@@ -561,12 +549,6 @@ if __name__ == '__main__':
     print p.get_tbl_pos_csv()
 
 
-
-    #p.recal_port()
-#    print p.get_tbl_pos_csv()
-#     print p.get_grouped_options_str_array()
-#     print p.group_pos_by_right()
-
     # sample ouput    
 # ["exch","type","contract_mth","right","strike","con_ration","pos","avgcost"],["HSI","OPT","20150828","C","22600",50.0,0.0000,0.0000,],["HSI","OPT","20150828","C","23000",50.0,-1.0000,1770.0000,],["HSI","OPT","20150828","C","23600",50.0,-2.0000,1470.0000,],["HSI","OPT","20150828","C","23800",50.0,-1.0000,920.0000,],["HSI","OPT","20150828","C","24000",50.0,-2.0000,1820.0000,],["HSI","OPT","20150828","C","24200",50.0,-1.0000,3120.0000,],["HSI","OPT","20150828","C","24800",50.0,-1.0000,220.0000,],["HSI","OPT","20150828","P","18000",50.0,-2.0000,1045.0000,],["HSI","OPT","20150828","P","18600",50.0,-1.0000,1120.0000,],["HSI","OPT","20150828","P","18800",50.0,-1.0000,1570.0000,],["HSI","OPT","20150828","P","19800",50.0,-1.0000,870.0000,],["HSI","OPT","20150828","P","20200",50.0,-1.0000,970.0000,],["HSI","OPT","20150828","P","20800",50.0,-2.0000,970.0000,],["HSI","OPT","20150828","P","21600",50.0,-1.0000,1570.0000,],["HSI","OPT","20150828","P","21800",50.0,-7.0000,1955.7143,],["HSI","OPT","20150828","P","23200",50.0,1.0000,25930.0000,],["HSI","OPT","20150929","C","24400",50.0,1.0000,24880.0000,],["HSI","OPT","20150929","P","21600",50.0,0.0000,0.0000,],["HSI","OPT","20150929","P","21800",50.0,2.0000,52713.3333,],["HSI","OPT","20150929","P","22600",50.0,3.0000,39763.3333,],["MHI","OPT","20150828","C","24400",10.0,-1.0000,2603.0000,],["MHI","OPT","20150828","P","20800",10.0,-1.0000,313.0000,],["MHI","OPT","20150828","P","21000",10.0,-1.0000,363.0000,],["MHI","OPT","20150828","P","23600",10.0,5.0000,4285.0000,],["MHI","OPT","20150929","C","24400",10.0,1.0000,4947.0000,],["MHI","OPT","20150929","P","21600",10.0,1.0000,12657.0000,],["MHI","OPT","20150929","P","22600",10.0,1.0000,9877.0000,],["MHI","OPT","20150929","P","23600",10.0,4.0000,7757.0000,],
 # [180.000000,-2.0,0],[186.000000,-1.0,0],[188.000000,-1.0,0],[198.000000,-1.0,0],[202.000000,-1.0,0],[208.000000,-2.2,0],[210.000000,-0.2,0],[216.000000,-0.8,0],[218.000000,-5.0,0],[226.000000,0,0.0],[226.000000,3.2,0],[230.000000,0,-1.0],[232.000000,1.0,0],[236.000000,0,-2.0],[236.000000,1.8,0],[238.000000,0,-1.0],[240.000000,0,-2.0],[242.000000,0,-1.0],[244.000000,0,1.0],[248.000000,0,-1.0],

二進制
finopt/portfolio.pyc


+ 0 - 0
finopt/trade/__init__.py


+ 98 - 19
finopt/trade/smart_order.py

@@ -6,16 +6,17 @@ import logging
 import thread
 import ConfigParser
 from ib.ext.Contract import Contract
+from ib.ext.ExecutionFilter import ExecutionFilter
+from ib.ext.Execution import Execution
 from ib.ext.Order import Order
 from ib.opt import ibConnection, message
 from time import sleep
 import time, datetime
-import optcal
-import opt_serve
 import redis
-from helper_func.py import dict2str, str2dict
-from options_data import ContractHelper 
-import portfolio_ex
+import threading
+from threading import Lock, Thread
+from finopt.options_data import ContractHelper
+
             
 # Tick Value      Description
 # 5001            impl vol
@@ -74,7 +75,7 @@ class SmartOrderSelector(object):
 class UnwindOrderSelector(SmartOrderSelector):
     right_type = None
     
-    def __init__(self, right_type. rule):
+    def __init__(self, right_type, rule):
         self.right_type = right_type
         
     
@@ -108,21 +109,99 @@ class UnwindOrderSelector(SmartOrderSelector):
             # return self.pos_max_IV()
             pass
         
+class OrderManager(Thread):
+    
+        config = None
+        tlock = None
+        
+        def __init__(self, config):
+            super(OrderManager, self).__init__()
+            self.config = config
+            self.tlock = Lock()
+
+        def on_ib_message(self, msg):
+            print msg.typeName, msg
+            if msg.typeName == 'openOrder':
+                print ContractHelper.printContract(msg.contract)
+            
+        
+        def orderStatus(self, orderId, status, filled, remaining, avgFillPrice, permId, parentId, lastFillPrice, clientId, whyHeId):
+            pass
+        
+        
+        def send_new_order(self):
+            self.tlock.acquire()
+            try:
+                self.new_order_entrant_unsafe()
+            finally:
+                logging.debug('recal_port: completed recal. releasing lock...')
+                self.tlock.release()  
+            
+        
+        def new_order_entrant_unsafe(self):
+            pass
+        
         
-     
+        def reqExecutions(self):
+            filt = ExecutionFilter()
+            self.con.reqExecutions(0, filt)
         
+        
+        def run(self):
+            host = config.get("market", "ib.gateway").strip('"').strip("'")
+            port = int(config.get("market", "ib.port"))
+            appid = int(config.get("market", "ib.appid.portfolio"))   
+            
+            self.con = ibConnection(host, port, appid)
+            self.con.registerAll(self.on_ib_message)
+            self.con.connect()
+            while 1:
+                self.con.reqAllOpenOrders()
+                self.reqExecutions()
+                sleep(2)
+
+
+class OrderHelper():
+    
+    def make_option_order(self, action, orderID, tif, orderType):
+        opt_order = Order()
+        opt_order.m_orderId = orderID
+        opt_order.m_clientId = 0
+        opt_order.m_permid = 0
+        opt_order.m_action = action
+        opt_order.m_lmtPrice = 0
+        opt_order.m_auxPrice = 0
+        opt_order.m_tif = tif
+        opt_order.m_transmit = False
+        opt_order.m_orderType = orderType
+        opt_order.m_totalQuantity = 1
+        return opt_order        
 
 if __name__ == '__main__':
            
-    logging.basicConfig(#filename = "log/opt.log", filemode = 'w', 
-                        level=logging.DEBUG,
-                        format='%(asctime)s %(levelname)-8s %(message)s')      
-    
-    config = ConfigParser.ConfigParser()
-    config.read("config/app.cfg")
-    
-    x = SmartOrderSelector()
-    print x
-    y = UnwindOrderSelector('c')
-    y.rule_IV()
-    print y
+    if len(sys.argv) != 2:
+        print("Usage: %s <config file>" % sys.argv[0])
+        exit(-1)    
+
+    cfg_path= sys.argv[1:]    
+    config = ConfigParser.SafeConfigParser()
+    if len(config.read(cfg_path)) == 0:      
+        raise ValueError, "Failed to open config file" 
+    
+    logconfig = eval(config.get("smart_order", "smart_order.logconfig").strip('"').strip("'"))
+    logconfig['format'] = '%(asctime)s %(levelname)-8s %(message)s'    
+    logging.basicConfig(**logconfig)       
+    
+    
+    odm = OrderManager(config) 
+    odm.start()
+    
+    
+    
+    
+    
+#     x = SmartOrderSelector()
+#     print x
+#     y = UnwindOrderSelector('c')
+#     y.rule_IV()
+#     print y

文件差異過大導致無法顯示
+ 104 - 0
html/bubble-port-static.html


+ 10 - 0
html/bubble-port-static_files/a

@@ -0,0 +1,10 @@
+if (window['google'] != undefined && window['google']['loader'] != undefined) {
+if (!window['google']['visualization']) {
+window['google']['visualization'] = {};
+google.visualization.Version = '1.1';
+google.visualization.JSHash = 'b9acaf9ce948f3550e84416288f03821';
+google.visualization.LoadArgs = 'file\75visualization\46v\0751.1\46packages\75corechart';
+}
+google.loader.writeLoadTag("css", google.loader.ServiceBase + "/api/visualization/1.1/b9acaf9ce948f3550e84416288f03821/ui+en.css", false);
+google.loader.writeLoadTag("script", google.loader.ServiceBase + "/api/visualization/1.1/b9acaf9ce948f3550e84416288f03821/webfontloader,format+en,default+en,ui+en,corechart+en.I.js", false);
+}

文件差異過大導致無法顯示
+ 1 - 0
html/bubble-port-static_files/jquery.js


文件差異過大導致無法顯示
+ 42 - 0
html/bubble-port-static_files/jsapi


二進制
html/bubble-port-static_files/marker.png


+ 59 - 0
html/bubble-port-static_files/tooltip.css

@@ -0,0 +1,59 @@
+/* Copyright 2012 Google Inc. All Rights Reserved. */
+
+.google-visualization-tooltip-action: hover {
+  background-color: #eeeeee;
+}
+.google-visualization-tooltip {
+  border:solid 1px #bdbdbd;
+  border-radius: 2px;
+  background-color: white;
+  position: absolute;
+  box-shadow: 0px 2px 2px 0px rgba(204, 204, 204, 0.6);
+  font-size: 12px;
+  padding: 0px;
+  -moz-box-shadow: 0px 2px 2px 0px rgba(204, 204, 204, 0.6);
+  -webkit-box-shadow: 0px 2px 2px 0px rgba(204, 204, 204, 0.6);
+}
+.google-visualization-tooltip-action-list {
+  list-style-type: none;
+  margin: 0;
+  padding: 0.5em 0em 0.5em 0em;
+  cursor: hand;
+}
+.google-visualization-tooltip-action {
+  margin: 0;
+  cursor: pointer;
+  padding: 0.5em 2em 0.5em 1em;
+}
+.google-visualization-tooltip-action:hover {
+  background-color: #eeeeee;
+}
+.google-visualization-tooltip-item-list {
+  list-style-type: none;
+  margin: 1em 0 1em 0;
+  padding: 0em;
+}
+.google-visualization-tooltip-item {
+  margin: 0.65em 0em 0.65em 0em;
+  padding: 0em 2em 0em 1em;
+}
+.google-visualization-tooltip-item-list
+.google-visualization-tooltip-item:first-child {
+  margin: 1em 0em 1em 0em;
+}
+.google-visualization-tooltip-separator {
+  margin: 0;
+  padding: 0;
+  height: 1px;
+  background-color: #dddddd;
+}
+.google-visualization-tooltip-square {
+  display: inline-block;
+  /* IE does not support inline-block fall back to float left */
+  float: left\9;
+  clear: none;
+  width: 0.5em;
+  height: 0.5em;
+  margin: 0.16em 0.7em 0em 0em;
+  border-bottom: solid 0.1em white;
+}

文件差異過大導致無法顯示
+ 1 - 0
html/bubble-port-static_files/uien.css


文件差異過大導致無法顯示
+ 22 - 0
html/bubble-port-static_files/webfontloaderformatendefaultenuiencorecharten.js


+ 139 - 0
html/bubble-port.html

@@ -0,0 +1,139 @@
+<html>
+  <head>
+   <style>
+   .chartWithMarkerOverlay {
+       position: relative;
+       width: 700px;
+   }
+   .overlay-text {
+       width: 200px;
+       height: 200px;
+       position: absolute;
+       top: 30px;   /* chartArea top */
+       left: 200px; /* chartArea left */
+   }
+   .overlay-marker {
+       width: 50px;
+       height: 50px;
+       position: absolute;
+       top: 53px;   /* chartArea top */
+       left: 528px; /* chartArea left */
+       color: #000066;
+       font: 15px arial;
+    
+   }
+   </style>
+  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
+    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
+    <script type="text/javascript">
+      google.load("visualization", "1.1", {packages:['corechart']});
+      google.setOnLoadCallback(drawChart);
+      function drawChart() {
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// guage functions
+
+
+		var data = google.visualization.arrayToDataTable( 
+{{{bubble_data}}}
+		); 
+
+
+		var options = { title: 'Portfolio Risk Distribution', 
+			hAxis: {title: 'Strike Price'}, vAxis: {title: ' Unreal P/L'}, 
+			// to display labels, remove the color: 'none option
+			bubble: {textStyle: {fontSize: 11, color: 'none'}}, colorAxis: {colors: ['red', 'blue']},
+			sizeAxis: {minValue: 2,  maxSize: 40}
+			//backgroundColor: '#E4E4E4'
+		 }; 
+
+
+		var chart = new google.visualization.BubbleChart(document.getElementById('chart_div')); 
+		chart.draw(data, options); 
+
+
+		google.visualization.events.addListener(chart, 'ready', placeIndexMarker);
+		
+
+
+		setInterval(function() {
+		  placeIndexMarker();
+		}, 2000);
+
+
+
+		function placeIndexMarker() {
+		    $.ajax({
+			type: 'Post',
+			url: '/ws_market_data?r_ckey={{{FUT_CONTRACT}}}&fid=4',
+			success: function (data) {
+
+				var spot = data
+				$('#spot').text(spot);
+
+				var cli = chart.getChartLayoutInterface();
+				document.querySelector('.overlay-marker').style.top = Math.floor(cli.getYLocation(0) - 45) + "px";
+				document.querySelector('.overlay-marker').style.left = Math.floor(cli.getXLocation(spot)) + "px";
+
+			}
+		    });
+		}
+
+
+
+
+//https://groups.google.com/forum/#!msg/google-chart-api/yYxkv4eorhA/P-MHQOLA19MJ
+/* testing
+		function placeMarker() {
+			var cli = chart.getChartLayoutInterface();
+			document.querySelector('.overlay-marker').style.top = Math.floor(cli.getYLocation(0) - 25) + "px";
+			var spot = Math.round(Math.max(25000 * Math.random(), 15000))
+			$('#pt_status').text(spot);
+			$('#spot').text(spot);
+			document.querySelector('.overlay-marker').style.left = Math.floor(cli.getXLocation(spot)) + "px";
+		};
+
+
+		var cli = chart.getChartLayoutInterface();
+
+		var l= cli.getChartAreaBoundingBox().left;
+		var t=cli.getChartAreaBoundingBox().top;
+		var h=cli.getChartAreaBoundingBox().height;
+		var w= cli.getChartAreaBoundingBox().width;
+		var hx = cli.getYLocation(50000);
+		var cx = cli.getYLocation(0);
+
+		$('#pt_status').text(l + ':' + t  + ':' + h  + ':' + w + ':' + hx + ':' + cx);
+		  function chartMouseOver(e) {
+			var cli = chart.getChartLayoutInterface();
+			var xx = Math.floor(cli.getXLocation(e['row'])) + 'px';
+			var yy = Math.floor(cli.getYLocation(data.getValue(e['row'], 1))) + 'px';
+		  	$('#pt_status').text(e['row'] + ':' + xx +  + ':' + yy + ':' + data.getValue(e['row'], 1));
+		  	$('#pt2_status').text(e['row'] + ':' + cli.getHAxisValue(e['row']));
+		  }
+*/
+      } // end drawChart
+
+
+
+
+
+
+    </script>
+
+
+  </head>
+  <body>
+<div id='pt_status'></div>
+<div id='pt2_status'></div>
+<div id="chart_div" style="width: 900px; height: 800px;"></div>
+<div id='temp'></div>
+  <div class="overlay-marker">
+  <img src="/public/green_marker.png" height="50"><div id='spot'></div>
+  </div>
+  </body>
+</html>
+

+ 139 - 0
html/bubble-port.html~

@@ -0,0 +1,139 @@
+<html>
+  <head>
+   <style>
+   .chartWithMarkerOverlay {
+       position: relative;
+       width: 700px;
+   }
+   .overlay-text {
+       width: 200px;
+       height: 200px;
+       position: absolute;
+       top: 30px;   /* chartArea top */
+       left: 200px; /* chartArea left */
+   }
+   .overlay-marker {
+       width: 50px;
+       height: 50px;
+       position: absolute;
+       top: 53px;   /* chartArea top */
+       left: 528px; /* chartArea left */
+       color: #000066;
+       font: 15px arial;
+    
+   }
+   </style>
+  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
+    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
+    <script type="text/javascript">
+      google.load("visualization", "1.1", {packages:['corechart']});
+      google.setOnLoadCallback(drawChart);
+      function drawChart() {
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// guage functions
+
+
+		var data = google.visualization.arrayToDataTable( 
+{{{bubble_data}}}
+		); 
+
+
+		var options = { title: 'Portfolio Risk Distribution', 
+			hAxis: {title: 'Strike Price'}, vAxis: {title: ' Unreal P/L'}, 
+			// to display labels, remove the color: 'none option
+			bubble: {textStyle: {fontSize: 11, color: 'none'}}, colorAxis: {colors: ['red', 'blue']},
+			sizeAxis: {minValue: 2,  maxSize: 40}
+			//backgroundColor: '#E4E4E4'
+		 }; 
+
+
+		var chart = new google.visualization.BubbleChart(document.getElementById('chart_div')); 
+		chart.draw(data, options); 
+
+
+		google.visualization.events.addListener(chart, 'ready', placeIndexMarker);
+		
+
+/*
+		setInterval(function() {
+		  placeIndexMarker();
+		}, 2000);
+*/
+
+
+		function placeIndexMarker() {
+		    $.ajax({
+			type: 'Post',
+			url: '/ws_market_data?r_ckey={{{FUT_CONTRACT}}}&fid=4',
+			success: function (data) {
+
+				var spot = data
+				$('#spot').text(spot);
+
+				var cli = chart.getChartLayoutInterface();
+				document.querySelector('.overlay-marker').style.top = Math.floor(cli.getYLocation(0) - 45) + "px";
+				document.querySelector('.overlay-marker').style.left = Math.floor(cli.getXLocation(spot)) + "px";
+
+			}
+		    });
+		}
+
+
+
+
+//https://groups.google.com/forum/#!msg/google-chart-api/yYxkv4eorhA/P-MHQOLA19MJ
+/* testing
+		function placeMarker() {
+			var cli = chart.getChartLayoutInterface();
+			document.querySelector('.overlay-marker').style.top = Math.floor(cli.getYLocation(0) - 25) + "px";
+			var spot = Math.round(Math.max(25000 * Math.random(), 15000))
+			$('#pt_status').text(spot);
+			$('#spot').text(spot);
+			document.querySelector('.overlay-marker').style.left = Math.floor(cli.getXLocation(spot)) + "px";
+		};
+
+
+		var cli = chart.getChartLayoutInterface();
+
+		var l= cli.getChartAreaBoundingBox().left;
+		var t=cli.getChartAreaBoundingBox().top;
+		var h=cli.getChartAreaBoundingBox().height;
+		var w= cli.getChartAreaBoundingBox().width;
+		var hx = cli.getYLocation(50000);
+		var cx = cli.getYLocation(0);
+
+		$('#pt_status').text(l + ':' + t  + ':' + h  + ':' + w + ':' + hx + ':' + cx);
+		  function chartMouseOver(e) {
+			var cli = chart.getChartLayoutInterface();
+			var xx = Math.floor(cli.getXLocation(e['row'])) + 'px';
+			var yy = Math.floor(cli.getYLocation(data.getValue(e['row'], 1))) + 'px';
+		  	$('#pt_status').text(e['row'] + ':' + xx +  + ':' + yy + ':' + data.getValue(e['row'], 1));
+		  	$('#pt2_status').text(e['row'] + ':' + cli.getHAxisValue(e['row']));
+		  }
+*/
+      } // end drawChart
+
+
+
+
+
+
+    </script>
+
+
+  </head>
+  <body>
+<div id='pt_status'></div>
+<div id='pt2_status'></div>
+<div id="chart_div" style="width: 900px; height: 800px;"></div>
+<div id='temp'></div>
+  <div class="overlay-marker">
+  <img src="/public/green_marker.png" height="50"><div id='spot'></div>
+  </div>
+  </body>
+</html>
+

文件差異過大導致無法顯示
+ 18 - 0
html/jq-test-tab.html


文件差異過大導致無法顯示
+ 17 - 0
html/jq-test-tab.html~


+ 255 - 0
html/opt-chains-tmpl-no-tabs.html

@@ -0,0 +1,255 @@
+<html>
+  <head>
+  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
+  <title> Trading Options Monitor </title>
+    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
+    <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/mathjs/2.1.1/math.min.js"></script>
+    <script type="text/javascript">
+      google.load("visualization", "1", {packages:["corechart"]});
+      google.load('visualization', '1', {'packages':['table']});
+      google.setOnLoadCallback(drawChart);
+      function drawChart() {
+	// data contains implied vols for a series of this and next month options
+	// the {{{stuff}}} is substituted by the backend python script with the actual data values 
+	var dataArray = [{{{data}}}];
+        var data = google.visualization.arrayToDataTable(dataArray);
+
+	// data2 contains premiums for a series of this and next month options 
+        var data2 = google.visualization.arrayToDataTable([
+{{{dataPremium}}}
+
+        ]);
+	
+
+        var options = {
+	title: "HSI PUT/CALL volatility",
+          hAxis: {minValue: 18000, maxValue: 22500},
+          vAxis: {minValue: 0.15, maxValue: 0.4},
+          chartArea: {width:'80%'},
+	  pointShape: 'diamond',
+          trendlines: {
+            0: {
+              type: 'polynomial',
+              showR2: true,
+              visibleInLegend: true,
+	      
+		},
+            1: {
+              type: 'polynomial',
+              showR2: true,
+              visibleInLegend: true
+
+            },
+            2: {
+              type: 'polynomial',
+              showR2: true,
+              visibleInLegend: true
+
+            },
+            3: {
+              type: 'polynomial',
+              showR2: true,
+              visibleInLegend: true
+
+            }
+          }
+        };
+
+
+	// helper routine to search for the min and max values in the data array
+	// the function skips row 1 which is a header row, 
+	// it skips the first column which is the strike price
+	function minMax(myStringArray){
+	    var arrayLength = myStringArray.length;
+	    var s = '';
+	    var min, max;
+	    min = 99999;
+	    max = -1;
+	    var allNums = new Array();
+	    var k = 0;
+	    for (var i = 1; i < arrayLength; i++) {
+		for (j = 1; j < myStringArray[i].length; j++){
+		        if (myStringArray[i][j] == null) continue;
+		        if (myStringArray[i][j] > max)
+		            max = myStringArray[i][j];
+		        if (myStringArray[i][j] < min)
+		            min = myStringArray[i][j];
+			allNums[k++] = myStringArray[i][j];	
+		}   
+		//s = s + myStringArray[i][0];
+		
+	    }
+	    return { "min" : min , "max": max, "median": math.median(allNums) };
+	}
+
+
+        var chartLinear = new google.visualization.ScatterChart(document.getElementById('chartLinear'));
+        chartLinear.draw(data, options);
+
+        options.trendlines[0].type = 'polynomial';
+        options.trendlines[1].type = 'polynomial';
+
+
+	// chart table display implied volatilities in a nicely formatted table	
+       var chartTbl = new google.visualization.Table(document.getElementById('chartTbl_div'));
+
+	// determine the min max and median of the implied vols
+	var data_range = minMax(dataArray);
+	var formatter = new google.visualization.BarFormat({base: data_range.median,
+                                                             min: data_range.min, 
+                                                             max: data_range.max, width: 120});
+	document.getElementById('vol_divider').value = (data_range.median / data_range.max) * 100;
+	document.getElementById('vol_divider_value').value = data_range.median;
+	var formatter2 = new google.visualization.NumberFormat({pattern:'0.####'});
+	for (i=1; i < 5; i++){
+		formatter2.format(data, i);
+		formatter.format(data, i); // Apply formatter to second column
+	}
+        var options2 = {
+          displayAnnotations: true,
+	  showRowNumber: true, width: '100%', height: '100%', allowHtml: true,
+        };
+	chartTbl.draw(data, options2);
+
+
+        var chartPremium = new google.visualization.ScatterChart(document.getElementById('chartPremium'));
+	options.title = 'PUT/CALL Premium';
+        chartPremium.draw(data2, options);
+	
+
+
+         document.getElementById('format-select').onchange = function() {
+
+           options['pointShape'] = this.value;
+
+           chartLinear.draw(data, options);
+
+         };
+
+        document.getElementById('vol_divider').onchange = function() {
+	   var x = this.value / 100 * (data_range.max - data_range.min) + data_range.min;
+	   document.getElementById('vol_divider_value').value = x;
+           //formatter = new google.visualization.BarFormat({base: x,min:0, max:0.5, width: 120});
+	   formatter = new google.visualization.BarFormat({base: x,
+                                                             min: data_range.min, 
+                                                             max: data_range.max, width: 120});
+   	   for (i=1; i < 5; i++){
+		formatter.format(data, i); // Apply formatter to second column
+	   }
+           chartTbl.draw(data, options2);
+         };
+
+
+        document.getElementById('haxis_range').onchange = function() {
+	   document.getElementById('haxis_from_value').value = this.value;
+	   options.hAxis.minValue = this.value;
+	   chartPremium.draw(data2, options);
+	   chartLinear.draw(data, options);
+
+         };
+      
+// The select handler. Call the chart's getSelection() method
+  function selectHandler() {
+    var selectedItem = chartLinear.getSelection()[0];
+    if (selectedItem) {
+      var value = data.getValue(selectedItem.row, selectedItem.column);
+      alert('The user selected ' + value);
+    }
+  }
+
+  // Listen for the 'select' event, and call my function selectHandler() when
+  // the user selects something on the chart.
+  google.visualization.events.addListener(chartLinear, 'select', selectHandler);
+
+      }
+
+
+    </script>
+    <script>
+    $(document).ready(function () {
+        $('input[id="b_refresh"]').click(function () {
+            
+            $.ajax({
+                type: 'Post',
+                url: '/ws_market_data?r_ckey=HSI-20151029-FUT-&fid=4',
+                success: function (data) {
+			document.getElementById('undly_last_px').value = data;
+                }
+            });
+            $.ajax({
+                type: 'Post',
+                url: '/getSHquote?qs=0000001,1399001,1399300',
+                success: function (data) {
+
+			var json_data = JSON.parse(data);
+
+			if (!String.prototype.format) {
+			  String.prototype.format = function() {
+			    var args = arguments;
+			    return this.replace(/{(\d+)}/g, function(match, number) { 
+			      return typeof args[number] != 'undefined'
+				? args[number]
+				: match
+			      ;
+			    });
+			  };
+			}
+
+
+			var s = "|  {0}: {1} [{2}%]  |  {3}: {4} [{5}%] |  {6}: {7} [{8}%]".format(
+							json_data['0000001']['name'],
+							json_data['0000001']['price'],
+							(json_data['0000001']['percent']*100).toFixed(2) ,
+							json_data['1399001']['name'],
+							json_data['1399001']['price'],
+							(json_data['1399001']['percent']*100).toFixed(2) ,
+							json_data['1399300']['name'],
+							json_data['1399300']['price'],
+							(json_data['1399300']['percent']*100).toFixed(2) );
+			
+			document.getElementById('ssidx_px').value = s;
+                }
+            });
+
+
+
+        })
+    })
+    </script>
+
+  </head>
+  <body>
+        <div id="d_undly_last_px">
+            <input type="button" id="b_refresh" value="Refresh Price" />
+	    <output id=undly_last_px></output>
+	    <output id=ssidx_px></output>
+        </div>
+    <div id="chartLinear" style="height: 350px; width: 850px"></div>
+    <div id="chartPremium" style="height: 350px; width: 850px"></div>
+<li>
+<label for=haxis_from>H-Axis Range Starts At:</label>
+<input type=range id=haxis_range min=10000 value=20000 max=25000 step=500>
+<output id=haxis_from_value></output>
+</li>
+<h2> Implied volatilities for this and next month HSI options</h2>
+    <div id='chartTbl_div' style='width: 900px; height: 500px;'></div>
+    <select id="format-select">
+      <option value="">none</option>
+      <option value="Diamond" selected>Diamond</option>
+      <option value="triangle">triangle</option>
+      <option value="square">square</option>
+      <option value="diamond">diamond</option>
+      <option value="star">star</option>
+      <option value="polygon">polygon</option>
+    </select>
+    <div id="number_format_chart">
+<li>
+<label for=vol_divider>Volatility Divider</label>
+<input type=range id=vol_divider min=0 value=50 max=100 step=5>
+<output id=vol_divider_value></output>
+</li>
+
+
+
+  </body>
+</html>

+ 286 - 0
html/opt-chains-tmpl-with-tabs.html

@@ -0,0 +1,286 @@
+<html>
+  <head>
+  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
+  <title> Trading Options Monitor </title>
+    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
+    <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/mathjs/2.1.1/math.min.js"></script>
+<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
+<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
+
+    <script type="text/javascript">
+//      google.load("visualization", "1", {packages:["corechart"]});
+//      google.load('visualization', '1', {'packages':['table', 'corehart']});
+      google.load("visualization", "1.1", {packages:["corechart", 'table']});
+      google.setOnLoadCallback(drawChart);
+      function drawChart() {
+	// data contains implied vols for a series of this and next month options
+	// the {{{stuff}}} is substituted by the backend python script with the actual data values 
+	var dataArray = [{{{data}}}];
+        var data = google.visualization.arrayToDataTable(dataArray);
+
+	// data2 contains premiums for a series of this and next month options 
+        var data2 = google.visualization.arrayToDataTable([
+{{{dataPremium}}}
+
+        ]);
+	
+
+        var options = {
+	title: "HSI PUT/CALL volatility",
+          hAxis: {minValue: 18000, maxValue: 22500},
+          vAxis: {minValue: 0.15, maxValue: 0.4},
+          chartArea: {width:'80%'},
+	  pointShape: 'diamond',
+          trendlines: {
+            0: {
+              type: 'polynomial',
+              showR2: true,
+              visibleInLegend: true,
+	      
+		},
+            1: {
+              type: 'polynomial',
+              showR2: true,
+              visibleInLegend: true
+
+            },
+            2: {
+              type: 'polynomial',
+              showR2: true,
+              visibleInLegend: true
+
+            },
+            3: {
+              type: 'polynomial',
+              showR2: true,
+              visibleInLegend: true
+
+            }
+          }
+        };
+
+
+	// helper routine to search for the min and max values in the data array
+	// the function skips row 1 which is a header row, 
+	// it skips the first column which is the strike price
+	function minMax(myStringArray){
+	    var arrayLength = myStringArray.length;
+	    var s = '';
+	    var min, max;
+	    min = 99999;
+	    max = -1;
+	    var allNums = new Array();
+	    var k = 0;
+	    for (var i = 1; i < arrayLength; i++) {
+		for (j = 1; j < myStringArray[i].length; j++){
+		        if (myStringArray[i][j] == null) continue;
+		        if (myStringArray[i][j] > max)
+		            max = myStringArray[i][j];
+		        if (myStringArray[i][j] < min)
+		            min = myStringArray[i][j];
+			allNums[k++] = myStringArray[i][j];	
+		}   
+		//s = s + myStringArray[i][0];
+		
+	    }
+	    return { "min" : min , "max": max, "median": math.median(allNums) };
+	}
+
+
+        var chartLinear = new google.visualization.ScatterChart(document.getElementById('chartLinear'));
+        chartLinear.draw(data, options);
+
+        options.trendlines[0].type = 'polynomial';
+        options.trendlines[1].type = 'polynomial';
+
+
+	// chart table display implied volatilities in a nicely formatted table	
+       var chartTbl = new google.visualization.Table(document.getElementById('chartTbl_div'));
+
+	// determine the min max and median of the implied vols
+	var data_range = minMax(dataArray);
+	var formatter = new google.visualization.BarFormat({base: data_range.median,
+                                                             min: data_range.min, 
+                                                             max: data_range.max, width: 120});
+	document.getElementById('vol_divider').value = (data_range.median / data_range.max) * 100;
+	document.getElementById('vol_divider_value').value = data_range.median;
+	var formatter2 = new google.visualization.NumberFormat({pattern:'0.####'});
+	for (i=1; i < 5; i++){
+		formatter2.format(data, i);
+		formatter.format(data, i); // Apply formatter to second column
+	}
+        var options2 = {
+          displayAnnotations: true,
+	  showRowNumber: true, width: '100%', height: '100%', allowHtml: true,
+        };
+	chartTbl.draw(data, options2);
+
+
+        var chartPremium = new google.visualization.ScatterChart(document.getElementById('chartPremium'));
+	options.title = 'PUT/CALL Premium';
+        chartPremium.draw(data2, options);
+	
+
+
+         document.getElementById('format-select').onchange = function() {
+
+           options['pointShape'] = this.value;
+
+           chartLinear.draw(data, options);
+
+         };
+
+        document.getElementById('vol_divider').onchange = function() {
+	   var x = this.value / 100 * (data_range.max - data_range.min) + data_range.min;
+	   document.getElementById('vol_divider_value').value = x;
+           //formatter = new google.visualization.BarFormat({base: x,min:0, max:0.5, width: 120});
+	   formatter = new google.visualization.BarFormat({base: x,
+                                                             min: data_range.min, 
+                                                             max: data_range.max, width: 120});
+   	   for (i=1; i < 5; i++){
+		formatter.format(data, i); // Apply formatter to second column
+	   }
+           chartTbl.draw(data, options2);
+         };
+
+
+        document.getElementById('haxis_range').onchange = function() {
+	   document.getElementById('haxis_from_value').value = this.value;
+	   options.hAxis.minValue = this.value;
+	   chartPremium.draw(data2, options);
+	   chartLinear.draw(data, options);
+
+         };
+      
+// The select handler. Call the chart's getSelection() method
+  function selectHandler() {
+    var selectedItem = chartLinear.getSelection()[0];
+    if (selectedItem) {
+      var value = data.getValue(selectedItem.row, selectedItem.column);
+      alert('The user selected ' + value);
+    }
+  }
+
+  // Listen for the 'select' event, and call my function selectHandler() when
+  // the user selects something on the chart.
+  google.visualization.events.addListener(chartLinear, 'select', selectHandler);
+
+      }
+
+
+    </script>
+    <script>
+    $(document).ready(function () {
+        $('input[id="b_refresh"]').click(function () {
+            
+            $.ajax({
+                type: 'Post',
+                url: '/ws_market_data?r_ckey=HSI-20151029-FUT-&fid=4',
+                success: function (data) {
+			document.getElementById('undly_last_px').value = data;
+                }
+            });
+            $.ajax({
+                type: 'Post',
+                url: '/getSHquote?qs=0000001,1399001,1399300',
+                success: function (data) {
+
+			var json_data = JSON.parse(data);
+
+			if (!String.prototype.format) {
+			  String.prototype.format = function() {
+			    var args = arguments;
+			    return this.replace(/{(\d+)}/g, function(match, number) { 
+			      return typeof args[number] != 'undefined'
+				? args[number]
+				: match
+			      ;
+			    });
+			  };
+			}
+
+
+			var s = "|  {0}: {1} [{2}%]  |  {3}: {4} [{5}%] |  {6}: {7} [{8}%]".format(
+							json_data['0000001']['name'],
+							json_data['0000001']['price'],
+							(json_data['0000001']['percent']*100).toFixed(2) ,
+							json_data['1399001']['name'],
+							json_data['1399001']['price'],
+							(json_data['1399001']['percent']*100).toFixed(2) ,
+							json_data['1399300']['name'],
+							json_data['1399300']['price'],
+							(json_data['1399300']['percent']*100).toFixed(2) );
+			
+			document.getElementById('ssidx_px').value = s;
+                }
+            });
+
+
+        })
+    })
+    </script>
+    <script>
+	$(document).ready(function() {
+		$(function() {
+			$( "#tabs" ).tabs();
+		});
+
+});
+
+
+    </script>
+
+  </head>
+  <body>
+
+<div id="tabs">
+  <ul>
+    <li><a href="#tabs-1">Volatility Curves</a></li>
+    <li><a href="#tabs-2">Implied Volatility Table</a></li>
+    <li><a href="#tabs-3">Risk Distribution</a></li>
+  </ul>
+  <div id="tabs-1">
+        <div id="d_undly_last_px">
+            <input type="button" id="b_refresh" value="Refresh Price" />
+	    <output id=undly_last_px></output>
+	    <output id=ssidx_px></output>
+        </div>
+        <div id="chartLinear" style="height: 350px; width: 850px"></div>
+        <div id="chartPremium" style="height: 350px; width: 850px"></div>
+	<li>
+	<label for=haxis_from>H-Axis Range Starts At:</label>
+	<input type=range id=haxis_range min=10000 value=20000 max=25000 step=500>
+	<output id=haxis_from_value></output>
+	</li>
+
+  </div>
+  <div id="tabs-2">
+	<h2> Implied volatilities for this and next month HSI options</h2>
+	    <div id='chartTbl_div' style='width: 900px; height: 500px;'></div>
+	    <select id="format-select">
+	      <option value="">none</option>
+	      <option value="Diamond" selected>Diamond</option>
+	      <option value="triangle">triangle</option>
+	      <option value="square">square</option>
+	      <option value="diamond">diamond</option>
+	      <option value="star">star</option>
+	      <option value="polygon">polygon</option>
+	    </select>
+	    <div id="number_format_chart">
+	<li>
+	<label for=vol_divider>Volatility Divider</label>
+	<input type=range id=vol_divider min=0 value=50 max=100 step=5>
+	<output id=vol_divider_value></output>
+	</li>
+    
+  </div>
+  <div id="tabs-3">
+  </div>
+</div>
+
+
+
+
+
+  </body>
+</html>

+ 288 - 0
html/opt-chains-tmpl-with-tabs.html~

@@ -0,0 +1,288 @@
+<html>
+  <head>
+  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
+  <title> Trading Options Monitor </title>
+    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
+    <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/mathjs/2.1.1/math.min.js"></script>
+<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
+<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
+
+    <script type="text/javascript">
+//      google.load("visualization", "1", {packages:["corechart"]});
+//      google.load('visualization', '1', {'packages':['table', 'corehart']});
+	google.load("visualization", "1.1", {packages:["corechart", 'table']});
+      google.setOnLoadCallback(drawChart);
+      function drawChart() {
+	// data contains implied vols for a series of this and next month options
+	// the {{{stuff}}} is substituted by the backend python script with the actual data values 
+	var dataArray = [{{{data}}}];
+        var data = google.visualization.arrayToDataTable(dataArray);
+
+	// data2 contains premiums for a series of this and next month options 
+        var data2 = google.visualization.arrayToDataTable([
+{{{dataPremium}}}
+
+        ]);
+	
+
+        var options = {
+	title: "HSI PUT/CALL volatility",
+          hAxis: {minValue: 18000, maxValue: 22500},
+          vAxis: {minValue: 0.15, maxValue: 0.4},
+          chartArea: {width:'80%'},
+	  pointShape: 'diamond',
+          trendlines: {
+            0: {
+              type: 'polynomial',
+              showR2: true,
+              visibleInLegend: true,
+	      
+		},
+            1: {
+              type: 'polynomial',
+              showR2: true,
+              visibleInLegend: true
+
+            },
+            2: {
+              type: 'polynomial',
+              showR2: true,
+              visibleInLegend: true
+
+            },
+            3: {
+              type: 'polynomial',
+              showR2: true,
+              visibleInLegend: true
+
+            }
+          }
+        };
+
+
+	// helper routine to search for the min and max values in the data array
+	// the function skips row 1 which is a header row, 
+	// it skips the first column which is the strike price
+	function minMax(myStringArray){
+	    var arrayLength = myStringArray.length;
+	    var s = '';
+	    var min, max;
+	    min = 99999;
+	    max = -1;
+	    var allNums = new Array();
+	    var k = 0;
+	    for (var i = 1; i < arrayLength; i++) {
+		for (j = 1; j < myStringArray[i].length; j++){
+		        if (myStringArray[i][j] == null) continue;
+		        if (myStringArray[i][j] > max)
+		            max = myStringArray[i][j];
+		        if (myStringArray[i][j] < min)
+		            min = myStringArray[i][j];
+			allNums[k++] = myStringArray[i][j];	
+		}   
+		//s = s + myStringArray[i][0];
+		
+	    }
+	    return { "min" : min , "max": max, "median": math.median(allNums) };
+	}
+
+
+        var chartLinear = new google.visualization.ScatterChart(document.getElementById('chartLinear'));
+        chartLinear.draw(data, options);
+
+        options.trendlines[0].type = 'polynomial';
+        options.trendlines[1].type = 'polynomial';
+
+
+	// chart table display implied volatilities in a nicely formatted table	
+       var chartTbl = new google.visualization.Table(document.getElementById('chartTbl_div'));
+
+	// determine the min max and median of the implied vols
+	var data_range = minMax(dataArray);
+	var formatter = new google.visualization.BarFormat({base: data_range.median,
+                                                             min: data_range.min, 
+                                                             max: data_range.max, width: 120});
+	document.getElementById('vol_divider').value = (data_range.median / data_range.max) * 100;
+	document.getElementById('vol_divider_value').value = data_range.median;
+	var formatter2 = new google.visualization.NumberFormat({pattern:'0.####'});
+	for (i=1; i < 5; i++){
+		formatter2.format(data, i);
+		formatter.format(data, i); // Apply formatter to second column
+	}
+        var options2 = {
+          displayAnnotations: true,
+	  showRowNumber: true, width: '100%', height: '100%', allowHtml: true,
+        };
+	chartTbl.draw(data, options2);
+
+
+        var chartPremium = new google.visualization.ScatterChart(document.getElementById('chartPremium'));
+	options.title = 'PUT/CALL Premium';
+        chartPremium.draw(data2, options);
+	
+
+
+         document.getElementById('format-select').onchange = function() {
+
+           options['pointShape'] = this.value;
+
+           chartLinear.draw(data, options);
+
+         };
+
+        document.getElementById('vol_divider').onchange = function() {
+	   var x = this.value / 100 * (data_range.max - data_range.min) + data_range.min;
+	   document.getElementById('vol_divider_value').value = x;
+           //formatter = new google.visualization.BarFormat({base: x,min:0, max:0.5, width: 120});
+	   formatter = new google.visualization.BarFormat({base: x,
+                                                             min: data_range.min, 
+                                                             max: data_range.max, width: 120});
+   	   for (i=1; i < 5; i++){
+		formatter.format(data, i); // Apply formatter to second column
+	   }
+           chartTbl.draw(data, options2);
+         };
+
+
+        document.getElementById('haxis_range').onchange = function() {
+	   document.getElementById('haxis_from_value').value = this.value;
+	   options.hAxis.minValue = this.value;
+	   chartPremium.draw(data2, options);
+	   chartLinear.draw(data, options);
+
+         };
+      
+// The select handler. Call the chart's getSelection() method
+  function selectHandler() {
+    var selectedItem = chartLinear.getSelection()[0];
+    if (selectedItem) {
+      var value = data.getValue(selectedItem.row, selectedItem.column);
+      alert('The user selected ' + value);
+    }
+  }
+
+  // Listen for the 'select' event, and call my function selectHandler() when
+  // the user selects something on the chart.
+  google.visualization.events.addListener(chartLinear, 'select', selectHandler);
+
+      }
+
+
+    </script>
+    <script>
+    $(document).ready(function () {
+        $('input[id="b_refresh"]').click(function () {
+            
+            $.ajax({
+                type: 'Post',
+                url: '/ws_market_data?r_ckey=HSI-20151029-FUT-&fid=4',
+                success: function (data) {
+			document.getElementById('undly_last_px').value = data;
+                }
+            });
+            $.ajax({
+                type: 'Post',
+                url: '/getSHquote?qs=0000001,1399001,1399300',
+                success: function (data) {
+
+			var json_data = JSON.parse(data);
+
+			if (!String.prototype.format) {
+			  String.prototype.format = function() {
+			    var args = arguments;
+			    return this.replace(/{(\d+)}/g, function(match, number) { 
+			      return typeof args[number] != 'undefined'
+				? args[number]
+				: match
+			      ;
+			    });
+			  };
+			}
+
+
+			var s = "|  {0}: {1} [{2}%]  |  {3}: {4} [{5}%] |  {6}: {7} [{8}%]".format(
+							json_data['0000001']['name'],
+							json_data['0000001']['price'],
+							(json_data['0000001']['percent']*100).toFixed(2) ,
+							json_data['1399001']['name'],
+							json_data['1399001']['price'],
+							(json_data['1399001']['percent']*100).toFixed(2) ,
+							json_data['1399300']['name'],
+							json_data['1399300']['price'],
+							(json_data['1399300']['percent']*100).toFixed(2) );
+			
+			document.getElementById('ssidx_px').value = s;
+                }
+            });
+
+
+        })
+    })
+    </script>
+    <script>
+$(document).ready(function() {
+
+      google.setOnLoadCallback(drawChart);
+//	$(function() {
+//		$( "#tabs" ).tabs();
+//	});
+
+});
+
+
+    </script>
+
+  </head>
+  <body>
+
+<div id="tabs">
+  <ul>
+    <li><a href="#tabs-1">Volatility Curves</a></li>
+    <li><a href="#tabs-2">Implied Volatility Table</a></li>
+    <li><a href="#tabs-3">Risk Distribution</a></li>
+  </ul>
+  <div id="tabs-1">
+        <div id="d_undly_last_px">
+            <input type="button" id="b_refresh" value="Refresh Price" />
+	    <output id=undly_last_px></output>
+	    <output id=ssidx_px></output>
+        </div>
+        <div id="chartLinear" style="height: 350px; width: 850px"></div>
+        <div id="chartPremium" style="height: 350px; width: 850px"></div>
+	<li>
+	<label for=haxis_from>H-Axis Range Starts At:</label>
+	<input type=range id=haxis_range min=10000 value=20000 max=25000 step=500>
+	<output id=haxis_from_value></output>
+	</li>
+
+  </div>
+  <div id="tabs-2">
+	<h2> Implied volatilities for this and next month HSI options</h2>
+	    <div id='chartTbl_div' style='width: 900px; height: 500px;'></div>
+	    <select id="format-select">
+	      <option value="">none</option>
+	      <option value="Diamond" selected>Diamond</option>
+	      <option value="triangle">triangle</option>
+	      <option value="square">square</option>
+	      <option value="diamond">diamond</option>
+	      <option value="star">star</option>
+	      <option value="polygon">polygon</option>
+	    </select>
+	    <div id="number_format_chart">
+	<li>
+	<label for=vol_divider>Volatility Divider</label>
+	<input type=range id=vol_divider min=0 value=50 max=100 step=5>
+	<output id=vol_divider_value></output>
+	</li>
+    
+  </div>
+  <div id="tabs-3">
+  </div>
+</div>
+
+
+
+
+
+  </body>
+</html>

+ 59 - 28
html/opt-chains-tmpl.html~

@@ -4,9 +4,11 @@
   <title> Trading Options Monitor </title>
     <script type="text/javascript" src="https://www.google.com/jsapi"></script>
     <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/mathjs/2.1.1/math.min.js"></script>
+
     <script type="text/javascript">
-      google.load("visualization", "1", {packages:["corechart"]});
-      google.load('visualization', '1', {'packages':['table']});
+//      google.load("visualization", "1", {packages:["corechart"]});
+//      google.load('visualization', '1', {'packages':['table', 'corehart']});
+	google.load("visualization", "1.1", {packages:["corechart", 'table']});
       google.setOnLoadCallback(drawChart);
       function drawChart() {
 	// data contains implied vols for a series of this and next month options
@@ -171,7 +173,7 @@
             
             $.ajax({
                 type: 'Post',
-                url: '/ws_market_data?r_ckey=HSI-20150929-FUT-&fid=4',
+                url: '/ws_market_data?r_ckey=HSI-20151029-FUT-&fid=4',
                 success: function (data) {
 			document.getElementById('undly_last_px').value = data;
                 }
@@ -212,42 +214,71 @@
             });
 
 
-
         })
     })
     </script>
+    <script>
+$(document).ready(function() {
+
+      google.setOnLoadCallback(drawChart);
+//	$(function() {
+//		$( "#tabs" ).tabs();
+//	});
+
+});
+
+
+    </script>
 
   </head>
   <body>
+
+<div id="tabs">
+  <ul>
+    <li><a href="#tabs-1">Volatility Curves</a></li>
+    <li><a href="#tabs-2">Implied Volatility Table</a></li>
+    <li><a href="#tabs-3">Risk Distribution</a></li>
+  </ul>
+  <div id="tabs-1">
         <div id="d_undly_last_px">
             <input type="button" id="b_refresh" value="Refresh Price" />
 	    <output id=undly_last_px></output>
 	    <output id=ssidx_px></output>
         </div>
-    <div id="chartLinear" style="height: 350px; width: 850px"></div>
-    <div id="chartPremium" style="height: 350px; width: 850px"></div>
-<li>
-<label for=haxis_from>H-Axis Range Starts At:</label>
-<input type=range id=haxis_range min=10000 value=20000 max=25000 step=500>
-<output id=haxis_from_value></output>
-</li>
-<h2> Implied volatilities for this and next month HSI options</h2>
-    <div id='chartTbl_div' style='width: 900px; height: 500px;'></div>
-    <select id="format-select">
-      <option value="">none</option>
-      <option value="Diamond" selected>Diamond</option>
-      <option value="triangle">triangle</option>
-      <option value="square">square</option>
-      <option value="diamond">diamond</option>
-      <option value="star">star</option>
-      <option value="polygon">polygon</option>
-    </select>
-    <div id="number_format_chart">
-<li>
-<label for=vol_divider>Volatility Divider</label>
-<input type=range id=vol_divider min=0 value=50 max=100 step=5>
-<output id=vol_divider_value></output>
-</li>
+        <div id="chartLinear" style="height: 350px; width: 850px"></div>
+        <div id="chartPremium" style="height: 350px; width: 850px"></div>
+	<li>
+	<label for=haxis_from>H-Axis Range Starts At:</label>
+	<input type=range id=haxis_range min=10000 value=20000 max=25000 step=500>
+	<output id=haxis_from_value></output>
+	</li>
+
+  </div>
+  <div id="tabs-2">
+	<h2> Implied volatilities for this and next month HSI options</h2>
+	    <div id='chartTbl_div' style='width: 900px; height: 500px;'></div>
+	    <select id="format-select">
+	      <option value="">none</option>
+	      <option value="Diamond" selected>Diamond</option>
+	      <option value="triangle">triangle</option>
+	      <option value="square">square</option>
+	      <option value="diamond">diamond</option>
+	      <option value="star">star</option>
+	      <option value="polygon">polygon</option>
+	    </select>
+	    <div id="number_format_chart">
+	<li>
+	<label for=vol_divider>Volatility Divider</label>
+	<input type=range id=vol_divider min=0 value=50 max=100 step=5>
+	<output id=vol_divider_value></output>
+	</li>
+    
+  </div>
+  <div id="tabs-3">
+  </div>
+</div>
+
+
 
 
 

+ 172 - 0
html/opt-pos-chart-tmpl-no-tabs.html

@@ -0,0 +1,172 @@
+<html>
+  <head>
+  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
+    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
+    <script type="text/javascript">
+      google.load("visualization", "1.1", {packages:["bar", 'table','gauge']});
+//      google.load('visualization', '1', {'packages':['table']});
+//      google.load("visualization", "1.1", {packages:["corechart"]});
+      google.setOnLoadCallback(drawChart);
+      function drawChart() {
+        var data = google.visualization.arrayToDataTable([
+          ['Strike Price', 'P', 'C', ],
+{{{dataPCpos}}}
+        ]);
+
+	var dataTbl = google.visualization.arrayToDataTable([
+{{{dataTablePos}}}
+
+        ]);
+
+
+        var options = {
+          width: 900,
+          chart: {
+            title: 'Option Postion Distribution. PUT:CALL Ratio [{{{PRvsCR}}}}]',
+            subtitle: 'for the month of {{{option_months}}}',
+          },
+ 
+        };
+
+        var chart = new google.charts.Bar(document.getElementById('barchart_material'));
+        chart.draw(data, options);
+
+
+
+
+	// chart table display implied volatilities in a nicely formatted table	
+       var chartTbl = new google.visualization.Table(document.getElementById('chartTbl_div'));
+
+
+       //var portTbl = new google.visualization.Table(document.getElementById('portTblDiv'));
+
+	var formatter = new google.visualization.NumberFormat({pattern:'0.00'});
+	for (var i = 2; i < 9; i++)
+		formatter.format(dataTbl, i); 
+        var options2 = {
+          displayAnnotations: true,
+	  showRowNumber: true, width: '100%', height: '100%', allowHtml: true,
+        };
+	chartTbl.draw(dataTbl, options2);
+
+	$('input[id="b_reload"]').click();
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// guage functions
+
+		var dataG = google.visualization.arrayToDataTable([
+		  ['Label', 'Value'],
+		  ['Delta', 0],
+		  ['Delta-C', 0],
+		  ['Delta-P', 0]
+		]);
+
+		var optionsG = {
+
+		  width: 400, height: 120,
+		  redFrom: -50, redTo: -25,
+		  yellowFrom:-24, yellowTo: -15,
+		  greenFrom: -10, greenTo: 10,	
+		  minorTicks: 5,
+		  min: -50, max: 50
+		};
+
+		var dataT = google.visualization.arrayToDataTable([
+		  ['Label', 'Value'],
+		  ['Theta', 0],
+		  ['Theta-C', 0],
+		  ['Theta-P', 0]
+		]);
+
+		var optionsT = {
+
+		  width: 400, height: 120,
+		  redFrom: -3000, redTo: -2000,
+		  yellowFrom:-1999, yellowTo: 500,
+		  greenFrom: 5000, greenTo: 15000,	
+		  minorTicks: 5,
+		  min: -3000, max: 15000
+		};
+
+		var gchart = new google.visualization.Gauge(document.getElementById('chart_div'));
+//		refreshPortSummary();
+//		gchart.draw(dataG, optionsG);
+
+		var tchart = new google.visualization.Gauge(document.getElementById('chartTheta_div'));
+		refreshPortSummary();
+		
+		function refreshPortSummary(){
+		    $.ajax({
+			type: 'Post',
+			url: '/ws_port_summary',
+			success: function (data) {
+				//alert(data);
+				var jdata = JSON.parse(data);
+				$('#temp').text(data);				
+				//alert(jdata.delta_all);
+				
+				dataG.setValue(0, 1, Math.round(jdata.delta_all*100)/100);
+				dataG.setValue(1, 1, Math.round(jdata.delta_c*100)/100);
+				dataG.setValue(2, 1, Math.round(jdata.delta_p*100)/100);
+				gchart.draw(dataG, optionsG);
+
+				dataT.setValue(0, 1, Math.round(jdata.theta_all));
+				dataT.setValue(1, 1, Math.round(jdata.theta_c));
+				dataT.setValue(2, 1, Math.round(jdata.theta_p));
+				tchart.draw(dataT, optionsT);
+
+				$('#pt_status').text("Unreal P/L: " + Math.round(jdata.unreal_pl*100)/100 + "   Cal Status: " + jdata.status);
+
+			}
+		    });
+
+		};
+
+		setInterval(function() {
+			refreshPortSummary();
+		}, 9500);    
+
+
+
+
+
+
+
+
+      } // end drawChart
+
+
+
+
+
+
+
+	
+
+
+		//})
+
+//	});
+
+    </script>
+
+
+  </head>
+  <body>
+<div id='pt_status'></div>
+<div id="chart_div" style="width: 400px; height: 120px;"></div>
+<div id="chartTheta_div" style="width: 400px; height: 120px;"></div>
+
+    <div id="barchart_material" style="width: 900px; height: 500px;"></div>
+    <div id='chartTbl_div' style='width: 900px; height: 500px;'></div>
+    <div id="portTbl">
+        <input type="button" id="b_reload" value="Reload" />
+    </div>
+    <div id='portTblDiv' style='width: 900px; height: 500px;'></div>
+<div id='temp'></div>
+
+  </body>
+</html>
+

+ 187 - 0
html/opt-pos-chart-tmpl-with-tabs.html

@@ -0,0 +1,187 @@
+<html>
+  <head>
+  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
+<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
+<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
+
+    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
+    <script type="text/javascript">
+      google.load("visualization", "1.1", {packages:["bar", 'table','gauge']});
+//      google.load('visualization', '1', {'packages':['table']});
+//      google.load("visualization", "1.1", {packages:["corechart"]});
+      google.setOnLoadCallback(drawChart);
+      function drawChart() {
+        var data = google.visualization.arrayToDataTable([
+          ['Strike Price', 'P', 'C', ],
+{{{dataPCpos}}}
+        ]);
+
+	var dataTbl = google.visualization.arrayToDataTable([
+{{{dataTablePos}}}
+
+        ]);
+
+
+        var options = {
+          width: 900,
+          chart: {
+            title: 'Option Postion Distribution. PUT:CALL Ratio [{{{PRvsCR}}}}]',
+            subtitle: 'for the month of {{{option_months}}}',
+          },
+ 
+        };
+
+        var chart = new google.charts.Bar(document.getElementById('barchart_material'));
+        chart.draw(data, options);
+
+
+
+
+	// chart table display implied volatilities in a nicely formatted table	
+       var chartTbl = new google.visualization.Table(document.getElementById('chartTbl_div'));
+
+
+       //var portTbl = new google.visualization.Table(document.getElementById('portTblDiv'));
+
+	var formatter = new google.visualization.NumberFormat({pattern:'0.00'});
+	for (var i = 2; i < 9; i++)
+		formatter.format(dataTbl, i); 
+        var options2 = {
+          displayAnnotations: true,
+	  showRowNumber: true, width: '100%', height: '100%', allowHtml: true,
+        };
+	chartTbl.draw(dataTbl, options2);
+
+	$('input[id="b_reload"]').click();
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// guage functions
+
+		var dataG = google.visualization.arrayToDataTable([
+		  ['Label', 'Value'],
+		  ['Delta', 0],
+		  ['Delta-C', 0],
+		  ['Delta-P', 0]
+		]);
+
+		var optionsG = {
+
+		  width: 400, height: 120,
+		  redFrom: -50, redTo: -25,
+		  yellowFrom:-24, yellowTo: -15,
+		  greenFrom: -10, greenTo: 10,	
+		  minorTicks: 5,
+		  min: -50, max: 50
+		};
+
+		var dataT = google.visualization.arrayToDataTable([
+		  ['Label', 'Value'],
+		  ['Theta', 0],
+		  ['Theta-C', 0],
+		  ['Theta-P', 0]
+		]);
+
+		var optionsT = {
+
+		  width: 400, height: 120,
+		  redFrom: -3000, redTo: -2000,
+		  yellowFrom:-1999, yellowTo: 500,
+		  greenFrom: 5000, greenTo: 15000,	
+		  minorTicks: 5,
+		  min: -3000, max: 15000
+		};
+
+		var gchart = new google.visualization.Gauge(document.getElementById('chart_div'));
+//		refreshPortSummary();
+//		gchart.draw(dataG, optionsG);
+
+		var tchart = new google.visualization.Gauge(document.getElementById('chartTheta_div'));
+		refreshPortSummary();
+		
+		function refreshPortSummary(){
+		    $.ajax({
+			type: 'Post',
+			url: '/ws_port_summary',
+			success: function (data) {
+				//alert(data);
+				var jdata = JSON.parse(data);
+				$('#temp').text(data);				
+				//alert(jdata.delta_all);
+				
+				dataG.setValue(0, 1, Math.round(jdata.delta_all*100)/100);
+				dataG.setValue(1, 1, Math.round(jdata.delta_c*100)/100);
+				dataG.setValue(2, 1, Math.round(jdata.delta_p*100)/100);
+				gchart.draw(dataG, optionsG);
+
+				dataT.setValue(0, 1, Math.round(jdata.theta_all));
+				dataT.setValue(1, 1, Math.round(jdata.theta_c));
+				dataT.setValue(2, 1, Math.round(jdata.theta_p));
+				tchart.draw(dataT, optionsT);
+
+				$('#pt_status').text("Unreal P/L: " + Math.round(jdata.unreal_pl*100)/100 + "   Cal Status: " + jdata.status);
+
+			}
+		    });
+
+		};
+
+		setInterval(function() {
+			refreshPortSummary();
+		}, 9500);    
+
+
+
+
+
+
+
+
+      } // end drawChart
+
+
+
+
+
+
+
+	
+
+
+		//})
+
+//	});
+
+    </script>
+    <script>
+	$(function() {
+		$( "#tabs" ).tabs();
+	});
+    </script>
+
+  </head>
+  <body>
+<div id="tabs">
+  <ul>
+    <li><a href="#tabs-1">Dashboard</a></li>
+    <li><a href="#tabs-2">Position Distribution</a></li>
+    <li><a href="#tabs-3">Risk Distribution</a></li>
+  </ul>
+  <div id="tabs-1">
+	<div id='pt_status'></div>
+	<div id="chart_div" style="width: 400px; height: 120px;"></div>
+	<div id="chartTheta_div" style="width: 400px; height: 120px;"></div>
+  </div>
+  <div id="tabs-2">
+    <div id="barchart_material" style="width: 900px; height: 500px;"></div>
+    
+  </div>
+  <div id="tabs-3">
+<div id='chartTbl_div' style='width: 900px; height: 500px;'></div>
+  </div>
+</div>
+
+  </body>
+</html>
+

+ 32 - 16
html/opt-pos-chart-tmpl.html~

@@ -1,12 +1,15 @@
 <html>
   <head>
   <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
+<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
+<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
+
     <script type="text/javascript" src="https://www.google.com/jsapi"></script>
     <script type="text/javascript">
       google.load("visualization", "1.1", {packages:["bar", 'table','gauge']});
 //      google.load('visualization', '1', {'packages':['table']});
 //      google.load("visualization", "1.1", {packages:["corechart"]});
-      google.setOnLoadCallback(drawChart);
+//      google.setOnLoadCallback(drawChart);
       function drawChart() {
         var data = google.visualization.arrayToDataTable([
           ['Strike Price', 'P', 'C', ],
@@ -64,8 +67,7 @@
 		]);
 
 		var optionsG = {
-		  chart:{
-			  title: 'Portfolio Delta Value'}, 
+
 		  width: 400, height: 120,
 		  redFrom: -50, redTo: -25,
 		  yellowFrom:-24, yellowTo: -15,
@@ -82,8 +84,7 @@
 		]);
 
 		var optionsT = {
-		  chart:{
-		  	title: 'Portfolio Theta Value'},
+
 		  width: 400, height: 120,
 		  redFrom: -3000, redTo: -2000,
 		  yellowFrom:-1999, yellowTo: 500,
@@ -153,21 +154,36 @@
 //	});
 
     </script>
-
+    <script>
+	$(document).ready(function(){
+	        google.setOnLoadCallback(drawChart);
+		$(function() {
+			$( "#tabs" ).tabs();
+		});
+	});
+    </script>
 
   </head>
   <body>
-<div id='pt_status'></div>
-<div id="chart_div" style="width: 400px; height: 120px;"></div>
-<div id="chartTheta_div" style="width: 400px; height: 120px;"></div>
-
+<div id="tabs">
+  <ul>
+    <li><a href="#tabs-1">Dashboard</a></li>
+    <li><a href="#tabs-2">Position Distribution</a></li>
+    <li><a href="#tabs-3">Risk Distribution</a></li>
+  </ul>
+  <div id="tabs-1">
+	<div id='pt_status'></div>
+	<div id="chart_div" style="width: 400px; height: 120px;"></div>
+	<div id="chartTheta_div" style="width: 400px; height: 120px;"></div>
+  </div>
+  <div id="tabs-2">
     <div id="barchart_material" style="width: 900px; height: 500px;"></div>
-    <div id='chartTbl_div' style='width: 900px; height: 500px;'></div>
-    <div id="portTbl">
-        <input type="button" id="b_reload" value="Reload" />
-    </div>
-    <div id='portTblDiv' style='width: 900px; height: 500px;'></div>
-<div id='temp'></div>
+    
+  </div>
+  <div id="tabs-3">
+<div id='chartTbl_div' style='width: 900px; height: 500px;'></div>
+  </div>
+</div>
 
   </body>
 </html>

二進制
html/public/green_marker.png


二進制
html/public/marker.png


部分文件因文件數量過多而無法顯示