wbfdm 1.43.2__py2.py3-none-any.whl → 1.44.0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of wbfdm might be problematic. Click here for more details.

@@ -192,6 +192,7 @@ class InstrumentModelSerializer(InstrumentAdditionalResourcesMixin, InstrumentMo
192
192
  if not instance.is_managed:
193
193
  res.update(
194
194
  {
195
+ "fin-summary": reverse("wbfdm:financial-summary-list", args=[instance.id], request=request),
195
196
  "swe-income-statement": reverse(
196
197
  "wbfdm:statementwithestimates-list", args=[instance.id, "income"], request=request
197
198
  ),
@@ -380,7 +380,7 @@ class TestStatementWithEstimates:
380
380
  "employees",
381
381
  "stock_compensation_employee_ratio",
382
382
  "capex",
383
- "outstanding_shares",
383
+ "shares_outstanding",
384
384
  "market_capitalization",
385
385
  "close",
386
386
  "market_capitalization",
wbfdm/urls.py CHANGED
@@ -195,6 +195,7 @@ instrument_router.register(
195
195
  )
196
196
  instrument_router.register(r"valuation_ratios", viewsets.ValuationRatioChartViewSet, basename="valuation_ratios")
197
197
  instrument_router.register(r"prices", viewsets.InstrumentPriceViewSet, basename="prices")
198
+ instrument_router.register(r"financial-summary", viewsets.FinancialSummary, basename="financial-summary")
198
199
 
199
200
  instrument_statement_router = WBCoreRouter()
200
201
  instrument_statement_router.register(
@@ -232,7 +232,7 @@ class InstrumentButtonViewConfig(ButtonViewConfig):
232
232
  key="pai",
233
233
  ),
234
234
  ],
235
- )
235
+ ),
236
236
  # bt.DropDownButton(
237
237
  # label="Financial Analysis (Old)",
238
238
  # weight=3,
