update logic and cache gold data
Browse files- app.py +39 -38
- metals_price.py +1 -1
- requirements.txt +2 -1
app.py
CHANGED
|
@@ -14,13 +14,15 @@ import re
|
|
| 14 |
from psx_scraper import PsxScraper
|
| 15 |
from metals_price import MetalsPrice
|
| 16 |
import os
|
|
|
|
| 17 |
|
| 18 |
|
| 19 |
CACHE = {
|
| 20 |
"dividends": None,
|
| 21 |
"gainers": None,
|
| 22 |
"last_updated": None,
|
| 23 |
-
"circuit_breaker": None
|
|
|
|
| 24 |
}
|
| 25 |
|
| 26 |
BASE_URL = "https://www.psx.com.pk"
|
|
@@ -336,24 +338,19 @@ def get_announcements_scrap():
|
|
| 336 |
return announcements
|
| 337 |
|
| 338 |
|
| 339 |
-
def
|
| 340 |
-
cleaned = []
|
| 341 |
|
| 342 |
-
|
| 343 |
-
|
| 344 |
-
|
| 345 |
-
|
| 346 |
-
|
| 347 |
-
|
| 348 |
-
|
| 349 |
-
|
| 350 |
-
|
| 351 |
-
|
| 352 |
-
|
| 353 |
-
# VERY IMPORTANT for charts
|
| 354 |
-
cleaned.sort(key=lambda x: x["date"])
|
| 355 |
-
|
| 356 |
-
return cleaned
|
| 357 |
|
| 358 |
|
| 359 |
def get_circuit_breakers():
|
|
@@ -371,13 +368,31 @@ def background_scrap():
|
|
| 371 |
while True:
|
| 372 |
try:
|
| 373 |
print("Updating cached data...")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 374 |
|
| 375 |
-
|
| 376 |
-
|
| 377 |
-
|
| 378 |
-
|
|
|
|
| 379 |
|
| 380 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 381 |
except Exception as e:
|
| 382 |
print("Background scrape error:", e)
|
| 383 |
time.sleep(3600)
|
|
@@ -442,19 +457,5 @@ def get_all_circuit_breakers():
|
|
| 442 |
|
| 443 |
@app.get("/gold_price")
|
| 444 |
def get_gold_historial_price():
|
| 445 |
-
print("key testing")
|
| 446 |
-
print(f"{api_key_metal}")
|
| 447 |
-
response = []
|
| 448 |
-
|
| 449 |
-
BASE_URL = "https://api.gold-api.com/history"
|
| 450 |
-
|
| 451 |
-
# Initialize the class
|
| 452 |
-
metals_api = MetalsPrice(api_key=f"{api_key_metal}", base_url=BASE_URL)
|
| 453 |
|
| 454 |
-
|
| 455 |
-
end = int(datetime.utcnow().timestamp())
|
| 456 |
-
start = int((datetime.utcnow() - timedelta(days=730)).timestamp())
|
| 457 |
-
|
| 458 |
-
data = metals_api.get_price_history("XAU", start, end)
|
| 459 |
-
|
| 460 |
-
return data
|
|
|
|
| 14 |
from psx_scraper import PsxScraper
|
| 15 |
from metals_price import MetalsPrice
|
| 16 |
import os
|
| 17 |
+
import pytz
|
| 18 |
|
| 19 |
|
| 20 |
CACHE = {
|
| 21 |
"dividends": None,
|
| 22 |
"gainers": None,
|
| 23 |
"last_updated": None,
|
| 24 |
+
"circuit_breaker": None,
|
| 25 |
+
"gold_price": None
|
| 26 |
}
|
| 27 |
|
| 28 |
BASE_URL = "https://www.psx.com.pk"
|
|
|
|
| 338 |
return announcements
|
| 339 |
|
| 340 |
|
| 341 |
+
def get_gold_data():
|
|
|
|
| 342 |
|
| 343 |
+
BASE_URL = "https://api.gold-api.com/history"
|
| 344 |
+
|
| 345 |
+
# Initialize the class
|
| 346 |
+
metals_api = MetalsPrice(api_key=f"{api_key_metal}", base_url=BASE_URL)
|
| 347 |
+
|
| 348 |
+
# Last 730 days (2 years)
|
| 349 |
+
end = int(datetime.utcnow().timestamp())
|
| 350 |
+
start = int((datetime.utcnow() - timedelta(days=730)).timestamp())
|
| 351 |
+
|
| 352 |
+
data = metals_api.get_price_history("XAU", start, end)
|
| 353 |
+
return data
|
|
|
|
|
|
|
|
|
|
|
|
|
| 354 |
|
| 355 |
|
| 356 |
def get_circuit_breakers():
|
|
|
|
| 368 |
while True:
|
| 369 |
try:
|
| 370 |
print("Updating cached data...")
|
| 371 |
+
|
| 372 |
+
pakistan_tz = pytz.timezone('Asia/Karachi')
|
| 373 |
+
current_time = datetime.now(pakistan_tz)
|
| 374 |
+
start_time = current_time.replace(hour=9, minute=0, second=0, microsecond=0)
|
| 375 |
+
end_time = current_time.replace(hour=17, minute=0, second=0, microsecond=0)
|
| 376 |
+
|
| 377 |
+
if start_time <= current_time <= end_time:
|
| 378 |
|
| 379 |
+
CACHE["dividends"] = simple_dividend_extraction()
|
| 380 |
+
CACHE["gainers"] = get_active_gainers()
|
| 381 |
+
CACHE["last_updated"] = time.time()
|
| 382 |
+
CACHE["circuit_breaker"] = get_circuit_breakers()
|
| 383 |
+
CACHE["gold_price"] = get_gold_data()
|
| 384 |
|
| 385 |
+
print(f"Next update after 3 hours delay...")
|
| 386 |
+
|
| 387 |
+
time.sleep(10800)
|
| 388 |
+
else:
|
| 389 |
+
next_run = current_time.replace(hour=9, minute=0, second=0, microsecond=0)
|
| 390 |
+
if current_time > next_run:
|
| 391 |
+
next_run += timedelta(days=1)
|
| 392 |
+
|
| 393 |
+
sleep_seconds = (next_run - current_time).total_seconds()
|
| 394 |
+
print(f"Outside working hours. Next update at {next_run.strftime('%Y-%m-%d %H:%M:%S %Z')}")
|
| 395 |
+
time.sleep(sleep_seconds)
|
| 396 |
except Exception as e:
|
| 397 |
print("Background scrape error:", e)
|
| 398 |
time.sleep(3600)
|
|
|
|
| 457 |
|
| 458 |
@app.get("/gold_price")
|
| 459 |
def get_gold_historial_price():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 460 |
|
| 461 |
+
return CACHE["gold_price"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
metals_price.py
CHANGED
|
@@ -18,7 +18,7 @@ class MetalsPrice: # Fixed typo: "Metails" -> "Metals"
|
|
| 18 |
start_timestamp: int = int(datetime.utcnow().timestamp()),
|
| 19 |
end_timestamp: int = int((datetime.utcnow() - timedelta(days=730)).timestamp()),
|
| 20 |
group_by: str = "day",
|
| 21 |
-
aggregation: str = "
|
| 22 |
order_by: str = "desc"
|
| 23 |
) -> List[Dict[str, Any]]:
|
| 24 |
"""
|
|
|
|
| 18 |
start_timestamp: int = int(datetime.utcnow().timestamp()),
|
| 19 |
end_timestamp: int = int((datetime.utcnow() - timedelta(days=730)).timestamp()),
|
| 20 |
group_by: str = "day",
|
| 21 |
+
aggregation: str = "max_price",
|
| 22 |
order_by: str = "desc"
|
| 23 |
) -> List[Dict[str, Any]]:
|
| 24 |
"""
|
requirements.txt
CHANGED
|
@@ -3,4 +3,5 @@ uvicorn
|
|
| 3 |
requests
|
| 4 |
beautifulsoup4
|
| 5 |
jinja2
|
| 6 |
-
pydantic
|
|
|
|
|
|
| 3 |
requests
|
| 4 |
beautifulsoup4
|
| 5 |
jinja2
|
| 6 |
+
pydantic
|
| 7 |
+
pytz
|