namespace AssetManager.Infrastructure.StrategyEngine; /// /// 技术指标计算库 /// public static class TechnicalIndicators { /// /// 计算简单移动平均 (SMA) /// /// 值列表 /// 周期 /// SMA 列表(长度与输入一致,前 period-1 个为 null) public static List CalculateSMA(List values, int period) { var result = new List(); if (values.Count < period) { result.AddRange(values.Select(_ => (decimal?)null)); return result; } // 前 period-1 个为 null for (int i = 0; i < period - 1; i++) { result.Add(null); } // 计算第一个 SMA decimal sum = 0; for (int i = 0; i < period; i++) { sum += values[i]; } result.Add(sum / period); // 滑动窗口计算后续 SMA for (int i = period; i < values.Count; i++) { sum = sum - values[i - period] + values[i]; result.Add(sum / period); } return result; } /// /// 计算指数移动平均 (EMA) /// /// 值列表 /// 周期 /// EMA 列表(长度与输入一致,前 period-1 个为 null) public static List CalculateEMA(List values, int period) { var result = new List(); if (values.Count < period) { result.AddRange(values.Select(_ => (decimal?)null)); return result; } // 前 period-1 个为 null for (int i = 0; i < period - 1; i++) { result.Add(null); } // 第一个 EMA 使用 SMA decimal sma = 0; for (int i = 0; i < period; i++) { sma += values[i]; } sma /= period; result.Add(sma); // 计算后续 EMA:EMA = (当前值 - 前一个 EMA) * 乘数 + 前一个 EMA decimal multiplier = 2.0m / (period + 1); decimal prevEma = sma; for (int i = period; i < values.Count; i++) { decimal ema = (values[i] - prevEma) * multiplier + prevEma; result.Add(ema); prevEma = ema; } return result; } /// /// 计算真实波幅 (TR) /// /// 最高价列表 /// 最低价列表 /// 收盘价列表 /// TR 列表 public static List CalculateTR(List highs, List lows, List closes) { var trList = new List(); if (highs.Count == 0) return trList; // 第一个 TR:High - Low trList.Add(highs[0] - lows[0]); // 后续 TR:Max(High-Low, High-PrevClose, PrevClose-Low) for (int i = 1; i < highs.Count; i++) { decimal prevClose = closes[i - 1]; decimal tr1 = highs[i] - lows[i]; decimal tr2 = Math.Abs(highs[i] - prevClose); decimal tr3 = Math.Abs(prevClose - lows[i]); trList.Add(Math.Max(Math.Max(tr1, tr2), tr3)); } return trList; } /// /// 计算平均真实波幅 (ATR) /// /// 最高价列表 /// 最低价列表 /// 收盘价列表 /// 周期(默认 14) /// ATR 列表(长度与输入一致,前 period-1 个为 null) public static List CalculateATR(List highs, List lows, List closes, int period = 14) { var result = new List(); var trList = CalculateTR(highs, lows, closes); if (trList.Count < period) { result.AddRange(trList.Select(_ => (decimal?)null)); return result; } // 前 period-1 个为 null for (int i = 0; i < period - 1; i++) { result.Add(null); } // 第一个 ATR:TR 的简单平均 decimal sum = 0; for (int i = 0; i < period; i++) { sum += trList[i]; } decimal atr = sum / period; result.Add(atr); // 后续 ATR:(前一个 ATR * (period-1) + 当前 TR) / period for (int i = period; i < trList.Count; i++) { atr = (atr * (period - 1) + trList[i]) / period; result.Add(atr); } return result; } /// /// 计算滚动窗口最高价 /// /// 值列表 /// 周期 /// 滚动最高价列表(长度与输入一致,前 period-1 个为 null) public static List CalculateHighestHigh(List values, int period) { var result = new List(); if (values.Count < period) { result.AddRange(values.Select(_ => (decimal?)null)); return result; } // 前 period-1 个为 null for (int i = 0; i < period - 1; i++) { result.Add(null); } // 滑动窗口计算 for (int i = period - 1; i < values.Count; i++) { decimal max = decimal.MinValue; for (int j = i - period + 1; j <= i; j++) { if (values[j] > max) max = values[j]; } result.Add(max); } return result; } /// /// 计算滚动窗口最低价 /// /// 值列表 /// 周期 /// 滚动最低价列表(长度与输入一致,前 period-1 个为 null) public static List CalculateLowestLow(List values, int period) { var result = new List(); if (values.Count < period) { result.AddRange(values.Select(_ => (decimal?)null)); return result; } // 前 period-1 个为 null for (int i = 0; i < period - 1; i++) { result.Add(null); } // 滑动窗口计算 for (int i = period - 1; i < values.Count; i++) { decimal min = decimal.MaxValue; for (int j = i - period + 1; j <= i; j++) { if (values[j] < min) min = values[j]; } result.Add(min); } return result; } }