update list cron job

This commit is contained in:
MuslemRahimi 2024-10-29 22:33:13 +01:00
parent e42073cd70
commit 2b12858d0f
4 changed files with 270 additions and 50 deletions

View File

@ -11,9 +11,8 @@ with open(f"json/stock-screener/data.json", 'rb') as file:
stock_screener_data_dict = {item['symbol']: item for item in stock_screener_data} stock_screener_data_dict = {item['symbol']: item for item in stock_screener_data}
async def save_json(cap_category, data): async def save_json(category, data, category_type='market-cap'):
"""Save data to JSON file for specific market cap category.""" with open(f"json/{category_type}/list/{category}.json", 'wb') as file:
with open(f"json/market-cap/list/{cap_category}.json", 'wb') as file: # Note: 'wb' for binary write
file.write(orjson.dumps(data)) file.write(orjson.dumps(data))
async def get_quote_data(symbol): async def get_quote_data(symbol):
@ -24,10 +23,18 @@ async def get_quote_data(symbol):
except FileNotFoundError: except FileNotFoundError:
return None return None
async def process_market_cap_category(cursor, category, condition): async def process_category(cursor, category, condition, category_type='market-cap'):
"""Process stocks for a specific market cap category""" """
Process stocks for a specific category (market cap or sector)
Args:
cursor: Database cursor
category: Category name
condition: SQL WHERE condition
category_type: Either 'market-cap' or 'sector'
"""
base_query = """ base_query = """
SELECT DISTINCT s.symbol, s.name, s.exchangeShortName, s.marketCap SELECT DISTINCT s.symbol, s.name, s.exchangeShortName, s.marketCap, s.sector
FROM stocks s FROM stocks s
WHERE {} WHERE {}
""" """
@ -44,9 +51,10 @@ async def process_market_cap_category(cursor, category, condition):
item = { item = {
'symbol': symbol, 'symbol': symbol,
'name': row[1], 'name': row[1],
'price': quote_data.get('price'), 'price': round(quote_data.get('price'),2),
'changesPercentage': quote_data.get('changesPercentage'), 'changesPercentage': round(quote_data.get('changesPercentage'),2),
'marketCap': quote_data.get('marketCap'), 'marketCap': quote_data.get('marketCap'),
'sector': row[4], # Include sector information
'revenue': None, 'revenue': None,
} }
@ -54,7 +62,8 @@ async def process_market_cap_category(cursor, category, condition):
if symbol in stock_screener_data_dict: if symbol in stock_screener_data_dict:
item['revenue'] = stock_screener_data_dict[symbol].get('revenue') item['revenue'] = stock_screener_data_dict[symbol].get('revenue')
result_list.append(item) if item['marketCap'] > 0:
result_list.append(item)
# Sort by market cap and save # Sort by market cap and save
sorted_result = sorted(result_list, key=lambda x: x['marketCap'] if x['marketCap'] else 0, reverse=True) sorted_result = sorted(result_list, key=lambda x: x['marketCap'] if x['marketCap'] else 0, reverse=True)
@ -62,13 +71,14 @@ async def process_market_cap_category(cursor, category, condition):
for rank, item in enumerate(sorted_result, 1): for rank, item in enumerate(sorted_result, 1):
item['rank'] = rank item['rank'] = rank
await save_json(category, sorted_result) await save_json(category, sorted_result, category_type)
print(f"Processed and saved {len(sorted_result)} stocks for {category}") print(f"Processed and saved {len(sorted_result)} stocks for {category}")
return sorted_result return sorted_result
async def run(): async def run():
"""Main function to run the analysis for all market cap categories""" """Main function to run the analysis for all categories"""
conditions = { market_cap_conditions = {
'mega-cap-stocks': "marketCap >= 200e9 AND (exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ' OR exchangeShortName = 'AMEX')", 'mega-cap-stocks': "marketCap >= 200e9 AND (exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ' OR exchangeShortName = 'AMEX')",
'large-cap-stocks': "marketCap < 200e9 AND marketCap >= 10e9 AND (exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ' OR exchangeShortName = 'AMEX')", 'large-cap-stocks': "marketCap < 200e9 AND marketCap >= 10e9 AND (exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ' OR exchangeShortName = 'AMEX')",
'mid-cap-stocks': "marketCap < 10e9 AND marketCap >= 2e9 AND (exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ' OR exchangeShortName = 'AMEX')", 'mid-cap-stocks': "marketCap < 10e9 AND marketCap >= 2e9 AND (exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ' OR exchangeShortName = 'AMEX')",
@ -77,14 +87,33 @@ async def run():
'nano-cap-stocks': "marketCap < 50e6 AND (exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ' OR exchangeShortName = 'AMEX')" 'nano-cap-stocks': "marketCap < 50e6 AND (exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ' OR exchangeShortName = 'AMEX')"
} }
sector_conditions = {
'financial': "(exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ' OR exchangeShortName = 'AMEX') AND (sector = 'Financials' OR sector = 'Financial Services')",
'healthcare': "(exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ' OR exchangeShortName = 'AMEX') AND (sector = 'Healthcare')",
'technology': "(exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ' OR exchangeShortName = 'AMEX') AND (sector = 'Technology')",
'industrials': "(exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ' OR exchangeShortName = 'AMEX') AND (sector = 'Industrials')",
'consumer-cyclical': "(exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ' OR exchangeShortName = 'AMEX') AND (sector = 'Consumer Cyclical')",
'real-estate': "(exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ' OR exchangeShortName = 'AMEX') AND (sector = 'Real Estate')",
'basic-materials': "(exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ' OR exchangeShortName = 'AMEX') AND (sector = 'Basic Materials')",
'communication-services': "(exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ' OR exchangeShortName = 'AMEX') AND (sector = 'Communication Services')",
'energy': "(exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ' OR exchangeShortName = 'AMEX') AND (sector = 'Energy')",
'consumer-defensive': "(exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ' OR exchangeShortName = 'AMEX') AND (sector = 'Consumer Defensive')",
'utilities': "(exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ' OR exchangeShortName = 'AMEX') AND (sector = 'Utilities')"
}
try: try:
con = sqlite3.connect('stocks.db') con = sqlite3.connect('stocks.db')
cursor = con.cursor() cursor = con.cursor()
cursor.execute("PRAGMA journal_mode = wal") cursor.execute("PRAGMA journal_mode = wal")
# Process each market cap category # Process market cap categories
for category, condition in conditions.items(): for category, condition in market_cap_conditions.items():
await process_market_cap_category(cursor, category, condition) await process_category(cursor, category, condition, 'market-cap')
await asyncio.sleep(1) # Small delay between categories
# Process sector categories
for category, condition in sector_conditions.items():
await process_category(cursor, category, condition, 'sector')
await asyncio.sleep(1) # Small delay between categories await asyncio.sleep(1) # Small delay between categories
except Exception as e: except Exception as e:
@ -93,6 +122,7 @@ async def run():
finally: finally:
con.close() con.close()
if __name__ == "__main__": if __name__ == "__main__":
try: try:
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()

