feat: add quant engine WBS verification harness

This commit is contained in:
2026-07-12 10:58:22 +09:00
parent a274ef448a
commit e7d1069222
39 changed files with 2888 additions and 287 deletions
@@ -1,6 +1,7 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.Logging;
using QuantEngine.Core.Interfaces;
using QuantEngine.Application.Interfaces;
using QuantEngine.Application.Services;
@@ -13,19 +14,20 @@ public class KisDataCollectionOrchestrator : ICollectionOrchestrator
private readonly ICollectionRepository _repository;
private readonly PriceDataNormalizer _normalizer;
private readonly SourcePriorityResolver _priorityResolver;
// Logging removed for simplicity
private readonly ILogger<KisDataCollectionOrchestrator> _logger;
public KisDataCollectionOrchestrator(
IKisApiClient kisApiClient,
ICollectionRepository repository,
PriceDataNormalizer normalizer,
SourcePriorityResolver priorityResolver)
SourcePriorityResolver priorityResolver,
ILogger<KisDataCollectionOrchestrator> logger)
{
_kisApiClient = kisApiClient;
_repository = repository;
_normalizer = normalizer;
_priorityResolver = priorityResolver;
_logger = logger;
}
public async Task<CollectionRunResult> RunCollectionAsync(string runId, string account, List<string> tickers)
@@ -42,7 +44,7 @@ public class KisDataCollectionOrchestrator : ICollectionOrchestrator
try
{
// Log: skipped
_logger.LogInformation("Starting collection run {RunId}", runId);
var kisSource = new KisApiPriceSource(_kisApiClient);
var rows = new List<Dictionary<string, object>>();
@@ -53,9 +55,9 @@ public class KisDataCollectionOrchestrator : ICollectionOrchestrator
{
try
{
// Log: skipped
_logger.LogInformation("Collecting ticker {Ticker} (run {RunId})", ticker, runId);
var kisResult = await kisSource.GetPriceDataAsync(ticker, account);
var seedRow = new Dictionary<string, object> { { "Ticker", ticker } };
var (normalized, provenance) = _normalizer.NormalizeCollectionRow(seedRow, kisResult, null, false);
@@ -80,7 +82,7 @@ public class KisDataCollectionOrchestrator : ICollectionOrchestrator
}
catch (Exception ex)
{
// Log: skipped
_logger.LogWarning(ex, "Collection failed for {Ticker} (run {RunId})", ticker, runId);
result.ErrorCount++;
errors.Add(new Dictionary<string, object>
{
@@ -116,33 +118,64 @@ public class KisDataCollectionOrchestrator : ICollectionOrchestrator
TotalErrors: result.ErrorCount
));
// Output JSON file
var outputPath = Path.Combine(Path.GetTempPath(), "kis_data_collection_v1.json");
// Determine gate status
var gate = result.SuccessCount == 0 ? "FAIL"
: result.ErrorCount == 0 ? "PASS"
: result.ErrorCount < result.SuccessCount * 0.1 ? "PASS"
: "PASS_WITH_WARNINGS";
// Output JSON file to <repo>/Temp/kis_dotnet_collection_v1.json
var outputPath = GetOutputPath();
var outputData = new
{
formula_id = "KIS_DATA_COLLECTION_V1",
formula_id = "KIS_DOTNET_COLLECTION_V1",
gate = gate,
run_id = runId,
started_at = startedAt,
finished_at = finishedAt,
row_count = rows.Count,
source_counts = sourceCounts,
errors = errors,
rows = rows
summary = new
{
success_count = result.SuccessCount,
error_count = result.ErrorCount,
source_counts = sourceCounts
}
};
File.WriteAllText(outputPath, JsonSerializer.Serialize(outputData, new JsonSerializerOptions { WriteIndented = true }));
// Log: skipped
_logger.LogInformation("Collection run {RunId} finished with status {Status}: {Success} ok, {Errors} errors",
runId, result.Status, result.SuccessCount, result.ErrorCount);
return result;
}
catch (Exception ex)
{
// Log: skipped
_logger.LogError(ex, "Collection run {RunId} failed with exception", runId);
result.Status = "FAILED";
result.FinishedAt = DataNormalizationHelper.KstNowIso();
result.ErrorMessage = ex.Message;
return result;
}
}
private static string GetOutputPath()
{
var baseDir = AppContext.BaseDirectory;
var current = new DirectoryInfo(baseDir);
while (current != null)
{
if (Directory.Exists(Path.Combine(current.FullName, ".git"))
|| File.Exists(Path.Combine(current.FullName, "GatherTradingData.json")))
{
var tempDir = Path.Combine(current.FullName, "Temp");
Directory.CreateDirectory(tempDir);
return Path.Combine(tempDir, "kis_dotnet_collection_v1.json");
}
current = current.Parent;
}
return Path.Combine(Path.GetTempPath(), "kis_dotnet_collection_v1.json");
}
}