{"version":3,"sources":["../src/errors.ts","../src/utils/serialize.ts","../src/client.ts","../src/types.ts","../src/utils/fund-type-validation.ts","../src/utils/date-validation.ts","../src/utils/response-mapping.ts","../src/utils/search-response-parser.ts","../src/utils/allocation-response-mapping.ts","../src/constants.ts","../src/tefas-client.ts","../src/utils/performance-calculator.ts"],"names":["ApiError","_ApiError","message","cause","TefasError","code","details","InvalidFundTypeError","fundType","supportedTypes","InvalidDateError","date","reason","FundNotFoundError","fundCode","DateRangeError","startDate","endDate","TefasApiError","NetworkError","ResponseValidationError","ConfigurationError","isTefasError","error","isInvalidFundTypeError","isInvalidDateError","isFundNotFoundError","isDateRangeError","isTefasApiError","isNetworkError","isResponseValidationError","isConfigurationError","isHttpError","HttpError","isTimeoutError","TimeoutError","isValidationError","ValidationError","_HttpError","status","statusText","responseData","_TimeoutError","_ValidationError","validationDetails","serializeFormData","data","params","key","value","buildQueryString","searchParams","queryString","ApiClient","_ApiClient","config","url","options","method","lastError","attempt","delay","resolve","fullUrl","contentType","headers","body","controller","timeoutMs","timeoutId","response","errorData","path","base","cleanPath","fullPath","customHeaders","FundType","SUPPORTED_FUND_TYPES","FUND_TYPE_DESCRIPTIONS","isValidFundType","validateFundType","getSupportedFundTypes","getFundTypeDescription","getAllFundTypeDescriptions","toTefasApiFundType","fromTefasApiFundType","apiFundType","isSupportedFundType","getFundTypeValidationError","normalizeFundType","validateAndNormalizeFundType","normalized","getFundTypeDisplayName","getFundTypeCategory","ISO_DATE_REGEX","isValidDateFormat","parsedDate","validateDate","fieldName","parseDate","formatDate","getCurrentDate","addDays","days","newDate","getDaysBetween","start","end","isPastDate","today","isFutureDate","validateDateRange","maxDays","convertToTefasDateFormat","year","month","day","parseFuzzyDate","dateInput","referenceDate","trimmedInput","parsedResult","te","normalizeFuzzyDateRange","normalizedStartDate","normalizedEndDate","mapTefasFundData","apiData","timestamp","dateString","volume","mapTefasResponse","apiResponse","fundData","index","mappedData","validateFundHistoryResponse","validateFundHistoryResponses","responses","filterByFundType","filterByFundCode","groupByFundCode","groups","sortByDate","a","b","sortByDateDescending","getUniqueFundCodes","fundCodes","getLatestByFundCode","sorted","latest","calculateTotalAssets","total","calculateAveragePrice","parseSearchResponse","results","i","item","parsed","fullName","errorMessage","isValidSearchResponse","convertTimestampToDate","parseCommaFormattedNumber","cleanValue","mapAllocationResponse","TEFAS_ALLOCATION_ENDPOINT","TefasClient","query","searchRequest","limit","historyResponse","contentResponse","historyData","contentData","historyMap","contentMap","history","content","allKeys","mergedData","fundName","merged","requiredHeaders","header","totalDays","MAX_DAYS","fundHistory","chunkStart","tentativeEnd","chunkEnd","chunkRequest","chunkResponse","chunkHistory","tefasRequest","allFundTypes","allResults","promises","result","fundContent","chunkContent","allocationRequest","request","httpError","PerformanceCalculator","riskFreeRate","frequency","minObservations","fundGroups","periodsPerYear","sortedData","prices","d","returns","cumulativeReturn","annualizedReturn","annualizedVolatility","sharpeRatio","existing","currentPrice","previousPrice","sum","acc","ret","years","product","standardDeviation","volatility","downsideReturns","downsideVolatility","maxDrawdown","peak","drawdown","fundReturns","benchmarkReturns","fundMean","mean","benchmarkMean","covariance","benchmarkVariance","activeReturns","fundRet","activeReturnMean","trackingError","beta","sample"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * TEFAS API Client Error Classes\n * \n * This module defines business-focused error classes for TEFAS operations.\n * All errors are designed to be user-friendly and actionable.\n */\n\n/**\n * Base error class for all API-related errors\n */\nexport class ApiError extends Error {\n  public readonly cause?: unknown;\n\n  constructor(message: string, cause?: unknown) {\n    super(message);\n    this.name = 'ApiError';\n    this.cause = cause;\n    \n    // Maintain proper stack trace for where our error was thrown\n    if (Error.captureStackTrace) {\n      Error.captureStackTrace(this, ApiError);\n    }\n  }\n}\n\n/**\n * Base error class for all TEFAS-related errors\n */\nexport class TefasError extends ApiError {\n  public readonly code: string;\n  public readonly details?: unknown;\n\n  constructor(message: string, code: string, details?: unknown) {\n    super(message);\n    this.name = 'TefasError';\n    this.code = code;\n    this.details = details;\n  }\n}\n\n/**\n * Error thrown when an invalid fund type is provided\n */\nexport class InvalidFundTypeError extends TefasError {\n  constructor(fundType: string) {\n    const supportedTypes = ['EMK', 'YAT', 'BYF', 'GYF', 'GSYF'];\n    super(\n      `Invalid fund type '${fundType}'. Supported types are: ${supportedTypes.join(', ')}`,\n      'INVALID_FUND_TYPE',\n      { providedType: fundType, supportedTypes }\n    );\n    this.name = 'InvalidFundTypeError';\n  }\n}\n\n/**\n * Error thrown when an invalid date format is provided\n */\nexport class InvalidDateError extends TefasError {\n  constructor(date: string, reason: string) {\n    super(\n      `Invalid date '${date}': ${reason}. Please use YYYY-MM-DD format (e.g., 2024-01-01)`,\n      'INVALID_DATE',\n      { providedDate: date, reason }\n    );\n    this.name = 'InvalidDateError';\n  }\n}\n\n/**\n * Error thrown when a specific fund code is not found\n */\nexport class FundNotFoundError extends TefasError {\n  constructor(fundCode: string) {\n    super(\n      `Fund '${fundCode}' not found. Please check the fund code and try again`,\n      'FUND_NOT_FOUND',\n      { fundCode }\n    );\n    this.name = 'FundNotFoundError';\n  }\n}\n\n/**\n * Error thrown when date range is invalid\n */\nexport class DateRangeError extends TefasError {\n  constructor(startDate: string, endDate: string, reason: string) {\n    super(\n      `Invalid date range from '${startDate}' to '${endDate}': ${reason}`,\n      'INVALID_DATE_RANGE',\n      { startDate, endDate, reason }\n    );\n    this.name = 'DateRangeError';\n  }\n}\n\n/**\n * Error thrown when TEFAS API returns an error\n */\nexport class TefasApiError extends TefasError {\n  constructor(message: string, details?: unknown) {\n    super(\n      `TEFAS API error: ${message}`,\n      'TEFAS_API_ERROR',\n      details\n    );\n    this.name = 'TefasApiError';\n  }\n}\n\n/**\n * Error thrown when network connectivity issues occur\n */\nexport class NetworkError extends ApiError {\n  constructor(message: string, cause?: unknown) {\n    super(message, cause);\n    this.name = 'NetworkError';\n  }\n}\n\n/**\n * Error thrown when response validation fails\n */\nexport class ResponseValidationError extends TefasError {\n  constructor(message: string, details?: unknown) {\n    super(\n      `Response validation failed: ${message}`,\n      'RESPONSE_VALIDATION_ERROR',\n      details\n    );\n    this.name = 'ResponseValidationError';\n  }\n}\n\n/**\n * Error thrown when configuration is invalid\n */\nexport class ConfigurationError extends TefasError {\n  constructor(message: string, details?: unknown) {\n    super(\n      `Configuration error: ${message}`,\n      'CONFIGURATION_ERROR',\n      details\n    );\n    this.name = 'ConfigurationError';\n  }\n}\n\n/**\n * Type guard to check if an error is a TefasError\n */\nexport function isTefasError(error: unknown): error is TefasError {\n  return error instanceof TefasError;\n}\n\n/**\n * Type guard to check if an error is an InvalidFundTypeError\n */\nexport function isInvalidFundTypeError(error: unknown): error is InvalidFundTypeError {\n  return error instanceof InvalidFundTypeError;\n}\n\n/**\n * Type guard to check if an error is an InvalidDateError\n */\nexport function isInvalidDateError(error: unknown): error is InvalidDateError {\n  return error instanceof InvalidDateError;\n}\n\n/**\n * Type guard to check if an error is a FundNotFoundError\n */\nexport function isFundNotFoundError(error: unknown): error is FundNotFoundError {\n  return error instanceof FundNotFoundError;\n}\n\n/**\n * Type guard to check if an error is a DateRangeError\n */\nexport function isDateRangeError(error: unknown): error is DateRangeError {\n  return error instanceof DateRangeError;\n}\n\n/**\n * Type guard to check if an error is a TefasApiError\n */\nexport function isTefasApiError(error: unknown): error is TefasApiError {\n  return error instanceof TefasApiError;\n}\n\n/**\n * Type guard to check if an error is a NetworkError\n */\nexport function isNetworkError(error: unknown): error is NetworkError {\n  return error instanceof NetworkError;\n}\n\n/**\n * Type guard to check if an error is a ResponseValidationError\n */\nexport function isResponseValidationError(error: unknown): error is ResponseValidationError {\n  return error instanceof ResponseValidationError;\n}\n\n/**\n * Type guard to check if an error is a ConfigurationError\n */\nexport function isConfigurationError(error: unknown): error is ConfigurationError {\n  return error instanceof ConfigurationError;\n}\n\n/**\n * Type guard to check if an error is an HttpError\n */\nexport function isHttpError(error: unknown): error is HttpError {\n  return error instanceof HttpError;\n}\n\n/**\n * Type guard to check if an error is a TimeoutError\n */\nexport function isTimeoutError(error: unknown): error is TimeoutError {\n  return error instanceof TimeoutError;\n}\n\n/**\n * Type guard to check if an error is a ValidationError\n */\nexport function isValidationError(error: unknown): error is ValidationError {\n  return error instanceof ValidationError;\n}\n\n/**\n * HTTP error class for REST API client\n */\nexport class HttpError extends ApiError {\n  public readonly status: number;\n  public readonly statusText: string;\n  public readonly responseData?: unknown;\n\n  constructor(message: string, status: number, statusText: string, responseData?: unknown) {\n    super(message);\n    this.name = 'HttpError';\n    this.status = status;\n    this.statusText = statusText;\n    this.responseData = responseData;\n    \n    if (Error.captureStackTrace) {\n      Error.captureStackTrace(this, HttpError);\n    }\n  }\n}\n\n/**\n * Timeout error class for REST API client\n */\nexport class TimeoutError extends ApiError {\n  constructor(message: string) {\n    super(message);\n    this.name = 'TimeoutError';\n    \n    if (Error.captureStackTrace) {\n      Error.captureStackTrace(this, TimeoutError);\n    }\n  }\n}\n\n/**\n * Validation error class for REST API client\n */\nexport class ValidationError extends ApiError {\n  public readonly validationDetails?: unknown;\n\n  constructor(message: string, validationDetails?: unknown) {\n    super(message);\n    this.name = 'ValidationError';\n    this.validationDetails = validationDetails;\n    \n    if (Error.captureStackTrace) {\n      Error.captureStackTrace(this, ValidationError);\n    }\n  }\n}","/**\n * Serialize data to application/x-www-form-urlencoded format\n *\n * Converts an object to a URL-encoded string suitable for form POST requests.\n * Undefined and null values are omitted from the output.\n * All values are converted to strings and properly URL-encoded.\n *\n * @param data - Object to serialize\n * @returns URL-encoded string\n *\n * @example\n * ```ts\n * serializeFormData({ name: 'John Doe', age: 30, active: true })\n * // Returns: \"name=John+Doe&age=30&active=true\"\n *\n * serializeFormData({ fontip: 'YAT', bastarih: '01.12.2024' })\n * // Returns: \"fontip=YAT&bastarih=01.12.2024\"\n * ```\n *\n * @since 1.0.0\n */\nexport function serializeFormData(\n  data: Record<string, any>\n): string {\n  const params = new URLSearchParams();\n\n  for (const [key, value] of Object.entries(data)) {\n    if (value !== undefined && value !== null) {\n      params.append(key, String(value));\n    }\n  }\n\n  return params.toString();\n}\n\n/**\n * Build query string from params object\n *\n * Converts an object to a query string with a leading '?'.\n * Undefined and null values are omitted from the output.\n * Returns an empty string if no valid parameters are provided.\n *\n * @param params - Object with query parameters\n * @returns Query string with leading '?' or empty string\n *\n * @example\n * ```ts\n * buildQueryString({ page: 1, limit: 10, active: true })\n * // Returns: \"?page=1&limit=10&active=true\"\n *\n * buildQueryString({})\n * // Returns: \"\"\n *\n * buildQueryString({ search: 'test query', page: 1 })\n * // Returns: \"?search=test+query&page=1\"\n * ```\n *\n * @since 1.0.0\n */\nexport function buildQueryString(\n  params: Record<string, string | number | boolean>\n): string {\n  const searchParams = new URLSearchParams();\n\n  for (const [key, value] of Object.entries(params)) {\n    if (value !== undefined && value !== null) {\n      searchParams.append(key, String(value));\n    }\n  }\n\n  const queryString = searchParams.toString();\n  return queryString ? `?${queryString}` : '';\n}\n\n","import { ApiClientConfig, RequestOptions, HttpMethod } from './types';\nimport { HttpError, NetworkError, TimeoutError, ValidationError } from './errors';\nimport { serializeFormData, buildQueryString } from './utils/serialize';\n\n/**\n * Type-safe REST API client for browser and Node.js environments\n * \n * @example\n * ```ts\n * const client = new ApiClient({\n *   baseUrl: 'https://api.example.com',\n *   timeout: 5000\n * });\n * \n * const users = await client.get<User[]>('/users');\n * ```\n */\nexport class ApiClient {\n  private config: ApiClientConfig;\n\n  /**\n   * Creates a new API client instance\n   * @param config - Client configuration options\n   * @throws {TypeError} If baseUrl is invalid or timeout is not a positive number\n   */\n  constructor(config: ApiClientConfig) {\n    // Validate baseUrl\n    if (!config.baseUrl || typeof config.baseUrl !== 'string') {\n      throw new TypeError('baseUrl is required and must be a string');\n    }\n\n    try {\n      new URL(config.baseUrl);\n    } catch {\n      throw new TypeError('baseUrl must be a valid URL');\n    }\n\n    // Validate timeout if provided\n    if (config.timeout !== undefined) {\n      if (typeof config.timeout !== 'number' || config.timeout <= 0) {\n        throw new TypeError('timeout must be a positive number');\n      }\n    }\n\n    // Set defaults\n    this.config = {\n      timeout: 30000, // 30 seconds default\n      headers: {},\n      ...config\n    };\n  }\n\n  /**\n   * Create a new client with updated configuration\n   * @param config - Partial configuration to merge\n   * @returns New ApiClient instance with merged configuration\n   * @example\n   * ```ts\n   * const client1 = new ApiClient({ baseUrl: 'https://api.example.com' });\n   * const client2 = client1.withConfig({ timeout: 5000 });\n   * // client1 unchanged, client2 has new timeout\n   * ```\n   */\n  withConfig(config: Partial<ApiClientConfig>): ApiClient {\n    return new ApiClient({ ...this.config, ...config });\n  }\n\n  /**\n   * Make a GET request\n   * @param url - Request URL (relative to baseUrl)\n   * @param options - Optional request configuration\n   * @returns Promise resolving to typed response data\n   * @example\n   * ```ts\n   * const users = await client.get<User[]>('/users', {\n   *   params: { page: 1, limit: 10 }\n   * });\n   * ```\n   */\n  async get<T>(\n    url: string, \n    options?: RequestOptions\n  ): Promise<T> {\n    return this.request<T>('GET', url, undefined, options);\n  }\n\n  /**\n   * Make a POST request\n   * @param url - Request URL (relative to baseUrl)\n   * @param data - Request body data\n   * @param options - Optional request configuration\n   * @returns Promise resolving to typed response data\n   * @example\n   * ```ts\n   * const user = await client.post<User>('/users', {\n   *   name: 'John Doe',\n   *   email: 'john@example.com'\n   * });\n   * ```\n   */\n  async post<T>(\n    url: string, \n    data?: unknown, \n    options?: RequestOptions\n  ): Promise<T> {\n    return this.request<T>('POST', url, data, options);\n  }\n\n  /**\n   * Core request method with retry logic\n   */\n  private async request<T>(\n    method: HttpMethod,\n    url: string,\n    data?: unknown,\n    options?: RequestOptions\n  ): Promise<T> {\n    const maxRetries = 3;\n    let lastError: Error;\n\n    for (let attempt = 0; attempt <= maxRetries; attempt++) {\n      try {\n        return await this.executeRequest<T>(method, url, data, options);\n      } catch (error) {\n        lastError = error as Error;\n        \n        // Only retry network errors\n        if (error instanceof NetworkError && attempt < maxRetries) {\n          const delay = Math.pow(2, attempt) * 1000; // Exponential backoff: 1s, 2s, 4s\n          await new Promise(resolve => setTimeout(resolve, delay));\n          continue;\n        }\n        \n        throw error;\n      }\n    }\n\n    throw lastError!;\n  }\n\n  /**\n   * Execute a single request\n   */\n  private async executeRequest<T>(\n    method: HttpMethod,\n    url: string,\n    data?: unknown,\n    options?: RequestOptions\n  ): Promise<T> {\n    // Build full URL\n    const fullUrl = this.buildUrl(url, options?.params);\n    \n    // Determine content type\n    const contentType = options?.contentType ?? 'json';\n    \n    // Build headers\n    const headers = this.buildHeaders(contentType, options?.headers);\n    \n    // Serialize body based on content type\n    const body = this.serializeBody(data, contentType);\n\n    // Setup timeout\n    const controller = new AbortController();\n    const timeoutMs = options?.timeout ?? this.config.timeout ?? 30000;\n    const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n\n    try {\n      const response = await fetch(fullUrl, {\n        method,\n        headers,\n        body,\n        signal: options?.signal ?? controller.signal\n      });\n\n      clearTimeout(timeoutId);\n\n      // Handle HTTP errors\n      if (!response.ok) {\n        const errorData = await this.parseResponse(response);\n        throw new HttpError(\n          `HTTP ${response.status}: ${response.statusText}`,\n          response.status,\n          response.statusText,\n          errorData\n        );\n      }\n\n      // Parse and return response\n      return await this.parseResponse(response);\n    } catch (error) {\n      clearTimeout(timeoutId);\n\n      // Re-throw known errors\n      if (error instanceof HttpError) {\n        throw error;\n      }\n\n      if (error instanceof ValidationError) {\n        throw error;\n      }\n\n      // Handle timeout\n      if (error instanceof DOMException && error.name === 'AbortError') {\n        throw new TimeoutError(`Request timeout after ${timeoutMs}ms`);\n      }\n\n      // Handle network errors\n      throw new NetworkError('Network request failed', error);\n    }\n  }\n\n  /**\n   * Build full URL with query parameters\n   */\n  private buildUrl(path: string, params?: Record<string, any>): string {\n    const base = this.config.baseUrl.replace(/\\/$/, '');\n    const cleanPath = path.startsWith('/') ? path : `/${path}`;\n    const fullPath = `${base}${cleanPath}`;\n    \n    if (params) {\n      return fullPath + buildQueryString(params);\n    }\n    \n    return fullPath;\n  }\n\n  /**\n   * Build request headers\n   */\n  private buildHeaders(\n    contentType: 'json' | 'form',\n    customHeaders?: Record<string, string>\n  ): Record<string, string> {\n    const headers: Record<string, string> = {\n      ...this.config.headers,\n      ...customHeaders\n    };\n\n    // Set Content-Type based on request type\n    if (contentType === 'json') {\n      headers['Content-Type'] = 'application/json';\n    } else if (contentType === 'form') {\n      headers['Content-Type'] = 'application/x-www-form-urlencoded';\n    }\n\n    return headers;\n  }\n\n  /**\n   * Serialize request body\n   */\n  private serializeBody(\n    data: unknown, \n    contentType: 'json' | 'form'\n  ): string | undefined {\n    if (!data) return undefined;\n\n    if (contentType === 'form') {\n      return serializeFormData(data as Record<string, any>);\n    }\n\n    return JSON.stringify(data);\n  }\n\n  /**\n   * Parse response body\n   */\n  private async parseResponse(response: Response): Promise<any> {\n    const contentType = response.headers.get('content-type');\n    \n    // Handle empty responses (204 No Content)\n    if (response.status === 204 || !contentType) {\n      return undefined;\n    }\n\n    // Parse JSON\n    if (contentType?.includes('application/json')) {\n      try {\n        return await response.json();\n      } catch (error) {\n        throw new ValidationError('Invalid JSON response', error);\n      }\n    }\n\n    // Default to text\n    return await response.text();\n  }\n}\n\n","/**\n * TEFAS API Client Types\n *\n * This module defines all TypeScript interfaces and types for the TEFAS client.\n * It provides strong typing for fund data, requests, and responses.\n */\n\n/**\n * Generic API response wrapper\n */\nexport interface ApiResponse<T> {\n  results: T[];\n}\n\n/**\n * Supported TEFAS fund types\n */\nexport enum FundType {\n  /** Emeklilik (Pension) funds */\n  EMK = 'EMK',\n  /** Yatırım (Investment) funds */\n  YAT = 'YAT',\n  /** Bireysel Yatırım (Individual Investment) funds */\n  BYF = 'BYF',\n  /** Gayrimenkul Yatırım (Real Estate Investment) funds */\n  GYF = 'GYF',\n  /** Girişim Sermayesi Yatırım (Venture Capital Investment) funds */\n  GSYF = 'GSYF'\n}\n\n/**\n * Input parameters for fund history retrieval\n */\nexport interface FundHistoryRequest {\n  /** Type of funds to retrieve (optional - if omitted, fetches all fund types) */\n  fundType?: FundType;\n  /** Start date in YYYY-MM-DD format */\n  startDate: string;\n  /** End date in YYYY-MM-DD format */\n  endDate: string;\n  /** Specific fund code (optional) */\n  fundCode?: string;\n}\n\n/**\n * Typed response data containing fund history information\n */\nexport interface FundHistoryResponse {\n  /** Fund identifier */\n  fundCode: string;\n  /** Human-readable fund name */\n  fundName: string;\n  /** Type of fund */\n  fundType: FundType;\n  /** Date of the data point (YYYY-MM-DD) */\n  date: string;\n  /** Fund price/NAV */\n  price: number;\n  /** Trading volume */\n  volume: number;\n  /** Total assets under management */\n  assets: number;\n}\n\n/**\n * Raw TEFAS API response structure\n * This represents the actual response format from the TEFAS API\n */\nexport interface TefasApiResponse {\n  /** Response data array */\n  data: TefasApiFundData[];\n  /** Response metadata */\n  meta?: {\n    total?: number;\n    page?: number;\n    limit?: number;\n  };\n}\n\n/**\n * Raw fund data from TEFAS API\n */\nexport interface TefasApiFundData {\n  /** Date string (timestamp) */\n  TARIH: string;\n  /** Fund code */\n  FONKODU: string;\n  /** Fund name */\n  FONUNVAN: string;\n  /** Price/NAV */\n  FIYAT: number;\n  /** Number of shares */\n  TEDPAYSAYISI: number;\n  /** Number of investors */\n  KISISAYISI: number;\n  /** Portfolio size */\n  PORTFOYBUYUKLUK: number;\n  /** Exchange bulletin price */\n  BORSABULTENFIYAT: string;\n}\n\n/**\n * TEFAS API request parameters\n */\nexport interface TefasApiRequest {\n  /** Fund type */\n  fontip: string;\n  /** Start date */\n  bastarih: string;\n  /** End date */\n  bittarih: string;\n  /** Fund code (optional) */\n  fonkod?: string;\n}\n\n/**\n * Configuration for TEFAS API client\n */\nexport interface TefasClientConfig {\n  /** TEFAS API base URL */\n  baseUrl: string;\n  /** Default timeout in milliseconds */\n  timeout: number;\n  /** Default headers */\n  headers: Record<string, string>;\n  /** Maximum retry attempts */\n  maxRetries: number;\n  /** Retry delay in milliseconds */\n  retryDelay: number;\n}\n\n/**\n * Validation result for input parameters\n */\nexport interface ValidationResult {\n  /** Whether validation passed */\n  isValid: boolean;\n  /** Error message if validation failed */\n  error?: string;\n  /** Error code for programmatic handling */\n  errorCode?: string;\n}\n\n/**\n * Date range validation result\n */\nexport interface DateRangeValidation {\n  /** Whether date range is valid */\n  isValid: boolean;\n  /** Error message if invalid */\n  error?: string;\n  /** Parsed start date */\n  startDate?: Date;\n  /** Parsed end date */\n  endDate?: Date;\n  /** Number of days in range */\n  daysInRange?: number;\n}\n\n/**\n * Result from fund search operation\n *\n * Contains basic fund identification information suitable for\n * autocomplete and selection interfaces.\n */\nexport interface SearchResult {\n  /**\n   * Fund code identifier (e.g., \"IIH\", \"TGE\")\n   *\n   * This is the 3-character code used for subsequent API calls\n   * like getFundHistory().\n   */\n  fundCode: string;\n\n  /**\n   * Full fund display name including code prefix\n   *\n   * Format: \"{CODE} - {FULL_NAME}\"\n   * Example: \"IIH - İSTANBUL PORTFÖY ÜÇÜNCÜ HİSSE SENEDİ FONU (HİSSE SENEDİ YOĞUN FON)\"\n   */\n  fundName: string;\n}\n\n/**\n * Optional configuration for fund search\n *\n * All properties are optional to provide flexible search capabilities.\n */\nexport interface SearchOptions {\n  /**\n   * Filter search results by fund type\n   *\n   * If omitted, searches across all fund types.\n   *\n   * @example\n   * { fundType: FundType.YAT } // Only search investment funds\n   */\n  fundType?: FundType;\n\n  /**\n   * Maximum number of results to return\n   *\n   * @default 10\n   * @example\n   * { limit: 5 } // Return at most 5 results\n   */\n  limit?: number;\n}\n\n/**\n * HTTP method types\n */\nexport type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n\n/**\n * API client configuration\n */\nexport interface ApiClientConfig {\n  /** Base URL for API requests */\n  baseUrl: string;\n  /** Request timeout in milliseconds */\n  timeout?: number;\n  /** Default headers for all requests */\n  headers?: Record<string, string>;\n}\n\n/**\n * Request options for API calls\n */\nexport interface RequestOptions {\n  /** Query parameters */\n  params?: Record<string, any>;\n  /** Custom headers for this request */\n  headers?: Record<string, string>;\n  /** Request timeout in milliseconds */\n  timeout?: number;\n  /** Content type for request body */\n  contentType?: 'json' | 'form';\n  /** Abort signal for request cancellation */\n  signal?: AbortSignal;\n}\n\n/**\n * Performance metrics for a fund\n */\nexport interface PerformanceMetrics {\n  /** Fund identifier */\n  fundCode: string;\n  /** Human-readable fund name */\n  fundName: string;\n  /** Type of fund */\n  fundType: FundType;\n  /** Number of data points used in calculations */\n  observations: number;\n  /** Total return over the entire period */\n  cumulativeReturn: number;\n  /** Annualized return (yearly return) */\n  annualizedReturn: number;\n  /** Annualized volatility (risk measure) */\n  annualizedVolatility: number;\n  /** Sharpe ratio (risk-adjusted return) */\n  sharpeRatio: number;\n}\n\n/**\n * Configuration options for performance metrics calculation\n */\nexport interface MetricsOptions {\n  /** Risk-free rate for Sharpe ratio calculation (default: 0) */\n  riskFreeRate?: number;\n  /** Data frequency for calculations */\n  frequency?: 'daily' | 'weekly' | 'monthly' | 'quarterly' | 'annual';\n  /** Return calculation method */\n  method?: 'simple' | 'logarithmic';\n  /** Minimum number of observations required (default: 30) */\n  minObservations?: number;\n}\n\n/**\n * Extended performance metrics including all risk-adjusted and additional metrics\n */\nexport interface ExtendedPerformanceMetrics {\n  /** Fund identifier */\n  fundCode: string;\n  /** Human-readable fund name */\n  fundName: string;\n  /** Type of fund */\n  fundType: FundType;\n  /** Number of data points used in calculations */\n  observations: number;\n  /** Total return over the entire period */\n  totalReturn: number;\n  /** Annualized return (yearly return) */\n  annualizedReturn: number;\n  /** Annualized volatility (risk measure) */\n  annualizedVolatility: number;\n  /** Sharpe ratio (risk-adjusted return) */\n  sharpeRatio: number;\n  /** Sortino ratio (downside risk-adjusted return) */\n  sortinoRatio: number;\n  /** Maximum drawdown (largest peak-to-trough decline) */\n  maximumDrawdown: number;\n  /** Calmar ratio (annualized return / max drawdown) */\n  calmarRatio: number;\n  /** Beta (market correlation) - requires benchmark data */\n  beta?: number;\n  /** Information Ratio (active return / tracking error) - requires benchmark data */\n  informationRatio?: number;\n  /** Treynor Ratio (excess return / beta) - requires benchmark data */\n  treynorRatio?: number;\n}\n\n/**\n * Metrics for a specific time period\n */\nexport interface PeriodMetrics {\n  /** Period identifier (e.g., '1M', '3M', '1Y', 'inception') */\n  period: string;\n  /** Start date of the period */\n  startDate: string;\n  /** End date of the period */\n  endDate: string;\n  /** Number of observations in this period */\n  observations: number;\n  /** Total return for this period */\n  totalReturn: number;\n  /** Benchmark total return for this period (if available) */\n  benchmarkReturn?: number;\n  /** Annualized return for this period */\n  annualizedReturn: number;\n  /** Annualized volatility for this period */\n  annualizedVolatility: number;\n  /** Sharpe ratio for this period */\n  sharpeRatio: number;\n  /** Sortino ratio for this period */\n  sortinoRatio: number;\n  /** Maximum drawdown for this period */\n  maximumDrawdown: number;\n  /** Calmar ratio for this period */\n  calmarRatio: number;\n  /** Beta for this period (if benchmark available) */\n  beta?: number;\n  /** Information Ratio for this period (if benchmark available) */\n  informationRatio?: number;\n  /** Treynor Ratio for this period (if benchmark available) */\n  treynorRatio?: number;\n}\n\n/**\n * Monthly return data for heat map visualization\n */\nexport interface MonthlyReturn {\n  /** Year (e.g., 2025) */\n  year: number;\n  /** Month (1-12, where 1 = January, 12 = December) */\n  month: number;\n  /** Monthly return as percentage (e.g., 3.3 for 3.3%) */\n  return: number;\n}\n\n/**\n * Weekly return data for heat map visualization\n */\nexport interface WeeklyReturn {\n  /** Year (e.g., 2025) */\n  year: number;\n  /** ISO week number (1-53) */\n  week: number;\n  /** Weekly return as percentage (e.g., 0.5 for 0.5%) */\n  return: number;\n}\n\n/**\n * Complete fund metrics response with all periods and summary metrics\n */\nexport interface FundMetricsResponse {\n  /** Fund identifier */\n  fundCode: string;\n  /** Human-readable fund name */\n  fundName: string;\n  /** Type of fund */\n  fundType: FundType;\n  /** Metrics calculated for different time periods */\n  periods: PeriodMetrics[];\n  /** Overall metrics from inception (if available) */\n  overall?: ExtendedPerformanceMetrics;\n  /** Monthly returns for heat map visualization */\n  monthlyReturns?: MonthlyReturn[];\n  /** Weekly returns for heat map visualization */\n  weeklyReturns?: WeeklyReturn[];\n}\n\n/**\n * Frequency to periods-per-year mapping\n */\nexport type FrequencyPeriods = {\n  daily: 252;\n  weekly: 52;\n  monthly: 12;\n  quarterly: 4;\n  annual: 1;\n};\n\n/**\n * Input parameters for fund allocation/portfolio composition retrieval\n */\nexport interface FundContentRequest {\n  /** Type of funds to retrieve (optional - if omitted, fetches all fund types) */\n  fundType?: FundType;\n  /** Start date in YYYY-MM-DD format */\n  startDate: string;\n  /** End date in YYYY-MM-DD format */\n  endDate: string;\n  /** Specific fund code (optional) */\n  fundCode?: string;\n}\n\n/**\n * Typed response data containing fund allocation/portfolio composition information\n */\nexport interface FundContentResponse {\n  /** Fund identifier */\n  fundCode: string;\n  /** Human-readable fund name */\n  fundName: string;\n  /** Type of fund */\n  fundType: FundType;\n  /** Date of the data point (YYYY-MM-DD) */\n  date: string;\n  /** Total fund value */\n  totalValue: number;\n\n  // Stock allocations\n  /** Percentage of stocks (HS) */\n  stocks?: number;\n  /** Percentage of foreign securities (YYF) */\n  foreignSecurities?: number;\n  /** Percentage of stock-based funds (HB) */\n  stockBasedFunds?: number;\n  /** Percentage of stock-based investment funds (YHS) */\n  stockBasedInvestmentFunds?: number;\n\n  // Bond allocations\n  /** Percentage of bonds (BB) */\n  bonds?: number;\n  /** Percentage of government bonds (DB) */\n  governmentBonds?: number;\n  /** Percentage of private sector bonds (ÖSDB) */\n  privateSectorBonds?: number;\n  /** Percentage of government securities (GSYKB) */\n  governmentSecurities?: number;\n  /** Percentage of government securities yield (GSYY) */\n  governmentSecuritiesYield?: number;\n  /** Percentage of government yield bonds (GYKB) */\n  governmentYieldBonds?: number;\n  /** Percentage of government yield (GYY) */\n  governmentYield?: number;\n\n  // Deposit and cash allocations\n  /** Percentage of deposits (D) */\n  deposits?: number;\n  /** Percentage of reverse purchase agreements (T) */\n  reversePurchaseAgreements?: number;\n  /** Percentage of precious metals (KM) */\n  preciousMetals?: number;\n  /** Percentage of cash and cash equivalents (OSKS) */\n  cashAndCashEquivalents?: number;\n  /** Percentage of other securities (OSKSYD) */\n  otherSecurities?: number;\n  /** Percentage of other securities yield (ÖKSYD) */\n  otherSecuritiesYield?: number;\n\n  // Treasury and government instruments\n  /** Percentage of treasury bills (BPP) */\n  treasuryBills?: number;\n  /** Percentage of individual investment funds (BYF) */\n  individualInvestmentFunds?: number;\n  /** Percentage of government debt instruments (DT) */\n  governmentDebtInstruments?: number;\n  /** Percentage of government debt instruments foreign (DÖT) */\n  governmentDebtInstrumentsForeign?: number;\n  /** Percentage of eurobonds (EUT) */\n  eurobonds?: number;\n  /** Percentage of foreign bonds (FB) */\n  foreignBonds?: number;\n  /** Percentage of foreign currency bonds (FKB) */\n  foreignCurrencyBonds?: number;\n  /** Percentage of gold and silver (GAS) */\n  goldAndSilver?: number;\n\n  // Participation accounts and certificates\n  /** Percentage of participation accounts (KBA) */\n  participationAccounts?: number;\n  /** Percentage of participation accounts gold (KH) */\n  participationAccountsGold?: number;\n  /** Percentage of participation accounts gold foreign (KHAU) */\n  participationAccountsGoldForeign?: number;\n  /** Percentage of participation accounts foreign currency (KHD) */\n  participationAccountsForeignCurrency?: number;\n  /** Percentage of participation accounts Turkish Lira (KHTL) */\n  participationAccountsTurkishLira?: number;\n  /** Percentage of public lease certificates (KKS) */\n  publicLeaseCertificates?: number;\n  /** Percentage of public lease certificates foreign currency (KKSD) */\n  publicLeaseCertificatesForeignCurrency?: number;\n  /** Percentage of public lease certificates Turkish Lira (KKSTL) */\n  publicLeaseCertificatesTurkishLira?: number;\n  /** Percentage of public lease certificates foreign (KKSYD) */\n  publicLeaseCertificatesForeign?: number;\n  /** Percentage of participation accounts foreign currency (KİBD) */\n  participationAccountsForeignCurrencyBonds?: number;\n\n  // Other instruments\n  /** Percentage of other securities Turkish Lira (OST) */\n  otherSecuritiesTurkishLira?: number;\n  /** Percentage of repo transactions (R) */\n  repoTransactions?: number;\n  /** Percentage of term deposits (TPP) */\n  termDeposits?: number;\n  /** Percentage of treasury bills (TR) */\n  treasuryBillsShort?: number;\n  /** Percentage of variable rate deposits (VDM) */\n  variableRateDeposits?: number;\n  /** Percentage of money market instruments (VM) */\n  moneyMarketInstruments?: number;\n  /** Percentage of money market instruments gold (VMAU) */\n  moneyMarketInstrumentsGold?: number;\n  /** Percentage of money market instruments foreign currency (VMD) */\n  moneyMarketInstrumentsForeignCurrency?: number;\n  /** Percentage of money market instruments Turkish Lira (VMTL) */\n  moneyMarketInstrumentsTurkishLira?: number;\n  /** Percentage of variable income instruments (VİNT) */\n  variableIncomeInstruments?: number;\n\n  // Investment fund participations\n  /** Percentage of investment fund participations (YBA) */\n  investmentFundParticipations?: number;\n  /** Percentage of investment fund participations bonds (YBKB) */\n  investmentFundParticipationsBonds?: number;\n  /** Percentage of investment fund participations other securities (YBOSB) */\n  investmentFundParticipationsOtherSecurities?: number;\n  /** Percentage of investment fund participations foreign currency (YBYF) */\n  investmentFundParticipationsForeignCurrency?: number;\n  /** Percentage of investment fund participations metals (YMK) */\n  investmentFundParticipationsMetals?: number;\n\n  // Precious metals and derivatives\n  /** Percentage of precious metals investment funds (KMBYF) */\n  preciousMetalsInvestmentFunds?: number;\n  /** Percentage of precious metals government debt instruments (KMKBA) */\n  preciousMetalsGovernmentDebtInstruments?: number;\n  /** Percentage of precious metals public lease certificates (KMKKS) */\n  preciousMetalsPublicLeaseCertificates?: number;\n}\n\n/**\n * Merged fund data combining history and content information\n *\n * This interface combines all fields from both FundHistoryResponse and FundContentResponse\n * to provide a unified view of fund data. Fields from either source may be null if\n * the corresponding data is not available for that fund/date combination.\n */\nexport interface FundResponse {\n  /** Fund identifier */\n  fundCode: string;\n  /** Human-readable fund name */\n  fundName: string;\n  /** Type of fund */\n  fundType: FundType;\n  /** Date of the data point (YYYY-MM-DD) */\n  date: string;\n\n  // History data fields (from FundHistoryResponse)\n  /** Fund price/NAV (null if not available) */\n  price: number | null;\n  /** Trading volume (null if not available) */\n  volume: number | null;\n  /** Total assets under management (null if not available) */\n  assets: number | null;\n\n  // Content data fields (from FundContentResponse)\n  /** Total fund value (null if not available) */\n  totalValue: number | null;\n\n  // Stock allocations\n  /** Percentage of stocks (HS) (null if not available) */\n  stocks?: number | null;\n  /** Percentage of foreign securities (YYF) (null if not available) */\n  foreignSecurities?: number | null;\n  /** Percentage of stock-based funds (HB) (null if not available) */\n  stockBasedFunds?: number | null;\n  /** Percentage of stock-based investment funds (YHS) (null if not available) */\n  stockBasedInvestmentFunds?: number | null;\n\n  // Bond allocations\n  /** Percentage of bonds (BB) (null if not available) */\n  bonds?: number | null;\n  /** Percentage of government bonds (DB) (null if not available) */\n  governmentBonds?: number | null;\n  /** Percentage of private sector bonds (ÖSDB) (null if not available) */\n  privateSectorBonds?: number | null;\n  /** Percentage of government securities (GSYKB) (null if not available) */\n  governmentSecurities?: number | null;\n  /** Percentage of government securities yield (GSYY) (null if not available) */\n  governmentSecuritiesYield?: number | null;\n  /** Percentage of government yield bonds (GYKB) (null if not available) */\n  governmentYieldBonds?: number | null;\n  /** Percentage of government yield (GYY) (null if not available) */\n  governmentYield?: number | null;\n\n  // Deposit and cash allocations\n  /** Percentage of deposits (D) (null if not available) */\n  deposits?: number | null;\n  /** Percentage of reverse purchase agreements (T) (null if not available) */\n  reversePurchaseAgreements?: number | null;\n  /** Percentage of precious metals (KM) (null if not available) */\n  preciousMetals?: number | null;\n  /** Percentage of cash and cash equivalents (OSKS) (null if not available) */\n  cashAndCashEquivalents?: number | null;\n  /** Percentage of other securities (OSKSYD) (null if not available) */\n  otherSecurities?: number | null;\n  /** Percentage of other securities yield (ÖKSYD) (null if not available) */\n  otherSecuritiesYield?: number | null;\n\n  // Treasury and government instruments\n  /** Percentage of treasury bills (BPP) (null if not available) */\n  treasuryBills?: number | null;\n  /** Percentage of individual investment funds (BYF) (null if not available) */\n  individualInvestmentFunds?: number | null;\n  /** Percentage of government debt instruments (DT) (null if not available) */\n  governmentDebtInstruments?: number | null;\n  /** Percentage of government debt instruments foreign (DÖT) (null if not available) */\n  governmentDebtInstrumentsForeign?: number | null;\n  /** Percentage of eurobonds (EUT) (null if not available) */\n  eurobonds?: number | null;\n  /** Percentage of foreign bonds (FB) (null if not available) */\n  foreignBonds?: number | null;\n  /** Percentage of foreign currency bonds (FKB) (null if not available) */\n  foreignCurrencyBonds?: number | null;\n  /** Percentage of gold and silver (GAS) (null if not available) */\n  goldAndSilver?: number | null;\n\n  // Participation accounts and certificates\n  /** Percentage of participation accounts (KBA) (null if not available) */\n  participationAccounts?: number | null;\n  /** Percentage of participation accounts gold (KH) (null if not available) */\n  participationAccountsGold?: number | null;\n  /** Percentage of participation accounts gold foreign (KHAU) (null if not available) */\n  participationAccountsGoldForeign?: number | null;\n  /** Percentage of participation accounts foreign currency (KHD) (null if not available) */\n  participationAccountsForeignCurrency?: number | null;\n  /** Percentage of participation accounts Turkish Lira (KHTL) (null if not available) */\n  participationAccountsTurkishLira?: number | null;\n  /** Percentage of public lease certificates (KKS) (null if not available) */\n  publicLeaseCertificates?: number | null;\n  /** Percentage of public lease certificates foreign currency (KKSD) (null if not available) */\n  publicLeaseCertificatesForeignCurrency?: number | null;\n  /** Percentage of public lease certificates Turkish Lira (KKSTL) (null if not available) */\n  publicLeaseCertificatesTurkishLira?: number | null;\n  /** Percentage of public lease certificates foreign (KKSYD) (null if not available) */\n  publicLeaseCertificatesForeign?: number | null;\n  /** Percentage of participation accounts foreign currency (KİBD) (null if not available) */\n  participationAccountsForeignCurrencyBonds?: number | null;\n\n  // Other instruments\n  /** Percentage of other securities Turkish Lira (OST) (null if not available) */\n  otherSecuritiesTurkishLira?: number | null;\n  /** Percentage of repo transactions (R) (null if not available) */\n  repoTransactions?: number | null;\n  /** Percentage of term deposits (TPP) (null if not available) */\n  termDeposits?: number | null;\n  /** Percentage of treasury bills (TR) (null if not available) */\n  treasuryBillsShort?: number | null;\n  /** Percentage of variable rate deposits (VDM) (null if not available) */\n  variableRateDeposits?: number | null;\n  /** Percentage of money market instruments (VM) (null if not available) */\n  moneyMarketInstruments?: number | null;\n  /** Percentage of money market instruments gold (VMAU) (null if not available) */\n  moneyMarketInstrumentsGold?: number | null;\n  /** Percentage of money market instruments foreign currency (VMD) (null if not available) */\n  moneyMarketInstrumentsForeignCurrency?: number | null;\n  /** Percentage of money market instruments Turkish Lira (VMTL) (null if not available) */\n  moneyMarketInstrumentsTurkishLira?: number | null;\n  /** Percentage of variable income instruments (VİNT) (null if not available) */\n  variableIncomeInstruments?: number | null;\n\n  // Investment fund participations\n  /** Percentage of investment fund participations (YBA) (null if not available) */\n  investmentFundParticipations?: number | null;\n  /** Percentage of investment fund participations bonds (YBKB) (null if not available) */\n  investmentFundParticipationsBonds?: number | null;\n  /** Percentage of investment fund participations other securities (YBOSB) (null if not available) */\n  investmentFundParticipationsOtherSecurities?: number | null;\n  /** Percentage of investment fund participations foreign currency (YBYF) (null if not available) */\n  investmentFundParticipationsForeignCurrency?: number | null;\n  /** Percentage of investment fund participations metals (YMK) (null if not available) */\n  investmentFundParticipationsMetals?: number | null;\n\n  // Precious metals and derivatives\n  /** Percentage of precious metals investment funds (KMBYF) (null if not available) */\n  preciousMetalsInvestmentFunds?: number | null;\n  /** Percentage of precious metals government debt instruments (KMKBA) (null if not available) */\n  preciousMetalsGovernmentDebtInstruments?: number | null;\n  /** Percentage of precious metals public lease certificates (KMKKS) (null if not available) */\n  preciousMetalsPublicLeaseCertificates?: number | null;\n}\n\n/**\n * Raw TEFAS allocation API response structure\n * This represents the actual response format from the TEFAS allocation API\n */\nexport interface TefasAllocationApiResponse {\n  /** Response data array */\n  data: TefasAllocationData[];\n  /** Response metadata */\n  draw?: number;\n  recordsTotal?: number;\n  recordsFiltered?: number;\n}\n\n/**\n * Raw allocation data from TEFAS API\n */\nexport interface TefasAllocationData {\n  /** Date string (timestamp in milliseconds) */\n  TARIH: string;\n  /** Fund code */\n  FONKODU: string;\n  /** Fund name */\n  FONUNVAN: string;\n  /** Total fund value (comma-formatted string) */\n  BilFiyat: string;\n\n  // Allocation percentages (all nullable)\n  BB?: number;\n  BPP?: number;\n  BYF?: number;\n  D?: number;\n  DB?: number;\n  DT?: number;\n  DÖT?: number;\n  EUT?: number;\n  FB?: number;\n  FKB?: number;\n  GAS?: number;\n  GSYKB?: number;\n  GSYY?: number;\n  GYKB?: number;\n  GYY?: number;\n  HB?: number;\n  HS?: number;\n  KBA?: number;\n  KH?: number;\n  KHAU?: number;\n  KHD?: number;\n  KHTL?: number;\n  KKS?: number;\n  KKSD?: number;\n  KKSTL?: number;\n  KKSYD?: number;\n  KM?: number;\n  KMBYF?: number;\n  KMKBA?: number;\n  KMKKS?: number;\n  KİBD?: number;\n  OSKS?: number;\n  OSKSYD?: number;\n  OST?: number;\n  R?: number;\n  T?: number;\n  TPP?: number;\n  TR?: number;\n  VDM?: number;\n  VM?: number;\n  VMAU?: number;\n  VMD?: number;\n  VMTL?: number;\n  VİNT?: number;\n  YBA?: number;\n  YBKB?: number;\n  YBOSB?: number;\n  YBYF?: number;\n  YHS?: number;\n  YMK?: number;\n  YYF?: number;\n  ÖKSYD?: number;\n  ÖSDB?: number;\n}\n","/**\n * Fund Type Validation Utilities\n * \n * This module provides utilities for fund type validation and management\n * for TEFAS API requests.\n */\n\nimport { FundType } from '../types';\nimport { InvalidFundTypeError } from '../errors';\n\n/**\n * Array of all supported fund types\n */\nexport const SUPPORTED_FUND_TYPES: readonly FundType[] = [\n  FundType.EMK,\n  FundType.YAT,\n  FundType.BYF,\n  FundType.GYF,\n  FundType.GSYF\n] as const;\n\n/**\n * Fund type descriptions for user-friendly error messages\n */\nexport const FUND_TYPE_DESCRIPTIONS: Record<FundType, string> = {\n  [FundType.EMK]: 'Emeklilik (Pension) funds',\n  [FundType.YAT]: 'Yatırım (Investment) funds',\n  [FundType.BYF]: 'Bireysel Yatırım (Individual Investment) funds',\n  [FundType.GYF]: 'Gayrimenkul Yatırım (Real Estate Investment) funds',\n  [FundType.GSYF]: 'Girişim Sermayesi Yatırım (Venture Capital Investment) funds'\n};\n\n/**\n * Validates if a value is a valid fund type\n * \n * @param value - Value to validate\n * @returns True if valid fund type, false otherwise\n */\nexport function isValidFundType(value: unknown): value is FundType {\n  return typeof value === 'string' && SUPPORTED_FUND_TYPES.includes(value as FundType);\n}\n\n/**\n * Validates a fund type and throws an error if invalid\n * \n * @param fundType - Fund type to validate\n * @throws InvalidFundTypeError if fund type is invalid\n */\nexport function validateFundType(fundType: unknown): asserts fundType is FundType {\n  if (!fundType || typeof fundType !== 'string') {\n    throw new InvalidFundTypeError(String(fundType));\n  }\n\n  if (!isValidFundType(fundType)) {\n    throw new InvalidFundTypeError(fundType);\n  }\n}\n\n/**\n * Gets all supported fund types\n * \n * @returns Array of supported fund types\n */\nexport function getSupportedFundTypes(): readonly FundType[] {\n  return SUPPORTED_FUND_TYPES;\n}\n\n/**\n * Gets fund type description\n * \n * @param fundType - Fund type to get description for\n * @returns Human-readable description of the fund type\n */\nexport function getFundTypeDescription(fundType: FundType): string {\n  return FUND_TYPE_DESCRIPTIONS[fundType];\n}\n\n/**\n * Gets all fund type descriptions\n * \n * @returns Object mapping fund types to their descriptions\n */\nexport function getAllFundTypeDescriptions(): Record<FundType, string> {\n  return { ...FUND_TYPE_DESCRIPTIONS };\n}\n\n/**\n * Converts a fund type to its TEFAS API representation\n * \n * @param fundType - Fund type to convert\n * @returns TEFAS API fund type string\n */\nexport function toTefasApiFundType(fundType: FundType): string {\n  // TEFAS API uses the same fund type codes\n  return fundType;\n}\n\n/**\n * Converts a TEFAS API fund type to our FundType enum\n * \n * @param apiFundType - TEFAS API fund type string\n * @returns FundType enum value\n * @throws InvalidFundTypeError if API fund type is not supported\n */\nexport function fromTefasApiFundType(apiFundType: string): FundType {\n  if (!isValidFundType(apiFundType)) {\n    throw new InvalidFundTypeError(apiFundType);\n  }\n  return apiFundType as FundType;\n}\n\n/**\n * Checks if a fund type is supported\n * \n * @param fundType - Fund type to check\n * @returns True if supported, false otherwise\n */\nexport function isSupportedFundType(fundType: string): boolean {\n  return isValidFundType(fundType);\n}\n\n/**\n * Gets fund type validation error message\n * \n * @param fundType - Invalid fund type\n * @returns User-friendly error message\n */\nexport function getFundTypeValidationError(fundType: string): string {\n  const supportedTypes = SUPPORTED_FUND_TYPES.join(', ');\n  return `Invalid fund type '${fundType}'. Supported types are: ${supportedTypes}`;\n}\n\n/**\n * Normalizes fund type string (uppercase, trimmed)\n * \n * @param fundType - Fund type string to normalize\n * @returns Normalized fund type string\n */\nexport function normalizeFundType(fundType: string): string {\n  return fundType.trim().toUpperCase();\n}\n\n/**\n * Validates and normalizes a fund type\n * \n * @param fundType - Fund type to validate and normalize\n * @returns Normalized fund type\n * @throws InvalidFundTypeError if fund type is invalid\n */\nexport function validateAndNormalizeFundType(fundType: string): FundType {\n  const normalized = normalizeFundType(fundType);\n  validateFundType(normalized);\n  return normalized as FundType;\n}\n\n/**\n * Gets fund type display name for UI purposes\n * \n * @param fundType - Fund type to get display name for\n * @returns Display name for the fund type\n */\nexport function getFundTypeDisplayName(fundType: FundType): string {\n  const descriptions = {\n    [FundType.EMK]: 'Pension Funds',\n    [FundType.YAT]: 'Investment Funds',\n    [FundType.BYF]: 'Individual Investment Funds',\n    [FundType.GYF]: 'Real Estate Investment Funds',\n    [FundType.GSYF]: 'Venture Capital Investment Funds'\n  };\n  \n  return descriptions[fundType];\n}\n\n/**\n * Gets fund type category for grouping purposes\n * \n * @param fundType - Fund type to get category for\n * @returns Category of the fund type\n */\nexport function getFundTypeCategory(fundType: FundType): string {\n  const categories = {\n    [FundType.EMK]: 'Retirement',\n    [FundType.YAT]: 'Investment',\n    [FundType.BYF]: 'Individual',\n    [FundType.GYF]: 'Real Estate',\n    [FundType.GSYF]: 'Venture Capital'\n  };\n  \n  return categories[fundType];\n}\n","/**\n * Date Validation Utilities\n * \n * This module provides utilities for date format validation and range checking\n * for TEFAS API requests.\n */\n\nimport { InvalidDateError, DateRangeError } from '../errors';\nimport { type DateRangeValidation } from '../types';\nimport * as chrono from 'chrono-node';\n\n/**\n * ISO 8601 date format regex (YYYY-MM-DD)\n */\nconst ISO_DATE_REGEX = /^\\d{4}-\\d{2}-\\d{2}$/;\n\n/**\n * Validates if a date string is in ISO 8601 format (YYYY-MM-DD)\n * \n * @param date - Date string to validate\n * @returns True if valid, false otherwise\n */\nexport function isValidDateFormat(date: string): boolean {\n  if (!ISO_DATE_REGEX.test(date)) {\n    return false;\n  }\n\n  // Check if the date is actually valid\n  const parsedDate = new Date(date);\n  return !isNaN(parsedDate.getTime()) && parsedDate.toISOString().split('T')[0] === date;\n}\n\n/**\n * Validates a date string and throws an error if invalid\n * \n * @param date - Date string to validate\n * @param fieldName - Name of the field for error messages\n * @throws InvalidDateError if date is invalid\n */\nexport function validateDate(date: string, fieldName: string = 'date'): void {\n  if (!date || typeof date !== 'string') {\n    throw new InvalidDateError(date, `${fieldName} must be a non-empty string`);\n  }\n\n  if (!ISO_DATE_REGEX.test(date)) {\n    throw new InvalidDateError(date, `${fieldName} must be in YYYY-MM-DD format`);\n  }\n\n  const parsedDate = new Date(date);\n  if (isNaN(parsedDate.getTime())) {\n    throw new InvalidDateError(date, `${fieldName} is not a valid date`);\n  }\n\n  // Check if the parsed date matches the input string (prevents dates like 2024-02-30)\n  if (parsedDate.toISOString().split('T')[0] !== date) {\n    throw new InvalidDateError(date, `${fieldName} is not a valid date`);\n  }\n}\n\n/**\n * Parses a date string to a Date object\n * \n * @param date - Date string in YYYY-MM-DD format\n * @returns Parsed Date object\n * @throws InvalidDateError if date is invalid\n */\nexport function parseDate(date: string): Date {\n  validateDate(date);\n  return new Date(date);\n}\n\n/**\n * Formats a date to YYYY-MM-DD string\n * \n * @param date - Date object to format\n * @returns Formatted date string\n */\nexport function formatDate(date: Date): string {\n  return date.toISOString().split('T')[0];\n}\n\n/**\n * Gets the current date in YYYY-MM-DD format\n * \n * @returns Current date string\n */\nexport function getCurrentDate(): string {\n  return formatDate(new Date());\n}\n\n/**\n * Adds days to a date\n * \n * @param date - Date string in YYYY-MM-DD format\n * @param days - Number of days to add (can be negative)\n * @returns New date string in YYYY-MM-DD format\n */\nexport function addDays(date: string, days: number): string {\n  const parsedDate = parseDate(date);\n  const newDate = new Date(parsedDate);\n  newDate.setDate(newDate.getDate() + days);\n  return formatDate(newDate);\n}\n\n/**\n * Calculates the number of days between two dates\n * \n * @param startDate - Start date string\n * @param endDate - End date string\n * @returns Number of days between dates\n */\nexport function getDaysBetween(startDate: string, endDate: string): number {\n  const start = parseDate(startDate);\n  const end = parseDate(endDate);\n  return Math.ceil((end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24));\n}\n\n/**\n * Checks if a date is in the past\n * \n * @param date - Date string to check\n * @returns True if date is in the past\n */\nexport function isPastDate(date: string): boolean {\n  const parsedDate = parseDate(date);\n  const today = new Date();\n  today.setHours(0, 0, 0, 0); // Reset time to start of day\n  return parsedDate < today;\n}\n\n/**\n * Checks if a date is in the future\n * \n * @param date - Date string to check\n * @returns True if date is in the future\n */\nexport function isFutureDate(date: string): boolean {\n  const parsedDate = parseDate(date);\n  const today = new Date();\n  today.setHours(23, 59, 59, 999); // Set time to end of day\n  return parsedDate > today;\n}\n\n/**\n * Validates a date range and throws an error if invalid\n * \n * @param startDate - Start date string in YYYY-MM-DD format\n * @param endDate - End date string in YYYY-MM-DD format\n * @param maxDays - Maximum allowed days in range (optional, no limit if not provided)\n * @throws InvalidDateError if either date format is invalid\n * @throws DateRangeError if date range is invalid\n */\nexport function validateDateRange(startDate: string, endDate: string, maxDays?: number): void {\n  // First validate individual dates\n  validateDate(startDate, 'start date');\n  validateDate(endDate, 'end date');\n\n  // Parse dates for comparison\n  const start = parseDate(startDate);\n  const end = parseDate(endDate);\n\n  // Check if start date is after end date\n  if (start > end) {\n    throw new DateRangeError(startDate, endDate, 'Start date must be before end date');\n  }\n\n  // Check if date range exceeds maximum allowed days (only if maxDays is provided)\n  if (maxDays !== undefined) {\n    const daysBetween = getDaysBetween(startDate, endDate);\n    if (daysBetween > maxDays) {\n      throw new DateRangeError(startDate, endDate, `Date range cannot exceed ${maxDays} days`);\n    }\n  }\n}\n\n/**\n * Converts a date from YYYY-MM-DD format to DD.MM.YYYY format for TEFAS API\n * \n * @param date - Date string in YYYY-MM-DD format\n * @returns Date string in DD.MM.YYYY format\n * @throws InvalidDateError if date is invalid\n */\nexport function convertToTefasDateFormat(date: string): string {\n  validateDate(date);\n  const [year, month, day] = date.split('-');\n  return `${day}.${month}.${year}`;\n}\n\n/**\n * Parses a fuzzy date string (e.g., \"today\", \"yesterday\", \"2024-01-01\") to a normalized YYYY-MM-DD format\n * \n * @param dateInput - Fuzzy date string (e.g., \"today\", \"yesterday\", \"2024-01-01\", \"last week\")\n * @param referenceDate - Optional reference date for relative date parsing (defaults to current date)\n * @returns Normalized date string in YYYY-MM-DD format\n * @throws InvalidDateError if date cannot be parsed\n * \n * @example\n * ```typescript\n * parseFuzzyDate('today'); // Returns current date in YYYY-MM-DD format\n * parseFuzzyDate('yesterday'); // Returns yesterday's date in YYYY-MM-DD format\n * parseFuzzyDate('2024-01-01'); // Returns '2024-01-01'\n * parseFuzzyDate('last week'); // Returns date from last week\n * ```\n */\nexport function parseFuzzyDate(dateInput: string, referenceDate?: Date): string {\n  if (!dateInput || typeof dateInput !== 'string') {\n    throw new InvalidDateError(dateInput, 'Date input must be a non-empty string');\n  }\n\n  const trimmedInput = dateInput.trim();\n  \n  // If it's already in YYYY-MM-DD format, validate and return as-is\n  if (ISO_DATE_REGEX.test(trimmedInput)) {\n    validateDate(trimmedInput);\n    return trimmedInput;\n  }\n\n  // Use chrono to parse fuzzy dates\n  const refDate = referenceDate || new Date();\n  const parsedResult = chrono.parseDate(trimmedInput, refDate);\n\n  if (!parsedResult) {\n    throw new InvalidDateError(dateInput, `Unable to parse date: \"${dateInput}\". Supported formats include: \"today\", \"yesterday\", \"2024-01-01\", \"last week\", etc.`);\n  }\n\n  // Convert to YYYY-MM-DD format\n  return formatDate(parsedResult);\n}\n\n/**\n * Validates and normalizes fuzzy date inputs for TEFAS API\n * \n * @param startDate - Start date (fuzzy or YYYY-MM-DD format)\n * @param endDate - End date (fuzzy or YYYY-MM-DD format)\n * @param maxDays - Maximum allowed days in range (optional, no limit if not provided)\n * @returns Object containing normalized start and end dates\n * @throws InvalidDateError if either date cannot be parsed\n * @throws DateRangeError if date range is invalid\n * \n * @example\n * ```typescript\n * const { startDate, endDate } = normalizeFuzzyDateRange('today', 'yesterday');\n * // Throws DateRangeError because start > end\n * \n * const { startDate, endDate } = normalizeFuzzyDateRange('yesterday', 'today');\n * // Returns normalized dates\n * ```\n */\nexport function normalizeFuzzyDateRange(\n  startDate: string, \n  endDate: string, \n  maxDays?: number\n): { startDate: string; endDate: string } {\n  // Parse fuzzy dates to normalized format\n  const normalizedStartDate = parseFuzzyDate(startDate);\n  const normalizedEndDate = parseFuzzyDate(endDate);\n\n  // Validate the date range\n  validateDateRange(normalizedStartDate, normalizedEndDate, maxDays);\n\n  return {\n    startDate: normalizedStartDate,\n    endDate: normalizedEndDate\n  };\n}\n","/**\n * Response Mapping Utilities\n * \n * This module provides utilities for mapping TEFAS API responses to typed responses\n * and validating response data.\n */\n\nimport { \n  FundHistoryResponse, \n  TefasApiResponse, \n  TefasApiFundData, \n  FundType\n} from '../types';\nimport { ResponseValidationError } from '../errors';\nimport { fromTefasApiFundType } from './fund-type-validation';\n\n/**\n * Maps a single TEFAS API fund data item to our typed response\n * \n * @param apiData - Raw fund data from TEFAS API\n * @returns Mapped fund history response\n * @throws ResponseValidationError if data is invalid\n */\nexport function mapTefasFundData(apiData: TefasApiFundData): FundHistoryResponse {\n  try {\n    // Validate required fields\n    if (!apiData.FONKODU || typeof apiData.FONKODU !== 'string') {\n      throw new ResponseValidationError('Missing or invalid fund code');\n    }\n\n    if (!apiData.FONUNVAN || typeof apiData.FONUNVAN !== 'string') {\n      throw new ResponseValidationError('Missing or invalid fund name');\n    }\n\n    if (!apiData.TARIH || typeof apiData.TARIH !== 'string') {\n      throw new ResponseValidationError('Missing or invalid date');\n    }\n\n    // Validate numeric fields\n    if (typeof apiData.FIYAT !== 'number' || apiData.FIYAT < 0) {\n      throw new ResponseValidationError('Invalid fund price');\n    }\n\n    if (typeof apiData.PORTFOYBUYUKLUK !== 'number' || apiData.PORTFOYBUYUKLUK < 0) {\n      throw new ResponseValidationError('Invalid total assets');\n    }\n\n    // Convert timestamp to date string (YYYY-MM-DD format)\n    const timestamp = parseInt(apiData.TARIH);\n    const date = new Date(timestamp);\n    const dateString = date.toISOString().split('T')[0]; // YYYY-MM-DD format\n\n    const volume = apiData.TEDPAYSAYISI || 0; // Use number of shares as volume\n\n    // Determine fund type from the API response or use a default\n    // This will be overridden by the calling function\n    const fundType = FundType.YAT; // Default, will be overridden by caller\n\n    return {\n      fundCode: apiData.FONKODU,\n      fundName: apiData.FONUNVAN,\n      fundType,\n      date: dateString,\n      price: apiData.FIYAT,\n      volume,\n      assets: apiData.PORTFOYBUYUKLUK\n    };\n  } catch (error) {\n    if (error instanceof ResponseValidationError) {\n      throw error;\n    }\n    throw new ResponseValidationError(`Failed to map fund data: ${error instanceof Error ? error.message : 'Unknown error'}`);\n  }\n}\n\n/**\n * Maps TEFAS API response to our typed response array\n * \n * @param apiResponse - Raw response from TEFAS API\n * @param fundType - Fund type from the request (used to set fund type in response)\n * @returns Array of mapped fund history responses\n * @throws ResponseValidationError if response is invalid\n */\nexport function mapTefasResponse(apiResponse: TefasApiResponse, fundType: FundType): FundHistoryResponse[] {\n  try {\n    // Validate response structure\n    if (!apiResponse || typeof apiResponse !== 'object') {\n      throw new ResponseValidationError('Invalid response structure');\n    }\n\n    if (!Array.isArray(apiResponse.data)) {\n      throw new ResponseValidationError('Response data is not an array');\n    }\n\n    // Map each fund data item\n    return apiResponse.data.map((fundData, index) => {\n      try {\n        const mappedData = mapTefasFundData(fundData);\n        // Override the fund type with the one from the request\n        mappedData.fundType = fundType;\n        return mappedData;\n      } catch (error) {\n        throw new ResponseValidationError(`Failed to map fund data at index ${index}: ${error instanceof Error ? error.message : 'Unknown error'}`);\n      }\n    });\n  } catch (error) {\n    if (error instanceof ResponseValidationError) {\n      throw error;\n    }\n    throw new ResponseValidationError(`Failed to map TEFAS response: ${error instanceof Error ? error.message : 'Unknown error'}`);\n  }\n}\n\n/**\n * Validates a single fund history response\n * \n * @param response - Fund history response to validate\n * @returns True if valid, false otherwise\n */\nexport function validateFundHistoryResponse(response: FundHistoryResponse): boolean {\n  try {\n    // Check required string fields\n    if (!response.fundCode || typeof response.fundCode !== 'string') return false;\n    if (!response.fundName || typeof response.fundName !== 'string') return false;\n    if (!response.date || typeof response.date !== 'string') return false;\n\n    // Check fund type\n    if (!Object.values(FundType).includes(response.fundType)) return false;\n\n    // Check numeric fields\n    if (typeof response.price !== 'number' || response.price < 0) return false;\n    if (typeof response.volume !== 'number' || response.volume < 0) return false;\n    if (typeof response.assets !== 'number' || response.assets < 0) return false;\n\n    // Check date format (basic validation)\n    if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(response.date)) return false;\n\n    return true;\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Validates an array of fund history responses\n * \n * @param responses - Array of fund history responses to validate\n * @returns True if all responses are valid, false otherwise\n */\nexport function validateFundHistoryResponses(responses: FundHistoryResponse[]): boolean {\n  if (!Array.isArray(responses)) return false;\n  \n  return responses.every(validateFundHistoryResponse);\n}\n\n/**\n * Filters fund history responses by fund type\n * \n * @param responses - Array of fund history responses\n * @param fundType - Fund type to filter by\n * @returns Filtered array of responses\n */\nexport function filterByFundType(responses: FundHistoryResponse[], fundType: FundType): FundHistoryResponse[] {\n  return responses.filter(response => response.fundType === fundType);\n}\n\n/**\n * Filters fund history responses by fund code\n * \n * @param responses - Array of fund history responses\n * @param fundCode - Fund code to filter by\n * @returns Filtered array of responses\n */\nexport function filterByFundCode(responses: FundHistoryResponse[], fundCode: string): FundHistoryResponse[] {\n  return responses.filter(response => response.fundCode === fundCode);\n}\n\n/**\n * Groups fund history responses by fund code\n * \n * @param responses - Array of fund history responses\n * @returns Object with fund codes as keys and arrays of responses as values\n */\nexport function groupByFundCode(responses: FundHistoryResponse[]): Record<string, FundHistoryResponse[]> {\n  return responses.reduce((groups, response) => {\n    const fundCode = response.fundCode;\n    if (!groups[fundCode]) {\n      groups[fundCode] = [];\n    }\n    groups[fundCode].push(response);\n    return groups;\n  }, {} as Record<string, FundHistoryResponse[]>);\n}\n\n/**\n * Sorts fund history responses by date (ascending)\n * \n * @param responses - Array of fund history responses\n * @returns Sorted array of responses\n */\nexport function sortByDate(responses: FundHistoryResponse[]): FundHistoryResponse[] {\n  return [...responses].sort((a, b) => a.date.localeCompare(b.date));\n}\n\n/**\n * Sorts fund history responses by date (descending)\n * \n * @param responses - Array of fund history responses\n * @returns Sorted array of responses\n */\nexport function sortByDateDescending(responses: FundHistoryResponse[]): FundHistoryResponse[] {\n  return [...responses].sort((a, b) => b.date.localeCompare(a.date));\n}\n\n/**\n * Gets unique fund codes from responses\n * \n * @param responses - Array of fund history responses\n * @returns Array of unique fund codes\n */\nexport function getUniqueFundCodes(responses: FundHistoryResponse[]): string[] {\n  const fundCodes = new Set(responses.map(response => response.fundCode));\n  return Array.from(fundCodes);\n}\n\n/**\n * Gets the latest response for each fund\n * \n * @param responses - Array of fund history responses\n * @returns Object with fund codes as keys and latest responses as values\n */\nexport function getLatestByFundCode(responses: FundHistoryResponse[]): Record<string, FundHistoryResponse> {\n  const sorted = sortByDateDescending(responses);\n  const latest: Record<string, FundHistoryResponse> = {};\n  \n  for (const response of sorted) {\n    if (!latest[response.fundCode]) {\n      latest[response.fundCode] = response;\n    }\n  }\n  \n  return latest;\n}\n\n/**\n * Calculates total assets across all funds\n * \n * @param responses - Array of fund history responses\n * @returns Total assets value\n */\nexport function calculateTotalAssets(responses: FundHistoryResponse[]): number {\n  return responses.reduce((total, response) => total + response.assets, 0);\n}\n\n/**\n * Calculates average price across all funds\n * \n * @param responses - Array of fund history responses\n * @returns Average price\n */\nexport function calculateAveragePrice(responses: FundHistoryResponse[]): number {\n  if (responses.length === 0) return 0;\n  const totalPrice = responses.reduce((total, response) => total + response.price, 0);\n  return totalPrice / responses.length;\n}\n","/**\n * Search Response Parser Utility\n *\n * Handles parsing of the nested JSON response structure from TEFAS GetAllFunds API.\n * The API returns a double-encoded JSON structure that requires special handling.\n */\n\nimport { SearchResult } from '../types';\nimport { ValidationError } from '../errors';\n\n/**\n * Raw search API response structure from TEFAS GetAllFunds endpoint\n * @internal\n */\ninterface SearchApiResponse {\n  /** Array of JSON-encoded strings */\n  d: string[];\n}\n\n/**\n * Parsed fund entry from nested JSON string\n * @internal\n */\ninterface ParsedFundEntry {\n  /** Full display name: \"{CODE} - {FULL_NAME}\" (code will be extracted and removed) */\n  First: string;\n  /** Fund code (e.g., \"IIH\") */\n  Second: string;\n}\n\n/**\n * Parse TEFAS search API response into SearchResult array\n *\n * The TEFAS GetAllFunds API returns a nested JSON structure:\n * 1. Top level has a \"d\" array property\n * 2. Each array element is a JSON-encoded string (double-encoded)\n * 3. Each string contains an object with \"First\" (display name) and \"Second\" (fund code)\n *\n * @param response - Raw API response object\n * @returns Array of SearchResult objects\n * @throws ValidationError if response structure is invalid\n *\n * @example\n * ```typescript\n * const apiResponse = {\n *   d: [\n *     '{\"First\":\"IIH - İSTANBUL PORTFÖY ÜÇÜNCÜ HİSSE SENEDİ FONU\",\"Second\":\"IIH\"}'\n *   ]\n * };\n * const results = parseSearchResponse(apiResponse);\n * // results = [{ fundCode: \"IIH\", fundName: \"İSTANBUL PORTFÖY ÜÇÜNCÜ HİSSE SENEDİ FONU\" }]\n * ```\n */\nexport function parseSearchResponse(response: unknown): SearchResult[] {\n  // Validate response structure\n  if (!response || typeof response !== 'object') {\n    throw new ValidationError('Invalid search response: response must be an object');\n  }\n\n  const apiResponse = response as SearchApiResponse;\n\n  if (!apiResponse.d || !Array.isArray(apiResponse.d)) {\n    throw new ValidationError('Invalid search response: missing or invalid \"d\" array');\n  }\n\n  // Handle empty results\n  if (apiResponse.d.length === 0) {\n    return [];\n  }\n\n  // Parse each JSON string in the array\n  const results: SearchResult[] = [];\n\n  for (let i = 0; i < apiResponse.d.length; i++) {\n    const item = apiResponse.d[i];\n\n    // Validate item is a string\n    if (typeof item !== 'string') {\n      throw new ValidationError(\n        `Invalid search response: item at index ${i} is not a string`\n      );\n    }\n\n    // Skip empty strings\n    if (item.trim().length === 0) {\n      continue;\n    }\n\n    try {\n      // Parse the nested JSON string\n      const parsed = JSON.parse(item) as ParsedFundEntry;\n\n      // Validate parsed structure\n      if (!parsed || typeof parsed !== 'object') {\n        throw new Error('Parsed item is not an object');\n      }\n\n      if (typeof parsed.First !== 'string' || typeof parsed.Second !== 'string') {\n        throw new Error('Missing or invalid First/Second properties');\n      }\n\n      // Extract full name from display format \"{CODE} - {FULL_NAME}\"\n      const fullName = parsed.First.includes(' - ') \n        ? parsed.First.split(' - ').slice(1).join(' - ') \n        : parsed.First;\n\n      // Map to SearchResult\n      results.push({\n        fundCode: parsed.Second,\n        fundName: fullName\n      });\n    } catch (error) {\n      // Provide clear error message for malformed JSON\n      const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n      throw new ValidationError(\n        `Invalid search response: failed to parse item at index ${i}: ${errorMessage}`,\n        error\n      );\n    }\n  }\n\n  return results;\n}\n\n/**\n * Validate that a search response has the expected structure\n *\n * @param response - Response to validate\n * @returns True if response has valid structure, false otherwise\n *\n * @example\n * ```typescript\n * if (isValidSearchResponse(apiResponse)) {\n *   const results = parseSearchResponse(apiResponse);\n * }\n * ```\n */\nexport function isValidSearchResponse(response: unknown): boolean {\n  try {\n    if (!response || typeof response !== 'object') {\n      return false;\n    }\n\n    const apiResponse = response as SearchApiResponse;\n\n    if (!apiResponse.d || !Array.isArray(apiResponse.d)) {\n      return false;\n    }\n\n    return true;\n  } catch {\n    return false;\n  }\n}\n","/**\n * Allocation Response Mapping Utilities\n * \n * This module provides utilities for mapping TEFAS allocation API responses\n * to clean, typed response objects with English property names.\n */\n\nimport { FundType, FundContentResponse, TefasAllocationApiResponse } from '../types';\n\n/**\n * Converts a timestamp string (milliseconds) to YYYY-MM-DD format\n * \n * @private\n * @param timestamp - Timestamp string in milliseconds\n * @returns Date string in YYYY-MM-DD format\n */\nfunction convertTimestampToDate(timestamp: string): string {\n  const date = new Date(parseInt(timestamp, 10));\n  // Handle invalid timestamps\n  if (isNaN(date.getTime())) {\n    return '1970-01-01';\n  }\n  return date.toISOString().split('T')[0];\n}\n\n/**\n * Parses a comma-formatted number string to a number\n * \n * @private\n * @param value - Comma-formatted number string (e.g., \"1,234,567.89\")\n * @returns Parsed number\n */\nfunction parseCommaFormattedNumber(value: string): number {\n  if (!value || value.trim() === '') {\n    return 0;\n  }\n  \n  // Remove commas and parse as float\n  const cleanValue = value.replace(/,/g, '');\n  return parseFloat(cleanValue) || 0;\n}\n\n/**\n * Maps TEFAS allocation API response to clean response objects\n * \n * This function converts the raw TEFAS API response format to our clean,\n * typed response format with English property names and proper data types.\n * \n * @param response - Raw TEFAS allocation API response\n * @param fundType - Fund type from the request\n * @returns Array of mapped fund content responses\n */\nexport function mapAllocationResponse(\n  response: TefasAllocationApiResponse,\n  fundType: FundType\n): FundContentResponse[] {\n  if (!response.data || !Array.isArray(response.data)) {\n    return [];\n  }\n\n  return response.data.map((item) => ({\n    fundCode: item.FONKODU,\n    fundName: item.FONUNVAN,\n    fundType,\n    date: convertTimestampToDate(item.TARIH),\n    totalValue: parseCommaFormattedNumber(item.BilFiyat),\n    \n    // Stock allocations\n    stocks: item.HS ?? undefined,\n    foreignSecurities: item.YYF ?? undefined,\n    stockBasedFunds: item.HB ?? undefined,\n    stockBasedInvestmentFunds: item.YHS ?? undefined,\n    \n    // Bond allocations\n    bonds: item.BB ?? undefined,\n    governmentBonds: item.DB ?? undefined,\n    privateSectorBonds: item.ÖSDB ?? undefined,\n    governmentSecurities: item.GSYKB ?? undefined,\n    governmentSecuritiesYield: item.GSYY ?? undefined,\n    governmentYieldBonds: item.GYKB ?? undefined,\n    governmentYield: item.GYY ?? undefined,\n    \n    // Deposit and cash allocations\n    deposits: item.D ?? undefined,\n    reversePurchaseAgreements: item.T ?? undefined,\n    preciousMetals: item.KM ?? undefined,\n    cashAndCashEquivalents: item.OSKS ?? undefined,\n    otherSecurities: item.OSKSYD ?? undefined,\n    otherSecuritiesYield: item.ÖKSYD ?? undefined,\n    \n    // Treasury and government instruments\n    treasuryBills: item.BPP ?? undefined,\n    individualInvestmentFunds: item.BYF ?? undefined,\n    governmentDebtInstruments: item.DT ?? undefined,\n    governmentDebtInstrumentsForeign: item.DÖT ?? undefined,\n    eurobonds: item.EUT ?? undefined,\n    foreignBonds: item.FB ?? undefined,\n    foreignCurrencyBonds: item.FKB ?? undefined,\n    goldAndSilver: item.GAS ?? undefined,\n    \n    // Participation accounts and certificates\n    participationAccounts: item.KBA ?? undefined,\n    participationAccountsGold: item.KH ?? undefined,\n    participationAccountsGoldForeign: item.KHAU ?? undefined,\n    participationAccountsForeignCurrency: item.KHD ?? undefined,\n    participationAccountsTurkishLira: item.KHTL ?? undefined,\n    publicLeaseCertificates: item.KKS ?? undefined,\n    publicLeaseCertificatesForeignCurrency: item.KKSD ?? undefined,\n    publicLeaseCertificatesTurkishLira: item.KKSTL ?? undefined,\n    publicLeaseCertificatesForeign: item.KKSYD ?? undefined,\n    participationAccountsForeignCurrencyBonds: item.KİBD ?? undefined,\n    \n    // Other instruments\n    otherSecuritiesTurkishLira: item.OST ?? undefined,\n    repoTransactions: item.R ?? undefined,\n    termDeposits: item.TPP ?? undefined,\n    treasuryBillsShort: item.TR ?? undefined,\n    variableRateDeposits: item.VDM ?? undefined,\n    moneyMarketInstruments: item.VM ?? undefined,\n    moneyMarketInstrumentsGold: item.VMAU ?? undefined,\n    moneyMarketInstrumentsForeignCurrency: item.VMD ?? undefined,\n    moneyMarketInstrumentsTurkishLira: item.VMTL ?? undefined,\n    variableIncomeInstruments: item.VİNT ?? undefined,\n    \n    // Investment fund participations\n    investmentFundParticipations: item.YBA ?? undefined,\n    investmentFundParticipationsBonds: item.YBKB ?? undefined,\n    investmentFundParticipationsOtherSecurities: item.YBOSB ?? undefined,\n    investmentFundParticipationsForeignCurrency: item.YBYF ?? undefined,\n    investmentFundParticipationsMetals: item.YMK ?? undefined,\n    \n    // Precious metals and derivatives\n    preciousMetalsInvestmentFunds: item.KMBYF ?? undefined,\n    preciousMetalsGovernmentDebtInstruments: item.KMKBA ?? undefined,\n    preciousMetalsPublicLeaseCertificates: item.KMKKS ?? undefined,\n  }));\n}\n","/**\n * Shared constants for the TEFAS API client\n */\n\n/**\n * Default maximum number of days per request window when splitting history calls\n */\nexport const DEFAULT_MAX_DAYS_PER_REQUEST = 90;\n\n/**\n * TEFAS API endpoint for fund allocation/portfolio composition data\n */\nexport const TEFAS_ALLOCATION_ENDPOINT = '/api/DB/BindHistoryAllocation';\n\n\n","/**\n * TEFAS API Client\n *\n * This module provides a simplified interface for accessing TEFAS API data.\n * It abstracts away HTTP implementation details and provides a clean, business-focused API.\n */\n\nimport { ApiClient } from './client';\nimport {\n  ApiResponse,\n  FundType,\n  FundHistoryResponse,\n  FundContentResponse,\n  FundResponse,\n  TefasApiRequest,\n  TefasApiResponse,\n  TefasAllocationApiResponse,\n  TefasClientConfig,\n  SearchResult,\n  SearchOptions\n} from './types';\nimport {\n  InvalidFundTypeError,\n  InvalidDateError,\n  DateRangeError,\n  FundNotFoundError,\n  TefasApiError,\n  NetworkError,\n  ConfigurationError,\n  ValidationError\n} from './errors';\nimport { validateFundType, SUPPORTED_FUND_TYPES } from './utils/fund-type-validation';\nimport { convertToTefasDateFormat, addDays, getDaysBetween, validateDateRange, normalizeFuzzyDateRange } from './utils/date-validation';\nimport { mapTefasResponse } from './utils/response-mapping';\nimport { parseSearchResponse } from './utils/search-response-parser';\nimport { mapAllocationResponse } from './utils/allocation-response-mapping';\nimport { DEFAULT_MAX_DAYS_PER_REQUEST, TEFAS_ALLOCATION_ENDPOINT } from './constants';\n\n// Ambient declaration for build-time injected constant\ndeclare const __VERSION__: string;\n\n/**\n * Simplified TEFAS API client that provides a clean interface for fund data access.\n *\n * This client wraps the base REST API client with TEFAS-specific configuration\n * and methods, hiding HTTP implementation details from users.\n *\n * @example\n * ```typescript\n * import { TefasClient, FundType } from 'tefas-client';\n *\n * const client = new TefasClient();\n *\n * // Get all pension funds for a date range\n * const funds = await client.getFundHistory(\n *   '2024-01-01',\n *   '2024-12-31',\n *   undefined,\n *   FundType.EMK\n * );\n *\n * // Get all funds across all types\n * const allFunds = await client.getFundHistory(\n *   '2024-01-01',\n *   '2024-12-31'\n * );\n *\n * // Get specific fund history\n * const specificFund = await client.getFundHistory(\n *   '2024-01-01',\n *   '2024-12-31',\n *   'TGE',\n *   FundType.EMK\n * );\n * ```\n */\nexport class TefasClient {\n  private readonly baseClient: ApiClient;\n  private readonly config: TefasClientConfig;\n  private maxDaysPerRequest: number = DEFAULT_MAX_DAYS_PER_REQUEST;\n\n  /**\n   * Creates a new TEFAS client instance.\n   *\n   * No configuration is required - the client uses hardcoded TEFAS API settings\n   * for zero-configuration setup.\n   *\n   * @throws ConfigurationError if TEFAS API configuration is invalid\n   */\n  constructor() {\n    // Hardcoded TEFAS API configuration\n    this.config = {\n      baseUrl: 'https://www.tefas.gov.tr',\n      timeout: 30000, // 30 seconds\n      headers: {\n        'Content-Type': 'application/x-www-form-urlencoded',\n        'Accept': 'application/json',\n        'User-Agent': `TefasClient/${this.getVersion()}`\n      },\n      maxRetries: 3,\n      retryDelay: 1000\n    };\n\n    // Create base API client with TEFAS configuration\n    this.baseClient = new ApiClient({\n      baseUrl: this.config.baseUrl,\n      timeout: this.config.timeout,\n      headers: this.config.headers\n    });\n\n    // Validate configuration\n    this.validateConfiguration();\n  }\n\n  /**\n   * Returns library version string for User-Agent; falls back to 'dev' in tests.\n   */\n  private getVersion(): string {\n    try {\n      // __VERSION__ is injected at build; guard for test/runtime\n      return typeof __VERSION__ !== 'undefined' ? __VERSION__ : 'dev';\n    } catch {\n      return 'dev';\n    }\n  }\n\n  /**\n   * Sets the maximum number of days per request window when fetching history.\n   * Defaults to 90; values must be integers between 1 and 365.\n   */\n  public setMaxDaysPerRequest(maxDays: number): void {\n    if (typeof maxDays !== 'number' || !Number.isInteger(maxDays)) {\n      throw new ValidationError('maxDaysPerRequest must be an integer');\n    }\n    if (maxDays <= 0 || maxDays > 365) {\n      throw new ValidationError('maxDaysPerRequest must be between 1 and 365');\n    }\n    this.maxDaysPerRequest = maxDays;\n  }\n\n  /**\n   * Get fund history data for funds of a specific type or all types.\n   *\n   * @private\n   * Internal method used by getFund. Use getFund() for public API access.\n   *\n   * This method retrieves historical fund data from TEFAS API. It supports both\n   * standard date formats (YYYY-MM-DD) and fuzzy date parsing for natural language\n   * expressions. The method automatically handles large date ranges by splitting\n   * them into smaller chunks to comply with TEFAS API limitations.\n   *\n   * @param startDate - Start date in YYYY-MM-DD format or fuzzy date (e.g., \"today\", \"yesterday\", \"2024-01-01\")\n   * @param endDate - End date in YYYY-MM-DD format or fuzzy date (e.g., \"today\", \"yesterday\", \"2024-01-01\")\n   * @param fundCode - Optional specific fund code to retrieve (3-character code like \"TGE\", \"IIH\")\n   * @param fundType - Optional fund type to filter by. If omitted, fetches all fund types\n   * @returns Promise resolving to array of fund history data\n   *\n   * @throws InvalidFundTypeError if fund type is not supported\n   * @throws InvalidDateError if date format is invalid\n   * @throws FundNotFoundError if fund code is not found\n   * @throws TefasApiError if TEFAS API returns an error\n   * @throws NetworkError if network request fails\n   *\n   * @see {@link getFund} for public API access\n   * @see {@link FundType} for available fund types\n   * @see {@link FundHistoryResponse} for response structure\n   */\n  private async getFundHistory(\n    startDate: string,\n    endDate: string,\n    fundCode?: string,\n    fundType?: FundType\n  ): Promise<ApiResponse<FundHistoryResponse>> {\n    try {\n      // Normalize fuzzy dates to YYYY-MM-DD format\n      const { startDate: normalizedStartDate, endDate: normalizedEndDate } =\n        normalizeFuzzyDateRange(startDate, endDate);\n\n      // Validate input parameters with normalized dates\n      this.validateFundHistoryRequest(fundType, normalizedStartDate, normalizedEndDate, fundCode);\n\n      // If fundType is provided, fetch only that type\n      if (fundType) {\n        return this.fetchFundHistoryForType(fundType, normalizedStartDate, normalizedEndDate, fundCode);\n      }\n\n      // If no fundType provided, fetch all fund types and merge results\n      return this.fetchAllFundTypes(normalizedStartDate, normalizedEndDate, fundCode);\n    } catch (error) {\n      // Translate errors to business-focused messages\n      throw this.translateError(error);\n    }\n  }\n\n  /**\n   * Get fund history data for all funds of a specific type or all types.\n   *\n   * @private\n   * Internal method used by getFund. Use getFund() for public API access.\n   *\n   * @param startDate - Start date in YYYY-MM-DD format or fuzzy date (e.g., \"today\", \"yesterday\", \"2024-01-01\")\n   * @param endDate - End date in YYYY-MM-DD format or fuzzy date (e.g., \"today\", \"yesterday\", \"2024-01-01\")\n   * @param fundType - Optional fund type to filter by. If omitted, fetches all fund types\n   * @returns Promise resolving to array of fund history data\n   *\n   * @throws InvalidFundTypeError if fund type is not supported\n   * @throws InvalidDateError if date format is invalid\n   * @throws TefasApiError if TEFAS API returns an error\n   * @throws NetworkError if network request fails\n   *\n   * @see {@link getFund} for public API access\n   */\n  private async getAllFundHistory(\n    startDate: string,\n    endDate: string,\n    fundType?: FundType\n  ): Promise<ApiResponse<FundHistoryResponse>> {\n    try {\n      // Normalize fuzzy dates to YYYY-MM-DD format\n      const { startDate: normalizedStartDate, endDate: normalizedEndDate } =\n        normalizeFuzzyDateRange(startDate, endDate);\n\n      // Validate input parameters with normalized dates\n      this.validateFundHistoryRequest(fundType, normalizedStartDate, normalizedEndDate);\n\n      // If fundType is provided, fetch only that type\n      if (fundType) {\n        return this.fetchFundHistoryForType(fundType, normalizedStartDate, normalizedEndDate);\n      }\n\n      // If no fundType provided, fetch all fund types and merge results\n      return this.fetchAllFundTypes(normalizedStartDate, normalizedEndDate);\n    } catch (error) {\n      // Translate errors to business-focused messages\n      throw this.translateError(error);\n    }\n  }\n\n  /**\n   * Search for funds by name or code prefix\n   *\n   * Enables autocomplete and fund selection by searching for funds matching\n   * the provided query string. The search is performed against both fund codes\n   * and fund names. Optionally filter by fund type and limit the number of results.\n   *\n   * This method is perfect for implementing autocomplete functionality, fund\n   * selection dropdowns, or finding funds by partial name matches. The search\n   * is case-insensitive and supports Turkish characters.\n   *\n   * @param query - Search query (fund code or name prefix)\n   * @param options - Optional search configuration (fundType filter, result limit)\n   * @returns Promise resolving to array of matching funds\n   *\n   * @throws ValidationError if query is empty or limit is invalid\n   * @throws InvalidFundTypeError if fundType is invalid\n   * @throws TefasApiError if TEFAS API returns an error\n   * @throws NetworkError if network request fails\n   *\n   * @example\n   * ```typescript\n   * import { TefasClient, FundType } from '@firstthumb/tefas-api';\n   *\n   * const client = new TefasClient();\n   *\n   * // Basic search by code prefix\n   * const results = await client.searchFund('IIH');\n   * console.log(results);\n   * // [{ fundCode: \"IIH\", fundName: \"IIH - İSTANBUL PORTFÖY...\" }]\n   *\n   * // Search with fund type filter\n   * const yatFunds = await client.searchFund('IS', { fundType: FundType.YAT });\n   * console.log(yatFunds); // Only investment funds (YAT type)\n   *\n   * // Search with custom result limit (great for autocomplete)\n   * const limitedResults = await client.searchFund('A', { limit: 5 });\n   * console.log(limitedResults.length); // At most 5 results\n   *\n   * // Combine filters and limits\n   * const filtered = await client.searchFund('IS', {\n   *   fundType: FundType.EMK,\n   *   limit: 3\n   * });\n   *\n   * // Use fund code for detailed history\n   * if (results.length > 0) {\n   *   const history = await client.getFundHistory(\n   *     '2024-01-01',\n   *     '2024-12-31',\n   *     results[0].fundCode,\n   *     FundType.YAT\n   *   );\n   * }\n   *\n   * // Autocomplete implementation example\n   * async function autocompleteFunds(query: string) {\n   *   if (query.length < 2) return [];\n   *\n   *   try {\n   *     const results = await client.searchFund(query, { limit: 10 });\n   *     return results.map(fund => ({\n   *       value: fund.fundCode,\n   *       label: fund.fundName,\n   *       code: fund.fundCode\n   *     }));\n   *   } catch (error) {\n   *     console.error('Search failed:', error);\n   *     return [];\n   *   }\n   * }\n   * ```\n   *\n   * @since 1.0.0\n   * @see {@link SearchResult} for result structure\n   * @see {@link SearchOptions} for configuration options\n   */\n  async searchFund(query: string, options?: SearchOptions): Promise<ApiResponse<SearchResult>> {\n    try {\n      // Validate input\n      this.validateSearchQuery(query);\n\n      // Validate options if provided\n      if (options?.fundType) {\n        validateFundType(options.fundType);\n      }\n\n      if (options?.limit !== undefined) {\n        this.validateLimit(options.limit);\n      }\n\n      // Trim query for API call\n      const trimmedQuery = query.trim();\n\n      // Build search API request\n      const searchRequest = {\n        prefixText: trimmedQuery,\n        count: options?.limit ?? 10,\n        contextKey: options?.fundType || ''\n      };\n\n      // Make API call to GetAllFunds endpoint\n      const response = await this.baseClient.post(\n        '/Service.asmx/GetAllFunds',\n        searchRequest,\n        { contentType: 'json' }\n      );\n\n      // Parse nested JSON response\n      const results = parseSearchResponse(response);\n\n      return { results };\n    } catch (error) {\n      // Translate errors to business-focused messages\n      throw this.translateError(error);\n    }\n  }\n\n  /**\n   * Validates limit parameter\n   *\n   * @private\n   * @param limit - Limit value to validate\n   * @throws ValidationError if limit is invalid\n   */\n  private validateLimit(limit: number): void {\n    if (typeof limit !== 'number') {\n      throw new ValidationError('limit must be a number');\n    }\n\n    if (!Number.isInteger(limit)) {\n      throw new ValidationError('limit must be an integer');\n    }\n\n    if (limit <= 0) {\n      throw new ValidationError('limit must be a positive integer');\n    }\n  }\n\n  /**\n   * Validates search query parameter\n   *\n   * @private\n   * @param query - Search query to validate\n   * @throws ValidationError if query is invalid\n   */\n  private validateSearchQuery(query: string): void {\n    // Check if query is provided\n    if (!query || typeof query !== 'string') {\n      throw new ValidationError('query must be a non-empty string');\n    }\n\n    // Check if query is not just whitespace\n    if (query.trim().length === 0) {\n      throw new ValidationError('query must be a non-empty string');\n    }\n  }\n\n  /**\n   * Get fund allocation/portfolio composition data for funds of a specific type or all types.\n   *\n   * @private\n   * Internal method used by getFund. Use getFund() for public API access.\n   *\n   * This method retrieves historical fund allocation data from TEFAS API. It supports both\n   * standard date formats (YYYY-MM-DD) and fuzzy date parsing for natural language\n   * expressions. The method automatically handles large date ranges by splitting\n   * them into smaller chunks to comply with TEFAS API limitations.\n   *\n   * @param startDate - Start date in YYYY-MM-DD format or fuzzy date (e.g., \"today\", \"yesterday\", \"2024-01-01\")\n   * @param endDate - End date in YYYY-MM-DD format or fuzzy date (e.g., \"today\", \"yesterday\", \"2024-01-01\")\n   * @param fundCode - Optional specific fund code to retrieve (3-character code like \"TGE\", \"IIH\")\n   * @param fundType - Optional fund type to filter by. If omitted, fetches all fund types\n   * @returns Promise resolving to array of fund allocation data\n   *\n   * @throws InvalidFundTypeError if fund type is not supported\n   * @throws InvalidDateError if date format is invalid\n   * @throws FundNotFoundError if fund code is not found\n   * @throws TefasApiError if TEFAS API returns an error\n   * @throws NetworkError if network request fails\n   *\n   * @see {@link getFund} for public API access\n   * @see {@link FundType} for available fund types\n   * @see {@link FundContentResponse} for response structure\n   */\n  private async getFundContent(\n    startDate: string,\n    endDate: string,\n    fundCode?: string,\n    fundType?: FundType\n  ): Promise<ApiResponse<FundContentResponse>> {\n    try {\n      // Normalize fuzzy dates to YYYY-MM-DD format\n      const { startDate: normalizedStartDate, endDate: normalizedEndDate } =\n        normalizeFuzzyDateRange(startDate, endDate);\n\n      // Validate input parameters with normalized dates\n      this.validateFundContentRequest(fundType, normalizedStartDate, normalizedEndDate, fundCode);\n\n      // If fundType is provided, fetch only that type\n      if (fundType) {\n        return this.fetchFundContentForType(fundType, normalizedStartDate, normalizedEndDate, fundCode);\n      }\n\n      // If no fundType provided, fetch all fund types and merge results\n      return this.fetchAllFundTypesContent(normalizedStartDate, normalizedEndDate, fundCode);\n    } catch (error) {\n      // Translate errors to business-focused messages\n      throw this.translateError(error);\n    }\n  }\n\n  /**\n   * Get merged fund data combining history and content information.\n   *\n   * This method retrieves both fund history and allocation data from TEFAS API\n   * and merges them based on fund code and date. It provides a unified view of\n   * fund data where fields from either source may be null if the corresponding\n   * data is not available for that fund/date combination.\n   *\n   * **Important:** This method always searches across ALL fund types (EMK, YAT, BYF, GYF, GSYF).\n   * Even when a specific fundCode is provided, it searches all fund types to find that fund.\n   * This is the primary public API for fetching fund data. For searching funds by name/code, use {@link searchFund}.\n   *\n   * The method supports both standard date formats (YYYY-MM-DD) and fuzzy date\n   * parsing for natural language expressions. It automatically handles large\n   * date ranges by splitting them into smaller chunks to comply with TEFAS API\n   * limitations.\n   *\n   * @param startDate - Start date in YYYY-MM-DD format or fuzzy date (e.g., \"today\", \"yesterday\", \"2024-01-01\")\n   * @param endDate - End date in YYYY-MM-DD format or fuzzy date (e.g., \"today\", \"yesterday\", \"2024-01-01\")\n   * @param fundCode - Optional specific fund code to retrieve (3-character code like \"TGE\", \"IIH\")\n   *   Note: When provided, this method still searches across ALL fund types (EMK, YAT, BYF, GYF, GSYF)\n   *   to find the fund code. If omitted, returns data for all funds across all types.\n   * @returns Promise resolving to array of merged fund data\n   *\n   * @throws InvalidDateError if date format is invalid\n   * @throws FundNotFoundError if fund code is not found\n   * @throws TefasApiError if TEFAS API returns an error\n   * @throws NetworkError if network request fails\n   *\n   * @example\n   * ```typescript\n   * import { TefasClient } from '@firstthumb/tefas-api';\n   *\n   * const client = new TefasClient();\n   *\n   * // Get merged data for a specific fund using fuzzy dates\n   * const fundData = await client.getFund(\n   *   'yesterday',\n   *   'today',\n   *   'TGE'\n   * );\n   * console.log(fundData[0].price); // Fund price\n   * console.log(fundData[0].stocks); // Stock allocation percentage\n   *\n   * // Get merged data for all funds across all types\n   * const allFunds = await client.getFund(\n   *   '2024-01-01',\n   *   '2024-12-31'\n   * );\n   * console.log(allFunds.length); // Total number of fund/date combinations\n   *\n   * // Get merged data using mixed date formats\n   * // This searches for 'IIH' across ALL fund types (EMK, YAT, BYF, GYF, GSYF)\n   * const recentData = await client.getFund(\n   *   'last week',\n   *   'today',\n   *   'IIH'\n   * );\n   *\n   * // Handle missing data gracefully\n   * recentData.forEach(fund => {\n   *   if (fund.price !== null) {\n   *     console.log(`Price: ${fund.price}`);\n   *   }\n   *   if (fund.stocks !== null && fund.stocks !== undefined) {\n   *     console.log(`Stock allocation: ${fund.stocks}%`);\n   *   }\n   * });\n   *\n   * // Handle errors gracefully\n   * try {\n   *   const data = await client.getFund('2024-01-01', '2024-01-31', 'INVALID');\n   * } catch (error) {\n   *   if (error instanceof FundNotFoundError) {\n   *     console.log('Fund not found');\n   *   }\n   * }\n   * ```\n   *\n   * @since 1.0.0\n   * @see {@link FundResponse} for response structure\n   * @see {@link getFundHistory} for history-only data\n   * @see {@link getFundContent} for content-only data\n   */\n  async getFund(\n    startDate: string,\n    endDate: string,\n    fundCode?: string\n  ): Promise<ApiResponse<FundResponse>> {\n    try {\n      // Normalize fuzzy dates to YYYY-MM-DD format\n      const { startDate: normalizedStartDate, endDate: normalizedEndDate } =\n        normalizeFuzzyDateRange(startDate, endDate);\n\n      // Fetch both history and content data in parallel\n      const [historyResponse, contentResponse] = await Promise.all([\n        this.getFundHistory(normalizedStartDate, normalizedEndDate, fundCode),\n        this.getFundContent(normalizedStartDate, normalizedEndDate, fundCode)\n      ]);\n\n      // Extract data from wrapped responses\n      const historyData = historyResponse.results;\n      const contentData = contentResponse.results;\n\n      // Create maps for efficient lookup by fundCode + date\n      const historyMap = new Map<string, FundHistoryResponse>();\n      const contentMap = new Map<string, FundContentResponse>();\n\n      // Populate history map\n      for (const history of historyData) {\n        const key = `${history.fundCode}_${history.date}`;\n        historyMap.set(key, history);\n      }\n\n      // Populate content map\n      for (const content of contentData) {\n        const key = `${content.fundCode}_${content.date}`;\n        contentMap.set(key, content);\n      }\n\n      // Collect all unique fundCode + date combinations\n      const allKeys = new Set<string>();\n      for (const key of historyMap.keys()) {\n        allKeys.add(key);\n      }\n      for (const key of contentMap.keys()) {\n        allKeys.add(key);\n      }\n\n      // Merge data for each unique combination\n      const mergedData: FundResponse[] = [];\n      for (const key of allKeys) {\n        const [fundCode, date] = key.split('_');\n        const history = historyMap.get(key);\n        const content = contentMap.get(key);\n\n        // Determine fund name and type from available data\n        const fundName = history?.fundName || content?.fundName || '';\n        const fundType = history?.fundType || content?.fundType || FundType.EMK;\n\n        // Create merged response\n        const merged: FundResponse = {\n          fundCode,\n          fundName,\n          fundType,\n          date,\n\n          // History fields\n          price: history?.price ?? null,\n          volume: history?.volume ?? null,\n          assets: history?.assets ?? null,\n\n          // Content fields\n          totalValue: content?.totalValue ?? null,\n          stocks: content?.stocks ?? null,\n          foreignSecurities: content?.foreignSecurities ?? null,\n          stockBasedFunds: content?.stockBasedFunds ?? null,\n          stockBasedInvestmentFunds: content?.stockBasedInvestmentFunds ?? null,\n          bonds: content?.bonds ?? null,\n          governmentBonds: content?.governmentBonds ?? null,\n          privateSectorBonds: content?.privateSectorBonds ?? null,\n          governmentSecurities: content?.governmentSecurities ?? null,\n          governmentSecuritiesYield: content?.governmentSecuritiesYield ?? null,\n          governmentYieldBonds: content?.governmentYieldBonds ?? null,\n          governmentYield: content?.governmentYield ?? null,\n          deposits: content?.deposits ?? null,\n          reversePurchaseAgreements: content?.reversePurchaseAgreements ?? null,\n          preciousMetals: content?.preciousMetals ?? null,\n          cashAndCashEquivalents: content?.cashAndCashEquivalents ?? null,\n          otherSecurities: content?.otherSecurities ?? null,\n          otherSecuritiesYield: content?.otherSecuritiesYield ?? null,\n          treasuryBills: content?.treasuryBills ?? null,\n          individualInvestmentFunds: content?.individualInvestmentFunds ?? null,\n          governmentDebtInstruments: content?.governmentDebtInstruments ?? null,\n          governmentDebtInstrumentsForeign: content?.governmentDebtInstrumentsForeign ?? null,\n          eurobonds: content?.eurobonds ?? null,\n          foreignBonds: content?.foreignBonds ?? null,\n          foreignCurrencyBonds: content?.foreignCurrencyBonds ?? null,\n          goldAndSilver: content?.goldAndSilver ?? null,\n          participationAccounts: content?.participationAccounts ?? null,\n          participationAccountsGold: content?.participationAccountsGold ?? null,\n          participationAccountsGoldForeign: content?.participationAccountsGoldForeign ?? null,\n          participationAccountsForeignCurrency: content?.participationAccountsForeignCurrency ?? null,\n          participationAccountsTurkishLira: content?.participationAccountsTurkishLira ?? null,\n          publicLeaseCertificates: content?.publicLeaseCertificates ?? null,\n          publicLeaseCertificatesForeignCurrency: content?.publicLeaseCertificatesForeignCurrency ?? null,\n          publicLeaseCertificatesTurkishLira: content?.publicLeaseCertificatesTurkishLira ?? null,\n          publicLeaseCertificatesForeign: content?.publicLeaseCertificatesForeign ?? null,\n          participationAccountsForeignCurrencyBonds: content?.participationAccountsForeignCurrencyBonds ?? null,\n          otherSecuritiesTurkishLira: content?.otherSecuritiesTurkishLira ?? null,\n          repoTransactions: content?.repoTransactions ?? null,\n          termDeposits: content?.termDeposits ?? null,\n          treasuryBillsShort: content?.treasuryBillsShort ?? null,\n          variableRateDeposits: content?.variableRateDeposits ?? null,\n          moneyMarketInstruments: content?.moneyMarketInstruments ?? null,\n          moneyMarketInstrumentsGold: content?.moneyMarketInstrumentsGold ?? null,\n          moneyMarketInstrumentsForeignCurrency: content?.moneyMarketInstrumentsForeignCurrency ?? null,\n          moneyMarketInstrumentsTurkishLira: content?.moneyMarketInstrumentsTurkishLira ?? null,\n          variableIncomeInstruments: content?.variableIncomeInstruments ?? null,\n          investmentFundParticipations: content?.investmentFundParticipations ?? null,\n          investmentFundParticipationsBonds: content?.investmentFundParticipationsBonds ?? null,\n          investmentFundParticipationsOtherSecurities: content?.investmentFundParticipationsOtherSecurities ?? null,\n          investmentFundParticipationsForeignCurrency: content?.investmentFundParticipationsForeignCurrency ?? null,\n          investmentFundParticipationsMetals: content?.investmentFundParticipationsMetals ?? null,\n          preciousMetalsInvestmentFunds: content?.preciousMetalsInvestmentFunds ?? null,\n          preciousMetalsGovernmentDebtInstruments: content?.preciousMetalsGovernmentDebtInstruments ?? null,\n          preciousMetalsPublicLeaseCertificates: content?.preciousMetalsPublicLeaseCertificates ?? null\n        };\n\n        mergedData.push(merged);\n      }\n\n      // Sort by date ascending for consistent ordering\n      mergedData.sort((a, b) => (a.date < b.date ? -1 : a.date > b.date ? 1 : 0));\n\n      return { results: mergedData };\n    } catch (error) {\n      // Translate errors to business-focused messages\n      throw this.translateError(error);\n    }\n  }\n\n  /**\n   * Validates the TEFAS API configuration.\n   *\n   * @private\n   * @throws ConfigurationError if configuration is invalid\n   */\n  private validateConfiguration(): void {\n    if (!this.config.baseUrl || typeof this.config.baseUrl !== 'string') {\n      throw new ConfigurationError('Invalid base URL configuration');\n    }\n\n    if (this.config.timeout <= 0) {\n      throw new ConfigurationError('Invalid timeout configuration');\n    }\n\n    if (!this.config.headers || typeof this.config.headers !== 'object') {\n      throw new ConfigurationError('Invalid headers configuration');\n    }\n\n    // Validate required headers\n    const requiredHeaders = ['Content-Type', 'Accept'];\n    for (const header of requiredHeaders) {\n      if (!this.config.headers[header]) {\n        throw new ConfigurationError(`Missing required header: ${header}`);\n      }\n    }\n  }\n\n  /**\n   * Validates fund history request parameters.\n   *\n   * @private\n   * @param fundType - Fund type to validate (optional)\n   * @param startDate - Start date to validate\n   * @param endDate - End date to validate\n   * @param fundCode - Optional fund code to validate\n   * @throws InvalidFundTypeError if fund type is invalid\n   * @throws InvalidDateError if date format is invalid\n   * @throws DateRangeError if date range is invalid\n   */\n  private validateFundHistoryRequest(\n    fundType: FundType | undefined,\n    startDate: string,\n    endDate: string,\n    fundCode?: string\n  ): void {\n    // Validate fund type if provided\n    if (fundType) {\n      validateFundType(fundType);\n    }\n\n    // Validate date range (includes individual date validation)\n    validateDateRange(startDate, endDate);\n\n    // Validate fund code if provided\n    if (fundCode !== undefined) {\n      if (!fundCode || typeof fundCode !== 'string' || fundCode.trim().length === 0) {\n        throw new InvalidDateError(fundCode, 'Fund code must be a non-empty string');\n      }\n\n      // TEFAS fund codes are typically 3 characters\n      if (fundCode.trim().length !== 3) {\n        throw new InvalidDateError(fundCode, 'Fund code must be exactly 3 characters');\n      }\n    }\n  }\n\n  /**\n   * Validates fund content request parameters.\n   *\n   * @private\n   * @param fundType - Fund type to validate (optional)\n   * @param startDate - Start date to validate\n   * @param endDate - End date to validate\n   * @param fundCode - Optional fund code to validate\n   * @throws InvalidFundTypeError if fund type is invalid\n   * @throws InvalidDateError if date format is invalid\n   * @throws DateRangeError if date range is invalid\n   */\n  private validateFundContentRequest(\n    fundType: FundType | undefined,\n    startDate: string,\n    endDate: string,\n    fundCode?: string\n  ): void {\n    // Validate fund type if provided\n    if (fundType) {\n      validateFundType(fundType);\n    }\n\n    // Validate date range (includes individual date validation)\n    validateDateRange(startDate, endDate);\n\n    // Validate fund code if provided\n    if (fundCode !== undefined) {\n      if (!fundCode || typeof fundCode !== 'string' || fundCode.trim().length === 0) {\n        throw new InvalidDateError(fundCode, 'Fund code must be a non-empty string');\n      }\n\n      // TEFAS fund codes are typically 3 characters\n      if (fundCode.trim().length !== 3) {\n        throw new InvalidDateError(fundCode, 'Fund code must be exactly 3 characters');\n      }\n    }\n  }\n\n  /**\n   * Fetches fund history for a specific fund type.\n   *\n   * @private\n   * @param fundType - Fund type to fetch\n   * @param startDate - Start date\n   * @param endDate - End date\n   * @param fundCode - Optional fund code\n   * @returns Promise resolving to fund history data\n   */\n  private async fetchFundHistoryForType(\n    fundType: FundType,\n    startDate: string,\n    endDate: string,\n    fundCode?: string\n  ): Promise<ApiResponse<FundHistoryResponse>> {\n    // If the requested range exceeds 90 days, split into chunks to avoid TEFAS API error\n    const totalDays = getDaysBetween(startDate, endDate);\n    const MAX_DAYS = this.maxDaysPerRequest; // inclusive window size\n\n    let fundHistory: FundHistoryResponse[] = [];\n    if (totalDays > MAX_DAYS) {\n      let chunkStart = startDate;\n      while (true) {\n        const tentativeEnd = addDays(chunkStart, MAX_DAYS - 1);\n        const chunkEnd = tentativeEnd > endDate ? endDate : tentativeEnd;\n\n        const chunkRequest = this.buildTefasRequest(fundType, chunkStart, chunkEnd, fundCode);\n        const chunkResponse = await this.baseClient.post<TefasApiResponse>(\n          '/api/DB/BindHistoryInfo',\n          chunkRequest,\n          { contentType: 'form' }\n        );\n        const chunkHistory = this.processTefasResponse(chunkResponse, fundType);\n        fundHistory = fundHistory.concat(chunkHistory);\n\n        if (chunkEnd === endDate) break;\n        chunkStart = addDays(chunkEnd, 1);\n      }\n    } else {\n      // Single call path\n      const tefasRequest = this.buildTefasRequest(fundType, startDate, endDate, fundCode);\n      const response = await this.baseClient.post<TefasApiResponse>('/api/DB/BindHistoryInfo', tefasRequest, {\n        contentType: 'form'\n      });\n      fundHistory = this.processTefasResponse(response, fundType);\n    }\n\n    // Ensure deterministic ordering by date ascending\n    fundHistory.sort((a, b) => (a.date < b.date ? -1 : a.date > b.date ? 1 : 0));\n\n    // If specific fund code was requested, validate it exists\n    if (fundCode && fundHistory.length === 0) {\n      throw new FundNotFoundError(fundCode);\n    }\n\n    return { results: fundHistory };\n  }\n\n  /**\n   * Fetches fund history for all fund types and merges results.\n   *\n   * @private\n   * @param startDate - Start date\n   * @param endDate - End date\n   * @param fundCode - Optional fund code\n   * @returns Promise resolving to merged fund history data\n   */\n  private async fetchAllFundTypes(\n    startDate: string,\n    endDate: string,\n    fundCode?: string\n  ): Promise<ApiResponse<FundHistoryResponse>> {\n    const allFundTypes = SUPPORTED_FUND_TYPES;\n    const allResults: FundHistoryResponse[] = [];\n\n    // Fetch data for each fund type in parallel\n    const promises = allFundTypes.map(async (fundType) => {\n      try {\n        const response = await this.fetchFundHistoryForType(fundType, startDate, endDate, fundCode);\n        return response.results;\n      } catch {\n        // If a specific fund type fails, continue with others\n        return [];\n      }\n    });\n\n    const results = await Promise.all(promises);\n\n    // Merge all results\n    for (const result of results) {\n      allResults.push(...result);\n    }\n\n    // Sort merged results by date ascending\n    allResults.sort((a, b) => (a.date < b.date ? -1 : a.date > b.date ? 1 : 0));\n\n    // If specific fund code was requested, validate it exists\n    if (fundCode && allResults.length === 0) {\n      throw new FundNotFoundError(fundCode);\n    }\n\n    return { results: allResults };\n  }\n\n  /**\n   * Fetches fund allocation data for a specific fund type.\n   *\n   * @private\n   * @param fundType - Fund type to fetch\n   * @param startDate - Start date\n   * @param endDate - End date\n   * @param fundCode - Optional fund code\n   * @returns Promise resolving to fund allocation data\n   */\n  private async fetchFundContentForType(\n    fundType: FundType,\n    startDate: string,\n    endDate: string,\n    fundCode?: string\n  ): Promise<ApiResponse<FundContentResponse>> {\n    // If the requested range exceeds 90 days, split into chunks to avoid TEFAS API error\n    const totalDays = getDaysBetween(startDate, endDate);\n    const MAX_DAYS = this.maxDaysPerRequest; // inclusive window size\n\n    let fundContent: FundContentResponse[] = [];\n    if (totalDays > MAX_DAYS) {\n      let chunkStart = startDate;\n      while (true) {\n        const tentativeEnd = addDays(chunkStart, MAX_DAYS - 1);\n        const chunkEnd = tentativeEnd > endDate ? endDate : tentativeEnd;\n\n        const chunkRequest = this.buildAllocationRequest(fundType, chunkStart, chunkEnd, fundCode);\n        const chunkResponse = await this.baseClient.post<TefasAllocationApiResponse>(\n          TEFAS_ALLOCATION_ENDPOINT,\n          chunkRequest,\n          { contentType: 'form' }\n        );\n        const chunkContent = this.processAllocationResponse(chunkResponse, fundType);\n        fundContent = fundContent.concat(chunkContent);\n\n        if (chunkEnd === endDate) break;\n        chunkStart = addDays(chunkEnd, 1);\n      }\n    } else {\n      // Single call path\n      const allocationRequest = this.buildAllocationRequest(fundType, startDate, endDate, fundCode);\n      const response = await this.baseClient.post<TefasAllocationApiResponse>(\n        TEFAS_ALLOCATION_ENDPOINT,\n        allocationRequest,\n        { contentType: 'form' }\n      );\n      fundContent = this.processAllocationResponse(response, fundType);\n    }\n\n    // Ensure deterministic ordering by date ascending\n    fundContent.sort((a, b) => (a.date < b.date ? -1 : a.date > b.date ? 1 : 0));\n\n    // If specific fund code was requested, validate it exists\n    if (fundCode && fundContent.length === 0) {\n      throw new FundNotFoundError(fundCode);\n    }\n\n    return { results: fundContent };\n  }\n\n  /**\n   * Fetches fund allocation data for all fund types and merges results.\n   *\n   * @private\n   * @param startDate - Start date\n   * @param endDate - End date\n   * @param fundCode - Optional fund code\n   * @returns Promise resolving to merged fund allocation data\n   */\n  private async fetchAllFundTypesContent(\n    startDate: string,\n    endDate: string,\n    fundCode?: string\n  ): Promise<ApiResponse<FundContentResponse>> {\n    const allFundTypes = SUPPORTED_FUND_TYPES;\n    const allResults: FundContentResponse[] = [];\n\n    // Fetch data for each fund type in parallel\n    const promises = allFundTypes.map(async (fundType) => {\n      try {\n        const response = await this.fetchFundContentForType(fundType, startDate, endDate, fundCode);\n        return response.results;\n      } catch {\n        // If a specific fund type fails, continue with others\n        return [];\n      }\n    });\n\n    const results = await Promise.all(promises);\n\n    // Merge all results\n    for (const result of results) {\n      allResults.push(...result);\n    }\n\n    // Sort merged results by date ascending\n    allResults.sort((a, b) => (a.date < b.date ? -1 : a.date > b.date ? 1 : 0));\n\n    // If specific fund code was requested, validate it exists\n    if (fundCode && allResults.length === 0) {\n      throw new FundNotFoundError(fundCode);\n    }\n\n    return { results: allResults };\n  }\n\n  /**\n   * Builds TEFAS API request parameters.\n   *\n   * @private\n   * @param fundType - Fund type\n   * @param startDate - Start date\n   * @param endDate - End date\n   * @param fundCode - Optional fund code\n   * @returns TEFAS API request object\n   */\n  private buildTefasRequest(\n    fundType: FundType,\n    startDate: string,\n    endDate: string,\n    fundCode?: string\n  ): TefasApiRequest {\n    const request: TefasApiRequest = {\n      fontip: fundType,\n      bastarih: convertToTefasDateFormat(startDate),\n      bittarih: convertToTefasDateFormat(endDate)\n    };\n\n    // Add fund code if provided\n    if (fundCode) {\n      request.fonkod = fundCode.trim().toUpperCase();\n    }\n\n    return request;\n  }\n\n  /**\n   * Builds TEFAS allocation API request parameters.\n   *\n   * @private\n   * @param fundType - Fund type\n   * @param startDate - Start date\n   * @param endDate - End date\n   * @param fundCode - Optional fund code\n   * @returns TEFAS allocation API request object\n   */\n  private buildAllocationRequest(\n    fundType: FundType,\n    startDate: string,\n    endDate: string,\n    fundCode?: string\n  ): Record<string, string> {\n    const request: Record<string, string> = {\n      fontip: fundType,\n      bastarih: convertToTefasDateFormat(startDate),\n      bittarih: convertToTefasDateFormat(endDate)\n    };\n\n    // Add fund code if provided\n    if (fundCode) {\n      request.fonkod = fundCode.trim().toUpperCase();\n    }\n\n    return request;\n  }\n\n  /**\n   * Processes TEFAS API response and maps it to our typed response.\n   *\n   * @private\n   * @param response - Raw TEFAS API response\n   * @param fundType - Fund type from the request\n   * @returns Array of mapped fund history responses\n   */\n  private processTefasResponse(response: TefasApiResponse, fundType: FundType): FundHistoryResponse[] {\n    return mapTefasResponse(response, fundType);\n  }\n\n  /**\n   * Processes TEFAS allocation API response and maps it to our typed response.\n   *\n   * @private\n   * @param response - Raw TEFAS allocation API response\n   * @param fundType - Fund type from the request\n   * @returns Array of mapped fund allocation responses\n   */\n  private processAllocationResponse(response: TefasAllocationApiResponse, fundType: FundType): FundContentResponse[] {\n    return mapAllocationResponse(response, fundType);\n  }\n\n  /**\n   * Translates errors to business-focused messages.\n   *\n   * @private\n   * @param error - Error to translate\n   * @returns Business-focused error\n   */\n  private translateError(error: unknown): Error {\n    // If it's already a TEFAS error, return as-is\n    if (error instanceof InvalidFundTypeError ||\n        error instanceof InvalidDateError ||\n        error instanceof DateRangeError ||\n        error instanceof FundNotFoundError ||\n        error instanceof TefasApiError ||\n        error instanceof NetworkError ||\n        error instanceof ConfigurationError ||\n        error instanceof ValidationError) {\n      return error;\n    }\n\n    // Handle network errors (check message first before HTTP status)\n    if (error && typeof error === 'object' && 'message' in error) {\n      const errorMessage = (error as Error).message.toLowerCase();\n      if (errorMessage.includes('fetch') || errorMessage.includes('network') || errorMessage.includes('timeout')) {\n        return new NetworkError('Unable to connect to TEFAS API. Please check your internet connection.');\n      }\n    }\n\n    // Handle HTTP errors from base client\n    if (error && typeof error === 'object' && 'status' in error) {\n      const httpError = error as { status: number; statusText?: string };\n      if (httpError.status === 404) {\n        return new FundNotFoundError('Requested fund data not found');\n      }\n      if (httpError.status >= 500) {\n        return new TefasApiError('TEFAS API is temporarily unavailable. Please try again later.');\n      }\n      if (httpError.status >= 400) {\n        return new TefasApiError('Invalid request. Please check your parameters and try again.');\n      }\n    }\n\n    // Default to generic TEFAS API error\n    return new TefasApiError(\n      error instanceof Error ? error.message : 'An unexpected error occurred',\n      error\n    );\n  }\n}\n","/**\n * Performance Calculator Utilities\n *\n * This module provides utilities for calculating financial performance metrics\n * from fund history data. Uses simple-statistics for mathematical calculations.\n */\n\nimport { standardDeviation, mean } from 'simple-statistics';\nimport {\n  FundHistoryResponse,\n  PerformanceMetrics,\n  MetricsOptions,\n  FundType\n} from '../types';\n\n/**\n * Performance calculator for fund metrics\n *\n * Provides static methods for calculating various financial performance metrics\n * including returns, volatility, and risk-adjusted measures.\n */\nexport class PerformanceCalculator {\n  /**\n   * Calculate performance metrics for multiple funds\n   *\n   * @param fundHistory - Array of fund history data\n   * @param options - Configuration options for calculations\n   * @returns Array of performance metrics for each fund\n   */\n  static calculateMetrics(\n    fundHistory: FundHistoryResponse[],\n    options: MetricsOptions = {}\n  ): PerformanceMetrics[] {\n    const {\n      riskFreeRate = 0,\n      frequency = 'daily',\n      method = 'simple',\n      minObservations = 30\n    } = options;\n\n    // Group data by fund code\n    const fundGroups = this.groupByFund(fundHistory);\n    const periodsPerYear = this.getPeriodsPerYear(frequency);\n\n    const results: PerformanceMetrics[] = [];\n\n    for (const [fundCode, data] of fundGroups) {\n      // Sort by date to ensure chronological order\n      const sortedData = data.sort((a, b) =>\n        new Date(a.date).getTime() - new Date(b.date).getTime()\n      );\n\n      if (sortedData.length < minObservations) {\n        results.push(this.createEmptyMetrics(fundCode, sortedData[0]));\n        continue;\n      }\n\n      const prices = sortedData.map(d => d.price);\n      const returns = this.calculateReturns(prices, method);\n\n      if (returns.length === 0) {\n        results.push(this.createEmptyMetrics(fundCode, sortedData[0]));\n        continue;\n      }\n\n      const cumulativeReturn = this.calculateCumulativeReturn(returns, method);\n      const annualizedReturn = this.calculateAnnualizedReturn(returns, periodsPerYear, method);\n      const annualizedVolatility = this.calculateVolatility(returns, periodsPerYear);\n      const sharpeRatio = this.calculateSharpeRatio(returns, riskFreeRate, periodsPerYear, method);\n\n      results.push({\n        fundCode,\n        fundName: sortedData[0].fundName,\n        fundType: sortedData[0].fundType,\n        observations: prices.length,\n        cumulativeReturn,\n        annualizedReturn,\n        annualizedVolatility,\n        sharpeRatio\n      });\n    }\n\n    return results;\n  }\n\n  /**\n   * Group fund history data by fund code\n   *\n   * @param fundHistory - Array of fund history data\n   * @returns Map of fund code to fund data array\n   */\n  static groupByFund(fundHistory: FundHistoryResponse[]): Map<string, FundHistoryResponse[]> {\n    const groups = new Map<string, FundHistoryResponse[]>();\n\n    for (const data of fundHistory) {\n      const existing = groups.get(data.fundCode) || [];\n      existing.push(data);\n      groups.set(data.fundCode, existing);\n    }\n\n    return groups;\n  }\n\n  /**\n   * Calculate returns from price series\n   *\n   * @param prices - Array of prices in chronological order\n   * @param method - Return calculation method\n   * @returns Array of returns\n   */\n  static calculateReturns(prices: number[], method: 'simple' | 'logarithmic'): number[] {\n    if (prices.length < 2) return [];\n\n    const returns: number[] = [];\n\n    for (let i = 1; i < prices.length; i++) {\n      const currentPrice = prices[i];\n      const previousPrice = prices[i - 1];\n\n      // Skip if previous price is invalid (zero or negative)\n      if (previousPrice <= 0) continue;\n\n      // Skip if current price is invalid (zero or negative)\n      if (currentPrice <= 0) continue;\n\n      if (method === 'logarithmic') {\n        returns.push(Math.log(currentPrice / previousPrice));\n      } else {\n        returns.push((currentPrice / previousPrice) - 1);\n      }\n    }\n\n    return returns;\n  }\n\n  /**\n   * Calculate cumulative return over the period\n   *\n   * @param returns - Array of returns\n   * @param method - Return calculation method\n   * @returns Cumulative return\n   */\n  static calculateCumulativeReturn(returns: number[], method: string): number {\n    if (returns.length === 0) return 0;\n\n    if (method === 'logarithmic') {\n      const sum = returns.reduce((acc, ret) => acc + ret, 0);\n      return Math.exp(sum) - 1;\n    } else {\n      const product = returns.reduce((acc, ret) => acc * (1 + ret), 1);\n      return product - 1;\n    }\n  }\n\n  /**\n   * Calculate annualized return\n   *\n   * @param returns - Array of returns\n   * @param periodsPerYear - Number of periods per year\n   * @param method - Return calculation method\n   * @returns Annualized return\n   */\n  static calculateAnnualizedReturn(\n    returns: number[],\n    periodsPerYear: number,\n    method: string\n  ): number {\n    if (returns.length === 0) return 0;\n\n    const years = returns.length / periodsPerYear;\n    if (years <= 0) return 0;\n\n    if (method === 'logarithmic') {\n      const sum = returns.reduce((acc, ret) => acc + ret, 0);\n      return Math.exp(sum / years) - 1;\n    } else {\n      const product = returns.reduce((acc, ret) => acc * (1 + ret), 1);\n      return Math.pow(product, 1 / years) - 1;\n    }\n  }\n\n  /**\n   * Calculate annualized volatility\n   *\n   * @param returns - Array of returns\n   * @param periodsPerYear - Number of periods per year\n   * @returns Annualized volatility\n   */\n  static calculateVolatility(returns: number[], periodsPerYear: number): number {\n    if (returns.length < 2) return 0;\n\n    const stdDev = standardDeviation(returns);\n    return stdDev * Math.sqrt(periodsPerYear);\n  }\n\n  /**\n   * Calculate Sharpe ratio\n   *\n   * @param returns - Array of returns\n   * @param riskFreeRate - Risk-free rate\n   * @param periodsPerYear - Number of periods per year\n   * @param method - Return calculation method\n   * @returns Sharpe ratio\n   */\n  static calculateSharpeRatio(\n    returns: number[],\n    riskFreeRate: number,\n    periodsPerYear: number,\n    method: string\n  ): number {\n    const annualizedReturn = this.calculateAnnualizedReturn(returns, periodsPerYear, method);\n    const volatility = this.calculateVolatility(returns, periodsPerYear);\n\n    if (volatility === 0) return 0;\n\n    return (annualizedReturn - riskFreeRate) / volatility;\n  }\n\n  /**\n   * Calculate Sortino ratio (uses only downside volatility)\n   *\n   * @param returns - Array of returns\n   * @param riskFreeRate - Risk-free rate\n   * @param periodsPerYear - Number of periods per year\n   * @param method - Return calculation method\n   * @returns Sortino ratio\n   */\n  static calculateSortinoRatio(\n    returns: number[],\n    riskFreeRate: number,\n    periodsPerYear: number,\n    method: string\n  ): number {\n    const annualizedReturn = this.calculateAnnualizedReturn(returns, periodsPerYear, method);\n\n    // Calculate downside deviation (only negative returns)\n    const downsideReturns = returns.filter(ret => ret < 0);\n    if (downsideReturns.length === 0) {\n      // If no negative returns, Sortino is undefined (return high value or Infinity)\n      return annualizedReturn > riskFreeRate ? Infinity : 0;\n    }\n\n    const downsideStdDev = standardDeviation(downsideReturns);\n    const downsideVolatility = downsideStdDev * Math.sqrt(periodsPerYear);\n\n    if (downsideVolatility === 0) return 0;\n\n    return (annualizedReturn - riskFreeRate) / downsideVolatility;\n  }\n\n  /**\n   * Calculate maximum drawdown\n   *\n   * @param prices - Array of prices in chronological order\n   * @returns Maximum drawdown as a percentage (negative value)\n   */\n  static calculateMaximumDrawdown(prices: number[]): number {\n    if (prices.length < 2) return 0;\n\n    let maxDrawdown = 0;\n    let peak = prices[0];\n\n    for (let i = 1; i < prices.length; i++) {\n      if (prices[i] > peak) {\n        peak = prices[i];\n      } else {\n        const drawdown = (prices[i] - peak) / peak;\n        if (drawdown < maxDrawdown) {\n          maxDrawdown = drawdown;\n        }\n      }\n    }\n\n    return maxDrawdown;\n  }\n\n  /**\n   * Calculate Calmar ratio (annualized return / maximum drawdown)\n   *\n   * @param returns - Array of returns\n   * @param prices - Array of prices in chronological order\n   * @param periodsPerYear - Number of periods per year\n   * @param method - Return calculation method\n   * @returns Calmar ratio\n   */\n  static calculateCalmarRatio(\n    returns: number[],\n    prices: number[],\n    periodsPerYear: number,\n    method: string\n  ): number {\n    const annualizedReturn = this.calculateAnnualizedReturn(returns, periodsPerYear, method);\n    const maxDrawdown = Math.abs(this.calculateMaximumDrawdown(prices));\n\n    if (maxDrawdown === 0) return 0;\n\n    return annualizedReturn / maxDrawdown;\n  }\n\n  /**\n   * Calculate Beta (sensitivity to benchmark/market movements)\n   *\n   * @param fundReturns - Array of fund returns\n   * @param benchmarkReturns - Array of benchmark returns (must align with fund returns)\n   * @returns Beta coefficient\n   */\n  static calculateBeta(fundReturns: number[], benchmarkReturns: number[]): number {\n    if (fundReturns.length !== benchmarkReturns.length || fundReturns.length < 2) {\n      return 0;\n    }\n\n    const fundMean = mean(fundReturns);\n    const benchmarkMean = mean(benchmarkReturns);\n\n    // Calculate covariance\n    let covariance = 0;\n    for (let i = 0; i < fundReturns.length; i++) {\n      covariance += (fundReturns[i] - fundMean) * (benchmarkReturns[i] - benchmarkMean);\n    }\n    covariance /= fundReturns.length;\n\n    // Calculate benchmark variance\n    const benchmarkVariance = standardDeviation(benchmarkReturns) ** 2;\n\n    if (benchmarkVariance === 0) return 0;\n\n    return covariance / benchmarkVariance;\n  }\n\n  /**\n   * Calculate Information Ratio (active return / tracking error)\n   *\n   * @param fundReturns - Array of fund returns\n   * @param benchmarkReturns - Array of benchmark returns (must align with fund returns)\n   * @param periodsPerYear - Number of periods per year\n   * @returns Information Ratio\n   */\n  static calculateInformationRatio(\n    fundReturns: number[],\n    benchmarkReturns: number[],\n    periodsPerYear: number\n  ): number {\n    if (fundReturns.length !== benchmarkReturns.length || fundReturns.length < 2) {\n      return 0;\n    }\n\n    // Calculate active returns (excess returns)\n    const activeReturns = fundReturns.map((fundRet, i) => fundRet - benchmarkReturns[i]);\n    const activeReturnMean = mean(activeReturns);\n\n    // Calculate tracking error (standard deviation of active returns)\n    const trackingError = standardDeviation(activeReturns) * Math.sqrt(periodsPerYear);\n\n    if (trackingError === 0) return 0;\n\n    // Annualize active return\n    const annualizedActiveReturn = activeReturnMean * periodsPerYear;\n\n    return annualizedActiveReturn / trackingError;\n  }\n\n  /**\n   * Calculate Treynor Ratio (excess return / beta)\n   *\n   * @param returns - Array of fund returns\n   * @param benchmarkReturns - Array of benchmark returns (must align with fund returns)\n   * @param riskFreeRate - Risk-free rate\n   * @param periodsPerYear - Number of periods per year\n   * @param method - Return calculation method\n   * @returns Treynor Ratio\n   */\n  static calculateTreynorRatio(\n    returns: number[],\n    benchmarkReturns: number[],\n    riskFreeRate: number,\n    periodsPerYear: number,\n    method: string\n  ): number {\n    const annualizedReturn = this.calculateAnnualizedReturn(returns, periodsPerYear, method);\n    const beta = this.calculateBeta(returns, benchmarkReturns);\n\n    if (beta === 0) return 0;\n\n    return (annualizedReturn - riskFreeRate) / beta;\n  }\n\n  /**\n   * Get periods per year for frequency\n   *\n   * @param frequency - Data frequency\n   * @returns Number of periods per year\n   */\n  static getPeriodsPerYear(frequency: string): number {\n    const mapping: Record<string, number> = {\n      daily: 252,\n      weekly: 52,\n      monthly: 12,\n      quarterly: 4,\n      annual: 1\n    };\n\n    return mapping[frequency] || 252;\n  }\n\n  /**\n   * Create empty metrics for insufficient data\n   *\n   * @param fundCode - Fund code\n   * @param sample - Sample data point for fund info\n   * @returns Empty performance metrics\n   */\n  static createEmptyMetrics(fundCode: string, sample: FundHistoryResponse): PerformanceMetrics {\n    return {\n      fundCode,\n      fundName: sample?.fundName || '',\n      fundType: sample?.fundType || FundType.YAT,\n      observations: 0,\n      cumulativeReturn: 0,\n      annualizedReturn: 0,\n      annualizedVolatility: 0,\n      sharpeRatio: 0\n    };\n  }\n}\n"]}