SoftTraderBackend/ServiceHandler/TrailingPriceEvaluator.cs
2026-03-21 09:16:59 -04:00

74 lines
2.0 KiB
C#

using System.Text.Json;
using Backend.DatabaseHandler;
using Backend.Interface;
namespace Backend.ServiceHandler;
public sealed class TrailingPriceEvaluator : IAlertEvaluator
{
public string AlertType => "trailing_price";
public Task<AlertEvaluation> EvaluateAsync(AlertRecord alert, MarketDataService marketData)
{
var parameters = JsonSerializer.Deserialize<TrailingPriceParameters>(alert.Parameters)
?? throw new InvalidOperationException($"Invalid parameters for alert {alert.Id}");
var snapshot = marketData.GetLiveQuote(alert.Symbol);
if (!snapshot.LastPrice.HasValue)
{
return Task.FromResult(new AlertEvaluation { Triggered = false });
}
double price = snapshot.LastPrice.Value;
var state = JsonSerializer.Deserialize<TrailingPriceState>(alert.LastState)
?? new TrailingPriceState();
bool triggered;
if (parameters.Direction.Equals("bullish", StringComparison.OrdinalIgnoreCase))
{
if (!state.PeakPrice.HasValue || price > state.PeakPrice.Value)
state.PeakPrice = price;
double dropPercent = (state.PeakPrice.Value - price) / state.PeakPrice.Value * 100.0;
triggered = dropPercent >= parameters.TrailPercent;
}
else
{
if (!state.TroughPrice.HasValue || price < state.TroughPrice.Value)
state.TroughPrice = price;
double risePercent = state.TroughPrice.Value == 0
? 0
: (price - state.TroughPrice.Value) / state.TroughPrice.Value * 100.0;
triggered = risePercent >= parameters.TrailPercent;
}
string updatedState = JsonSerializer.Serialize(new
{
peakPrice = state.PeakPrice,
troughPrice = state.TroughPrice,
lastPrice = price
});
return Task.FromResult(new AlertEvaluation
{
Triggered = triggered,
UpdatedLastState = updatedState
});
}
private sealed class TrailingPriceParameters
{
public string Direction { get; set; } = string.Empty;
public double TrailPercent { get; set; }
}
private sealed class TrailingPriceState
{
public double? PeakPrice { get; set; }
public double? TroughPrice { get; set; }
}
}