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;
}
}