/** * TEFAS API Client Types * * This module defines all TypeScript interfaces and types for the TEFAS client. * It provides strong typing for fund data, requests, and responses. */ /** * Generic API response wrapper */ interface ApiResponse { results: T[]; } /** * Supported TEFAS fund types */ declare enum FundType { /** Emeklilik (Pension) funds */ EMK = "EMK", /** Yatırım (Investment) funds */ YAT = "YAT", /** Bireysel Yatırım (Individual Investment) funds */ BYF = "BYF", /** Gayrimenkul Yatırım (Real Estate Investment) funds */ GYF = "GYF", /** Girişim Sermayesi Yatırım (Venture Capital Investment) funds */ GSYF = "GSYF" } /** * Typed response data containing fund history information */ interface FundHistoryResponse { /** Fund identifier */ fundCode: string; /** Human-readable fund name */ fundName: string; /** Type of fund */ fundType: FundType; /** Date of the data point (YYYY-MM-DD) */ date: string; /** Fund price/NAV */ price: number; /** Trading volume */ volume: number; /** Total assets under management */ assets: number; /** Number of investors */ investorCount: number; } /** * Raw TEFAS API response structure * This represents the actual response format from the TEFAS API */ interface TefasApiResponse { /** Response data array */ data: TefasApiFundData[]; /** Response metadata */ meta?: { total?: number; page?: number; limit?: number; }; } /** * Raw fund data from TEFAS API */ interface TefasApiFundData { /** Date string (timestamp) */ TARIH: string; /** Fund code */ FONKODU: string; /** Fund name */ FONUNVAN: string; /** Price/NAV */ FIYAT: number; /** Number of shares */ TEDPAYSAYISI: number; /** Number of investors */ KISISAYISI: number; /** Portfolio size */ PORTFOYBUYUKLUK: number; /** Exchange bulletin price */ BORSABULTENFIYAT: string; } /** * TEFAS API request parameters */ interface TefasApiRequest { /** Fund type */ fontip: string; /** Start date */ bastarih: string; /** End date */ bittarih: string; /** Fund code (optional) */ fonkod?: string; } /** * Configuration for TEFAS API client */ interface TefasClientConfig { /** TEFAS API base URL */ baseUrl: string; /** Default timeout in milliseconds */ timeout: number; /** Default headers */ headers: Record; /** Maximum retry attempts */ maxRetries: number; /** Retry delay in milliseconds */ retryDelay: number; /** * Cache configuration (used when cacheAdapter is not provided) * * This configures the default in-memory cache adapter. * If you want to use a custom cache (Redis, Cloudflare KV, etc.), * provide a cacheAdapter instead. */ cache?: { /** Whether caching is enabled (default: true) */ enabled?: boolean; /** Time to live in milliseconds (default: 900000 = 15 minutes) */ ttl?: number; /** Maximum number of cache entries (default: 1000) */ maxSize?: number; }; /** * Custom cache adapter for pluggable caching strategies * * Provide your own cache implementation (Redis, Cloudflare KV, localStorage, etc.) * If not provided, uses the default in-memory cache with settings from `cache` config. * * @example * ```typescript * import { RedisCacheAdapter } from '@tefas-api/cache-redis'; * * const client = new TefasClient({ * cacheAdapter: new RedisCacheAdapter({ url: 'redis://localhost:6379' }) * }); * ``` */ cacheAdapter?: any; } /** * Date range validation result */ interface DateRangeValidation { /** Whether date range is valid */ isValid: boolean; /** Error message if invalid */ error?: string; /** Parsed start date */ startDate?: Date; /** Parsed end date */ endDate?: Date; /** Number of days in range */ daysInRange?: number; } /** * Result from fund search operation * * Contains basic fund identification information suitable for * autocomplete and selection interfaces. */ interface SearchResult { /** * Fund code identifier (e.g., "IIH", "TGE") * * This is the 3-character code used for subsequent API calls * like getFundHistory(). */ fundCode: string; /** * Full fund display name including code prefix * * Format: "{CODE} - {FULL_NAME}" * Example: "IIH - İSTANBUL PORTFÖY ÜÇÜNCÜ HİSSE SENEDİ FONU (HİSSE SENEDİ YOĞUN FON)" */ fundName: string; /** * Type of fund (e.g., FundType.EMK, FundType.YAT) * * This indicates the fund category and is always included in search results. */ fundType: FundType; } /** * Optional configuration for fund search * * All properties are optional to provide flexible search capabilities. */ interface SearchOptions { /** * Filter search results by fund type * * If omitted, searches across all fund types. * * @example * { fundType: FundType.YAT } // Only search investment funds */ fundType?: FundType; /** * Maximum number of results to return * * @default 10 * @example * { limit: 5 } // Return at most 5 results */ limit?: number; } /** * Fund category information from Fundfy */ interface FundCategory { abbreviation: string; fullName: string; } /** * Fund benchmark information from Fundfy */ interface FundBenchmark { benchmark: string; percentage: number; } /** * Detailed fund information from Fundfy */ interface FundDetail { code: string; title: string; auditFirm: string | null; emailAddress: string | null; fundDuration: string | null; contactAddress: string | null; founder: string | null; founderLogo: string | null; umbrellaFundType: string | null; umbrellaFundName: string | null; fundCategory: FundCategory | null; risk: number | null; yearlyManagementFee: number | null; buyingValor: number | null; sellingValor: number | null; strategyStatement: string | null; fundBenchmarks: FundBenchmark[]; } /** * HTTP method types */ type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; /** * API client configuration */ interface ApiClientConfig { /** Base URL for API requests */ baseUrl: string; /** Request timeout in milliseconds */ timeout?: number; /** Default headers for all requests */ headers?: Record; } /** * Request options for API calls */ interface RequestOptions { /** Query parameters */ params?: Record; /** Custom headers for this request */ headers?: Record; /** Request timeout in milliseconds */ timeout?: number; /** Content type for request body */ contentType?: 'json' | 'form'; /** Abort signal for request cancellation */ signal?: AbortSignal; } /** * Performance metrics for a fund */ interface PerformanceMetrics { /** Fund identifier */ fundCode: string; /** Human-readable fund name */ fundName: string; /** Type of fund */ fundType: FundType; /** Number of data points used in calculations */ observations: number; /** Total return over the entire period */ cumulativeReturn: number; /** Annualized return (yearly return) */ annualizedReturn: number; /** Annualized volatility (risk measure) */ annualizedVolatility: number; /** Sharpe ratio (risk-adjusted return) */ sharpeRatio: number; } /** * Configuration options for performance metrics calculation */ interface MetricsOptions { /** Risk-free rate for Sharpe ratio calculation (default: 0) */ riskFreeRate?: number; /** Data frequency for calculations */ frequency?: 'daily' | 'weekly' | 'monthly' | 'quarterly' | 'annual'; /** Return calculation method */ method?: 'simple' | 'logarithmic'; /** Minimum number of observations required (default: 30) */ minObservations?: number; } /** * Typed response data containing fund allocation/portfolio composition information */ interface FundContentResponse { /** Fund identifier */ fundCode: string; /** Human-readable fund name */ fundName: string; /** Type of fund */ fundType: FundType; /** Date of the data point (YYYY-MM-DD) */ date: string; /** Total fund value */ totalValue: number; /** Percentage of stocks (HS) */ stocks?: number; /** Percentage of foreign securities (YYF) */ foreignSecurities?: number; /** Percentage of stock-based funds (HB) */ stockBasedFunds?: number; /** Percentage of stock-based investment funds (YHS) */ stockBasedInvestmentFunds?: number; /** Percentage of bonds (BB) */ bonds?: number; /** Percentage of government bonds (DB) */ governmentBonds?: number; /** Percentage of private sector bonds (ÖSDB) */ privateSectorBonds?: number; /** Percentage of government securities (GSYKB) */ governmentSecurities?: number; /** Percentage of government securities yield (GSYY) */ governmentSecuritiesYield?: number; /** Percentage of government yield bonds (GYKB) */ governmentYieldBonds?: number; /** Percentage of government yield (GYY) */ governmentYield?: number; /** Percentage of deposits (D) */ deposits?: number; /** Percentage of reverse purchase agreements (T) */ reversePurchaseAgreements?: number; /** Percentage of precious metals (KM) */ preciousMetals?: number; /** Percentage of cash and cash equivalents (OSKS) */ cashAndCashEquivalents?: number; /** Percentage of other securities (OSKSYD) */ otherSecurities?: number; /** Percentage of other securities yield (ÖKSYD) */ otherSecuritiesYield?: number; /** Percentage of treasury bills (BPP) */ treasuryBills?: number; /** Percentage of individual investment funds (BYF) */ individualInvestmentFunds?: number; /** Percentage of government debt instruments (DT) */ governmentDebtInstruments?: number; /** Percentage of government debt instruments foreign (DÖT) */ governmentDebtInstrumentsForeign?: number; /** Percentage of eurobonds (EUT) */ eurobonds?: number; /** Percentage of foreign bonds (FB) */ foreignBonds?: number; /** Percentage of foreign currency bonds (FKB) */ foreignCurrencyBonds?: number; /** Percentage of gold and silver (GAS) */ goldAndSilver?: number; /** Percentage of participation accounts (KBA) */ participationAccounts?: number; /** Percentage of participation accounts gold (KH) */ participationAccountsGold?: number; /** Percentage of participation accounts gold foreign (KHAU) */ participationAccountsGoldForeign?: number; /** Percentage of participation accounts foreign currency (KHD) */ participationAccountsForeignCurrency?: number; /** Percentage of participation accounts Turkish Lira (KHTL) */ participationAccountsTurkishLira?: number; /** Percentage of public lease certificates (KKS) */ publicLeaseCertificates?: number; /** Percentage of public lease certificates foreign currency (KKSD) */ publicLeaseCertificatesForeignCurrency?: number; /** Percentage of public lease certificates Turkish Lira (KKSTL) */ publicLeaseCertificatesTurkishLira?: number; /** Percentage of public lease certificates foreign (KKSYD) */ publicLeaseCertificatesForeign?: number; /** Percentage of participation accounts foreign currency (KİBD) */ participationAccountsForeignCurrencyBonds?: number; /** Percentage of other securities Turkish Lira (OST) */ otherSecuritiesTurkishLira?: number; /** Percentage of repo transactions (R) */ repoTransactions?: number; /** Percentage of term deposits (TPP) */ termDeposits?: number; /** Percentage of treasury bills (TR) */ treasuryBillsShort?: number; /** Percentage of variable rate deposits (VDM) */ variableRateDeposits?: number; /** Percentage of money market instruments (VM) */ moneyMarketInstruments?: number; /** Percentage of money market instruments gold (VMAU) */ moneyMarketInstrumentsGold?: number; /** Percentage of money market instruments foreign currency (VMD) */ moneyMarketInstrumentsForeignCurrency?: number; /** Percentage of money market instruments Turkish Lira (VMTL) */ moneyMarketInstrumentsTurkishLira?: number; /** Percentage of variable income instruments (VİNT) */ variableIncomeInstruments?: number; /** Percentage of investment fund participations (YBA) */ investmentFundParticipations?: number; /** Percentage of investment fund participations bonds (YBKB) */ investmentFundParticipationsBonds?: number; /** Percentage of investment fund participations other securities (YBOSB) */ investmentFundParticipationsOtherSecurities?: number; /** Percentage of investment fund participations foreign currency (YBYF) */ investmentFundParticipationsForeignCurrency?: number; /** Percentage of investment fund participations metals (YMK) */ investmentFundParticipationsMetals?: number; /** Percentage of precious metals investment funds (KMBYF) */ preciousMetalsInvestmentFunds?: number; /** Percentage of precious metals government debt instruments (KMKBA) */ preciousMetalsGovernmentDebtInstruments?: number; /** Percentage of precious metals public lease certificates (KMKKS) */ preciousMetalsPublicLeaseCertificates?: number; } /** * Merged fund data combining history and content information * * This interface combines all fields from both FundHistoryResponse and FundContentResponse * to provide a unified view of fund data. Fields from either source may be null if * the corresponding data is not available for that fund/date combination. */ interface FundResponse { /** Fund identifier */ fundCode: string; /** Human-readable fund name */ fundName: string; /** Type of fund */ fundType: FundType; /** Date of the data point (YYYY-MM-DD) */ date: string; /** Fund price/NAV (null if not available) */ price: number | null; /** Trading volume (null if not available) */ volume: number | null; /** Total assets under management (null if not available) */ assets: number | null; /** Number of investors (null if not available) */ investorCount: number | null; /** Total fund value (null if not available) */ totalValue: number | null; /** Percentage of stocks (HS) (null if not available) */ stocks?: number | null; /** Percentage of foreign securities (YYF) (null if not available) */ foreignSecurities?: number | null; /** Percentage of stock-based funds (HB) (null if not available) */ stockBasedFunds?: number | null; /** Percentage of stock-based investment funds (YHS) (null if not available) */ stockBasedInvestmentFunds?: number | null; /** Percentage of bonds (BB) (null if not available) */ bonds?: number | null; /** Percentage of government bonds (DB) (null if not available) */ governmentBonds?: number | null; /** Percentage of private sector bonds (ÖSDB) (null if not available) */ privateSectorBonds?: number | null; /** Percentage of government securities (GSYKB) (null if not available) */ governmentSecurities?: number | null; /** Percentage of government securities yield (GSYY) (null if not available) */ governmentSecuritiesYield?: number | null; /** Percentage of government yield bonds (GYKB) (null if not available) */ governmentYieldBonds?: number | null; /** Percentage of government yield (GYY) (null if not available) */ governmentYield?: number | null; /** Percentage of deposits (D) (null if not available) */ deposits?: number | null; /** Percentage of reverse purchase agreements (T) (null if not available) */ reversePurchaseAgreements?: number | null; /** Percentage of precious metals (KM) (null if not available) */ preciousMetals?: number | null; /** Percentage of cash and cash equivalents (OSKS) (null if not available) */ cashAndCashEquivalents?: number | null; /** Percentage of other securities (OSKSYD) (null if not available) */ otherSecurities?: number | null; /** Percentage of other securities yield (ÖKSYD) (null if not available) */ otherSecuritiesYield?: number | null; /** Percentage of treasury bills (BPP) (null if not available) */ treasuryBills?: number | null; /** Percentage of individual investment funds (BYF) (null if not available) */ individualInvestmentFunds?: number | null; /** Percentage of government debt instruments (DT) (null if not available) */ governmentDebtInstruments?: number | null; /** Percentage of government debt instruments foreign (DÖT) (null if not available) */ governmentDebtInstrumentsForeign?: number | null; /** Percentage of eurobonds (EUT) (null if not available) */ eurobonds?: number | null; /** Percentage of foreign bonds (FB) (null if not available) */ foreignBonds?: number | null; /** Percentage of foreign currency bonds (FKB) (null if not available) */ foreignCurrencyBonds?: number | null; /** Percentage of gold and silver (GAS) (null if not available) */ goldAndSilver?: number | null; /** Percentage of participation accounts (KBA) (null if not available) */ participationAccounts?: number | null; /** Percentage of participation accounts gold (KH) (null if not available) */ participationAccountsGold?: number | null; /** Percentage of participation accounts gold foreign (KHAU) (null if not available) */ participationAccountsGoldForeign?: number | null; /** Percentage of participation accounts foreign currency (KHD) (null if not available) */ participationAccountsForeignCurrency?: number | null; /** Percentage of participation accounts Turkish Lira (KHTL) (null if not available) */ participationAccountsTurkishLira?: number | null; /** Percentage of public lease certificates (KKS) (null if not available) */ publicLeaseCertificates?: number | null; /** Percentage of public lease certificates foreign currency (KKSD) (null if not available) */ publicLeaseCertificatesForeignCurrency?: number | null; /** Percentage of public lease certificates Turkish Lira (KKSTL) (null if not available) */ publicLeaseCertificatesTurkishLira?: number | null; /** Percentage of public lease certificates foreign (KKSYD) (null if not available) */ publicLeaseCertificatesForeign?: number | null; /** Percentage of participation accounts foreign currency (KİBD) (null if not available) */ participationAccountsForeignCurrencyBonds?: number | null; /** Percentage of other securities Turkish Lira (OST) (null if not available) */ otherSecuritiesTurkishLira?: number | null; /** Percentage of repo transactions (R) (null if not available) */ repoTransactions?: number | null; /** Percentage of term deposits (TPP) (null if not available) */ termDeposits?: number | null; /** Percentage of treasury bills (TR) (null if not available) */ treasuryBillsShort?: number | null; /** Percentage of variable rate deposits (VDM) (null if not available) */ variableRateDeposits?: number | null; /** Percentage of money market instruments (VM) (null if not available) */ moneyMarketInstruments?: number | null; /** Percentage of money market instruments gold (VMAU) (null if not available) */ moneyMarketInstrumentsGold?: number | null; /** Percentage of money market instruments foreign currency (VMD) (null if not available) */ moneyMarketInstrumentsForeignCurrency?: number | null; /** Percentage of money market instruments Turkish Lira (VMTL) (null if not available) */ moneyMarketInstrumentsTurkishLira?: number | null; /** Percentage of variable income instruments (VİNT) (null if not available) */ variableIncomeInstruments?: number | null; /** Percentage of investment fund participations (YBA) (null if not available) */ investmentFundParticipations?: number | null; /** Percentage of investment fund participations bonds (YBKB) (null if not available) */ investmentFundParticipationsBonds?: number | null; /** Percentage of investment fund participations other securities (YBOSB) (null if not available) */ investmentFundParticipationsOtherSecurities?: number | null; /** Percentage of investment fund participations foreign currency (YBYF) (null if not available) */ investmentFundParticipationsForeignCurrency?: number | null; /** Percentage of investment fund participations metals (YMK) (null if not available) */ investmentFundParticipationsMetals?: number | null; /** Percentage of precious metals investment funds (KMBYF) (null if not available) */ preciousMetalsInvestmentFunds?: number | null; /** Percentage of precious metals government debt instruments (KMKBA) (null if not available) */ preciousMetalsGovernmentDebtInstruments?: number | null; /** Percentage of precious metals public lease certificates (KMKKS) (null if not available) */ preciousMetalsPublicLeaseCertificates?: number | null; /** Audit firm name (null if not available) */ auditFirm: string | null; /** Email address (null if not available) */ emailAddress: string | null; /** Fund duration (null if not available) */ fundDuration: string | null; /** Contact address (null if not available) */ contactAddress: string | null; /** Founder name (null if not available) */ founder: string | null; /** Founder logo filename (null if not available) */ founderLogo: string | null; /** Umbrella fund type (null if not available) */ umbrellaFundType: string | null; /** Umbrella fund name (null if not available) */ umbrellaFundName: string | null; /** Fund category information (null if not available) */ fundCategory: FundCategory | null; /** Risk level (null if not available) */ risk: number | null; /** Yearly management fee (null if not available) */ yearlyManagementFee: number | null; /** Buying valor (null if not available) */ buyingValor: number | null; /** Selling valor (null if not available) */ sellingValor: number | null; /** Strategy statement (null if not available) */ strategyStatement: string | null; /** Fund benchmarks array */ fundBenchmarks: FundBenchmark[]; } /** * Raw TEFAS allocation API response structure * This represents the actual response format from the TEFAS allocation API */ interface TefasAllocationApiResponse { /** Response data array */ data: TefasAllocationData[]; /** Response metadata */ draw?: number; recordsTotal?: number; recordsFiltered?: number; } /** * Raw allocation data from TEFAS API */ interface TefasAllocationData { /** Date string (timestamp in milliseconds) */ TARIH: string; /** Fund code */ FONKODU: string; /** Fund name */ FONUNVAN: string; /** Total fund value (comma-formatted string) */ BilFiyat: string; BB?: number; BPP?: number; BYF?: number; D?: number; DB?: number; DT?: number; DÖT?: number; EUT?: number; FB?: number; FKB?: number; GAS?: number; GSYKB?: number; GSYY?: number; GYKB?: number; GYY?: number; HB?: number; HS?: number; KBA?: number; KH?: number; KHAU?: number; KHD?: number; KHTL?: number; KKS?: number; KKSD?: number; KKSTL?: number; KKSYD?: number; KM?: number; KMBYF?: number; KMKBA?: number; KMKKS?: number; KİBD?: number; OSKS?: number; OSKSYD?: number; OST?: number; R?: number; T?: number; TPP?: number; TR?: number; VDM?: number; VM?: number; VMAU?: number; VMD?: number; VMTL?: number; VİNT?: number; YBA?: number; YBKB?: number; YBOSB?: number; YBYF?: number; YHS?: number; YMK?: number; YYF?: number; ÖKSYD?: number; ÖSDB?: number; } /** * Cache adapter interfaces for pluggable caching strategies * * This module defines the contract for cache implementations, allowing users * to provide custom caching backends (Redis, Cloudflare KV, localStorage, etc.) * while maintaining a consistent API. */ /** * Core cache adapter interface with essential operations * * All methods are async to support both local (Map, localStorage) and remote * (Redis, Cloudflare KV) cache implementations. * * @template T - Type of values stored in the cache * * @example * ```typescript * // Implement custom cache adapter * class RedisCacheAdapter implements CacheAdapter { * async get(key: string): Promise { * const value = await redis.get(key); * return value ? JSON.parse(value) : undefined; * } * * async set(key: string, value: MyData, ttl?: number): Promise { * await redis.setEx(key, ttl ?? 900, JSON.stringify(value)); * } * * // ... implement other methods * } * ``` */ interface CacheAdapter { /** * Retrieves a value from the cache * * @param key - Cache key * @returns Cached value or undefined if not found or expired */ get(key: string): Promise; /** * Stores a value in the cache * * @param key - Cache key * @param value - Value to cache * @param ttl - Optional time-to-live in seconds (overrides default TTL) */ set(key: string, value: T, ttl?: number): Promise; /** * Removes a specific entry from the cache * * @param key - Cache key to delete * @returns true if key was deleted, false if it didn't exist */ delete(key: string): Promise; /** * Clears all entries from the cache */ clear(): Promise; /** * Checks if a key exists in the cache and is not expired * * @param key - Cache key * @returns true if key exists and is valid */ has(key: string): Promise; } /** * Cache statistics information * * Not all cache implementations can provide all statistics. * Optional fields allow adapters to return only what they can track. */ interface CacheStats { /** Current number of cache entries (if trackable) */ size?: number; /** Whether caching is enabled */ enabled: boolean; /** Time-to-live in milliseconds (if applicable) */ ttl?: number; /** Maximum cache size before eviction (if applicable) */ maxSize?: number; } /** * Extended cache adapter interface with statistics and maintenance operations * * This interface is optional - not all cache implementations can provide * statistics or manual cleanup operations. Implementations should only * implement this if they can meaningfully support these operations. * * @template T - Type of values stored in the cache * * @example * ```typescript * class MemoryCacheAdapter implements CacheAdapterWithStats { * async getStats(): Promise { * return { * size: this.cache.size, * enabled: true, * ttl: this.ttl, * maxSize: this.maxSize * }; * } * * async prune(): Promise { * return this.cache.removeExpired(); * } * } * ``` */ interface CacheAdapterWithStats extends CacheAdapter { /** * Gets cache statistics * * @returns Cache statistics object */ getStats(): Promise; /** * Removes expired entries from the cache (manual cleanup) * * This is optional because some caches (Redis, Cloudflare KV) handle * expiration automatically and don't need manual pruning. * * @returns Number of entries removed */ prune?(): Promise; } /** * Type guard to check if a cache adapter supports statistics * * @param adapter - Cache adapter to check * @returns true if adapter implements CacheAdapterWithStats * * @example * ```typescript * if (isCacheAdapterWithStats(cache)) { * const stats = await cache.getStats(); * console.log(`Cache size: ${stats.size}`); * } * ``` */ declare function isCacheAdapterWithStats(adapter: CacheAdapter): adapter is CacheAdapterWithStats; /** * TEFAS API Client * * This module provides a simplified interface for accessing TEFAS API data. * It abstracts away HTTP implementation details and provides a clean, business-focused API. */ /** * Simplified TEFAS API client that provides a clean interface for fund data access. * * This client wraps the base REST API client with TEFAS-specific configuration * and methods, hiding HTTP implementation details from users. * * @example * ```typescript * import { TefasClient, FundType } from 'tefas-client'; * * const client = new TefasClient(); * * // Get all pension funds for a date range * const funds = await client.getFundHistory( * '2024-01-01', * '2024-12-31', * undefined, * FundType.EMK * ); * * // Get all funds across all types * const allFunds = await client.getFundHistory( * '2024-01-01', * '2024-12-31' * ); * * // Get specific fund history * const specificFund = await client.getFundHistory( * '2024-01-01', * '2024-12-31', * 'TGE', * FundType.EMK * ); * ``` */ declare class TefasClient { private readonly baseClient; private readonly config; private maxDaysPerRequest; private readonly cache; /** * Creates a new TEFAS client instance. * * No configuration is required - the client uses hardcoded TEFAS API settings * for zero-configuration setup. Optionally accepts a partial configuration * to override default settings like cache behavior. * * @param configOverrides - Optional configuration overrides * @throws ConfigurationError if TEFAS API configuration is invalid */ constructor(configOverrides?: Partial); /** * Returns library version string for User-Agent; falls back to 'dev' in tests. */ private getVersion; /** * Sets the maximum number of days per request window when fetching history. * Defaults to 90; values must be integers between 1 and 365. */ setMaxDaysPerRequest(maxDays: number): void; /** * Get fund history data for funds of a specific type or all types. * * @private * Internal method used by getFund. Use getFund() for public API access. * * This method retrieves historical fund data from TEFAS API. It supports both * standard date formats (YYYY-MM-DD) and fuzzy date parsing for natural language * expressions. The method automatically handles large date ranges by splitting * them into smaller chunks to comply with TEFAS API limitations. * * @param startDate - Start date in YYYY-MM-DD format or fuzzy date (e.g., "today", "yesterday", "2024-01-01") * @param endDate - End date in YYYY-MM-DD format or fuzzy date (e.g., "today", "yesterday", "2024-01-01") * @param fundCode - Optional specific fund code to retrieve (3-character code like "TGE", "IIH") * @param fundType - Optional fund type to filter by. If omitted, fetches all fund types * @returns Promise resolving to array of fund history data * * @throws InvalidFundTypeError if fund type is not supported * @throws InvalidDateError if date format is invalid * @throws FundNotFoundError if fund code is not found * @throws TefasApiError if TEFAS API returns an error * @throws NetworkError if network request fails * * @see {@link getFund} for public API access * @see {@link FundType} for available fund types * @see {@link FundHistoryResponse} for response structure */ private getFundHistory; /** * Search for funds by name or code prefix * * Enables autocomplete and fund selection by searching for funds matching * the provided query string. The search is performed against both fund codes * and fund names. Optionally filter by fund type and limit the number of results. * * This method is perfect for implementing autocomplete functionality, fund * selection dropdowns, or finding funds by partial name matches. The search * is case-insensitive and supports Turkish characters. * * @param query - Search query (fund code or name prefix) * @param options - Optional search configuration (fundType filter, result limit) * @returns Promise resolving to array of matching funds * * @throws ValidationError if query is empty or limit is invalid * @throws InvalidFundTypeError if fundType is invalid * @throws TefasApiError if TEFAS API returns an error * @throws NetworkError if network request fails * * @example * ```typescript * import { TefasClient, FundType } from '@firstthumb/tefas-api'; * * const client = new TefasClient(); * * // Basic search by code prefix * const results = await client.searchFund('IIH'); * console.log(results); * // [{ fundCode: "IIH", fundName: "IIH - İSTANBUL PORTFÖY..." }] * * // Search with fund type filter * const yatFunds = await client.searchFund('IS', { fundType: FundType.YAT }); * console.log(yatFunds); // Only investment funds (YAT type) * * // Search with custom result limit (great for autocomplete) * const limitedResults = await client.searchFund('A', { limit: 5 }); * console.log(limitedResults.length); // At most 5 results * * // Combine filters and limits * const filtered = await client.searchFund('IS', { * fundType: FundType.EMK, * limit: 3 * }); * * // Use fund code for detailed history * if (results.length > 0) { * const history = await client.getFundHistory( * '2024-01-01', * '2024-12-31', * results[0].fundCode, * FundType.YAT * ); * } * * // Autocomplete implementation example * async function autocompleteFunds(query: string) { * if (query.length < 2) return []; * * try { * const results = await client.searchFund(query, { limit: 10 }); * return results.map(fund => ({ * value: fund.fundCode, * label: fund.fundName, * code: fund.fundCode * })); * } catch (error) { * console.error('Search failed:', error); * return []; * } * } * ``` * * @since 1.0.0 * @see {@link SearchResult} for result structure * @see {@link SearchOptions} for configuration options */ /** * Search funds for a specific fund type * * @private * @param query - Search query string * @param fundType - Fund type to search * @param limit - Optional limit for number of results * @returns Array of SearchResult objects for the specified fund type */ private searchFundByType; searchFund(query: string, options?: SearchOptions): Promise>; /** * Fetch fund detail data from Fundfy and return selected fields. * * @private * @param fundCode - Fund code identifier * @returns Fund detail information */ private getFundDetails; /** * Validates limit parameter * * @private * @param limit - Limit value to validate * @throws ValidationError if limit is invalid */ private validateLimit; /** * Validates search query parameter * * @private * @param query - Search query to validate * @throws ValidationError if query is invalid */ private validateSearchQuery; /** * Get fund allocation/portfolio composition data for funds of a specific type or all types. * * @private * Internal method used by getFund. Use getFund() for public API access. * * This method retrieves historical fund allocation data from TEFAS API. It supports both * standard date formats (YYYY-MM-DD) and fuzzy date parsing for natural language * expressions. The method automatically handles large date ranges by splitting * them into smaller chunks to comply with TEFAS API limitations. * * @param startDate - Start date in YYYY-MM-DD format or fuzzy date (e.g., "today", "yesterday", "2024-01-01") * @param endDate - End date in YYYY-MM-DD format or fuzzy date (e.g., "today", "yesterday", "2024-01-01") * @param fundCode - Optional specific fund code to retrieve (3-character code like "TGE", "IIH") * @param fundType - Optional fund type to filter by. If omitted, fetches all fund types * @returns Promise resolving to array of fund allocation data * * @throws InvalidFundTypeError if fund type is not supported * @throws InvalidDateError if date format is invalid * @throws FundNotFoundError if fund code is not found * @throws TefasApiError if TEFAS API returns an error * @throws NetworkError if network request fails * * @see {@link getFund} for public API access * @see {@link FundType} for available fund types * @see {@link FundContentResponse} for response structure */ private getFundContent; /** * Get merged fund data combining history and content information. * * This method retrieves both fund history and allocation data from TEFAS API * and merges them based on fund code and date. It provides a unified view of * fund data where fields from either source may be null if the corresponding * data is not available for that fund/date combination. * * **Filtering Behavior:** * - When `fundType` is provided: Searches only that specific fund type * - When `fundType` is omitted: Searches across ALL fund types (EMK, YAT, BYF, GYF, GSYF) * - When both `fundCode` and `fundType` are provided: Filters to that specific fund in that type * * This is the primary public API for fetching fund data. For searching funds by name/code, use {@link searchFund}. * * The method supports both standard date formats (YYYY-MM-DD) and fuzzy date * parsing for natural language expressions. It automatically handles large * date ranges by splitting them into smaller chunks to comply with TEFAS API * limitations. * * @param startDate - Start date in YYYY-MM-DD format or fuzzy date (e.g., "today", "yesterday", "2024-01-01") * @param endDate - End date in YYYY-MM-DD format or fuzzy date (e.g., "today", "yesterday", "2024-01-01") * @param fundCode - Optional specific fund code to retrieve (3-character code like "TGE", "IIH") * @param fundType - Optional fund type to filter by (EMK, YAT, BYF, GYF, GSYF). If omitted, searches all types. * @returns Promise resolving to array of merged fund data * * @throws InvalidFundTypeError if fund type is invalid * @throws InvalidDateError if date format is invalid * @throws FundNotFoundError if fund code is not found * @throws TefasApiError if TEFAS API returns an error * @throws NetworkError if network request fails * * @example * ```typescript * import { TefasClient, FundType } from '@firstthumb/tefas-api'; * * const client = new TefasClient(); * * // Get merged data for a specific fund using fuzzy dates * const fundData = await client.getFund( * 'yesterday', * 'today', * 'TGE' * ); * console.log(fundData[0].price); // Fund price * console.log(fundData[0].stocks); // Stock allocation percentage * * // Get merged data for all funds across all types * const allFunds = await client.getFund( * '2024-01-01', * '2024-12-31' * ); * console.log(allFunds.length); // Total number of fund/date combinations * * // Filter by fund type - get only pension funds (EMK) * const pensionFunds = await client.getFund( * '2024-01-01', * '2024-12-31', * undefined, * FundType.EMK * ); * * // Get specific fund in specific type * const specificPensionFund = await client.getFund( * 'last week', * 'today', * 'TGE', * FundType.EMK * ); * * // Handle missing data gracefully * fundData.forEach(fund => { * if (fund.price !== null) { * console.log(`Price: ${fund.price}`); * } * if (fund.stocks !== null && fund.stocks !== undefined) { * console.log(`Stock allocation: ${fund.stocks}%`); * } * }); * * // Handle errors gracefully * try { * const data = await client.getFund('2024-01-01', '2024-01-31', 'INVALID'); * } catch (error) { * if (error instanceof FundNotFoundError) { * console.log('Fund not found'); * } * } * ``` * * @since 1.0.0 * @see {@link FundResponse} for response structure * @see {@link getFundHistory} for history-only data * @see {@link getFundContent} for content-only data */ getFund(startDate: string, endDate: string, fundCode?: string, fundType?: FundType, skipFundDetails?: boolean): Promise>; /** * Validates the TEFAS API configuration. * * @private * @throws ConfigurationError if configuration is invalid */ private validateConfiguration; /** * Validates fund history request parameters. * * @private * @param fundType - Fund type to validate (optional) * @param startDate - Start date to validate * @param endDate - End date to validate * @param fundCode - Optional fund code to validate * @throws InvalidFundTypeError if fund type is invalid * @throws InvalidDateError if date format is invalid * @throws DateRangeError if date range is invalid */ private validateFundHistoryRequest; /** * Validates fund content request parameters. * * @private * @param fundType - Fund type to validate (optional) * @param startDate - Start date to validate * @param endDate - End date to validate * @param fundCode - Optional fund code to validate * @throws InvalidFundTypeError if fund type is invalid * @throws InvalidDateError if date format is invalid * @throws DateRangeError if date range is invalid */ private validateFundContentRequest; /** * Fetches fund history for a specific fund type. * * @private * @param fundType - Fund type to fetch * @param startDate - Start date * @param endDate - End date * @param fundCode - Optional fund code * @param throwOnNotFound - Whether to throw error if fund not found (default: true) * @returns Promise resolving to fund history data */ private fetchFundHistoryForType; /** * Fetches fund history for all fund types and merges results. * * @private * @param startDate - Start date * @param endDate - End date * @param fundCode - Optional fund code * @returns Promise resolving to merged fund history data */ private fetchAllFundTypes; /** * Fetches fund allocation data for a specific fund type. * * @private * @param fundType - Fund type to fetch * @param startDate - Start date * @param endDate - End date * @param fundCode - Optional fund code * @param throwOnNotFound - Whether to throw error if fund not found (default: true) * @returns Promise resolving to fund allocation data */ private fetchFundContentForType; /** * Fetches fund allocation data for all fund types and merges results. * * @private * @param startDate - Start date * @param endDate - End date * @param fundCode - Optional fund code * @returns Promise resolving to merged fund allocation data */ private fetchAllFundTypesContent; /** * Builds TEFAS API request parameters. * * @private * @param fundType - Fund type * @param startDate - Start date * @param endDate - End date * @param fundCode - Optional fund code * @returns TEFAS API request object */ private buildTefasRequest; /** * Builds TEFAS allocation API request parameters. * * @private * @param fundType - Fund type * @param startDate - Start date * @param endDate - End date * @param fundCode - Optional fund code * @returns TEFAS allocation API request object */ private buildAllocationRequest; /** * Processes TEFAS API response and maps it to our typed response. * * @private * @param response - Raw TEFAS API response * @param fundType - Fund type from the request * @returns Array of mapped fund history responses */ private processTefasResponse; /** * Processes TEFAS allocation API response and maps it to our typed response. * * @private * @param response - Raw TEFAS allocation API response * @param fundType - Fund type from the request * @returns Array of mapped fund allocation responses */ private processAllocationResponse; /** * Maps Fundfy response to FundDetail shape */ private mapFundfyResponse; /** * Extracts filename from a URL string; returns null if input is falsy. */ private extractFilename; /** * Generates a unique cache key for getFund requests * * @private * @param startDate - Start date (normalized) * @param endDate - End date (normalized) * @param fundCode - Optional fund code * @param fundType - Optional fund type * @returns Cache key string */ private generateCacheKey; /** * Clears all cached fund data * * Use this method to force fresh data retrieval or to free up memory. * Subsequent getFund() calls will fetch data from the API. * * @example * ```typescript * const client = new TefasClient(); * await client.getFund('2024-01-01', '2024-01-31'); // Fetches from API * await client.getFund('2024-01-01', '2024-01-31'); // Returns cached data * await client.clearCache(); * await client.getFund('2024-01-01', '2024-01-31'); // Fetches from API again * ``` */ clearCache(): Promise; /** * Invalidates cache for a specific fund/date range combination * * @param startDate - Start date in YYYY-MM-DD format or fuzzy date * @param endDate - End date in YYYY-MM-DD format or fuzzy date * @param fundCode - Optional specific fund code * @param fundType - Optional fund type * * @example * ```typescript * const client = new TefasClient(); * // Invalidate specific cache entry * await client.invalidateCache('2024-01-01', '2024-01-31', 'TGE', FundType.EMK); * ``` */ invalidateCache(startDate: string, endDate: string, fundCode?: string, fundType?: FundType): Promise; /** * Gets cache statistics * * Returns undefined if the cache adapter doesn't support statistics. * * @returns Cache statistics including size, TTL, and configuration, or undefined * * @example * ```typescript * const client = new TefasClient(); * const stats = await client.getCacheStats(); * if (stats) { * console.log(`Cache has ${stats.size} entries, TTL: ${stats.ttl}ms`); * } * ``` */ getCacheStats(): Promise; /** * Removes expired entries from the cache * * This method is useful for freeing up memory by removing stale entries. * The cache automatically checks expiration on access, but this method * allows for proactive cleanup. * * Returns undefined if the cache adapter doesn't support manual pruning. * * @returns Number of entries removed, or undefined if not supported * * @example * ```typescript * const client = new TefasClient(); * const removed = await client.pruneCache(); * if (removed !== undefined) { * console.log(`Removed ${removed} expired cache entries`); * } * ``` */ pruneCache(): Promise; /** * Retries an async operation with random delays between attempts * * @private * @param operation - Async function to retry * @param operationName - Name of the operation for logging * @param maxRetries - Maximum number of retry attempts (default: 3) * @returns Result of the operation * @throws Last error if all retries fail */ private retryWithDelay; /** * Translates errors to business-focused messages. * * @private * @param error - Error to translate * @returns Business-focused error */ private translateError; } /** * Type-safe REST API client for browser and Node.js environments * * @example * ```ts * const client = new ApiClient({ * baseUrl: 'https://api.example.com', * timeout: 5000 * }); * * const users = await client.get('/users'); * ``` */ declare class ApiClient { private config; /** * Creates a new API client instance * @param config - Client configuration options * @throws {TypeError} If baseUrl is invalid or timeout is not a positive number */ constructor(config: ApiClientConfig); /** * Create a new client with updated configuration * @param config - Partial configuration to merge * @returns New ApiClient instance with merged configuration * @example * ```ts * const client1 = new ApiClient({ baseUrl: 'https://api.example.com' }); * const client2 = client1.withConfig({ timeout: 5000 }); * // client1 unchanged, client2 has new timeout * ``` */ withConfig(config: Partial): ApiClient; /** * Make a GET request * @param url - Request URL (relative to baseUrl) * @param options - Optional request configuration * @returns Promise resolving to typed response data * @example * ```ts * const users = await client.get('/users', { * params: { page: 1, limit: 10 } * }); * ``` */ get(url: string, options?: RequestOptions): Promise; /** * Make a POST request * @param url - Request URL (relative to baseUrl) * @param data - Request body data * @param options - Optional request configuration * @returns Promise resolving to typed response data * @example * ```ts * const user = await client.post('/users', { * name: 'John Doe', * email: 'john@example.com' * }); * ``` */ post(url: string, data?: unknown, options?: RequestOptions): Promise; /** * Core request method with retry logic */ private request; /** * Execute a single request */ private executeRequest; /** * Build full URL with query parameters */ private buildUrl; /** * Build request headers */ private buildHeaders; /** * Serialize request body */ private serializeBody; /** * Parse response body */ private parseResponse; } /** * TEFAS API Client Error Classes * * This module defines business-focused error classes for TEFAS operations. * All errors are designed to be user-friendly and actionable. */ /** * Base error class for all API-related errors */ declare class ApiError extends Error { readonly cause?: unknown; constructor(message: string, cause?: unknown); } /** * Base error class for all TEFAS-related errors */ declare class TefasError extends ApiError { readonly code: string; readonly details?: unknown; constructor(message: string, code: string, details?: unknown); } /** * Error thrown when an invalid fund type is provided */ declare class InvalidFundTypeError extends TefasError { constructor(fundType: string); } /** * Error thrown when an invalid date format is provided */ declare class InvalidDateError extends TefasError { constructor(date: string, reason: string); } /** * Error thrown when a specific fund code is not found */ declare class FundNotFoundError extends TefasError { constructor(fundCode: string); } /** * Error thrown when date range is invalid */ declare class DateRangeError extends TefasError { constructor(startDate: string, endDate: string, reason: string); } /** * Error thrown when TEFAS API returns an error */ declare class TefasApiError extends TefasError { constructor(message: string, details?: unknown); } /** * Error thrown when network connectivity issues occur */ declare class NetworkError extends ApiError { constructor(message: string, cause?: unknown); } /** * Error thrown when response validation fails */ declare class ResponseValidationError extends TefasError { constructor(message: string, details?: unknown); } /** * Error thrown when configuration is invalid */ declare class ConfigurationError extends TefasError { constructor(message: string, details?: unknown); } /** * Type guard to check if an error is a TefasError */ declare function isTefasError(error: unknown): error is TefasError; /** * Type guard to check if an error is an InvalidFundTypeError */ declare function isInvalidFundTypeError(error: unknown): error is InvalidFundTypeError; /** * Type guard to check if an error is an InvalidDateError */ declare function isInvalidDateError(error: unknown): error is InvalidDateError; /** * Type guard to check if an error is a FundNotFoundError */ declare function isFundNotFoundError(error: unknown): error is FundNotFoundError; /** * Type guard to check if an error is a DateRangeError */ declare function isDateRangeError(error: unknown): error is DateRangeError; /** * Type guard to check if an error is a TefasApiError */ declare function isTefasApiError(error: unknown): error is TefasApiError; /** * Type guard to check if an error is a NetworkError */ declare function isNetworkError(error: unknown): error is NetworkError; /** * Type guard to check if an error is a ResponseValidationError */ declare function isResponseValidationError(error: unknown): error is ResponseValidationError; /** * Type guard to check if an error is a ConfigurationError */ declare function isConfigurationError(error: unknown): error is ConfigurationError; /** * Type guard to check if an error is an HttpError */ declare function isHttpError(error: unknown): error is HttpError; /** * Type guard to check if an error is a TimeoutError */ declare function isTimeoutError(error: unknown): error is TimeoutError; /** * Type guard to check if an error is a ValidationError */ declare function isValidationError(error: unknown): error is ValidationError; /** * HTTP error class for REST API client */ declare class HttpError extends ApiError { readonly status: number; readonly statusText: string; readonly responseData?: unknown; constructor(message: string, status: number, statusText: string, responseData?: unknown); } /** * Timeout error class for REST API client */ declare class TimeoutError extends ApiError { constructor(message: string); } /** * Validation error class for REST API client */ declare class ValidationError extends ApiError { readonly validationDetails?: unknown; constructor(message: string, validationDetails?: unknown); } /** * In-memory cache with TTL (Time To Live) support for TEFAS API responses. * * This cache helps reduce redundant API calls by storing responses temporarily. * Each cache entry expires after the configured TTL period. */ /** * Configuration options for the cache * * @public */ interface CacheOptions { /** * Time to live in milliseconds. Default: 15 minutes (900000ms) */ ttl?: number; /** * Whether caching is enabled. Default: true */ enabled?: boolean; /** * Maximum number of cache entries. Default: 1000 * When exceeded, oldest entries are removed (LRU-style) */ maxSize?: number; } /** * Memory-based cache adapter using Map * * This adapter wraps the TtlCache implementation and provides the CacheAdapter * interface. It is the default cache used when no custom adapter is provided. */ /** * In-memory cache adapter using Map with TTL support * * This is the default cache implementation that wraps the existing TtlCache. * All methods return Promises for consistency with the async CacheAdapter interface, * even though operations are synchronous. * * Features: * - TTL-based expiration * - LRU-style eviction when max size is reached * - Automatic expiration checking on access * - Manual cache management (clear, prune, stats) * * @template T - Type of values stored in the cache * * @example * ```typescript * const cache = new MemoryCacheAdapter({ * ttl: 15 * 60 * 1000, // 15 minutes * maxSize: 1000, * enabled: true * }); * * await cache.set('key1', myData); * const value = await cache.get('key1'); * ``` */ declare class MemoryCacheAdapter implements CacheAdapterWithStats { private readonly cache; private readonly enabled; /** * Creates a new memory cache adapter * * @param options - Cache configuration options */ constructor(options?: CacheOptions); /** * Retrieves a value from the cache * * @param key - Cache key * @returns Cached value or undefined if not found or expired */ get(key: string): Promise; /** * Stores a value in the cache * * Note: The current TtlCache implementation doesn't support per-key TTL. * The ttl parameter is accepted for interface compatibility but uses * the cache-wide TTL configured in the constructor. * * @param key - Cache key * @param value - Value to cache * @param ttl - Time-to-live in seconds (currently ignored, uses cache-wide TTL) */ set(key: string, value: T, ttl?: number): Promise; /** * Removes a specific entry from the cache * * @param key - Cache key to delete * @returns true if key was deleted, false if it didn't exist */ delete(key: string): Promise; /** * Clears all entries from the cache */ clear(): Promise; /** * Checks if a key exists in the cache and is not expired * * @param key - Cache key * @returns true if key exists and is valid */ has(key: string): Promise; /** * Gets cache statistics * * @returns Cache statistics including size, TTL, and configuration */ getStats(): Promise; /** * Removes expired entries from the cache * * This method is useful for freeing up memory by removing stale entries. * The cache automatically checks expiration on access, but this method * allows for proactive cleanup. * * @returns Number of entries removed */ prune(): Promise; } /** * Cloudflare Workers KV cache adapter * * This adapter allows using Cloudflare Workers KV as a distributed cache * backend for the TEFAS API client. Perfect for edge computing scenarios * where you want to cache API responses globally. * * @example * ```typescript * // In a Cloudflare Worker * import { TefasClient, CloudflareKVCacheAdapter } from '@firstthumb/tefas-api'; * * export default { * async fetch(request: Request, env: Env): Promise { * const cache = new CloudflareKVCacheAdapter({ * namespace: env.TEFAS_CACHE, * ttl: 15 * 60 * 1000 * }); * * const client = new TefasClient({ cacheAdapter: cache }); * const data = await client.getFund('2024-01-01', '2024-12-31'); * * return Response.json(data); * } * }; * ``` */ /** * Minimal KV namespace interface * * This matches the Cloudflare Workers KV API without requiring * @cloudflare/workers-types as a dependency. If you have the types * package, they're fully compatible. */ interface KVNamespace { get(key: string, options?: { type?: 'text' | 'json' | 'arrayBuffer' | 'stream'; }): Promise; put(key: string, value: string | ArrayBuffer | ReadableStream, options?: { expirationTtl?: number; expiration?: number; }): Promise; delete(key: string): Promise; list(options?: { prefix?: string; limit?: number; cursor?: string; }): Promise<{ keys: Array<{ name: string; }>; list_complete: boolean; cursor?: string; }>; } /** * Configuration options for Cloudflare KV cache adapter */ interface CloudflareKVCacheOptions { /** * The Cloudflare KV namespace to use for caching * * This is typically bound to your Worker via wrangler.toml: * ```toml * [[kv_namespaces]] * binding = "TEFAS_CACHE" * id = "your-kv-namespace-id" * ``` */ namespace: KVNamespace; /** * Default time-to-live in milliseconds * * Note: This will be converted to seconds for KV storage. * Cloudflare KV minimum TTL is 60 seconds. * * @default 900000 (15 minutes) */ ttl?: number; /** * Optional key prefix for namespace isolation * * Useful if sharing a KV namespace across multiple applications * or environments. * * @default "tefas:" * @example "prod:tefas:" or "staging:tefas:" */ prefix?: string; } /** * Cloudflare Workers KV cache adapter * * Implements the CacheAdapter interface using Cloudflare Workers KV * as the storage backend. Values are automatically serialized to JSON. * * **Features:** * - Globally distributed edge caching * - Automatic JSON serialization * - TTL support (converted from milliseconds to seconds) * - Key prefixing for namespace isolation * * **Limitations:** * - `clear()` is not fully supported (KV has no bulk delete by pattern) * - `has()` performs a full `get()` operation (KV has no exists check) * - Eventual consistency (updates may take time to propagate globally) * * @template T - Type of values stored in the cache */ declare class CloudflareKVCacheAdapter implements CacheAdapter { private readonly kv; private readonly ttl; private readonly prefix; /** * Creates a new Cloudflare KV cache adapter * * @param options - Configuration options including KV namespace */ constructor(options: CloudflareKVCacheOptions); /** * Generates the full key with prefix * * @param key - Cache key * @returns Prefixed key */ private getKey; /** * Converts TTL from milliseconds to seconds for KV * * Cloudflare KV requires TTL in seconds and has a minimum of 60 seconds. * * @param ttl - TTL in milliseconds * @returns TTL in seconds, minimum 60 */ private convertTtl; /** * Retrieves a value from Cloudflare KV * * @param key - Cache key * @returns Cached value or undefined if not found or expired */ get(key: string): Promise; /** * Stores a value in Cloudflare KV * * Values are automatically serialized to JSON. TTL is converted from * milliseconds to seconds with a minimum of 60 seconds. * * @param key - Cache key * @param value - Value to cache * @param ttl - Optional time-to-live in milliseconds (overrides default) */ set(key: string, value: T, ttl?: number): Promise; /** * Removes a specific entry from Cloudflare KV * * @param key - Cache key to delete * @returns true (KV delete doesn't return a boolean, always returns true) */ delete(key: string): Promise; /** * Clears all cache entries with the configured prefix * * **⚠️ Limitation:** Cloudflare KV doesn't support efficient bulk deletion. * This method lists all keys with the prefix and deletes them individually, * which can be slow and may hit rate limits for large caches. * * For production use, consider these alternatives: * 1. Use key versioning (e.g., prefix with "v1:", "v2:") * 2. Let entries expire naturally via TTL * 3. Manually track keys in a separate list * * @throws Error if listing or deletion fails */ clear(): Promise; /** * Checks if a key exists in Cloudflare KV * * **Note:** KV doesn't have a dedicated exists check, so this performs * a full `get()` operation. The value is not returned to save memory. * * @param key - Cache key * @returns true if key exists and is valid */ has(key: string): Promise; } /** * Date Validation Utilities * * This module provides utilities for date format validation and range checking * for TEFAS API requests. */ /** * Validates if a date string is in ISO 8601 format (YYYY-MM-DD) * * @param date - Date string to validate * @returns True if valid, false otherwise */ declare function isValidDateFormat(date: string): boolean; /** * Validates a date string and throws an error if invalid * * @param date - Date string to validate * @param fieldName - Name of the field for error messages * @throws InvalidDateError if date is invalid */ declare function validateDate(date: string, fieldName?: string): void; /** * Parses a date string to a Date object * * @param date - Date string in YYYY-MM-DD format * @returns Parsed Date object * @throws InvalidDateError if date is invalid */ declare function parseDate(date: string): Date; /** * Formats a date to YYYY-MM-DD string * * @param date - Date object to format * @returns Formatted date string */ declare function formatDate(date: Date): string; /** * Gets the current date in YYYY-MM-DD format * * @returns Current date string */ declare function getCurrentDate(): string; /** * Adds days to a date * * @param date - Date string in YYYY-MM-DD format * @param days - Number of days to add (can be negative) * @returns New date string in YYYY-MM-DD format */ declare function addDays(date: string, days: number): string; /** * Calculates the number of days between two dates * * @param startDate - Start date string * @param endDate - End date string * @returns Number of days between dates */ declare function getDaysBetween(startDate: string, endDate: string): number; /** * Checks if a date is in the past * * @param date - Date string to check * @returns True if date is in the past */ declare function isPastDate(date: string): boolean; /** * Checks if a date is in the future * * @param date - Date string to check * @returns True if date is in the future */ declare function isFutureDate(date: string): boolean; /** * Validates a date range and throws an error if invalid * * @param startDate - Start date string in YYYY-MM-DD format * @param endDate - End date string in YYYY-MM-DD format * @param maxDays - Maximum allowed days in range (optional, no limit if not provided) * @throws InvalidDateError if either date format is invalid * @throws DateRangeError if date range is invalid */ declare function validateDateRange(startDate: string, endDate: string, maxDays?: number): void; /** * Validates that start date is not more than 5 years ago (TEFAS API constraint) * * TEFAS API has a Web Application Firewall (WAF) that rejects requests with * startDate earlier than 5 years ago. We add a 1-day buffer for safety. * * @param startDate - Start date string in YYYY-MM-DD format * @throws InvalidDateError if date format is invalid * @throws DateRangeError if startDate is earlier than 5 years ago + 1 day buffer * * @example * ```typescript * // Today is 2025-11-22 * validateTefasDateLimit('2020-11-23'); // Valid (exactly 5 years ago + 1 day) * validateTefasDateLimit('2020-11-22'); // Throws DateRangeError (too far back) * validateTefasDateLimit('2020-11-20'); // Throws DateRangeError (too far back) * ``` */ declare function validateTefasDateLimit(startDate: string): void; /** * Converts a date from YYYY-MM-DD format to DD.MM.YYYY format for TEFAS API * * @param date - Date string in YYYY-MM-DD format * @returns Date string in DD.MM.YYYY format * @throws InvalidDateError if date is invalid */ declare function convertToTefasDateFormat(date: string): string; /** * Parses a fuzzy date string (e.g., "today", "yesterday", "2024-01-01") to a normalized YYYY-MM-DD format * * @param dateInput - Fuzzy date string (e.g., "today", "yesterday", "2024-01-01", "last week") * @param referenceDate - Optional reference date for relative date parsing (defaults to current date) * @returns Normalized date string in YYYY-MM-DD format * @throws InvalidDateError if date cannot be parsed * * @example * ```typescript * parseFuzzyDate('today'); // Returns current date in YYYY-MM-DD format * parseFuzzyDate('yesterday'); // Returns yesterday's date in YYYY-MM-DD format * parseFuzzyDate('2024-01-01'); // Returns '2024-01-01' * parseFuzzyDate('last week'); // Returns date from last week * ``` */ declare function parseFuzzyDate(dateInput: string, referenceDate?: Date): string; /** * Validates and normalizes fuzzy date inputs for TEFAS API * * @param startDate - Start date (fuzzy or YYYY-MM-DD format) * @param endDate - End date (fuzzy or YYYY-MM-DD format) * @param maxDays - Maximum allowed days in range (optional, no limit if not provided) * @returns Object containing normalized start and end dates * @throws InvalidDateError if either date cannot be parsed * @throws DateRangeError if date range is invalid * * @example * ```typescript * const { startDate, endDate } = normalizeFuzzyDateRange('today', 'yesterday'); * // Throws DateRangeError because start > end * * const { startDate, endDate } = normalizeFuzzyDateRange('yesterday', 'today'); * // Returns normalized dates * ``` */ declare function normalizeFuzzyDateRange(startDate: string, endDate: string, maxDays?: number): { startDate: string; endDate: string; }; /** * Fund Type Validation Utilities * * This module provides utilities for fund type validation and management * for TEFAS API requests. */ /** * Array of all supported fund types */ declare const SUPPORTED_FUND_TYPES: readonly FundType[]; /** * Fund type descriptions for user-friendly error messages */ declare const FUND_TYPE_DESCRIPTIONS: Record; /** * Validates if a value is a valid fund type * * @param value - Value to validate * @returns True if valid fund type, false otherwise */ declare function isValidFundType(value: unknown): value is FundType; /** * Validates a fund type and throws an error if invalid * * @param fundType - Fund type to validate * @throws InvalidFundTypeError if fund type is invalid */ declare function validateFundType(fundType: unknown): asserts fundType is FundType; /** * Gets all supported fund types * * @returns Array of supported fund types */ declare function getSupportedFundTypes(): readonly FundType[]; /** * Gets fund type description * * @param fundType - Fund type to get description for * @returns Human-readable description of the fund type */ declare function getFundTypeDescription(fundType: FundType): string; /** * Gets all fund type descriptions * * @returns Object mapping fund types to their descriptions */ declare function getAllFundTypeDescriptions(): Record; /** * Converts a fund type to its TEFAS API representation * * @param fundType - Fund type to convert * @returns TEFAS API fund type string */ declare function toTefasApiFundType(fundType: FundType): string; /** * Converts a TEFAS API fund type to our FundType enum * * @param apiFundType - TEFAS API fund type string * @returns FundType enum value * @throws InvalidFundTypeError if API fund type is not supported */ declare function fromTefasApiFundType(apiFundType: string): FundType; /** * Checks if a fund type is supported * * @param fundType - Fund type to check * @returns True if supported, false otherwise */ declare function isSupportedFundType(fundType: string): boolean; /** * Gets fund type validation error message * * @param fundType - Invalid fund type * @returns User-friendly error message */ declare function getFundTypeValidationError(fundType: string): string; /** * Normalizes fund type string (uppercase, trimmed) * * @param fundType - Fund type string to normalize * @returns Normalized fund type string */ declare function normalizeFundType(fundType: string): string; /** * Validates and normalizes a fund type * * @param fundType - Fund type to validate and normalize * @returns Normalized fund type * @throws InvalidFundTypeError if fund type is invalid */ declare function validateAndNormalizeFundType(fundType: string): FundType; /** * Gets fund type display name for UI purposes * * @param fundType - Fund type to get display name for * @returns Display name for the fund type */ declare function getFundTypeDisplayName(fundType: FundType): string; /** * Gets fund type category for grouping purposes * * @param fundType - Fund type to get category for * @returns Category of the fund type */ declare function getFundTypeCategory(fundType: FundType): string; /** * Response Mapping Utilities * * This module provides utilities for mapping TEFAS API responses to typed responses * and validating response data. */ /** * Maps a single TEFAS API fund data item to our typed response * * @param apiData - Raw fund data from TEFAS API * @returns Mapped fund history response * @throws ResponseValidationError if data is invalid */ declare function mapTefasFundData(apiData: TefasApiFundData): FundHistoryResponse; /** * Maps TEFAS API response to our typed response array * * @param apiResponse - Raw response from TEFAS API * @param fundType - Fund type from the request (used to set fund type in response) * @returns Array of mapped fund history responses * @throws ResponseValidationError if response is invalid */ declare function mapTefasResponse(apiResponse: TefasApiResponse, fundType: FundType): FundHistoryResponse[]; /** * Validates a single fund history response * * @param response - Fund history response to validate * @returns True if valid, false otherwise */ declare function validateFundHistoryResponse(response: FundHistoryResponse): boolean; /** * Validates an array of fund history responses * * @param responses - Array of fund history responses to validate * @returns True if all responses are valid, false otherwise */ declare function validateFundHistoryResponses(responses: FundHistoryResponse[]): boolean; /** * Filters fund history responses by fund type * * @param responses - Array of fund history responses * @param fundType - Fund type to filter by * @returns Filtered array of responses */ declare function filterByFundType(responses: FundHistoryResponse[], fundType: FundType): FundHistoryResponse[]; /** * Filters fund history responses by fund code * * @param responses - Array of fund history responses * @param fundCode - Fund code to filter by * @returns Filtered array of responses */ declare function filterByFundCode(responses: FundHistoryResponse[], fundCode: string): FundHistoryResponse[]; /** * Groups fund history responses by fund code * * @param responses - Array of fund history responses * @returns Object with fund codes as keys and arrays of responses as values */ declare function groupByFundCode(responses: FundHistoryResponse[]): Record; /** * Sorts fund history responses by date (ascending) * * @param responses - Array of fund history responses * @returns Sorted array of responses */ declare function sortByDate(responses: FundHistoryResponse[]): FundHistoryResponse[]; /** * Sorts fund history responses by date (descending) * * @param responses - Array of fund history responses * @returns Sorted array of responses */ declare function sortByDateDescending(responses: FundHistoryResponse[]): FundHistoryResponse[]; /** * Gets unique fund codes from responses * * @param responses - Array of fund history responses * @returns Array of unique fund codes */ declare function getUniqueFundCodes(responses: FundHistoryResponse[]): string[]; /** * Gets the latest response for each fund * * @param responses - Array of fund history responses * @returns Object with fund codes as keys and latest responses as values */ declare function getLatestByFundCode(responses: FundHistoryResponse[]): Record; /** * Calculates total assets across all funds * * @param responses - Array of fund history responses * @returns Total assets value */ declare function calculateTotalAssets(responses: FundHistoryResponse[]): number; /** * Calculates average price across all funds * * @param responses - Array of fund history responses * @returns Average price */ declare function calculateAveragePrice(responses: FundHistoryResponse[]): number; /** * Search Response Parser Utility * * Handles parsing of the nested JSON response structure from TEFAS GetAllFunds API. * The API returns a double-encoded JSON structure that requires special handling. */ /** * Parse TEFAS search API response into SearchResult array * * The TEFAS GetAllFunds API returns a nested JSON structure: * 1. Top level has a "d" array property * 2. Each array element is a JSON-encoded string (double-encoded) * 3. Each string contains an object with "First" (display name) and "Second" (fund code) * * @param response - Raw API response object * @param fundType - Fund type to include in each result * @returns Array of SearchResult objects * @throws ValidationError if response structure is invalid * * @example * ```typescript * const apiResponse = { * d: [ * '{"First":"IIH - İSTANBUL PORTFÖY ÜÇÜNCÜ HİSSE SENEDİ FONU","Second":"IIH"}' * ] * }; * const results = parseSearchResponse(apiResponse, FundType.YAT); * // results = [{ fundCode: "IIH", fundName: "İSTANBUL PORTFÖY ÜÇÜNCÜ HİSSE SENEDİ FONU", fundType: FundType.YAT }] * ``` */ declare function parseSearchResponse(response: unknown, fundType: FundType): SearchResult[]; /** * Validate that a search response has the expected structure * * @param response - Response to validate * @returns True if response has valid structure, false otherwise * * @example * ```typescript * if (isValidSearchResponse(apiResponse)) { * const results = parseSearchResponse(apiResponse, FundType.YAT); * } * ``` */ declare function isValidSearchResponse(response: unknown): boolean; /** * Performance Calculator Utilities * * This module provides utilities for calculating financial performance metrics * from fund history data. Uses simple-statistics for mathematical calculations. */ /** * Performance calculator for fund metrics * * Provides static methods for calculating various financial performance metrics * including returns, volatility, and risk-adjusted measures. */ declare class PerformanceCalculator { /** * Calculate performance metrics for multiple funds * * @param fundHistory - Array of fund history data * @param options - Configuration options for calculations * @returns Array of performance metrics for each fund */ static calculateMetrics(fundHistory: FundHistoryResponse[], options?: MetricsOptions): PerformanceMetrics[]; /** * Group fund history data by fund code * * @param fundHistory - Array of fund history data * @returns Map of fund code to fund data array */ static groupByFund(fundHistory: FundHistoryResponse[]): Map; /** * Calculate returns from price series * * @param prices - Array of prices in chronological order * @param method - Return calculation method * @returns Array of returns */ static calculateReturns(prices: number[], method: 'simple' | 'logarithmic'): number[]; /** * Calculate cumulative return over the period * * @param returns - Array of returns * @param method - Return calculation method * @returns Cumulative return */ static calculateCumulativeReturn(returns: number[], method: string): number; /** * Calculate annualized return * * @param returns - Array of returns * @param periodsPerYear - Number of periods per year * @param method - Return calculation method * @returns Annualized return */ static calculateAnnualizedReturn(returns: number[], periodsPerYear: number, method: string): number; /** * Calculate annualized volatility * * @param returns - Array of returns * @param periodsPerYear - Number of periods per year * @returns Annualized volatility */ static calculateVolatility(returns: number[], periodsPerYear: number): number; /** * Calculate Sharpe ratio * * @param returns - Array of returns * @param riskFreeRate - Risk-free rate * @param periodsPerYear - Number of periods per year * @param method - Return calculation method * @returns Sharpe ratio */ static calculateSharpeRatio(returns: number[], riskFreeRate: number, periodsPerYear: number, method: string): number; /** * Calculate Sortino ratio (uses only downside volatility) * * @param returns - Array of returns * @param riskFreeRate - Risk-free rate * @param periodsPerYear - Number of periods per year * @param method - Return calculation method * @returns Sortino ratio */ static calculateSortinoRatio(returns: number[], riskFreeRate: number, periodsPerYear: number, method: string): number; /** * Calculate maximum drawdown * * @param prices - Array of prices in chronological order * @returns Maximum drawdown as a percentage (negative value) */ static calculateMaximumDrawdown(prices: number[]): number; /** * Calculate Calmar ratio (annualized return / maximum drawdown) * * @param returns - Array of returns * @param prices - Array of prices in chronological order * @param periodsPerYear - Number of periods per year * @param method - Return calculation method * @returns Calmar ratio */ static calculateCalmarRatio(returns: number[], prices: number[], periodsPerYear: number, method: string): number; /** * Calculate Beta (sensitivity to benchmark/market movements) * * @param fundReturns - Array of fund returns * @param benchmarkReturns - Array of benchmark returns (must align with fund returns) * @returns Beta coefficient */ static calculateBeta(fundReturns: number[], benchmarkReturns: number[]): number; /** * Calculate Information Ratio (active return / tracking error) * * @param fundReturns - Array of fund returns * @param benchmarkReturns - Array of benchmark returns (must align with fund returns) * @param periodsPerYear - Number of periods per year * @returns Information Ratio */ static calculateInformationRatio(fundReturns: number[], benchmarkReturns: number[], periodsPerYear: number): number; /** * Calculate Treynor Ratio (excess return / beta) * * @param returns - Array of fund returns * @param benchmarkReturns - Array of benchmark returns (must align with fund returns) * @param riskFreeRate - Risk-free rate * @param periodsPerYear - Number of periods per year * @param method - Return calculation method * @returns Treynor Ratio */ static calculateTreynorRatio(returns: number[], benchmarkReturns: number[], riskFreeRate: number, periodsPerYear: number, method: string): number; /** * Get periods per year for frequency * * @param frequency - Data frequency * @returns Number of periods per year */ static getPeriodsPerYear(frequency: string): number; /** * Create empty metrics for insufficient data * * @param fundCode - Fund code * @param sample - Sample data point for fund info * @returns Empty performance metrics */ static createEmptyMetrics(fundCode: string, sample: FundHistoryResponse): PerformanceMetrics; } export { ApiClient, type ApiClientConfig, ApiError, type ApiResponse, type CacheAdapter, type CacheAdapterWithStats, type CacheOptions, type CacheStats, CloudflareKVCacheAdapter, type CloudflareKVCacheOptions, ConfigurationError, DateRangeError, type DateRangeValidation, FUND_TYPE_DESCRIPTIONS, type FundBenchmark, type FundCategory, type FundContentResponse, type FundDetail, type FundHistoryResponse, FundNotFoundError, type FundResponse, FundType, HttpError, type HttpMethod, InvalidDateError, InvalidFundTypeError, type KVNamespace, MemoryCacheAdapter, type MetricsOptions, NetworkError, PerformanceCalculator, type PerformanceMetrics, type RequestOptions, ResponseValidationError, SUPPORTED_FUND_TYPES, type SearchOptions, type SearchResult, type TefasAllocationApiResponse, type TefasAllocationData, TefasApiError, type TefasApiFundData, type TefasApiRequest, type TefasApiResponse, TefasClient, type TefasClientConfig, TefasError, TimeoutError, ValidationError, addDays, calculateAveragePrice, calculateTotalAssets, convertToTefasDateFormat, filterByFundCode, filterByFundType, formatDate, fromTefasApiFundType, getAllFundTypeDescriptions, getCurrentDate, getDaysBetween, getFundTypeCategory, getFundTypeDescription, getFundTypeDisplayName, getFundTypeValidationError, getLatestByFundCode, getSupportedFundTypes, getUniqueFundCodes, groupByFundCode, isCacheAdapterWithStats, isConfigurationError, isDateRangeError, isFundNotFoundError, isFutureDate, isHttpError, isInvalidDateError, isInvalidFundTypeError, isNetworkError, isPastDate, isResponseValidationError, isSupportedFundType, isTefasApiError, isTefasError, isTimeoutError, isValidDateFormat, isValidFundType, isValidSearchResponse, isValidationError, mapTefasFundData, mapTefasResponse, normalizeFundType, normalizeFuzzyDateRange, parseDate, parseFuzzyDate, parseSearchResponse, sortByDate, sortByDateDescending, toTefasApiFundType, validateAndNormalizeFundType, validateDate, validateDateRange, validateFundHistoryResponse, validateFundHistoryResponses, validateFundType, validateTefasDateLimit };