82 lines
3.3 KiB
C#
82 lines
3.3 KiB
C#
using System.Collections.Generic;
|
|
using System.Threading.Tasks;
|
|
using QuantEngine.Core.Domain;
|
|
using QuantEngine.Core.Interfaces;
|
|
|
|
namespace QuantEngine.Application.Services
|
|
{
|
|
public class FormulaService
|
|
{
|
|
private readonly IPostgresqlHistoryStore _historyStore;
|
|
private readonly DecisionLearningService _learningService;
|
|
|
|
public FormulaService(IPostgresqlHistoryStore historyStore, DecisionLearningService learningService)
|
|
{
|
|
_historyStore = historyStore;
|
|
_learningService = learningService;
|
|
}
|
|
|
|
public TimingDecisionResult ComputeTimingDecision(Dictionary<string, object> ctx)
|
|
=> FormulaEngine.ComputeTimingDecision(RequireContext(ctx));
|
|
|
|
public SellDecisionResult ComputeSellDecision(Dictionary<string, object> ctx)
|
|
=> FormulaEngine.ComputeSellDecision(RequireContext(ctx));
|
|
|
|
public FinalDecisionResult ComputeFinalDecision(Dictionary<string, object> ctx)
|
|
=> FormulaEngine.ComputeFinalDecision(RequireContext(ctx));
|
|
|
|
public async Task<Guid> ComputeAndRecordFinalDecisionAsync(
|
|
Dictionary<string, object> ctx,
|
|
string decisionKey,
|
|
string instrumentId,
|
|
string sourceVersion,
|
|
IEnumerable<FactorEvidenceInput> factorEvidence)
|
|
{
|
|
var normalizedContext = RequireContext(ctx);
|
|
var decision = ComputeFinalDecision(normalizedContext);
|
|
return await _learningService.RecordDecisionAsync(
|
|
RequireValue(decisionKey, nameof(decisionKey)),
|
|
DateTimeOffset.UtcNow,
|
|
RequireValue(instrumentId, nameof(instrumentId)),
|
|
decision.FinalAction,
|
|
"PASS",
|
|
Convert.ToDecimal(decision.PriorityScore),
|
|
RequireValue(sourceVersion, nameof(sourceVersion)),
|
|
factorEvidence,
|
|
new { context_keys = normalizedContext.Keys.OrderBy(key => key).ToArray() },
|
|
new { formula = "FormulaEngine.ComputeFinalDecision", source_version = sourceVersion });
|
|
}
|
|
|
|
public CashShortfallResult ComputeCashShortfallHarness(
|
|
Dictionary<string, object> asResult,
|
|
double totalAsset,
|
|
Dictionary<string, object> cashFloorInfo,
|
|
double mrsScore)
|
|
=> FormulaEngine.ComputeCashShortfallHarness(asResult, totalAsset, cashFloorInfo, mrsScore);
|
|
|
|
public CashRecoveryPlanResult ComputeCashRecoveryOptimizer(
|
|
List<Dictionary<string, object>> sellCandidates,
|
|
double cashShortfallMinKrw)
|
|
=> FormulaEngine.ComputeCashRecoveryOptimizer(sellCandidates, cashShortfallMinKrw);
|
|
|
|
public Task<int> AppendFormulaRunAsync(string formulaName, Dictionary<string, object?> payload)
|
|
=> _historyStore.AppendAsync($"formula_{RequireValue(formulaName, nameof(formulaName))}_history", payload);
|
|
|
|
private static Dictionary<string, object> RequireContext(Dictionary<string, object> ctx)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(ctx);
|
|
return ctx;
|
|
}
|
|
|
|
private static string RequireValue(string value, string parameterName)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(value))
|
|
{
|
|
throw new ArgumentException("Value is required.", parameterName);
|
|
}
|
|
|
|
return value.Trim();
|
|
}
|
|
}
|
|
}
|