namespace QuantEngine.Application.Services; /// /// 데이터 정규화 유틸 — Python kis_data_collection_v1.py 라인 76-99 포팅 /// public static class DataNormalizationHelper { /// /// 값을 double로 강제 변환 (Python _coerce_float 대응) /// null/"" → null, "1,234.56%" → 1234.56 /// public static double? CoerceFloat(object? value) { if (value == null || string.IsNullOrEmpty(value.ToString())) return null; try { var str = value.ToString()?.Replace(",", "").Replace("%", "").Trim() ?? ""; if (string.IsNullOrEmpty(str)) return null; return double.Parse(str); } catch { return null; } } /// /// 재귀적으로 첫 번째 non-null 값 찾기 (Python _find_first_value 대응) /// public static object? FindFirstValue(Dictionary? payload, params string[] keys) { if (payload == null) return null; var stack = new Stack(); stack.Push(payload); while (stack.Count > 0) { var item = stack.Pop(); if (item is Dictionary dict) { foreach (var key in keys) { if (dict.TryGetValue(key, out var value) && value != null && !string.IsNullOrEmpty(value.ToString())) return value; } foreach (var value in dict.Values) { if (value != null) stack.Push(value); } } else if (item is List list) { foreach (var value in list) { if (value != null) stack.Push(value); } } } return null; } /// /// KST 현재 시각을 ISO 8601 형식으로 반환 /// public static string KstNowIso() { var kst = TimeZoneInfo.FindSystemTimeZoneById("Korea Standard Time"); return TimeZoneInfo.ConvertTime(DateTime.Now, kst).ToString("o"); } }