sarim commited on
Commit
f641e6a
·
1 Parent(s): d4b7c04

add circuit breaker ticker

Browse files
Files changed (3) hide show
  1. app.py +16 -3
  2. models.py +28 -2
  3. psx_scraper.py +27 -2
app.py CHANGED
@@ -18,7 +18,7 @@ CACHE = {
18
  "dividends": None,
19
  "gainers": None,
20
  "last_updated": None,
21
- "announcements":None
22
  }
23
 
24
  BASE_URL = "https://www.psx.com.pk"
@@ -391,11 +391,24 @@ def get_gainers_loosers():
391
  return CACHE["gainers"]
392
 
393
  @app.get("/get_symbol_detail{symbol}")
394
- def get_announcements(symbol:str):
395
 
396
  r = requests.get(f'https://dps.psx.com.pk/company/{symbol}')
397
 
398
  scraper = PsxScraper(html_content=r.text)
399
  company_data = scraper.scrape_all_data()
400
 
401
- return company_data
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  "dividends": None,
19
  "gainers": None,
20
  "last_updated": None,
21
+ "announcements": None
22
  }
23
 
24
  BASE_URL = "https://www.psx.com.pk"
 
391
  return CACHE["gainers"]
392
 
393
  @app.get("/get_symbol_detail{symbol}")
394
+ def get_symbol_detail(symbol:str):
395
 
396
  r = requests.get(f'https://dps.psx.com.pk/company/{symbol}')
397
 
398
  scraper = PsxScraper(html_content=r.text)
399
  company_data = scraper.scrape_all_data()
400
 
401
+ return company_data
402
+
403
+
404
+ @app.get("/circuit-breakers/all")
405
+ def get_all_circuit_breakers(symbol:str):
406
+
407
+ r = requests.get("https://dps.psx.com.pk/circuit-breakers")
408
+
409
+ scraper = PsxScraper(html_content=r.text)
410
+
411
+ return {
412
+ "upper": scraper.fetch_circuit_breaker_table("upperCap"),
413
+ "lower": scraper.fetch_circuit_breaker_table("lowerCap"),
414
+ }
models.py CHANGED
@@ -1,5 +1,5 @@
1
  from typing import Dict, List, Optional
2
- from pydantic import BaseModel, Field, validator
3
  from datetime import datetime
4
 
5
 
@@ -110,4 +110,30 @@ class CompanyData(BaseModel):
110
  announcements: List[FinancialResult]
111
  financials: Financials
112
  ratios: List[RatioEntry]
113
- timestamp: datetime = Field(default_factory=datetime.now)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  from typing import Dict, List, Optional
2
+ from pydantic import BaseModel, Field, validator, field_validator
3
  from datetime import datetime
4
 
5
 
 
110
  announcements: List[FinancialResult]
111
  financials: Financials
112
  ratios: List[RatioEntry]
113
+ timestamp: datetime = Field(default_factory=datetime.now)
114
+
115
+
116
+
117
+ class CircuitBreakerRow(BaseModel):
118
+ symbol: str
119
+ ldcp: float
120
+ open: float
121
+ high: float
122
+ low: float
123
+ current: float
124
+ change: float
125
+ change_percent: float
126
+ volume: int
127
+
128
+ @field_validator(
129
+ "ldcp", "open", "high", "low", "current", "change", "change_percent",
130
+ mode="before"
131
+ )
132
+ @classmethod
133
+ def parse_float(cls, v):
134
+ return float(v.replace(",", "").replace("%", ""))
135
+
136
+ @field_validator("volume", mode="before")
137
+ @classmethod
138
+ def parse_int(cls, v):
139
+ return int(v.replace(",", ""))
psx_scraper.py CHANGED
@@ -1,6 +1,6 @@
1
  from bs4 import BeautifulSoup
2
  import re
3
- from models import FinancialResult,FinancialEntry,Financials,RatioEntry,CompanyData
4
  from typing import List, Optional, Dict, Any
5
 
6
  class PsxScraper(object):
@@ -233,5 +233,30 @@ class PsxScraper(object):
233
  ratios=self.extract_ratios()
234
  )
235
 
236
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
 
 
1
  from bs4 import BeautifulSoup
2
  import re
3
+ from models import FinancialResult,FinancialEntry,Financials,RatioEntry,CompanyData, CircuitBreakerRow
4
  from typing import List, Optional, Dict, Any
5
 
6
  class PsxScraper(object):
 
233
  ratios=self.extract_ratios()
234
  )
235
 
236
+
237
+
238
+ def fetch_circuit_breaker_table(self,table_id:str) -> list[CircuitBreakerRow]:
239
+ table = self.soup.find("table", id=table_id)
240
+ if not table or not table.tbody:
241
+ return []
242
+ records = []
243
+ for row in table.tbody.find_all("tr"):
244
+ cols = [td.get_text(strip=True) for td in row.find_all("td")]
245
+
246
+ records.append(
247
+ CircuitBreakerRow(
248
+ symbol=cols[0],
249
+ ldcp=cols[1],
250
+ open=cols[2],
251
+ high=cols[3],
252
+ low=cols[4],
253
+ current=cols[5],
254
+ change=cols[6],
255
+ change_percent=cols[7],
256
+ volume=cols[8],
257
+ )
258
+ )
259
+
260
+ return records
261
+
262