using Managing.Core; using Managing.Domain.Candles; using Managing.Domain.Shared.Rules; using Managing.Domain.Strategies.Base; using Skender.Stock.Indicators; using static Managing.Common.Enums; namespace Managing.Domain.Strategies.Context; public class StDevContext : Indicator { public List Signals { get; set; } public StDevContext(string name, int period) : base(name, IndicatorType.StDev) { Signals = new List(); Period = period; } public override List Run() { if (Candles.Count <= Period) { return null; } try { var stDev = Candles.GetStdDev(Period.Value).ToList(); var stDevCandles = MapStDev(stDev, Candles.TakeLast(Period.Value)); if (stDev.Count == 0) return null; var lastCandle = stDevCandles.Last(); var zScore = lastCandle.ZScore ?? 0; // Determine confidence based on Z-score ranges // Lower absolute Z-score = more normal volatility = higher confidence for trading // Higher absolute Z-score = more extreme volatility = lower confidence for trading Confidence confidence; if (Math.Abs(zScore) <= 0.5) { // Very low volatility - ideal conditions for trading confidence = Confidence.High; } else if (Math.Abs(zScore) <= 1.0) { // Normal volatility - good conditions for trading confidence = Confidence.Medium; } else if (Math.Abs(zScore) <= 1.5) { // Elevated volatility - caution advised confidence = Confidence.Low; } else { // High volatility - trading not recommended confidence = Confidence.None; } // Context strategies always return TradeDirection.None // The confidence level indicates the quality of market conditions AddSignal(lastCandle, TradeDirection.None, confidence); return Signals.Where(s => s.Confidence != Confidence.None).OrderBy(s => s.Date).ToList(); } catch (RuleException) { return null; } } public override IndicatorsResultBase GetStrategyValues() { var test = new IndicatorsResultBase() { StdDev = Candles.GetStdDev(Period.Value).ToList() }; return test; } private List MapStDev(List stDev, IEnumerable candles) { var sctList = new List(); foreach (var candle in candles) { var currentSct = stDev.Find(candle.Date); if (currentSct != null) { sctList.Add(new CandleStDev() { Close = candle.Close, Open = candle.Open, Date = candle.Date, Ticker = candle.Ticker, Exchange = candle.Exchange, StDev = currentSct.StdDev, ZScore = currentSct.ZScore, StdDevSma = currentSct.StdDevSma, Mean = currentSct.Mean }); } } return sctList; } private void AddSignal(CandleStDev candleSignal, TradeDirection direction, Confidence confidence) { var signal = new Signal( MiscExtensions.ParseEnum(candleSignal.Ticker), direction, confidence, candleSignal, candleSignal.Date, candleSignal.Exchange, Type, SignalType); if (!Signals.Any(s => s.Identifier == signal.Identifier)) { Signals.AddItem(signal); } } private class CandleStDev : Candle { public double? StDev { get; internal set; } public double? ZScore { get; internal set; } public double? StdDevSma { get; internal set; } public double? Mean { get; internal set; } } }