@infosel-sdk/funds
v1.0.2
Published
SDK de Fondos para la plataforma de servicios financieros Infosel
Readme
@infosel-sdk/funds
SDK de Fondos para la plataforma de servicios financieros Infosel. Proporciona acceso completo a información de fondos de inversión, incluyendo prospectos, rendimientos históricos, precios y datos fundamentales.
🚀 Características
- 📊 Información de Fondos: Acceso a datos completos de fondos de inversión
- 📈 Rendimientos: Cálculo de rendimientos en múltiples períodos (diario, semanal, mensual, anual)
- 📋 Prospectos: Información detallada de prospectos de fondos
- 📊 Precios Históricos: Datos históricos de precios con diferentes intervalos
- 🔍 Filtros Avanzados: Búsqueda por tipo, administrador y otros criterios
- ⚡ Integración Core: Completamente integrado con @infosel-sdk/core
- 🌍 Multi-Ambiente: Soporte para QA y producción
📦 Instalación
npm install @infosel-sdk/fundsDependencias
- @infosel-sdk/core: ^0.0.2 (requerido)
- dayjs: ^1.11.10 (para manejo de fechas)
- tslib: ^2.8.1 (para TypeScript)
🔧 Configuración Inicial
Configurar el SDK Core
Primero, necesitas configurar el SDK Core con autenticación:
import { InfoselSdkManager, AuthConfigurationBuilder } from '@infosel-sdk/core';
import InfoselFunds from '@infosel-sdk/funds';
// Configurar autenticación KeyCloak
const authConfig = AuthConfigurationBuilder.keyCloak()
.withRealm('funds-realm')
.withEnvironment('qa') // o 'prod'
.withCredentials({
grant_type: 'client_credentials',
client_id: 'your-funds-client',
client_secret: 'your-funds-secret',
})
.build();
// Inicializar el SDK Core
const sdkManager = InfoselSdkManager.initWithConfiguration({
authConfiguration: authConfig,
});
// Inicializar el SDK de Fondos
const fundsSdk = InfoselFunds.init({
sdkManager,
});📚 Métodos Disponibles
1. Obtener Lista de Fondos
// Obtener todos los fondos
const allFunds = await fundsSdk.getFunds();
// Filtrar por tipo de fondo
const equityFunds = await fundsSdk.getFunds({
typeId: 1, // Fondos de renta variable
});
// Filtrar por administrador
const specificAdminFunds = await fundsSdk.getFunds({
administratorId: 123,
});
// Combinar filtros
const filteredFunds = await fundsSdk.getFunds({
typeId: 2, // Fondos de renta fija
administratorId: 456,
});
console.log('Fondos encontrados:', allFunds.length);
console.log('Primer fondo:', allFunds[0]);Respuesta esperada:
type Funds = {
readonly id: number;
readonly marketTypeId: number;
readonly valueTypeIds: number;
readonly exchangeId: number;
readonly symbol: string;
readonly issuer: string;
readonly series: string;
readonly isTrading: number;
readonly name: string;
readonly instrumentKey: string;
readonly exchangeValueType: string;
readonly isin: string;
readonly active: number;
};2. Obtener Prospecto de Fondo
// Obtener prospecto por emisora
const prospectus = await fundsSdk.getFundProspectus({
issuer: 'BANORTE',
});
console.log('Nombre del negocio:', prospectus.bussinesName);
console.log('Tipo de fondo:', prospectus.fundType);
console.log('Clase de activo:', prospectus.fundAssetClass);
console.log('Administrador:', prospectus.administrator);
console.log('Activos bajo gestión:', prospectus.assetsUnderManagement);Respuesta esperada:
type FundProspectus = {
readonly fundId: number;
readonly series: string[];
readonly issuer: string;
readonly bussinesName: string;
readonly fundDateAuth: string;
readonly fundType: string;
readonly fundAssetClass: string;
readonly administrator: string;
readonly fundTerm: string;
readonly investmentRegime: string;
readonly liquidity: string;
readonly lockInPeriod: string;
readonly netAsset: number;
readonly assetsUnderManagement: number;
readonly fundHoldings: number;
readonly marketRating: string;
readonly creditRating: string;
readonly fundManager: string;
readonly active: number;
readonly closeTime: string;
};3. Obtener Rendimientos de Fondo
// Obtener rendimientos para una fecha específica
const yields = await fundsSdk.getFundYield({
issuer: 'BANORTE',
series: 'A',
date: new Date('2024-01-15'),
});
console.log('Rendimiento anual:', yields.annual);
console.log('Rendimiento diario:', yields.daily);
console.log('Rendimiento mensual:', yields.monthly);
console.log('Rendimiento semanal:', yields.weekly);
console.log('Rendimiento año a la fecha:', yields.yearToDate);Respuesta esperada:
type FundYield = {
readonly annual: number;
readonly daily: number;
readonly dailyAnnualized: number;
readonly monthly: number;
readonly monthlyAnnualized: number;
readonly weekly: number;
readonly weeklyAnnualized: number;
readonly yearToDate: number;
readonly yearToDateAnnualized: number;
};4. Obtener Precios Históricos
// Obtener precios históricos diarios
const dailyPrices = await fundsSdk.getFundHistoricalPrices({
issuer: 'BANORTE',
series: 'A',
period: 30, // 30 días
interval: 'D', // Diario
});
// Obtener precios semanales
const weeklyPrices = await fundsSdk.getFundHistoricalPrices({
issuer: 'BANORTE',
series: 'A',
period: 12, // 12 semanas
interval: 'W', // Semanal
});
// Obtener precios mensuales
const monthlyPrices = await fundsSdk.getFundHistoricalPrices({
issuer: 'BANORTE',
series: 'A',
period: 24, // 24 meses
interval: 'M', // Mensual
});
// Obtener precios trimestrales
const quarterlyPrices = await fundsSdk.getFundHistoricalPrices({
issuer: 'BANORTE',
series: 'A',
period: 8, // 8 trimestres
interval: 'Q', // Trimestral
});
console.log('Precios diarios:', dailyPrices.length);
console.log('Último precio:', dailyPrices[dailyPrices.length - 1]);Respuesta esperada:
type FundsHistoricalPrices = {
readonly date: string;
readonly high: number;
readonly low: number;
readonly close: number;
};🔍 Casos de Uso Comunes
Dashboard de Fondos
async function createFundsDashboard() {
try {
// Obtener lista de fondos activos
const activeFunds = await fundsSdk.getFunds();
const dashboardData = await Promise.all(
activeFunds.slice(0, 10).map(async fund => {
// Obtener prospecto
const prospectus = await fundsSdk.getFundProspectus({
issuer: fund.issuer,
});
// Obtener rendimiento actual
const yield = await fundsSdk.getFundYield({
issuer: fund.issuer,
series: fund.series,
date: new Date(),
});
// Obtener precios históricos (últimos 30 días)
const historicalPrices = await fundsSdk.getFundHistoricalPrices({
issuer: fund.issuer,
series: fund.series,
period: 30,
interval: 'D',
});
return {
fund,
prospectus,
currentYield: yield.annual,
priceHistory: historicalPrices,
};
}),
);
return dashboardData;
} catch (error) {
console.error('Error al crear dashboard:', error);
throw error;
}
}Análisis de Rendimiento
async function analyzeFundPerformance(issuer: string, series: string) {
try {
// Obtener rendimientos en diferentes períodos
const yields = await fundsSdk.getFundYield({
issuer,
series,
date: new Date(),
});
// Obtener precios históricos para análisis técnico
const dailyPrices = await fundsSdk.getFundHistoricalPrices({
issuer,
series,
period: 90, // 90 días
interval: 'D',
});
const monthlyPrices = await fundsSdk.getFundHistoricalPrices({
issuer,
series,
period: 36, // 36 meses
interval: 'M',
});
// Calcular métricas de rendimiento
const performanceMetrics = {
shortTerm: yields.monthly,
mediumTerm: yields.annual,
longTerm: yields.yearToDate,
volatility: calculateVolatility(dailyPrices),
trend: analyzeTrend(monthlyPrices),
};
return performanceMetrics;
} catch (error) {
console.error('Error en análisis de rendimiento:', error);
throw error;
}
}
function calculateVolatility(prices: FundsHistoricalPrices[]): number {
// Implementar cálculo de volatilidad
const returns = prices
.slice(1)
.map((price, i) => (price.close - prices[i].close) / prices[i].close);
const mean = returns.reduce((sum, ret) => sum + ret, 0) / returns.length;
const variance =
returns.reduce((sum, ret) => sum + Math.pow(ret - mean, 2), 0) /
returns.length;
return Math.sqrt(variance);
}
function analyzeTrend(
prices: FundsHistoricalPrices[],
): 'up' | 'down' | 'sideways' {
if (prices.length < 2) return 'sideways';
const firstPrice = prices[0].close;
const lastPrice = prices[prices.length - 1].close;
const change = (lastPrice - firstPrice) / firstPrice;
if (change > 0.05) return 'up';
if (change < -0.05) return 'down';
return 'sideways';
}Comparación de Fondos
async function compareFunds(
fund1: { issuer: string; series: string },
fund2: { issuer: string; series: string },
) {
try {
const [prospectus1, prospectus2, yield1, yield2] = await Promise.all([
fundsSdk.getFundProspectus({ issuer: fund1.issuer }),
fundsSdk.getFundProspectus({ issuer: fund2.issuer }),
fundsSdk.getFundYield({
issuer: fund1.issuer,
series: fund1.series,
date: new Date(),
}),
fundsSdk.getFundYield({
issuer: fund2.issuer,
series: fund2.series,
date: new Date(),
}),
]);
const comparison = {
fund1: {
name: prospectus1.bussinesName,
type: prospectus1.fundType,
assetClass: prospectus1.fundAssetClass,
annualYield: yield1.annual,
assetsUnderManagement: prospectus1.assetsUnderManagement,
},
fund2: {
name: prospectus2.bussinesName,
type: prospectus2.fundType,
assetClass: prospectus2.fundAssetClass,
annualYield: yield2.annual,
assetsUnderManagement: prospectus2.assetsUnderManagement,
},
analysis: {
higherYield: yield1.annual > yield2.annual ? 'fund1' : 'fund2',
yieldDifference: Math.abs(yield1.annual - yield2.annual),
largerFund:
prospectus1.assetsUnderManagement > prospectus2.assetsUnderManagement
? 'fund1'
: 'fund2',
},
};
return comparison;
} catch (error) {
console.error('Error al comparar fondos:', error);
throw error;
}
}🚨 Manejo de Errores
import { SdkError, SdkErrorType } from '@infosel-sdk/core';
try {
const funds = await fundsSdk.getFunds();
console.log('Fondos obtenidos:', funds);
} catch (error) {
if (error instanceof SdkError) {
switch (error.type) {
case SdkErrorType.REQUEST_OBJECT_IS_REQUIRED:
console.error('Request object is required for this operation');
break;
case SdkErrorType.AXIOS_RESPONSE_ERROR:
console.error('HTTP response error:', error.message);
break;
case SdkErrorType.GRAPH_QL_ERROR:
console.error('GraphQL error:', error.message);
break;
default:
console.error('SDK error:', error.message);
}
} else {
console.error('Unexpected error:', error);
}
}🔧 Configuración Avanzada
Personalización de URLs
import { InfoselSdkManager, AuthConfigurationBuilder } from '@infosel-sdk/core';
import InfoselFunds from '@infosel-sdk/funds';
// Configuración personalizada para diferentes ambientes
const customConfig = {
qa: {
baseUrl: 'https://custom-qa-api.infosel.com/funds/api/v1',
realm: 'qa-funds',
clientId: 'qa-funds-client',
clientSecret: 'qa-funds-secret',
},
prod: {
baseUrl: 'https://custom-prod-api.infosel.com/funds/api/v1',
realm: 'prod-funds',
clientId: 'prod-funds-client',
clientSecret: 'prod-funds-secret',
},
};
function createCustomFundsSdk(environment: 'qa' | 'prod') {
const config = customConfig[environment];
const authConfig = AuthConfigurationBuilder.keyCloak()
.withEnvironment(environment)
.withRealm(config.realm)
.withCredentials({
grant_type: 'client_credentials',
client_id: config.clientId,
client_secret: config.clientSecret,
})
.build();
const sdkManager = InfoselSdkManager.initWithConfiguration({
authConfiguration: authConfig,
});
return InfoselFunds.init({ sdkManager });
}🧪 Testing
import { InfoselSdkManager, AuthConfigurationBuilder } from '@infosel-sdk/core';
import InfoselFunds from '@infosel-sdk/funds';
// Mock del SDK Manager para testing
const mockSdkManager = {
mode: 'qa',
getRealm: () => 'test-realm',
} as any;
// Test de inicialización
describe('InfoselFunds', () => {
it('should initialize with SDK manager', () => {
const fundsSdk = InfoselFunds.init({ sdkManager: mockSdkManager });
expect(fundsSdk).toBeDefined();
});
});📊 Estructura de Datos
Tipos de Request
// Filtros para obtener fondos
type FundsRequest = {
readonly typeId?: number; // ID del tipo de fondo
readonly administratorId?: number; // ID del administrador
};
// Request para prospecto
type FundProspectusRequest = {
readonly issuer: string; // Emisora del fondo
};
// Request para rendimientos
type FundYieldRequest = {
readonly issuer: string; // Emisora del fondo
readonly series: string; // Serie del fondo
readonly date: Date; // Fecha para el cálculo
};
// Request para precios históricos
type FundHistoricalPricesRequest = {
readonly issuer: string; // Emisora del fondo
readonly series: string; // Serie del fondo
readonly period: number; // Período en unidades del intervalo
readonly interval: 'D' | 'W' | 'M' | 'Q'; // D=Diario, W=Semanal, M=Mensual, Q=Trimestral
};🔗 Integración con Otros SDKs
import { InfoselSdkManager, AuthConfigurationBuilder } from '@infosel-sdk/core';
import InfoselFunds from '@infosel-sdk/funds';
import InfoselMarkets from '@infosel-sdk/markets';
// Configuración compartida
const authConfig = AuthConfigurationBuilder.keyCloak()
.withRealm('shared-realm')
.withEnvironment('prod')
.withCredentials({
grant_type: 'client_credentials',
client_id: 'shared-client',
client_secret: 'shared-secret',
})
.build();
const sdkManager = InfoselSdkManager.initWithConfiguration({
authConfiguration: authConfig,
});
// Inicializar múltiples SDKs
const fundsSdk = InfoselFunds.init({ sdkManager });
const marketsSdk = InfoselMarkets.init({ sdkManager });
// Uso combinado
async function getFundWithMarketData(issuer: string, series: string) {
const [fundProspectus, marketInstruments] = await Promise.all([
fundsSdk.getFundProspectus({ issuer }),
marketsSdk.searchInstruments({ query: issuer, limit: 10 }),
]);
return {
fund: fundProspectus,
relatedInstruments: marketInstruments,
};
}📈 Performance y Optimización
Lazy Loading de Use Cases
El SDK implementa lazy loading para optimizar el uso de memoria:
// Los use cases se crean solo cuando se necesitan
const funds = await fundsSdk.getFunds(); // Crea GetFundsUseCase internamente
// Reutiliza la instancia existente
const moreFunds = await fundsSdk.getFunds(); // Usa la instancia existenteManejo de Promesas
// Ejecutar múltiples operaciones en paralelo
const [funds, prospectus, yields] = await Promise.all([
fundsSdk.getFunds(),
fundsSdk.getFundProspectus({ issuer: 'BANORTE' }),
fundsSdk.getFundYield({ issuer: 'BANORTE', series: 'A', date: new Date() }),
]);
// Ejecutar operaciones secuenciales cuando hay dependencias
const funds = await fundsSdk.getFunds();
const firstFund = funds[0];
const prospectus = await fundsSdk.getFundProspectus({
issuer: firstFund.issuer,
});🔍 Troubleshooting
Problemas Comunes
Error de autenticación
// Verificar configuración del realm console.log('Realm configurado:', sdkManager.getRealm()); // Verificar ambiente console.log('Ambiente:', sdkManager.mode);Fondos no encontrados
// Verificar filtros aplicados const allFunds = await fundsSdk.getFunds(); console.log('Total de fondos:', allFunds.length); // Verificar fondos activos const activeFunds = allFunds.filter(fund => fund.active === 1); console.log('Fondos activos:', activeFunds.length);Errores de fecha
// Asegurar formato correcto de fecha const today = new Date(); console.log('Fecha utilizada:', today.toISOString()); // Para rendimientos, usar fecha válida const yields = await fundsSdk.getFundYield({ issuer: 'BANORTE', series: 'A', date: new Date('2024-01-15'), // Formato ISO });
📚 API Reference
Clases Principales
InfoselFunds: Clase principal del SDK de fondosGetFundsUseCase: Use case para obtener fondosGetProspectusUseCase: Use case para obtener prospectosGetFundYieldUseCase: Use case para obtener rendimientosGetFundHistoricalPricesUseCase: Use case para obtener precios históricos
Métodos Públicos
getFunds(request?: FundsRequest): Promise<Funds[]>getFundProspectus(request: FundProspectusRequest): Promise<FundProspectus>getFundYield(request: FundYieldRequest): Promise<FundYield>getFundHistoricalPrices(request: FundHistoricalPricesRequest): Promise<FundsHistoricalPrices[]>
🤝 Contribución
- Fork el proyecto
- Crea una rama para tu feature (
git checkout -b feature/AmazingFeature) - Commit tus cambios (
git commit -m 'Add some AmazingFeature') - Push a la rama (
git push origin feature/AmazingFeature) - Abre un Pull Request
📄 Licencia
Este proyecto está bajo la Licencia MIT. Ver el archivo LICENSE para más detalles.
📞 Soporte
- Documentación: SDK Core Documentation
- Issues: GitHub Issues
- Equipo: Infosel Team
Hecho con ❤️ por el equipo de Infosel
