Administrator
2025-12-23 2911432f3d146791edda5e911909d2360953842b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package com.xcong.excoin.modules.okxNewPrice.indicator;
 
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
 
/**
 * 技术指标基础类,提供通用计算方法
 * 
 * 指标组合策略:
 * 1. 趋势判断(MA/AdvancedMA/MACD):判断价格的整体走势方向
 * 2. 动量确认(RSI/KDJ):确认当前趋势的强度和可持续性
 * 3. 波动参考(BOLL):确定价格的合理波动范围和突破时机
 * 
 * 多空方向选择逻辑:
 * - 多头信号:MA多头排列 + MACD金叉 + RSI(30-70) + BOLL价格在上轨与中轨之间
 * - 空头信号:MA空头排列 + MACD死叉 + RSI(30-70) + BOLL价格在下轨与中轨之间
 * - 震荡信号:AdvancedMA三线粘合 + RSI(40-60) + BOLL带宽收窄
 * 
 * 开仓和平仓策略:
 * - 开多:MA金叉 + MACD金叉 + KDJ金叉 + RSI(30-70) + 价格突破BOLL中轨
 * - 开空:MA死叉 + MACD死叉 + KDJ死叉 + RSI(30-70) + 价格跌破BOLL中轨
 * - 平多:MA死叉 + MACD死叉 + RSI超买(>70) + 价格跌破BOLL中轨
 * - 平空:MA金叉 + MACD金叉 + RSI超卖(<30) + 价格突破BOLL中轨
 */
public abstract class IndicatorBase {
 
    /**
     * 计算移动平均值
     * @param prices 价格列表
     * @param period 周期
     * @return 移动平均值
     */
    protected BigDecimal calculateMA(List<BigDecimal> prices, int period) {
        if (prices == null || prices.size() < period) {
            return BigDecimal.ZERO;
        }
        BigDecimal sum = BigDecimal.ZERO;
        for (int i = prices.size() - period; i < prices.size(); i++) {
            sum = sum.add(prices.get(i));
        }
        return sum.divide(new BigDecimal(period), 8, RoundingMode.HALF_UP);
    }
 
    /**
     * 计算指数移动平均值
     * @param prices 价格列表
     * @param period 周期
     * @param prevEMA 前一个EMA值
     * @return 指数移动平均值
     */
    protected BigDecimal calculateEMA(List<BigDecimal> prices, int period, BigDecimal prevEMA) {
        if (prices == null || prices.size() == 0) {
            return BigDecimal.ZERO;
        }
        if (prevEMA == null || prevEMA.compareTo(BigDecimal.ZERO) == 0) {
            return calculateMA(prices, Math.min(period, prices.size()));
        }
        BigDecimal k = new BigDecimal(2).divide(new BigDecimal(period + 1), 8, RoundingMode.HALF_UP);
        BigDecimal currentPrice = prices.get(prices.size() - 1);
        return currentPrice.multiply(k).add(prevEMA.multiply(BigDecimal.ONE.subtract(k)));
    }
 
    /**
     * 计算标准差
     * @param prices 价格列表
     * @param period 周期
     * @return 标准差
     */
    protected BigDecimal calculateStdDev(List<BigDecimal> prices, int period) {
        if (prices == null || prices.size() < period) {
            return BigDecimal.ZERO;
        }
        BigDecimal ma = calculateMA(prices, period);
        BigDecimal sumSquares = BigDecimal.ZERO;
        for (int i = prices.size() - period; i < prices.size(); i++) {
            BigDecimal diff = prices.get(i).subtract(ma);
            sumSquares = sumSquares.add(diff.multiply(diff));
        }
        BigDecimal variance = sumSquares.divide(new BigDecimal(period), 8, RoundingMode.HALF_UP);
        return sqrt(variance);
    }
 
    /**
     * 计算平方根(简化实现)
     * @param value 输入值
     * @return 平方根
     */
    protected BigDecimal sqrt(BigDecimal value) {
        if (value.compareTo(BigDecimal.ZERO) < 0) {
            return BigDecimal.ZERO;
        }
        return new BigDecimal(Math.sqrt(value.doubleValue())).setScale(8, RoundingMode.HALF_UP);
    }
 
    /**
     * 获取最近的价格数据
     * @param prices 所有价格数据
     * @param period 周期
     * @return 最近period个价格数据
     */
    protected List<BigDecimal> getRecentPrices(List<BigDecimal> prices, int period) {
        if (prices == null || prices.size() == 0) {
            return new ArrayList<>();
        }
        int startIndex = Math.max(0, prices.size() - period);
        return prices.subList(startIndex, prices.size());
    }
 
    /**
     * 计算ATR(Average True Range)
     * @param high 最高价列表
     * @param low 最低价列表
     * @param close 收盘价列表
     * @param period 周期
     * @return ATR值
     */
    protected BigDecimal calculateATR(List<BigDecimal> high, List<BigDecimal> low, List<BigDecimal> close, int period) {
        if (high == null || low == null || close == null || 
            high.size() < period || low.size() < period || close.size() < period) {
            return BigDecimal.ZERO;
        }
 
        List<BigDecimal> trList = new ArrayList<>();
        for (int i = 1; i < high.size(); i++) {
            BigDecimal trueRange = calculateTrueRange(high.get(i), low.get(i), close.get(i - 1));
            trList.add(trueRange);
        }
 
        // 使用简单移动平均计算ATR
        return calculateMA(trList, Math.min(period, trList.size()));
    }
 
    /**
     * 计算真实波幅(True Range)
     * @param high 当前最高价
     * @param low 当前最低价
     * @param prevClose 前收盘价
     * @return 真实波幅
     */
    protected BigDecimal calculateTrueRange(BigDecimal high, BigDecimal low, BigDecimal prevClose) {
        BigDecimal h1 = high.subtract(low);
        BigDecimal h2 = high.subtract(prevClose).abs();
        BigDecimal h3 = low.subtract(prevClose).abs();
        return h1.max(h2).max(h3);
    }
 
    /**
     * 计算标准化波动率(基于ATR)
     * @param close 收盘价列表
     * @param atr ATR值
     * @return 标准化波动率(百分比)
     */
    protected BigDecimal normalizeVolatility(List<BigDecimal> close, BigDecimal atr) {
        if (close == null || close.size() == 0 || atr.compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimal.ZERO;
        }
        return atr.divide(close.get(close.size() - 1), 4, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
    }
}