core services and tests

This commit is contained in:
2026-06-26 18:06:36 +09:00
parent e0508324e5
commit 1e6bf702bc
12 changed files with 675 additions and 8 deletions
@@ -30,4 +30,62 @@ public class FormulaEngineTests
Assert.NotNull(result);
Assert.Equal("BUY_BREAKOUT_PILOT_ONLY", result.Action);
}
[Fact]
public void ComputeSellDecisionProducesExitTrimWhenRiskWindowIsOpen()
{
var ctx = new Dictionary<string, object>
{
{ "close", 100.0 },
{ "profitPct", 31.0 },
{ "tp1Price", 108.0 },
{ "tp2Price", 112.0 },
{ "timingAction", "BUY_STAGE1_READY" },
{ "atr20", 4.0 }
};
var result = FormulaEngine.ComputeSellDecision(ctx);
Assert.Equal("PROFIT_TRIM_35", result.Action);
Assert.Equal(35, result.RatioPct);
Assert.Equal("SIGNAL_CONFIRMED", result.Validation);
}
[Fact]
public void ComputeFinalDecisionPromotesSellReadyWhenSellSignalIsConfirmed()
{
var ctx = new Dictionary<string, object>
{
{ "sellAction", "TRIM_35" },
{ "sellValidation", "SIGNAL_CONFIRMED" },
{ "timingScoreEntry", 72.0 },
{ "timingScoreExit", 15.0 }
};
var result = FormulaEngine.ComputeFinalDecision(ctx);
Assert.Equal("SELL_READY", result.FinalAction);
Assert.Equal(10, result.ActionPriority);
Assert.Equal("RULE_ENGINE", result.DecisionSource);
}
[Fact]
public void ComputeCashShortfallHarnessCalculatesTargetAndShortfall()
{
var asResult = new Dictionary<string, object>
{
{ "settlementCashD2Krw", 10_000_000.0 }
};
var cashFloor = new Dictionary<string, object>
{
{ "minPct", 15.0 }
};
var result = FormulaEngine.ComputeCashShortfallHarness(asResult, 100_000_000.0, cashFloor, 6.0);
Assert.Equal(10.0, result.CashCurrentPctD2);
Assert.Equal(15.0, result.CashTargetPct);
Assert.Equal(5_000_000.0, result.CashShortfallMinKrw);
Assert.Equal(5_000_000.0, result.CashShortfallTargetKrw);
}
}