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,41 @@
1
+ import re
2
+ from functools import lru_cache
3
+
4
+ from wbcore.contrib.currency.models import Currency
5
+ from wbcore.contrib.geography.models import Geography
6
+ from wbfdm.preferences import get_non_ticker_words
7
+
8
+ START_DELIMITER = r"(?:^|(?<=[(\s\.\-<]))"
9
+ END_DELIMITER = r"(?=[\s\.)\-\>'’,]|$)"
10
+
11
+
12
+ @lru_cache()
13
+ def non_ticker_words():
14
+ return (
15
+ list(Geography.countries.values_list("code_2", flat=True))
16
+ + list(Geography.countries.values_list("code_3", flat=True))
17
+ + list(Currency.objects.values_list("key", flat=True))
18
+ + get_non_ticker_words()
19
+ )
20
+
21
+
22
+ def re_ric(input: str):
23
+ # [(\s<]([A-Z]{2}[A-Za-z0-9_.-]+\.[A-Za-z]+)[(\s>] led to too many false positive (e.g. end of sentence when whitespace are missing. We refined by considering only uppercase code
24
+ return set(re.findall(START_DELIMITER + r"([A-Z0-9]{2}[A-Z0-9_.-]+\.[A-Z]+)" + END_DELIMITER, input))
25
+
26
+
27
+ def re_bloomberg(input: str):
28
+ return set(
29
+ filter(
30
+ lambda x: x not in non_ticker_words(),
31
+ re.findall(START_DELIMITER + r"([A-Z]{2,5}(?:\-[A-Z]{2})?)" + END_DELIMITER, input),
32
+ )
33
+ )
34
+
35
+
36
+ def re_isin(input: str):
37
+ return set(re.findall(START_DELIMITER + r"([A-Z]{2}[A-Z0-9]{9}[0-9])" + END_DELIMITER, input))
38
+
39
+
40
+ def re_mnemonic(input: str):
41
+ return set(re.findall(START_DELIMITER + r"([A-Z]+:[A-Z]+)" + END_DELIMITER, input))
wbfdm/preferences.py ADDED
@@ -0,0 +1,21 @@
1
+ from contextlib import suppress
2
+
3
+ from django.db.utils import ProgrammingError
4
+ from dynamic_preferences.registries import global_preferences_registry
5
+
6
+
7
+ def get_default_classification_group(*args, **kwargs):
8
+ from wbfdm.models.instruments.classifications import ClassificationGroup
9
+
10
+ with suppress(RuntimeError, ProgrammingError):
11
+ global_preferences = global_preferences_registry.manager()
12
+ if group_id := global_preferences["wbfdm__default_classification_group"]:
13
+ with suppress(ClassificationGroup.DoesNotExist):
14
+ return ClassificationGroup.objects.get(id=group_id)
15
+ return ClassificationGroup.objects.get_or_create(is_primary=True, defaults={"name": "Default"})[0]
16
+
17
+
18
+ def get_non_ticker_words(*args, **kwargs) -> list[str]:
19
+ global_preferences = global_preferences_registry.manager()
20
+ return global_preferences["wbfdm__non_ticker_words"].split(",")
21
+ return list()
@@ -0,0 +1,4 @@
1
+ from .esg import InstrumentControversySerializer
2
+ from .instruments import *
3
+ from .officers import OfficerSerializer
4
+ from .exchanges import ExchangeModelSerializer, ExchangeRepresentationSerializer
@@ -0,0 +1,36 @@
1
+ from wbcore import serializers
2
+ from wbfdm.enums import (
3
+ ESGControveryFlag,
4
+ ESGControverySeverity,
5
+ ESGControveryStatus,
6
+ ESGControveryType,
7
+ )
8
+
9
+
10
+ class InstrumentControversySerializer(serializers.Serializer):
11
+ id = serializers.PrimaryKeyCharField()
12
+ headline = serializers.TextField()
13
+ narrative = serializers.TextField()
14
+ source = serializers.CharField()
15
+ status = serializers.ChoiceField(choices=ESGControveryStatus.choices)
16
+ type = serializers.ChoiceField(choices=ESGControveryType.choices)
17
+ assessment = serializers.ChoiceField(choices=ESGControverySeverity.choices)
18
+ response = serializers.TextField()
19
+ review = serializers.DateField()
20
+ initiated = serializers.DateField()
21
+ flag = serializers.ChoiceField(choices=ESGControveryFlag.choices)
22
+
23
+ class Meta:
24
+ fields = (
25
+ "id",
26
+ "headline",
27
+ "narrative",
28
+ "source",
29
+ "status",
30
+ "type",
31
+ "assessment",
32
+ "response",
33
+ "review",
34
+ "initiated",
35
+ "flag",
36
+ )
@@ -0,0 +1,39 @@
1
+ from wbcore import serializers as wb_serializers
2
+ from wbcore.contrib.geography.serializers import GeographyRepresentationSerializer
3
+ from wbfdm.models import Exchange
4
+
5
+
6
+ class ExchangeRepresentationSerializer(wb_serializers.RepresentationSerializer):
7
+ _detail = wb_serializers.HyperlinkField(reverse_name="wbfdm:exchange-detail")
8
+
9
+ class Meta:
10
+ model = Exchange
11
+ fields = ("id", "name", "mic_code", "_detail")
12
+
13
+
14
+ class ExchangeModelSerializer(wb_serializers.ModelSerializer):
15
+ _country = GeographyRepresentationSerializer(source="country")
16
+ _city = GeographyRepresentationSerializer(source="city")
17
+
18
+ class Meta:
19
+ model = Exchange
20
+ fields = (
21
+ "id",
22
+ "name",
23
+ "mic_code",
24
+ "operating_mic_code",
25
+ "bbg_exchange_codes",
26
+ "bbg_composite_primary",
27
+ "bbg_composite",
28
+ "refinitiv_identifier_code",
29
+ "refinitiv_mnemonic",
30
+ "country",
31
+ "_country",
32
+ "city",
33
+ "website",
34
+ "opening_time",
35
+ "closing_time",
36
+ "_city",
37
+ "city",
38
+ "comments",
39
+ )
@@ -0,0 +1,37 @@
1
+ from .instruments import (
2
+ InstrumentModelListSerializer,
3
+ InstrumentModelSerializer,
4
+ InstrumentRepresentationSerializer,
5
+ InstrumentTypeRepresentationSerializer,
6
+ InvestableUniverseRepresentationSerializer,
7
+ ClassifiableInstrumentRepresentationSerializer,
8
+ SecurityRepresentationSerializer,
9
+ InvestableInstrumentRepresentationSerializer,
10
+ PrimaryInvestableInstrumentRepresentationSerializer,
11
+ EquityRepresentationSerializer,
12
+ ProductRepresentationSerializer,
13
+ ManagedInstrumentRepresentationSerializer,
14
+ )
15
+ from .instrument_prices import InstrumentPriceModelSerializer, InstrumentPriceInstrumentModelSerializer
16
+ from .instrument_relationships import (
17
+ InstrumentClassificationRelatedInstrumentModelSerializer,
18
+ InstrumentClassificationRelatedInstrumentRepresentationSerializer,
19
+ RelatedInstrumentThroughInstrumentModelSerializer,
20
+ InstrumentFavoriteGroupRepresentationSerializer,
21
+ InstrumentFavoriteGroupModelSerializer,
22
+ InstrumentClassificationThroughModelSerializer,
23
+ )
24
+ from .instrument_requests import InstrumentRequestRepresentationSerializer, InstrumentRequestModelSerializer
25
+ from .classifications import (
26
+ ClassificationRepresentationSerializer,
27
+ ClassificationZeroHeightRepresentationSerializer,
28
+ ClassificationIsFavoriteZeroHeightRepresentationSerializer,
29
+ ClassificationGroupRepresentationSerializer,
30
+ ClassificationModelSerializer,
31
+ ClassificationGroupModelSerializer,
32
+ )
33
+ from .instrument_lists import (
34
+ InstrumentListModelSerializer,
35
+ InstrumentListRepresentationSerializer,
36
+ InstrumentListThroughModelSerializer,
37
+ )
@@ -0,0 +1,139 @@
1
+ from rest_framework import serializers as rf_serializers
2
+ from rest_framework.reverse import reverse
3
+ from wbcore import serializers as wb_serializers
4
+ from wbcore.serializers import DefaultAttributeFromRemoteField
5
+ from wbfdm.models.instruments import Classification, ClassificationGroup
6
+ from wbfdm.preferences import get_default_classification_group
7
+
8
+
9
+ class ClassificationRepresentationSerializer(wb_serializers.RepresentationSerializer):
10
+ _detail = wb_serializers.HyperlinkField(reverse_name="wbfdm:classification-detail")
11
+
12
+ class Meta:
13
+ model = Classification
14
+ fields = (
15
+ "id",
16
+ "name",
17
+ "computed_str",
18
+ "level",
19
+ "height",
20
+ "code_aggregated",
21
+ "_detail",
22
+ )
23
+
24
+
25
+ class ClassificationZeroHeightRepresentationSerializer(ClassificationRepresentationSerializer):
26
+ def get_filter_params(self, request):
27
+ filter_params = {"height": 0}
28
+ if (view := request.parser_context.get("view", None)) and (
29
+ instrument_id := view.kwargs.get("instrument_id", None)
30
+ ):
31
+ filter_params["instruments_neq"] = instrument_id
32
+ return filter_params
33
+
34
+
35
+ class ClassificationIsFavoriteZeroHeightRepresentationSerializer(ClassificationRepresentationSerializer):
36
+ def get_filter_params(self, request):
37
+ filter_params = {
38
+ "height": 0,
39
+ "instruments_through__is_favorite": True,
40
+ }
41
+ if group := get_default_classification_group():
42
+ filter_params["group"] = group.id
43
+ return filter_params
44
+
45
+
46
+ class ClassificationGroupRepresentationSerializer(wb_serializers.RepresentationSerializer):
47
+ max_depth = wb_serializers.IntegerField(read_only=True)
48
+ _detail = wb_serializers.HyperlinkField(reverse_name="wbfdm:classificationgroup-detail")
49
+
50
+ class Meta:
51
+ model = ClassificationGroup
52
+ fields = ("id", "name", "is_primary", "max_depth", "_detail")
53
+
54
+
55
+ class ClassificationModelSerializer(wb_serializers.ModelSerializer):
56
+ parent = wb_serializers.PrimaryKeyRelatedField(
57
+ queryset=Classification.objects.all(), default=DefaultAttributeFromRemoteField("parent_id", Classification)
58
+ )
59
+ _parent = ClassificationRepresentationSerializer(source="parent")
60
+ group = wb_serializers.PrimaryKeyRelatedField(
61
+ queryset=ClassificationGroup.objects.all(),
62
+ default=DefaultAttributeFromRemoteField("parent_id", Classification, source="group"),
63
+ )
64
+ _group = ClassificationGroupRepresentationSerializer(source="group")
65
+ code_aggregated = wb_serializers.CharField(required=False, default="")
66
+ level_representation = wb_serializers.CharField(required=False, default="")
67
+ description = wb_serializers.TextAreaField(label="Description", allow_null=True, allow_blank=True, required=False)
68
+
69
+ @wb_serializers.register_only_instance_resource()
70
+ def additional_resources(self, instance, request, user, **kwargs):
71
+ resources = {
72
+ "childs": reverse("wbfdm:classificationparent-classification-list", args=[instance.id], request=request),
73
+ }
74
+ if instance.children.exists():
75
+ resources[
76
+ "iciclechart"
77
+ ] = f'{reverse("wbfdm:classificationgroup-iciclechart-list", args=[instance.group.id], request=request)}?top_classification={instance.id}'
78
+ resources[
79
+ "treechart"
80
+ ] = f'{reverse("wbfdm:classificationgroup-treechart-list", args=[instance.group.id], request=request)}?top_classification={instance.id}'
81
+
82
+ resources["instruments"] = reverse("wbfdm:classification-instrument-list", args=[instance.id], request=request)
83
+
84
+ return resources
85
+
86
+ def validate(self, data):
87
+ errors = {}
88
+ if parent := data.get("parent", None):
89
+ data["level"] = parent.level + 1
90
+ data["group"] = parent.group
91
+ if (
92
+ (investable := data.get("investable", None))
93
+ and self.instance
94
+ and investable is True
95
+ and self.instance.get_ancestors().filter(investable=False).exists()
96
+ ):
97
+ errors["investable"] = "This classification cannot be investable as long as its parent is non investable."
98
+ if len(errors.keys()) > 0:
99
+ raise rf_serializers.ValidationError(errors)
100
+ return data
101
+
102
+ class Meta:
103
+ model = Classification
104
+ fields = (
105
+ "id",
106
+ "parent",
107
+ "_parent",
108
+ "height",
109
+ "group",
110
+ "_group",
111
+ "level",
112
+ "level_representation",
113
+ "name",
114
+ "code_aggregated",
115
+ "investable",
116
+ "description",
117
+ "_additional_resources",
118
+ )
119
+
120
+
121
+ class ClassificationGroupModelSerializer(wb_serializers.ModelSerializer):
122
+ @wb_serializers.register_resource()
123
+ def additional_resources(self, instance, request, user):
124
+ if instance.classifications.exists():
125
+ return {
126
+ "classifications": reverse(
127
+ "wbfdm:classificationgroup-classification-list", args=[instance.id], request=request
128
+ ),
129
+ "treechart": reverse("wbfdm:classificationgroup-treechart-list", args=[instance.id], request=request),
130
+ "iciclechart": reverse(
131
+ "wbfdm:classificationgroup-iciclechart-list", args=[instance.id], request=request
132
+ ),
133
+ }
134
+
135
+ return {}
136
+
137
+ class Meta:
138
+ model = ClassificationGroup
139
+ fields = ("id", "name", "is_primary", "max_depth", "code_level_digits", "_additional_resources")
@@ -0,0 +1,61 @@
1
+ from rest_framework.reverse import reverse
2
+ from wbcore import serializers as wb_serializers
3
+ from wbfdm.models.instruments.instrument_lists import (
4
+ InstrumentList,
5
+ InstrumentListThroughModel,
6
+ )
7
+ from wbfdm.serializers.instruments import SecurityRepresentationSerializer
8
+
9
+
10
+ class InstrumentListRepresentationSerializer(wb_serializers.RepresentationSerializer):
11
+ _detail = wb_serializers.HyperlinkField(reverse_name="wbfdm:instrumentlist-detail")
12
+
13
+ class Meta:
14
+ model = InstrumentList
15
+ fields = (
16
+ "id",
17
+ "name",
18
+ "_detail",
19
+ )
20
+
21
+
22
+ class InstrumentListModelSerializer(wb_serializers.ModelSerializer):
23
+ @wb_serializers.register_only_instance_resource()
24
+ def instruments(self, instance, request, user, **kwargs):
25
+ if instance:
26
+ base_url = reverse("wbfdm:instrumentlist-instrumentlistthrough-list", args=[instance.id], request=request)
27
+ return {"instruments": base_url}
28
+ return {}
29
+
30
+ class Meta:
31
+ model = InstrumentList
32
+ read_only_fields = ("id", "identifier")
33
+ fields = (
34
+ "id",
35
+ "name",
36
+ "identifier",
37
+ "instrument_list_type",
38
+ "_additional_resources",
39
+ )
40
+
41
+
42
+ class InstrumentListThroughModelSerializer(wb_serializers.ModelSerializer):
43
+ _instrument = SecurityRepresentationSerializer(source="instrument")
44
+ _instrument_list = InstrumentListRepresentationSerializer(source="instrument_list")
45
+
46
+ class Meta:
47
+ model = InstrumentListThroughModel
48
+ read_only_fields = ("instrument_str",)
49
+ fields = (
50
+ "id",
51
+ "instrument_str",
52
+ "instrument",
53
+ "_instrument",
54
+ "instrument_list",
55
+ "_instrument_list",
56
+ "from_date",
57
+ "to_date",
58
+ "comment",
59
+ "validated",
60
+ "_additional_resources",
61
+ )
@@ -0,0 +1,73 @@
1
+ from wbcore import serializers as wb_serializers
2
+ from wbfdm.models import InstrumentPrice
3
+ from wbfdm.serializers.instruments.instruments import (
4
+ InvestableInstrumentRepresentationSerializer,
5
+ )
6
+
7
+
8
+ class InstrumentPriceModelSerializer(wb_serializers.ModelSerializer):
9
+ _instrument = InvestableInstrumentRepresentationSerializer(source="instrument")
10
+ currency_symbol = wb_serializers.CharField(read_only=True)
11
+ net_value = wb_serializers.DecimalField(max_digits=16, decimal_places=2, default=0)
12
+ net_value_usd = wb_serializers.DecimalField(max_digits=16, decimal_places=2, default=0)
13
+ gross_value = wb_serializers.DecimalField(max_digits=16, decimal_places=2, default=0)
14
+ daily_diff_net_value = wb_serializers.FloatField(required=False, read_only=True, default=0, precision=4)
15
+ daily_diff_gross_value = wb_serializers.FloatField(required=False, read_only=True, default=0, precision=4)
16
+ real_price_exists = wb_serializers.BooleanField(default=False, read_only=True)
17
+
18
+ class Meta:
19
+ model = InstrumentPrice
20
+ percent_fields = [
21
+ "daily_diff_net_value",
22
+ "daily_diff_gross_value",
23
+ ]
24
+ decorators = {
25
+ "market_capitalization": wb_serializers.decorator(
26
+ decorator_type="text", position="left", value="{{currency_symbol}}"
27
+ ),
28
+ }
29
+ fields = (
30
+ "id",
31
+ "date",
32
+ "net_value",
33
+ "net_value_usd",
34
+ "gross_value",
35
+ "calculated",
36
+ "real_price_exists",
37
+ "sharpe_ratio",
38
+ "correlation",
39
+ "beta",
40
+ "daily_diff_net_value",
41
+ "daily_diff_gross_value",
42
+ "instrument",
43
+ "_instrument",
44
+ "volume",
45
+ "volume_50d",
46
+ "volume_200d",
47
+ "currency_symbol",
48
+ "outstanding_shares_consolidated",
49
+ "market_capitalization",
50
+ )
51
+
52
+
53
+ class InstrumentPriceInstrumentModelSerializer(InstrumentPriceModelSerializer):
54
+ class Meta(InstrumentPriceModelSerializer.Meta):
55
+ fields = (
56
+ "id",
57
+ "date",
58
+ "net_value",
59
+ "net_value_usd",
60
+ "gross_value",
61
+ "sharpe_ratio",
62
+ "calculated",
63
+ "correlation",
64
+ "beta",
65
+ "daily_diff_net_value",
66
+ "daily_diff_gross_value",
67
+ "volume",
68
+ "volume_50d",
69
+ "volume_200d",
70
+ "currency_symbol",
71
+ "outstanding_shares_consolidated",
72
+ "market_capitalization",
73
+ )
@@ -0,0 +1,170 @@
1
+ from rest_framework import serializers
2
+ from rest_framework.reverse import reverse
3
+ from wbcore import serializers as wb_serializers
4
+ from wbcore.contrib.directory.models import Person
5
+ from wbcore.contrib.directory.serializers import PersonRepresentationSerializer
6
+ from wbcore.contrib.tags.serializers import TagSerializerMixin
7
+ from wbfdm.models import (
8
+ Classification,
9
+ Instrument,
10
+ InstrumentClassificationRelatedInstrument,
11
+ InstrumentClassificationThroughModel,
12
+ InstrumentFavoriteGroup,
13
+ RelatedInstrumentThroughModel,
14
+ )
15
+
16
+ from .classifications import ClassificationZeroHeightRepresentationSerializer
17
+ from .instruments import (
18
+ ClassifiableInstrumentRepresentationSerializer,
19
+ InvestableInstrumentRepresentationSerializer,
20
+ PrimaryInvestableInstrumentRepresentationSerializer,
21
+ )
22
+
23
+
24
+ class InstrumentFavoriteGroupRepresentationSerializer(wb_serializers.RepresentationSerializer):
25
+ _detail = wb_serializers.HyperlinkField(reverse_name="wbfdm:favoritegroup-detail")
26
+
27
+ class Meta:
28
+ model = InstrumentFavoriteGroup
29
+ fields = ("id", "name", "owner", "public", "_detail")
30
+
31
+
32
+ class InstrumentFavoriteGroupModelSerializer(wb_serializers.ModelSerializer):
33
+ _instruments = PrimaryInvestableInstrumentRepresentationSerializer(source="instruments", many=True)
34
+ owner = wb_serializers.PrimaryKeyRelatedField(
35
+ queryset=lambda: Person.objects.filter_only_internal(),
36
+ default=wb_serializers.CurrentUserDefault("profile"),
37
+ read_only=lambda view: not view.request.user.is_superuser,
38
+ )
39
+ _owner = PersonRepresentationSerializer(source="owner")
40
+ public = wb_serializers.BooleanField(read_only=True)
41
+
42
+ # @wb_serializers.register_only_instance_resource()
43
+ # def instruments(self, instance, request, user, **kwargs):
44
+ # if instance.instruments.exists():
45
+ # return {"instruments": reverse("wbfdm:favoritegroup-instrument-list", args=[instance.id], request=request)}
46
+ # return dict()
47
+
48
+ def validate(self, data):
49
+ if not data.get("owner", None):
50
+ data["owner"] = self.context["request"].user.profile if self.context.get("request") else None
51
+ return data
52
+
53
+ class Meta:
54
+ model = InstrumentFavoriteGroup
55
+ fields = (
56
+ "id",
57
+ "name",
58
+ "owner",
59
+ "_owner",
60
+ "public",
61
+ "primary",
62
+ "instruments",
63
+ "_instruments",
64
+ "_additional_resources",
65
+ )
66
+
67
+
68
+ class RelatedInstrumentThroughInstrumentModelSerializer(wb_serializers.ModelSerializer):
69
+ _related_instrument = InvestableInstrumentRepresentationSerializer(source="related_instrument")
70
+ _instrument = InvestableInstrumentRepresentationSerializer(source="instrument")
71
+
72
+ class Meta:
73
+ model = RelatedInstrumentThroughModel
74
+ fields = (
75
+ "id",
76
+ "_related_instrument",
77
+ "related_instrument",
78
+ "_instrument",
79
+ "instrument",
80
+ "related_type",
81
+ "is_primary",
82
+ )
83
+
84
+
85
+ class InstrumentClassificationThroughModelSerializer(TagSerializerMixin, wb_serializers.ModelSerializer):
86
+ instrument = wb_serializers.PrimaryKeyRelatedField(
87
+ queryset=Instrument.objects.all(), default=wb_serializers.DefaultFromKwargs("instrument_id")
88
+ )
89
+ _instrument = ClassifiableInstrumentRepresentationSerializer(source="instrument")
90
+ classification = wb_serializers.PrimaryKeyRelatedField(
91
+ queryset=Classification.objects.all(), default=wb_serializers.DefaultFromKwargs("classification_id")
92
+ )
93
+ _classification = ClassificationZeroHeightRepresentationSerializer(source="classification")
94
+ reason = wb_serializers.TextAreaField(label="Reason", allow_null=True, allow_blank=True, required=False)
95
+ _related_instruments = ClassifiableInstrumentRepresentationSerializer(source="related_instruments", many=True)
96
+
97
+ @wb_serializers.register_resource()
98
+ def related_instrument_list(self, instance, request, user):
99
+ return {"related_instruments": reverse("wbfdm:related_instrument-list", args=[instance.id], request=request)}
100
+
101
+ def validate(self, data):
102
+ instrument = data.get("instrument", self.instance.instrument if self.instance else None)
103
+ classification = data.get("classification", self.instance.classification if self.instance else None)
104
+ if not instrument:
105
+ raise serializers.ValidationError({"instrument": "Instrument cannot be null"})
106
+ if not classification:
107
+ raise serializers.ValidationError({"classification": "Classification cannot be null"})
108
+
109
+ if (
110
+ not self.instance
111
+ and InstrumentClassificationThroughModel.objects.filter(
112
+ classification=classification, instrument=instrument
113
+ ).exists()
114
+ ):
115
+ if hasattr(data, "instrument"):
116
+ raise serializers.ValidationError(
117
+ {
118
+ "instrument": f"A relationship already exists between {instrument} and {classification}",
119
+ }
120
+ )
121
+ else:
122
+ raise serializers.ValidationError(
123
+ {
124
+ "classification": f"A relationship already exists between {instrument} and {classification}",
125
+ }
126
+ )
127
+
128
+ return data
129
+
130
+ class Meta:
131
+ model = InstrumentClassificationThroughModel
132
+ fields = (
133
+ "id",
134
+ "instrument",
135
+ "classification",
136
+ "_instrument",
137
+ "_classification",
138
+ "related_instruments",
139
+ "_related_instruments",
140
+ "is_favorite",
141
+ "reason",
142
+ "pure_player",
143
+ "top_player",
144
+ "percent_of_revenue",
145
+ "tags",
146
+ "_tags",
147
+ "_additional_resources",
148
+ )
149
+ percent_fields = ["percent_of_revenue"]
150
+
151
+
152
+ class InstrumentClassificationRelatedInstrumentRepresentationSerializer(wb_serializers.ModelSerializer):
153
+ class Meta:
154
+ model = InstrumentClassificationRelatedInstrument
155
+ fields = ("id", "related_instrument")
156
+
157
+
158
+ class InstrumentClassificationRelatedInstrumentModelSerializer(wb_serializers.ModelSerializer):
159
+ _related_instrument = ClassifiableInstrumentRepresentationSerializer(source="related_instrument")
160
+
161
+ class Meta:
162
+ model = InstrumentClassificationRelatedInstrument
163
+ fields = (
164
+ "id",
165
+ "classified_instrument",
166
+ # "_classified_instrument",
167
+ "related_instrument",
168
+ "_related_instrument",
169
+ "related_instrument_type",
170
+ )