본문으로 건너뛰기

SOL CoD 시뮬레이션 정확도 산정 가이드

본 문서는 SOL 예측 시뮬레이션(Chain of Debate 기반)의 정확도 산정 방식, 저장 구조, CQRS 흐름, API 사용법을 정리합니다.

개요

  • 목표: 특정 치료 일차(dayIndex) D의 SOL을 예측하고, 이후 실제 SOL과 비교하여 정확도를 관리합니다.
  • 데이터 사용 규칙: D일차 예측은 D−1일까지의 데이터(수면 로그/설문/학습/CRM 등)만 사용합니다.
  • 기본 범위: 기본 시뮬레이션은 8일차부터 시작(1–7일의 기록으로 8일차 예측)하며, 필요 시 metadata.simulationRange로 조정합니다.

데이터 저장 구조(Prisma, private 스키마)

  • simulation_sessions

    • 세션 메타/진행 상태/집계 메트릭(정확도/합의/성능) 저장
    • 주요 필드: status, totalPredictions, completedPredictions, accuracyMae, accuracyRmse, accuracyMape, accuracyWithin15min, averageDebateRounds, averageConsensusScore, totalExecutionTime
  • simulation_predictions

    • 일차별 예측 결과 저장(예측 점수 및 신뢰도/합의/토론 지표 포함)
    • 주요 필드: dayIndex, predictedSOL, actualSOL?, confidenceScore, absoluteError?, percentageError?, squaredError?, isWithinThreshold?, participantAgents[], consensusScore, debateRounds, executionTimeMs, dataQualityScore, agentPredictions{}, analysisEvidence{}
  • simulation_comparisons

    • 예측 vs 실제 비교 행 단위 저장(예측별 1행, upsert)
    • 주요 필드: simulationPredictionId(unique), comparisonDate, predictedSOL, actualSOL, absoluteError, relativeError(%), isWithinThreshold, thresholdMinutes
  • simulation_debate_session / simulation_debate_round / simulation_expert_opinion

    • CoD 토론 이력(세션/라운드/전문가 의견) 저장

예측 단위 정확도 산정(단일 dayIndex)

SimulationPrediction 도메인 엔티티가 실제값을 설정하면 정확도 지표를 계산합니다.

  • 실제값 설정: prediction.setActualSOL(actualSOL)

  • 계산 지표

    • 절대오차(Absolute Error): |predictedSOL − actualSOL| (분)
    • 백분율오차(Percentage Error): absoluteError / actualSOL × 100 (actual=0 특례 처리)
    • 제곱오차(Squared Error): (predictedSOL − actualSOL)^2
    • 임계 내 정확도: absoluteError ≤ 15분 → isWithinThreshold = true
  • 예측 품질/등급

    • getPredictionQuality()가 종합 점수와 등급을 산출합니다.
    • 구성(가중치): 정확도 40% + 신뢰도(confidence) 30% + 데이터품질 20% + 토론품질 10%
    • 결과: qualityScore(0–100), accuracyGrade(A/B/C/D/F)

참고: 임계 15분은 기본값이며, 비교 커맨드 옵션으로 다른 임계 구성을 적용할 수 있습니다.

세션 단위 정확도 산정(집계)

예측들이 생성된 후, CompareSimulationResultsCommand로 실제값을 주입해 비교/집계를 수행합니다.

  • 입력: comparisonData[] = [{ simulationDate: 'YYYY-MM-DD', actualSOL: number, ... }]
  • 처리: 각 예측에 실제값을 반영하고, 오차 지표를 계산하여 simulation_comparisons에 upsert 저장
  • 집계 지표(세션 업데이트)
    • MAE(Mean Absolute Error)
    • RMSE(Root Mean Square Error)
    • MAPE(Mean Absolute Percentage Error)
    • ±15분 이내 비율(withinThresholdRate)
    • 등급 분포(A/B/C/D/F)

비교 결과는 GetSimulationResultsQuery로 조회 시 summarycomparisons에 포함됩니다.

