wbfdm 2.2.1__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.

Files changed (337) hide show
  1. wbfdm/__init__.py +2 -0
  2. wbfdm/admin/__init__.py +42 -0
  3. wbfdm/admin/classifications.py +39 -0
  4. wbfdm/admin/esg.py +23 -0
  5. wbfdm/admin/exchanges.py +53 -0
  6. wbfdm/admin/instrument_lists.py +23 -0
  7. wbfdm/admin/instrument_prices.py +62 -0
  8. wbfdm/admin/instrument_requests.py +33 -0
  9. wbfdm/admin/instruments.py +117 -0
  10. wbfdm/admin/instruments_relationships.py +25 -0
  11. wbfdm/admin/options.py +101 -0
  12. wbfdm/analysis/__init__.py +2 -0
  13. wbfdm/analysis/esg/__init__.py +0 -0
  14. wbfdm/analysis/esg/enums.py +82 -0
  15. wbfdm/analysis/esg/esg_analysis.py +217 -0
  16. wbfdm/analysis/esg/utils.py +13 -0
  17. wbfdm/analysis/financial_analysis/__init__.py +1 -0
  18. wbfdm/analysis/financial_analysis/financial_metric_analysis.py +88 -0
  19. wbfdm/analysis/financial_analysis/financial_ratio_analysis.py +125 -0
  20. wbfdm/analysis/financial_analysis/financial_statistics_analysis.py +271 -0
  21. wbfdm/analysis/financial_analysis/statement_with_estimates.py +558 -0
  22. wbfdm/analysis/financial_analysis/utils.py +316 -0
  23. wbfdm/analysis/technical_analysis/__init__.py +1 -0
  24. wbfdm/analysis/technical_analysis/technical_analysis.py +138 -0
  25. wbfdm/analysis/technical_analysis/traces.py +165 -0
  26. wbfdm/analysis/utils.py +32 -0
  27. wbfdm/apps.py +14 -0
  28. wbfdm/contrib/__init__.py +0 -0
  29. wbfdm/contrib/dsws/__init__.py +0 -0
  30. wbfdm/contrib/dsws/client.py +285 -0
  31. wbfdm/contrib/internal/__init__.py +0 -0
  32. wbfdm/contrib/internal/dataloaders/__init__.py +0 -0
  33. wbfdm/contrib/internal/dataloaders/market_data.py +87 -0
  34. wbfdm/contrib/metric/__init__.py +0 -0
  35. wbfdm/contrib/metric/admin/__init__.py +2 -0
  36. wbfdm/contrib/metric/admin/instruments.py +12 -0
  37. wbfdm/contrib/metric/admin/metrics.py +43 -0
  38. wbfdm/contrib/metric/apps.py +10 -0
  39. wbfdm/contrib/metric/backends/__init__.py +2 -0
  40. wbfdm/contrib/metric/backends/base.py +159 -0
  41. wbfdm/contrib/metric/backends/performances.py +265 -0
  42. wbfdm/contrib/metric/backends/statistics.py +182 -0
  43. wbfdm/contrib/metric/decorators.py +14 -0
  44. wbfdm/contrib/metric/dispatch.py +23 -0
  45. wbfdm/contrib/metric/dto.py +88 -0
  46. wbfdm/contrib/metric/exceptions.py +6 -0
  47. wbfdm/contrib/metric/factories.py +33 -0
  48. wbfdm/contrib/metric/filters.py +28 -0
  49. wbfdm/contrib/metric/migrations/0001_initial.py +88 -0
  50. wbfdm/contrib/metric/migrations/0002_remove_instrumentmetric_unique_instrument_metric_and_more.py +26 -0
  51. wbfdm/contrib/metric/migrations/__init__.py +0 -0
  52. wbfdm/contrib/metric/models.py +180 -0
  53. wbfdm/contrib/metric/orchestrators.py +94 -0
  54. wbfdm/contrib/metric/registry.py +80 -0
  55. wbfdm/contrib/metric/serializers.py +44 -0
  56. wbfdm/contrib/metric/tasks.py +27 -0
  57. wbfdm/contrib/metric/tests/__init__.py +0 -0
  58. wbfdm/contrib/metric/tests/backends/__init__.py +0 -0
  59. wbfdm/contrib/metric/tests/backends/test_performances.py +152 -0
  60. wbfdm/contrib/metric/tests/backends/test_statistics.py +48 -0
  61. wbfdm/contrib/metric/tests/conftest.py +92 -0
  62. wbfdm/contrib/metric/tests/test_dto.py +73 -0
  63. wbfdm/contrib/metric/tests/test_models.py +72 -0
  64. wbfdm/contrib/metric/tests/test_tasks.py +24 -0
  65. wbfdm/contrib/metric/tests/test_viewsets.py +79 -0
  66. wbfdm/contrib/metric/urls.py +19 -0
  67. wbfdm/contrib/metric/viewsets/__init__.py +1 -0
  68. wbfdm/contrib/metric/viewsets/configs/__init__.py +1 -0
  69. wbfdm/contrib/metric/viewsets/configs/display.py +92 -0
  70. wbfdm/contrib/metric/viewsets/configs/menus.py +11 -0
  71. wbfdm/contrib/metric/viewsets/configs/utils.py +137 -0
  72. wbfdm/contrib/metric/viewsets/mixins.py +245 -0
  73. wbfdm/contrib/metric/viewsets/viewsets.py +40 -0
  74. wbfdm/contrib/msci/__init__.py +0 -0
  75. wbfdm/contrib/msci/client.py +92 -0
  76. wbfdm/contrib/msci/dataloaders/__init__.py +0 -0
  77. wbfdm/contrib/msci/dataloaders/esg.py +87 -0
  78. wbfdm/contrib/msci/dataloaders/esg_controversies.py +81 -0
  79. wbfdm/contrib/msci/sync.py +58 -0
  80. wbfdm/contrib/msci/tests/__init__.py +0 -0
  81. wbfdm/contrib/msci/tests/conftest.py +1 -0
  82. wbfdm/contrib/msci/tests/test_client.py +70 -0
  83. wbfdm/contrib/qa/__init__.py +0 -0
  84. wbfdm/contrib/qa/apps.py +22 -0
  85. wbfdm/contrib/qa/database_routers.py +25 -0
  86. wbfdm/contrib/qa/dataloaders/__init__.py +0 -0
  87. wbfdm/contrib/qa/dataloaders/adjustments.py +56 -0
  88. wbfdm/contrib/qa/dataloaders/corporate_actions.py +59 -0
  89. wbfdm/contrib/qa/dataloaders/financials.py +83 -0
  90. wbfdm/contrib/qa/dataloaders/market_data.py +117 -0
  91. wbfdm/contrib/qa/dataloaders/officers.py +59 -0
  92. wbfdm/contrib/qa/dataloaders/reporting_dates.py +67 -0
  93. wbfdm/contrib/qa/dataloaders/statements.py +267 -0
  94. wbfdm/contrib/qa/tasks.py +0 -0
  95. wbfdm/dataloaders/__init__.py +0 -0
  96. wbfdm/dataloaders/cache.py +129 -0
  97. wbfdm/dataloaders/protocols.py +112 -0
  98. wbfdm/dataloaders/proxies.py +201 -0
  99. wbfdm/dataloaders/types.py +209 -0
  100. wbfdm/dynamic_preferences_registry.py +45 -0
  101. wbfdm/enums.py +657 -0
  102. wbfdm/factories/__init__.py +13 -0
  103. wbfdm/factories/classifications.py +56 -0
  104. wbfdm/factories/controversies.py +27 -0
  105. wbfdm/factories/exchanges.py +21 -0
  106. wbfdm/factories/instrument_list.py +22 -0
  107. wbfdm/factories/instrument_prices.py +79 -0
  108. wbfdm/factories/instruments.py +63 -0
  109. wbfdm/factories/instruments_relationships.py +31 -0
  110. wbfdm/factories/options.py +66 -0
  111. wbfdm/figures/__init__.py +1 -0
  112. wbfdm/figures/financials/__init__.py +1 -0
  113. wbfdm/figures/financials/financial_analysis_charts.py +469 -0
  114. wbfdm/figures/financials/financials_charts.py +711 -0
  115. wbfdm/filters/__init__.py +31 -0
  116. wbfdm/filters/classifications.py +100 -0
  117. wbfdm/filters/exchanges.py +22 -0
  118. wbfdm/filters/financials.py +95 -0
  119. wbfdm/filters/financials_analysis.py +119 -0
  120. wbfdm/filters/instrument_prices.py +112 -0
  121. wbfdm/filters/instruments.py +198 -0
  122. wbfdm/filters/utils.py +44 -0
  123. wbfdm/import_export/__init__.py +0 -0
  124. wbfdm/import_export/backends/__init__.py +0 -0
  125. wbfdm/import_export/backends/cbinsights/__init__.py +2 -0
  126. wbfdm/import_export/backends/cbinsights/deals.py +44 -0
  127. wbfdm/import_export/backends/cbinsights/equities.py +41 -0
  128. wbfdm/import_export/backends/cbinsights/mixin.py +15 -0
  129. wbfdm/import_export/backends/cbinsights/utils/__init__.py +0 -0
  130. wbfdm/import_export/backends/cbinsights/utils/classifications.py +4150 -0
  131. wbfdm/import_export/backends/cbinsights/utils/client.py +217 -0
  132. wbfdm/import_export/backends/refinitiv/__init__.py +5 -0
  133. wbfdm/import_export/backends/refinitiv/daily_fundamental.py +36 -0
  134. wbfdm/import_export/backends/refinitiv/fiscal_period.py +63 -0
  135. wbfdm/import_export/backends/refinitiv/forecast.py +178 -0
  136. wbfdm/import_export/backends/refinitiv/fundamental.py +103 -0
  137. wbfdm/import_export/backends/refinitiv/geographic_segment.py +32 -0
  138. wbfdm/import_export/backends/refinitiv/instrument.py +55 -0
  139. wbfdm/import_export/backends/refinitiv/instrument_price.py +77 -0
  140. wbfdm/import_export/backends/refinitiv/mixin.py +29 -0
  141. wbfdm/import_export/backends/refinitiv/utils/__init__.py +1 -0
  142. wbfdm/import_export/backends/refinitiv/utils/controller.py +182 -0
  143. wbfdm/import_export/handlers/__init__.py +0 -0
  144. wbfdm/import_export/handlers/instrument.py +253 -0
  145. wbfdm/import_export/handlers/instrument_list.py +101 -0
  146. wbfdm/import_export/handlers/instrument_price.py +71 -0
  147. wbfdm/import_export/handlers/option.py +54 -0
  148. wbfdm/import_export/handlers/private_equities.py +49 -0
  149. wbfdm/import_export/parsers/__init__.py +0 -0
  150. wbfdm/import_export/parsers/cbinsights/__init__.py +0 -0
  151. wbfdm/import_export/parsers/cbinsights/deals.py +39 -0
  152. wbfdm/import_export/parsers/cbinsights/equities.py +56 -0
  153. wbfdm/import_export/parsers/cbinsights/fundamentals.py +45 -0
  154. wbfdm/import_export/parsers/refinitiv/__init__.py +0 -0
  155. wbfdm/import_export/parsers/refinitiv/daily_fundamental.py +7 -0
  156. wbfdm/import_export/parsers/refinitiv/forecast.py +7 -0
  157. wbfdm/import_export/parsers/refinitiv/fundamental.py +9 -0
  158. wbfdm/import_export/parsers/refinitiv/geographic_segment.py +7 -0
  159. wbfdm/import_export/parsers/refinitiv/instrument.py +75 -0
  160. wbfdm/import_export/parsers/refinitiv/instrument_price.py +26 -0
  161. wbfdm/import_export/parsers/refinitiv/utils.py +96 -0
  162. wbfdm/import_export/resources/__init__.py +0 -0
  163. wbfdm/import_export/resources/classification.py +23 -0
  164. wbfdm/import_export/resources/instrument_prices.py +33 -0
  165. wbfdm/import_export/resources/instruments.py +176 -0
  166. wbfdm/jinja2.py +7 -0
  167. wbfdm/management/__init__.py +30 -0
  168. wbfdm/menu.py +11 -0
  169. wbfdm/migrations/0001_initial.py +71 -0
  170. wbfdm/migrations/0002_rename_statements_instrumentlookup_financials_and_more.py +144 -0
  171. wbfdm/migrations/0003_instrument_estimate_backend_and_more.py +34 -0
  172. wbfdm/migrations/0004_rename_financials_instrumentlookup_statements_and_more.py +86 -0
  173. wbfdm/migrations/0005_instrument_corporate_action_backend.py +29 -0
  174. wbfdm/migrations/0006_instrument_officer_backend.py +29 -0
  175. wbfdm/migrations/0007_instrument_country_instrument_currency_and_more.py +117 -0
  176. wbfdm/migrations/0008_controversy.py +75 -0
  177. wbfdm/migrations/0009_alter_controversy_flag_alter_controversy_initiated_and_more.py +85 -0
  178. wbfdm/migrations/0010_classification_classificationgroup_deal_exchange_and_more.py +1299 -0
  179. wbfdm/migrations/0011_delete_instrumentlookup_instrument_corporate_actions_and_more.py +169 -0
  180. wbfdm/migrations/0012_instrumentprice_created_instrumentprice_modified.py +564 -0
  181. wbfdm/migrations/0013_instrument_is_investable_universe_and_more.py +199 -0
  182. wbfdm/migrations/0014_alter_controversy_instrument.py +22 -0
  183. wbfdm/migrations/0015_instrument_instrument_investible_index.py +16 -0
  184. wbfdm/migrations/0016_instrumenttype_name_repr.py +18 -0
  185. wbfdm/migrations/0017_instrument_instrument_security_index.py +16 -0
  186. wbfdm/migrations/0018_instrument_instrument_level_index.py +20 -0
  187. wbfdm/migrations/0019_alter_controversy_source.py +17 -0
  188. wbfdm/migrations/0020_optionaggregate_option_and_more.py +249 -0
  189. wbfdm/migrations/0021_delete_instrumentdailystatistics.py +15 -0
  190. wbfdm/migrations/0022_instrument_cusip_option_open_interest_20d_and_more.py +91 -0
  191. wbfdm/migrations/0023_instrument_unique_ric_instrument_unique_rmc_and_more.py +53 -0
  192. wbfdm/migrations/0024_option_open_interest_10d_option_volume_10d_and_more.py +36 -0
  193. wbfdm/migrations/0025_instrument_is_primary_and_more.py +29 -0
  194. wbfdm/migrations/0026_instrument_is_cash_equivalent.py +30 -0
  195. wbfdm/migrations/0027_remove_instrument_unique_ric_and_more.py +100 -0
  196. wbfdm/migrations/__init__.py +0 -0
  197. wbfdm/models/__init__.py +4 -0
  198. wbfdm/models/esg/__init__.py +1 -0
  199. wbfdm/models/esg/controversies.py +81 -0
  200. wbfdm/models/exchanges/__init__.py +1 -0
  201. wbfdm/models/exchanges/exchanges.py +223 -0
  202. wbfdm/models/fields.py +117 -0
  203. wbfdm/models/fk_fields.py +403 -0
  204. wbfdm/models/indicators.py +0 -0
  205. wbfdm/models/instruments/__init__.py +19 -0
  206. wbfdm/models/instruments/classifications.py +265 -0
  207. wbfdm/models/instruments/instrument_lists.py +120 -0
  208. wbfdm/models/instruments/instrument_prices.py +540 -0
  209. wbfdm/models/instruments/instrument_relationships.py +251 -0
  210. wbfdm/models/instruments/instrument_requests.py +196 -0
  211. wbfdm/models/instruments/instruments.py +991 -0
  212. wbfdm/models/instruments/llm/__init__.py +1 -0
  213. wbfdm/models/instruments/llm/create_instrument_news_relationships.py +78 -0
  214. wbfdm/models/instruments/mixin/__init__.py +0 -0
  215. wbfdm/models/instruments/mixin/financials_computed.py +804 -0
  216. wbfdm/models/instruments/mixin/financials_serializer_fields.py +1407 -0
  217. wbfdm/models/instruments/mixin/instruments.py +294 -0
  218. wbfdm/models/instruments/options.py +225 -0
  219. wbfdm/models/instruments/private_equities.py +59 -0
  220. wbfdm/models/instruments/querysets.py +73 -0
  221. wbfdm/models/instruments/utils.py +41 -0
  222. wbfdm/preferences.py +21 -0
  223. wbfdm/serializers/__init__.py +4 -0
  224. wbfdm/serializers/esg.py +36 -0
  225. wbfdm/serializers/exchanges.py +39 -0
  226. wbfdm/serializers/instruments/__init__.py +37 -0
  227. wbfdm/serializers/instruments/classifications.py +139 -0
  228. wbfdm/serializers/instruments/instrument_lists.py +61 -0
  229. wbfdm/serializers/instruments/instrument_prices.py +73 -0
  230. wbfdm/serializers/instruments/instrument_relationships.py +170 -0
  231. wbfdm/serializers/instruments/instrument_requests.py +61 -0
  232. wbfdm/serializers/instruments/instruments.py +274 -0
  233. wbfdm/serializers/instruments/mixins.py +104 -0
  234. wbfdm/serializers/officers.py +20 -0
  235. wbfdm/signals.py +7 -0
  236. wbfdm/sync/__init__.py +0 -0
  237. wbfdm/sync/abstract.py +31 -0
  238. wbfdm/sync/runner.py +22 -0
  239. wbfdm/tasks.py +69 -0
  240. wbfdm/tests/__init__.py +0 -0
  241. wbfdm/tests/analysis/__init__.py +0 -0
  242. wbfdm/tests/analysis/financial_analysis/__init__.py +0 -0
  243. wbfdm/tests/analysis/financial_analysis/test_statement_with_estimates.py +392 -0
  244. wbfdm/tests/analysis/financial_analysis/test_utils.py +322 -0
  245. wbfdm/tests/analysis/test_esg.py +159 -0
  246. wbfdm/tests/conftest.py +92 -0
  247. wbfdm/tests/dataloaders/__init__.py +0 -0
  248. wbfdm/tests/dataloaders/test_cache.py +73 -0
  249. wbfdm/tests/models/__init__.py +0 -0
  250. wbfdm/tests/models/test_classifications.py +99 -0
  251. wbfdm/tests/models/test_exchanges.py +7 -0
  252. wbfdm/tests/models/test_instrument_list.py +117 -0
  253. wbfdm/tests/models/test_instrument_prices.py +306 -0
  254. wbfdm/tests/models/test_instruments.py +202 -0
  255. wbfdm/tests/models/test_merge.py +99 -0
  256. wbfdm/tests/models/test_options.py +69 -0
  257. wbfdm/tests/test_tasks.py +6 -0
  258. wbfdm/tests/tests.py +10 -0
  259. wbfdm/urls.py +222 -0
  260. wbfdm/utils.py +54 -0
  261. wbfdm/viewsets/__init__.py +10 -0
  262. wbfdm/viewsets/configs/__init__.py +5 -0
  263. wbfdm/viewsets/configs/buttons/__init__.py +8 -0
  264. wbfdm/viewsets/configs/buttons/classifications.py +23 -0
  265. wbfdm/viewsets/configs/buttons/exchanges.py +9 -0
  266. wbfdm/viewsets/configs/buttons/instrument_prices.py +49 -0
  267. wbfdm/viewsets/configs/buttons/instruments.py +283 -0
  268. wbfdm/viewsets/configs/display/__init__.py +22 -0
  269. wbfdm/viewsets/configs/display/classifications.py +138 -0
  270. wbfdm/viewsets/configs/display/esg.py +75 -0
  271. wbfdm/viewsets/configs/display/exchanges.py +42 -0
  272. wbfdm/viewsets/configs/display/instrument_lists.py +137 -0
  273. wbfdm/viewsets/configs/display/instrument_prices.py +199 -0
  274. wbfdm/viewsets/configs/display/instrument_requests.py +116 -0
  275. wbfdm/viewsets/configs/display/instruments.py +618 -0
  276. wbfdm/viewsets/configs/display/instruments_relationships.py +65 -0
  277. wbfdm/viewsets/configs/display/monthly_performances.py +72 -0
  278. wbfdm/viewsets/configs/display/officers.py +16 -0
  279. wbfdm/viewsets/configs/display/prices.py +21 -0
  280. wbfdm/viewsets/configs/display/statement_with_estimates.py +101 -0
  281. wbfdm/viewsets/configs/display/statements.py +48 -0
  282. wbfdm/viewsets/configs/endpoints/__init__.py +41 -0
  283. wbfdm/viewsets/configs/endpoints/classifications.py +87 -0
  284. wbfdm/viewsets/configs/endpoints/esg.py +20 -0
  285. wbfdm/viewsets/configs/endpoints/exchanges.py +6 -0
  286. wbfdm/viewsets/configs/endpoints/financials_analysis.py +65 -0
  287. wbfdm/viewsets/configs/endpoints/instrument_lists.py +38 -0
  288. wbfdm/viewsets/configs/endpoints/instrument_prices.py +51 -0
  289. wbfdm/viewsets/configs/endpoints/instrument_requests.py +20 -0
  290. wbfdm/viewsets/configs/endpoints/instruments.py +13 -0
  291. wbfdm/viewsets/configs/endpoints/instruments_relationships.py +31 -0
  292. wbfdm/viewsets/configs/endpoints/statements.py +6 -0
  293. wbfdm/viewsets/configs/menus/__init__.py +9 -0
  294. wbfdm/viewsets/configs/menus/classifications.py +19 -0
  295. wbfdm/viewsets/configs/menus/exchanges.py +10 -0
  296. wbfdm/viewsets/configs/menus/instrument_lists.py +10 -0
  297. wbfdm/viewsets/configs/menus/instruments.py +20 -0
  298. wbfdm/viewsets/configs/menus/instruments_relationships.py +33 -0
  299. wbfdm/viewsets/configs/titles/__init__.py +42 -0
  300. wbfdm/viewsets/configs/titles/classifications.py +79 -0
  301. wbfdm/viewsets/configs/titles/esg.py +11 -0
  302. wbfdm/viewsets/configs/titles/exchanges.py +12 -0
  303. wbfdm/viewsets/configs/titles/financial_ratio_analysis.py +6 -0
  304. wbfdm/viewsets/configs/titles/financials_analysis.py +50 -0
  305. wbfdm/viewsets/configs/titles/instrument_prices.py +50 -0
  306. wbfdm/viewsets/configs/titles/instrument_requests.py +16 -0
  307. wbfdm/viewsets/configs/titles/instruments.py +31 -0
  308. wbfdm/viewsets/configs/titles/instruments_relationships.py +21 -0
  309. wbfdm/viewsets/configs/titles/market_data.py +13 -0
  310. wbfdm/viewsets/configs/titles/prices.py +15 -0
  311. wbfdm/viewsets/configs/titles/statement_with_estimates.py +10 -0
  312. wbfdm/viewsets/esg.py +72 -0
  313. wbfdm/viewsets/exchanges.py +63 -0
  314. wbfdm/viewsets/financial_analysis/__init__.py +3 -0
  315. wbfdm/viewsets/financial_analysis/financial_metric_analysis.py +85 -0
  316. wbfdm/viewsets/financial_analysis/financial_ratio_analysis.py +85 -0
  317. wbfdm/viewsets/financial_analysis/statement_with_estimates.py +145 -0
  318. wbfdm/viewsets/instruments/__init__.py +80 -0
  319. wbfdm/viewsets/instruments/classifications.py +279 -0
  320. wbfdm/viewsets/instruments/financials_analysis.py +614 -0
  321. wbfdm/viewsets/instruments/instrument_lists.py +77 -0
  322. wbfdm/viewsets/instruments/instrument_prices.py +542 -0
  323. wbfdm/viewsets/instruments/instrument_requests.py +51 -0
  324. wbfdm/viewsets/instruments/instruments.py +106 -0
  325. wbfdm/viewsets/instruments/instruments_relationships.py +235 -0
  326. wbfdm/viewsets/instruments/utils.py +27 -0
  327. wbfdm/viewsets/market_data.py +172 -0
  328. wbfdm/viewsets/mixins.py +9 -0
  329. wbfdm/viewsets/officers.py +27 -0
  330. wbfdm/viewsets/prices.py +62 -0
  331. wbfdm/viewsets/statements/__init__.py +1 -0
  332. wbfdm/viewsets/statements/statements.py +100 -0
  333. wbfdm/viewsets/technical_analysis/__init__.py +1 -0
  334. wbfdm/viewsets/technical_analysis/monthly_performances.py +93 -0
  335. wbfdm-2.2.1.dist-info/METADATA +15 -0
  336. wbfdm-2.2.1.dist-info/RECORD +337 -0
  337. wbfdm-2.2.1.dist-info/WHEEL +5 -0
