/** * Composable: useModels * TanStack Query integration for model data fetching */ import { useQuery, useMutation, useQueryClient } from '@tanstack/vue-query' import { ref } from 'vue' export type ModelPhase = | 'Freeze' | 'Mature' | 'Score' | 'Diagnose' | 'Hypothesis' | 'Challenger' | 'Validate' | 'Review' | 'Manual Activation' export interface Model { modelId: string name: string phase: ModelPhase active: boolean lastValidation: string pbo: number dsr: number returnMtd: number createdAt: string } export interface ModelDetail extends Model { description: string updatedAt: string oos: number validationHistory: ValidationEntry[] configuration: { lookbackPeriod: number rebalanceFrequency: string riskLimit: number maxPositions: number minLiquidityDays: number } } export interface ValidationEntry { date: string phase: ModelPhase pbo: number dsr: number oos: number status: 'approved' | 'rejected' } export interface ModelListParams { page?: number pageSize?: number search?: string phase?: string active?: boolean } export interface ModelListResponse { items: Model[] total: number page: number pageSize: number } // Mock API client (replace with actual API calls) const apiClient = { async listModels(params: ModelListParams): Promise { await new Promise(resolve => setTimeout(resolve, 300)) const items: Model[] = [ { modelId: '00000000-0000-0000-0000-000000000001', name: 'Alpha Strategy v1', phase: 'Validate', active: false, lastValidation: '2026-08-10', pbo: 15.2, dsr: 96.5, returnMtd: 12.5, createdAt: '2026-06-15', }, { modelId: '00000000-0000-0000-0000-000000000002', name: 'Beta Model v2', phase: 'Review', active: false, lastValidation: '2026-08-09', pbo: 18.3, dsr: 94.2, returnMtd: 8.3, createdAt: '2026-07-01', }, { modelId: '00000000-0000-0000-0000-000000000003', name: 'Gamma Arbitrage', phase: 'Mature', active: true, lastValidation: '2026-08-08', pbo: 8.5, dsr: 98.1, returnMtd: 18.7, createdAt: '2026-05-10', }, ] return { items: items.slice(0, params.pageSize || 50), total: items.length, page: params.page || 1, pageSize: params.pageSize || 50, } }, async getModelDetail(modelId: string): Promise { await new Promise(resolve => setTimeout(resolve, 200)) return { modelId, name: 'Alpha Strategy v1', description: 'Quantitative trading strategy based on technical analysis', phase: 'Validate', active: false, lastValidation: '2026-08-10', pbo: 15.2, dsr: 96.5, oos: 1.8, returnMtd: 12.5, createdAt: '2026-06-15', updatedAt: '2026-08-10', validationHistory: [ { date: '2026-08-10', phase: 'Validate', pbo: 15.2, dsr: 96.5, oos: 1.8, status: 'approved', }, { date: '2026-08-05', phase: 'Review', pbo: 16.1, dsr: 95.2, oos: 2.1, status: 'approved', }, ], configuration: { lookbackPeriod: 252, rebalanceFrequency: 'daily', riskLimit: 2.0, maxPositions: 20, minLiquidityDays: 10, }, } }, async activateModel(modelId: string) { await new Promise(resolve => setTimeout(resolve, 500)) return { modelId, active: true } }, async deactivateModel(modelId: string) { await new Promise(resolve => setTimeout(resolve, 500)) return { modelId, active: false } }, async transitionPhase(modelId: string, newPhase: ModelPhase) { await new Promise(resolve => setTimeout(resolve, 500)) return { modelId, phase: newPhase } }, } // Query key factories export const modelQueryKeys = { all: ['models'] as const, lists: () => [...modelQueryKeys.all, 'list'] as const, list: (params: ModelListParams) => [...modelQueryKeys.lists(), params] as const, details: () => [...modelQueryKeys.all, 'detail'] as const, detail: (modelId: string) => [...modelQueryKeys.details(), modelId] as const, } /** * Fetch list of models with pagination */ export function useModelsList(params: ModelListParams = {}) { return useQuery({ queryKey: modelQueryKeys.list(params), queryFn: () => apiClient.listModels(params), staleTime: 5 * 60 * 1000, // 5 minutes gcTime: 10 * 60 * 1000, // 10 minutes }) } /** * Fetch single model detail */ export function useModelDetail(modelId: string) { return useQuery({ queryKey: modelQueryKeys.detail(modelId), queryFn: () => apiClient.getModelDetail(modelId), enabled: !!modelId, staleTime: 5 * 60 * 1000, gcTime: 10 * 60 * 1000, }) } /** * Activate a model (mutation) */ export function useActivateModel() { const queryClient = useQueryClient() return useMutation({ mutationFn: (modelId: string) => apiClient.activateModel(modelId), onSuccess: (data) => { // Invalidate model detail and list queryClient.invalidateQueries({ queryKey: modelQueryKeys.detail(data.modelId) }) queryClient.invalidateQueries({ queryKey: modelQueryKeys.lists() }) }, }) } /** * Deactivate a model (mutation) */ export function useDeactivateModel() { const queryClient = useQueryClient() return useMutation({ mutationFn: (modelId: string) => apiClient.deactivateModel(modelId), onSuccess: (data) => { queryClient.invalidateQueries({ queryKey: modelQueryKeys.detail(data.modelId) }) queryClient.invalidateQueries({ queryKey: modelQueryKeys.lists() }) }, }) } /** * Transition model to next phase (mutation) */ export function useTransitionPhase() { const queryClient = useQueryClient() return useMutation({ mutationFn: ({ modelId, phase }: { modelId: string; phase: ModelPhase }) => apiClient.transitionPhase(modelId, phase), onSuccess: (data) => { queryClient.invalidateQueries({ queryKey: modelQueryKeys.detail(data.modelId) }) queryClient.invalidateQueries({ queryKey: modelQueryKeys.lists() }) }, }) } /** * Refetch models list */ export function useRefreshModels() { const queryClient = useQueryClient() return async () => { await queryClient.refetchQueries({ queryKey: modelQueryKeys.lists() }) } }