summaryrefslogtreecommitdiffstats
path: root/examples/financialStatements.ipynb
blob: 15859f43159f8e00d6170e0365933d1917578d60 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Financial Statements in the OpenBB Platform\n",
    "\n",
    "OpenBB Platform data extensions provide access to financial statements as quarterly or annual.  There are also endpoints for ratios and other common non-GAAP metrics.  Most data providers require a subscription to access all data. Refer to the website of a specific provider for details on entitlements and coverage.\n",
    "\n",
    "Financial statement functions are grouped under the `obb.equity.fundamental` module.\n",
    "\n",
    "## Endpoints\n",
    "\n",
    "The typical financial statements consist of three endpoints:\n",
    "\n",
    "- Balance Sheet: `obb.equity.fundamental.balance()`\n",
    "- Income Statement: `obb.equity.fundamental.income()`\n",
    "- Cash Flow Statement: `obb.equity.fundamental.cash()`\n",
    "\n",
    "The main parameters are:\n",
    "\n",
    "- `symbol`: The company's symbol.\n",
    "- `period`: 'annual' or 'quarter'. Default is 'annual'.\n",
    "- `limit`: Limit the number of results returned, from the latest. Default is 5. For perspective, 150 will go back to 1985. The amount of historical records varies by provider.\n",
    "\n",
    "### Field Names\n",
    "\n",
    "Some considerations to keep in mind when working with financial statements data are:\n",
    "\n",
    "- Every data provider has their own way of parsing and organizing the three financial statements.\n",
    "- Items within each statement will vary by source and by the type of company reporting.\n",
    "- Names of line items will vary by source.\n",
    "- \"Date\" values may differ because they are from the period starting/ending or date of reporting.\n",
    "\n",
    "This example highlights how different providers will have different labels for compnay facts."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from openbb import obb\n",
    "import pandas as pd\n",
    "\n",
    "df = pd.DataFrame()\n",
    "\n",
    "df[\"yfinance\"] = (\n",
    "  obb.equity.fundamental.balance(\"TGT\", provider=\"yfinance\", limit=4)\n",
    "  .to_df()[\"TotalAssets\"].reset_index(drop=True)\n",
    ")\n",
    "\n",
    "df[\"fmp\"] = (\n",
    "  obb.equity.fundamental.balance(\"TGT\", provider=\"fmp\", limit=4)\n",
    "  .to_df()[\"assets\"].convert_dtypes().reset_index(drop=True)\n",
    ")\n",
    "\n",
    "df[\"intrinio\"] = (\n",
    "  obb.equity.fundamental.balance(\"TGT\", provider=\"intrinio\", limit=4)\n",
    "  .to_df()[\"total assets\"].convert_dtypes().reset_index(drop=True)\n",
    ")\n",
    "\n",
    "df[\"polygon\"] = (\n",
    "  obb.equity.fundamental.balance(\"TGT\", provider=\"polygon\", limit=4)\n",
    "  .to_df()[\"total_assets\"].convert_dtypes().reset_index(drop=True)\n",
    ")\n",
    "\n",
    "df\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Weighted Average Shares Outstanding\n",
    "\n",
    "This key metric will be found under the income statement.  It might also be called, 'basic', and the numbers do not include authorized but unissued shares.  A declining count over time is a sign that the company is returning capital to shareholders in the form of buy backs.  Under ideal circumstances, it is more capital-efficient, for both company and shareholders, because distributions are double-taxed.  The company pays income tax on paid dividends, and the beneficiary pays income tax again on receipt.\n",
    "\n",
    "A company will disclose how many shares are outstanding at the end of the period  as a weighted average over the reporting period - three months.\n",
    "\n",
    "Let's take a look at Target.  To make the numbers easier to read, we'll divide the entire column by one million."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "data = (\n",
    "  obb.equity.fundamental.income(\"TGT\", provider=\"fmp\", limit=150, period=\"quarter\")\n",
    "  .to_df()\n",
    ")\n",
    "\n",
    "shares = data[\"weighted_average_shares_outstanding\"]/1000000\n",
    "\n",
    "display(shares.head(1))\n",
    "\n",
    "display(shares.tail(1))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Thirty-seven years later, the share count is approaching a two-thirds reduction.  12.2% over the past five years.  In four reporting periods, 1.3 million shares have been taken out of the float."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "display(shares.pct_change(20).iloc[-1])\n",
    "\n",
    "display(shares.iloc[-4] - shares.iloc[-1])\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "With an average closing price of $143.37, that represents approximately $190M in buy backs."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "price = (\n",
    "  obb.equity.price.historical(\"TGT\", start_date=\"2022-10-01\", provider=\"fmp\")\n",
    "  .to_df()\n",
    ")\n",
    "\n",
    "round((price[\"close\"].mean()*1300000)/1000000, 2)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Dividends Paid\n",
    "\n",
    "Dividends paid is in the cash flow statement.  We can calculate the amount-per-share with the reported data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dividends = (\n",
    "  obb.equity.fundamental.cash(\"TGT\", provider=\"fmp\", limit=150, period=\"quarter\")\n",
    "  .to_df()[[\"dividends_paid\"]]\n",
    ")\n",
    "\n",
    "dividends[\"shares\"] = data[\"weighted_average_shares_outstanding\"]\n",
    "dividends[\"div_per_share\"] = dividends[\"dividends_paid\"]/dividends[\"shares\"]\n",
    "\n",
    "dividends[\"div_per_share\"].tail(4)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This can be compared against the real amounts paid to common share holders, as announced.  Note that the dates above represent the report date, and that dividends paid are attributed to the quarter they were paid in.  The value from \"2023-01-28\" equates to the fourth quarter of 2022."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "(\n",
    "  obb.equity.fundamental.dividends(\"TGT\", provider=\"fmp\")\n",
    "  .to_df()[\"dividend\"]\n",
    "  .loc[\"2022-11-15\":\"2023-08-15\"]\n",
    ")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The numbers check out, and the $2B paid to investors over four quarters is more than ten times the $190M returned through share buy backs.\n",
    "\n",
    "### Financial Attributes\n",
    "\n",
    "The `openbb-intrinio` data extension has an endpoint for extracting a single fact from financial statements.  There is a helper function for looking up the correct `tag`.\n",
    "\n",
    "#### Search Financial Attributes\n",
    "\n",
    "Search attributes by keyword."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "(\n",
    "    obb.equity.fundamental.search_financial_attributes(\"marketcap\")\n",
    "    .to_df()\n",
    ")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `tag` is what we need, in this case it is what we searched for."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "marketcap = (\n",
    "  obb.equity.fundamental.financial_attributes(symbol=\"TGT\", tag = \"marketcap\", period=\"quarter\")\n",
    "  .to_df()\n",
    ")\n",
    "\n",
    "marketcap.tail(5)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Doing some quick math, and ignoring the most recent value, we can see that the market cap of Target was down nearly a quarter over the last four reporting periods."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "(\n",
    "    (marketcap.loc[\"2023-09-30\"] - marketcap.loc[\"2022-12-31\"])/marketcap.loc[\"2022-12-31\"]\n",
    ").value\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Ratios and Other Metrics\n",
    "\n",
    "Other valuation functions are derivatives of the financial statements, but the data provider does the math.  Values are typically ratios between line items, on a per-share basis, or as a percent growth.\n",
    "\n",
    "This data set is where you can find EPS, FCF, P/B, EBIT, quick ratio, etc.\n",
    "\n",
    "### Quick Ratio\n",
    "\n",
    "Target's quick ratio could be one reason why its share price is losing traction against the market.  Its ability to pay current obligations is not optimistically reflected in a 0.27 score, approximately 50% below the historical median."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ratios = (\n",
    "  obb.equity.fundamental.ratios(\"TGT\", limit=50, provider=\"fmp\")\n",
    "  .to_df()\n",
    ")\n",
    "\n",
    "display(f\"Current Quick Ratio: {round(ratios['quick_ratio'].iloc[-1], 4)}\")\n",
    "display(f\"Median Quick Ratio: {round(ratios['quick_ratio'].median(), 4)}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Free Cash Flow Yield\n",
    "\n",
    "The `metrics` endpoint, with the `openbb-fmp` data extension, has a field for free cash flow yield.  It is calculated by taking the free cash flow per share divided by the current share price.  We could arrive at this answer by writing some code, but these types of endpoints do the work so we don't have to.  This is part of the value-add that API data distributors provide, they allow you to get straight to work with data.\n",
    "\n",
    "We'll use this endpoint to extract the data, and compare with some of Target's competition over the last ten years."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# List of other retail chains\n",
    "tickers = [\"COST\", \"BJ\", \"DLTR\", \"DG\", \"WMT\", \"BIG\", \"M\", \"KSS\", \"TJX\"]\n",
    "\n",
    "# Create a dictionary of tickers and company names.\n",
    "names = {\n",
    "    ticker: obb.equity.fundamental.overview(ticker, provider=\"fmp\").results.company_name\n",
    "    for ticker in tickers\n",
    "}\n",
    "# Create a column for each.\n",
    "fcf_yield = pd.DataFrame()\n",
    "for ticker in tickers:\n",
    "    fcf_yield[names[ticker]] = (\n",
    "        obb.equity.fundamental.metrics(ticker, provider=\"fmp\", period=\"annual\", limit=10)\n",
    "        .to_df()\n",
    "        .reset_index()\n",
    "        .set_index(\"calendar_year\")\n",
    "        .sort_index(ascending=False)\n",
    "        [\"free_cash_flow_yield\"]\n",
    "    )\n",
    "fcf_yield.transpose()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There are more usage examples on our [website](https://docs.openbb.co/platform/usage)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "obb-sdk4",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}