npm package: @infosel-sdk/markets
Description: Financial markets SDK for Infosel platform. Provides comprehensive tools for accessing market data, managing instruments, creating widgets, and handling workspaces for financial applications.
Author: Infosel Team
Latest version: 2.0.1

# @infosel-sdk/markets

SDK de Mercados Financieros para la plataforma Infosel. Proporciona herramientas completas para acceder a datos de mercado, buscar instrumentos y obtener detalles financieros para aplicaciones financieras.

## 🚀 Características

- **Acceso a Datos de Mercado**: Datos de mercado en tiempo real e históricos
- **Búsqueda de Instrumentos**: Buscar instrumentos financieros con filtros avanzados
- **Datos de Gráficos**: Acceder a datos de gráficos con múltiples marcos de tiempo
- **Reportes Financieros**: Acceder a datos financieros e informes de instrumentos
- **Detalles de Instrumentos**: Obtener perfiles y datos financieros detallados de instrumentos

## 📦 Instalación

```bash
npm install @infosel-sdk/markets
```

## 🚀 Inicio Rápido

### ✨ Configuración Moderna (Recomendado)

La nueva API del core proporciona una configuración más limpia y validada:

```typescript
import InfoselMarkets from '@infosel-sdk/markets';
import { InfoselSdkManager, AuthConfigurationBuilder } from '@infosel-sdk/core';

// Configuración moderna con Builder Pattern
const authConfig = AuthConfigurationBuilder.keyCloak()
  .withRealm('hub')
  .withEnvironment('qa')
  .withCredentials({
    grant_type: 'client_credentials',
    client_id: 'tu-client-id',
    client_secret: 'tu-client-secret',
  })
  .build();

// Inicializar SDK Manager con configuración moderna
const sdkManager = InfoselSdkManager.initWithConfiguration({
  authConfiguration: authConfig,
});

// Inicializar SDK de Mercados
const marketsSDK = InfoselMarkets.init({ sdkManager });

// Usar el SDK
const searchResults = await marketsSDK.searchInstruments({
  query: 'AAPL',
  limit: 10,
  offset: 0,
});
```

### Configuración con Token Existente

```typescript
import InfoselMarkets from '@infosel-sdk/markets';
import {
  InfoselSdkManager,
  AuthConfigurationBuilder,
  Token,
} from '@infosel-sdk/core';

// Configuración con token existente
const token: Token = {
  accessToken: 'tu-access-token',
  refreshToken: 'tu-refresh-token',
};

const authConfig = AuthConfigurationBuilder.existingToken()
  .withRealm('hub')
  .withEnvironment('prod')
  .withClientId('hub-app')
  .withToken(token)
  .build();

const sdkManager = InfoselSdkManager.initWithConfiguration({
  authConfiguration: authConfig,
});

const marketsSDK = InfoselMarkets.init({ sdkManager });
```

## 🔍 Validación de Configuración

La nueva API incluye validaciones robustas:

```typescript
import { AuthConfigurationBuilder } from '@infosel-sdk/core';

const builder = AuthConfigurationBuilder.keyCloak()
  .withRealm('invalid@realm') // Caracteres inválidos
  .withCredentials({
    grant_type: 'client_credentials',
    client_id: '', // Client ID vacío
    client_secret: 'secret',
  });

// Validar antes de construir
const validation = builder.validate();
if (!validation.isValid) {
  console.log('Errores:', validation.errors);
  // ['Realm contains invalid characters...', 'Client ID is required...']
}

// O validar automáticamente al construir
try {
  const config = builder.build();
} catch (error) {
  console.error(error.message); // Lista todos los errores de validación
}
```

## 📚 API Completa del SDK

### 🔍 Búsqueda y Gestión de Instrumentos

#### Buscar Instrumentos

```typescript
// Búsqueda básica
const searchResults = await marketsSDK.searchInstruments({
  query: 'AAPL',
  limit: 10,
});

// Búsqueda con filtros avanzados
const filteredResults = await marketsSDK.searchInstruments({
  query: 'TECH',
  limit: 20,
  marketTypeIds: [1, 2], // Tipos de mercado específicos
  valueTypeIds: [1], // Tipos de valor específicos
  exchangeIds: [1, 2], // Exchanges específicos
});

console.log('Instrumentos encontrados:', searchResults);
```

