topsecrettraders commited on
Commit
03fdad1
·
verified ·
1 Parent(s): 94363dd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +61 -53
app.py CHANGED
@@ -939,80 +939,88 @@ HTML_TEMPLATE = """
939
 
940
  // --- VALIDATION LOGIC FOR HISTORICAL DATA ---
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')) {
949
- if(data[sym].ltp > 0) refPrice = data[sym].ltp;
950
- }
951
- // Fallback to Future if Spot not found or is 0
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,7 +1034,7 @@ HTML_TEMPLATE = """
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('');
 
939
 
940
  // --- VALIDATION LOGIC FOR HISTORICAL DATA ---
941
  function validateSnapshot(data) {
942
+ // 1. Get Reference Price (Spot/Future) from the HISTORICAL packet
943
  let refPrice = 0;
944
 
945
+ // Try Spot first (using global SPOT_SYM)
946
+ if (SPOT_SYM && data[SPOT_SYM] && data[SPOT_SYM].ltp > 0) {
947
+ refPrice = data[SPOT_SYM].ltp;
948
+ }
949
+
950
+ // If no spot, try Futures (using global FUT_SYMS)
951
+ if (refPrice === 0 && FUT_SYMS.length > 0) {
952
+ for(let f of FUT_SYMS) {
953
+ if(data[f.s] && data[f.s].ltp > 0) {
954
+ refPrice = data[f.s].ltp;
955
+ break;
956
+ }
957
  }
958
  }
959
 
960
+ // CRITERIA 1: Missing Reference Price is a Critical Error
961
  if(refPrice === 0) return false;
962
 
963
+ // 2. Identify Target Strikes based on ACTIVE EXPIRY (Selected in UI)
964
+ if(!ACTIVE_EXP || !CHAIN_DATA) return true; // Cannot validate without Master context
 
965
 
966
+ // Filter Master DB for items belonging to the Selected Expiry only
967
+ const relevantItems = CHAIN_DATA.filter(x => x.e === ACTIVE_EXP && (x.t === 'CE' || x.t === 'PE'));
968
+
969
+ if(relevantItems.length === 0) return true;
 
 
 
 
 
 
 
 
 
 
970
 
971
+ // Group Master Items by Strike { 21000: { CE: "Sym...", PE: "Sym..." } }
972
+ let masterMap = {};
973
+ let allStrikes = [];
974
 
975
+ relevantItems.forEach(item => {
976
+ if(!masterMap[item.k]) {
977
+ masterMap[item.k] = { CE: null, PE: null };
978
+ allStrikes.push(item.k);
979
+ }
980
+ masterMap[item.k][item.t] = item.s;
981
+ });
982
+
983
  allStrikes.sort((a,b) => a - b);
984
+
985
+ // 3. Find ATM Strike based on the Historical Reference Price
986
  let closest = allStrikes.reduce((prev, curr) =>
987
  Math.abs(curr - refPrice) < Math.abs(prev - refPrice) ? curr : prev
988
  );
989
  let atmIdx = allStrikes.indexOf(closest);
990
 
991
+ // 4. Define Range: ATM ± 7 Strikes
992
+ let startIdx = Math.max(0, atmIdx - 7);
993
+ let endIdx = Math.min(allStrikes.length - 1, atmIdx + 7);
994
+
995
+ // 5. Strict Validation Loop
996
+ for(let i = startIdx; i <= endIdx; i++) {
997
  let k = allStrikes[i];
998
+ let requiredSyms = masterMap[k];
999
 
1000
+ // --- CHECK A: CALL OPTION ---
1001
+ if(requiredSyms.CE) {
1002
+ let d = data[requiredSyms.CE];
1003
+
1004
+ // 1. Is the instrument completely MISSING from history packet?
1005
+ if(!d) return false;
1006
+
1007
+ // 2. Is data insufficient (Zero Buy Qty AND Zero Sell Qty)?
1008
+ if((d.totalbuyqty || 0) === 0 && (d.totalsellqty || 0) === 0) return false;
1009
  }
1010
 
1011
+ // --- CHECK B: PUT OPTION ---
1012
+ if(requiredSyms.PE) {
1013
+ let d = data[requiredSyms.PE];
1014
+
1015
+ // 1. Is the instrument completely MISSING from history packet?
1016
+ if(!d) return false;
1017
+
1018
+ // 2. Is data insufficient (Zero Buy Qty AND Zero Sell Qty)?
1019
+ if((d.totalbuyqty || 0) === 0 && (d.totalsellqty || 0) === 0) return false;
1020
+ }
1021
  }
1022
 
1023
+ return true; // Passed all checks
1024
  }
1025
 
1026
  function renderSecondBar() {
 
1034
  <div class="sec-pill ${idx===0?'active':''} ${statusClass}"
1035
  onclick="selectSnapshot(${idx})"
1036
  id="pill-${idx}"
1037
+ title="${isValid ? 'Data OK' : 'MISSING DATA (Ref/Inst) OR ZERO QTY'}">
1038
  :${item.s}
1039
  </div>
1040
  `}).join('');