Skip to content

Instantly share code, notes, and snippets.

@freelancing-solutions
Created January 5, 2023 11:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save freelancing-solutions/6d5b020c683cd4c6021a6e490c6a2703 to your computer and use it in GitHub Desktop.
Save freelancing-solutions/6d5b020c683cd4c6021a6e490c6a2703 to your computer and use it in GitHub Desktop.
fundamental data
import asyncio
from typing import List, Generator, Callable, Any, Dict, Union
from flask import jsonify
from flask_apispec import doc, marshal_with
from google.cloud import ndb
from src.cache.cache_manager import app_cache
from src.exceptions import status_codes
from src.models.fundamental import (FundamentalGeneral, GeneralAddress, GeneralContact, GeneralListings,
GeneralOfficers,
FundamentalHighlights, FundamentalValuation, FundamentalSharesStats,
FundamentalTechnicals,
FundamentalSplitsDividends, FundamentalAnalystRanks, InstitutionHolders,
FundsHolders,
FundamentalInsiderTransactions, FundamentalOutStandingShares,
AnnualOutStandingShares, QuarterlyOutStandingShares,
HistoryEarnings, TrendEarnings, AnnualEarnings, FundamentalFinancials,
QuarterlyBalanceSheets, AnnualBalanceSheets, FundamentalDividendsByYear)
from src.schemas.fundamentals.generaldetails import GeneralResponseSchema
from src.schemas.fundamentals.public_schema import PublicFundamentalsResponseSchema
from src.views import ViewModel, CACHE_TIMEOUT_DAY, MResponse
from collections import ChainMap
class GetAllFundamentalGeneralAPI(ViewModel):
"""
**GetAllFundamentalGeneralAPI**
will return only general fundamental data for all companies listed in stock exchanges
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@doc(description="return general fundamental data for all companies")
@marshal_with(GeneralResponseSchema)
@app_cache.cache.memoize(timeout=CACHE_TIMEOUT_DAY)
def get(self) -> MResponse:
"""
return general fundamental data for all companies
:return: Tuple
"""
fundamental_list = await ndb.transaction_async(FundamentalGeneral.get_all())
_payload = [fundamental.to_dict() for fundamental in fundamental_list]
_message: str = "fundamental data found"
return jsonify(dict(status=True, message=_message, payload=_payload)), status_codes.status_ok_code
# noinspection DuplicatedCode
class GetCompanyFundamentalDataAPI(ViewModel):
"""
**GetCompanyFundamentalDataAPI**
Get complete company fundamental data
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@doc(description="for each stock code return the fundamental data for the company")
@marshal_with(PublicFundamentalsResponseSchema)
@app_cache.cache.memoize(timeout=CACHE_TIMEOUT_DAY)
async def get(self, stock_code: str) -> MResponse:
payload = await ndb.transaction_async(callback=self.get_fundamental_data(stock_code=stock_code), retries=3)
return jsonify(status=True, payload=payload), status_codes.status_ok_code
# noinspection PyUnresolvedReferences
# noinspection PyTypeChecker
@ndb.toplevel
async def get_fundamental_data(self, stock_code : str) -> dict[str, str]:
"""
**get_fundamental_data**
obtain the entire fundamental record for a specific company
:param stock_code:
:return:
"""
_tasks, fundamental_inst = await self.create_tasks(stock_code=stock_code)
# please ensure to use gather here as we need the results in order
payload = fundamental_inst.to_dict()
results = await asyncio.gather(*_tasks)
_gen = self.instance_gen(results=results)
payload = await self.create_payload(_gen=_gen, payload=payload)
_message: str = f"fundamental data for {stock_code} found"
return jsonify(doc(status=True, payload=payload, message=_message)), status_codes.status_ok_code
@staticmethod
async def create_payload(_gen, payload):
"""
create fundamental data payload
:param _gen:
:param payload:
:return: payload: Dict
"""
general_address_inst = next(_gen)
contacts_inst = next(_gen)
listing_inst_list: list = next(_gen)
officers_inst_list: list = next(_gen)
highlights_inst = next(_gen)
valuation_inst = next(_gen)
share_stats = next(_gen)
technicals_inst = next(_gen)
splits_inst = next(_gen)
fundamentals_analyst_ranks: list = next(_gen)
institution_holders_list: list = next(_gen)
funds_holders_list: list = next(_gen)
insiders_transaction_list: list = next(_gen)
outstanding_shares_list: list = next(_gen)
annual_outstanding_shares_list: list = next(_gen)
quarterly_outstanding_shares_list: list = next(_gen)
historical_earnings_list: list = next(_gen)
trend_earnings_list: list = next(_gen)
annual_earnings_list: list = next(_gen)
financials_list: list = next(_gen)
quarterly_balance_sheets_list: list = next(_gen)
annual_balance_sheets_list: list = next(_gen)
updates = {key: value.to_dict() for key, value in [
('address', general_address_inst),
('contacts', contacts_inst),
('listing', [listing.to_dict() for listing in listing_inst_list]),
('officers', [officer.to_dict() for officer in officers_inst_list]),
('highlights', highlights_inst),
('valuation', valuation_inst),
('share_stats', share_stats),
('technicals', technicals_inst),
('splits', splits_inst),
('analyst_ranks', fundamentals_analyst_ranks),
('institution_holders', [holder.to_dict() for holder in institution_holders_list]),
('funds_holders', [holder.to_dict() for holder in funds_holders_list]),
('insider_transactions', [transaction.to_dict() for transaction in insiders_transaction_list]),
('outstanding_shares', [share.to_dict() for share in outstanding_shares_list]),
('annual_outstanding_shares', [share.to_dict() for share in annual_outstanding_shares_list]),
('quarterly_outstanding_shares', [share.to_dict() for share in quarterly_outstanding_shares_list]),
('historical_earnings', [earning.to_dict() for earning in historical_earnings_list]),
('trend_earnings', [earning.to_dict() for earning in trend_earnings_list]),
('annual_earnings', [earning.to_dict() for earning in annual_earnings_list]),
('financials', [financial.to_dict() for financial in financials_list]),
('annual_balance_sheets', [balance_sheet.to_dict() for balance_sheet in annual_balance_sheets_list]),
('quarterly_balance_sheets', [balance_sheet.to_dict() for balance_sheet in quarterly_balance_sheets_list]),
]}
payload = dict(ChainMap(payload, updates))
return payload
async def create_tasks(self, stock_code) -> tuple[map, FundamentalGeneral]:
"""
create tasks which will be used to generate the payload
:param stock_code:
:return:
"""
tasks = [self.get_general_address, self.get_contacts, self.get_general_listing, self.get_general_officers,
self.get_fundamental_highlights, self.get_valuations, self.get_share_stats, self.get_technicals,
self.get_splits, self.get_analyst_ranks, self.get_institution_holders, self.get_funds_holders,
self.get_insiders_transactions, self.get_outstanding_shares, self.get_annual_outstanding_shares,
self.get_quarterly_outstanding_shares, self.get_historical_earnings, self.get_trend_earnings,
self.get_annual_earnings, self.get_fundamental_financials, self.get_quarterly_balance_sheets,
self.get_annual_balance_sheets]
fundamental_inst = FundamentalGeneral.query(FundamentalGeneral.stock_symbol == stock_code).get_async()
_id: str = fundamental_inst.fundamental_id
_tasks = map(lambda _task: _task(_id), tasks)
return _tasks, fundamental_inst
@staticmethod
def instance_gen(results) -> Generator[Union[Dict[str, Any], List[Dict[str, Any]]]]:
"""
this method will generator the relevant dictionary or list of dictionaries
depending on the results of the query
:param results:
:return:
"""
for result in results:
yield result
@staticmethod
@ndb.tasklet
async def get_annual_balance_sheets(_id: str) -> List[AnnualBalanceSheets]:
annual_sheets = yield AnnualBalanceSheets.query(AnnualBalanceSheets.fundamental_id == _id).fetch_async()
yield [sheet for sheet in annual_sheets]
raise ndb.Return(annual_sheets)
@staticmethod
@ndb.tasklet
async def get_quarterly_balance_sheets(_id: str) -> List[QuarterlyBalanceSheets]:
quarterly_sheets = yield QuarterlyBalanceSheets.query(
QuarterlyBalanceSheets.fundamental_id == _id).fetch_async()
yield [quarter for quarter in quarterly_sheets]
raise ndb.Return(quarterly_sheets)
@staticmethod
@ndb.tasklet
async def get_fundamental_financials(_id: str) -> List[FundamentalFinancials]:
financials_list = yield FundamentalFinancials.query(FundamentalFinancials.fundamental_id == _id).fetch_async()
yield [finance for finance in financials_list]
raise ndb.Return(financials_list)
@staticmethod
@ndb.tasklet
async def get_annual_earnings(_id: str) -> List[AnnualEarnings]:
annual_earnings = yield AnnualEarnings.query(AnnualEarnings.fundamental_id == _id).fetch_async()
yield [earning for earning in annual_earnings]
raise ndb.Return(annual_earnings)
@staticmethod
@ndb.tasklet
async def get_trend_earnings(_id: str) -> List[TrendEarnings]:
trend_earnings = yield TrendEarnings.query(TrendEarnings.fundamental_id == _id).fetch_async()
yield [trend for trend in trend_earnings]
raise ndb.Return(trend_earnings)
@staticmethod
@ndb.tasklet
async def get_historical_earnings(_id: str) -> List[HistoryEarnings]:
historical_earnings = yield HistoryEarnings.query(HistoryEarnings.fundamental_id == _id).fetch_async()
yield [historical for historical in historical_earnings]
raise ndb.Return(historical_earnings)
@staticmethod
@ndb.tasklet
async def get_quarterly_outstanding_shares(_id: str) -> List[QuarterlyOutStandingShares]:
quarterly_outstanding_shares = yield QuarterlyOutStandingShares.query(
QuarterlyOutStandingShares.fundamental_id == _id).fetch_async()
yield [share for share in quarterly_outstanding_shares]
raise ndb.Return(quarterly_outstanding_shares)
@staticmethod
@ndb.tasklet
async def get_annual_outstanding_shares(_id: str) -> List[AnnualOutStandingShares]:
annual_outstanding = yield AnnualOutStandingShares.query(
AnnualOutStandingShares.fundamental_id == _id).fetch_async()
yield [share for share in annual_outstanding]
raise ndb.Return(annual_outstanding)
@staticmethod
@ndb.tasklet
async def get_outstanding_shares(_id: str) -> List[FundamentalOutStandingShares]:
out_standing_shares = yield FundamentalOutStandingShares.query(
FundamentalOutStandingShares.fundamental_id == _id).fetch_async()
yield [share for share in out_standing_shares]
raise ndb.Return(out_standing_shares)
@staticmethod
@ndb.tasklet
async def get_insiders_transactions(_id: str) -> List[FundamentalInsiderTransactions]:
insiders_transactions = yield FundamentalInsiderTransactions.query(
FundamentalInsiderTransactions.fundamental_id == _id).fetch_async()
yield [insider for insider in insiders_transactions]
raise ndb.Return(insiders_transactions)
@staticmethod
@ndb.tasklet
async def get_funds_holders(_id: str) -> List[FundsHolders]:
funds_holders = yield FundsHolders.query(FundsHolders.fundamental_id == _id).fetch_async()
yield [funds for funds in funds_holders]
raise ndb.Return(funds_holders)
@staticmethod
@ndb.tasklet
async def get_institution_holders(_id: str) -> List[InstitutionHolders]:
institution_holders_list = yield InstitutionHolders.query(
InstitutionHolders.fundamental_id == _id).fetch_async()
yield [institution_ for institution_ in institution_holders_list]
raise ndb.Return(institution_holders_list)
@staticmethod
@ndb.tasklet
async def get_analyst_ranks(_id: str) -> FundamentalAnalystRanks:
analyst_rank = yield FundamentalAnalystRanks.query(
FundamentalAnalystRanks.fundamental_id == _id).get_async()
raise ndb.Return(analyst_rank)
@staticmethod
@ndb.tasklet
async def get_splits(_id: str) -> FundamentalSplitsDividends:
splits_dividends = yield FundamentalSplitsDividends.query(
FundamentalSplitsDividends.fundamental_id == _id).get_async()
_by_year_list = yield GetCompanyFundamentalDataAPI.splits_by_year(splits_dividends)
splits_dividends.update(number_of_dividends_by_year=[_by_year.to_dict() for _by_year in _by_year_list])
raise ndb.Return(splits_dividends)
@staticmethod
@ndb.tasklet
async def splits_by_year(splits_dividends):
_by_year_list = yield FundamentalDividendsByYear.query(
FundamentalDividendsByYear.split_dividend_id == splits_dividends.split_dividend_id).fetch_async()
yield [_year for _year in _by_year_list]
raise ndb.Return(_by_year_list)
@staticmethod
@ndb.tasklet
async def get_technicals(_id: str) -> FundamentalTechnicals:
fun_technicals = yield FundamentalTechnicals.query(FundamentalTechnicals.fundamental_id == _id).get_async()
raise ndb.Return(fun_technicals)
@staticmethod
@ndb.tasklet
async def get_share_stats(_id: str) -> FundamentalSharesStats:
share_stats = yield FundamentalSharesStats.query(FundamentalSharesStats.fundamental_id == _id).get_async()
raise ndb.Return(share_stats)
@staticmethod
@ndb.tasklet
async def get_valuations(_id: str) -> FundamentalValuation:
valuation = yield FundamentalValuation.query(FundamentalValuation.fundamental_id == _id).get_async()
raise ndb.Return(valuation)
@staticmethod
@ndb.tasklet
async def get_fundamental_highlights(_id: str) -> FundamentalHighlights:
highlights_inst = yield FundamentalHighlights.query(FundamentalHighlights.fundamental_id == _id).fetch_async()
raise ndb.Return(highlights_inst)
@staticmethod
@ndb.tasklet
async def get_general_officers(_id: str) -> List[GeneralOfficers]:
general_officers = yield GeneralOfficers.query(GeneralOfficers.fundamental_id == _id).fetch_async()
yield [officer for officer in general_officers]
raise ndb.Return(general_officers)
@staticmethod
@ndb.tasklet
async def get_general_listing(_id: str) -> GeneralListings:
general_listings = yield GeneralListings.query(GeneralListings.fundamental_id == _id).get_async()
raise ndb.Return(general_listings)
@staticmethod
@ndb.tasklet
async def get_contacts(_id: str) -> GeneralContact:
contacts_inst = yield GeneralContact.query(GeneralContact.fundamental_id == _id).get_async()
raise ndb.Return(contacts_inst)
@staticmethod
@ndb.tasklet
async def get_general_address(_id: str) -> GeneralAddress:
general_address_inst = yield GeneralAddress.query(GeneralAddress.fundamental_id == _id).get_async()
raise ndb.Return(general_address_inst)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment