Improved code by making more oo

add functionality and ingo in order frm.
This commit is contained in:
Joe Tretter
2020-04-29 22:56:37 -05:00
parent bd726a01c7
commit 06d86f8c30
7 changed files with 287 additions and 187 deletions

1
.gitignore vendored
View File

@@ -108,3 +108,4 @@ dist
# Stores VSCode versions used for testing VSCode extensions # Stores VSCode versions used for testing VSCode extensions
.vscode-test .vscode-test
server/quoteDBs/consolidated.sqlite3 server/quoteDBs/consolidated.sqlite3
server/quoteDBs/processedDBs

View File

@@ -92,6 +92,40 @@ body {
z-index:1; z-index:1;
} }
#lbCostAmount {
position: absolute;
top:0;
left:100;
font-weight: bolder;
text-align: right;
color:crimson;
width: 180px;
}
#frmOrder ul li {
border-top:1px solid blue;
}
#frmOrder div.orderItemLine2 {
text-align: right;
}
#frmOrder ul li .totalCost {
font-weight: bolder;
color: blue;
}
#frmOrder span.quantity {
font-weight: bolder;
color: blue;
}
#frmOrder span.openType {
font-weight: bolder;
color: blue;
}
#frmOrder span.singlePrice {
color: blue;
}
#datePicker { #datePicker {
background-color:#ccff00; background-color:#ccff00;
position:fixed; position:fixed;
@@ -123,6 +157,13 @@ body {
color:#0000FF; color:#0000FF;
cursor: no-drop; cursor: no-drop;
} }
.plusMinus {
background-color: blue;
color:#ccff00;
cursor: pointer;
padding-bottom: 2px;
margin-left: 1px;
}
.priceClick { .priceClick {
cursor: copy; cursor: copy;

View File

@@ -11,8 +11,9 @@
<!-- app-css --> <!-- app-css -->
<link rel="stylesheet" href="css/optiTrainer.css"> <link rel="stylesheet" href="css/optiTrainer.css">
<script src='js/optiTrainer.js'></script> <script src='js/orderFrame.js'></script>
<script src='js/masterFilter.js'></script> <script src='js/masterFilter.js'></script>
<script src='js/optiTrainer.js'></script>
<title>OptionTrainer</title> <title>OptionTrainer</title>
</head> </head>

View File

@@ -1,12 +1,10 @@
var filterContext={};
let createMasterFilterFrame=()=>{ let createMasterFilterFrame=()=>{
let theFrameDiv=document.createElement("div"); let me=window.myMasterFilter = document.createElement("div");
theFrameDiv.setAttribute("id","frmMasterFilter"); me.setAttribute("id","frmMasterFilter");
theFrameDiv.className="container-fluid " me.className="container-fluid "
window.document.getElementById('app').append(theFrameDiv); window.document.getElementById('app').append(me);
theFrameDiv.innerHTML=` me.innerHTML=`
<div id='datePicker'></div> <div id='datePicker'></div>
<div class="dropdown" id="grpSymbol"> <div class="dropdown" id="grpSymbol">
@@ -36,18 +34,21 @@ let createMasterFilterFrame=()=>{
<!--button onclick='rq()'>LOAD</button--> <!--button onclick='rq()'>LOAD</button-->
`; `;
fetchSymbols(); let _filterContext={}; // TODO: This is bad, grown design - should be replaced with a proper object oriented structure and observer pattern.
Object.defineProperty(me,"selectedDate",{
get:_=>{ return (_filterContext.theDate);}
})
Object.defineProperty(me,"selectedTime",{
get:_=>{ return (_filterContext.selectedTime);}
})
return true; me.beforeShowDay=(theDate)=>{
}
let beforeShowDay=(theDate)=>{
let isoDate=theDate.toISOString().substr(0,10); let isoDate=theDate.toISOString().substr(0,10);
//console.log("BeforeShow",isoDate,theDate); //console.log("BeforeShow",isoDate,theDate);
let isDateFound=false; let isDateFound=false;
for (let i=0;i<filterContext.availableDates.length;i++){ for (let i=0;i<_filterContext.availableDates.length;i++){
if (filterContext.availableDates[i].Date===theDate.toISOString().substr(0,10)){ if (_filterContext.availableDates[i].Date===theDate.toISOString().substr(0,10)){
isDateFound=true; isDateFound=true;
break; break;
}; };
@@ -56,77 +57,77 @@ let beforeShowDay=(theDate)=>{
if (!isDateFound) { if (!isDateFound) {
return {enabled:false, tooltip:"No data"}; return {enabled:false, tooltip:"No data"};
} }
} }
let fetchSymbols=()=>{ me.fetchSymbols=()=>{
$.get({ $.get({
url:"/getSymbols" url:"/getSymbols"
}).done(response=>{ }).done(response=>{
let allSymbols=response; let allSymbols=response;
console.log(allSymbols); console.log(allSymbols);
refreshSymbolList(allSymbols); me.refreshSymbolList(allSymbols);
}); });
} }
let getCurrentSymbol=()=>{ me.getCurrentSymbol=()=>{
return(filterContext.theSymbol); return(_filterContext.theSymbol);
} }
let symbolChanged=(newSymbol)=>{ me.symbolChanged=(newSymbol)=>{
console.log("symbolChanged",newSymbol); console.log("symbolChanged",newSymbol);
filterContext.theSymbol=newSymbol _filterContext.theSymbol=newSymbol
document.title=getCurrentSymbol(); document.title=me.getCurrentSymbol();
$("#tbSymbol").text(getCurrentSymbol()); $("#tbSymbol").text(me.getCurrentSymbol());
getAvailDatesForSymbol(getCurrentSymbol()).done(_=>{ me.getAvailDatesForSymbol(me.getCurrentSymbol()).done(_=>{
$("#datePicker").datepicker('destroy'); $("#datePicker").datepicker('destroy');
$("#datePicker").datepicker({beforeShowDay:beforeShowDay}); $("#datePicker").datepicker({beforeShowDay:me.beforeShowDay});
if (document.getElementById("datePicker").hasHandler !== true) { // work around multiple binding of the eventhandler - it seems that destroy doesn't remove the old handler.... if (document.getElementById("datePicker").hasHandler !== true) { // work around multiple binding of the eventhandler - it seems that destroy doesn't remove the old handler....
$("#datePicker").datepicker().on('changeDate', (e)=>{ $("#datePicker").datepicker().on('changeDate', (e)=>{
if (e.date !== undefined) { if (e.date !== undefined) {
console.log("DatePicker changed date",e.date); console.log("DatePicker changed date",e.date);
filterContext.theDate=e.date.toISOString().substr(0,10); _filterContext.theDate=e.date.toISOString().substr(0,10);
showTimesForDay(filterContext.theDate); me.showTimesForDay(_filterContext.theDate);
} }
}); });
document.getElementById("datePicker").hasHandler= true; document.getElementById("datePicker").hasHandler= true;
} }
if (filterContext.theDate === undefined) { if (_filterContext.theDate === undefined) {
console.log("no date in contest, setting date to the last in chain."); console.log("no date in contest, setting date to the last in chain.");
filterContext.theDate=filterContext.availableDates[filterContext.availableDates.length-1].Date; _filterContext.theDate=_filterContext.availableDates[_filterContext.availableDates.length-1].Date;
} }
currentTZDate = new Date(Date.parse(filterContext.theDate) + new Date().getTimezoneOffset()*60000); currentTZDate = new Date(Date.parse(_filterContext.theDate) + new Date().getTimezoneOffset()*60000);
console.log("setting datepicker date to ", filterContext.theDate, currentTZDate); console.log("setting datepicker date to ", _filterContext.theDate, currentTZDate);
$("#datePicker").datepicker('setDate',currentTZDate); $("#datePicker").datepicker('setDate',currentTZDate);
}); });
} }
let timeChanged=(newTime)=>{ me.timeChanged=(newTime)=>{
if (filterContext.selectedTime!==newTime){ if (_filterContext.selectedTime!==newTime){
filterContext.selectedTime=newTime; _filterContext.selectedTime=newTime;
$("#tbSelectedTime").text(newTime); $("#tbSelectedTime").text(newTime);
console.log("Time changed", newTime); console.log("Time changed", newTime);
} }
requestOptionChain(); me.requestOptionChain();
} }
let requestOptionChain=()=>{ me.requestOptionChain=()=>{
$.ajax({ $.ajax({
url:"/getOptionChain?Date=" + filterContext.theDate + "&Symbol=" + filterContext.theSymbol + "&Time="+filterContext.selectedTime url:"/getOptionChain?Date=" + _filterContext.theDate + "&Symbol=" + _filterContext.theSymbol + "&Time="+ _filterContext.selectedTime
}).done(response=>{ }).done(response=>{
dta=JSON.parse(response[0].Data); dta=JSON.parse(response[0].Data);
//console.log("received",dta); //console.log("received",dta);
displayOptionChain(); displayOptionChain();
$("#tbUnderlyingPrice").text(dta.underlyingPrice.toLocaleString('en',{minimumFractionDigits: 2, maximumFractionDigits: 2})); $("#tbUnderlyingPrice").text(dta.underlyingPrice.toLocaleString('en',{minimumFractionDigits: 2, maximumFractionDigits: 2}));
}); });
} }
let showTimesForDay=()=>{ me.showTimesForDay=()=>{
return $.ajax({ return $.ajax({
url:"/getTimes?Date=" + filterContext.theDate + "&Symbol=" + filterContext.theSymbol url:"/getTimes?Date=" + _filterContext.theDate + "&Symbol=" + _filterContext.theSymbol
}).done(response=>{ }).done(response=>{
let availableTimes=response; let availableTimes=response;
//console.log(availableTimes); //console.log(availableTimes);
@@ -135,41 +136,46 @@ let showTimesForDay=()=>{
allTimes = availableTimes; allTimes = availableTimes;
for (let i=0;i<allTimes.length;i++){ for (let i=0;i<allTimes.length;i++){
theTime=allTimes[i].Time; theTime=allTimes[i].Time;
if (filterContext.selectedTime !== undefined) { if (_filterContext.selectedTime !== undefined) {
if (filterContext.selectedTime.substring(0,4) === theTime.substring(0,4)){ if (_filterContext.selectedTime.substring(0,4) === theTime.substring(0,4)){
timeChanged(theTime); me.timeChanged(theTime);
} }
} else { } else {
if (i==4) { if (i==4) {
// select the 4th time in the day... that's usually around 9:30 // select the 4th time in the day... that's usually around 9:30
timeChanged(theTime); me.timeChanged(theTime);
} }
} }
//lbTime.append($(`<option ${selectedFlag}>${theTime}</option>`)) //lbTime.append($(`<option ${selectedFlag}>${theTime}</option>`))
lbTime.append($(`<button onclick="timeChanged('${theTime}');" class="dropdown-item" type="button">${theTime.substring(0,5)}</button>`)) lbTime.append($(`<button onclick="myMasterFilter.timeChanged('${theTime}');" class="dropdown-item" type="button">${theTime.substring(0,5)}</button>`))
} }
$("#lbTime").change(); $("#lbTime").change();
}); });
} }
let getAvailDatesForSymbol=(theSymbol)=>{ me.getAvailDatesForSymbol=(theSymbol)=>{
return $.ajax({ return $.ajax({
url:"/getDates?Symbol=" + theSymbol url:"/getDates?Symbol=" + theSymbol
}).done(response=>{ }).done(response=>{
let availableDates=response; let availableDates=response;
//console.log(availableDates); //console.log(availableDates);
filterContext.availableDates=availableDates; _filterContext.availableDates=availableDates;
}); });
} }
let refreshSymbolList=(allSymbols)=>{ me.refreshSymbolList=(allSymbols)=>{
let lbSymbol=$("#lbSymbol"); let lbSymbol=$("#lbSymbol");
lbSymbol.empty(); lbSymbol.empty();
for (let i=0;i<allSymbols.length;i++){ for (let i=0;i<allSymbols.length;i++){
theSymbol=allSymbols[i].Symbol; theSymbol=allSymbols[i].Symbol;
console.log(theSymbol); console.log(theSymbol);
lbSymbol.append($(`<button onclick="symbolChanged('${theSymbol}');" class="dropdown-item" type="button">${theSymbol}</button>`)) lbSymbol.append($(`<button onclick="myMasterFilter.symbolChanged('${theSymbol}');" class="dropdown-item" type="button">${theSymbol}</button>`))
} }
}
me.fetchSymbols();
return true;
} }

View File

@@ -1,4 +1,3 @@
var costAmount=0;
var allCombinations; var allCombinations;
var optionChainContext={}; var optionChainContext={};
@@ -12,50 +11,6 @@ $(document).ready(_=>{
$("#datePicker").datepicker({beforeShowDay:selectDataFirst}); $("#datePicker").datepicker({beforeShowDay:selectDataFirst});
}); });
let createOrderFrame=()=>{
let theFrameDiv=document.createElement("div");
theFrameDiv.setAttribute("id","frmOrder");
theFrameDiv.className="container-fluid ";
window.document.getElementById('app').append(theFrameDiv);
theFrameDiv.innerHTML=`
<button onclick="clearOrder()" type="button" class="btn btn-danger">Clear All</button>
<br>
<span id='lbCost' class="bold">Gain $</span><span id='lbCostAmount'>0</span>
<ul id='listOrderItems'>
</ul>
`;
}
let clearOrder=()=>{
costAmount=0;
$("#listOrderItems").empty();
showCostAmount();
}
let addToOrder=(openType,optionData)=>{
optionData=JSON.parse(optionData.replace(/'/g,'"'));
console.log("AddToOrder",openType,optionData);
let price=(openType.substr(0,1)==="b")?optionData.ask:optionData.bid;
price=price*100;
let priceEffect=price * ((openType.substr(0,1)==="b")?-1:1);
costAmount+=priceEffect;
showCostAmount();
$("#listOrderItems").append(`<li><a class='danger' onclick='removeFromOrder(this,${priceEffect});'>[X]</a> ${openType} | ${optionData.symbol} | ${price.toLocaleString('en',{minimumFractionDigits: 2, maximumFractionDigits: 2})}</li>`);
}
let removeFromOrder=(ele,priceEffect)=>{
costAmount-=priceEffect;
let li=ele.parentElement;
li.parentElement.removeChild(li);
showCostAmount();
}
let showCostAmount=_=>{
$("#lbCostAmount").text(costAmount.toLocaleString('en',{minimumFractionDigits: 2, maximumFractionDigits: 2}));
}
let dta={}; let dta={};
@@ -90,8 +45,8 @@ let getCallArtifact=(callData,allColumns)=>{
classes += " priceClick"; classes += " priceClick";
artifact+=` artifact+=`
<td class="${classes} ralign" onclick="addToOrder('sell','${strCallJSON}')"><a title="Sell">${bidFrm}</a></td> <td class="${classes} ralign" onclick="myOrderFrame.addToOrder('sell','${strCallJSON}')"><a title="Sell">${bidFrm}</a></td>
<td class="${classes} ralign" onclick="addToOrder('buy','${strCallJSON}')"><a title="Buy">${askFrm}</a></td> <td class="${classes} ralign" onclick="myOrderFrame.addToOrder('buy','${strCallJSON}')"><a title="Buy">${askFrm}</a></td>
`; `;
return artifact; return artifact;
} }
@@ -116,8 +71,8 @@ let getPutArtifact=(putData,allColumns)=>{
classes += " priceClick"; classes += " priceClick";
artifact+=` artifact+=`
<td class="${classes} ralign" onclick="addToOrder('sell','${strPutJSON}')"><a title="Sell">${bidFrm}</a></td> <td class="${classes} ralign" onclick="myOrderFrame.addToOrder('sell','${strPutJSON}')"><a title="Sell">${bidFrm}</a></td>
<td class="${classes} ralign" onclick="addToOrder('buy','${strPutJSON}')"><a title="Buy">${askFrm}</a></td> <td class="${classes} ralign" onclick="myOrderFrame.addToOrder('buy','${strPutJSON}')"><a title="Buy">${askFrm}</a></td>
`; `;
return artifact; return artifact;
} }

95
client/js/orderFrame.js Normal file
View File

@@ -0,0 +1,95 @@
let createOrderFrame=()=>{
let me = window.myOrderFrame = document.createElement("div");
me.setAttribute("id","frmOrder");
me.className="container-fluid ";
me.innerHTML=`
<button onclick='myOrderFrame.clearOrder()' type="button" class="btn btn-danger">Clear All</button>
<br>
<div id='lbCostAmount'>0</div>
<ul id='listOrderItems'>
</ul>
`;
$('#app').append(me);
me.addToOrder=(openType,optionData)=>{
optionData=JSON.parse(optionData.replace(/'/g,'"'));
console.log("AddToOrder",openType,optionData);
let me=document.createElement("li");
me.multiplier = 100; // assume always 100 multipier
me.price = (openType.substr(0,1)==="b")?optionData.ask:optionData.bid;
me.priceEffect = ((openType.substr(0,1)==="b")?-1:1);
me.quantity = 1; // at this point, we add 1 by default.
me.updateNumbers=()=>{
let prevTotalCostAmount=me.totalCostAmount;
me.singleCostAmount = me.priceEffect * me.multiplier * me.price
me.totalCostAmount = me.singleCostAmount * me.quantity;
if ((prevTotalCostAmount !== undefined) && (prevTotalCostAmount !== me.totalCostAmount)) {
myOrderFrame.costAmount += (me.totalCostAmount - prevTotalCostAmount);
}
if (me.getElementsByClassName("quantity")[0] !== undefined) {
me.getElementsByClassName("quantity")[0].innerText = me.quantity;
me.getElementsByClassName("totalCost")[0].innerText = me.totalCostAmount.toLocaleString('en',{minimumFractionDigits: 0, maximumFractionDigits: 2});
}
};
me.updateNumbers();
me.increaseQty=_=>{
me.quantity += 1;
me.updateNumbers();
}
me.decreaseQty=_=>{
if (me.quantity>1) { // don't go below 0, if we did, we had to chnage the order type to use the correct (bid/ask) price.
me.quantity -= 1;
me.updateNumbers();
}
}
me.removeFromOrder=_=>{
me.quantity=0;
me.updateNumbers();
me.parentElement.removeChild(me);
}
me.innerHTML=`
<a class='danger' onclick='this.parentElement.removeFromOrder();'>[X]</a> ${myMasterFilter.selectedDate}|${myMasterFilter.selectedTime.substr(0,5)}|<span class="opentype">${openType}</span>@<span class="singlePrice">${Math.abs(me.singleCostAmount).toLocaleString('en',{minimumFractionDigits: 0, maximumFractionDigits: 2})}</span>|<span class='quantity'>${me.quantity}</span> <a class='plusMinus' onclick='this.parentElement.increaseQty();'>[+]</a><a class='plusMinus' onclick='this.parentElement.decreaseQty();'>[-]</a>
<div class='orderItemLine2'>
${optionData.symbol} =&gt; <span class='totalCost'>${me.totalCostAmount.toLocaleString('en',{minimumFractionDigits: 0, maximumFractionDigits: 2})}</span>
</div>
`;
$("#listOrderItems").append(me);
// adjust the cumulation on the order frame
myOrderFrame.costAmount+=me.totalCostAmount;
}
me.clearOrder = ()=>{
me.costAmount=0;
$("#listOrderItems").empty();
}
me.showCostAmount=_=>{
$("#lbCostAmount").text(me.costAmount.toLocaleString('en',{minimumFractionDigits: 0, maximumFractionDigits: 2}));
}
let _costAmount={};
Object.defineProperty(me,'costAmount',{
get:_=>{return(_costAmount);},
set: (newVal)=>{
console.log("changed cost", newVal);
_costAmount=newVal;
me.showCostAmount();
}
});
// InitializeCostAmount
me.costAmount=0;
}

1
server/start-win.bat Normal file
View File

@@ -0,0 +1 @@
node node_modules\micro-core\bin\micro-serve index.js