算法代码传到这github
demo:StockChart
五、KDJ
通过一个特定的周期(常为9日、9周等)内出现过的最高价、最低价及最后一个计算周期的收盘价及这三者之间的比例关系,来计算最后一个计算周期的未成熟随机值RSV,然后根据平滑移动平均线的方法来计算K值、D值与J值
计算方式 (摘抄自百度百科)
KDJ的计算比较复杂,首先要计算周期(n日、n周等)的RSV值,即未成熟值,然后再计算K值、D值、J值等。以n日KDJ数值的计算为例,其计算公式为
n日RSV=(Cn-Ln)/(Hn-Ln)×100
公式中,Cn为第n日收盘价;Ln为n日内的最低价;Hn为n日内的最高价。
其次,计算K值与D值:
当日K值=2/3×前一日K值+1/3×当日RSV
当日D值=2/3×前一日D值+1/3×当日K值
若无前一日K 值与D值,则可分别用50来代替。
J值=3当日K值-2当日D值
以9日为周期的KD线为例,即未成熟随机值,计算公式为
9日RSV=(C-L9)÷(H9-L9)×100
公式中,C为第9日的收盘价;L9为9日内的最低价;H9为9日内的最高价。
K值=2/3×第8日K值+1/3×第9日RSV
D值=2/3×第8日D值+1/3×第9日K值
J值=3第9日K值-2第9日D值
/**
* kdj 9,3,3
* N:=9; P1:=3; P2:=3;
* RSV:=(CLOSE-L(LOW,N))/(H(HIGH,N)-L(LOW,N))*100;
* K:SMA(RSV,P1,1);
* D:SMA(K,P2,1);
* J:3*K-2*D;
* @param entries 数据集合
* @param n 指标周期 9
* @param m 权重 1
* @param P1 参数值为3
* @param P2 参数值为3
* @return
*/
public static List[] getKDJ(List<CandleEntry> entries, int n, int P1, int P2, int m) {
List<Entry> kValue = new ArrayList();
List<Entry> dValue = new ArrayList();
List<Entry> jValue = new ArrayList();
List<Entry> maxs = getPeriodHighest(entries, n);
List<Entry> mins = getPeriodLowest(entries, n);
//确保和 传入的list size一致,
int size = entries.size() - maxs.size();
for (int i = 0; i < size; i++) {
maxs.add(0, new Entry());
mins.add(0, new Entry());
}
float rsv = 0;
float lastK = 50;
float lastD = 50;
for (int i = n - 1; i < entries.size(); i++) {
float x = entries.get(i).getX();
if (i >= maxs.size())
break;
if (i >= mins.size())
break;
float div = maxs.get(i).getY() - mins.get(i).getY();
if (div == 0) {
//使用上一次的
} else {
rsv = ((entries.get(i).getClose() - mins.get(i).getY())
/ (div)) * 100;
}
float k = countSMA(rsv, P1, m, lastK);
float d = countSMA(k, P2, m, lastD);
float j = 3 * k - 2 * d;
lastK = k;
lastD = d;
kValue.add(new Entry(x, k));
dValue.add(new Entry(x, d));
jValue.add(new Entry(x, j));
}
return new List[]{kValue, dValue, jValue};
}
/**
* SMA(C,N,M) = (M*C+(N-M)*Y')/N
* C=今天收盘价-昨天收盘价 N=就是周期比如 6或者12或者24, M=权重,一般取1
*
* @param c 今天收盘价-昨天收盘价
* @param n 周期
* @param m 1
* @param sma 上一个周期的sma
* @return
*/
private static float countSMA(float c, float n, float m, float sma) {
return (m * c + (n - m) * sma) / n;
}
/**
* n周期内最低值集合
* @param entries
* @param n
* @return
*/
private static List<Entry> getPeriodLowest(List<CandleEntry> entries, int n) {
List<Entry> result = new ArrayList<>();
float minValue = 0;
for (int i = n - 1; i < entries.size(); i++) {
float x = entries.get(i).getX();
for (int j = i - n + 1; j <= i; j++) {
if (j == i - n + 1) {
minValue = entries.get(j).getLow();
} else {
minValue = Math.min(minValue, entries.get(j).getLow());
}
}
result.add(new Entry(x, minValue));
}
return result;
}
/**
* N周期内最高值集合
* @param entries
* @param n
* @return
*/
private static List<Entry> getPeriodHighest(List<CandleEntry> entries, int n) {
List<Entry> result = new ArrayList<>();
float maxValue = entries.get(0).getHigh();
for (int i = n - 1; i < entries.size(); i++) {
float x = entries.get(i).getX();
for (int j = i - n + 1; j <= i; j++) {
if (j == i - n + 1) {
maxValue = entries.get(j).getHigh();
} else {
maxValue = Math.max(maxValue, entries.get(j).getHigh());
}
}
result.add(new Entry(x, maxValue));
}
return result;
}
六、RSI
相对强弱指数RSI是根据一定时期内上涨点数和涨跌点数之和的比率制作出的一种技术曲线。能够反映出市场在一定时期内的景气程度。
计算方式
RSI:= SMA(MAX(Close-LastClose,0),N,1)/SMA(ABS(Close-LastClose),N,1)*100
(看下面的算法似乎很简单,但是个人觉得这个指标计算反而是比较难缠的一个。。。)
/**
* RSI(n)
* RSI(N):= SMA(MAX(Close-LastClose,0),N,1)/SMA(ABS(Close-LastClose),N,1)*100
*
* @param entries
* @param n
* @param m 加权 1
* @return
*/
public static List<Entry> getRSI(List<CandleEntry> entries, int n, int m) {
List<Entry> result = new ArrayList();
float preIn = 0;
float preAll = 0;
for (int i = 1; i < entries.size(); i++) {
float diff = entries.get(i).getClose() - entries.get(i - 1).getClose();
preIn = countSMA(Math.max(diff, 0), n, m, preIn);
preAll = countSMA(Math.abs(diff), n, m, preAll);
if (i >= n) {
float x = entries.get(i).getX();
result.add(new Entry(x, preIn / preAll * 100));
}
}
return result;
}