#### Obtener Campos del Instrumento

```typescript
const fields = await marketsSDK.getInstrumentFields({
  instrumentKey: '1/12576/0/AC*/AAPL',
  useCache: true, // Opcional
});

console.log('Campos del instrumento:', fields);
console.log('Precio actual:', fields.precioActual);
console.log('Variación:', fields.variacion);
```

### 📊 Detalles Financieros de Instrumentos

#### Perfil del Instrumento

```typescript
const profile = await marketsSDK.getInstrumentDetailProfile({
  instrumentKey: '1/12576/0/AC*/AAPL',
});

console.log('Perfil del instrumento:', profile);
```

#### Datos Financieros Trimestrales

```typescript
const quarterlyData = await marketsSDK.getInstrumentDetailFinancialQuartely({
  instrumentKey: '1/12576/0/AC*/AAPL',
  exercise: '2023',
  period: 4, // Q4
});

console.log('Datos trimestrales:', quarterlyData);
```

#### Datos Financieros Anuales

```typescript
const annualData = await marketsSDK.getInstrumentDetailFinancialAnnual({
  instrumentKey: '1/12576/0/AC*/AAPL',
  exercise: '2023',
  fields: 'revenue,profit,assets', // Opcional: campos específicos
});

console.log('Datos anuales:', annualData);
```

#### Razones Financieras del Instrumento

```typescript
const financialReasons = await marketsSDK.getInstrumentDetailFinancialReasons({
  instrumentKey: '1/12576/0/AC*/AAPL',
  exercise: '2023',
  period: 'Q4',
});

console.log('Razones financieras:', financialReasons);
```

#### Reportes Financieros con Razones

```typescript
const reportReasons = await marketsSDK.getInstrumentReportFinancialReasons({
  instrumentKey: '1/12576/0/AC*/AAPL',
  exercises: '2023,2022', // Opcional: múltiples ejercicios
});

console.log('Reporte con razones:', reportReasons);
```

### 📈 Datos de Gráficos

#### Obtener Datos de Gráfico

```typescript
// Gráfico diario
const dailyChart = await marketsSDK.getChartData({
  instrumentKey: '1/12576/0/AC*/AAPL',
  period: {
    type: 'day',
    value: 1,
    interval: 1,
  },
});

// Gráfico semanal
const weeklyChart = await marketsSDK.getChartData({
  instrumentKey: '1/12576/0/AC*/AAPL',
  period: {
    type: 'week',
    value: 4,
    interval: 1,
  },
});

// Gráfico mensual
const monthlyChart = await marketsSDK.getChartData({
  instrumentKey: '1/12576/0/AC*/AAPL',
  period: {
    type: 'month',
    value: 12,
    interval: 1,
  },
});

console.log('Datos del gráfico diario:', dailyChart);
```

#### Tipos de Períodos Disponibles

```typescript
// Tipos de período soportados:
// - 'day': Períodos diarios
// - 'week': Períodos semanales
// - 'month': Períodos mensuales
// - 'year': Períodos anuales

// Ejemplos de configuración:
const periods = {
  // 1 día con intervalos de 1 hora
  daily: { type: 'day', value: 1, interval: 1 },

  // 5 días con intervalos de 1 día
  week: { type: 'day', value: 5, interval: 1 },

  // 4 semanas con intervalos de 1 semana
  monthly: { type: 'week', value: 4, interval: 1 },

  // 12 meses con intervalos de 1 mes
  yearly: { type: 'month', value: 12, interval: 1 },
};
```

## 🔧 Ejemplos Prácticos Completos

### 📱 Dashboard de Trading Completo

