wbfdm 1.54.21__tar.gz → 1.55.4__tar.gz

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 (367) hide show
  1. {wbfdm-1.54.21 → wbfdm-1.55.4}/PKG-INFO +1 -1
  2. wbfdm-1.55.4/wbfdm/contrib/qa/dataloaders/fx_rates.py +49 -0
  3. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/qa/dataloaders/market_data.py +29 -36
  4. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/qa/dataloaders/statements.py +9 -2
  5. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/dataloaders/protocols.py +10 -0
  6. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/dataloaders/proxies.py +13 -1
  7. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/dataloaders/types.py +6 -0
  8. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/factories/instruments.py +2 -2
  9. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/handlers/option.py +2 -2
  10. wbfdm-1.55.4/wbfdm/migrations/0032_alter_instrumentprice_outstanding_shares.py +18 -0
  11. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/instruments/instrument_prices.py +3 -1
  12. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/instruments/mixin/financials_computed.py +0 -4
  13. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/instruments/querysets.py +4 -5
  14. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/tasks.py +4 -2
  15. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/tests/models/test_instrument_prices.py +0 -14
  16. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/instruments/instrument_prices.py +9 -9
  17. {wbfdm-1.54.21 → wbfdm-1.55.4}/.gitignore +0 -0
  18. {wbfdm-1.54.21 → wbfdm-1.55.4}/pyproject.toml +0 -0
  19. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/__init__.py +0 -0
  20. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/admin/__init__.py +0 -0
  21. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/admin/classifications.py +0 -0
  22. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/admin/esg.py +0 -0
  23. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/admin/exchanges.py +0 -0
  24. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/admin/instrument_lists.py +0 -0
  25. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/admin/instrument_prices.py +0 -0
  26. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/admin/instrument_requests.py +0 -0
  27. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/admin/instruments.py +0 -0
  28. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/admin/instruments_relationships.py +0 -0
  29. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/admin/options.py +0 -0
  30. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/analysis/__init__.py +0 -0
  31. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/analysis/esg/__init__.py +0 -0
  32. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/analysis/esg/enums.py +0 -0
  33. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/analysis/esg/esg_analysis.py +0 -0
  34. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/analysis/esg/utils.py +0 -0
  35. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/analysis/financial_analysis/__init__.py +0 -0
  36. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/analysis/financial_analysis/change_point_detection.py +0 -0
  37. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/analysis/financial_analysis/financial_metric_analysis.py +0 -0
  38. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/analysis/financial_analysis/financial_ratio_analysis.py +0 -0
  39. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/analysis/financial_analysis/financial_statistics_analysis.py +0 -0
  40. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/analysis/financial_analysis/statement_with_estimates.py +0 -0
  41. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/analysis/financial_analysis/utils.py +0 -0
  42. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/analysis/technical_analysis/__init__.py +0 -0
  43. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/analysis/technical_analysis/technical_analysis.py +0 -0
  44. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/analysis/technical_analysis/traces.py +0 -0
  45. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/analysis/utils.py +0 -0
  46. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/apps.py +0 -0
  47. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/backends/dto.py +0 -0
  48. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/__init__.py +0 -0
  49. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/dsws/__init__.py +0 -0
  50. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/dsws/client.py +0 -0
  51. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/dsws/dataloaders/market_data.py +0 -0
  52. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/internal/__init__.py +0 -0
  53. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/internal/dataloaders/__init__.py +0 -0
  54. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/internal/dataloaders/market_data.py +0 -0
  55. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/__init__.py +0 -0
  56. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/admin/__init__.py +0 -0
  57. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/admin/instruments.py +0 -0
  58. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/admin/metrics.py +0 -0
  59. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/apps.py +0 -0
  60. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/backends/__init__.py +0 -0
  61. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/backends/base.py +0 -0
  62. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/backends/performances.py +0 -0
  63. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/backends/statistics.py +0 -0
  64. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/backends/utils.py +0 -0
  65. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/decorators.py +0 -0
  66. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/dispatch.py +0 -0
  67. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/dto.py +0 -0
  68. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/exceptions.py +0 -0
  69. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/factories.py +0 -0
  70. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/filters.py +0 -0
  71. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/migrations/0001_initial.py +0 -0
  72. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/migrations/0002_remove_instrumentmetric_unique_instrument_metric_and_more.py +0 -0
  73. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/migrations/__init__.py +0 -0
  74. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/models.py +0 -0
  75. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/orchestrators.py +0 -0
  76. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/registry.py +0 -0
  77. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/serializers.py +0 -0
  78. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/tasks.py +0 -0
  79. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/tests/__init__.py +0 -0
  80. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/tests/backends/__init__.py +0 -0
  81. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/tests/backends/test_performances.py +0 -0
  82. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/tests/backends/test_statistics.py +0 -0
  83. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/tests/conftest.py +0 -0
  84. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/tests/test_dto.py +0 -0
  85. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/tests/test_models.py +0 -0
  86. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/tests/test_tasks.py +0 -0
  87. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/tests/test_viewsets.py +0 -0
  88. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/urls.py +0 -0
  89. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/viewsets/__init__.py +0 -0
  90. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/viewsets/configs/__init__.py +0 -0
  91. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/viewsets/configs/display.py +0 -0
  92. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/viewsets/configs/menus.py +0 -0
  93. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/viewsets/configs/utils.py +0 -0
  94. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/viewsets/mixins.py +0 -0
  95. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/metric/viewsets/viewsets.py +0 -0
  96. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/msci/__init__.py +0 -0
  97. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/msci/client.py +0 -0
  98. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/msci/dataloaders/__init__.py +0 -0
  99. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/msci/dataloaders/esg.py +0 -0
  100. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/msci/dataloaders/esg_controversies.py +0 -0
  101. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/msci/sync.py +0 -0
  102. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/msci/tests/__init__.py +0 -0
  103. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/msci/tests/conftest.py +0 -0
  104. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/msci/tests/test_client.py +0 -0
  105. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/qa/__init__.py +0 -0
  106. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/qa/apps.py +0 -0
  107. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/qa/database_routers.py +0 -0
  108. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/qa/dataloaders/__init__.py +0 -0
  109. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/qa/dataloaders/adjustments.py +0 -0
  110. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/qa/dataloaders/corporate_actions.py +0 -0
  111. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/qa/dataloaders/financials.py +0 -0
  112. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/qa/dataloaders/officers.py +0 -0
  113. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/qa/dataloaders/reporting_dates.py +0 -0
  114. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/qa/dataloaders/utils.py +0 -0
  115. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/qa/jinja2/qa/sql/companies.sql +0 -0
  116. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/qa/jinja2/qa/sql/ibes/base_estimates.sql +0 -0
  117. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/qa/jinja2/qa/sql/ibes/calendarized.sql +0 -0
  118. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/qa/jinja2/qa/sql/ibes/complete.sql +0 -0
  119. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/qa/jinja2/qa/sql/ibes/estimates.sql +0 -0
  120. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/qa/jinja2/qa/sql/ibes/financials.sql +0 -0
  121. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/qa/jinja2/qa/sql/instruments.sql +0 -0
  122. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/qa/jinja2/qa/sql/quotes.sql +0 -0
  123. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/qa/sync/exchanges.py +0 -0
  124. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/qa/sync/instruments.py +0 -0
  125. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/qa/sync/utils.py +0 -0
  126. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/contrib/qa/tasks.py +0 -0
  127. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/dataloaders/__init__.py +0 -0
  128. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/dataloaders/cache.py +0 -0
  129. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/dynamic_preferences_registry.py +0 -0
  130. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/enums.py +0 -0
  131. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/factories/__init__.py +0 -0
  132. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/factories/classifications.py +0 -0
  133. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/factories/controversies.py +0 -0
  134. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/factories/exchanges.py +0 -0
  135. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/factories/instrument_list.py +0 -0
  136. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/factories/instrument_prices.py +0 -0
  137. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/factories/instruments_relationships.py +0 -0
  138. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/factories/options.py +0 -0
  139. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/figures/__init__.py +0 -0
  140. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/figures/financials/__init__.py +0 -0
  141. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/figures/financials/financial_analysis_charts.py +0 -0
  142. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/figures/financials/financials_charts.py +0 -0
  143. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/filters/__init__.py +0 -0
  144. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/filters/classifications.py +0 -0
  145. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/filters/exchanges.py +0 -0
  146. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/filters/financials.py +0 -0
  147. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/filters/financials_analysis.py +0 -0
  148. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/filters/instrument_prices.py +0 -0
  149. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/filters/instruments.py +0 -0
  150. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/filters/utils.py +0 -0
  151. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/__init__.py +0 -0
  152. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/backends/__init__.py +0 -0
  153. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/backends/cbinsights/__init__.py +0 -0
  154. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/backends/cbinsights/deals.py +0 -0
  155. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/backends/cbinsights/equities.py +0 -0
  156. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/backends/cbinsights/mixin.py +0 -0
  157. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/backends/cbinsights/utils/__init__.py +0 -0
  158. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/backends/cbinsights/utils/classifications.py +0 -0
  159. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/backends/cbinsights/utils/client.py +0 -0
  160. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/backends/refinitiv/__init__.py +0 -0
  161. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/backends/refinitiv/daily_fundamental.py +0 -0
  162. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/backends/refinitiv/fiscal_period.py +0 -0
  163. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/backends/refinitiv/forecast.py +0 -0
  164. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/backends/refinitiv/fundamental.py +0 -0
  165. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/backends/refinitiv/geographic_segment.py +0 -0
  166. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/backends/refinitiv/instrument.py +0 -0
  167. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/backends/refinitiv/instrument_price.py +0 -0
  168. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/backends/refinitiv/mixin.py +0 -0
  169. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/backends/refinitiv/utils/__init__.py +0 -0
  170. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/backends/refinitiv/utils/controller.py +0 -0
  171. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/handlers/__init__.py +0 -0
  172. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/handlers/instrument.py +0 -0
  173. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/handlers/instrument_list.py +0 -0
  174. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/handlers/instrument_price.py +0 -0
  175. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/handlers/private_equities.py +0 -0
  176. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/parsers/__init__.py +0 -0
  177. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/parsers/cbinsights/__init__.py +0 -0
  178. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/parsers/cbinsights/deals.py +0 -0
  179. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/parsers/cbinsights/equities.py +0 -0
  180. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/parsers/cbinsights/fundamentals.py +0 -0
  181. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/parsers/refinitiv/__init__.py +0 -0
  182. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/parsers/refinitiv/daily_fundamental.py +0 -0
  183. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/parsers/refinitiv/forecast.py +0 -0
  184. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/parsers/refinitiv/fundamental.py +0 -0
  185. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/parsers/refinitiv/geographic_segment.py +0 -0
  186. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/parsers/refinitiv/instrument.py +0 -0
  187. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/parsers/refinitiv/instrument_price.py +0 -0
  188. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/parsers/refinitiv/utils.py +0 -0
  189. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/resources/__init__.py +0 -0
  190. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/resources/classification.py +0 -0
  191. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/resources/instrument_prices.py +0 -0
  192. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/import_export/resources/instruments.py +0 -0
  193. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/jinja2.py +0 -0
  194. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/locale/de/LC_MESSAGES/django.mo +0 -0
  195. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/locale/de/LC_MESSAGES/django.po +0 -0
  196. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/locale/en/LC_MESSAGES/django.mo +0 -0
  197. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/locale/en/LC_MESSAGES/django.po +0 -0
  198. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/locale/fr/LC_MESSAGES/django.mo +0 -0
  199. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/locale/fr/LC_MESSAGES/django.po +0 -0
  200. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/management/__init__.py +0 -0
  201. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0001_initial.py +0 -0
  202. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0002_rename_statements_instrumentlookup_financials_and_more.py +0 -0
  203. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0003_instrument_estimate_backend_and_more.py +0 -0
  204. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0004_rename_financials_instrumentlookup_statements_and_more.py +0 -0
  205. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0005_instrument_corporate_action_backend.py +0 -0
  206. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0006_instrument_officer_backend.py +0 -0
  207. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0007_instrument_country_instrument_currency_and_more.py +0 -0
  208. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0008_controversy.py +0 -0
  209. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0009_alter_controversy_flag_alter_controversy_initiated_and_more.py +0 -0
  210. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0010_classification_classificationgroup_deal_exchange_and_more.py +0 -0
  211. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0011_delete_instrumentlookup_instrument_corporate_actions_and_more.py +0 -0
  212. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0012_instrumentprice_created_instrumentprice_modified.py +0 -0
  213. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0013_instrument_is_investable_universe_and_more.py +0 -0
  214. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0014_alter_controversy_instrument.py +0 -0
  215. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0015_instrument_instrument_investible_index.py +0 -0
  216. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0016_instrumenttype_name_repr.py +0 -0
  217. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0017_instrument_instrument_security_index.py +0 -0
  218. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0018_instrument_instrument_level_index.py +0 -0
  219. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0019_alter_controversy_source.py +0 -0
  220. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0020_optionaggregate_option_and_more.py +0 -0
  221. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0021_delete_instrumentdailystatistics.py +0 -0
  222. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0022_instrument_cusip_option_open_interest_20d_and_more.py +0 -0
  223. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0023_instrument_unique_ric_instrument_unique_rmc_and_more.py +0 -0
  224. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0024_option_open_interest_10d_option_volume_10d_and_more.py +0 -0
  225. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0025_instrument_is_primary_and_more.py +0 -0
  226. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0026_instrument_is_cash_equivalent.py +0 -0
  227. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0027_remove_instrument_unique_ric_and_more.py +0 -0
  228. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0028_instrumentprice_annualized_daily_volatility.py +0 -0
  229. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0029_alter_instrumentprice_volume.py +0 -0
  230. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0030_alter_relatedinstrumentthroughmodel_related_type.py +0 -0
  231. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/0031_exchange_apply_round_lot_size_and_more.py +0 -0
  232. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/migrations/__init__.py +0 -0
  233. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/__init__.py +0 -0
  234. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/esg/__init__.py +0 -0
  235. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/esg/controversies.py +0 -0
  236. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/exchanges/__init__.py +0 -0
  237. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/exchanges/exchanges.py +0 -0
  238. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/fields.py +0 -0
  239. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/fk_fields.py +0 -0
  240. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/indicators.py +0 -0
  241. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/instruments/__init__.py +0 -0
  242. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/instruments/classifications.py +0 -0
  243. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/instruments/instrument_lists.py +0 -0
  244. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/instruments/instrument_relationships.py +0 -0
  245. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/instruments/instrument_requests.py +0 -0
  246. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/instruments/instruments.py +0 -0
  247. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/instruments/llm/__init__.py +0 -0
  248. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/instruments/llm/create_instrument_news_relationships.py +0 -0
  249. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/instruments/mixin/__init__.py +0 -0
  250. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/instruments/mixin/financials_serializer_fields.py +0 -0
  251. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/instruments/mixin/instruments.py +0 -0
  252. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/instruments/options.py +0 -0
  253. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/instruments/private_equities.py +0 -0
  254. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/models/instruments/utils.py +0 -0
  255. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/preferences.py +0 -0
  256. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/serializers/__init__.py +0 -0
  257. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/serializers/esg.py +0 -0
  258. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/serializers/exchanges.py +0 -0
  259. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/serializers/instruments/__init__.py +0 -0
  260. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/serializers/instruments/classifications.py +0 -0
  261. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/serializers/instruments/instrument_lists.py +0 -0
  262. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/serializers/instruments/instrument_prices.py +0 -0
  263. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/serializers/instruments/instrument_relationships.py +0 -0
  264. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/serializers/instruments/instrument_requests.py +0 -0
  265. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/serializers/instruments/instruments.py +0 -0
  266. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/serializers/instruments/mixins.py +0 -0
  267. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/serializers/officers.py +0 -0
  268. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/signals.py +0 -0
  269. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/sync/__init__.py +0 -0
  270. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/sync/abstract.py +0 -0
  271. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/sync/runner.py +0 -0
  272. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/tests/__init__.py +0 -0
  273. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/tests/analysis/__init__.py +0 -0
  274. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/tests/analysis/financial_analysis/__init__.py +0 -0
  275. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/tests/analysis/financial_analysis/test_statement_with_estimates.py +0 -0
  276. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/tests/analysis/financial_analysis/test_utils.py +0 -0
  277. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/tests/analysis/test_esg.py +0 -0
  278. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/tests/conftest.py +0 -0
  279. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/tests/dataloaders/__init__.py +0 -0
  280. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/tests/dataloaders/test_cache.py +0 -0
  281. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/tests/models/__init__.py +0 -0
  282. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/tests/models/test_classifications.py +0 -0
  283. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/tests/models/test_exchanges.py +0 -0
  284. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/tests/models/test_instrument_list.py +0 -0
  285. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/tests/models/test_instruments.py +0 -0
  286. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/tests/models/test_merge.py +0 -0
  287. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/tests/models/test_options.py +0 -0
  288. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/tests/models/test_queryset.py +0 -0
  289. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/tests/test_tasks.py +0 -0
  290. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/tests/tests.py +0 -0
  291. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/urls.py +0 -0
  292. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/utils.py +0 -0
  293. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/__init__.py +0 -0
  294. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/__init__.py +0 -0
  295. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/buttons/__init__.py +0 -0
  296. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/buttons/classifications.py +0 -0
  297. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/buttons/exchanges.py +0 -0
  298. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/buttons/instrument_prices.py +0 -0
  299. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/buttons/instruments.py +0 -0
  300. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/display/__init__.py +0 -0
  301. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/display/classifications.py +0 -0
  302. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/display/esg.py +0 -0
  303. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/display/exchanges.py +0 -0
  304. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/display/financial_summary.py +0 -0
  305. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/display/instrument_lists.py +0 -0
  306. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/display/instrument_prices.py +0 -0
  307. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/display/instrument_requests.py +0 -0
  308. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/display/instruments.py +0 -0
  309. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/display/instruments_relationships.py +0 -0
  310. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/display/monthly_performances.py +0 -0
  311. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/display/officers.py +0 -0
  312. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/display/prices.py +0 -0
  313. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/display/statement_with_estimates.py +0 -0
  314. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/display/statements.py +0 -0
  315. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/endpoints/__init__.py +0 -0
  316. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/endpoints/classifications.py +0 -0
  317. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/endpoints/esg.py +0 -0
  318. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/endpoints/exchanges.py +0 -0
  319. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/endpoints/financials_analysis.py +0 -0
  320. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/endpoints/instrument_lists.py +0 -0
  321. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/endpoints/instrument_prices.py +0 -0
  322. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/endpoints/instrument_requests.py +0 -0
  323. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/endpoints/instruments.py +0 -0
  324. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/endpoints/instruments_relationships.py +0 -0
  325. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/endpoints/statements.py +0 -0
  326. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/menus/__init__.py +0 -0
  327. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/menus/classifications.py +0 -0
  328. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/menus/exchanges.py +0 -0
  329. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/menus/instrument_lists.py +0 -0
  330. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/menus/instruments.py +0 -0
  331. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/menus/instruments_relationships.py +0 -0
  332. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/titles/__init__.py +0 -0
  333. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/titles/classifications.py +0 -0
  334. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/titles/esg.py +0 -0
  335. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/titles/exchanges.py +0 -0
  336. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/titles/financial_ratio_analysis.py +0 -0
  337. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/titles/financials_analysis.py +0 -0
  338. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/titles/instrument_prices.py +0 -0
  339. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/titles/instrument_requests.py +0 -0
  340. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/titles/instruments.py +0 -0
  341. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/titles/instruments_relationships.py +0 -0
  342. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/titles/market_data.py +0 -0
  343. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/titles/prices.py +0 -0
  344. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/configs/titles/statement_with_estimates.py +0 -0
  345. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/esg.py +0 -0
  346. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/exchanges.py +0 -0
  347. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/financial_analysis/__init__.py +0 -0
  348. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/financial_analysis/financial_metric_analysis.py +0 -0
  349. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/financial_analysis/financial_ratio_analysis.py +0 -0
  350. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/financial_analysis/financial_summary.py +0 -0
  351. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/financial_analysis/statement_with_estimates.py +0 -0
  352. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/instruments/__init__.py +0 -0
  353. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/instruments/classifications.py +0 -0
  354. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/instruments/financials_analysis.py +0 -0
  355. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/instruments/instrument_lists.py +0 -0
  356. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/instruments/instrument_requests.py +0 -0
  357. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/instruments/instruments.py +0 -0
  358. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/instruments/instruments_relationships.py +0 -0
  359. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/instruments/utils.py +0 -0
  360. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/market_data.py +0 -0
  361. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/mixins.py +0 -0
  362. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/officers.py +0 -0
  363. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/prices.py +0 -0
  364. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/statements/__init__.py +0 -0
  365. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/statements/statements.py +0 -0
  366. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/technical_analysis/__init__.py +0 -0
  367. {wbfdm-1.54.21 → wbfdm-1.55.4}/wbfdm/viewsets/technical_analysis/monthly_performances.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wbfdm
