luxorasap 0.2.9__tar.gz → 0.2.11__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.
- {luxorasap-0.2.9 → luxorasap-0.2.11}/PKG-INFO +1 -1
- {luxorasap-0.2.9 → luxorasap-0.2.11}/pyproject.toml +2 -2
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap/__init__.py +1 -1
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap/datareader/core.py +91 -76
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap.egg-info/PKG-INFO +1 -1
- {luxorasap-0.2.9 → luxorasap-0.2.11}/README.md +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/setup.cfg +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap/btgapi/__init__.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap/btgapi/auth.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap/btgapi/reports.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap/btgapi/trades.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap/datareader/__init__.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap/ingest/__init__.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap/ingest/cloud/__init__.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap/ingest/legacy_local/dataloader.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap/utils/__init__.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap/utils/dataframe/__init__.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap/utils/dataframe/reader.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap/utils/dataframe/transforms.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap/utils/storage/__init__.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap/utils/storage/blob.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap/utils/storage/change_tracker.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap/utils/tools/__init__.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap/utils/tools/excel.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap.egg-info/SOURCES.txt +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap.egg-info/dependency_links.txt +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap.egg-info/entry_points.txt +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap.egg-info/requires.txt +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/src/luxorasap.egg-info/top_level.txt +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/tests/test_btgapi_auth.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/tests/test_btgapi_reports.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/tests/test_btgapi_trades.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/tests/test_datareader.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/tests/test_ingest_cloud.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/tests/test_ingest_legacy_local.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/tests/test_utils_change_tracker.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/tests/test_utils_dataframe.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/tests/test_utils_storage.py +0 -0
- {luxorasap-0.2.9 → luxorasap-0.2.11}/tests/tests_utils_pickle_excel.py +0 -0
|
@@ -10,7 +10,7 @@ build-backend = "setuptools.build_meta"
|
|
|
10
10
|
#############################
|
|
11
11
|
[project]
|
|
12
12
|
name = "luxorasap"
|
|
13
|
-
version = "0.2.
|
|
13
|
+
version = "0.2.11"
|
|
14
14
|
description = "Toolbox da Luxor para ingestão, análise e automação de dados financeiros."
|
|
15
15
|
readme = "README.md"
|
|
16
16
|
requires-python = ">=3.9"
|
|
@@ -78,7 +78,7 @@ exclude = ["tests*"]
|
|
|
78
78
|
# bumpver (sem-ver)
|
|
79
79
|
#############################
|
|
80
80
|
[tool.bumpver]
|
|
81
|
-
current_version = "0.2.
|
|
81
|
+
current_version = "0.2.11"
|
|
82
82
|
version_pattern = "MAJOR.MINOR.PATCH"
|
|
83
83
|
|
|
84
84
|
# regex explícito – obrigatório no bumpver 2024+
|
|
@@ -13,7 +13,7 @@ from types import ModuleType
|
|
|
13
13
|
try:
|
|
14
14
|
__version__: str = metadata.version(__name__)
|
|
15
15
|
except metadata.PackageNotFoundError: # editable install
|
|
16
|
-
__version__ = "0.2.
|
|
16
|
+
__version__ = "0.2.11"
|
|
17
17
|
|
|
18
18
|
# ─── Lazy loader ─────────────────────────────────────────────────
|
|
19
19
|
def __getattr__(name: str) -> ModuleType:
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import pandas as pd
|
|
3
3
|
import datetime as dt
|
|
4
4
|
from datetime import timezone
|
|
5
|
-
|
|
5
|
+
import logging
|
|
6
6
|
import os, sys
|
|
7
7
|
import time
|
|
8
8
|
import numpy as np
|
|
@@ -77,7 +77,7 @@ class LuxorQuery:
|
|
|
77
77
|
return file_last_update > self.tables_in_use[table_name]["update_time"]
|
|
78
78
|
|
|
79
79
|
except:
|
|
80
|
-
|
|
80
|
+
logging.info(f"Arquivo <{file_path}> não encontrado.")
|
|
81
81
|
|
|
82
82
|
return False
|
|
83
83
|
|
|
@@ -85,7 +85,7 @@ class LuxorQuery:
|
|
|
85
85
|
def __get_tickers_bbg(self):
|
|
86
86
|
# Deprecated.
|
|
87
87
|
# Criado apenas para manter compatibilidade
|
|
88
|
-
|
|
88
|
+
logging.info("Acesso direto a tabela 'bbg_ticker' sera descontinuado.\nAo inves disso, pegue os valores unicos de asset[Ticker_BBG]")
|
|
89
89
|
return pd.DataFrame(self.get_table("assets")["Ticker_BBG"].unique())
|
|
90
90
|
|
|
91
91
|
|
|
@@ -107,7 +107,8 @@ class LuxorQuery:
|
|
|
107
107
|
return tables
|
|
108
108
|
|
|
109
109
|
|
|
110
|
-
def get_table(self, table_name, index=False, index_name="index", dtypes_override={}, force_reload=False,
|
|
110
|
+
def get_table(self, table_name, index=False, index_name="index", dtypes_override={}, force_reload=False,
|
|
111
|
+
drop_last_updated_columns=True, auto_convert_mapped_types=True):
|
|
111
112
|
"""
|
|
112
113
|
Retorna uma copia do DataFrame do 'table_name' correspondente. Se não estiver disponivel,
|
|
113
114
|
retorna None.
|
|
@@ -143,9 +144,10 @@ class LuxorQuery:
|
|
|
143
144
|
return self.tables_in_use[table_name]["table_data"]
|
|
144
145
|
|
|
145
146
|
|
|
146
|
-
table_data = self.__load_table(table_name, index=index, index_name=index_name, dtypes_override=dtypes_override
|
|
147
|
+
table_data = self.__load_table(table_name, index=index, index_name=index_name, dtypes_override=dtypes_override,
|
|
148
|
+
auto_convert_mapped_types=auto_convert_mapped_types)
|
|
147
149
|
|
|
148
|
-
if drop_last_updated_columns:
|
|
150
|
+
if (table_data is not None) and drop_last_updated_columns:
|
|
149
151
|
if "Last_Updated" in table_data.columns:
|
|
150
152
|
return table_data.drop(columns=["Last_Updated"])
|
|
151
153
|
|
|
@@ -153,8 +155,7 @@ class LuxorQuery:
|
|
|
153
155
|
|
|
154
156
|
|
|
155
157
|
|
|
156
|
-
def __load_table(self, table_name, index=False, index_name="index", dtypes_override={}):
|
|
157
|
-
|
|
158
|
+
def __load_table(self, table_name, index=False, index_name="index", dtypes_override={}, auto_convert_mapped_types=True):
|
|
158
159
|
def __load_parquet(table_name):
|
|
159
160
|
table_path = f"{self.blob_directory}/{table_name}.parquet"#self.tables_path/"parquet"/f"{table_name}.parquet"
|
|
160
161
|
|
|
@@ -165,13 +166,16 @@ class LuxorQuery:
|
|
|
165
166
|
table_data, blob_read_success = self.blob_client.read_df(table_path)#__read_blob_parquet(table_name)
|
|
166
167
|
|
|
167
168
|
if not blob_read_success:
|
|
168
|
-
|
|
169
|
+
logging.info(f"Não foi possível carregar a tabela '{table_name}' do blob.")
|
|
169
170
|
#print("--> Onedrive fallback.")
|
|
170
171
|
#table_data = pd.read_parquet(table_path,engine="fastparquet")
|
|
171
172
|
update_time = self.blob_client.get_df_update_time(table_path)
|
|
172
173
|
|
|
173
174
|
assert(table_data is not None)
|
|
174
175
|
|
|
176
|
+
if not auto_convert_mapped_types:
|
|
177
|
+
return table_data, table_path, update_time
|
|
178
|
+
|
|
175
179
|
table_columns = set(table_data.columns)
|
|
176
180
|
|
|
177
181
|
float_dtypes = {"Last_Price", "Price", "px_last", "Quota", "#", "Avg_price", "Variation", "Variation_tot",
|
|
@@ -200,9 +204,9 @@ class LuxorQuery:
|
|
|
200
204
|
for col in table_columns.intersection(float_dtypes):
|
|
201
205
|
table_data[col] = table_data[col].astype(float)
|
|
202
206
|
except :
|
|
203
|
-
|
|
204
|
-
#
|
|
205
|
-
#
|
|
207
|
+
logging.info(f"Ao carregar tabela '{table_name}', nao foi possivel converter dados da coluna {col} para float.")
|
|
208
|
+
#logging.info(f"Colunas com erro: {table_columns.intersection(float_dtypes)}")
|
|
209
|
+
#logging.info(f"Colunas disponiveis: {table_columns}")
|
|
206
210
|
#print(table_data.dtypes)
|
|
207
211
|
|
|
208
212
|
raise ValueError(f"Erro ao converter colunas para float na tabela '{table_name}'.")
|
|
@@ -212,7 +216,7 @@ class LuxorQuery:
|
|
|
212
216
|
cols_to_format = list(set(table_data.columns) - {"Date", "Fund"})
|
|
213
217
|
table_data[cols_to_format] = table_data[cols_to_format].astype(float)
|
|
214
218
|
except ValueError:
|
|
215
|
-
|
|
219
|
+
logging.info("Ao carregar tabela 'hist_px_last', nao foi possivel converter dados para float.")
|
|
216
220
|
|
|
217
221
|
for col in table_columns.intersection(date_dtypes):
|
|
218
222
|
try:
|
|
@@ -227,7 +231,7 @@ class LuxorQuery:
|
|
|
227
231
|
.replace("false", "").replace("falso", "")
|
|
228
232
|
.replace("0", "").replace("nan", "").astype(bool))
|
|
229
233
|
except Exception:
|
|
230
|
-
|
|
234
|
+
logging.info(f"Ao carregar tabela '{table_name}', nao foi possivel converter dados da coluna {col} para bool.")
|
|
231
235
|
raise ValueError(f"Erro ao converter coluna {col} para bool na tabela '{table_name}'.")
|
|
232
236
|
|
|
233
237
|
for col in table_columns.intersection(str_nan_format):
|
|
@@ -238,7 +242,7 @@ class LuxorQuery:
|
|
|
238
242
|
return table_data.copy(), table_path, update_time
|
|
239
243
|
|
|
240
244
|
except Exception:
|
|
241
|
-
|
|
245
|
+
logging.info(f"Nao foi possivel carregar a tabela <{table_name}>.")
|
|
242
246
|
return None, None, None
|
|
243
247
|
|
|
244
248
|
#def __load_csv(table_name):
|
|
@@ -249,7 +253,7 @@ class LuxorQuery:
|
|
|
249
253
|
# table_data = pd.read_csv(table_path, sep=";")
|
|
250
254
|
# return table_data.copy(), table_path, update_time
|
|
251
255
|
# except Exception:
|
|
252
|
-
#
|
|
256
|
+
# logging.info(f"Nao foi possivel carregar a tabela <{table_name}> no formato .csv")
|
|
253
257
|
# return None, None, None
|
|
254
258
|
#
|
|
255
259
|
#def __load_excel(table_name):
|
|
@@ -258,7 +262,7 @@ class LuxorQuery:
|
|
|
258
262
|
# update_time = os.path.getmtime(table_path)
|
|
259
263
|
# # Nao deixar crashar caso nao consiga ler do excel !
|
|
260
264
|
# table_data = pd.read_excel(table_path)
|
|
261
|
-
#
|
|
265
|
+
# logging.info(f"Tabela {table_name} carregada do arquivo em excel. Limite 1M de linhas.")
|
|
262
266
|
# return table_data.copy(), table_path, update_time
|
|
263
267
|
# except FileNotFoundError:
|
|
264
268
|
# return None, table_path, None
|
|
@@ -271,7 +275,7 @@ class LuxorQuery:
|
|
|
271
275
|
|
|
272
276
|
#assert(table_data is not None)
|
|
273
277
|
if table_data is None:
|
|
274
|
-
|
|
278
|
+
logging.info(f"Nao foi possivel carregar a tabela <{table_name}>.")
|
|
275
279
|
return table_data
|
|
276
280
|
|
|
277
281
|
if index:
|
|
@@ -279,7 +283,7 @@ class LuxorQuery:
|
|
|
279
283
|
table_data = table_data.set_index(index_name, drop=True)
|
|
280
284
|
|
|
281
285
|
except Exception:
|
|
282
|
-
|
|
286
|
+
logging.info(f"Nao foi possível setar a coluna {index_name} como index para a tabela {table_name}.")
|
|
283
287
|
|
|
284
288
|
#table_data = self.__persist_column_formatting(table_data)
|
|
285
289
|
|
|
@@ -362,17 +366,17 @@ class LuxorQuery:
|
|
|
362
366
|
|
|
363
367
|
except PermissionError:
|
|
364
368
|
hist_prices_tables = [] # desconsidera appends feitos no loop nao concluido
|
|
365
|
-
|
|
366
|
-
|
|
369
|
+
logging.info("Não foi possível carregar as tabelas pois tem algum arquivo aberto.")
|
|
370
|
+
logging.info(f"Tentativas de atualização: {update_attempts} de {update_attempts_limit}")
|
|
367
371
|
time.sleep(30)
|
|
368
372
|
|
|
369
373
|
except:
|
|
370
|
-
|
|
371
|
-
|
|
374
|
+
logging.info("Não foi possivel carregar as tabelas.")
|
|
375
|
+
logging.info(f"Tentativas de atualização: {update_attempts} de {update_attempts_limit}")
|
|
372
376
|
time.sleep(5*update_attempts)
|
|
373
377
|
|
|
374
378
|
if not update_success:
|
|
375
|
-
|
|
379
|
+
logging.info("Nao foi possivel atualizar os dados. Execução finalizada.")
|
|
376
380
|
|
|
377
381
|
|
|
378
382
|
def text_to_lowercase(self, t):
|
|
@@ -386,7 +390,7 @@ class LuxorQuery:
|
|
|
386
390
|
try:
|
|
387
391
|
return t.map(lambda x: x.lower().strip() if isinstance(x, str) else x)
|
|
388
392
|
except AttributeError:
|
|
389
|
-
|
|
393
|
+
logging.info("Pendente de atualizacao para o python 3.12.2")
|
|
390
394
|
return t.applymap(lambda x: x.lower().strip() if isinstance(x, str) else x)
|
|
391
395
|
|
|
392
396
|
def get_px_update_time(self):
|
|
@@ -441,7 +445,7 @@ class LuxorQuery:
|
|
|
441
445
|
usdbrl = self.get_price(usdbrl_ticker, px_date=px_date)
|
|
442
446
|
currency_factor = usdbrl
|
|
443
447
|
except ValueError:
|
|
444
|
-
|
|
448
|
+
logging.info(f"Erro ao converter moeda para {currency} para o ticker '{ticker}'.")
|
|
445
449
|
currency_factor = 1
|
|
446
450
|
|
|
447
451
|
ticker = ticker.lower()
|
|
@@ -475,11 +479,11 @@ class LuxorQuery:
|
|
|
475
479
|
else:
|
|
476
480
|
#if px_last_at_date is None:
|
|
477
481
|
if logger_level == "trace":
|
|
478
|
-
|
|
482
|
+
logging.info(f"Preço nao disponivel para o ticker '{ticker}'. Preço setado para 0.")
|
|
479
483
|
elif logger_level == "info":
|
|
480
|
-
|
|
484
|
+
logging.info(f"Preço nao disponivel para o ticker '{ticker}'. Preço setado para 0.")
|
|
481
485
|
else: # logger_level == "erro":
|
|
482
|
-
|
|
486
|
+
logging.info(f"Preço nao disponivel para o ticker '{ticker}'. Preço setado para 0.")
|
|
483
487
|
px_last_at_date = 0
|
|
484
488
|
|
|
485
489
|
|
|
@@ -509,13 +513,13 @@ class LuxorQuery:
|
|
|
509
513
|
except (IndexError , KeyError):
|
|
510
514
|
# Nao achou o ativo em nenhuma das tabelas, retorna 0
|
|
511
515
|
if logger_level == "trace":
|
|
512
|
-
|
|
516
|
+
logging.info(f"Preço nao disponivel para o tikcker '{ticker}'. Preço setado para 0.")
|
|
513
517
|
elif logger_level == "info":
|
|
514
|
-
|
|
518
|
+
logging.info(f"Preço nao disponivel para o tikcker '{ticker}'. Preço setado para 0.")
|
|
515
519
|
else: # logger_level == "erro":
|
|
516
|
-
|
|
520
|
+
logging.info(f"Preço nao disponivel para o tikcker '{ticker}'. Preço setado para 0.")
|
|
517
521
|
|
|
518
|
-
|
|
522
|
+
logging.info(f"Preço nao disponivel para o tikcker '{ticker}'. Preço setado para 0.")
|
|
519
523
|
self.price_cache[cache_key] = px_last_at_date
|
|
520
524
|
return 0
|
|
521
525
|
|
|
@@ -640,7 +644,7 @@ class LuxorQuery:
|
|
|
640
644
|
force_month_end=force_month_end)
|
|
641
645
|
|
|
642
646
|
if recent_date < previous_date:
|
|
643
|
-
|
|
647
|
+
logging.info("Possivel inversao dos parametros de inicio e fim do periodo.")
|
|
644
648
|
temp = recent_date
|
|
645
649
|
recent_date = previous_date
|
|
646
650
|
previous_date = temp
|
|
@@ -707,7 +711,7 @@ class LuxorQuery:
|
|
|
707
711
|
|
|
708
712
|
if p[0] == 'not found':
|
|
709
713
|
assets_not_found = list(p[1]["Asset"].unique())
|
|
710
|
-
|
|
714
|
+
logging.info(f"currency_map nao suporta Location dos ativos {assets_not_found}.")
|
|
711
715
|
continue
|
|
712
716
|
price_currency = p[0]
|
|
713
717
|
|
|
@@ -769,7 +773,7 @@ class LuxorQuery:
|
|
|
769
773
|
|
|
770
774
|
convertion_data = convertion_rule.get(price_currency+"_"+dest_currency, None)
|
|
771
775
|
if convertion_data is None:
|
|
772
|
-
|
|
776
|
+
logging.info(f"Conversao de moeda nao disponivel para {price_currency} -> {dest_currency}.")
|
|
773
777
|
prices = pd.DataFrame({}, columns=prices.columns)
|
|
774
778
|
return prices
|
|
775
779
|
convertion_ticker = convertion_data["currency_ticker"]
|
|
@@ -810,19 +814,19 @@ class LuxorQuery:
|
|
|
810
814
|
data_value = self.last_all_flds[ticker+"_"+flds]["Value"]
|
|
811
815
|
except KeyError:
|
|
812
816
|
if logger_level == "trace":
|
|
813
|
-
|
|
817
|
+
logging.info(f"Dado de {flds} nao disponivel para o ticker '{ticker}'.")
|
|
814
818
|
elif logger_level == "info":
|
|
815
|
-
|
|
819
|
+
logging.info(f"Dado de {flds} nao disponivel para o ticker '{ticker}'.")
|
|
816
820
|
else: # logger_level == "erro":
|
|
817
|
-
|
|
821
|
+
logging.info(f"Dado de {flds} nao disponivel para o ticker '{ticker}'.")
|
|
818
822
|
return None
|
|
819
823
|
except KeyError:
|
|
820
824
|
if logger_level == "trace":
|
|
821
|
-
|
|
825
|
+
logging.info(f"Dado de {flds} nao disponivel para o ticker '{ticker}'.")
|
|
822
826
|
elif logger_level == "info":
|
|
823
|
-
|
|
827
|
+
logging.info(f"Dado de {flds} nao disponivel para o ticker '{ticker}'.")
|
|
824
828
|
else: # logger_level == "erro":
|
|
825
|
-
|
|
829
|
+
logging.info(f"Dado de {flds} nao disponivel para o ticker '{ticker}'.")
|
|
826
830
|
return None
|
|
827
831
|
|
|
828
832
|
# Formatando o valor retornado
|
|
@@ -833,7 +837,7 @@ class LuxorQuery:
|
|
|
833
837
|
if data_type == "date":
|
|
834
838
|
return dt.datetime.fromtimestamp(float(data_value))
|
|
835
839
|
if data_type != "text":
|
|
836
|
-
|
|
840
|
+
logging.info(f"field '{flds}' nao foi cadastrado na tabela field_map.")
|
|
837
841
|
return data_value
|
|
838
842
|
|
|
839
843
|
# Buscamos por dado numa data especifica.
|
|
@@ -845,7 +849,7 @@ class LuxorQuery:
|
|
|
845
849
|
if len(data) > 0:
|
|
846
850
|
return data.tail(1).squeeze()
|
|
847
851
|
except KeyError:
|
|
848
|
-
|
|
852
|
+
logging.info(f"Dado de {flds} nao disponivel para o ticker '{ticker}'.")
|
|
849
853
|
# Nenhum dado encontrado para a data informada
|
|
850
854
|
return None
|
|
851
855
|
|
|
@@ -1061,11 +1065,11 @@ class LuxorQuery:
|
|
|
1061
1065
|
complementary_previous_date=previous_date
|
|
1062
1066
|
|
|
1063
1067
|
if previous_date < dt.date(2018,12,31) and cash_ticker == 'jpmutcc lx equity':
|
|
1064
|
-
#
|
|
1068
|
+
#logging.info(f"Nao ha datas anteriores a {dt.date(2018,12,31)} para o JPMUTCC. Sera usada essa.")
|
|
1065
1069
|
previous_date = dt.date(2018,12,31)
|
|
1066
1070
|
|
|
1067
1071
|
if previous_date < dt.date(2020,3,2) and cash_ticker == 'sofrindx index':
|
|
1068
|
-
#
|
|
1072
|
+
#logging.info(f"Nao ha datas anteriores a {dt.date(2018,12,31)} para o JPMUTCC. Sera usada essa.")
|
|
1069
1073
|
previous_date = dt.date(2020,3,2)
|
|
1070
1074
|
|
|
1071
1075
|
|
|
@@ -1174,7 +1178,7 @@ class LuxorQuery:
|
|
|
1174
1178
|
force_month_end=force_month_end)
|
|
1175
1179
|
|
|
1176
1180
|
if recent_date < previous_date:
|
|
1177
|
-
|
|
1181
|
+
logging.info("Possivel inversao dos parametros de inicio e fim do periodo.")
|
|
1178
1182
|
temp = recent_date
|
|
1179
1183
|
recent_date = previous_date
|
|
1180
1184
|
previous_date = temp
|
|
@@ -1197,7 +1201,7 @@ class LuxorQuery:
|
|
|
1197
1201
|
if (previous_price == 0) or (previous_date is None) or (previous_price is None):
|
|
1198
1202
|
return 0
|
|
1199
1203
|
except ValueError:
|
|
1200
|
-
|
|
1204
|
+
logging.info(f"ValueError:\nticker:{ticker} previous_price: {previous_price} previous_date:{previous_date}")
|
|
1201
1205
|
|
|
1202
1206
|
if adjust_amortization:
|
|
1203
1207
|
last_price = self.get_quota_adjusted_by_amortization(ticker, last_price, recent_date)
|
|
@@ -1211,7 +1215,7 @@ class LuxorQuery:
|
|
|
1211
1215
|
usdbrl_ticker="bmfxclco curncy", adjust_amortization=False, force_month_end=False):
|
|
1212
1216
|
#TODO -> garantir que a tabela de precos esta sendo atualizada pelos precos no intraday
|
|
1213
1217
|
if adjust_amortization:
|
|
1214
|
-
|
|
1218
|
+
logging.info("Ajuste de amortizacao ainda NAO implementado para esse metodo.")
|
|
1215
1219
|
# Aproveitando a get_prices, para realizar as filtragens
|
|
1216
1220
|
pct_changes = self.get_prices(tickers=tickers, recent_date=recent_date,
|
|
1217
1221
|
previous_date=previous_date, currency=currency,
|
|
@@ -1906,7 +1910,12 @@ class LuxorQuery:
|
|
|
1906
1910
|
.fillna(0)+1).reset_index()
|
|
1907
1911
|
|
|
1908
1912
|
us_margin_cost = self.get_prices("sofr + 75bps", period="60m", currency=currency, usdbrl_ticker=usdbrl_ticker)
|
|
1909
|
-
|
|
1913
|
+
try:
|
|
1914
|
+
us_margin_cost["Date"] = us_margin_cost["Date"].dt.date
|
|
1915
|
+
except AttributeError:
|
|
1916
|
+
logging.info(f'Erro ao converter usd_margin_cost para date. currency:{currency}, usdbrl_ticker:{usdbrl_ticker}\
|
|
1917
|
+
{us_margin_cost.dtypes}')
|
|
1918
|
+
|
|
1910
1919
|
us_margin_cost = (us_margin_cost[["Date", "Last_Price"]]
|
|
1911
1920
|
.rename(columns={"Last_Price":"us_margin_cost"})
|
|
1912
1921
|
.set_index("Date").pct_change()
|
|
@@ -2151,28 +2160,34 @@ class LuxorQuery:
|
|
|
2151
2160
|
types_to_recalculate = ['ndf usdbrl']
|
|
2152
2161
|
# Separando os dados em dois grupos, para editar um deles
|
|
2153
2162
|
df_exposure = df.query("Type.isin(@types_to_recalculate)").copy()
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2163
|
+
if len(df_exposure) > 0:
|
|
2164
|
+
df = df.query("~Type.isin(@types_to_recalculate)").copy()
|
|
2165
|
+
# Calculo especifico para pnl do FX.
|
|
2166
|
+
|
|
2167
|
+
df_exposure["Pnl_Bought"] = df_exposure["Pnl_Bought"].astype('float')
|
|
2168
|
+
df_exposure["Pnl_Sold"] = df_exposure["Pnl_Sold"].astype('float')
|
|
2169
|
+
df_exposure["Pnl_Unchanged"] = df_exposure["Pnl_Unchanged"].astype('float')
|
|
2170
|
+
|
|
2171
|
+
df_exposure["Total_Pnl"] = df_exposure["Pnl_Bought"] + df_exposure["Pnl_Sold"] \
|
|
2172
|
+
+ df_exposure["Pnl_Unchanged"]
|
|
2173
|
+
|
|
2174
|
+
df_exposure = df_exposure.set_index(["Asset_ID"])
|
|
2175
|
+
# Valor de mercado sera o PnL acumulado
|
|
2176
|
+
|
|
2177
|
+
df_exposure["Total_Pnl"] = df_exposure.groupby(["Asset_ID"])["Total_Pnl"].cumsum()
|
|
2178
|
+
df_exposure = df_exposure.reset_index()
|
|
2179
|
+
df_exposure["Close_Mkt_Value"] = df_exposure["Total_Pnl"]
|
|
2180
|
+
df_exposure["Open_Mkt_Value"] = df_exposure["Close_Mkt_Value"].shift(1, fill_value=0)
|
|
2181
|
+
|
|
2182
|
+
# Retirando qualquer possibilidade de impacto para aporte e resgate
|
|
2183
|
+
df_exposure["Shares_Bought_Cost"] = 0
|
|
2184
|
+
df_exposure["Amount_Sold"] = 0
|
|
2185
|
+
# TODO Pensar o que vai mudar no caso de uma zeragem parcial
|
|
2186
|
+
df_exposure = df_exposure.drop(columns="Total_Pnl")
|
|
2187
|
+
|
|
2188
|
+
|
|
2189
|
+
# Juntando dfs novamente
|
|
2190
|
+
df = pd.concat([df, df_exposure])
|
|
2176
2191
|
|
|
2177
2192
|
# Calculando net de aporte e resgate por ativo
|
|
2178
2193
|
df["Cash_Flow"] = abs(df["Shares_Bought_Cost"]) + -abs(df["Amount_Sold"])
|
|
@@ -2344,7 +2359,7 @@ class LuxorQuery:
|
|
|
2344
2359
|
|
|
2345
2360
|
return float(hist_metrics[metrics].squeeze())
|
|
2346
2361
|
except KeyError:
|
|
2347
|
-
|
|
2362
|
+
logging.info(f"Metrica(s) {metrics} indisponivel(is)")
|
|
2348
2363
|
|
|
2349
2364
|
|
|
2350
2365
|
def get_risk_metric_variation(self, fund_name, recent_date, previous_date, metrics=None):
|
|
@@ -2370,7 +2385,7 @@ class LuxorQuery:
|
|
|
2370
2385
|
"""
|
|
2371
2386
|
|
|
2372
2387
|
if (previous_date is not None) and (previous_date > recent_date):
|
|
2373
|
-
|
|
2388
|
+
logging.info("Data inicial é menor que a data final. Parametros invertidos?")
|
|
2374
2389
|
sys.exit()
|
|
2375
2390
|
|
|
2376
2391
|
# Obtendo tabela de retornos historicos extraida do retorno consolidado
|
|
@@ -2395,7 +2410,7 @@ class LuxorQuery:
|
|
|
2395
2410
|
if type(segments) is list:
|
|
2396
2411
|
seg_filter = segments
|
|
2397
2412
|
else:
|
|
2398
|
-
|
|
2413
|
+
logging.info("'segments' precisa ser do tipo 'list' ou 'str'")
|
|
2399
2414
|
sys.exit()
|
|
2400
2415
|
|
|
2401
2416
|
group_results = group_results.query(" Segment.isin(@seg_filter)").copy()
|
|
@@ -2617,7 +2632,7 @@ class LuxorQuery:
|
|
|
2617
2632
|
return next_date
|
|
2618
2633
|
return month_ending
|
|
2619
2634
|
return next_date
|
|
2620
|
-
|
|
2635
|
+
logging.info("'mode' desconhecido.")
|
|
2621
2636
|
|
|
2622
2637
|
|
|
2623
2638
|
def calculate_attribution(self, fund, previous_date, recent_date, fund_currency):
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|