```typescript
import InfoselMarkets from '@infosel-sdk/markets';
import { InfoselSdkManager, AuthConfigurationBuilder } from '@infosel-sdk/core';

class TradingDashboard {
  private marketsSDK: InfoselMarkets;

  constructor() {
    this.initializeSDK();
  }

  private async initializeSDK() {
    const authConfig = AuthConfigurationBuilder.keyCloak()
      .withRealm('hub')
      .withEnvironment('qa')
      .withCredentials({
        grant_type: 'client_credentials',
        client_id: process.env.KEYCLOAK_CLIENT_ID!,
        client_secret: process.env.KEYCLOAK_CLIENT_SECRET!,
      })
      .build();

    const sdkManager = InfoselSdkManager.initWithConfiguration({
      authConfiguration: authConfig,
    });

    this.marketsSDK = InfoselMarkets.init({ sdkManager });
  }

  // Obtener datos completos de un instrumento
  async getCompleteInstrumentData(instrumentKey: string) {
    try {
      // 1. Obtener campos del instrumento
      const fields = await this.marketsSDK.getInstrumentFields({
        instrumentKey,
      });

      // 2. Obtener datos del gráfico
      const chartData = await this.marketsSDK.getChartData({
        instrumentKey,
        period: { type: 'day', value: 30, interval: 1 },
      });

      // 3. Obtener perfil del instrumento
      const profile = await this.marketsSDK.getInstrumentDetailProfile({
        instrumentKey,
      });

      // 4. Obtener datos financieros
      const [quarterly, annual, financialReasons] = await Promise.all([
        this.marketsSDK.getInstrumentDetailFinancialQuartely({
          instrumentKey,
          exercise: '2023',
          period: 4,
        }),
        this.marketsSDK.getInstrumentDetailFinancialAnnual({
          instrumentKey,
          exercise: '2023',
          fields: 'revenue,profit',
        }),
        this.marketsSDK.getInstrumentDetailFinancialReasons({
          instrumentKey,
          exercise: '2023',
          period: 'Q4',
        }),
      ]);

      return {
        fields,
        chartData,
        profile,
        quarterly,
        annual,
        financialReasons,
      };
    } catch (error) {
      console.error('Error obteniendo datos del instrumento:', error);
      throw error;
    }
  }

  // Buscar instrumentos
  async searchInstruments(query: string, limit: number = 10) {
    try {
      const results = await this.marketsSDK.searchInstruments({
        query,
        limit,
      });
      return results;
    } catch (error) {
      console.error('Error buscando instrumentos:', error);
      throw error;
    }
  }

  // Obtener datos financieros
  async getFinancialData(instrumentKey: string) {
    try {
      const [quarterly, annual, profile] = await Promise.all([
        this.marketsSDK.getInstrumentDetailFinancialQuartely({
          instrumentKey,
          exercise: '2023',
          period: 4,
        }),
        this.marketsSDK.getInstrumentDetailFinancialAnnual({
          instrumentKey,
          exercise: '2023',
          fields: 'revenue,profit',
        }),
        this.marketsSDK.getInstrumentDetailProfile({
          instrumentKey,
        }),
      ]);

      return { quarterly, annual, profile };
    } catch (error) {
      console.error('Error obteniendo datos financieros:', error);
      throw error;
    }
  }
}

// Uso del dashboard
async function main() {
  const dashboard = new TradingDashboard();

  try {
    // Obtener datos completos de un instrumento
    const instrumentData = await dashboard.getCompleteInstrumentData(
      '1/12576/0/AC*/AAPL',
    );
    console.log('Datos del instrumento:', instrumentData);

    // Buscar instrumentos
    const searchResults = await dashboard.searchInstruments('TECH', 5);
    console.log('Resultados de búsqueda:', searchResults);

    // Obtener datos financieros
    const financialData = await dashboard.getFinancialData(
      '1/12576/0/AC*/AAPL',
    );
    console.log('Datos financieros:', financialData);
  } catch (error) {
    console.error('Error en main:', error);
  }
}

main();
```

### 🔍 Sistema de Búsqueda Avanzada

