import {z} from 'zod' export type GetApiIndexUuidOptions = {baseUrl?: string | undefined, fetch?: typeof fetch | undefined}; export const deadline = z.object({business_days_prior: z.number().int(), deadline_type: z.enum(["calculation", "restatement"]), metrics: z.array(z.string()).optional(), next_day: z.boolean(), og_priority: z.enum(["P1", "P2", "P3"]), time_of_day: z.string()}); export const administrative = z.object({client: z.object({approved_by: z.string().optional(), owner: z.string().optional(), requested_by: z.string().optional()}).optional(), deadlines: z.array(deadline).optional(), role: z.enum(["data point", "verification", "calculation", "development", "administration"])}); export const baseDate = z.string(); export const indexBenchmark = z.object({benchmark_metric: z.string().optional(), index_metric: z.string().optional(), threshold: z.number(), ticker: z.string()}); export const levelCheckParams = z.object({max: z.number().nullable(), min: z.number().nullable()}); export const percentChangeCheckParams = z.object({max: z.number().nullable(), min: z.number().nullable()}); export const historyCheckParams = z.object({days: z.number().int().gte(0).lte(365).nullable()}); export const calculationCheck = z.array(z.union([z.object({check_type: z.literal("LEVEL_CHECK"), alert_type: z.enum(["email", "slack", "opsgenie", "fail_computation"]).optional(), enabled: z.boolean(), metric: z.string(), params: levelCheckParams}), z.object({check_type: z.literal("PERCENT_CHANGE_CHECK"), alert_type: z.enum(["email", "slack", "opsgenie", "fail_computation"]).optional(), enabled: z.boolean(), metric: z.string(), params: percentChangeCheckParams}), z.object({check_type: z.literal("HISTORY_CHECK"), alert_type: z.enum(["email", "slack", "opsgenie", "fail_computation"]).optional(), enabled: z.boolean(), metric: z.string(), params: historyCheckParams})])); export const metricsSchema = z.object({data_type: z.enum(["string", "number64", "datetime64", "int64", "bool", "object"]), description: z.string(), name: z.string(), object_schema: z.object({}).optional()}); export const isoDate = z.string(); export const freezerConfig = z.object({corax: z.boolean().optional(), fx_rates: z.boolean().optional(), prices: z.boolean().optional(), primary_index_name: z.string().optional(), rebalances: z.boolean().optional()}); export const provider = z.enum(["bloomberg", "reuters", "morningstar", "factset", "nasdaq", "wind", "secapi"]); export const identifierUUIDRef = z.object({enabled: z.boolean().optional(), name: z.string(), provider: provider}); export const merqTimestamp = z.union([z.string(), z.string(), z.string()]); export const intradayTickFilter = z.object({days_of_week: z.array(z.number().int()).optional(), end_date: merqTimestamp.optional(), end_time: z.string().optional(), exclude_holidays: z.boolean().optional(), start_date: merqTimestamp.optional(), start_time: z.string().optional()}); export const intradayPublishConfigDbTarget = z.object({active_time_ranges: z.array(intradayTickFilter).optional(), target: z.literal("db")}); export const intradayPublishConfigSecapiTarget = z.object({active_time_ranges: z.array(intradayTickFilter).optional(), target: z.literal("secapi")}); export const intradayPublishConfigBloombergTargetParams = z.object({rounding_decimals: z.number().int().optional(), ticker: z.string().optional()}); export const intradayPublishConfigBloombergTarget = z.object({active_time_ranges: z.array(intradayTickFilter).optional(), params: intradayPublishConfigBloombergTargetParams.optional(), target: z.literal("bloomberg")}); export const reutersProviderKwargsPostType = z.enum(["EOD", "RT", "EOD_AND_RT", "EOD_AND_RT_COMBINED"]); export const intradayPublishConfigReutersTargetParams = z.object({post_type: reutersProviderKwargsPostType.optional(), rounding_decimals: z.number().int().optional(), ticker: z.string().optional()}); export const intradayPublishConfigReutersTarget = z.object({active_time_ranges: z.array(intradayTickFilter).optional(), params: intradayPublishConfigReutersTargetParams.optional(), target: z.literal("reuters")}); export const intradayPublishConfig = z.record(z.string(), z.array(z.union([intradayPublishConfigDbTarget, intradayPublishConfigSecapiTarget, intradayPublishConfigBloombergTarget, intradayPublishConfigReutersTarget]))); export const alertHours = z.object({end: z.string().optional(), start: z.string().optional()}); export const intradayAlertType = z.enum(["opsgenie", "slack"]); export const intradayFlatlineAlerts = z.object({alert_hours: alertHours.optional(), alert_type: intradayAlertType.optional(), enabled: z.boolean().optional(), min_ticks: z.number().int().gte(2).optional(), window_length: z.number().int().gte(1).optional()}); export const intradayAlerting = z.object({flatline_alerts: intradayFlatlineAlerts.optional()}); export const intradayInfraTimedScaling = z.object({enabled: z.boolean().optional(), end_time_buffer: z.number().int().gte(5).lte(120).optional(), start_time_buffer: z.number().int().gte(10).lte(59).optional()}); export const intradayPreOpenWarmup = z.object({enabled: z.boolean().optional(), lead_seconds: z.number().int().gte(10).lte(3540).optional()}); export const rangePrefetch = z.object({enabled: z.boolean().optional(), max_batch_ticks: z.number().int().gte(2).lte(10).optional(), max_span_seconds: z.number().gt(0).optional(), read_timeout_seconds: z.number().gt(0).optional()}); export const intraday = z.object({publish_config: intradayPublishConfig.optional(), active_time_ranges: z.array(intradayTickFilter).optional(), alerting: intradayAlerting.optional(), calculation_max_retry_delay: z.number().int().gte(0).optional(), data_refresh_period: z.number().int().gte(0).optional(), enabled: z.boolean(), heartbeat_timeout: z.number().int().gte(1).optional(), infra_timed_scaling: intradayInfraTimedScaling.optional(), ohl_enabled: z.boolean().optional(), opening_tick_time: z.string().optional(), pre_open_warmup: intradayPreOpenWarmup.optional(), range_prefetch: rangePrefetch.optional(), resource_cpu_request: z.number().int().gte(1).optional(), resource_memory_request: z.number().int().gte(0).optional(), security_id: z.string().optional(), startup_failure_timeout: z.number().int().gte(1).optional(), summaries_read_replica: z.boolean().optional(), tick_delay: z.number().int().gte(0).optional(), ticker_period: z.number().gte(1).optional(), tzinfo: z.string()}); export const notificationConfig = z.object({email_list_uuid: z.string().optional(), emails: z.array(z.string()).optional(), enabled: z.boolean().optional()}); export const rebalFrequency = z.enum(["Annual", "Daily", "Monthly", "Quarterly", "Semi-Annual", "Weekly", "Bi-Monthly", "Intraday", "None"]); export const related = z.object({default_display: z.boolean().optional(), id: z.string(), metric: z.string().optional(), name: z.string(), type: z.enum(["security", "index"])}); export const s3Bucket = z.object({bucket: z.string(), path: z.string().optional()}); export const argumentsOrEnvVars = z.array(z.array(z.string())); export const subPod = z.object({arguments: argumentsOrEnvVars.optional(), command: z.string(), env_vars: argumentsOrEnvVars.optional(), pod_kwargs: z.object({name: z.string().optional()}).optional(), pod_type: z.string(), uuid: z.string()}); export const airflowConfig = z.object({affinity_match_expression_key: z.string().optional(), dag: z.record(z.string(), z.unknown()).optional(), description: z.string().optional(), env: z.record(z.string(), z.unknown()).optional(), pod: z.record(z.string(), z.unknown()).optional(), s3_location: s3Bucket.optional(), subpods: z.array(subPod).optional()}); export const dqmsConfig = z.object({enabled: z.boolean().optional()}); export const flatCalendarSchema = z.object({calendar_identifiers: z.array(z.string()).optional(), condition: z.enum(["any", "all", "custom"]).optional(), holidays_to_add: z.array(z.string()).optional(), holidays_to_remove: z.array(z.string()).optional(), swaps_monitor_codes: z.array(z.string()).optional(), weekmask: z.array(z.enum(["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"])).optional()}); export const calendarIdentifiers = z.object({calendar_identifiers: z.array(z.string()).optional()}); export const holidaysToAdd = z.object({holidays_to_add: z.array(z.string()).optional()}); export const nestedCalendarSchema: z.ZodType = z.object({children: z.array(z.union([calendarIdentifiers, holidaysToAdd, z.lazy(() => nestedCalendarSchema)])), operator: z.enum(["union", "intersection", "difference"]), weekmask: z.array(z.enum(["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"])).optional()}); export const holidayCalendarSpec = z.union([flatCalendarSchema, nestedCalendarSchema]); export const disseminationDestinations = z.object({email_dissapi_configs: z.array(z.object({bcc_list: z.array(z.string()).optional(), cc_list: z.array(z.string()).optional(), content: z.string().optional(), email_list: z.array(z.string()).optional(), file_keys: z.array(z.string()).optional(), recipient_list: z.array(z.string()), subject: z.string()})).optional(), s3_dissapi_configs: z.array(z.object({bucket: z.string(), file_keys: z.array(z.string()), key_prefix: z.string()})).optional(), sftp_dissapi_configs: z.array(z.object({file_keys: z.array(z.string()), sftp_ids: z.array(z.string())})).optional()}); export const indexReport = z.object({dissemination_destinations: disseminationDestinations.optional(), program_args: z.object({}).optional(), task_id: z.string().optional(), uuid: z.string()}); export const schedule = z.object({business_days_prior: z.number().int().optional(), event_driven: z.boolean().optional(), holiday_calendar: z.object({cal_type: z.string().optional(), mic: z.string().optional()}).optional(), retries: z.number().int(), retry_interval_min: z.number().int(), schedule_cron: z.string().optional(), schedule_start: z.string(), timeout_delta: z.string().optional(), triggers: z.array(z.string()).optional()}); export const runConfig = z.object({airflow_config: airflowConfig.optional(), alert_priority: z.enum(["P1", "P2", "P3", "P4", "P5"]).optional(), command: z.string().optional(), command_arguments: argumentsOrEnvVars.optional(), day_chunk_size: z.number().int().optional(), dqms: dqmsConfig.optional(), holiday_calendar: holidayCalendarSpec.optional(), index_report_uuids: z.array(z.string()).optional(), index_reports: z.union([z.array(z.string()), z.array(indexReport)]).optional(), job_enabled: z.boolean(), num_days_to_load: z.number().int(), pod_image_and_tag: z.string().optional(), schedule: schedule, state_key: z.string().min(1).optional(), tzinfo: z.string().optional()}).and(z.record(z.string(), z.unknown())); export const runConfigLabel = z.object({airflow_config: airflowConfig.optional(), alert_priority: z.enum(["P1", "P2", "P3", "P4", "P5"]).optional(), command: z.string().optional(), command_arguments: argumentsOrEnvVars.optional(), day_chunk_size: z.number().int().optional(), dqms: dqmsConfig.optional(), holiday_calendar: holidayCalendarSpec.optional(), index_report_uuids: z.array(z.string()).optional(), index_reports: z.union([z.array(z.string()), z.array(indexReport)]).optional(), job_enabled: z.boolean(), num_days_to_load: z.number().int(), pod_image_and_tag: z.string().optional(), schedule: schedule, state_key: z.string().min(1).optional(), tzinfo: z.string().optional(), label: z.string()}).and(z.record(z.string(), z.unknown())); export const indexSpec = z.object({index_class_args: z.object({}).optional(), index_class_code: z.string(), index_variables: z.object({}).optional(), version: z.number().int().optional()}); export const customCharts = z.object({chart_type: z.enum(["line", "spline", "area", "bar", "column"]).optional(), compare_mode: z.enum(["absolute", "percent"]).optional(), constructor_type: z.enum(["chart", "stockChart"]).optional(), data: z.array(z.object({array_field: z.string(), key_field: z.string(), url: z.string(), values: z.array(z.object({display_name: z.string(), path: z.string()}))})).optional(), name: z.string(), size: z.number().optional(), xlabel: z.string(), ylabel: z.string()}); export const webpage = z.object({custom_charts: z.array(customCharts).optional(), visible: z.boolean().optional()}); export const status = z.object({created_at: z.string().optional(), created_by: z.string().optional(), last_modified: z.string(), last_modified_by: z.string().optional(), locked_after: z.string().optional()}); export const indexDefinitionPatchPutGet = z.object({administrative: administrative, base_date: baseDate.optional(), base_year: z.number().int().optional(), benchmark: z.union([indexBenchmark, z.array(indexBenchmark)]).optional(), calc_freq: z.enum(["Daily", "Daily, EOD", "Daily, Real Time", "Intraday"]).optional(), calculation_check: calculationCheck.optional(), currency: z.string().optional(), custom_metrics: z.array(metricsSchema).optional(), description: z.string(), display_month: z.enum(["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]).optional(), documents: z.object({}).optional(), eod_rt_price_check: z.boolean().optional(), excess_strategy: z.literal("keep_in_cash").optional(), family: z.string().optional(), family_codes: z.array(z.string()).optional(), family_description: z.string().optional(), fill_missing_data: z.boolean().optional(), first_value_date: isoDate.optional(), freezer_config: freezerConfig.optional(), identifiers: z.array(identifierUUIDRef).optional(), intraday: intraday.optional(), launch_date: z.string(), methodology: z.string().optional(), month: z.number().int().optional(), name: z.string(), namespace: z.string(), notify_configuration: notificationConfig.optional(), plot_metric: z.string().optional(), portfolio_allocation_display: z.boolean().optional(), portfolio_display: z.object({fields: z.array(z.object({display_name: z.string().optional(), field_name: z.string().optional()})).optional()}).optional(), portfolio_handler_id: z.string().optional(), rebal_freq: rebalFrequency.optional(), related: z.array(related).optional(), run_configuration: runConfig.optional(), run_configurations: z.array(runConfigLabel).optional(), sales_force_deal_id: z.string().optional(), spec: indexSpec.optional(), stage: z.enum(["prod", "test", "development", "backtest", "inqubator"]), tags: z.string().optional(), title: z.string(), webpage: webpage.optional(), weighting_method: z.enum(["Other", "Equal"]).optional(), id: z.string(), status: status}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Returns the MerQube index with this uuid * * GET /index/{uuid} */ export const getApiIndexUuid = async (options?: GetApiIndexUuidOptions) => { const {baseUrl = "https://api.merqube.com", fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") const url = `${baseUrl.replace(/\/+$/, '')}/index/${encodeURIComponent(String(args.uuid))}${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "GET", headers}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(indexDefinitionPatchPutGet, await res.json()) };