| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453 |
- <html>
- <head>
- <title>Simple client</title>
-
- <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>
- </head>
- <style>
- ul#menu li {
- display:inline;
- }
- table.minimalistBlack {
- border: 1px solid #000000;
- width: 100%;
- text-align: left;
- border-collapse: collapse;
- }
- table.minimalistBlack td, table.minimalistBlack th {
- border: 1px solid #000000;
- padding: 5px 4px;
- }
- table.minimalistBlack tbody td {
- font-size: 12px;
- }
- table.minimalistBlack thead {
- background: #CFCFCF;
- background: -moz-linear-gradient(top, #dbdbdb 0%, #d3d3d3 66%, #CFCFCF 100%);
- background: -webkit-linear-gradient(top, #dbdbdb 0%, #d3d3d3 66%, #CFCFCF 100%);
- background: linear-gradient(to bottom, #dbdbdb 0%, #d3d3d3 66%, #CFCFCF 100%);
- border-bottom: 3px solid #000000;
- }
- table.minimalistBlack thead th {
- font-size: 12px;
- font-weight: bold;
- color: #000000;
- text-align: left;
- }
- table.minimalistBlack tfoot {
- font-size: 13px;
- font-weight: bold;
- color: #000000;
- border-top: 3px solid #000000;
- }
- table.minimalistBlack tfoot td {
- font-size: 13px;
- }
- .container{
- max-width: 20px;
- margin: o auto;
- padding: 5px;
- }
- .bg-led{
- padding: 5px 8px;
- max-width: 20px;
- margin: o auto;
-
- background-color:green;
- }
- .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: 375px; /* chartArea top */
- left: 350px; /* chartArea left */
- color: #000066;
- font: 15px arial;
-
- }
- </style>
- <body>
- <ul id="menu">
- <li><input type="radio" name='acct' id="acct" value="U9050568" checked="checked"> U9050568</li>
- <li><input type="radio" name='acct' id="acct" value="U8080985"> U8080985</li>
- <li><button id="reload_port">Reload Portfolio</button></li>
- <li><button id="port-btn">Update summary information</button></li>
- <li class="bg-led indicator"></li>
- </ul>
-
-
- <table id='port_sum' class="minimalistBlack">
- <thead>
- <tr>
- <th>Total Delta/Theta</th>
- <th>Futures Delta/Theta</th>
- <th>Call Delta/Theta</th>
- <th>Put Delta/Theta</th>
- <th>Calls/Puts</th>
- <th>PL / Potential Gain<div class="container"></th>
- <th>HSIF Curr / Next Mth</th>
- <th>change %</th>
- </tr>
- </thead>
-
- <tbody>
- <tr>
- <td>(nan)</td><td>(nan)</td><td>(nan)</td><td>(nan)</td><td>(nan)</td><td>(nan)</td><td>(nan)</td><td>(nan)</td></tr>
- <tr>
- <td>(nan)</td><td>(nan)</td><td>(nan)</td><td>(nan)</td><td>(nan)</td><td>(nan)</td><td>(nan)</td><td>(nan)</td></tr>
- <tr>
- </tbody>
- </tr>
- </table>
-
- <div id="chart_div"></div>
- <div id="table_div" style="height:400"></div>
- <div class="overlay-marker">
- <img src="public/green_marker.png" height="50"><div id='spot'></div>
- </div>
- <button id="change-btn">change columns</button>
-
- <form onsubmit="onSubmit(); return false;">
- <input type="text" id="input">
- <input type="submit" value="Send">
- <button onclick="onCloseClick(); return false;">close</button>
- </form>
- <div id="log"></div>
- <script>
-
-
- var account;
-
- $(document).ready(function () {
-
- // retrieve the last saved preference
- var account = localStorage.getItem('account');
- console.log('retrieving the account code from storage => ' + (account == null ? '<not found>' : account));
- if (account == null){
- account = $('input[id=acct]:checked').val();
-
-
- }
- qs = "input[id=acct][value='" + account + "']"
- document.querySelectorAll(qs)[0].checked=true;
-
- // test: setCellValue('port_sum', 1, 2, 'x6yz');
-
- });
-
-
- $('#port-btn').click(function(){
- account = $('input[id=acct]:checked').val()
- ws.send(JSON.stringify({event: 'event_request_port_summary', target_resource:{}, 'account': account}));
- });
- $('#reload_port').click(function(){
- alert('Reloading portfolio...');
-
- // save the account number that was selected
- // so that it could be retrieved when the page
- // is reloaded later
- localStorage.setItem('account', $('input[id=acct]:checked').val());
- if (ws != null){
- ws.close();
- location.reload();
- }
- });
- var chartOptions = {
- width: 800,
- height: 400,
- legend: { position: 'right', maxLines: 3 },
- bar: { groupWidth: '85%' },
- isStacked: true,allowHtml: true,
- /*series: {
- 0:{color:'lightgreen'},
- 1:{color:'black'},
- 2:{color:'#1E90FF',},
- }*/
- };
- var columnChart = {'view': null, 'data': null, 'chart': null, 'options': chartOptions};
- var tableOptions = {allowHtml: true, sortColumn:1,
- showRowNumber: true, width: '95%', height: '100%'};
- var tableChart = {'view': null, 'data': null, 'chart': null, 'options': tableOptions};
-
-
-
- google.load("visualization", "1.1", {packages:["corechart", 'table','gauge']});
- //google.setOnLoadCallback(drawTable);
- google.setOnLoadCallback(init);
-
- function setCellValue(table, rowNum, colNum, newValue)
- {
- //$('#port_sum').find("tr:eq(1)").find("td:eq(1)").html('new stuff');
- $('#'+table).find('tr:eq('+rowNum+')').find('td:eq(' + colNum + ')').html(newValue);
-
- };
-
- function getCellValue(table, rowNum, colNum)
- {
- //$('#port_sum').find("tr:eq(1)").find("td:eq(1)").html('new stuff');
- return $('#'+table).find('tr:eq('+rowNum+')').find('td:eq(' + colNum + ')').html();
-
- };
-
- function getRandomInt(min, max) {
- return Math.floor(Math.random() * (max - min + 1)) + min;
- }
-
-
- function setupFormatter(tableData){
- var numF = new google.visualization.NumberFormat(
- {prefix: '$', pattern:'0.00', negativeColor: 'red', negativeParens: true});
- var percentF = new google.visualization.NumberFormat(
- {pattern: '##.#%'})
- var arrowF = new google.visualization.ArrowFormat();
- var barF = new google.visualization.BarFormat({width: 80,
- colorPositive: 'green', max:100 });
- var barIV = new google.visualization.BarFormat({width: 80,
- colorPositive: 'red', min: 0, max:0.5 });
-
- var colorF = new google.visualization.ColorFormat();
- colorF.addRange(-100, 0, 'white', 'red');
- colorF.addRange(0, 100, 'white', 'blue');
- var colorGF = new google.visualization.ColorFormat();
- colorGF.addGradientRange(null, null, 'white', 'orange', 'blue');
-
-
- numF.format(tableChart.data, 2); //avg cost
- numF.format(tableChart.data, 3); //market value
- numF.format(tableChart.data, 4); //avg px
- colorF.format(tableChart.data, 6); // position
- percentF.format(tableChart.data, 7); //delta
-
- numF.format(tableChart.data, 10); // position delta
- numF.format(tableChart.data, 11); // position theta
- numF.format(tableChart.data, 12); // position gamma
- colorGF.format(tableChart.data, 13); //unreal p/l
- barF.format(tableChart.data, 14) //% gain loss
- barIV.format(tableChart.data, 15); //iv
-
- }
-
- var ws;
- var ws_url = "ws://localhost:9001/";
- var tableChart;
-
- function init() {
-
- var account = $('input[id=acct]:checked').val();
-
- // Connect to Web Socket
- ws = new WebSocket(ws_url);
-
- // Set event handlers.
- ws.onopen = function() {
- var account = $('input[id=acct]:checked').val();
-
-
- output("onopen account = " + account );
-
- ws.send(JSON.stringify({event: 'event_tm_request_table_structure', target_resource:{'class': 'Portfolio'}, 'account': account}));
- ws.send(JSON.stringify({event: 'event_tm_request_table_structure', target_resource:{'class': 'PortfolioColumnChartTM'}, 'account': account}));
- ws.send(JSON.stringify({event: 'event_request_port_summary', target_resource:{}, 'account': account}));
- };
-
- ws.onmessage = function(e) {
- // e.data contains received string.
- // signal incoming by flashing a green box
- $('.indicator').fadeIn(50).fadeOut(50);
-
- try {
- d1= JSON.parse(e.data);
-
- }
- catch(err) {
- output("onmessage:json parse exception: value= " + e.data);
- console.log('error parsing e.data' + e.data);
- }
-
-
-
-
- // 2019.1 if the messageis not intended
- if (d1.event == 'event_tm_table_structure_changed' && d1.account != account)
- return;
- else if (d1.event == 'event_tm_table_row_updated' && d1['value']['source']['account'] != account)
- return;
-
-
- if (d1.event == "event_tm_table_structure_changed"){
-
- if (d1.source.class == 'Portfolio'){
- tableChart.data = new google.visualization.DataTable(d1.value);
- tableChart.view = new google.visualization.DataView(tableChart.data);
- tableChart.view.setRows(tableChart.view.getFilteredRows([{column: 16, test: function(value, row, column, table) {
- return (value == 'HSI' || value == 'MHI')
- }},
- {column: 6, test: function(value, row, column, table) {
- return (value != 0)
- }},
-
- ]));
- setupFormatter(tableChart.data);
- tableChart.chart = new google.visualization.Table(document.getElementById('table_div'));
- tableChart.chart.draw(tableChart.view, tableChart.options);
- output('number of rows: ' + tableChart.data.getNumberOfRows());
-
- } else if (d1.source.class == 'PortfolioColumnChartTM'){
- columnChart.data = new google.visualization.DataTable(d1.value);
- console.log('updating pcc for ' + d1.account);
- columnChart.view = new google.visualization.DataView(columnChart.data);
- columnChart.chart = new google.visualization.ColumnChart(
- document.getElementById('chart_div'));
- columnChart.chart.draw(columnChart.view, columnChart.options);
- google.visualization.events.addListener(columnChart.chart, 'ready', placeIndexMarker);
- }
-
- } else if (d1.event == 'event_tm_table_row_updated'){
-
- //console.log(d1.value.row.toString()+ ':' + d1.value.row_values[0]['v']);
- for (var c=2; c < d1.value.row_values.length; c++){
- tableChart.data.setCell(d1.value.row, c, d1.value.row_values[c]["v"]);
-
- }
- //data.setCell(d1.value.row, 1, d1.value.row_values[0]['v']);
-
- tableChart.options.sortColumn = tableChart.chart.getSortInfo().column;
- tableChart.chart.draw(tableChart.view, tableChart.options);
-
-
- } else if (d1.event == 'event_tm_table_row_inserted'){
- var newRow = d1.value.row_values.map(function(x){
- return x['v'];
- });
- output('adding new row: ' + newRow.toString());
- data.addRow(newRow);
- options.sortColumn = table.getSortInfo().column;
- table.draw(view, options);
-
- } else if (d1.event == 'event_port_values_updated' && d1.account == account){
- setPortSummaryTableVal(d1.value);
- } else if (d1.event == 'tickPrice'){
- if (d1.current_or_next == 'current'){
- setCellValue('port_sum', 1, 6, d1.price);
- if (d1.change)
- setCellValue('port_sum', 1, 7, d1.change.toFixed(2));
- }
- else{ // next month
- setCellValue('port_sum', 2, 6, d1.price);
- if (d1.change)
- setCellValue('port_sum', 2, 7, d1.change.toFixed(2));
- }
- if (columnChart){
- placeIndexMarker();
- }
-
- }
- };
-
- ws.onclose = function() {
- output("onclose");
- };
-
- ws.onerror = function(e) {
- output("onerror");
- console.log(e)
- };
- }
-
- function placeIndexMarker(){
- // get the current month futures spot px
- var spot = getCellValue('port_sum', 1, 6);
- var cli = columnChart.chart.getChartLayoutInterface();
- //top = cli.getChartAreaBoundingBox().top;
- //height = cli.getChartAreaBoundingBox().height;
- top = cli.getBoundingBox('chartarea').top;
- height = cli.getBoundingBox('chartarea').height;
-
- document.querySelector('.overlay-marker').style.top = Math.floor(top - height) + "px";
- document.querySelector('.overlay-marker').style.left = Math.floor(cli.getXLocation(spot) - 25) + "px";
- }
-
- function setPortSummaryTableVal(port_values){
- var val2cellDict = {
- 9000: [1,0],
- 9001: [1,1],
- 9002: [1,2],
- 9003: [1,3],
- 9031: [1,4],
- 9040: [1,5],
- 9010: [2,0],
- 9012: [2,2],
- 9013: [2,3],
- 9032: [2,4],
- 9041: [2,5]
- }
-
- for(var port_id in val2cellDict) {
- //console.log('in setPortSummaryTableVal ' + String(port_id) + ", ");
- var num = Number(port_values[port_id]);
- num = (isFloat(num)) ? num.toFixed(2) : num;
- setCellValue('port_sum', val2cellDict[port_id][0], val2cellDict[port_id][1], num);
- }
- }
-
- function isFloat(n){
- return Number(n) === n && n % 1 !== 0;
- }
- function onSubmit() {
- var input = document.getElementById("input");
- // You can send message to the Web Socket using ws.send.
- ws.send(input.value);
- output("send: " + input.value);
- input.value = "";
- input.focus();
- }
-
- function onCloseClick() {
-
- ws.close();
- }
-
- function output(str) {
- var log = document.getElementById("log");
- var escaped = str.replace(/&/, "&").replace(/</, "<").
- replace(/>/, ">").replace(/"/, """); // "
- log.innerHTML = escaped + "<br>" + log.innerHTML;
- }
-
- </script>
- </body>
- </html>
|