refactor(dotnet): centralize domain numeric guards
This commit is contained in:
@@ -28,6 +28,9 @@ namespace QuantEngine.Core.Domain
|
||||
|
||||
public static class ExitDecisions
|
||||
{
|
||||
private static bool IsValidNumber(double? value)
|
||||
=> value.HasValue && !double.IsNaN(value.Value) && !double.IsInfinity(value.Value);
|
||||
|
||||
public static StopPriceResult ComputeStopPriceCore(
|
||||
double? entryPrice,
|
||||
double? atr20,
|
||||
@@ -36,7 +39,7 @@ namespace QuantEngine.Core.Domain
|
||||
{
|
||||
var result = new StopPriceResult();
|
||||
|
||||
if (!entryPrice.HasValue)
|
||||
if (!IsValidNumber(entryPrice))
|
||||
{
|
||||
result.StopPrice = null;
|
||||
result.StopPriceStatus = "NO_STOP_PRICE";
|
||||
@@ -44,38 +47,45 @@ namespace QuantEngine.Core.Domain
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!atr20.HasValue && !atrMultiplier.HasValue)
|
||||
if (!IsValidNumber(atr20) && !IsValidNumber(atrMultiplier))
|
||||
{
|
||||
result.StopPrice = entryPrice.Value * 0.92;
|
||||
result.StopPrice = entryPrice.GetValueOrDefault() * 0.92;
|
||||
result.StopPriceStatus = "DATA_MISSING — 하네스 업데이트 필요";
|
||||
result.DataMissing.Add("atr20");
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!atrMultiplier.HasValue && (!currentPrice.HasValue || currentPrice.Value == 0))
|
||||
var hasCurrentPrice = IsValidNumber(currentPrice) && currentPrice!.Value != 0;
|
||||
|
||||
if (!IsValidNumber(atrMultiplier) && !hasCurrentPrice)
|
||||
{
|
||||
result.StopPrice = entryPrice.Value * 0.92;
|
||||
result.StopPrice = entryPrice.GetValueOrDefault() * 0.92;
|
||||
result.StopPriceStatus = "DATA_MISSING — 하네스 업데이트 필요";
|
||||
if (!atr20.HasValue) result.DataMissing.Add("atr20");
|
||||
if (!currentPrice.HasValue || currentPrice.Value == 0) result.DataMissing.Add("current_price");
|
||||
if (!IsValidNumber(atr20)) result.DataMissing.Add("atr20");
|
||||
if (!hasCurrentPrice) result.DataMissing.Add("current_price");
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!atrMultiplier.HasValue)
|
||||
if (!IsValidNumber(atrMultiplier))
|
||||
{
|
||||
double atr20Pct = (atr20!.Value / currentPrice!.Value) * 100;
|
||||
var atr20Value = atr20.GetValueOrDefault();
|
||||
var currentPriceValue = currentPrice.GetValueOrDefault();
|
||||
double atr20Pct = (atr20Value / currentPriceValue) * 100;
|
||||
atrMultiplier = atr20Pct >= 8 ? 2.0 : 1.5;
|
||||
result.Atr20Pct = atr20Pct;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Atr20Pct = (currentPrice.HasValue && currentPrice.Value != 0)
|
||||
? (atr20!.Value / currentPrice.Value) * 100
|
||||
result.Atr20Pct = hasCurrentPrice
|
||||
? (atr20.GetValueOrDefault() / currentPrice.GetValueOrDefault()) * 100
|
||||
: (double?)null;
|
||||
}
|
||||
|
||||
var entryPriceValue = entryPrice.GetValueOrDefault();
|
||||
var atr20FinalValue = atr20.GetValueOrDefault();
|
||||
var atrMultiplierValue = atrMultiplier.GetValueOrDefault();
|
||||
result.AtrMultiplier = atrMultiplier;
|
||||
result.StopPrice = Math.Max(entryPrice.Value * 0.92, entryPrice.Value - atr20!.Value * atrMultiplier.Value);
|
||||
result.StopPrice = Math.Max(entryPriceValue * 0.92, entryPriceValue - atr20FinalValue * atrMultiplierValue);
|
||||
result.StopPriceStatus = "PASS";
|
||||
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user