```typescript
class AdvancedInstrumentSearch {
  private marketsSDK: InfoselMarkets;

  constructor(marketsSDK: InfoselMarkets) {
    this.marketsSDK = marketsSDK;
  }

  // Búsqueda con múltiples filtros
  async searchWithFilters(options: {
    query: string;
    marketTypes?: number[]; // Tipos de mercado (ej: [1, 2] para Acciones y Bonos)
    valueTypes?: number[]; // Tipos de valor (ej: [1] para Equity)
    exchanges?: number[]; // Exchanges (ej: [1, 2] para NYSE y NASDAQ)
    limit?: number;
  }) {
    try {
      const results = await this.marketsSDK.searchInstruments({
        query: options.query,
        limit: options.limit || 20,
        marketTypeIds: options.marketTypes,
        valueTypeIds: options.valueTypes,
        exchangeIds: options.exchanges,
      });

      return results;
    } catch (error) {
      console.error('Error en búsqueda avanzada:', error);
      throw error;
    }
  }

  // Búsqueda por sector (filtra solo acciones)
  async searchBySector(sector: string, limit: number = 15) {
    return this.searchWithFilters({
      query: sector,
      limit,
      marketTypes: [1], // 1 = Mercado de acciones
    });
  }

  // Búsqueda por exchange específico
  async searchByExchange(exchange: string, limit: number = 15) {
    return this.searchWithFilters({
      query: exchange,
      limit,
      exchanges: [1, 2], // 1 = NYSE, 2 = NASDAQ
    });
  }
}

// Uso del sistema de búsqueda
const searchSystem = new AdvancedInstrumentSearch(marketsSDK);

// Búsqueda por sector
const techStocks = await searchSystem.searchBySector('TECHNOLOGY');
console.log('Acciones de tecnología:', techStocks);

// Búsqueda por exchange
const nasdaqStocks = await searchSystem.searchByExchange('NASDAQ');
console.log('Acciones del NASDAQ:', nasdaqStocks);
```

## 📚 Referencia de API

### Clases Principales

#### `InfoselMarkets`

Punto de entrada principal para el SDK de Mercados. Se inicializa usando el método estático `init()` que recibe el `InfoselSdkManager`.

#### `InfoselSdkManager`

Gestor central del SDK que maneja la configuración, autenticación y modo de operación. Se inicializa usando el método estático `initWithConfiguration()` con configuración moderna o `init()` con configuración legacy.

#### `AuthConfigurationBuilder`

Builder para crear configuraciones de autenticación validadas y centralizadas. Proporciona una API fluida para configurar autenticación KeyCloak y basada en tokens.

#### `MarketsMapper`

Mapeador de datos para convertir entre modelos de API y dominio.

### Métodos Disponibles

#### 🔍 Búsqueda y Campos de Instrumentos

| Método                          | Descripción                              | Parámetros                |
| ------------------------------- | ---------------------------------------- | ------------------------- |
| `searchInstruments()`           | Buscar instrumentos financieros          | `SearchInstrumentRequest` |
| `getInstrumentFields()`         | Obtener campos del instrumento           | `GetLastRequest`          |
| `getInstrumentMultipleFields()` | Obtener campos de múltiples instrumentos | `GetLastRequest`          |

#### 📊 Detalles de Instrumentos

| Método                                   | Descripción                      | Parámetros                                  |
| ---------------------------------------- | -------------------------------- | ------------------------------------------- |
| `getInstrumentDetailProfile()`           | Obtener perfil del instrumento   | `InstrumentDetailProfileRequest`            |
| `getInstrumentDetailFinancialQuartely()` | Datos financieros trimestrales   | `InstrumentDetailFinancialQuarterlyRequest` |
| `getInstrumentDetailFinancialAnnual()`   | Datos financieros anuales        | `InstrumentDetailFinancialAnnualRequest`    |
| `getInstrumentDetailFinancialReasons()`  | Razones financieras              | `InstrumentDetailFinancialReasonsRequest`   |
| `getInstrumentReportFinancialReasons()`  | Reportes financieros con razones | `InstrumentReportFinancialReasonsRequest`   |

#### 📈 Datos de Gráficos

| Método           | Descripción               | Parámetros     |
| ---------------- | ------------------------- | -------------- |
| `getChartData()` | Obtener datos de gráficos | `ChartRequest` |

### Entidades

#### Entidades Principales

- `Instrument`: Representación básica de instrumento financiero (instrumentKey, symbol)
- `InstrumentFields`: Campos completos de mercado de un instrumento
- `ChartItem`: Punto de datos del gráfico
- `SearchResultItem`: Elemento de resultado de búsqueda
- `InstrumentDetailProfile`: Perfil detallado del instrumento
- `InstrumentDetailFinancial`: Datos financieros del instrumento
- `InstrumentDetailFinancialReasons`: Razones financieras del instrumento
- `InstrumentReportFinancialReasons`: Reporte financiero con razones

#### Entidades de Solicitud/Respuesta

