topsecrettraders commited on
Commit
94363dd
·
verified ·
1 Parent(s): 1947cab

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +52 -46
app.py CHANGED
@@ -941,9 +941,8 @@ HTML_TEMPLATE = """
941
  function validateSnapshot(data) {
942
  // 1. Identify Reference Price (Spot or Future)
943
  let refPrice = 0;
944
- let hasOptions = false;
945
 
946
- // Loop to find Reference and check if data exists
947
  for(let sym in data) {
948
  // Check for Spot or Index (Priority)
949
  if(sym.includes('INDEX') || sym.endsWith('-EQ') || sym.startsWith('BSE:SENSEX')) {
@@ -953,60 +952,67 @@ HTML_TEMPLATE = """
953
  else if(sym.endsWith('FUT') && refPrice === 0) {
954
  if(data[sym].ltp > 0) refPrice = data[sym].ltp;
955
  }
956
- // Check if options exist in this packet
957
- if(sym.endsWith('CE') || sym.endsWith('PE')) hasOptions = true;
958
  }
959
 
960
  // CRITERIA 1: Missing Reference Price (Corrupted)
961
  if(refPrice === 0) return false;
962
 
963
- // CRITERIA 2: Validate ATM ± Range Data (Zero Qty Check)
964
- if(hasOptions) {
965
- // Extract valid strikes from symbol keys
966
- let strikes = [];
967
- for(let sym in data) {
968
- // Regex matches Fyers symbols ending in Number+CE/PE (e.g., ...22100CE)
969
- let match = sym.match(/(\d+)(CE|PE)$/);
970
- if(match && match[1]) {
971
- strikes.push({
972
- k: parseFloat(match[1]),
973
- d: data[sym]
974
- });
975
- }
976
- }
977
 
978
- if(strikes.length > 0) {
979
- // Find ATM Strike based on Ref Price
980
- strikes.sort((a,b) => a.k - b.k);
981
- let closest = strikes.reduce((prev, curr) =>
982
- Math.abs(curr.k - refPrice) < Math.abs(prev.k - refPrice) ? curr : prev
983
- );
 
984
 
985
- // Get unique strikes to determine index range
986
- let uniqKs = [...new Set(strikes.map(i => i.k))].sort((a,b)=>a-b);
987
- let atmIndex = uniqKs.indexOf(closest.k);
988
 
989
- // Define Range: ATM ± 5 strikes
990
- let start = Math.max(0, atmIndex - 5);
991
- let end = Math.min(uniqKs.length - 1, atmIndex + 5);
992
- let targetKs = uniqKs.slice(start, end + 1);
993
-
994
- // Check specific options in this range
995
- for(let item of strikes) {
996
- if(targetKs.includes(item.k)) {
997
- let qB = item.d.totalbuyqty;
998
- let qS = item.d.totalsellqty;
999
-
1000
- // THE CHECK: If both Buy AND Sell Qty are 0 or undefined -> Data is inefficient
1001
- if((!qB && !qS) || (qB === 0 && qS === 0)) {
1002
- return false; // Mark as Bad
1003
- }
1004
- }
1005
- }
1006
  }
1007
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
1008
 
1009
- return true; // Data passed checks
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1010
  }
1011
 
1012
  function renderSecondBar() {
@@ -1020,7 +1026,7 @@ HTML_TEMPLATE = """
1020
  <div class="sec-pill ${idx===0?'active':''} ${statusClass}"
1021
  onclick="selectSnapshot(${idx})"
1022
  id="pill-${idx}"
1023
- title="${isValid ? 'Data OK' : 'Data Inefficient (Zero Qty or Missing Ref)'}">
1024
  :${item.s}
1025
  </div>
1026
  `}).join('');
 
941
  function validateSnapshot(data) {
942
  // 1. Identify Reference Price (Spot or Future)
943
  let refPrice = 0;
 
944
 
945
+ // Loop to find Reference
946
  for(let sym in data) {
947
  // Check for Spot or Index (Priority)
948
  if(sym.includes('INDEX') || sym.endsWith('-EQ') || sym.startsWith('BSE:SENSEX')) {
 
952
  else if(sym.endsWith('FUT') && refPrice === 0) {
953
  if(data[sym].ltp > 0) refPrice = data[sym].ltp;
954
  }
 
 
955
  }
956
 
957
  // CRITERIA 1: Missing Reference Price (Corrupted)
958
  if(refPrice === 0) return false;
959
 
960
+ // 2. Parse and Organize Data by Strike
961
+ let strikesMap = {}; // { 21000: { CE: obj, PE: obj } }
962
+ let allStrikes = [];
 
 
 
 
 
 
 
 
 
 
 
963
 
964
+ for(let sym in data) {
965
+ // Regex to extract Strike + Type (e.g. ...22100CE -> 22100, CE)
966
+ // Handles potential decimal strikes as well
967
+ let match = sym.match(/(\d+(?:\.\d+)?)(CE|PE)$/);
968
+ if(match && match[1]) {
969
+ let k = parseFloat(match[1]);
970
+ let type = match[2]; // 'CE' or 'PE'
971
 
972
+ if(!strikesMap[k]) strikesMap[k] = { CE: null, PE: null };
973
+ strikesMap[k][type] = data[sym];
 
974
 
975
+ if(!allStrikes.includes(k)) allStrikes.push(k);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
976
  }
977
  }
978
+
979
+ if(allStrikes.length === 0) return false; // No options found
980
+
981
+ // 3. Find ATM Strike based on Ref Price
982
+ allStrikes.sort((a,b) => a - b);
983
+ let closest = allStrikes.reduce((prev, curr) =>
984
+ Math.abs(curr - refPrice) < Math.abs(prev - refPrice) ? curr : prev
985
+ );
986
+ let atmIdx = allStrikes.indexOf(closest);
987
+
988
+ // 4. Validate Range: ATM ± 7 Strikes
989
+ let start = Math.max(0, atmIdx - 7);
990
+ let end = Math.min(allStrikes.length - 1, atmIdx + 7);
991
 
992
+ // Iterate through the specific range
993
+ for(let i = start; i <= end; i++) {
994
+ let k = allStrikes[i];
995
+ let instruments = strikesMap[k];
996
+
997
+ // CRITERIA 2: Missing Instrument (Pair Check)
998
+ // If either CE or PE is completely missing from the data -> Corrupted
999
+ if(!instruments.CE || !instruments.PE) {
1000
+ return false;
1001
+ }
1002
+
1003
+ // CRITERIA 3: Data Quality (Zero Qty Check)
1004
+ // Check CE Quality
1005
+ let ceB = instruments.CE.totalbuyqty || 0;
1006
+ let ceS = instruments.CE.totalsellqty || 0;
1007
+ if(ceB === 0 && ceS === 0) return false;
1008
+
1009
+ // Check PE Quality
1010
+ let peB = instruments.PE.totalbuyqty || 0;
1011
+ let peS = instruments.PE.totalsellqty || 0;
1012
+ if(peB === 0 && peS === 0) return false;
1013
+ }
1014
+
1015
+ return true; // Data Passed all checks
1016
  }
1017
 
1018
  function renderSecondBar() {
 
1026
  <div class="sec-pill ${idx===0?'active':''} ${statusClass}"
1027
  onclick="selectSnapshot(${idx})"
1028
  id="pill-${idx}"
1029
+ title="${isValid ? 'Data OK' : 'Inefficient Data: Missing Inst/Qty or Ref'}">
1030
  :${item.s}
1031
  </div>
1032
  `}).join('');