@@ -0,0 +1,67 @@
1
+ from typing import Iterator
2
+
3
+ from django.db import connections
4
+ from jinjasql import JinjaSql
5
+ from wbcore.contrib.dataloader.dataloaders import Dataloader
6
+ from wbcore.contrib.dataloader.utils import dictfetchall
7
+ from wbfdm.dataloaders.protocols import ReportDateProtocol
8
+ from wbfdm.dataloaders.types import ReportDateDataDict
9
+
10
+
11
+ class IbesReportingDateDataloader(ReportDateProtocol, Dataloader):
12
+ def reporting_dates(self, only_next: bool = True) -> Iterator[ReportDateDataDict]:
13
+ lookup = {k: v for k, v in self.entities.values_list("dl_parameters__reporting_dates__parameters", "id")}
14
+
15
+ sql = """
16
+ with next_events as (
17
+ select
18
+ *,
19
+ row_number() over (partition by EstPermID, PerType order by PerEndDate) as rn
20
+ from TREExpectedRptDate
21
+ where StartDate > getdate()
22
+ )
23
+
24
+ select
25
+ rp.EstPermID as external_id,
26
+ 'qa-ibes' as source,
27
+ convert(date, rp.PerEndDate) as per_end_date,
28
+ convert(date, rp.StartDate) as start_date,
29
+ convert(date, rp.EndDate) as end_date,
30
+ iif(rp.PerType=4, 0, 1) as interim,
31
+ case
32
+ when rp.MarketPhase = 'AMC' then 'after_market'
33
+ when rp.MarketPhase = 'BMO' then 'before_market'
34
+ else null
35
+ end as market_phase,
36
+ lower(rp.Status) as status
37
+ {% if only_next %}
38
+ from next_events as rp
39
+ {% else %}
40
+ from TREExpectedRptDate as rp
41
+ {% endif %}
42
+ where rp.EstPermID in (
43
+ {% for instrument in instruments %}
44
+ {{instrument}} {% if not loop.last %}, {% endif %}
45
+ {% endfor %}
46
+ )
47
+ {% if only_next %}
48
+ AND rp.rn = 1
49
+ {% endif %}
50
+ """
51
+
52
+ query, bind_params = JinjaSql(param_style="format").prepare_query(
53
+ sql,
54
+ {
55
+ "instruments": lookup.keys(),
56
+ "only_next": only_next,
57
+ },
58
+ )
59
+ with connections["qa"].cursor() as cursor:
60
+ cursor.execute(
61
+ query,
62
+ bind_params,
63
+ )
64
+ for row in dictfetchall(cursor):
65
+ row["instrument_id"] = lookup[row["external_id"]]
66
+ row["interim"] = bool(row["interim"])
67
+ yield row
@@ -0,0 +1,267 @@
1
+ from datetime import date
2
+ from enum import Enum
3
+ from typing import Iterator
4
+
5
+ from django.db import connections
6
+ from jinjasql import JinjaSql # type: ignore
7
+ from wbcore.contrib.dataloader.dataloaders import Dataloader
8
+ from wbcore.contrib.dataloader.utils import dictfetchall
9
+ from wbfdm.dataloaders.protocols import StatementsProtocol
10
+ from wbfdm.dataloaders.types import StatementDataDict
11
+ from wbfdm.enums import DataType, Financial, PeriodType, StatementType
12
+
13
+
14
+ class RKDStatementType(Enum):
15
+ INCOME_STATEMENT = 1
16
+ CASHFLOW_STATEMENT = 2
17
+ BALANCE_SHEET = 3
18
+
19
+
20
+ class RKDFinancial(Enum):
21
+ EMPLOYEES = "METL"
22
+ CASH_AND_SHORT_TERM_INVESTMENT = "SCSI"
23
+ DILUTED_WEIGHTED_AVG_SHARES = "SDWS"
24
+ TOTAL_DEBT = "STLD"
25
+ NET_DEBT = "SNTD"
26
+ STOCK_COMPENSATION = "VSCP"
27
+ TANGIBLE_BOOK_VALUE_PER_SHARE = "STBP"
28
+ REVENUE = "RTLR"
29
+ SHARES_OUTSTANDING = "QTCO"
30
+ EPS = "SDAI"
31
+ CASH_FLOW_FROM_OPERATIONS = "OTLO"
32
+ CAPEX = "SCEX"
33
+
34
+
35
+ reported_sql = """
36
+ SELECT
37
+ CONCAT(val.Code, '-', CONVERT(DATE, val.PerEndDt), '-', fil.InterimNo, '-', val.LineID) as id,
38
+ val.LineID as external_ordering,
39
+ itemsub.Desc_ as external_description,
40
+ itemsub.StdCOA as external_code,
41
+ val.Code as external_identifier,
42
+ CONVERT(DATE, val.PerEndDt) as period_end_date,
43
+ per.Fyr as year,
44
+ fil.InterimNo as interim,
45
+ CASE
46
+ when fil.PerTypeCode = 1 THEN 'Y'
47
+ when fil.PerTypeCode = 2 THEN 'Q'
48
+ when fil.PerTypeCode = 3 THEN 'S'
49
+ when fil.PerTypeCode = 4 THEN 'T'
50
+ when fil.PerTypeCode = 5 THEN 'Q'
51
+ when fil.PerTypeCode = 6 THEN 'Y'
52
+ END as period_type,
53
+ CASE
54
+ WHEN fil.UnitsConvToCode = 'T' AND item.ItemPrecision in (1,2) THEN val.Value_ * 1e3
55
+ WHEN fil.UnitsConvToCode = 'M' AND item.ItemPrecision in (1,2) THEN val.Value_ * 1e6
56
+ WHEN fil.UnitsConvToCode = 'B' AND item.ItemPrecision in (1,2) THEN val.Value_ * 1e9
57
+ ELSE val.Value_
58
+ END as value,
59
+ 'qa-rkd' as source,
60
+ CASE
61
+ WHEN item.IsCurrency = 1 THEN code.Desc_
62
+ ELSE NULL
63
+ END AS currency
64
+
65
+ FROM RKDFndCSFFinVal AS val
66
+
67
+ JOIN RKDFndCSFStmt AS stmt ON
68
+ val.Code = stmt.Code
69
+ AND val.PerEndDt = stmt.PerEndDt
70
+ AND val.PerTypeCode = stmt.PerTypeCode
71
+ AND val.StmtDt = stmt.StmtDt
72
+ AND val.StmtTypeCode = stmt.StmtTypeCode
73
+ AND stmt.CompStmtCode = 1
74
+
75
+ JOIN RKDFndCSFPerFiling AS fil ON
76
+ stmt.Code = fil.Code
77
+ AND stmt.PerEndDt = fil.PerEndDt
78
+ AND stmt.PerTypeCode = fil.PerTypeCode
79
+ AND stmt.StmtDt = fil.StmtDt
80
+
81
+ LEFT JOIN RKDFNDCSFITEMSUB AS itemsub ON
82
+ val.Code = itemsub.Code
83
+ AND val.PerTypeCode = itemsub.PerTypeCode
84
+ AND val.StmtTypeCode = itemsub.StmtTypeCode
85
+ AND val.LineID = itemsub.LineID
86
+
87
+ LEFT JOIN RKDFndCSFItem AS item ON
88
+ itemsub.Item = item.Item
89
+
90
+ LEFT JOIN RKDFndCode AS code ON
91
+ fil.CurrConvToCode = code.Code
92
+ AND code.Type_ = 58
93
+
94
+ LEFT JOIN RKDFndCsfPeriod AS per ON
95
+ per.Code = fil.Code
96
+ AND per.PerEndDt = fil.PerEndDt
97
+ AND per.PerTypeCode = (
98
+ CASE
99
+ WHEN fil.PerTypeCode = 1 THEN 1
100
+ WHEN fil.PerTypeCode in (2,3,4,5) THEN 5
101
+ END
102
+ )
103
+
104
+ WHERE
105
+ val.Code in (
106
+ {% for instrument in instruments %}
107
+ {{instrument}} {% if not loop.last %}, {% endif %}
108
+ {% endfor %})
109
+ AND val.StmtTypeCode = {{ statement_type }}
110
+ {% if from_year %}AND per.Fyr >= {{ from_year }} {% endif %}
111
+ {% if to_year %}AND per.Fyr <= {{ to_year }} {% endif %}
112
+ {% if from_date %}AND val.PerEndDt >= {{ from_date }} {% endif %}
113
+ {% if to_date %}AND val.PerEndDt <= {{ to_date }} {% endif %}
114
+ {% if period_type == 'interim' %}AND fil.InterimNo > 0{% elif period_type == 'annual' %}AND (fil.InterimNo = 0 OR fil.InterimNo IS NULL){% endif %}
115
+ ORDER BY val.LineID
116
+ """
117
+ standardized_sql = """
118
+ SELECT
119
+ CONCAT(val.Code, '-', CONVERT(DATE, val.PerEndDt), '-', fil.InterimNo, '-', item.LineID) as id,
120
+ item.LineID as external_ordering,
121
+ item.Desc_ as external_description,
122
+ item.COA as external_code,
123
+ val.Code as external_identifier,
124
+ CONVERT(DATE, val.PerEndDt) as period_end_date,
125
+ per.Fyr as year,
126
+ CASE
127
+ when fil.PerTypeCode = 1 THEN 'Y'
128
+ when fil.PerTypeCode = 2 THEN 'Q'
129
+ when fil.PerTypeCode = 3 THEN 'S'
130
+ when fil.PerTypeCode = 4 THEN 'T'
131
+ when fil.PerTypeCode = 5 THEN 'Q'
132
+ when fil.PerTypeCode = 6 THEN 'Y'
133
+ END as period_type,
134
+ fil.InterimNo as interim,
135
+ CASE
136
+ WHEN fil.UnitsConvToCode = 'T' AND item.ItemPrecision in (1,2) THEN val.Value_ * 1e3
137
+ WHEN fil.UnitsConvToCode = 'M' AND item.ItemPrecision in (1,2) THEN val.Value_ * 1e6
138
+ WHEN fil.UnitsConvToCode = 'B' AND item.ItemPrecision in (1,2) THEN val.Value_ * 1e9
139
+ ELSE val.Value_
140
+ END as value,
141
+ 'qa-rkd' as source,
142
+ CASE
143
+ WHEN item.IsCurrency = 1 THEN code.Desc_
144
+ ELSE NULL
145
+ END AS currency
146
+
147
+ FROM RKDFndStdFinVal AS val
148
+
149
+ LEFT JOIN RKDFndStdPeriod AS per ON
150
+ per.Code = val.Code
151
+ AND per.PerEndDt = val.PerEndDt
152
+ AND per.PerTypeCode = (
153
+ CASE
154
+ WHEN val.PerTypeCode = 1 THEN 1
155
+ WHEN val.PerTypeCode in (2,3,4,5) THEN 5
156
+ END
157
+ )
158
+ AND per.PerEnddt = (
159
+ SELECT TOP 1 per2.PerEndDt
160
+ FROM RKDFndStdPeriod AS per2
161
+ WHERE per.Code = per2.Code
162
+ AND per.PerTypeCode = per2.PerTypeCode
163
+ AND per.Fyr = per2.Fyr
164
+ AND (
165
+ per2.InterimNo = per.InterimNo
166
+ OR (
167
+ per2.InterimNo IS NULL AND per.InterimNo IS NULL
168
+ )
169
+ )
170
+ ORDER BY per2.PerEndDt DESC
171
+ )
172
+
173
+ JOIN RKDFndStdStmt AS stmt ON
174
+ val.Code = stmt.Code
175
+ AND val.PerEndDt = stmt.PerEndDt
176
+ AND val.PerTypeCode = stmt.PerTypeCode
177
+ AND val.StmtDt = stmt.StmtDt
178
+ AND val.StmtTypeCode = stmt.StmtTypeCode
179
+ AND stmt.CompStmtCode = 1
180
+ AND stmt.StmtDt = (
181
+ select top 1 stmt2.StmtDt
182
+ from RKDFndStdStmt as stmt2
183
+ where stmt2.Code = stmt.Code
184
+ and stmt2.PerEndDt = stmt.PerEndDt
185
+ and stmt2.PerTypeCode = stmt.PerTypeCode
186
+ and stmt2.StmtTypeCode = stmt.StmtTypeCode
187
+ and stmt2.CompStmtCode = stmt.CompStmtCode
188
+ order by stmt2.StmtDt desc
189
+ )
190
+
191
+ JOIN RKDFndStdPerFiling AS fil ON
192
+ stmt.Code = fil.Code
193
+ AND stmt.PerEndDt = fil.PerEndDt
194
+ AND stmt.PerTypeCode = fil.PerTypeCode
195
+ AND stmt.StmtDt = fil.StmtDt
196
+
197
+ LEFT JOIN RKDFndStdItem AS item ON
198
+ val.Item = item.Item
199
+
200
+ LEFT JOIN RKDFndCode AS code ON
201
+ fil.CurrConvToCode = code.Code
202
+ AND code.Type_ = 58
203
+
204
+ WHERE
205
+ val.Code in (
206
+ {% for instrument in instruments %}
207
+ {{instrument}} {% if not loop.last %}, {% endif %}
208
+ {% endfor %})
209
+ {% if statement_type %} AND val.StmtTypeCode = {{ statement_type }}{% endif %}
210
+ {% if from_year %}AND per.Fyr >= {{ from_year }} {% endif %}
211
+ {% if to_year %}AND per.Fyr <= {{ to_year }} {% endif %}
212
+ {% if from_date %}AND val.PerEndDt >= {{ from_date }} {% endif %}
213
+ {% if to_date %}AND val.PerEndDt <= {{ to_date }} {% endif %}
214
+ {% if period_type == 'interim' %}AND fil.InterimNo > 0{% elif period_type == 'annual' %}AND (fil.InterimNo = 0 OR fil.InterimNo IS NULL){% endif %}
215
+ {% if external_codes %}
216
+ AND item.COA in (
217
+ {% for external_code in external_codes %}
218
+ {{ external_code }} {% if not loop.last %}, {% endif %}
219
+ {% endfor %}
220
+ )
221
+ {% endif %}
222
+ ORDER BY item.LineID
223
+ """
224
+
225
+
226
+ class RKDStatementsDataloader(StatementsProtocol, Dataloader):
227
+ def statements(
228
+ self,
229
+ statement_type: StatementType | None = None,
230
+ from_date: date | None = None,
231
+ to_date: date | None = None,
232
+ from_year: int | None = None,
233
+ to_year: int | None = None,
234
+ period_type: PeriodType = PeriodType.ALL,
235
+ data_type: DataType = DataType.STANDARDIZED,
236
+ financials: list[Financial] | None = None,
237
+ target_currency: str | None = None,
238
+ ) -> Iterator[StatementDataDict]:
239
+ lookup = {k: v for k, v in self.entities.values_list("dl_parameters__statements__parameters", "id")}
240
+ sql = reported_sql if data_type is DataType.REPORTED else standardized_sql
241
+ query, bind_params = JinjaSql(param_style="format").prepare_query(
242
+ sql,
243
+ {
244
+ "instruments": lookup.keys(),
245
+ "statement_type": RKDStatementType[statement_type.name].value if statement_type else None,
246
+ "from_year": from_year,
247
+ "to_year": to_year,
248
+ "from_date": from_date,
249
+ "to_date": to_date,
250
+ "period_type": period_type.value,
251
+ "external_codes": [RKDFinancial[fin.name].value for fin in financials or []],
252
+ },
253
+ )
254
+ with connections["qa"].cursor() as cursor:
255
+ cursor.execute(
256
+ query,
257
+ bind_params,
258
+ )
259
+ for row in dictfetchall(cursor):
260
+ if row["interim"] is None:
261
+ row["interim"] = 0
262
+ # sometime we get None for the year. We default to the period end date year then
263
+ row["year"] = int(row["year"] or row["period_end_date"].year)
264
+ row["instrument_id"] = lookup[row["external_identifier"]]
265
+ if financials:
266
+ row["financial"] = Financial[RKDFinancial(row["external_code"]).name].value
267
+ yield row
File without changes
File without changes
@@ -0,0 +1,129 @@
1
+ import itertools
2
+ from typing import Any, Generic, Iterable, TypedDict, TypeVar, cast
3
+
4
+ from django.core.cache import cache
5
+
6
+ T = TypeVar("T", bound=TypedDict)
7
+
8
+
9
+ class Cache(Generic[T]):
10
+ """
11
+ A Cache Class to handle 3-Dimensional data (identifier-key-value)
12
+ """
13
+
14
+ def __init__(
15
+ self,
16
+ identifier_key: str = "instrument_id",
17
+ symbol_key: str = "factor_code",
18
+ value_key: str = "value",
19
+ timeout: int | None = None,
20
+ ):
21
+ """
22
+ Constructor of the Cache Class
23
+ Args:
24
+ identifier_key: The lookup identifier field. Default to `instrument_id`
25
+ symbol_key: The symbol lookup field. Default to `factor_code`
26
+ value_key: The value lookup field. Default to `value`
27
+ timeout: The cache timeout configuration value. Default to None (never expired)
28
+ """
29
+ self.identifier_key = identifier_key
30
+ self.symbol_key = symbol_key
31
+ self.value_key = value_key
32
+ self.timeout = timeout
33
+ self.id_symbol_pairs: list[tuple[str, str]] = []
34
+ self.missing_keys = []
35
+ self.missing_ids = set()
36
+ self.missing_symbols = set()
37
+
38
+ def _get_cache_key(self, id: str, symbol: str) -> str:
39
+ """
40
+ Generate the key used in the caching layer based on the given ID and symbol.
41
+
42
+ Args:
43
+ id (str): The ID to be used in the cache key.
44
+ symbol (str): The symbol to be used in the cache key.
45
+
46
+ Returns:
47
+ str: A cache key in the format "id_symbol" where both the ID and symbol
48
+ are in lowercase.
49
+ """
50
+ return f"{str(id).lower()}_{symbol.lower()}"
51
+
52
+ def _deserialize_cache(self, id: str, symbol: str, value: Any) -> T:
53
+ """
54
+ Data retreived from cache is deserialized using this method. We expect a key value format which is converted into a dictionary with keys as identifier, symbol and value
55
+
56
+ Args:
57
+ id: identifier
58
+ symbol: symbol
59
+ value: value
60
+
61
+ Returns:
62
+ a dictionary with keys as identifier, symbol and value
63
+ """
64
+ res = {self.identifier_key: int(id), self.symbol_key: symbol, self.value_key: value}
65
+ return cast(T, res)
66
+
67
+ def initialize(self, ids: list[int], symbols: list[str]):
68
+ """
69
+ Initialize the instance with a list of IDs and symbols.
70
+
71
+ This method takes a list of identifiers and a list of symbols and creates a list of
72
+ tuples containing all possible pairs of identifiers (converted to strings) and symbols.
73
+ It also initializes sets for symbol and identifiers not present in cache
74
+
75
+ Args:
76
+ ids (list[int]): A list of integer IDs.
77
+ symbols (list[str]): A list of symbol strings.
78
+ """
79
+ self.id_symbol_pairs = list(map(lambda x: (str(x[0]), x[1]), itertools.product(ids, symbols)))
80
+ self.missing_ids = set()
81
+ self.missing_symbols = set()
82
+ self.missing_keys = list()
83
+
84
+ def fetch_from_cache(self) -> Iterable[T]:
85
+ """
86
+ Fetch values already stored in the cache.
87
+
88
+ This method iterates over all identifiers and symbols pair and return the cached value if it exists or mark this pair as missing
89
+
90
+ Yields:
91
+ T: Deserialized cached values.
92
+ """
93
+ sentinel = object()
94
+ for id, symbol in self.id_symbol_pairs:
95
+ key = self._get_cache_key(id, symbol)
96
+ cached_value = cache.get(key, sentinel)
97
+ if cached_value is not None and cached_value is not sentinel:
98
+ yield self._deserialize_cache(id, symbol, cached_value)
99
+ elif (
100
+ cached_value is sentinel
101
+ ): # otherwise, it's literal None and then it means the cache contains "None" for that key
102
+ self.missing_symbols.add(symbol)
103
+ self.missing_ids.add(id)
104
+ self.missing_keys.append(key)
105
+
106
+ def write(self, row: T) -> T:
107
+ """
108
+ Write given row into the cache
109
+
110
+ Args:
111
+ row: a dictionary typed object
112
+
113
+ Returns:
114
+ a dictionary typed object
115
+ """
116
+ if (key := row.get(self.identifier_key)) and (symbol := row.get(self.symbol_key)):
117
+ value = row.get(self.value_key)
118
+ key = self._get_cache_key(str(key), str(symbol))
119
+ cache.set(key, value, timeout=self.timeout)
120
+ if key in self.missing_keys: # mark row's key are "handled"
121
+ self.missing_keys.remove(key)
122
+ return row
123
+
124
+ def close(self):
125
+ """
126
+ Close cache stream by fixing missing keys not handled as None value in the cache (it shows that the value was actually fetched but didn't returned any value)
127
+ """
128
+ for key in self.missing_keys:
129
+ cache.set(key, None, timeout=self.timeout)
@@ -0,0 +1,112 @@
1
+ from datetime import date
2
+ from typing import Iterator, Protocol
3
+
4
+ from wbfdm.dataloaders.types import (
5
+ AdjustmentDataDict,
6
+ CorporateActionDataDict,
7
+ ESGControversyDataDict,
8
+ ESGDataDict,
9
+ FinancialDataDict,
10
+ MarketDataDict,
11
+ OfficerDataDict,
12
+ ReportDateDataDict,
13
+ StatementDataDict,
14
+ )
15
+ from wbfdm.enums import (
16
+ ESG,
17
+ CalendarType,
18
+ DataType,
19
+ EstimateType,
20
+ Financial,
21
+ Frequency,
22
+ MarketData,
23
+ PeriodType,
24
+ SeriesType,
25
+ StatementType,
26
+ )
27
+
28
+
29
+ class ReportDateProtocol(Protocol):
30
+ def reporting_dates(self, only_next: bool = True) -> Iterator[ReportDateDataDict]:
31
+ ...
32
+
33
+
34
+ class AdjustmentsProtocol(Protocol):
35
+ def adjustments(self, from_date: date, to_date: date) -> Iterator[AdjustmentDataDict]:
36
+ ...
37
+
38
+
39
+ class MarketDataProtocol(Protocol):
40
+ def market_data(
41
+ self,
42
+ values: list[MarketData] | None = [MarketData.CLOSE],
43
+ from_date: date | None = None,
44
+ to_date: date | None = None,
45
+ exact_date: date | None = None,
46
+ frequency: Frequency = Frequency.DAILY,
47
+ target_currency: str | None = None,
48
+ ) -> Iterator[MarketDataDict]:
49
+ ...
50
+
51
+
52
+ class CorporateActionsProtocol(Protocol):
53
+ def corporate_actions(
54
+ self, from_date: date | None = None, to_date: date | None = None
55
+ ) -> Iterator[CorporateActionDataDict]:
56
+ ...
57
+
58
+
59
+ class OfficersProtocol(Protocol):
60
+ def officers(self) -> Iterator[OfficerDataDict]:
61
+ ...
62
+
63
+
64
+ class StatementsProtocol(Protocol):
65
+ def statements(
66
+ self,
67
+ statement_type: StatementType | None = None,
68
+ from_date: date | None = None,
69
+ to_date: date | None = None,
70
+ from_year: int | None = None,
71
+ to_year: int | None = None,
72
+ period_type: PeriodType = PeriodType.ALL,
73
+ data_type: DataType = DataType.STANDARDIZED,
74
+ financials: list[Financial] | None = None,
75
+ target_currency: str | None = None,
76
+ ) -> Iterator[StatementDataDict]:
77
+ ...
78
+
79
+
80
+ class FinancialsProtocol(Protocol):
81
+ def financials(
82
+ self,
83
+ values: list[Financial],
84
+ from_date: date | None = None,
85
+ to_date: date | None = None,
86
+ from_year: int | None = None,
87
+ to_year: int | None = None,
88
+ from_index: int | None = None,
89
+ to_index: int | None = None,
90
+ from_valid: date | None = None,
91
+ to_valid: date | None = None,
92
+ period_type: PeriodType = PeriodType.ANNUAL,
93
+ calendar_type: CalendarType = CalendarType.FISCAL,
94
+ series_type: SeriesType = SeriesType.COMPLETE,
95
+ data_type: DataType = DataType.STANDARDIZED,
96
+ estimate_type: EstimateType = EstimateType.VALID,
97
+ target_currency: str | None = None,
98
+ ) -> Iterator[FinancialDataDict]:
99
+ ...
100
+
101
+
102
+ class ESGControversyProtocol(Protocol):
103
+ def esg_controversies(self) -> Iterator[ESGControversyDataDict]:
104
+ ...
105
+
106
+
107
+ class ESGProtocol(Protocol):
108
+ def esg(
109
+ self,
110
+ values: list[ESG],
111
+ ) -> Iterator[ESGDataDict]:
112
+ ...