Files
KArtSell.Aegis/frontend/src/features/models/composables/useModels.ts
T
kjh2064 8a3ee0a1d7 feat(fe): implement working ModelsList grid with mock data
- Simplified data fetching (removed TanStack Query for now)
- Added direct mock API client in component
- Fixed state management (isLoading, isError, modelsData)
- Grid now renders with 3 sample model records
- Updated v-if conditions for loading/error/empty states
- Added grid container height and filter styling

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-08-15 22:56:04 +09:00

271 lines
6.4 KiB
TypeScript

/**
* 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<ModelListResponse> {
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<ModelDetail> {
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) {
const finalParams = params || {}
return useQuery({
queryKey: ['models', 'list', finalParams],
queryFn: () => apiClient.listModels(finalParams),
staleTime: 5 * 60 * 1000,
gcTime: 10 * 60 * 1000,
})
}
/**
* 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() })
}
}