- `SearchInstrumentsRequest`: Parámetros de búsqueda de instrumentos
- `GetLastRequest`: Parámetros para obtener campos de instrumento
- `ChartRequest`: Parámetros de solicitud de datos de gráfico
- `InstrumentDetailProfileRequest`: Parámetros para obtener perfil
- `InstrumentDetailFinancialAnnualRequest`: Parámetros para datos anuales
- `InstrumentDetailFinancialQuarterlyRequest`: Parámetros para datos trimestrales
- `InstrumentDetailFinancialReasonsRequest`: Parámetros para razones financieras
- `InstrumentReportFinancialReasonsRequest`: Parámetros para reporte financiero

#### Tipos de Períodos de Gráficos

- `day`: Períodos diarios
- `week`: Períodos semanales
- `month`: Períodos mensuales
- `year`: Períodos anuales

## 🔗 Dependencias

- `@infosel-sdk/core`: Funcionalidad core del SDK (versión ^0.0.4)
- `axios`: Cliente HTTP
- `tslib`: Biblioteca runtime de TypeScript

## 🆕 Novedades en Core v0.0.4

### ✨ Configuration Builder Pattern

- **Nueva API fluida** para configuración sin duplicaciones
- **Validaciones centralizadas** con mensajes de error descriptivos
- **Single source of truth** para configuración de realm
- **Compatibilidad hacia atrás** mantenida

### 🔧 Mejoras en Configuración

- **Configuración dinámica de realm** para múltiples ambientes
- **Validación de formatos** de realm, client_id y credenciales
- **Valores por defecto inteligentes** basados en el tipo de autenticación
- **Type safety mejorado** con TypeScript

## 🧪 Testing

### Pruebas Unitarias

```bash
# Ejecutar tests unitarios
npm test

# Ejecutar tests con cobertura
npm run test:coverage
```

### Pruebas E2E (End-to-End)

Las pruebas e2e utilizan información real y autenticación con Keycloak para verificar el funcionamiento completo del SDK.

#### Configuración

```bash
# Variables de entorno requeridas
KEYCLOAK_CLIENT_ID=
KEYCLOAK_CLIENT_SECRET=
TEST_ENV=qa                    # qa, prod, preprod
TEST_TIMEOUT=30000            # Timeout en milisegundos
DEBUG_E2E=true                # Habilitar logs de debug
```

#### Ejecución

```bash
# Ejecutar todas las pruebas e2e
npm run test:e2e

# Ejecutar con debug habilitado
npm run test:e2e:debug

# Usando el script de utilidad
./src/__tests__/e2e/run-e2e.sh

# Con opciones personalizadas
./src/__tests__/e2e/run-e2e.sh -d -e prod -t 60000
```

#### Script de Utilidad

El script `run-e2e.sh` proporciona una interfaz fácil para ejecutar pruebas e2e:

```bash
# Mostrar ayuda
./src/__tests__/e2e/run-e2e.sh --help

# Ejecutar con configuración por defecto
./src/__tests__/e2e/run-e2e.sh

# Ejecutar en entorno de producción con debug
./src/__tests__/e2e/run-e2e.sh -d -e prod

# Ejecutar con credenciales personalizadas
./src/__tests__/e2e/run-e2e.sh -c my-client -s my-secret
```

#### Pruebas Incluidas

- **SDK Core Configuration**: Verificación de inicialización y autenticación
- **Markets API Integration**: Conexión real a la API de markets
- **Instrument Search**: Búsqueda de instrumentos con datos reales
- **Instrument Fields**: Obtención de campos de instrumentos
- **Performance and Reliability**: Verificación de tiempos de respuesta y concurrencia

#### Notas Importantes

- Las pruebas e2e requieren conectividad a internet
- Utilizan servicios reales, no mocks
- Los timeouts son más largos que en pruebas unitarias
- Se ejecutan secuencialmente para evitar conflictos
- No se incluyen en el coverage report

Para más detalles, consulta el [README de pruebas e2e](src/__tests__/e2e/README.md).

## 📞 Soporte

Para soporte y preguntas, por favor contacta al equipo de desarrollo de Infosel.

## 🔗 Paquetes Relacionados

- `@infosel-sdk/core`: Funcionalidad core del SDK (versión ^0.0.4)
- `@infosel-sdk/widgets`: SDK de widgets y espacios de trabajo (versión ^1.0.0)
- `@infosel-sdk/news`: SDK de noticias y contenido
- `@infosel-sdk/securities`: SDK de valores y trading

---