처리 흐름(요약)

  1. RunSequentialSimulationCommand 실행
  • dayIndex 범위(기본 8–42)를 순차 실행
  • D일차 예측은 D−1일까지의 데이터로 수행
  • simulation_predictions에 예측 저장(신뢰도/합의/토론 지표 포함)
  1. 실제값 비교: CompareSimulationResultsCommand
  • 예측 대상 날짜별 실제 SOL을 입력
  • 각 예측에 actualSOL 설정 → 오차 계산 → simulation_comparisons upsert
  • 세션 메트릭(MAE/RMSE/MAPE/±15분)을 업데이트
  1. 결과 조회: GetSimulationResultsQuery
  • 세션 메타/메트릭 + 예측 목록 + 비교 목록을 옵션에 따라 반환

CQRS/명령·쿼리 예시

RunSequentialSimulationCommand

new RunSequentialSimulationCommand(
userId,
'My SOL Backtest',
userCycleId, // 미지정 시 최신 사이클
SimulationType.BACKTESTING,
{
simulationRange: { startDayIndex: 8, endDayIndex: 42 },
description: 'Backtesting with CoD'
}
)

CompareSimulationResultsCommand

new CompareSimulationResultsCommand(
sessionId,
userId,
[
{ simulationDate: '2024-07-10', actualSOL: 28 },
{ simulationDate: '2024-07-11', actualSOL: 35 },
// ...
],
{
accuracyThresholds: { excellent: 5, good: 10, acceptable: 15 },
updateSessionMetrics: true,
overwriteExisting: false
}
)

API 엔드포인트(Universal API)

  • POST /simulation/start

    • 본문 DTO: userId, sessionName, userCycleId?, description?
    • 내부적으로 RunSequentialSimulationCommand 실행
  • GET /simulation/results/:sessionId?userId=...&includePredictions=true&includeComparisons=true&includeMetrics=true

    • 내부적으로 GetSimulationResultsQuery 실행
    • 세션 메타/예측/비교/요약 메트릭 반환

비교 실행용 API는 별도 공개되지 않았으며, 내부 작업 또는 배치에서 CQRS로 호출합니다(필요 시 노출 가능).

임계값/등급 규칙

  • 기본 임계: ±15분(개별 예측 isWithinThreshold 산정에 사용)
  • 비교 등급(A–F, 리포트용): 기본값은 다음 기준(옵션으로 조정 가능)
    • A ≤ 5분, B ≤ 10분, C ≤ 15분, D ≤ 30분, F > 30분

날짜 매핑(dayIndex → date)

  • 예측 생성 시에는 실제 치료 시작일/타임존을 반영해 dayIndexsimulationDate를 일관되게 관리합니다.
  • 비교 시 입력되는 simulationDate는 해당 예측의 대상 날짜와 매칭되어야 합니다.
  • 향후 모든 비교 경로가 DayIndexConversionService를 통해 확정적인 매핑을 사용하도록 점진 개선 중입니다.

참고 구현 위치

  • Handlers

    • 순차 시뮬레이션: RunSequentialSimulationHandler
    • 비교/집계: CompareSimulationResultsHandler
    • 결과 조회: GetSimulationResultsHandler
  • Repository(Prisma)

    • PrismaSimulationRepository.savePrediction / .saveComparison / .findComparisonsBySessionId
    • 세션 메트릭 업데이트: .saveSession

예시: simulation_comparisons 레코드

{
"simulationSessionId": "<session-uuid>",
"simulationPredictionId": "<prediction-uuid>",
"comparisonDate": "2024-07-10",
"predictedSOL": 31,
"actualSOL": 28,
"absoluteError": 3,
"relativeError": 10.71,
"isWithinThreshold": true,
"thresholdMinutes": 15,
"createdAt": "2024-07-10T10:00:00.000Z"
}

요약

  • 개별 예측은 absoluteError/percentageError/isWithinThreshold로 정확도를 표시하고, getPredictionQuality()로 종합 등급을 부여합니다.
  • 세션 단위로 MAE/RMSE/MAPE/±15분 비율 및 등급 분포를 집계하여 정확도 트렌드와 성능을 추적합니다.
  • 비교 데이터는 simulation_comparisons에 영구 저장되어 재현성과 감사 가능성을 보장합니다.