View File

@ -316,8 +316,7 @@ class HistoricalDate(BaseModel):
class OptionsWatchList(BaseModel): class OptionsWatchList(BaseModel):
optionsIdList: list optionsIdList: list
class MarketCapData(BaseModel):
category: str
# Replace NaN values with None in the resulting JSON object # Replace NaN values with None in the resulting JSON object
def replace_nan_inf_with_none(obj): def replace_nan_inf_with_none(obj):
@ -2079,12 +2078,6 @@ async def filter_stock_list(data: FilterStockList, api_key: str = Security(get_a
""" """
conditions = { conditions = {
'megaCap': "marketCap >= 200e9 AND (exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ')",
'largeCap': "marketCap < 200e9 AND marketCap >= 10e9 AND (exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ')",
'midCap': "marketCap < 10e9 AND marketCap >= 2e9 AND (exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ')",
'smallCap': "marketCap < 2e9 AND marketCap >= 300e6 AND (exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ')",
'microCap': "marketCap < 300e6 AND marketCap >= 50e6 AND (exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ')",
'nanoCap': "marketCap < 50e6 AND (exchangeShortName = 'NYSE' OR exchangeShortName = 'NASDAQ')",
'nasdaq': "exchangeShortName = 'NASDAQ'", 'nasdaq': "exchangeShortName = 'NASDAQ'",
'nyse': "exchangeShortName = 'NYSE'", 'nyse': "exchangeShortName = 'NYSE'",
'xetra': "exchangeShortName = 'XETRA'", 'xetra': "exchangeShortName = 'XETRA'",
@ -4144,10 +4137,10 @@ async def get_statistics(data: TickerData, api_key: str = Security(get_api_key))
) )
@app.post("/cap-category") @app.post("/list-category")
async def get_statistics(data: MarketCapData, api_key: str = Security(get_api_key)): async def get_statistics(data: FilterStockList, api_key: str = Security(get_api_key)):
category = data.category filter_list = data.filterList
cache_key = f"market-cap-category-{category}" cache_key = f"filter-list-{filter_list}"
cached_result = redis_client.get(cache_key) cached_result = redis_client.get(cache_key)
if cached_result: if cached_result:
return StreamingResponse( return StreamingResponse(
@ -4155,8 +4148,13 @@ async def get_statistics(data: MarketCapData, api_key: str = Security(get_api_ke
media_type="application/json", media_type="application/json",
headers={"Content-Encoding": "gzip"} headers={"Content-Encoding": "gzip"}
) )
if filter_list in ['financial','healthcare','technology','industrials','consumer-cyclical','real-estate','basic-materials','communication-services','energy','consumer-defensive','utilities']:
category_type = 'sector'
else:
category_type = 'market-cap'
try: try:
with open(f"json/market-cap/list/{category}.json", 'rb') as file: with open(f"json/{category_type}/list/{filter_list}.json", 'rb') as file:
res = orjson.loads(file.read()) res = orjson.loads(file.read())
except: except:
res = [] res = []

View File

@ -265,7 +265,7 @@ def run_tracker():
"cron_lobbying_tracker.py", "cron_lobbying_tracker.py",
"cron_sentiment_tracker.py" "cron_sentiment_tracker.py"
"cron_insider_tracker.py" "cron_insider_tracker.py"
"cron_cap_category.py" "cron_list.py"
] ]
for script in scripts: for script in scripts:
run_command(["python3", script]) run_command(["python3", script])

File diff suppressed because one or more lines are too long