3
- Version: 1.54.21
3
+ Version: 1.55.4
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.*
@@ -0,0 +1,49 @@
1
+ from datetime import date, timedelta
2
+ from typing import Iterator
3
+
4
+ import pypika as pk
5
+ from django.db import connections
6
+ from pypika import Case
7
+ from pypika import functions as fn
8
+ from pypika.enums import Order, SqlTypes
9
+ from wbcore.contrib.dataloader.dataloaders import Dataloader
10
+ from wbcore.contrib.dataloader.utils import dictfetchall
11
+
12
+ from wbfdm.dataloaders.protocols import FXRateProtocol
13
+ from wbfdm.dataloaders.types import FXRateDict
14
+
15
+
16
+ class DatastreamFXRatesDataloader(FXRateProtocol, Dataloader):
17
+ def fx_rates(
18
+ self,
19
+ from_date: date,
20
+ to_date: date,
21
+ target_currency: str,
22
+ ) -> Iterator[FXRateDict]:
23
+ currencies = list(self.entities.values_list("currency__key", flat=True))
24
+ # Define tables
25
+ fx_rate = pk.Table("DS2FxRate")
26
+ fx_code = pk.Table("DS2FxCode")
27
+
28
+ # Base query to get data we always need unconditionally
29
+ query = (
30
+ pk.MSSQLQuery.from_(fx_rate)
31
+ # We join on _codes, which removes all instruments not in _codes - implicit where
32
+ .join(fx_code)
33
+ .on(fx_rate.ExRateIntCode == fx_code.ExRateIntCode)
34
+ .where((fx_rate.ExRateDate >= from_date) & (fx_rate.ExRateDate <= to_date + timedelta(days=1)))
35
+ .where(
36
+ (fx_code.ToCurrCode == target_currency)
37
+ & (fx_code.FromCurrCode.isin(currencies))
38
+ & (fx_code.RateTypeCode == "SPOT")
39
+ )
40
+ .orderby(fx_rate.ExRateDate, order=Order.desc)
41
+ .select(
42
+ fn.Cast(fx_rate.ExRateDate, SqlTypes.DATE).as_("fx_date"),
43
+ fn.Concat(fx_code.FromCurrCode, fx_code.ToCurrCode).as_("currency_pair"),
44
+ (Case().when(fx_code.FromCurrCode == target_currency, 1).else_(1 / fx_rate.midrate)).as_("fx_rate"),
45
+ )
46
+ )
47
+ with connections["qa"].cursor() as cursor:
48
+ cursor.execute(query.get_sql())
49
+ yield from dictfetchall(cursor, FXRateDict)
@@ -1,3 +1,4 @@
1
+ from collections import defaultdict
1
2
  from contextlib import suppress
