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,31 @@
1
+ from .classifications import (
2
+ ClassificationFilter,
3
+ ClassificationTreeChartFilter,
4
+ InstrumentClassificationThroughModelViewFilterSet,
5
+ )
6
+ from .financials_analysis import (
7
+ FinancialAnalysisFilterSet,
8
+ FinancialAnalysisValuationRatiosFilterSet,
9
+ EarningsAnalysisFilterSet,
10
+ GroupKeyFinancialsFilterSet,
11
+ )
12
+ from .instruments import (
13
+ InstrumentFavoriteGroupFilterSet,
14
+ InstrumentFilterSet,
15
+ BaseClassifiedInstrumentFilterSet,
16
+ MonthlyPerformancesInstrumentFilterSet,
17
+ )
18
+ from .instrument_prices import (
19
+ InstrumentPriceFilterSet,
20
+ InstrumentPriceSingleBenchmarkFilterSet,
21
+ InstrumentPriceFrequencyFilter,
22
+ InstrumentPriceFinancialStatisticsChartFilterSet,
23
+ InstrumentPriceInstrumentFilterSet,
24
+ )
25
+ from .exchanges import ExchangeFilterSet
26
+ from .financials import (
27
+ MarketDataChartFilterSet,
28
+ FinancialRatioFilterSet,
29
+ StatementFilter,
30
+ StatementWithEstimateFilter,
31
+ )
@@ -0,0 +1,100 @@
1
+ from wbcore import filters as wb_filters
2
+ from wbfdm.models import (
3
+ Classification,
4
+ ClassificationGroup,
5
+ Instrument,
6
+ InstrumentClassificationThroughModel,
7
+ )
8
+
9
+
10
+ class ClassificationFilter(wb_filters.FilterSet):
11
+ instruments = wb_filters.ModelChoiceFilter(
12
+ label="Instrument",
13
+ queryset=Instrument.objects.all(),
14
+ endpoint=Instrument.get_representation_endpoint(),
15
+ filter_params={"is_classifiable": True},
16
+ value_key=Instrument.get_representation_value_key(),
17
+ label_key=Instrument.get_representation_label_key(),
18
+ )
19
+
20
+ instruments_neq = wb_filters.ModelChoiceFilter(
21
+ label="Instrument not classified in",
22
+ queryset=Instrument.objects.all(),
23
+ endpoint=Instrument.get_representation_endpoint(),
24
+ value_key=Instrument.get_representation_value_key(),
25
+ label_key=Instrument.get_representation_label_key(),
26
+ filter_params={"is_classifiable": True},
27
+ field_name="instruments",
28
+ lookup_expr="exact",
29
+ exclude=True,
30
+ )
31
+
32
+ instrument_type_key = wb_filters.CharFilter(
33
+ label="Instrument Type Key", hidden=True, method="filter_instrument_type_key"
34
+ )
35
+
36
+ def filter_instrument_type_key(self, queryset, name, value):
37
+ if value:
38
+ return queryset.filter(instruments__instrument_type__key=value).distinct()
39
+ return queryset
40
+
41
+ class Meta:
42
+ model = Classification
43
+ fields = {
44
+ "id": ["in"],
45
+ "parent": ["exact"],
46
+ "height": ["gte", "exact", "lte"],
47
+ "level": ["gte", "exact", "lte"],
48
+ "group": ["exact"],
49
+ "level_representation": ["icontains"],
50
+ "name": ["icontains"],
51
+ "code_aggregated": ["icontains", "exact"],
52
+ }
53
+ hidden_fields = ["id__in"]
54
+
55
+
56
+ class ClassificationTreeChartFilter(wb_filters.FilterSet):
57
+ top_classification = wb_filters.ModelChoiceFilter(
58
+ label="Top Classification",
59
+ queryset=Classification.objects.all(),
60
+ endpoint=Classification.get_representation_endpoint(),
61
+ value_key=Classification.get_representation_value_key(),
62
+ label_key=Classification.get_representation_label_key(),
63
+ method="filter_top_classification",
64
+ )
65
+
66
+ aggregation_type = wb_filters.ChoiceFilter(
67
+ choices=[("classification_count", "Classification Count"), ("instrument_count", "Instrument Count")],
68
+ default="classification_count",
69
+ label="Aggregation Type",
70
+ method="fake_filter",
71
+ )
72
+
73
+ def filter_top_classification(self, queryset, name, value):
74
+ if value:
75
+ return queryset.filter(id__in=value.get_descendants().values("id"))
76
+ return queryset
77
+
78
+ class Meta:
79
+ model = Classification
80
+ fields = {}
81
+
82
+
83
+ class InstrumentClassificationThroughModelViewFilterSet(wb_filters.FilterSet):
84
+ classification__group = wb_filters.ModelChoiceFilter(
85
+ label="Group",
86
+ queryset=ClassificationGroup.objects.all(),
87
+ endpoint=ClassificationGroup.get_representation_endpoint(),
88
+ value_key=ClassificationGroup.get_representation_value_key(),
89
+ label_key=ClassificationGroup.get_representation_label_key(),
90
+ )
91
+
92
+ class Meta:
93
+ model = InstrumentClassificationThroughModel
94
+ fields = {
95
+ "instrument": ["exact"],
96
+ "classification": ["exact"],
97
+ "is_favorite": ["exact"],
98
+ "pure_player": ["exact"],
99
+ "top_player": ["exact"],
100
+ }
@@ -0,0 +1,22 @@
1
+ from wbcore import filters as wb_filters
2
+ from wbfdm.models import Exchange
3
+
4
+
5
+ class ExchangeFilterSet(wb_filters.FilterSet):
6
+ class Meta:
7
+ model = Exchange
8
+ fields = {
9
+ "name": ["exact", "icontains"],
10
+ "mic_code": ["exact", "icontains"],
11
+ "operating_mic_code": ["exact", "icontains"],
12
+ "bbg_composite_primary": ["exact"],
13
+ "bbg_composite": ["exact", "icontains"],
14
+ "refinitiv_identifier_code": ["exact", "icontains"],
15
+ "refinitiv_mnemonic": ["exact", "icontains"],
16
+ "country": ["exact"],
17
+ "city": ["exact"],
18
+ "website": ["exact", "icontains"],
19
+ "comments": ["exact", "icontains"],
20
+ "opening_time": ["exact", "gte", "lte"],
21
+ "closing_time": ["exact", "gte", "lte"],
22
+ }
@@ -0,0 +1,95 @@
1
+ from wbcore import filters
2
+ from wbcore.filters.defaults import five_year_data_range
3
+ from wbfdm.enums import CalendarType, DataType, Indicator, MarketDataChartType
4
+ from wbfdm.models.instruments import Instrument
5
+
6
+
7
+ class MarketDataChartFilterSet(filters.FilterSet):
8
+ period = filters.FinancialPerformanceDateRangeFilter(
9
+ label="Period",
10
+ method="fake_filter",
11
+ default=five_year_data_range,
12
+ )
13
+ chart_type = filters.ChoiceFilter(
14
+ method="fake_filter",
15
+ label="Chart Type",
16
+ choices=MarketDataChartType.choices,
17
+ default="close",
18
+ )
19
+ benchmarks = filters.ModelMultipleChoiceFilter(
20
+ label="Benchmarks",
21
+ queryset=Instrument.objects.all(),
22
+ endpoint=Instrument.get_representation_endpoint(),
23
+ value_key=Instrument.get_representation_value_key(),
24
+ label_key=Instrument.get_representation_label_key(),
25
+ filter_params={"is_security": True},
26
+ method="fake_filter",
27
+ )
28
+ indicators = filters.MultipleChoiceFilter(
29
+ method="fake_filter",
30
+ label="Indicators",
31
+ choices=Indicator.choices,
32
+ required=False,
33
+ )
34
+ volume = filters.BooleanFilter(
35
+ method="fake_filter",
36
+ label="Add Volume",
37
+ default=False,
38
+ required=False,
39
+ )
40
+ show_estimates = filters.BooleanFilter(
41
+ method="fake_filter",
42
+ label="Show Estimates",
43
+ default=True,
44
+ required=False,
45
+ )
46
+
47
+ class Meta:
48
+ model = Instrument
49
+ fields = {}
50
+
51
+
52
+ class FinancialRatioFilterSet(filters.FilterSet):
53
+ ttm = filters.BooleanFilter(
54
+ method="fake_filter",
55
+ label="TTM/FTM",
56
+ default=True,
57
+ )
58
+
59
+ period = filters.FinancialPerformanceDateRangeFilter(
60
+ method="fake_filter",
61
+ label="Period",
62
+ default=five_year_data_range,
63
+ )
64
+
65
+ class Meta:
66
+ model = Instrument
67
+ fields = {}
68
+
69
+
70
+ class StatementFilter(filters.FilterSet):
71
+ data_type = filters.ChoiceFilter(
72
+ method="fake_filter",
73
+ label="Data Type",
74
+ choices=DataType.choices,
75
+ required=True,
76
+ default=DataType.STANDARDIZED,
77
+ )
78
+
79
+ class Meta:
80
+ model = Instrument
81
+ fields = {}
82
+
83
+
84
+ class StatementWithEstimateFilter(filters.FilterSet):
85
+ calendar_type = filters.ChoiceFilter(
86
+ method="fake_filter",
87
+ label="Calendar Type",
88
+ choices=CalendarType.choices,
89
+ required=True,
90
+ default=CalendarType.FISCAL,
91
+ )
92
+
93
+ class Meta:
94
+ model = Instrument
95
+ fields = {}
@@ -0,0 +1,119 @@
1
+ from datetime import date
2
+
3
+ from django.db import models
4
+ from pandas.tseries.offsets import BYearEnd
5
+ from psycopg.types.range import DateRange
6
+ from wbcore import filters as wb_filters
7
+ from wbfdm.figures.financials.financial_analysis_charts import (
8
+ PeriodChoices,
9
+ VariableChoices,
10
+ )
11
+ from wbfdm.models.instruments.instruments import Instrument
12
+
13
+
14
+ def byearend_n_year_ago(n):
15
+ today = date.today()
16
+ return (today - BYearEnd(n)).date()
17
+
18
+
19
+ def byearend_2_year_ago(field, request, view):
20
+ return byearend_n_year_ago(2)
21
+
22
+
23
+ class GroupKeyFinancialsFilterSet(wb_filters.FilterSet):
24
+ group_keys = wb_filters.CharFilter(
25
+ required=True,
26
+ method=lambda q, n, v: q,
27
+ )
28
+
29
+ class Meta:
30
+ models = Instrument
31
+ fields = {}
32
+
33
+
34
+ class FinancialAnalysisFilterSet(wb_filters.FilterSet):
35
+ class Meta:
36
+ model = Instrument
37
+ fields = {}
38
+
39
+
40
+ def _get_12m(field, request, view):
41
+ return date(date.today().year - 1, 1, 1)
42
+
43
+
44
+ class FinancialAnalysisValuationRatiosFilterSet(wb_filters.FilterSet):
45
+ date = wb_filters.FinancialPerformanceDateRangeFilter(
46
+ method=lambda queryset, label, value: queryset,
47
+ label="Date Range",
48
+ required=True,
49
+ clearable=False,
50
+ default=lambda r, v, q: DateRange(_get_12m(r, v, q), date.today()),
51
+ )
52
+
53
+ class OutputChoices(models.TextChoices):
54
+ TSTABLE = "TSTABLE", "Table (Time-series)"
55
+ TABLE = "TABLE", "Table (Last Value)"
56
+ CHART = "CHART", "Chart"
57
+
58
+ class RangeChoices(models.TextChoices):
59
+ MINMAX = "MINMAX", "Min-Max (entire period)"
60
+ ROLLING = "ROLLING", "Rolling"
61
+
62
+ output = wb_filters.ChoiceFilter(
63
+ choices=OutputChoices.choices, label="Output", method="fake_filter", default=OutputChoices.CHART
64
+ )
65
+ period = wb_filters.ChoiceFilter(
66
+ choices=PeriodChoices.choices, label="Period", method="fake_filter", default=PeriodChoices.NTM
67
+ )
68
+ vs_related = wb_filters.BooleanFilter(label="Versus related", default=False, method="fake_filter")
69
+ clean_data = wb_filters.BooleanFilter(label="Clean data", default=True, method="fake_filter")
70
+ ranges = wb_filters.BooleanFilter(label="Draw ranges", default=False, required=False, method="fake_filter")
71
+ range_type = wb_filters.ChoiceFilter(
72
+ choices=RangeChoices.choices,
73
+ label="Range type",
74
+ method="fake_filter",
75
+ required=True,
76
+ default=RangeChoices.MINMAX,
77
+ )
78
+ range_period = wb_filters.NumberFilter(
79
+ precision=0, label="Rolling period", method="fake_filter", required=True, default=120
80
+ )
81
+ x_axis_var = wb_filters.ChoiceFilter(
82
+ choices=VariableChoices.choices, label="X-Axis", method="fake_filter", default=VariableChoices.EPSG
83
+ )
84
+ y_axis_var = wb_filters.ChoiceFilter(
85
+ choices=VariableChoices.choices, label="Y-Axis", method="fake_filter", default=VariableChoices.PE
86
+ )
87
+ z_axis_var = wb_filters.ChoiceFilter(
88
+ choices=VariableChoices.choices, label="Bubble", method="fake_filter", default=VariableChoices.MKTCAP
89
+ )
90
+ median = wb_filters.BooleanFilter(label="Median", default=True, method="fake_filter")
91
+
92
+ class Meta:
93
+ model = Instrument
94
+ fields = {}
95
+
96
+
97
+ class EarningsAnalysisFilterSet(wb_filters.FilterSet):
98
+ date = wb_filters.FinancialPerformanceDateRangeFilter(
99
+ method=lambda queryset, label, value: queryset,
100
+ label="Date Range",
101
+ required=True,
102
+ clearable=False,
103
+ default=lambda r, v, q: DateRange(_get_12m(r, v, q), date.today()),
104
+ )
105
+
106
+ class OutputChoices(models.TextChoices):
107
+ EPS = "EPS", "Earnings ($)"
108
+
109
+ analysis = wb_filters.ChoiceFilter(
110
+ choices=OutputChoices.choices, label="Analysis", method=lambda q, n, v: q, default=OutputChoices.EPS
111
+ )
112
+ period = wb_filters.ChoiceFilter(
113
+ choices=PeriodChoices.choices, label="Period", method=lambda q, n, v: q, default=PeriodChoices.NTM
114
+ )
115
+ vs_related = wb_filters.BooleanFilter(label="Show related", default=False, method=lambda q, n, v: q)
116
+
117
+ class Meta:
118
+ model = Instrument
119
+ fields = {}
@@ -0,0 +1,112 @@
1
+ from datetime import date
2
+
3
+ from django.db import models
4
+ from psycopg.types.range import DateRange
5
+ from wbcore import filters as wb_filters
6
+ from wbfdm.filters.utils import get_earliest_date, get_latest_date
7
+ from wbfdm.models import Instrument, InstrumentPrice
8
+
9
+ from .financials_analysis import byearend_2_year_ago
10
+
11
+
12
+ class FakeDateRange(wb_filters.FilterSet):
13
+ date = wb_filters.FinancialPerformanceDateRangeFilter(
14
+ method=lambda queryset, label, value: queryset,
15
+ label="Date Range",
16
+ required=True,
17
+ clearable=False,
18
+ default=lambda r, v, q: DateRange(byearend_2_year_ago(r, v, q), date.today()),
19
+ )
20
+
21
+ class Meta:
22
+ model = Instrument
23
+ fields = {}
24
+
25
+
26
+ class InstrumentPriceFilterSet(wb_filters.FilterSet):
27
+ date = wb_filters.FinancialPerformanceDateRangeFilter(
28
+ method=wb_filters.DateRangeFilter.base_date_range_filter_method,
29
+ label="Date Range",
30
+ required=True,
31
+ clearable=False,
32
+ default=lambda r, v, q: DateRange(get_earliest_date(r, v, q), get_latest_date(r, v, q)),
33
+ )
34
+
35
+ class Meta:
36
+ model = InstrumentPrice
37
+ fields = {
38
+ "volume": ["gte", "exact", "lte"],
39
+ "volume_50d": ["gte", "exact", "lte"],
40
+ # 'volume_200d': ['exact'],
41
+ "market_capitalization": ["gte", "exact", "lte"],
42
+ "instrument__instrument_type": ["exact"],
43
+ }
44
+
45
+
46
+ class InstrumentPriceSingleBenchmarkFilterSet(InstrumentPriceFilterSet):
47
+ benchmark = wb_filters.ModelChoiceFilter(
48
+ label="Compare to..",
49
+ queryset=Instrument.objects.all(),
50
+ endpoint=Instrument.get_representation_endpoint(),
51
+ value_key=Instrument.get_representation_value_key(),
52
+ label_key=Instrument.get_representation_label_key(),
53
+ filter_params={"is_security": True},
54
+ method="fake_filter",
55
+ )
56
+
57
+ class Meta:
58
+ model = InstrumentPrice
59
+ fields = {}
60
+
61
+
62
+ class InstrumentPriceMultipleBenchmarkChartFilterSet(InstrumentPriceFilterSet):
63
+ benchmarks = wb_filters.ModelMultipleChoiceFilter(
64
+ label="Benchmarks",
65
+ queryset=Instrument.objects.all(),
66
+ endpoint=Instrument.get_representation_endpoint(),
67
+ value_key=Instrument.get_representation_value_key(),
68
+ label_key=Instrument.get_representation_label_key(),
69
+ filter_params={"is_security": True},
70
+ method="fake_filter",
71
+ )
72
+ normalized = wb_filters.BooleanFilter(label="Normalize", default=True, method="fake_filter")
73
+
74
+ class Meta:
75
+ model = InstrumentPrice
76
+ fields = {}
77
+
78
+
79
+ class InstrumentPriceFrequencyFilter(InstrumentPriceFilterSet):
80
+ class FrequencyChoice(models.TextChoices):
81
+ DAILY = "B", "Daily"
82
+ WEEKLY = "W-MON", "Weekly (Monday)"
83
+ MONTHLY = "BME", "Monthly"
84
+
85
+ frequency = wb_filters.ChoiceFilter(
86
+ label="Frequency", choices=FrequencyChoice.choices, default=FrequencyChoice.DAILY, method="fake_filter"
87
+ )
88
+
89
+ class Meta:
90
+ model = InstrumentPrice
91
+ fields = {}
92
+
93
+
94
+ class InstrumentPriceFinancialStatisticsChartFilterSet(
95
+ InstrumentPriceSingleBenchmarkFilterSet, InstrumentPriceFrequencyFilter
96
+ ):
97
+ class Meta:
98
+ model = InstrumentPrice
99
+ fields = {}
100
+
101
+
102
+ class InstrumentPriceInstrumentFilterSet(wb_filters.FilterSet):
103
+ class Meta:
104
+ model = InstrumentPrice
105
+ fields = {
106
+ "date": ["gte", "exact", "lte"],
107
+ "net_value": ["gte", "exact", "lte"],
108
+ "sharpe_ratio": ["gte", "exact", "lte"],
109
+ "correlation": ["gte", "exact", "lte"],
110
+ "beta": ["gte", "exact", "lte"],
111
+ "calculated": ["exact"],
112
+ }
@@ -0,0 +1,198 @@
1
+ from datetime import datetime
2
+
3
+ from django.db.models import Q
4
+ from psycopg.types.range import DateRange
5
+ from wbcore import filters as wb_filters
6
+ from wbcore.contrib.tags.filters import TagFilterMixin
7
+ from wbfdm.filters.utils import get_earliest_date, get_latest_date
8
+ from wbfdm.models.instruments import (
9
+ ClassificationGroup,
10
+ Instrument,
11
+ InstrumentClassificationThroughModel,
12
+ InstrumentFavoriteGroup,
13
+ )
14
+ from wbfdm.models.instruments.classifications import Classification
15
+ from wbfdm.preferences import get_default_classification_group
16
+
17
+
18
+ def get_default_favorite_group(field, request, view):
19
+ if favorite := InstrumentFavoriteGroup.objects.filter(owner=request.user.profile, primary=True).first():
20
+ return favorite.id
21
+ return None
22
+
23
+
24
+ class InstrumentFavoriteGroupFilterSet(wb_filters.FilterSet):
25
+ favorite_group = wb_filters.ModelChoiceFilter(
26
+ label="Favorite Group",
27
+ queryset=InstrumentFavoriteGroup.objects.all(),
28
+ endpoint=InstrumentFavoriteGroup.get_representation_endpoint(),
29
+ value_key=InstrumentFavoriteGroup.get_representation_value_key(),
30
+ label_key=InstrumentFavoriteGroup.get_representation_label_key(),
31
+ default=get_default_favorite_group,
32
+ method="filter_favorite_group",
33
+ )
34
+
35
+ def filter_favorite_group(self, queryset, name, value):
36
+ if value:
37
+ return queryset.filter(id__in=value.instruments.values_list("id"))
38
+ return queryset
39
+
40
+ class Meta:
41
+ model = Instrument
42
+ fields = {}
43
+
44
+
45
+ class InstrumentFilterSet(TagFilterMixin, InstrumentFavoriteGroupFilterSet):
46
+ parent = wb_filters.ModelChoiceFilter(
47
+ label="Parent",
48
+ queryset=Instrument.objects.all(),
49
+ endpoint=Instrument.get_representation_endpoint(),
50
+ value_key=Instrument.get_representation_value_key(),
51
+ label_key=Instrument.get_representation_label_key(),
52
+ hidden=True,
53
+ )
54
+
55
+ classifications = wb_filters.ModelChoiceFilter(
56
+ label="Classification",
57
+ queryset=Classification.objects.all(),
58
+ endpoint=Classification.get_representation_endpoint(),
59
+ value_key=Classification.get_representation_value_key(),
60
+ label_key=Classification.get_representation_label_key(),
61
+ method="filter_classification",
62
+ )
63
+
64
+ classifications_neq = wb_filters.ModelChoiceFilter(
65
+ label="Instrument not classified in..",
66
+ queryset=Classification.objects.all(),
67
+ endpoint=Classification.get_representation_endpoint(),
68
+ value_key=Classification.get_representation_value_key(),
69
+ label_key=Classification.get_representation_label_key(),
70
+ method="filter_classification",
71
+ hidden=True,
72
+ )
73
+
74
+ def filter_classification(self, queryset, name, value):
75
+ if value:
76
+ if name == "classifications":
77
+ return queryset.filter(classifications__in=value.get_descendants(include_self=True))
78
+ else:
79
+ return queryset.exclude(classifications__in=value.get_descendants(include_self=True))
80
+ return queryset
81
+
82
+ is_active = wb_filters.BooleanFilter(label="Only Active", method="filter_is_active")
83
+
84
+ def filter_is_active(self, queryset, name, value):
85
+ today = datetime.today()
86
+ if value is True:
87
+ return queryset.filter(
88
+ (Q(delisted_date__isnull=True) | Q(delisted_date__gte=today))
89
+ & Q(inception_date__isnull=False)
90
+ & Q(inception_date__lte=today)
91
+ )
92
+ return queryset
93
+
94
+ is_investable = wb_filters.BooleanFilter(
95
+ label="Is Investable", default=True, method="filter_is_investable", hidden=True
96
+ )
97
+
98
+ def filter_is_investable(self, queryset, name, value):
99
+ if value:
100
+ return queryset.filter(children__isnull=True)
101
+ return queryset
102
+
103
+ instrument_type__key = wb_filters.CharFilter(label="Instrument Type Key", hidden=True)
104
+ instrument_type__is_classifiable = wb_filters.BooleanFilter(label="Instrument Type Classifiable", hidden=True)
105
+
106
+ is_classifiable = wb_filters.BooleanFilter(label="Is Classifiable", method="filter_is_classifiable", hidden=True)
107
+
108
+ def filter_is_classifiable(self, queryset, name, value):
109
+ if value:
110
+ return queryset.filter(instrument_type__is_classifiable=True, level=0)
111
+ return queryset
112
+
113
+ # is_tree_in_investable_universe = wb_filters.BooleanFilter(label="Investable Universe", method="filter_is_tree_in_investable_universe", required=True)
114
+ # def filter_is_tree_in_investable_universe(self, queryset, name, value):
115
+ # if value is not None:
116
+ # return queryset.annotate(
117
+ # is_tree_in_investable_universe=Exists(
118
+ # Instrument.objects.filter(
119
+ # tree_id=OuterRef("tree_id"),
120
+ # lft__gte=OuterRef("lft"),
121
+ # rght__lte=OuterRef("rght"),
122
+ # is_investable_universe=True
123
+ # )
124
+ # )
125
+ # ).filter(Q(is_tree_in_investable_universe=value))
126
+ # return queryset
127
+ def __init__(self, data=None, *args, **kwargs):
128
+ if data:
129
+ data = data.dict()
130
+ if "parent" in data:
131
+ data.pop("classifications", None) # remove classifications in case we are navigating the tree
132
+ data.pop("level", None)
133
+ super().__init__(data=data, *args, **kwargs)
134
+
135
+ class Meta:
136
+ model = Instrument
137
+ fields = {
138
+ "is_investable_universe": ["exact"],
139
+ "instrument_type": ["exact"],
140
+ "isin": ["exact"],
141
+ "ticker": ["exact"],
142
+ "currency": ["exact"],
143
+ # "related_instruments": ["exact"], # I don't think this filter is necessary
144
+ "country": ["exact"],
145
+ "exchange": ["exact"],
146
+ "id": ["in"],
147
+ "is_managed": ["exact"],
148
+ "is_security": ["exact"],
149
+ "is_primary": ["exact"],
150
+ "parent": ["exact", "isnull"],
151
+ "level": ["exact"],
152
+ }
153
+ hidden_fields = ["id__in", "is_managed", "is_security", "level"]
154
+
155
+
156
+ def _get_default_classification_group_id(*args, **kwargs):
157
+ if group := get_default_classification_group():
158
+ return group.id
159
+ return None
160
+
161
+
162
+ class BaseClassifiedInstrumentFilterSet(TagFilterMixin, wb_filters.FilterSet):
163
+ classification_group = wb_filters.ModelChoiceFilter(
164
+ label="Classification Group",
165
+ queryset=ClassificationGroup.objects.all(),
166
+ endpoint=ClassificationGroup.get_representation_endpoint(),
167
+ value_key=ClassificationGroup.get_representation_value_key(),
168
+ label_key=ClassificationGroup.get_representation_label_key(),
169
+ default=_get_default_classification_group_id(),
170
+ method="fake_filter",
171
+ required=True,
172
+ )
173
+
174
+ def query_classification(self, queryset, name, value):
175
+ if value:
176
+ return queryset.filter(**{name.replace("_", "__"): value.id})
177
+ return queryset
178
+
179
+ class Meta:
180
+ model = InstrumentClassificationThroughModel
181
+ fields = {
182
+ "instrument": ["exact"],
183
+ "is_favorite": ["exact"],
184
+ }
185
+
186
+
187
+ class MonthlyPerformancesInstrumentFilterSet(wb_filters.FilterSet):
188
+ period = wb_filters.FinancialPerformanceDateRangeFilter(
189
+ label="Period",
190
+ required=True,
191
+ clearable=False,
192
+ method="fake_filter",
193
+ default=lambda r, v, q: DateRange(get_earliest_date(r, v, q), get_latest_date(r, v, q)),
194
+ )
195
+
196
+ class Meta:
197
+ model = Instrument
198
+ fields = {}