Инструментарий Quant Trader’s Toolkit — ссылки на полную серию:
- "Обзор"
- Бесплатные и быстрые фундаментальные данные от SEC (вы здесь)
Ваше ожидание окончено!
Вы когда-нибудь пытались получить необходимые фундаментальные данные?! Вы когда-нибудь хотели использовать квартальные фундаментальные данные, но обнаруживали, что они скрыты за платным доступом?! Что ж, сегодня вы получаете код Python для доступа к БЕСПЛАТНЫМ ФУНДАМЕНТАЛЬНЫМ ДАННЫМ из документов секонд-х, БЫСТРО И ЛЕГКО, благодаря вашим друзьям из The Quant Trading Room!
Данные — король
Данные станут основой любой стратегии, которую вы будете строить в качестве специалиста по количественному анализу. В частности, получение высококачественных данных, к которым другие люди не имеют доступа, в конечном итоге станет тем, где вы найдете свои самые прибыльные альфы. Как вы думаете, каковы ваши шансы найти преимущество, используя только данные OHLC, полученные от yfinance? Они низкие…. очень низкий. Однако не стоит паниковать! В этой серии «Инструментарий Quant Trader’s Toolkit» мы предоставим вам инструменты, которые позволят вам отделить себя от подражателей и найти преимущества, которые будут финансировать арендные платежи вашего сахарного ребенка ;).
Получить все публично торгуемые компании
Эта первая функция позволяет вам получить ключи центрального индекса (CIK) ВСЕХ публично торгуемых компаний, которые отвечают за представление отчетов в Комиссию по ценным бумагам и биржам.
def get_all_companies(headers): companyTickers = requests.get( "https://www.sec.gov/files/company_tickers.json", headers=headers) company_dct = companyTickers.json() cik_lst = [str(company_dct[x]['cik_str']).zfill(10) for x in company_dct] return cik_lst
Получить данные о подаче данных CIK
Эта функция позволяет вам взять один из CIK из списка, возвращенного последней функцией, и запросить данные из всех этих компаний 10-K (Годовой отчет) и 10-Q (Квартальный отчет), начиная с 2009 года. Словарь возвращается, который включает название компании, CIK и данные для отчетов 10-K и 10-Q как в отдельной, так и в объединенной форме для более полного представления об основных принципах компании.
def get_filing_data_by_cik(cik, headers): companyFacts = requests.get( f'https://data.sec.gov/api/xbrl/companyfacts/CIK{cik}.json', headers=headers) cFacts = companyFacts.json() facts = cFacts['facts'] date_dict = {'Q1': '03-30-', 'Q2': '06-30-', 'Q3': '09-30-', 'FY': '12-31-'} Q10K10_tags_values = [(f"{t}_{u}", [(f"{date_dict[i['fp']]}{i['fy']}", i['val']) for i in facts[c][t]['units'][u] if i['form'] in ['10-Q','10-K'] ] ) for c in facts.keys() for t in facts[c].keys() for u in facts[c][t]['units'].keys() ] K10_tags_values = [(f"{t}_{u}", [(f"{date_dict[i['fp']]}{i['fy']}", i['val']) for i in facts[c][t]['units'][u] if i['form'] in ['10-K'] ] ) for c in facts.keys() for t in facts[c].keys() for u in facts[c][t]['units'].keys() ] Q10_tags_values = [(f"{t}_{u}", [(f"{date_dict[i['fp']]}{i['fy']}", i['val']) for i in facts[c][t]['units'][u] if i['form'] in ['10-Q'] ] ) for c in facts.keys() for t in facts[c].keys() for u in facts[c][t]['units'].keys() ] filing_data = {'name': cFacts['entityName'], 'cik': cFacts['cik'], '10Q10K': {k:v for k,v in Q10K10_tags_values}, '10K': {k:v for k,v in K10_tags_values}, '10Q': {k:v for k,v in Q10_tags_values} } return filing_data
Просмотр данных
Теперь, когда у вас есть словарь, содержащий все фундаментальные данные из отчетов 10-K и 10-Q, пришло время преобразовать эти данные в форму, на которую мы можем смотреть, не причиняя себе вреда. Просто заполните параметры этой функции данными о регистрации, которые вы только что собрали для конкретной интересующей вас компании, укажите, из какой формы вы хотите просмотреть данные, и включите в данные допуск для значений nan. Например, при извлечении каждого тега (например, EntityCommonStockSharesOutstanding_shares) из файла некоторые теги заполняются значениями nan и только несколькими значениями, отличными от nan. Если вас устраивает 50% значений nan в исходном теге, установите nan_tolerance=50. Если вы сейчас немного запутались, просто поставьте nan_tolerance=20 и назовите это хорошим. Только теги с данными менее 20% будут включены в ваш окончательный фрейм данных.
def convert_dict_to_df(filing_data, form, nan_tolerance=100): ''' filing_data: dict form: lst ['10K'], ['10Q'], or ['10K', '10Q'] nan_tolerance: int a integer from 1 - 100 ''' form_df = pd.DataFrame() if form == ['10K']: tenk = filing_data['10K'] for i in tqdm(tenk.keys()): if len(tenk[i]) > 0: df = pd.DataFrame(tenk[i], columns=['date', i]) df.index = pd.to_datetime(df.date) df = df.drop(columns=['date']) df = df.resample('Y').last() length = len(df) percent_nan = df.isnull().sum() * 100 / length if percent_nan[0] < nan_tolerance: if form_df.empty: form_df = df else: form_df = pd.merge(form_df, df, on=['date'], how='outer') elif form == ['10Q']: tenq = filing_data['10Q'] for i in tqdm(tenq.keys()): if len(tenq[i]) > 0: df = pd.DataFrame(tenq[i], columns=['date', i]) df.index = pd.to_datetime(df.date) df = df.drop(columns=['date']) df = df.resample('Q').last() length = len(df) percent_nan = df.isnull().sum() * 100 / length if percent_nan[0] < nan_tolerance: if form_df.empty: form_df = df else: form_df = pd.merge(form_df, df, on=['date'], how='outer') elif form == ['10Q', '10K'] or form == ['10K', '10Q']: tenqk = filing_data['10Q10K'] for i in tqdm(tenqk.keys()): if len(tenqk[i]) > 0: df = pd.DataFrame(tenqk[i], columns=['date', i]) df.index = pd.to_datetime(df.date) df = df.drop(columns=['date']) df = df.resample('Q').last() length = len(df) percent_nan = df.isnull().sum() * 100 / length if length > 30 and percent_nan[0] < nan_tolerance : if form_df.empty: form_df = df else: form_df = pd.merge(form_df, df, on=['date'], how='outer') else: print("Invalid form.") print("Vaild inputs are ['10K'], ['10Q'], or ['10K', '10Q']") form_df.dropna(axis=1, how='all', inplace=True) form_df.dropna(axis=0, how='all', inplace=True) form_df = form_df.fillna(0) return form_df
Собираем все вместе
Пришло время применить вышеперечисленные функции! Во-первых, SEC требует, чтобы вы указали свой адрес электронной почты в качестве пользовательского агента при отправке запроса на получение их API. Затем мы получим все CIK, выберем один для использования, получим данные о регистрации этой компании и просмотрим данные во фрейме данных pandas.
from tqdm import tqdm import requests import pandas as pd # View Dataframe as an interactive table in Jupyter Notebook from itables import init_notebook_mode init_notebook_mode(all_interactive=True) headers = {'User-Agent': "[email protected]"} cik_lst = get_all_companies(headers) filing_data = get_filing_data_by_cik(cik_lst[1], headers) df = convert_dict_to_df(filing_data, form=['10Q', '10K'], nan_tolerance=20) df
Это все люди! Я оставлю вам несколько мудрых слов моего отца.
«Всегда помните первые два правила работы с данными. 1) Получайте удовольствие! и 2) Получайте удовольствие!»
Пожалуйста, не стесняйтесь комментировать любые вопросы, проблемы или темы, которые вы хотели бы осветить в будущих сообщениях!
Загляните на наш YouTube, где мы подробно разбираем код в наших статьях!
Если вы нашли этот или любой другой наш контент ценным, рассмотрите возможность купить нам кофе.
Получите полный доступ ко всем нашим статьям, став участником Medium!
** ЭТО СОДЕРЖАНИЕ НЕ ЯВЛЯЕТСЯ ФИНАНСОВОЙ КОНСУЛЬТАЦИЕЙ. ЭТО СТРОГО ОБРАЗОВАТЕЛЬНЫЙ **