2
3
  from datetime import date
3
4
  from enum import Enum
@@ -7,13 +8,14 @@ from typing import TYPE_CHECKING, Iterator
7
8
 
8
9
  import pypika as pk
9
10
  from django.db import ProgrammingError, connections
10
- from pypika import Case, Column, MSSQLQuery
11
+ from pypika import Column, MSSQLQuery
11
12
  from pypika import functions as fn
12
13
  from pypika.enums import Order, SqlTypes
13
14
  from pypika.terms import ValueWrapper
14
15
  from wbcore.contrib.dataloader.dataloaders import Dataloader
15
16
  from wbcore.contrib.dataloader.utils import dictfetchall
16
17
 
18
+ from wbfdm.contrib.qa.dataloaders.fx_rates import DatastreamFXRatesDataloader
17
19
  from wbfdm.contrib.qa.dataloaders.utils import create_table
18
20
  from wbfdm.dataloaders.protocols import MarketDataProtocol
19
21
  from wbfdm.dataloaders.types import MarketDataDict
@@ -60,10 +62,19 @@ class DatastreamMarketDataDataloader(MarketDataProtocol, Dataloader):
60
62
  Returns:
61
63
  Iterator[MarketDataDict]: An iterator of dictionaries conforming to the DailyValuationDict.
