136 lines
4.1 KiB
C#
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; }
|
|
}
|
|
} |