backend/app/cron_dividends.py
2025-04-08 11:46:55 +02:00

153 lines
5.7 KiB
Python

import aiohttp
import ujson
import sqlite3
import asyncio
import pandas as pd
from tqdm import tqdm
from datetime import datetime, timedelta
import pytz
import orjson
import os
from dotenv import load_dotenv
load_dotenv()
ny_tz = pytz.timezone('America/New_York')
today = datetime.now(ny_tz).replace(hour=0, minute=0, second=0, microsecond=0)
N_days_ago = today - timedelta(days=10)
async def save_as_json(symbol, data, file_name):
# Ensure the directory exists
os.makedirs(file_name, exist_ok=True)
file_path = os.path.join(file_name, f"{symbol}.json")
with open(file_path, 'w') as file:
ujson.dump(data, file)
async def get_data(ticker, con, etf_con, stock_symbols, etf_symbols):
try:
# Choose the appropriate table and column names
if ticker in etf_symbols:
table_name = 'etfs'
column_name = 'etf_dividend'
else:
table_name = 'stocks'
column_name = 'stock_dividend'
# Build and execute the SQL query
query_template = f"""
SELECT {column_name}
FROM {table_name}
WHERE symbol = ?
"""
df = pd.read_sql_query(
query_template,
etf_con if table_name == 'etfs' else con,
params=(ticker,)
)
# Load the JSON data
res = orjson.loads(df[column_name].iloc[0])
# Filter out records that do not have a recordDate or paymentDate
filtered_res = [item for item in res if item['recordDate'] and item['paymentDate']]
if not filtered_res:
raise ValueError("No valid dividend records found.")
# Extract payout frequency and dividend yield from the first valid record
payout_frequency = filtered_res[0]['frequency']
dividend_yield = filtered_res[0]['yield']
# Determine the period for the last year using the maximum record date
max_record_date = max(datetime.fromisoformat(item['recordDate']) for item in filtered_res)
one_year_ago = max_record_date - timedelta(days=365)
# Calculate dividend growth rate
# Sort records by record date
sorted_records = sorted(filtered_res, key=lambda x: datetime.fromisoformat(x['recordDate']))
# Get the year of the latest dividend
latest_year = datetime.fromisoformat(sorted_records[-1]['recordDate']).year
# Find the first dividend in the current year and the first dividend from previous year
latest_dividend = None
previous_year_dividend = None
for record in sorted_records:
try:
record_date = datetime.fromisoformat(record['recordDate'])
if record_date.year == latest_year and latest_dividend is None:
latest_dividend = record['adjDividend']
elif record_date.year == latest_year - 1 and previous_year_dividend is None:
previous_year_dividend = record['adjDividend']
# Break if we found both dividends
if latest_dividend is not None and previous_year_dividend is not None:
break
except:
pass
# Calculate growth rate if both values exist
dividend_growth = None
if latest_dividend is not None and previous_year_dividend is not None and previous_year_dividend != 0:
dividend_growth = round(((latest_dividend - previous_year_dividend) / previous_year_dividend) * 100, 2)
# Sum up all adjDividend values for records in the last year
annual_dividend = sum(
item['adjDividend']
for item in filtered_res
if datetime.fromisoformat(item['recordDate']) >= one_year_ago
)
with open(f"json/quote/{ticker}.json","r") as file:
try:
quote_data = orjson.loads(file.read())
eps = quote_data['eps']
payout_ratio = round((1 - (eps - annual_dividend) / eps) * 100, 2) if eps else None
except:
payout_ratio = None
return {
'payoutFrequency': payout_frequency,
'annualDividend': round(annual_dividend,2) if annual_dividend != None else annual_dividend,
'dividendYield': round(dividend_yield,2) if dividend_yield != None else dividend_yield,
'payoutRatio': round(payout_ratio,2) if payout_ratio != None else payout_ratio,
'dividendGrowth': dividend_growth,
'history': filtered_res,
}
except Exception as e:
print(f"Error processing ticker {ticker}: {e}")
return {}
async def run():
con = sqlite3.connect('stocks.db')
cursor = con.cursor()
cursor.execute("PRAGMA journal_mode = wal")
cursor.execute("SELECT DISTINCT symbol FROM stocks WHERE symbol NOT LIKE '%.%'")
stock_symbols = [row[0] for row in cursor.fetchall()]
etf_con = sqlite3.connect('etf.db')
etf_cursor = etf_con.cursor()
etf_cursor.execute("SELECT DISTINCT symbol FROM etfs")
etf_symbols = [row[0] for row in etf_cursor.fetchall()]
total_symbols = stock_symbols + etf_symbols
for ticker in tqdm(total_symbols):
try:
res = await get_data(ticker, con, etf_con, stock_symbols, etf_symbols)
if len(res.get('history', [])) > 0:
await save_as_json(ticker, res, 'json/dividends/companies')
except Exception as e:
print(f"Error saving data for {ticker}: {e}")
con.close()
etf_con.close()
try:
asyncio.run(run())
except Exception as e:
print(e)