@@ -20,3 +20,4 @@ from .instruments_relationships import (
20
20
  from .exchanges import ExchangeDisplayConfig
21
21
  from .monthly_performances import MonthlyPerformancesInstrumentDisplayViewConfig
22
22
  from .esg import InstrumentESGPAIDisplayViewConfig, InstrumentESGControversyDisplayViewConfig
23
+ from .financial_summary import FinancialSummaryDisplayViewConfig
@@ -0,0 +1,133 @@
1
+ import typing
2
+
3
+ from wbcore.contrib.color.enums import WBColor
4
+ from wbcore.metadata.configs import display as dp
5
+ from wbcore.metadata.configs.display import DisplayViewConfig
6
+
7
+ if typing.TYPE_CHECKING:
8
+ from wbfdm.viewsets import FinancialSummary
9
+
10
+
11
+ class FinancialSummaryDisplayViewConfig(DisplayViewConfig):
12
+ view: "FinancialSummary"
13
+
14
+ ESTIMATE_COLOR = "#D2E5F6"
15
+
16
+ def get_list_display(self) -> dp.ListDisplay:
17
+ def generate_formatting_rules(col_key: str) -> typing.Iterator[dp.FormattingRule]:
18
+ yield dp.FormattingRule(
19
+ condition=[("==", "eps_growth", "id")],
20
+ style={
21
+ "borderBottom": "1px solid #000000",
22
+ },
23
+ )
24
+ yield dp.FormattingRule(
25
+ condition=[("==", "roic", "id")],
26
+ style={
27
+ "borderBottom": "1px solid #000000",
28
+ },
29
+ )
30
+ yield dp.FormattingRule(
31
+ condition=[("==", "interest_coverage_ratio", "id")],
32
+ style={
33
+ "borderBottom": "1px solid #000000",
34
+ },
35
+ )
36
+ yield dp.FormattingRule(
37
+ condition=[("==", "revenue_growth", "id")],
38
+ style={
39
+ "color": "#9FA0A1",
40
+ "fontStyle": "italic",
41
+ },
42
+ )
43
+ yield dp.FormattingRule(
44
+ condition=[("==", "net_profit_growth", "id")],
45
+ style={
46
+ "color": "#9FA0A1",
47
+ "fontStyle": "italic",
48
+ },
49
+ )
50
+ yield dp.FormattingRule(
51
+ condition=[("==", "eps_growth", "id")],
52
+ style={
53
+ "color": "#9FA0A1",
54
+ "fontStyle": "italic",
55
+ },
56
+ )
57
+ yield dp.FormattingRule(
58
+ condition=[("==", "free_cash_flow_per_share_growth", "id")],
59
+ style={
60
+ "color": "#9FA0A1",
61
+ "fontStyle": "italic",
62
+ },
63
+ )
64
+ yield dp.FormattingRule(
65
+ condition=[("==", "year", "id")],
66
+ style={
67
+ "fontWeight": "bold",
68
+ },
69
+ )
70
+ yield dp.FormattingRule(
71
+ style={"color": WBColor.RED_DARK.value},
72
+ condition=[("<", 0)],
73
+ )
74
+ if self.view.estimate_columns.get(col_key, False) is True:
75
+ yield dp.FormattingRule(style={"background-color": self.ESTIMATE_COLOR})
76
+
77
+ def generate_field(col: str) -> dp.Field:
78
+ return dp.Field(
79
+ key=col,
80
+ label=col,
81
+ width=80,
82
+ formatting_rules=generate_formatting_rules(col),
83
+ auto_size=False,
84
+ resizable=False,
85
+ movable=False,
86
+ menu=False,
87
+ size_to_fit=False,
88
+ )
89
+
90
+ return dp.ListDisplay(
91
+ fields=[
92
+ dp.Field(
93
+ key="label",
94
+ label=" ",
95
+ width=120,
96
+ auto_size=False,
97
+ resizable=False,
98
+ movable=False,
99
+ menu=False,
100
+ size_to_fit=False,
101
+ formatting_rules=[
102
+ dp.FormattingRule(
103
+ condition=[("==", "eps_growth", "id")],
104
+ style={
105
+ "borderBottom": "1px solid #000000",
106
+ },
107
+ ),
108
+ dp.FormattingRule(
109
+ condition=[("==", "roic", "id")],
110
+ style={
111
+ "borderBottom": "1px solid #000000",
112
+ },
113
+ ),
114
+ dp.FormattingRule(
115
+ condition=[("==", "interest_coverage_ratio", "id")],
116
+ style={
117
+ "borderBottom": "1px solid #000000",
118
+ },
119
+ ),
120
+ dp.FormattingRule(style={"background-color": "#ECECEC"}),
121
+ dp.FormattingRule(
122
+ condition=[("==", "year", "id")],
123
+ style={
124
+ "fontWeight": "bold",
125
+ },
126
+ ),
127
+ ],
128
+ ),
129
+ *map(generate_field, self.view.fiscal_columns),
130
+ ],
131
+ condensed=True,
132
+ editable=False,
133
+ )
@@ -17,7 +17,7 @@ from wbcore.metadata.configs.display.instance_display.shortcuts import (
17
17
  default,
18
18
  )
19
19
  from wbcore.metadata.configs.display.instance_display.styles import Style
20
- from wbcore.metadata.configs.display.instance_display.utils import repeat
20
+ from wbcore.metadata.configs.display.instance_display.utils import repeat, repeat_field
21
21
  from wbfdm.contrib.metric.viewsets.configs.utils import (
22
22
  get_performance_fields,
23
23
  get_statistic_field,
@@ -123,19 +123,18 @@ class InstrumentDisplayConfig(DisplayViewConfig):
123
123
  layouts={
124
124
  default(): Layout(
125
125
  grid_template_areas=[
126
- ["name", "name_repr", "market_data", "valuation_ratios-new"],
127
- ["instrument_type", "exchange", "market_data", "valuation_ratios-new"],
128
- ["isin", "ticker", "market_data", "valuation_ratios-new"],
129
- ["currency", "country", "market_data", "valuation_ratios-new"],
130
- ["inception_date", "delisted_date", "market_data", "valuation_ratios-new"],
131
- [".", ".", "market_data", "valuation_ratios-new"],
132
- ["description", "description", "description", "description"],
126
+ ["name", "ticker", "isin", "exchange", "market_data_chart", "valuation_ratios-new"],
127
+ ["name_repr", "instrument_type", "currency", "country", "market_data_chart", "valuation_ratios-new"],
128
+ ["inception_date", "delisted_date", ".", ".", "market_data_chart", "valuation_ratios-new"],
129
+ ["description", "description", "description", "description", "market_data_chart", "valuation_ratios-new"],
130
+ [repeat_field(4, "fin-summary"), repeat_field(2, ".")],
133
131
  ],
134
- grid_template_rows=["auto"] * 6 + ["300px"],
135
- grid_template_columns=["1fr", "1fr", "500px", "500px"],
132
+ grid_template_rows=["min-content"] * 3 + ["1fr", "446px"],
133
+ grid_template_columns=[repeat(4, "183px"), "1fr", "1fr"],
136
134
  inlines=[
137
- Inline(key="market_data", endpoint="market_data"),
138
- Inline(key="valuation_ratios-new", endpoint="valuation_ratios-new"),
135
+ Inline(key="market_data_chart", endpoint="market_data", title="Prices"),
136
+ Inline(key="valuation_ratios-new", endpoint="valuation_ratios-new", title="Ratios"),
137
+ Inline(key="fin-summary", endpoint="fin-summary", title="Financial Summary", hide_controls=True),
139
138
  ],
140
139
  ),
141
140
  },
@@ -1,3 +1,4 @@
1
1
  from .statement_with_estimates import StatementWithEstimatesPandasViewSet
2
2
  from .financial_metric_analysis import FinancialMetricAnalysisPandasViewSet
3
3
  from .financial_ratio_analysis import ValuationRatioChartViewSet
4
+ from .financial_summary import FinancialSummary
@@ -0,0 +1,256 @@
1
+ import pandas as pd
2
+ from django.utils.functional import cached_property
3
+ from wbcore.contrib.io.viewsets import ExportPandasAPIViewSet
4
+ from wbcore.metadata.configs.endpoints import NoEndpointViewConfig
5
+ from wbcore.pandas import fields as pf
6
+ from wbcore.pandas.utils import sanitize_fields, pct_change_with_negative_values
7
+ from wbcore.pandas.utils import (
8
+ override_number_to_decimal,
9
+ override_number_to_percent,
10
+ override_number_to_x,
11
+ override_number_to_integer_without_decorations,
12
+ )
13
+ from wbfdm.enums import Financial
14
+ from wbfdm.models.instruments import Instrument
15
+
16
+ from wbfdm.viewsets.configs.display import (
17
+ FinancialSummaryDisplayViewConfig,
18
+ )
19
+
20
+
21
+ from ..mixins import InstrumentMixin
22
+
23
+
24
+ class FinancialSummary(InstrumentMixin, ExportPandasAPIViewSet):
25
+ queryset = Instrument.objects.none()
26
+ display_config_class = FinancialSummaryDisplayViewConfig
27
+ ordering_fields = "__all__"
28
+ endpoint_config_class = NoEndpointViewConfig
29
+
30
+ def get_queryset(self):
31
+ return Instrument.objects.filter(id=self.instrument.id)
32
+
33
+ def get_pandas_fields(self, request):
34
+ return pf.PandasFields(
35
+ fields=[
36
+ pf.PKField(key="id", label="ID"),
37
+ pf.CharField(key="label", label="Financial"),
38
+ pf.JsonField(key="_overwrites", label="Overwrites"),
39
+ *[pf.FloatField(key=k, label=k, precision=1) for k in self.fiscal_columns],
40
+ ]
41
+ )
42
+
43
+ def get_dataframe(self, request, queryset, **kwargs):
44
+ # Get all necessary data from the dataloader and load a dataframe
45
+ df = pd.DataFrame(
46
+ queryset.dl.financials(
47
+ values=self.FINANCIAL_VALUES,
48
+ from_index=-5,
49
+ to_index=3,
50
+ )
51
+ )
52
+
53
+ # Pivot the data
54
+ df = df.pivot_table(
55
+ columns="financial",
56
+ index=["year", "period_end_date", "estimate"],
57
+ values="value",
58
+ ).rename_axis(columns=None)
59
+
60
+ sanitize_fields(df, map(lambda enum: enum.value, self.FINANCIAL_VALUES))
61
+
62
+ # Compute all necessary fields
63
+ df["revenue_growth"] = df["revenue"].pct_change() * 100
64
+ df["gross_profit_pct"] = df["gross_profit"] / df["revenue"] * 100
65
+ df["ebitda_pct"] = df["ebitda"] / df["revenue"] * 100
66
+ df["ebit_pct"] = df["ebit"] / df["revenue"] * 100
67
+ df["net_income_pct"] = df["net_income"] / df["revenue"] * 100
68
+ df["eps_growth"] = pct_change_with_negative_values(df, "eps") * 100
69
+
70
+ df["net_debt_ebitda"] = df["net_debt"] / df["ebitda"]
71
+ df["debt_assets"] = df["total_debt"] / df["total_assets"] * 100
72
+ df["debt_equity"] = df["total_debt"] / df["total_assets"] * 100
73
+
74
+ df["interest_coverage_ratio"] = df["ebit"] / df["interest_expense"]
75
+ df["free_cash_flow_per_share"] = df["free_cash_flow"] / df["shares_outstanding"]
76
+ df["free_cash_flow_per_share_growth"] = pct_change_with_negative_values(df, "free_cash_flow_per_share") * 100
77
+
78
+ # Normalize data
79
+ df["revenue"] = df["revenue"] / 1_000_000
80
+ df["net_income"] = df["net_income"] / 1_000_000
81
+
82
+ # Sort the columns into the desired order
83
+ # Reset the index to get the period end date as a column
84
+ # Pivot back to have the dates on top
85
+ df = df[self.FIELDS]
86
+
87
+ # Reset the 2 indices and transpose back
88
+ df = df.reset_index(level=[0, 2]).sort_index()
89
+
90
+ # Adjust the columns to be in a different format
91
+ df.index = df.index.map(lambda x: x.strftime("%b/%y"))
92
+ MAX_ROW = 8
93
+ if df.shape[0] > MAX_ROW:
94
+ df = df.iloc[1:] # remove first row
95
+ df = df.iloc[0 : min([df.shape[0], MAX_ROW])] # keep only 8 row maximum
96
+
97
+ self._estimate_columns = df["estimate"].to_dict()
98
+ df = df.drop(columns=["estimate"], errors="ignore")
99
+ return df
100
+
101
+ def manipulate_dataframe(self, df):
102
+ df = df.T
103
+ # Add labels for human readable output
104
+ df["label"] = self.LABELS
105
+
106
+ override_number_to_percent(
107
+ df,
108
+ *list(
109
+ map(
110
+ lambda x: df.index == x,
111
+ [
112
+ "revenue_growth",
113
+ "gross_profit_pct",
114
+ "ebitda_pct",
115
+ "ebit_pct",
116
+ "net_income_pct",
117
+ "eps_growth",
118
+ "roe",
119
+ "roic",
120
+ "roc",
121
+ "roa",
122
+ "debt_equity",
123
+ "debt_assets",
124
+ "free_cash_flow_per_share_growth",
125
+ ],
126
+ )
127
+ ),
128
+ )
129
+
130
+ override_number_to_x(
131
+ df,
132
+ *list(
133
+ map(
134
+ lambda x: df.index == x,
135
+ [
136
+ "net_debt_ebitda",
137
+ "interest_coverage_ratio",
138
+ ],
139
+ )
140
+ ),
141
+ )
142
+
143
+ override_number_to_decimal(
144
+ df,
145
+ *list(
146
+ map(
147
+ lambda x: df.index == x,
148
+ [
149
+ "revenue",
150
+ "net_income",
151
+ ],
152
+ )
153
+ ),
154
+ )
155
+
156
+ override_number_to_integer_without_decorations(
157
+ df,
158
+ *list(
159
+ map(
160
+ lambda x: df.index == x,
161
+ [
162
+ "year",
163
+ ],
164
+ )
165
+ ),
166
+ )
167
+
168
+ return df.reset_index(names="id")
169
+
170
+ @cached_property
171
+ def fiscal_columns(self) -> list:
172
+ """Returns the fiscal columns from the dataframe"""
173
+ return self.df.columns.difference(["label", "_overwrites", "id"]).to_list()
174
+
175
+ @cached_property
176
+ def estimate_columns(self) -> dict:
177
+ """Returns a dictionary with the estimate column for each fiscal column
178
+ The _estimate_columns will be set if the dataframe is constructed.
179
+ """
180
+ return getattr(self, "_estimate_columns", {})
181
+
182
+ @cached_property
183
+ def FINANCIAL_VALUES(self) -> list[Financial]:
184
+ return [
185
+ Financial.REVENUE, # SAL
186
+ Financial.GROSS_PROFIT, # GRI
187
+ Financial.EBITDA, # EBT
188
+ Financial.EBIT, # EBI
189
+ Financial.NET_INCOME, # NET
190
+ Financial.EPS, # EPS
191
+ Financial.SHAREHOLDERS_EQUITY, # SHE
192
+ Financial.TOTAL_ASSETS, # TAS
193
+ Financial.TAX_RATE, # TAX
194
+ Financial.RETURN_ON_INVESTED_CAPITAL, # RIC
195
+ Financial.NET_DEBT, # NDT
196
+ Financial.TOTAL_DEBT, # TDT
197
+ Financial.INTEREST_EXPENSE, # INE
198
+ Financial.FREE_CASH_FLOW, # FCF
199
+ Financial.SHARES_OUTSTANDING,
200
+ Financial.CURRENT_LIABILITIES, # CRL
201
+ Financial.CASH_EQUIVALENTS,
202
+ Financial.RETURN_ON_EQUITY,
203
+ Financial.RETURN_ON_ASSETS,
204
+ Financial.RETURN_ON_CAPITAL,
205
+ Financial.RETURN_ON_INVESTED_CAPITAL,
206
+ ]
207
+
208
+ @cached_property
209
+ def FIELDS(self) -> list[str]:
210
+ return [
211
+ "revenue",
212
+ "revenue_growth",
213
+ "gross_profit_pct",
214
+ "ebitda_pct",
215
+ "ebit_pct",
216
+ "net_income_pct",
217
+ "net_income",
218
+ "eps",
219
+ "eps_growth",
220
+ "roe",
221
+ "roa",
222
+ "roc",
223
+ "roic",
224
+ "net_debt_ebitda",
225
+ "debt_assets",
226
+ "debt_equity",
227
+ "interest_coverage_ratio",
228
+ "free_cash_flow_per_share",
229
+ "free_cash_flow_per_share_growth",
230
+ ]
231
+
232
+ @property
233
+ def LABELS(self) -> list[str]:
234
+ currency_key = self.instrument.currency.key if self.instrument.currency else "N.A."
235
+ return [
236
+ f"in {currency_key} MN",
237
+ "Revenue",
238
+ "Y/Y Change",
239
+ "Gross Margin",
240
+ "EBITDA Margin",
241
+ "EBIT Margin",
242
+ "Net Profit Margin",
243
+ "Net Profit",
244
+ "EPS",
245
+ "Y/Y Change",
246
+ "ROE",
247
+ "ROA",
248
+ "ROC",
249
+ "ROIC",
250
+ "Net Debt/EBITDA",
251
+ "D/A",
252
+ "D/E",
253
+ "Int. Cov. Ratio",
254
+ "FCF per share",
255
+ "Y/Y Change",
256
+ ]
wbfdm/viewsets/mixins.py CHANGED
@@ -4,6 +4,8 @@ from wbfdm.models import Instrument
4
4
 
5
5
 
6
6
  class InstrumentMixin:
7
+ kwargs: dict
8
+
7
9
  @cached_property
8
10
  def instrument(self) -> Instrument:
9
11
  return get_object_or_404(Instrument, pk=self.kwargs["instrument_id"])
@@ -1,9 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wbfdm
3
- Version: 1.43.2
3
+ Version: 1.44.0
4
4
  Summary: The workbench module ensures rapid access to diverse financial data (market, fundamental, forecasts, ESG), with features for storing instruments, classifying them, and conducting financial analysis.
5
5
  Author-email: Christopher Wittlinger <c.wittlinger@stainly.com>
6
6
  Requires-Dist: roman==4.*
7
+ Requires-Dist: sentry-sdk==2.*
7
8
  Requires-Dist: stockstats==0.6.*
8
9
  Requires-Dist: wbcore
9
10
  Requires-Dist: wbnews
@@ -13,3 +14,4 @@ Requires-Dist: requests-cache==1.0.*; extra == 'dsws'
13
14
  Provides-Extra: qa
14
15
  Requires-Dist: jinjasql2==0.1.*; extra == 'qa'
15
16
  Requires-Dist: mssql-django==1.4.*; extra == 'qa'
17
+ Requires-Dist: pypika; extra == 'qa'
@@ -1,13 +1,13 @@
1
1
  wbfdm/__init__.py,sha256=uyfGiipFnhOCQlqywx7wsgp6d-SYnqPqsPQd_xePZl8,23
2
2
  wbfdm/apps.py,sha256=83jiPNQfxUbO7KYKBS5qo5SZNuz25Kmmy_txoVmIKG0,333
3
3
  wbfdm/dynamic_preferences_registry.py,sha256=tE9ZxlQDD7rqKM3GXjxyORQqDjf39GTENkOCZFt8Ixo,1299
4
- wbfdm/enums.py,sha256=ZJ8DtwfujPnLYMwHvWEqAjotF5b1g-mlarGRSeqkJDs,33019
4
+ wbfdm/enums.py,sha256=5AuUouk5uuSNmRc6e-SiBu4FPmHVTN60ol9ftiuVrAc,33041
5
5
  wbfdm/jinja2.py,sha256=pkIC1U-0rf6vn0DDEUzZ8dPYiTGEPY8LBTRMi9wYiuc,199
6
6
  wbfdm/menu.py,sha256=c_uP0wIxboHvY0BfHbYPI9GI4F41UxSgREqbzcaxzHM,399
7
7
  wbfdm/preferences.py,sha256=8ghDcaapOMso1kjtNfKbSFykPUTxzqI5R77gM3BgiMs,927
8
8
  wbfdm/signals.py,sha256=9BQKFURv4iLAvQKagrk0K_3iKrgIveqRaN7jvzyC_Lg,427
9
9
  wbfdm/tasks.py,sha256=gWilvQeIsbPBpWOPJFlAGPrQUPFLtSG_WTfpDibnRBg,2496
10
- wbfdm/urls.py,sha256=p25rDUAB2RNJGiSvhJqlii4wdTytRDmkbtVr7L9Sd-U,8780
10
+ wbfdm/urls.py,sha256=zWtY11MM8YCwtuOakznfQZFMkQhxUAEscI_frzLwjVM,8886
11
11
  wbfdm/utils.py,sha256=4cWrCpqXxHIjtSlt4DDPFvmtaqXw_H0nqhM6sGuXx0o,1938
12
12
  wbfdm/admin/__init__.py,sha256=Z1VtH_gjD71K79KcD-2Q2Lu_p_7j0akMZj7gNxdz1CQ,1398
13
13
  wbfdm/admin/classifications.py,sha256=LwCwHilOO66f4-GSua0eu1RUjtpVdGjN1FevlISwT1A,1140
@@ -30,7 +30,7 @@ wbfdm/analysis/financial_analysis/financial_metric_analysis.py,sha256=ps1z634JO6
30
30
  wbfdm/analysis/financial_analysis/financial_ratio_analysis.py,sha256=M1iLyuxE66TXI4gm_etXMxBK8MGpaOZTiBf0l3e2udo,4622
31
31
  wbfdm/analysis/financial_analysis/financial_statistics_analysis.py,sha256=oxLT_3VgDIStMVOXSp5IE1VHVs4XWTdEaUdZr-L1D9s,13076
32
32
  wbfdm/analysis/financial_analysis/statement_with_estimates.py,sha256=w-V6O3EnO0IZvC8oCzoPJ5jVMDdKCYMmFBrRj7yb2Io,24085
33
- wbfdm/analysis/financial_analysis/utils.py,sha256=ko88qzmt0zv0D1xjvK4OU5VRF7Uu45dRMbXy4DLqLlI,13485
33
+ wbfdm/analysis/financial_analysis/utils.py,sha256=F8ij4pgkw5Qad4_95S32O_Z1vd0rs-GYh-zZpt6WVgM,13576
34
34
  wbfdm/analysis/technical_analysis/__init__.py,sha256=nQdpDl2okzWID6UT7fyfl36RSLNO1ZZzxRt_mkGVVkY,50
35
35
  wbfdm/analysis/technical_analysis/technical_analysis.py,sha256=MkK5HrLz9_TCVAv4qDDZjx6EIqsvusMYB7ybg3MvSsg,4961
36
36
  wbfdm/analysis/technical_analysis/traces.py,sha256=1wzmW7JcQXki0q14TdG36tacZpIFJ_bO4KHx_5TgNxc,6371
@@ -96,13 +96,14 @@ wbfdm/contrib/qa/apps.py,sha256=NVH9FSbJh3XnddR5coJ51jka7nd9wXjwnCqO7h8gNXA,528
96
96
  wbfdm/contrib/qa/database_routers.py,sha256=MIfLEqenhcdgKER4Vl2T-gMudN76rmsDoPrAVesl334,950
97
97
  wbfdm/contrib/qa/tasks.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
98
98
  wbfdm/contrib/qa/dataloaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
99
- wbfdm/contrib/qa/dataloaders/adjustments.py,sha256=_71oYH7jWf4gMSroTtyeuagdiNbpxbDWMHqD2p9vzG4,2220
100
- wbfdm/contrib/qa/dataloaders/corporate_actions.py,sha256=OvoXQjysL9gqDP79j52lzcJm2yTWtd94OmKDW0NGDLA,2276
99
+ wbfdm/contrib/qa/dataloaders/adjustments.py,sha256=am5_9Pm471qtiKRO5AUtQ_19DutqhF8rHcWziMMNptA,2981
100
+ wbfdm/contrib/qa/dataloaders/corporate_actions.py,sha256=jbfQ4GyyPy9mnpBFUHoJSErf7Y6pMlnErE5UUCVpPJA,2912
101
101
  wbfdm/contrib/qa/dataloaders/financials.py,sha256=U2rCUFV0efAPsEEzUq_1gdW0VL-V3fuAM_hpGrJxjko,3474
102
- wbfdm/contrib/qa/dataloaders/market_data.py,sha256=gAzy00nhFWqABG7kjvCfvpyYnehWI-VRtmyyS76-yP0,4880
103
- wbfdm/contrib/qa/dataloaders/officers.py,sha256=QfsMbnlWOhvJc4jyPHJX3STqIwOUqlCCoZddELc405E,2268
102
+ wbfdm/contrib/qa/dataloaders/market_data.py,sha256=6QkOwpOEJdu1d5eYx_d2QEA801hoHUrJdd3GMwS7Itg,5831
103
+ wbfdm/contrib/qa/dataloaders/officers.py,sha256=O14KPWAAtEswOgzRjlN_d-vCyl1unRngejeGYXBu9DU,2942
104
104
  wbfdm/contrib/qa/dataloaders/reporting_dates.py,sha256=Nq83u7eAhsPe9b4ePI5xcgvWEgW1XwHLyVzxpbgcdnQ,2492
105
105
  wbfdm/contrib/qa/dataloaders/statements.py,sha256=tE5ux6bFmAezivssRkm3cNW51lJLoAjHbUao1gR4JMM,10093
106
+ wbfdm/contrib/qa/dataloaders/utils.py,sha256=EyKDh0KDBtj62J_8UHsj3nwCn_R9zGteENUMGHA7DDw,621
106
107
  wbfdm/contrib/qa/jinja2/qa/sql/companies.sql,sha256=RzTkfVjBVOgyirgKxp2rnJdjsKl8d3YM-d2qdjHx9cw,3801
107
108
  wbfdm/contrib/qa/jinja2/qa/sql/instruments.sql,sha256=7p31aJDtKusfSzhrjyUo8FlmbPXNyffWtNclm8DZkFM,3863
108
109
  wbfdm/contrib/qa/jinja2/qa/sql/quotes.sql,sha256=JEljMTlHM4978cvJkiKnKXn09FrcgcQqq4KkwWQUwcM,3910
@@ -116,9 +117,9 @@ wbfdm/contrib/qa/sync/instruments.py,sha256=8aTQVJ_cw1phe4FWikn79pjCfUijaTcwkdhQ
116
117
  wbfdm/contrib/qa/sync/utils.py,sha256=TYZY3QB75POUmme1U71yo6WPzf4AXs4pWpFdI1Hq2GY,8936
117
118
  wbfdm/dataloaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
118
119
  wbfdm/dataloaders/cache.py,sha256=K9BeVxT7p-BMvjurINt18bfrUDccp840uIjfDBLJRNk,4841
119
- wbfdm/dataloaders/protocols.py,sha256=wCBHWPkTGVHMcAJU6VkuwisKyvMNJt1jTsSerJDuX2M,3024
120
- wbfdm/dataloaders/proxies.py,sha256=uydex6hhdwx0R663fYvuiNjnpEJmdUg1UpgNitFsHc8,7043
121
- wbfdm/dataloaders/types.py,sha256=JN3fgOpuE7RRnCDq8eNjk5JQx7KTOgrjNXH7ms36vg4,5347
120
+ wbfdm/dataloaders/protocols.py,sha256=8ibd-jAdlwu-JvRL2LqJMi5mOcWyWYh1Ll_wD4nPJxE,2994
121
+ wbfdm/dataloaders/proxies.py,sha256=u8vV7HpVrTSueXsRF0lweKvfJlEwJSn8F4Z5T_J6ge8,7071
122
+ wbfdm/dataloaders/types.py,sha256=wtXMGbUV-m32EHBCEbO5p3KPCHI87G_V9o9K0DpVgxM,5463
122
123
  wbfdm/factories/__init__.py,sha256=yYxAKBde_ksIr-3g4RjL6d5Wu-nmsuEDdYNyJpgfpQU,660
123
124
  wbfdm/factories/classifications.py,sha256=3xGuvhivIxkTKwZK4uHCNkqzRfsHMUHYLl0yQhlah3Y,1826
124
125
  wbfdm/factories/controversies.py,sha256=bltnEeDetGXsNsz_BqFQoTmLWuqGhq6oZb-aKVrhS-Y,928
@@ -248,7 +249,7 @@ wbfdm/serializers/instruments/instrument_lists.py,sha256=fh2HGrVMP0TPVFMmNA54l-q
248
249
  wbfdm/serializers/instruments/instrument_prices.py,sha256=yU3coJ6M6BWt7PSupBCG509iIIlgRv9zTvnbrKcf5yo,2592
249
250
  wbfdm/serializers/instruments/instrument_relationships.py,sha256=0AkA_gOUTQTaV6dgzqR5doc4rTli-7Grb1_So1b3rPw,6653
250
251
  wbfdm/serializers/instruments/instrument_requests.py,sha256=vAaObfiRJegM44KfevzSOxP8JsfTBzeCigATpi6f9jU,2175
251
- wbfdm/serializers/instruments/instruments.py,sha256=toLTOmwWeVjKyk89-YTGngNjG5PDkeVFctg7kiAVJ34,11494
252
+ wbfdm/serializers/instruments/instruments.py,sha256=itZtcatOkG9L22L2_os8vdFWldimmis7thIUMo1_xuc,11607
252
253
  wbfdm/serializers/instruments/mixins.py,sha256=kxvjgi6zgAeIDkryDm3x3VYtiwP-rk4mcI825RsVXWM,4394
253
254
  wbfdm/sync/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
254
255
  wbfdm/sync/abstract.py,sha256=u1zjHT0ZJabUZpy3_EUCTtEig0p5Fuhlx69O9BsV_Gs,849
@@ -260,7 +261,7 @@ wbfdm/tests/tests.py,sha256=i0CntYKvaHWmdJe34sZMLeKRiHL4uRfhdM30_4gp08Q,253
260
261
  wbfdm/tests/analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
261
262
  wbfdm/tests/analysis/test_esg.py,sha256=_xNg98SlU5i0N0qE3aZ9YU06Ec_fMBdu8q8Hmw116l4,7228
262
263
  wbfdm/tests/analysis/financial_analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
263
- wbfdm/tests/analysis/financial_analysis/test_statement_with_estimates.py,sha256=j6Jm2WcSEAKmBDhczJJxR8Zv9GNiqHlckStwUndzr1w,13664
264
+ wbfdm/tests/analysis/financial_analysis/test_statement_with_estimates.py,sha256=ZZlNiN9L-QlJuqRo7YA9gfad77Jn7dPLz30QHvJax2s,13664
264
265
  wbfdm/tests/analysis/financial_analysis/test_utils.py,sha256=YciCIzfvfqrZECAPv02qtPdxBlKktmAoA2OEuqnAYjw,12474
265
266
  wbfdm/tests/dataloaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
266
267
  wbfdm/tests/dataloaders/test_cache.py,sha256=prrjtJ1swX1m9rwQ30dOHvozUuPzJzi-6yJ8eupczis,2472
@@ -276,7 +277,7 @@ wbfdm/viewsets/__init__.py,sha256=ZM29X0-5AkSH2rzF_gKUI4FoaEWCcMTXPjruJ4Gi_x8,38
276
277
  wbfdm/viewsets/esg.py,sha256=mw6WF2zqifakXEJZWkfgvOHANqCgcNeMH_GP5Je-u0o,2866
277
278
  wbfdm/viewsets/exchanges.py,sha256=w4C50GlG4B6_inkmaDfR8PKOFRxOn-fiucgT-BuBeF4,1784
278
279
  wbfdm/viewsets/market_data.py,sha256=9hCg6PmdJtr7Rs0PVzjGwgG8QysjUd-97DO3ZL8Tkm4,6717
279
- wbfdm/viewsets/mixins.py,sha256=yJSFcALodxU6Oec__HQRjTsrwozKxJmP-VSeFMnCdBU,306
280
+ wbfdm/viewsets/mixins.py,sha256=nKaoC8u4ZR6eMNrNaKbE4BEAnu8wS9IkLYWTDjM3tfE,324
280
281
  wbfdm/viewsets/officers.py,sha256=eE56hOW4xNHytRx3izqkBu2KHEQql2VENT8cmzmzx2E,1058
281
282
  wbfdm/viewsets/prices.py,sha256=O7yL4n1danXgnikYboMaRYsfama_-gJjwNuxx6tCROI,2399
282
283
  wbfdm/viewsets/configs/__init__.py,sha256=2SZRwO-GJF8yxLi6WLfDhMb5-pmOdjdcspdJb6FKgWM,114
@@ -284,15 +285,16 @@ wbfdm/viewsets/configs/buttons/__init__.py,sha256=anGBjblMGGvyAUblYbnpmUulXQaulG
284
285
  wbfdm/viewsets/configs/buttons/classifications.py,sha256=sxfwIItdNGoJ1slnbKmWbxgN5nYq3fzVEUfeNFLebII,823
285
286
  wbfdm/viewsets/configs/buttons/exchanges.py,sha256=2swv3ORAaYF525mXRpp_3zmEl760FJSKYZfsR1ai8KM,255
286
287
  wbfdm/viewsets/configs/buttons/instrument_prices.py,sha256=Tvbbwl8FmXU7vZdhe9n0ICfYO1QkUlw7pD4WSfdSxp0,1873
287
- wbfdm/viewsets/configs/buttons/instruments.py,sha256=6mdp695fdEnD3kbTHq2SKzmvlLhaGhBDI2cZnzlQT2s,12304
288
- wbfdm/viewsets/configs/display/__init__.py,sha256=13H05D9MrOiHuduGmMYMh_rRfUXVJSwmg5oAgTm30-E,959
288
+ wbfdm/viewsets/configs/buttons/instruments.py,sha256=p-E-bw3sxC5fitNfLpn_i8wC0nyk-YUId_GKDFczrLk,12305
289
+ wbfdm/viewsets/configs/display/__init__.py,sha256=9ogNTPHvsuxPf53snrEGFhEPFqcO1sth5PkPBrqAfng,1024
289
290
  wbfdm/viewsets/configs/display/classifications.py,sha256=xolaLg6WDG7Dtwd3gQXWElmyH10GgaT03tL3a3PhKfE,5206
290
291
  wbfdm/viewsets/configs/display/esg.py,sha256=gdo8vz5tW_0Maxd6YTE5ZYakcXm--f89lxwZIxvlIdI,3639
291
292
  wbfdm/viewsets/configs/display/exchanges.py,sha256=uo-rh_20FjreGmqAiPbU0zTZ-I2CoV0bBC4uxX4hQbs,1946
293
+ wbfdm/viewsets/configs/display/financial_summary.py,sha256=K8CPV9uy0wsK-yLQIDTqMAXTb-W1-pUp6OCMwii7jYo,4738
292
294
  wbfdm/viewsets/configs/display/instrument_lists.py,sha256=8-K3PK8AoI8POPo9aAc_3YtDjuFEByAK_I1jNuu0HzQ,5123
293
295
  wbfdm/viewsets/configs/display/instrument_prices.py,sha256=hRXlx1eenm1_LTzWL5xVU1ai4cL2FtYtgg55kMqmFYA,6939
294
296
  wbfdm/viewsets/configs/display/instrument_requests.py,sha256=Er5S2aVEwABgG79mdiyMTQUVueHEeqV5bAS01JMUQ-4,5128
295
- wbfdm/viewsets/configs/display/instruments.py,sha256=7kjLqu4yneEeo6f-uPUWugm2uX8cM-eqtYLUCvd-TOw,16958
297
+ wbfdm/viewsets/configs/display/instruments.py,sha256=_T4YFpQyL1lT7N8fuqkoXhoYcjTPIxzXjZzxnUH-KTw,17088
296
298
  wbfdm/viewsets/configs/display/instruments_relationships.py,sha256=BLAl2ZciWR5Waf3qPd1QQwdiupgIf_wGK6rmYe9byuY,2480
297
299
  wbfdm/viewsets/configs/display/monthly_performances.py,sha256=ESsGTLhPmmXz3YjEWNjwaOjA1RNzVDKtJt3JILL2MMc,2973
298
300
  wbfdm/viewsets/configs/display/officers.py,sha256=qUwN9HPSSlT85aUSFNY-30550P35j3RZCYqRPj_rFAs,654
@@ -329,9 +331,10 @@ wbfdm/viewsets/configs/titles/instruments_relationships.py,sha256=vpgQrXekD64P42
329
331
  wbfdm/viewsets/configs/titles/market_data.py,sha256=YUVC4aFm1oAKFgn_JKqyq--PhXZn-FFRMoFWiB_-1dA,518
330
332
  wbfdm/viewsets/configs/titles/prices.py,sha256=O43pAxiZsfRl6CwJX1hX6zABWKD0a9nQLSaywtNZEBM,382
331
333
  wbfdm/viewsets/configs/titles/statement_with_estimates.py,sha256=ZL4K0hOM0dVBplu76toF4-U3VXBS31gyV3_eTGQYHjE,407
332
- wbfdm/viewsets/financial_analysis/__init__.py,sha256=aSKp3r8v0awMWM5P6K-FShQJJYVvPhorRELd8yqmKAg,215
334
+ wbfdm/viewsets/financial_analysis/__init__.py,sha256=cTTcvGnhz2Ep9RpkyUyTOpjTXJz7BWt1AGAMjiIY9C8,263
333
335
  wbfdm/viewsets/financial_analysis/financial_metric_analysis.py,sha256=ZO3iUExFu5BUK8a_wRu9ldOvRKc70l8Jpdjl2_4hp7s,3315
334
336
  wbfdm/viewsets/financial_analysis/financial_ratio_analysis.py,sha256=YtsSJUnqHjTpiarZcqo14IhWDXF3UXc_zla-slDpqiU,3097
337
+ wbfdm/viewsets/financial_analysis/financial_summary.py,sha256=IxCqGstwDQC4jfv_7111vbZ85FcBLXnhxrrsNOKNAg4,8434
335
338
  wbfdm/viewsets/financial_analysis/statement_with_estimates.py,sha256=1GiSgKZR8iyNK6yJs79eLSt7bo60KQoTv4o3vBsc9xU,6098
336
339
  wbfdm/viewsets/instruments/__init__.py,sha256=uydDdU6oZ6W2lgFkr3-cU7WZU7TeokXAA1J0xEgiLD0,2826
337
340
  wbfdm/viewsets/instruments/classifications.py,sha256=pDQG9rlXUbc4LvWgVOGTir0Dcp02z-78AODNH-SjynA,11440
@@ -346,6 +349,6 @@ wbfdm/viewsets/statements/__init__.py,sha256=odxtFYUDICPmz8WCE3nx93EvKZLSPBEI4d7
346
349
  wbfdm/viewsets/statements/statements.py,sha256=AVU5A7p63uWITEcMDl95iKyN-fBO5RwJlbxHrJZvz7o,4083
347
350
  wbfdm/viewsets/technical_analysis/__init__.py,sha256=qtCIBg0uSiZeJq_1tEQFilnorMBkMe6uCMfqar6-cLE,77
348
351
  wbfdm/viewsets/technical_analysis/monthly_performances.py,sha256=8VgafjW4efEJKTfBqUvAu-EG2eNawl2Cmh9QFt4sN8w,3973
349
- wbfdm-1.43.2.dist-info/METADATA,sha256=LQQVT_3y0lG7hMTdxqXD4aL-hrdA7MfYnWJKblwE3pg,668
350
- wbfdm-1.43.2.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
351
- wbfdm-1.43.2.dist-info/RECORD,,
352
+ wbfdm-1.44.0.dist-info/METADATA,sha256=hQLhyfFZ2TSrNlm_G9_u0VLVdUPmz11yuuFuJq0fTJo,736
353
+ wbfdm-1.44.0.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
354
+ wbfdm-1.44.0.dist-info/RECORD,,
File without changes