62
64
  """
63
-
64
65
  lookup = {
65
66
  f"{k[0]},{k[1]}": v for k, v in self.entities.values_list("dl_parameters__market_data__parameters", "id")
66
67
  }
68
+ fx_rates = defaultdict(dict)
69
+ if target_currency:
70
+ if exact_date:
71
+ from_date = exact_date
72
+ to_date = exact_date
73
+ if from_date and to_date:
74
+ for fx_rate in DatastreamFXRatesDataloader(self.entities).fx_rates(
75
+ from_date, to_date, target_currency
76
+ ):
77
+ fx_rates[fx_rate["currency_pair"]][fx_rate["fx_date"]] = fx_rate["fx_rate"]
67
78
 
68
79
  # Define tables
69
80
  pricing = pk.Table("vw_DS2Pricing")
@@ -90,33 +101,7 @@ class DatastreamMarketDataDataloader(MarketDataProtocol, Dataloader):
90
101
  .orderby(pricing.MarketDate, order=Order.desc)
91
102
  )
92
103
 
93
- # if a target currency is required, we join on the fx tables and set the currency to the desired one
94
- # otherwise we just set the currency to whatever the currency is from the instrument
95
- fx_rate = None
96
- if target_currency:
97
- query = query.select(ValueWrapper(target_currency).as_("currency"))
98
- fx_code = pk.Table("DS2FxCode")
99
- fx_rate = pk.Table("DS2FxRate")
100
- query = (
101
- query.select(
102
- (Case().when(pricing.Currency == target_currency, 1).else_(1 / fx_rate.midrate)).as_("fx_rate")
103
- )
104
- # Join FX code table matching currencies and ensuring SPOT rate type
105
- .left_join(fx_code)
106
- .on(
107
- (fx_code.FromCurrCode == pricing.Currency)
108
- & (fx_code.ToCurrCode == target_currency)
109
- & (fx_code.RateTypeCode == "SPOT")
110
- )
111
- # Join FX rate table matching internal code and date
112
- .left_join(fx_rate)
113
- .on((fx_rate.ExRateIntCode == fx_code.ExRateIntCode) & (fx_rate.ExRateDate == pricing.MarketDate))
114
- # We filter out rows which do not have a proper fx rate (we exclude same currency conversions)
115
- .where((Case().when(pricing.Currency == target_currency, 1).else_(fx_rate.midrate).isnotnull()))
116
- )
117
-
118
- else:
119
- query = query.select(pricing.Currency.as_("currency"))
104
+ query = query.select(pricing.Currency.as_("currency"))
120
105
 
121
106
  # if market cap or shares outstanding are required we need to join with an additional table
122
107
  if MarketData.MARKET_CAPITALIZATION in values or MarketData.SHARES_OUTSTANDING in values:
@@ -130,9 +115,6 @@ class DatastreamMarketDataDataloader(MarketDataProtocol, Dataloader):
130
115
  )
131
116
 
132
117
  value = pricing_2.Close_
133
- if fx_rate and apply_fx_rate:
134
- value /= Case().when(pricing_2.Currency == target_currency, 1).else_(fx_rate.midrate)
135
-
136
118
  query = query.select(value.as_("undadjusted_close"))
137
119
  query = query.select(
138
120
  MSSQLQuery.from_(num_shares)
@@ -148,9 +130,6 @@ class DatastreamMarketDataDataloader(MarketDataProtocol, Dataloader):
148
130
  ):
149
131
  ds2_value = DS2MarketData[market_data.name].value
150
132
  value = getattr(pricing, ds2_value)
151
- if fx_rate and apply_fx_rate and market_data is not MarketData.SHARES_OUTSTANDING:
152
- value /= Case().when(pricing.Currency == target_currency, 1).else_(fx_rate.midrate)
153
-
154
133
  query = query.select(value.as_(market_data.value))
155
134
 
156
135
  # Add conditional where clauses
@@ -189,7 +168,21 @@ class DatastreamMarketDataDataloader(MarketDataProtocol, Dataloader):
189
168
 
190
169
  if MarketData.SHARES_OUTSTANDING in values:
191
170
  row["outstanding_shares"] = (row["market_capitalization"] / row["close"]) if row["close"] else None
192
- row["fx_rate"] = row.get("fx_rate", 1.0)
171
+ if target_currency:
172
+ try:
173
+ if target_currency == row["currency"]:
174
+ fx_rate = 1.0
175
+ else:
176
+ fx_rate = fx_rates[f'{row["currency"]}{target_currency}'][row["valuation_date"]] or 1.0
177
+ if apply_fx_rate:
178
+ for e in MarketData:
179
+ if e != MarketData.SHARES_OUTSTANDING and e.value in row and row[e.value]:
180
+ row[e.value] = row[e.value] * fx_rate
181
+ row["currency"] = target_currency
182
+ row["fx_rate"] = fx_rate
183
+ except KeyError:
184
+ # if we don't find the fx rate but we asked for it, we invalid that row and do not return it
185
+ continue
193
186
  yield row
194
187
 
195
188
  cursor.execute(MSSQLQuery.drop_table(mapping).get_sql())
@@ -239,6 +239,10 @@ class RKDStatementsDataloader(StatementsProtocol, Dataloader):
239
239
  ) -> Iterator[StatementDataDict]:
240
240
  lookup = {k: v for k, v in self.entities.values_list("dl_parameters__statements__parameters", "id")}
241
241
  sql = reported_sql if data_type is DataType.REPORTED else standardized_sql
242
+ if not financials:
243
+ financials = []
244
+ external_codes = [RKDFinancial[fin.name].value for fin in financials if fin.name in RKDFinancial.__members__]
245
+
242
246
  query, bind_params = JinjaSql(param_style="format").prepare_query(
243
247
  sql,
244
248
  {
@@ -249,7 +253,7 @@ class RKDStatementsDataloader(StatementsProtocol, Dataloader):
249
253
  "from_date": from_date,
250
254
  "to_date": to_date,
251
255
  "period_type": period_type.value,
252
- "external_codes": [RKDFinancial[fin.name].value for fin in financials or []],
256
+ "external_codes": external_codes,
253
257
  },
254
258
  )
255
259
  with connections["qa"].cursor() as cursor:
@@ -264,5 +268,8 @@ class RKDStatementsDataloader(StatementsProtocol, Dataloader):
264
268
  row["year"] = int(row["year"] or row["period_end_date"].year)
265
269
  row["instrument_id"] = lookup[row["external_identifier"]]
266
270
  if financials:
267
- row["financial"] = Financial[RKDFinancial(row["external_code"]).name].value
271
+ try:
272
+ row["financial"] = Financial[RKDFinancial(row["external_code"]).name].value
273
+ except (ValueError, KeyError):
274
+ continue
268
275
  yield row
@@ -7,6 +7,7 @@ from wbfdm.dataloaders.types import (
7
7
  ESGControversyDataDict,
8
8
  ESGDataDict,
9
9
  FinancialDataDict,
10
+ FXRateDict,
10
11
  MarketDataDict,
11
12
  OfficerDataDict,
12
13
  ReportDateDataDict,
@@ -36,6 +37,15 @@ class AdjustmentsProtocol(Protocol):
36
37
  ) -> Iterator[AdjustmentDataDict]: ...
37
38
 
38
39
 
40
+ class FXRateProtocol(Protocol):
41
+ def fx_rates(
42
+ self,
43
+ from_date: date,
44
+ to_date: date,
45
+ target_currency: str,
46
+ ) -> Iterator[FXRateDict]: ...
47
+
48
+
39
49
  class MarketDataProtocol(Protocol):
40
50
  def market_data(
41
51
  self,
@@ -9,6 +9,7 @@ from wbfdm.dataloaders.protocols import (
9
9
  ESGControversyProtocol,
10
10
  ESGProtocol,
11
11
  FinancialsProtocol,
12
+ FXRateProtocol,
12
13
  MarketDataProtocol,
13
14
  OfficersProtocol,
14
15
  ReportDateProtocol,
@@ -20,6 +21,7 @@ from wbfdm.dataloaders.types import (
20
21
  ESGControversyDataDict,
21
22
  ESGDataDict,
22
23
  FinancialDataDict,
24
+ FXRateDict,
23
25
  MarketDataDict,
24
26
  OfficerDataDict,
25
27
  ReportDateDataDict,
@@ -53,7 +55,8 @@ def _market_data_row_parser(row):
53
55
 
54
56
  class InstrumentDataloaderProxy(
55
57
  DataloaderProxy[
56
- AdjustmentsProtocol
58
+ FXRateProtocol
59
+ | AdjustmentsProtocol
57
60
  | MarketDataProtocol
58
61
  | CorporateActionsProtocol
59
62
  | OfficersProtocol
@@ -68,6 +71,15 @@ class InstrumentDataloaderProxy(
68
71
  for dl in self.iterate_dataloaders("reporting_dates"):
69
72
  yield from dl.reporting_dates(only_next=only_next)
70
73
 
74
+ def fx_rates(
75
+ self,
76
+ from_date: date,
77
+ to_date: date,
78
+ target_currency: str,
79
+ ) -> Iterator[FXRateDict]:
80
+ for dl in self.iterate_dataloaders("fx_rates"):
81
+ yield from dl.fx_rates(from_date, to_date, target_currency)
82
+
71
83
  def adjustments(self, from_date: date | None = None, to_date: date | None = None) -> Iterator[AdjustmentDataDict]:
72
84
  for dl in self.iterate_dataloaders("adjustments"):
73
85
  yield from dl.adjustments(from_date=from_date, to_date=to_date)
@@ -26,6 +26,12 @@ class BaseDict(TypedDict):
26
26
  currency: NotRequired[str]
27
27
 
28
28
 
29
+ class FXRateDict(TypedDict):
30
+ currency_pair: str
31
+ fx_date: date
32
+ fx_rate: float
33
+
34
+
29
35
  class MarketDataDict(BaseDict):
30
36
  """
