pyEscoAPI 0.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyEscoAPI-0.0.4/PKG-INFO +15 -0
- pyEscoAPI-0.0.4/README.md +1 -0
- pyEscoAPI-0.0.4/pyEscoAPI/__init__.py +6 -0
- pyEscoAPI-0.0.4/pyEscoAPI/esco_api.py +566 -0
- pyEscoAPI-0.0.4/pyEscoAPI.egg-info/PKG-INFO +15 -0
- pyEscoAPI-0.0.4/pyEscoAPI.egg-info/SOURCES.txt +10 -0
- pyEscoAPI-0.0.4/pyEscoAPI.egg-info/dependency_links.txt +1 -0
- pyEscoAPI-0.0.4/pyEscoAPI.egg-info/requires.txt +1 -0
- pyEscoAPI-0.0.4/pyEscoAPI.egg-info/top_level.txt +1 -0
- pyEscoAPI-0.0.4/pyproject.toml +23 -0
- pyEscoAPI-0.0.4/setup.cfg +4 -0
- pyEscoAPI-0.0.4/tests/test_client.py +155 -0
pyEscoAPI-0.0.4/PKG-INFO
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: pyEscoAPI
|
|
3
|
+
Version: 0.0.4
|
|
4
|
+
Summary: Python client for Esco API (Esco bolsa)
|
|
5
|
+
Author-email: Codetria <hola@codetria.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
Keywords: Esco,API,bolsa,client,market,provider
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.11
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
Requires-Dist: requests==2.31.0
|
|
14
|
+
|
|
15
|
+
# Python client for Esco API (Esco bolsa)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Python client for Esco API (Esco bolsa)
|
|
@@ -0,0 +1,566 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from datetime import datetime, timedelta
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from http import HTTPMethod
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
from requests import Response
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(f"{__name__}")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class APIVersion(Enum):
|
|
13
|
+
VERSION_9 = 9
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class EscoAPI:
|
|
17
|
+
base_url: str
|
|
18
|
+
username: str
|
|
19
|
+
password: str
|
|
20
|
+
client_id: str = ""
|
|
21
|
+
version: APIVersion = APIVersion.VERSION_9
|
|
22
|
+
|
|
23
|
+
__token: str = ""
|
|
24
|
+
__expire_datetime: datetime
|
|
25
|
+
|
|
26
|
+
def __make_request(
|
|
27
|
+
self,
|
|
28
|
+
request_endpoint: str,
|
|
29
|
+
request_method: HTTPMethod,
|
|
30
|
+
request_body: dict,
|
|
31
|
+
error_message: str = ""
|
|
32
|
+
):
|
|
33
|
+
req_call = getattr(requests, request_method.lower())
|
|
34
|
+
headers = {
|
|
35
|
+
"api-version": str(self.version.value)
|
|
36
|
+
}
|
|
37
|
+
if self.__token:
|
|
38
|
+
headers["Authorization"] = f"Bearer {self.__token}"
|
|
39
|
+
params = {
|
|
40
|
+
"url": f"{self.base_url}{request_endpoint}",
|
|
41
|
+
"json": request_body,
|
|
42
|
+
"headers": headers
|
|
43
|
+
}
|
|
44
|
+
result: Response = req_call(**params)
|
|
45
|
+
if 200 <= result.status_code <= 299:
|
|
46
|
+
return result.json()
|
|
47
|
+
else:
|
|
48
|
+
if not error_message:
|
|
49
|
+
error_message = f"Error during endpoint call: {request_endpoint}. Code: {result.status_code}"
|
|
50
|
+
raise ConnectionRefusedError(error_message)
|
|
51
|
+
|
|
52
|
+
def __esco_login(self):
|
|
53
|
+
req_body = {
|
|
54
|
+
"userName": self.username,
|
|
55
|
+
"password": self.password,
|
|
56
|
+
"clientId": self.client_id
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
result_data = self.__make_request(
|
|
60
|
+
request_endpoint="/login",
|
|
61
|
+
request_body=req_body,
|
|
62
|
+
request_method=HTTPMethod.POST,
|
|
63
|
+
error_message="Login to ESCO API failed."
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
self.__token = result_data["access_token"]
|
|
67
|
+
expires_in_minutes = result_data["expires_in"] - 1
|
|
68
|
+
self.__expire_datetime = datetime.now() + timedelta(minutes=expires_in_minutes)
|
|
69
|
+
|
|
70
|
+
def __pre_connection(self):
|
|
71
|
+
if datetime.now() > self.__expire_datetime:
|
|
72
|
+
self.__esco_login()
|
|
73
|
+
|
|
74
|
+
def __new__(cls, base_url: str, username: str, password: str, client_id: str, version: APIVersion):
|
|
75
|
+
if not hasattr(cls, 'instance'):
|
|
76
|
+
cls.instance = super(EscoAPI, cls).__new__(cls)
|
|
77
|
+
# noinspection PyUnresolvedReferences
|
|
78
|
+
return cls.instance
|
|
79
|
+
|
|
80
|
+
def __init__(
|
|
81
|
+
self,
|
|
82
|
+
base_url: str,
|
|
83
|
+
username: str,
|
|
84
|
+
password: str,
|
|
85
|
+
client_id: str = "",
|
|
86
|
+
version: APIVersion = APIVersion.VERSION_9
|
|
87
|
+
):
|
|
88
|
+
"""
|
|
89
|
+
Initializes the EscoAPI client, starting a login to the platform.
|
|
90
|
+
Instantiating a new EscoAPI client will not result in a new login (Singleton).
|
|
91
|
+
Login runs automatically when the last token expires.
|
|
92
|
+
:param base_url: The URL of your EscoAPI implementation. Include the protocol without slash at the end.
|
|
93
|
+
:param username: The username of your EscoAPI client.
|
|
94
|
+
:param password: The password of your EscoAPI client.
|
|
95
|
+
:param client_id: Optional. Include if you want to specify a client_id.
|
|
96
|
+
:param version: Optional. The EscoAPI version that you want to use. Default: Version 9.
|
|
97
|
+
"""
|
|
98
|
+
self.base_url = f"{base_url}/api/v{version.value}"
|
|
99
|
+
self.username = username
|
|
100
|
+
self.password = password
|
|
101
|
+
self.client_id = client_id
|
|
102
|
+
self.version = version
|
|
103
|
+
|
|
104
|
+
self.__esco_login()
|
|
105
|
+
|
|
106
|
+
def get_posiciones(
|
|
107
|
+
self,
|
|
108
|
+
cuenta: str,
|
|
109
|
+
por_concertacion: bool = True,
|
|
110
|
+
es_consolidado: bool = False,
|
|
111
|
+
incluir_monedas: bool = True,
|
|
112
|
+
incluir_titulos: bool = False,
|
|
113
|
+
incluir_opciones: bool = False,
|
|
114
|
+
incluir_futuros: bool = False,
|
|
115
|
+
incluir_fondos: bool = False,
|
|
116
|
+
solo_saldos_iniciales: bool = True
|
|
117
|
+
):
|
|
118
|
+
"""
|
|
119
|
+
Esta consulta devuelve las tenencias de instrumentos de una cuenta o una lista de cuentas a una fecha
|
|
120
|
+
indicada y discrimina vencimientos de 24, 48hs y futuro. Las tenencias no se valúan generando una
|
|
121
|
+
respuesta mas rapida de la consulta.
|
|
122
|
+
:param cuenta: Cuenta comitente a consultar.
|
|
123
|
+
:param por_concertacion: Indica si las tenencias se buscan por Fecha de Concertación o no.
|
|
124
|
+
:param es_consolidado: Indica si se muestran todas las cuentas del usuario consolidadas o solo la cuenta seleccionada
|
|
125
|
+
:param incluir_monedas: Indica si se incluyen tenencias de Monedas
|
|
126
|
+
:param incluir_titulos: Indica si se incluyen tenencias de Titulos
|
|
127
|
+
:param incluir_opciones: Indica si se incluyen tenencias de Opciones
|
|
128
|
+
:param incluir_futuros: Indica si se incluyen tenencias de Futuros
|
|
129
|
+
:param incluir_fondos: Indica si se incluyen tenencias de Fondos
|
|
130
|
+
:param solo_saldos_iniciales: Indica si solo se muestran saldos al inicio del día o se impactan movimientos realizados en en el dia
|
|
131
|
+
"""
|
|
132
|
+
req_body = {
|
|
133
|
+
"cuentas": cuenta,
|
|
134
|
+
"porConcertacion": por_concertacion,
|
|
135
|
+
"esConsolidado": es_consolidado,
|
|
136
|
+
"incluirMonedas": incluir_monedas,
|
|
137
|
+
"incluirTitulos": incluir_titulos,
|
|
138
|
+
"incluirOpciones": incluir_opciones,
|
|
139
|
+
"incluirFuturos": incluir_futuros,
|
|
140
|
+
"incluirFondos": incluir_fondos,
|
|
141
|
+
"soloSaldosIniciales": solo_saldos_iniciales
|
|
142
|
+
}
|
|
143
|
+
self.__pre_connection()
|
|
144
|
+
return self.__make_request(
|
|
145
|
+
request_endpoint="/get-posiciones",
|
|
146
|
+
request_body=req_body,
|
|
147
|
+
request_method=HTTPMethod.POST
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
def get_disponible_mon(
|
|
151
|
+
self,
|
|
152
|
+
cuenta: str,
|
|
153
|
+
fecha_disponible: datetime = datetime.now(),
|
|
154
|
+
moneda: str = "ARS",
|
|
155
|
+
dias_rescates_pendientes: int = 0,
|
|
156
|
+
dias_suscripciones_pendientes: int = 0,
|
|
157
|
+
plazo: int = 0,
|
|
158
|
+
incluye_creditos: bool = True,
|
|
159
|
+
fecha_colocacion_hasta: datetime = datetime.now(),
|
|
160
|
+
es_bloqueado_bcra: bool = False
|
|
161
|
+
):
|
|
162
|
+
"""
|
|
163
|
+
Esta consulta informa el disponible de moneda para una cuenta comitente a una fecha determinada.
|
|
164
|
+
La respuesta discrimina cómo se compone el saldo disponible.
|
|
165
|
+
|
|
166
|
+
:param cuenta: Código de Comitente
|
|
167
|
+
:param fecha_disponible: Fecha en que se pide la consulta
|
|
168
|
+
:param moneda: Código ISO de la moneda
|
|
169
|
+
:param dias_rescates_pendientes: Cantidad de días de antiguedad máximo para considerar Rescates pendientes de liquidación
|
|
170
|
+
:param dias_suscripciones_pendientes: Cantidad de días de antiguedad máximo para considerar Suscripciones pendientes de liquidación.
|
|
171
|
+
:param plazo: Plazo de liquidación del movimiento que se está cargando. Se suma al campo Fecha el plazo en días hábiles para calcular la fecha a la que se debe mostrar el disponible.
|
|
172
|
+
:param incluye_creditos: Indica si se deben considerar en el disponible los créditos para operar asignados en Back Office.
|
|
173
|
+
:param fecha_colocacion_hasta: Se usa en licitaciones, es la fecha de liquidación del proceso de licitación.
|
|
174
|
+
:param es_bloqueado_bcra: Indica si se discriminan los USD que no se pueden utilizar para compras según BCRA 7340
|
|
175
|
+
"""
|
|
176
|
+
req_body = {
|
|
177
|
+
"cuenta": cuenta,
|
|
178
|
+
"fechaDisponible": fecha_disponible.strftime('%Y-%m-%dT%H:%M:%S.%fZ'),
|
|
179
|
+
"moneda": moneda,
|
|
180
|
+
"diasRescatesPendientes": dias_rescates_pendientes,
|
|
181
|
+
"diasSuscripcionesPendientes": dias_suscripciones_pendientes,
|
|
182
|
+
"plazo": plazo,
|
|
183
|
+
"incluyeCreditos": incluye_creditos,
|
|
184
|
+
"fechaColocacionHasta": fecha_colocacion_hasta.strftime('%Y-%m-%dT%H:%M:%S.%fZ'),
|
|
185
|
+
"esBloqueadoBcra": es_bloqueado_bcra
|
|
186
|
+
}
|
|
187
|
+
self.__pre_connection()
|
|
188
|
+
return self.__make_request(
|
|
189
|
+
request_endpoint="/get-disponible-mon",
|
|
190
|
+
request_body=req_body,
|
|
191
|
+
request_method=HTTPMethod.POST
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
def get_tenencia_val(
|
|
195
|
+
self,
|
|
196
|
+
cuenta: str,
|
|
197
|
+
fecha: datetime = datetime.now(),
|
|
198
|
+
por_concertacion: bool = True,
|
|
199
|
+
es_consolidado: bool = False,
|
|
200
|
+
agrupar_por_moneda: bool = True,
|
|
201
|
+
moneda_valuacion: str = "ARS",
|
|
202
|
+
incluir_ppp: bool = False,
|
|
203
|
+
incluir_monedas: bool = True,
|
|
204
|
+
incluir_titulos: bool = False,
|
|
205
|
+
incluir_opciones: bool = False,
|
|
206
|
+
incluir_futuros: bool = False,
|
|
207
|
+
incluir_fondos: bool = False,
|
|
208
|
+
valuar_posicion: bool = True,
|
|
209
|
+
utiliza_cotizaciones_online: bool = True
|
|
210
|
+
):
|
|
211
|
+
"""
|
|
212
|
+
Esta consulta devuelve la tenencia valorizada de una cuenta a una determinada fecha.
|
|
213
|
+
:param cuenta: Código de Comitente
|
|
214
|
+
:param fecha: Fecha a la que se consultan las tenencias
|
|
215
|
+
:param por_concertacion: Indica si las tenencias se buscan por Fecha de Concertación o no.
|
|
216
|
+
:param es_consolidado: Indica si se muestran todas las cuentas del usuario consolidadas o solo la cuenta seleccionada.
|
|
217
|
+
:param agrupar_por_moneda: Indica si agrupa los instrumentos por moneda de emisión.
|
|
218
|
+
:param moneda_valuacion: Indica la moneda que se utiliza para valuar todos los instrumentos.
|
|
219
|
+
:param incluir_ppp: Indica si se incluye PPP
|
|
220
|
+
:param incluir_monedas: Indica si se incluyen tenencias de Monedas
|
|
221
|
+
:param incluir_titulos: Indica si se incluyen tenencias de Titulos
|
|
222
|
+
:param incluir_opciones: Indica si se incluyen tenencias de Opciones
|
|
223
|
+
:param incluir_futuros: Indica si se incluyen tenencias de Futuros
|
|
224
|
+
:param incluir_fondos: Indica si se incluyen tenencias de Fondos
|
|
225
|
+
:param valuar_posicion: Indica si se debe valuar la posición o no
|
|
226
|
+
:param utiliza_cotizaciones_online: Indica si utiliza cotizaciones online o busca directamente cotizaciones de VBolsa
|
|
227
|
+
"""
|
|
228
|
+
req_body = {
|
|
229
|
+
"cuentas": cuenta,
|
|
230
|
+
"fecha": fecha.strftime('%Y-%m-%dT%H:%M:%S.%fZ'),
|
|
231
|
+
"porConcertacion": por_concertacion,
|
|
232
|
+
"esConsolidado": es_consolidado,
|
|
233
|
+
"agruparPorMoneda": agrupar_por_moneda,
|
|
234
|
+
"monedaValuacion": moneda_valuacion,
|
|
235
|
+
"incluirPPP": incluir_ppp,
|
|
236
|
+
"incluirMonedas": incluir_monedas,
|
|
237
|
+
"incluirTitulos": incluir_titulos,
|
|
238
|
+
"incluirOpciones": incluir_opciones,
|
|
239
|
+
"incluirFuturos": incluir_futuros,
|
|
240
|
+
"incluirFondos": incluir_fondos,
|
|
241
|
+
"valuarPosicion": valuar_posicion,
|
|
242
|
+
"utilizaCotizacionesOnLine": utiliza_cotizaciones_online
|
|
243
|
+
}
|
|
244
|
+
self.__pre_connection()
|
|
245
|
+
return self.__make_request(
|
|
246
|
+
request_endpoint="/get-tenenciaval",
|
|
247
|
+
request_body=req_body,
|
|
248
|
+
request_method=HTTPMethod.POST
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
def get_tenencia_val_vencimientos(
|
|
252
|
+
self,
|
|
253
|
+
cuenta: str,
|
|
254
|
+
fecha: datetime = datetime.now(),
|
|
255
|
+
incluir_ppp: bool = True
|
|
256
|
+
):
|
|
257
|
+
"""
|
|
258
|
+
Esta consulta devuelve la valuación de una cuenta a una determinada fecha (por liquidación) y los
|
|
259
|
+
vencimientos posteriores a esa fecha.
|
|
260
|
+
:param cuenta: Código de Comitente
|
|
261
|
+
:param fecha: Fecha a la que se deben recuperar los movimientos que conforman los saldos. En esta consulta los movimientos se recuperan siempre por fecha de liquidación.
|
|
262
|
+
:param incluir_ppp: Indica si se incluye ppp en la consulta. PPP se genera en un proceso de Vbolsa.
|
|
263
|
+
"""
|
|
264
|
+
req_body = {
|
|
265
|
+
"cuentas": cuenta,
|
|
266
|
+
"fecha": fecha.strftime('%Y-%m-%dT%H:%M:%S.%fZ'),
|
|
267
|
+
"incluirPPP": incluir_ppp
|
|
268
|
+
}
|
|
269
|
+
self.__pre_connection()
|
|
270
|
+
return self.__make_request(
|
|
271
|
+
request_endpoint="/get-tenenciaval-vencimientos",
|
|
272
|
+
request_body=req_body,
|
|
273
|
+
request_method=HTTPMethod.POST
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
def get_rendimiento_cartera(
|
|
277
|
+
self,
|
|
278
|
+
cuenta: str,
|
|
279
|
+
fecha_desde: datetime = datetime.now() - timedelta(days=15),
|
|
280
|
+
fecha_hasta: datetime = datetime.now(),
|
|
281
|
+
por_concertacion: bool = True
|
|
282
|
+
):
|
|
283
|
+
"""
|
|
284
|
+
|
|
285
|
+
:param cuenta: Número de Cuenta Comitente
|
|
286
|
+
:param fecha_desde: Fecha inicial del período de Rendimientos consultado.
|
|
287
|
+
:param fecha_hasta: Fecha final del período de Rendimientos consultado.
|
|
288
|
+
:param por_concertacion: Indica si saldos y movimientos involucrados en esta consulta se buscan por Fecha de Concertación o Liquidación.
|
|
289
|
+
"""
|
|
290
|
+
req_body = {
|
|
291
|
+
"cuenta": cuenta,
|
|
292
|
+
"fechaDesde": fecha_desde.strftime('%Y-%m-%dT%H:%M:%S.%fZ'),
|
|
293
|
+
"fechaHasta": fecha_hasta.strftime('%Y-%m-%dT%H:%M:%S.%fZ'),
|
|
294
|
+
"porConcertacion": por_concertacion
|
|
295
|
+
}
|
|
296
|
+
self.__pre_connection()
|
|
297
|
+
return self.__make_request(
|
|
298
|
+
request_endpoint="/get-rendimiento-cartera",
|
|
299
|
+
request_body=req_body,
|
|
300
|
+
request_method=HTTPMethod.POST
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
def get_instrumentos(
|
|
304
|
+
self,
|
|
305
|
+
cod_tp_especie: int,
|
|
306
|
+
page_number: int = 1,
|
|
307
|
+
page_size: int = 200,
|
|
308
|
+
solo_byma: bool = True
|
|
309
|
+
):
|
|
310
|
+
"""
|
|
311
|
+
Es una consulta de Instrumentos que se pueden operar. Se toman de la tabla que registra todos los
|
|
312
|
+
instrumentos para operar WEB. La respuesta es paginada.
|
|
313
|
+
:param cod_tp_especie: Codigo interno del tipo de especie.
|
|
314
|
+
:param page_number: Número de página a mostrar.
|
|
315
|
+
:param page_size: Cantidad de registros por página.
|
|
316
|
+
:param solo_byma:Indica si solo se recuperan los Instrumentos con Abreviaturas Byma. Por defecto informa solo Byma.
|
|
317
|
+
"""
|
|
318
|
+
req_body = {
|
|
319
|
+
"codTpEspecie": cod_tp_especie,
|
|
320
|
+
"soloByMA": solo_byma,
|
|
321
|
+
"paramPagination": {
|
|
322
|
+
"pageNumber": page_number,
|
|
323
|
+
"pageSize": page_size
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
self.__pre_connection()
|
|
327
|
+
return self.__make_request(
|
|
328
|
+
request_endpoint="/get-instrumentos-paginada",
|
|
329
|
+
request_body=req_body,
|
|
330
|
+
request_method=HTTPMethod.POST
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
def get_cotizaciones(self, instrumento: str, exact_match: bool = True):
|
|
334
|
+
"""
|
|
335
|
+
Es una consulta de cotizaciones de instrumentos, se busca en la información en la tabla de cotizaciones
|
|
336
|
+
online que registra cotizaciones para un mismo instrumento en distintas monedas y plazos
|
|
337
|
+
:param instrumento: Abreviatura o descripción del instrumento. Se puede ingresar total o parcial dependiendo del siguiente parámetro.
|
|
338
|
+
:param exact_match: Este parámetro indica si se debe busca exacto el texto ingresado o no.
|
|
339
|
+
"""
|
|
340
|
+
req_body = {
|
|
341
|
+
"instrumento": instrumento,
|
|
342
|
+
"exactMatch": exact_match
|
|
343
|
+
}
|
|
344
|
+
self.__pre_connection()
|
|
345
|
+
return self.__make_request(
|
|
346
|
+
request_endpoint="/get-cotizaciones",
|
|
347
|
+
request_body=req_body,
|
|
348
|
+
request_method=HTTPMethod.POST
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
def get_cotizaciones_fondos(self):
|
|
352
|
+
"""
|
|
353
|
+
Es una consulta de cotizaciones y datos de Fondos Comunes de Inversión. Se informan las cotizaciones
|
|
354
|
+
cargadas en VBolsa.
|
|
355
|
+
:return:
|
|
356
|
+
"""
|
|
357
|
+
self.__pre_connection()
|
|
358
|
+
return self.__make_request(
|
|
359
|
+
request_endpoint="/get-cotizaciones-fondos",
|
|
360
|
+
request_body={},
|
|
361
|
+
request_method=HTTPMethod.POST
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
def get_cotizaciones_historicas(
|
|
365
|
+
self,
|
|
366
|
+
instrumento: str,
|
|
367
|
+
fecha_desde: datetime = datetime.now() - timedelta(days=7),
|
|
368
|
+
fecha_hasta: datetime = datetime.now()
|
|
369
|
+
):
|
|
370
|
+
"""
|
|
371
|
+
Es una consulta de cotizaciones históricas de un instrumento. Se informan las cotizaciones cargadas en VBolsa.
|
|
372
|
+
:param instrumento: Abreviatura del instrumento, se puede ingresar cualquier abreviatura vinculada. Se recupera la cotización de cierre que está cargada en VBolsa, la abreviatura se usa para ubicar el instrumento.
|
|
373
|
+
:param fecha_desde: Fecha inicial de la consulta.
|
|
374
|
+
:param fecha_hasta: Fecha final de la consulta.
|
|
375
|
+
"""
|
|
376
|
+
req_body = {
|
|
377
|
+
"instrumento": instrumento,
|
|
378
|
+
"fechaDesde": fecha_desde.strftime('%Y-%m-%dT%H:%M:%S.%fZ'),
|
|
379
|
+
"fechaHasta": fecha_hasta.strftime('%Y-%m-%dT%H:%M:%S.%fZ'),
|
|
380
|
+
}
|
|
381
|
+
self.__pre_connection()
|
|
382
|
+
return self.__make_request(
|
|
383
|
+
request_endpoint="/get-cotizaciones-historicas",
|
|
384
|
+
request_body=req_body,
|
|
385
|
+
request_method=HTTPMethod.POST
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
def get_cotizaciones_historicas_fci(
|
|
389
|
+
self,
|
|
390
|
+
instrumento: str,
|
|
391
|
+
fecha_desde: datetime = datetime.now() - timedelta(days=7),
|
|
392
|
+
fecha_hasta: datetime = datetime.now()
|
|
393
|
+
):
|
|
394
|
+
"""
|
|
395
|
+
Es una consulta de cotizaciones históricas de un FCI. Se informan las cotizaciones cargadas en VBolsa.
|
|
396
|
+
:param instrumento: Código de Interfaz Bloomberg del Fondo.
|
|
397
|
+
:param fecha_desde: Fecha inicial de la consulta.
|
|
398
|
+
:param fecha_hasta: Fecha final de la consulta.
|
|
399
|
+
"""
|
|
400
|
+
req_body = {
|
|
401
|
+
"instrumento": instrumento,
|
|
402
|
+
"fechaDesde": fecha_desde.strftime('%Y-%m-%dT%H:%M:%S.%fZ'),
|
|
403
|
+
"fechaHasta": fecha_hasta.strftime('%Y-%m-%dT%H:%M:%S.%fZ'),
|
|
404
|
+
}
|
|
405
|
+
self.__pre_connection()
|
|
406
|
+
return self.__make_request(
|
|
407
|
+
request_endpoint="/get-cotizaciones-historicas-fci",
|
|
408
|
+
request_body=req_body,
|
|
409
|
+
request_method=HTTPMethod.POST
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
def get_instrumento(self, abreviatura: str):
|
|
413
|
+
"""
|
|
414
|
+
Devuelve los instrumentos filtrados por su abreviatura.
|
|
415
|
+
:param abreviatura: Abreviatura del instrumento, se puede ingresar cualquier abreviatura vinculada.
|
|
416
|
+
"""
|
|
417
|
+
req_body = {
|
|
418
|
+
"abreviatura": abreviatura
|
|
419
|
+
}
|
|
420
|
+
self.__pre_connection()
|
|
421
|
+
return self.__make_request(
|
|
422
|
+
request_endpoint="/get-instrumento",
|
|
423
|
+
request_body=req_body,
|
|
424
|
+
request_method=HTTPMethod.POST
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
def get_cotizaciones_cierre_search(self, instrumento: str, mercado: str = "ME"):
|
|
428
|
+
"""
|
|
429
|
+
Es una consulta de cotizaciones de cierre de instrumentos
|
|
430
|
+
:param instrumento: Abreviatura del instrumento, se puede ingresar cualquier abreviatura vinculada. Se recupera la cotización de cierre que esta cargada en VBolsa, la abreviatura se usa para ubicar el instrumento.
|
|
431
|
+
:param mercado: Mercado al cual corresponde la abreviatura ingresada. Default: ME (ByMA)
|
|
432
|
+
:return:
|
|
433
|
+
"""
|
|
434
|
+
req_body = {
|
|
435
|
+
"instrumento": instrumento,
|
|
436
|
+
"mercado": mercado
|
|
437
|
+
}
|
|
438
|
+
self.__pre_connection()
|
|
439
|
+
return self.__make_request(
|
|
440
|
+
request_endpoint="/get-cotizaciones-cierre-search",
|
|
441
|
+
request_body=req_body,
|
|
442
|
+
request_method=HTTPMethod.POST
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
def get_monedas(self):
|
|
446
|
+
"""
|
|
447
|
+
Devuelve la lista de Monedas habilitadas.
|
|
448
|
+
"""
|
|
449
|
+
self.__pre_connection()
|
|
450
|
+
return self.__make_request(
|
|
451
|
+
request_endpoint="/get-monedas",
|
|
452
|
+
request_body={},
|
|
453
|
+
request_method=HTTPMethod.GET
|
|
454
|
+
)
|
|
455
|
+
|
|
456
|
+
def get_feriados(self):
|
|
457
|
+
"""
|
|
458
|
+
Devuelve la lista de Feriados habilitados.
|
|
459
|
+
"""
|
|
460
|
+
self.__pre_connection()
|
|
461
|
+
return self.__make_request(
|
|
462
|
+
request_endpoint="/get-feriados",
|
|
463
|
+
request_body={},
|
|
464
|
+
request_method=HTTPMethod.GET
|
|
465
|
+
)
|
|
466
|
+
|
|
467
|
+
def get_provincias(self):
|
|
468
|
+
"""
|
|
469
|
+
Devuelve la lista de Provincias habilitadas.
|
|
470
|
+
"""
|
|
471
|
+
self.__pre_connection()
|
|
472
|
+
return self.__make_request(
|
|
473
|
+
request_endpoint="/get-provincias",
|
|
474
|
+
request_body={},
|
|
475
|
+
request_method=HTTPMethod.GET
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
def get_paises(self):
|
|
479
|
+
"""
|
|
480
|
+
Devuelve la lista de Paises habilitados.
|
|
481
|
+
"""
|
|
482
|
+
self.__pre_connection()
|
|
483
|
+
return self.__make_request(
|
|
484
|
+
request_endpoint="/get-paises",
|
|
485
|
+
request_body={},
|
|
486
|
+
request_method=HTTPMethod.GET
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
def get_tipos_especies(self):
|
|
490
|
+
"""
|
|
491
|
+
Devuelve la lista de tipos de especies.
|
|
492
|
+
"""
|
|
493
|
+
self.__pre_connection()
|
|
494
|
+
return self.__make_request(
|
|
495
|
+
request_endpoint="/get-tipos-especies",
|
|
496
|
+
request_body={},
|
|
497
|
+
request_method=HTTPMethod.GET
|
|
498
|
+
)
|
|
499
|
+
|
|
500
|
+
def get_tipos_fondos(self):
|
|
501
|
+
"""
|
|
502
|
+
Devuelve la lista de tipos de especies.
|
|
503
|
+
"""
|
|
504
|
+
self.__pre_connection()
|
|
505
|
+
return self.__make_request(
|
|
506
|
+
request_endpoint="/get-tipos-fondos",
|
|
507
|
+
request_body={},
|
|
508
|
+
request_method=HTTPMethod.GET
|
|
509
|
+
)
|
|
510
|
+
|
|
511
|
+
def get_tipos_riesgo_comitente(self):
|
|
512
|
+
"""
|
|
513
|
+
Devuelve la lista de tipos de riesgo de Comitente.
|
|
514
|
+
"""
|
|
515
|
+
self.__pre_connection()
|
|
516
|
+
return self.__make_request(
|
|
517
|
+
request_endpoint="/get-tipos-riesgo-comitente",
|
|
518
|
+
request_body={},
|
|
519
|
+
request_method=HTTPMethod.GET
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
def get_detalle_cuenta(self, cuenta: str):
|
|
523
|
+
"""
|
|
524
|
+
Esta consulta muestra el detalle de datos de la cuenta
|
|
525
|
+
:param cuenta: Número de Comitente.
|
|
526
|
+
"""
|
|
527
|
+
req_body = {
|
|
528
|
+
"cuenta": cuenta,
|
|
529
|
+
"timeStamp": 13128022,
|
|
530
|
+
"paramPagination": {
|
|
531
|
+
"pageNumber": 1,
|
|
532
|
+
"pageSize": 1
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
self.__pre_connection()
|
|
536
|
+
return self.__make_request(
|
|
537
|
+
request_endpoint="/get-detalle-cuenta",
|
|
538
|
+
request_body=req_body,
|
|
539
|
+
request_method=HTTPMethod.POST
|
|
540
|
+
)
|
|
541
|
+
|
|
542
|
+
def get_cuentas_por_cuit(self, cuit: str):
|
|
543
|
+
"""
|
|
544
|
+
Es una consulta que informa las cuentas comitente que corresponden al CUIT ingresado. El cuit puede
|
|
545
|
+
ser del comitente o de los condóminos.
|
|
546
|
+
:param cuit: Nro de CUIT a buscar. Se deben ingresar solo numeros.
|
|
547
|
+
"""
|
|
548
|
+
self.__pre_connection()
|
|
549
|
+
return self.__make_request(
|
|
550
|
+
request_endpoint=f"/get-cuentas-por-cuit?CUIT={cuit}",
|
|
551
|
+
request_body={},
|
|
552
|
+
request_method=HTTPMethod.GET
|
|
553
|
+
)
|
|
554
|
+
|
|
555
|
+
def get_persona(self, num_doc: int, tipo_doc: int = 1):
|
|
556
|
+
"""
|
|
557
|
+
Retorna datos de una persona filtrando por tipo y número de documento.
|
|
558
|
+
:param num_doc: Número de documento de la Persona a buscar.
|
|
559
|
+
:param tipo_doc: Código del Tipo de Documento. 1: DNI, 2: Pasaporte, 3: Otros.
|
|
560
|
+
"""
|
|
561
|
+
self.__pre_connection()
|
|
562
|
+
return self.__make_request(
|
|
563
|
+
request_endpoint=f"/get-persona?tipoDoc={tipo_doc}&numDoc={num_doc}",
|
|
564
|
+
request_body={},
|
|
565
|
+
request_method=HTTPMethod.GET
|
|
566
|
+
)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: pyEscoAPI
|
|
3
|
+
Version: 0.0.4
|
|
4
|
+
Summary: Python client for Esco API (Esco bolsa)
|
|
5
|
+
Author-email: Codetria <hola@codetria.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
Keywords: Esco,API,bolsa,client,market,provider
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.11
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
Requires-Dist: requests==2.31.0
|
|
14
|
+
|
|
15
|
+
# Python client for Esco API (Esco bolsa)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
pyEscoAPI/__init__.py
|
|
4
|
+
pyEscoAPI/esco_api.py
|
|
5
|
+
pyEscoAPI.egg-info/PKG-INFO
|
|
6
|
+
pyEscoAPI.egg-info/SOURCES.txt
|
|
7
|
+
pyEscoAPI.egg-info/dependency_links.txt
|
|
8
|
+
pyEscoAPI.egg-info/requires.txt
|
|
9
|
+
pyEscoAPI.egg-info/top_level.txt
|
|
10
|
+
tests/test_client.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
requests==2.31.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pyEscoAPI
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = 'pyEscoAPI'
|
|
7
|
+
version = "0.0.4"
|
|
8
|
+
license = {text = "MIT License"}
|
|
9
|
+
authors = [
|
|
10
|
+
{ name="Codetria", email="hola@codetria.com" },
|
|
11
|
+
]
|
|
12
|
+
dependencies = [
|
|
13
|
+
"requests==2.31.0"
|
|
14
|
+
]
|
|
15
|
+
keywords = ["Esco", "API", "bolsa", "client", "market", "provider"]
|
|
16
|
+
description = 'Python client for Esco API (Esco bolsa)'
|
|
17
|
+
readme = "README.md"
|
|
18
|
+
requires-python = ">=3.11"
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"License :: OSI Approved :: MIT License",
|
|
22
|
+
"Operating System :: OS Independent",
|
|
23
|
+
]
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from datetime import datetime, timedelta
|
|
3
|
+
|
|
4
|
+
import pytest
|
|
5
|
+
|
|
6
|
+
from pyEscoAPI import EscoAPI
|
|
7
|
+
from pyEscoAPI.esco_api import APIVersion
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@pytest.fixture
|
|
11
|
+
def api_client():
|
|
12
|
+
return EscoAPI(
|
|
13
|
+
base_url=os.getenv("base_url"),
|
|
14
|
+
username=os.getenv("user_name"),
|
|
15
|
+
password=os.getenv("password"),
|
|
16
|
+
client_id=os.getenv("client_id"),
|
|
17
|
+
version=APIVersion.VERSION_9
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_get_posiciones(api_client):
|
|
22
|
+
cuenta = "351008539"
|
|
23
|
+
result = api_client.get_posiciones(cuenta=cuenta)
|
|
24
|
+
assert result[0]["cuenta"] == int(cuenta)
|
|
25
|
+
assert result[0]["abreviatura"] == "ARS"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_get_disponible_mon(api_client):
|
|
29
|
+
cuenta = "351008539"
|
|
30
|
+
result = api_client.get_disponible_mon(cuenta=cuenta)
|
|
31
|
+
assert result[0]["orden"] == 0
|
|
32
|
+
assert result[0]["simbolo"] == "ARS"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_get_tenencia_val(api_client):
|
|
36
|
+
cuenta = "351008539"
|
|
37
|
+
result = api_client.get_tenencia_val(cuenta=cuenta)
|
|
38
|
+
assert result[0]["grupo"] == "MON"
|
|
39
|
+
assert result[0]["abreviatura"] == "ARS"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_get_tenencia_val_vencimientos(api_client):
|
|
43
|
+
cuenta = "351008539"
|
|
44
|
+
result = api_client.get_tenencia_val_vencimientos(cuenta=cuenta)
|
|
45
|
+
assert result[0]["grupo"] == "MON"
|
|
46
|
+
assert result[0]["abreviatura"] == "ARS"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_get_rendimiento_cartera(api_client):
|
|
50
|
+
cuenta = "351008539"
|
|
51
|
+
result = api_client.get_rendimiento_cartera(cuenta=cuenta)
|
|
52
|
+
assert "resultados1" in result
|
|
53
|
+
assert "resultados2" in result
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_get_instrumentos(api_client):
|
|
57
|
+
cod_tp_especie = 2 # Bonos (Titulos Publicos)
|
|
58
|
+
result = api_client.get_instrumentos(cod_tp_especie=cod_tp_especie)
|
|
59
|
+
assert result["data"][0]["tpEspecie"] == "Titulo Publicos"
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_get_cotizaciones(api_client):
|
|
63
|
+
instrumento = "AL30"
|
|
64
|
+
result = api_client.get_cotizaciones(instrumento=instrumento)
|
|
65
|
+
assert result[0]["abreviatura"] == "AL30"
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def test_get_cotizaciones_fondos(api_client):
|
|
69
|
+
result = api_client.get_cotizaciones_fondos()
|
|
70
|
+
assert len(result) > 0
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_get_cotizaciones_historicas(api_client):
|
|
74
|
+
instrumento = "AL30"
|
|
75
|
+
result = api_client.get_cotizaciones_historicas(
|
|
76
|
+
instrumento=instrumento,
|
|
77
|
+
fecha_desde=datetime.now() - timedelta(days=30)
|
|
78
|
+
)
|
|
79
|
+
assert result[0]["moneda"] == "ARS"
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def test_get_cotizaciones_historicas_fci(api_client):
|
|
83
|
+
instrumento = "CPYMESA AR"
|
|
84
|
+
result = api_client.get_cotizaciones_historicas_fci(
|
|
85
|
+
instrumento=instrumento,
|
|
86
|
+
fecha_desde=datetime.now() - timedelta(days=30)
|
|
87
|
+
)
|
|
88
|
+
assert result[0]["moneda"] == "ARS"
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def test_get_cotizaciones_cierre_search(api_client):
|
|
92
|
+
instrumento = "AL30"
|
|
93
|
+
result = api_client.get_cotizaciones_cierre_search(
|
|
94
|
+
instrumento=instrumento
|
|
95
|
+
)
|
|
96
|
+
assert result[0]["monedaAbreviatura"] == "ARS"
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def test_get_instrumento(api_client):
|
|
100
|
+
instrumento = "COME"
|
|
101
|
+
result = api_client.get_instrumento(abreviatura=instrumento)
|
|
102
|
+
assert result[0]["moneda"] == "ARS"
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def test_get_monedas(api_client):
|
|
106
|
+
result = api_client.get_monedas()
|
|
107
|
+
assert result[0]["simbolo"] == "ARS"
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def test_get_feriados(api_client):
|
|
111
|
+
result = api_client.get_feriados()
|
|
112
|
+
assert len(result) > 0
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def test_get_provincias(api_client):
|
|
116
|
+
result = api_client.get_provincias()
|
|
117
|
+
assert len(result) > 0
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def test_get_paises(api_client):
|
|
121
|
+
result = api_client.get_paises()
|
|
122
|
+
assert len(result) > 0
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def test_get_tipos_especies(api_client):
|
|
126
|
+
result = api_client.get_tipos_especies()
|
|
127
|
+
assert len(result) > 0
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def test_get_tipos_fondos(api_client):
|
|
131
|
+
result = api_client.get_tipos_fondos()
|
|
132
|
+
assert len(result) >= 0 # Returns no result in dev for some reason
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def test_get_tipos_riesgo_comitente(api_client):
|
|
136
|
+
result = api_client.get_tipos_riesgo_comitente()
|
|
137
|
+
assert len(result) > 0
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def test_get_detalle_cuenta(api_client):
|
|
141
|
+
cuenta = "351008539"
|
|
142
|
+
result = api_client.get_detalle_cuenta(cuenta=cuenta)
|
|
143
|
+
assert result["data"][0]["cuentaDetalle"]["numComitente"] == int(cuenta)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def test_get_cuentas_por_cuit(api_client):
|
|
147
|
+
cuit = "20076387878"
|
|
148
|
+
result = api_client.get_cuentas_por_cuit(cuit)
|
|
149
|
+
assert len(result) > 0
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def test_get_persona(api_client):
|
|
153
|
+
dni = 7638787
|
|
154
|
+
result = api_client.get_persona(num_doc=dni)
|
|
155
|
+
assert int(result["numDoc"]) == dni
|