Files
managing-apps/src/Managing.Domain/Strategies/Context/StDevContext.cs

136 lines
4.1 KiB
C#

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<Signal> Signals { get; set; }
public StDevContext(string name, int period) : base(name, IndicatorType.StDev)
{
Signals = new List<Signal>();
Period = period;
}
public override List<Signal> 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<CandleStDev> MapStDev(List<StdDevResult> stDev, IEnumerable<Candle> candles)
{
var sctList = new List<CandleStDev>();
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<Ticker>(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; }
}
}