31
37
  Represents a dictionary for daily valuation data.
@@ -21,7 +21,7 @@ class InstrumentFactory(factory.django.DjangoModelFactory):
21
21
  instrument_type = factory.SubFactory(InstrumentTypeFactory)
22
22
  inception_date = factory.Faker("past_date")
23
23
  delisted_date = None
24
- currency = factory.SubFactory("wbcore.contrib.currency.factories.CurrencyFactory")
24
+ currency = factory.SubFactory("wbcore.contrib.currency.factories.CurrencyUSDFactory")
25
25
  country = factory.SubFactory("wbcore.contrib.geography.factories.CountryFactory")
26
26
  exchange = factory.SubFactory("wbfdm.factories.exchanges.ExchangeFactory")
27
27
 
@@ -54,7 +54,7 @@ class InstrumentFactory(factory.django.DjangoModelFactory):
54
54
 
55
55
  class CashFactory(factory.django.DjangoModelFactory):
56
56
  is_cash = True
57
- currency = factory.SubFactory("wbcore.contrib.currency.factories.CurrencyFactory")
57
+ currency = factory.SubFactory("wbcore.contrib.currency.factories.CurrencyUSDFactory")
58
58
  name = factory.LazyAttribute(lambda o: o.currency.title)
59
59
  instrument_type = factory.LazyAttribute(
60
60
  lambda o: InstrumentType.objects.get_or_create(key="cash", defaults={"name": "Cash", "short_name": "Cash"})[0]
@@ -26,7 +26,7 @@ class OptionAggregateImportHandler(ImportExportHandler):
26
26
 
27
27
  def _get_instance(self, data: Dict[str, Any], history: Optional[models.QuerySet] = None, **kwargs) -> models.Model:
28
28
  with suppress(ObjectDoesNotExist):
29
- return self.model.objects.filter(instrument=data["instrument"], date=data["date"], type=data["type"])
29
+ return self.model.objects.get(instrument=data["instrument"], date=data["date"], type=data["type"])
30
30
 
31
31
 
32
32
  class OptionImportHandler(ImportExportHandler):
@@ -46,7 +46,7 @@ class OptionImportHandler(ImportExportHandler):
46
46
 
47
47
  def _get_instance(self, data: Dict[str, Any], history: Optional[models.QuerySet] = None, **kwargs) -> models.Model:
48
48
  with suppress(ObjectDoesNotExist):
49
- return self.model.objects.filter(
49
+ return self.model.objects.get(
50
50
  instrument=data["instrument"],
51
51
  contract_identifier=data["contract_identifier"],
52
52
  date=data["date"],
@@ -0,0 +1,18 @@
1
+ # Generated by Django 5.0.14 on 2025-08-27 07:59
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('wbfdm', '0031_exchange_apply_round_lot_size_and_more'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterField(
14
+ model_name='instrumentprice',
15
+ name='outstanding_shares',
16
+ field=models.DecimalField(blank=True, decimal_places=4, help_text='The amount of outstanding share for this instrument', max_digits=16, null=True, verbose_name='Outstanding Shares'),
17
+ ),
18
+ ]
@@ -195,9 +195,11 @@ class InstrumentPrice(
195
195
  verbose_name="Value (Gross)",
196
196
  ) # TODO: I think we need to remove this field that is not really used here.
197
197
 
198
- outstanding_shares = DynamicDecimalField(
198
+ outstanding_shares = models.DecimalField(
199
199
  decimal_places=4,
200
200
  max_digits=16,
201
+ blank=True,
202
+ null=True,
201
203
  verbose_name="Outstanding Shares",
202
204
  help_text="The amount of outstanding share for this instrument",
203
205
  )
@@ -697,10 +697,6 @@ import pandas as pd
697
697
  #
698
698
  #
699
699
  class InstrumentPriceComputedMixin:
700
- def _compute_outstanding_shares(self):
701
- if self.outstanding_shares is None and (previous_price := self.previous_price):
702
- return previous_price.outstanding_shares
703
-
704
700
  def _compute_outstanding_shares_consolidated(self):
705
701
  if self.outstanding_shares_consolidated is None and self.outstanding_shares is not None:
706
702
  return self.outstanding_shares
@@ -200,7 +200,7 @@ class InstrumentQuerySet(QuerySet):
200
200
  padded_from_date = from_date - timedelta(days=15)
201
201
  padded_to_date = to_date + timedelta(days=3)
202
202
  logger.info(
203
- f"Loading returns from {from_date:%Y-%m-%d} (padded to {padded_from_date:%Y-%m-%d}) to {to_date:%Y-%m-%d} (padded to {padded_to_date:%Y-%m-%d})"
203
+ f"Loading returns from {from_date:%Y-%m-%d} (padded to {padded_from_date:%Y-%m-%d}) to {to_date:%Y-%m-%d} (padded to {padded_to_date:%Y-%m-%d}) for {self.count()} instruments"
204
204
  )
205
205
 
206
206
  if use_dl:
@@ -248,13 +248,12 @@ class InstrumentQuerySet(QuerySet):
248
248
  (df.index <= pd.Timestamp(to_date)) & (df.index >= pd.Timestamp(from_date))
249
249
  ] # ensure the returned df corresponds to requested date range
250
250
  prices_df = df["close"]
251
-
252
251
  if "fx_rate" in df.columns:
253
252
  fx_rate_df = df["fx_rate"].fillna(1.0)
254
253
  else:
255
254
  fx_rate_df = pd.DataFrame(np.ones(prices_df.shape), index=prices_df.index, columns=prices_df.columns)
256
255
  returns = prices_to_returns(fx_rate_df * prices_df, drop_inceptions_nan=False, fill_nan=True)
257
- return {ts.date(): row for ts, row in prices_df.to_dict("index").items()}, returns.replace(
258
- [np.inf, -np.inf, np.nan], 0
259
- )
256
+ return {
257
+ ts.date(): row for ts, row in prices_df.replace([np.nan], None).to_dict("index").items()
258
+ }, returns.replace([np.inf, -np.inf, np.nan], 0)
260
259
  return {}, pd.DataFrame()
@@ -1,8 +1,9 @@
1
+ from contextlib import suppress
1
2
  from datetime import date, timedelta
2
3
 
3
4
  from celery import shared_task
4
5
  from django.db import transaction
5
- from django.db.models import Q
6
+ from django.db.models import ProtectedError, Q
6
7
  from pandas.tseries.offsets import BDay
7
8
  from tqdm import tqdm
8
9
 
@@ -89,7 +90,8 @@ def full_synchronization_as_task():
89
90
  (Q(name="") & Q(name_repr="")) | (Q(source__in=["qa-ds2-security", "qa-ds2-quote"]) & Q(parent__isnull=True))
90
91
  )
91
92
  for instrument in qs:
92
- instrument.delete()
93
+ with suppress(ProtectedError):
94
+ instrument.delete()
93
95
  initialize_exchanges()
94
96
  initialize_instruments()
95
97
  with transaction.atomic():
@@ -1,10 +1,8 @@
1
1
  from datetime import date
2
- from decimal import Decimal
3
2
 
4
3
  import pandas as pd
5
4
  import pytest
6
5
  from faker import Faker
7
- from pandas.tseries.offsets import BDay
8
6
  from wbcore.models import DynamicDecimalField, DynamicFloatField
9
7
 
10
8
  from wbfdm.models import Instrument, InstrumentPrice, RelatedInstrumentThroughModel
@@ -168,18 +166,6 @@ class TestInstrumentPriceModel:
168
166
  assert isinstance(instrument_price._meta.get_field("gross_value"), DynamicDecimalField)
169
167
  assert instrument_price.gross_value == instrument_price.net_value
170
168
 
171
- @pytest.mark.parametrize("instrument_price__outstanding_shares", [Decimal(10)])
172
- def test_compute_outstanding_shares(self, instrument_price, instrument_price_factory):
173
- next_price = instrument_price_factory.create(
174
- instrument=instrument_price.instrument,
175
- date=instrument_price.date + BDay(1),
176
- outstanding_shares=None,
177
- calculated=instrument_price.calculated,
178
- )
179
- assert hasattr(instrument_price, "_compute_outstanding_shares")
180
- assert isinstance(instrument_price._meta.get_field("outstanding_shares"), DynamicDecimalField)
181
- assert next_price.outstanding_shares == instrument_price.outstanding_shares
182
-
183
169
  @pytest.mark.parametrize("instrument_price__volume_50d", [None])
184
170
  def test_compute_volume_50d(self, instrument_price, instrument_price_factory):
185
171
  assert hasattr(instrument_price, "_compute_volume_50d")
@@ -174,22 +174,22 @@ class InstrumentPriceInstrumentStatisticsChartView(InstrumentMixin, viewsets.Cha
174
174
 
175
175
  if self.instrument.related_instruments.count() > 0:
176
176
  reference = self.instrument.related_instruments.first().name_repr
177
- risk = self.instrument.primary_risk_instrument.name_repr
178
177
  df = pd.DataFrame(queryset.values("date", "sharpe_ratio", "correlation", "beta")).replace(
179
178
  [np.inf, -np.inf], np.nan
180
179
  )
181
180
 
182
181
  if not df.empty:
183
182
  df = df.set_index("date").sort_index().dropna()
184
- fig.add_trace(
185
- go.Scatter(
186
- x=df.index,
187
- y=df.sharpe_ratio,
188
- mode="lines",
189
- name=f"Sharpe Ratio ({risk})",
190
- hovertemplate=get_hovertemplate_timeserie(currency=""),
183
+ if risk_instrument := self.instrument.primary_risk_instrument:
184
+ fig.add_trace(
185
+ go.Scatter(
186
+ x=df.index,
187
+ y=df.sharpe_ratio,
188
+ mode="lines",
189
+ name=f"Sharpe Ratio ({risk_instrument.name_repr})",
190
+ hovertemplate=get_hovertemplate_timeserie(currency=""),
191
+ )
191
192
  )
192
- )
193
193
  fig.add_trace(
194
194
  go.Scatter(
195
195
  x=df.index,
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes