k線介紹
股市及期貨市場中的K線圖的畫法包含四個數(shù)據(jù),即開盤價、最高價、最低價、收盤價,所有的k線都是圍繞這四個數(shù)據(jù)展開
k線指標(biāo)介紹
k線指標(biāo)其實(shí)就是技術(shù)指標(biāo), 認(rèn)為的根據(jù)某些算法來預(yù)測價格未來的走勢,或者幫助分析價格背后的市場因素。
k線的幾種指標(biāo)實(shí)現(xiàn)
[圖片上傳失敗...(image-d8e3a-1617104321100)]
SAR的實(shí)現(xiàn)
SAR指標(biāo)又叫拋物線指標(biāo)或停損轉(zhuǎn)向操作點(diǎn)指標(biāo),其全稱叫“Stop and Reverse,縮寫SAR”,是由美國技術(shù)分析大師威爾斯-威爾德(Wells Wilder)所創(chuàng)造的,是一種簡單易學(xué)、比較準(zhǔn)確的中短期技術(shù)分析工具。
更多信息查看百度百科
SAR的計(jì)算公式
計(jì)算公式代碼實(shí)現(xiàn)
public List<Entry> getSar(List<CandleEntry> entries) {
if (sarList == null) {
sarList = new ArrayList<>();
}
if (!sarList.isEmpty()) {
sarList.clear();
}
int len = entries.size();
for (int i = 0; i < len; i++) {
Entry entry = new Entry(calculateSar(i, entries), i);
entry.setTrendUp(currentTrend);
sarList.add(entry);
}
return sarList;
}
/**
*
* @param entries source data
* @param index 下標(biāo)
* @param windowSize 窗口size
* @return
*/
private float getHighestValue(List<CandleEntry> entries, int index, int windowSize){
if (entries.get(index).getHigh() == Float.NaN && windowSize != 1) {
return getHighestValue(entries, index - 1, windowSize - 1);
}
int end = Math.max(0, index - windowSize + 1);
float highest = entries.get(index).getHigh();
for (int i = index - 1; i >= end; i--) {
if (highest < entries.get(i).getHigh()) {
highest = entries.get(i).getHigh();
}
}
return highest;
}
/**
*
* @param entries
* @param index
* @param windowSize
* @return
*/
private float getLowestValue(List<CandleEntry> entries, int index, int windowSize){
if (entries.get(index).getHigh() == Float.NaN && windowSize != 1) {
return getLowestValue(entries, index - 1, windowSize - 1);
}
int end = Math.max(0, index - windowSize + 1);
float lowest = entries.get(index).getLow();
for (int i = index - 1; i >= end; i--) {
if (lowest > entries.get(i).getLow()) {
lowest = entries.get(i).getLow();
}
}
return lowest;
}
protected float calculateSar(int index, List<CandleEntry> entries) {
float sar = 0f;
Entry entry = null;
if (index == 0) {
return entries.get(0).getClose(); // no trend detection possible for the first value
} else if (index == 1) {// start trend detection
currentTrend = entries.get(0).getClose() < entries.get(1).getClose();
if (!currentTrend) { // down trend
sar = entries.get(index).getHigh(); // put sar on max price of candlestick
} else { // up trend
sar = entries.get(index).getLow(); // put sar on min price of candlestick
}
currentExtremePoint = sar;
minMaxExtremePoint = currentExtremePoint;
return sar;
}
float priorSar = sarList.get(index - 1).getVal();
if (currentTrend) { // if up trend
sar = priorSar + (accelerationFactor * (currentExtremePoint - priorSar));
currentTrend = entries.get(index).getLow() > sar;
if (!currentTrend) { // check if sar touches the min price
sar = minMaxExtremePoint; // sar starts at the highest extreme point of previous up trend
currentTrend = false; // switch to down trend and reset values
startTrendIndex = index;
accelerationFactor = accelerationStart;
currentExtremePoint = entries.get(index).getLow(); // put point on max
minMaxExtremePoint = currentExtremePoint;
} else { // up trend is going on
// currentExtremePoint = new HighestValueIndicator(highPriceIndicator, index - startTrendIndex)
// .getValue(index);
currentExtremePoint = getHighestValue(entries, index, index - startTrendIndex);
if (currentExtremePoint > minMaxExtremePoint) {
incrementAcceleration();
minMaxExtremePoint = currentExtremePoint;
}
}
} else { // downtrend
sar = priorSar - (accelerationFactor * (priorSar - currentExtremePoint));
currentTrend = entries.get(index).getHigh() > sar;
if (currentTrend) { // check if switch to up trend
sar = minMaxExtremePoint; // sar starts at the lowest extreme point of previous down trend
accelerationFactor = accelerationStart;
startTrendIndex = index;
currentExtremePoint = entries.get(index).getHigh();;
minMaxExtremePoint = currentExtremePoint;
} else { // down trend io going on
//currentExtremePoint = new LowestValueIndicator(lowPriceIndicator, index - startTrendIndex)
// .getValue(index);
currentExtremePoint = getLowestValue(entries, index, index - startTrendIndex);
if (currentExtremePoint < minMaxExtremePoint) {
incrementAcceleration();
minMaxExtremePoint = currentExtremePoint;
}
}
}
return sar;
}
/**
* Increments the acceleration factor.
*/
private void incrementAcceleration() {
if (accelerationFactor > maxAcceleration) {
accelerationFactor = maxAcceleration;
} else {
accelerationFactor = accelerationFactor + accelerationIncrement;
}
}
OBV的實(shí)現(xiàn)
OBV 的英文全稱是:On Balance Volume,是由美國的投資分析家Joe Granville所創(chuàng)。該指標(biāo)通過統(tǒng)計(jì)成交量變動的趨勢來推測股價趨勢。OBV以“N”字型為波動單位,并且由許許多多“N”型波構(gòu)成了OBV的曲線圖,對一浪高于一浪的“N”型波,稱其為“上升潮”(UP TIDE),至于上升潮中的下跌回落則稱為“跌潮”(DOWN FIELD)。
更多信息查看百度百科
- OBV的計(jì)算公式
計(jì)算公式
- 代碼實(shí)現(xiàn)
private float calculateObv(int index, List<KlinePointBean> entries) {
if (index == 0) {
return 0f;
}
final float prevClose = entries.get(index - 1).getClose();
final float currentClose = entries.get(index).getClose();
final float obvPrev = obvList.get(index - 1).getVal();
if (prevClose > currentClose) {
return obvPrev - (entries.get(index).getAmount());
} else if (prevClose < currentClose) {
return obvPrev + (entries.get(index).getAmount());
} else {
return 0;
}
}
RSI的實(shí)現(xiàn)
RSI最早被用于期貨交易中,后來人們發(fā)現(xiàn)用該指標(biāo)來指導(dǎo)股票市場投資效果也十分不錯,并對該指標(biāo)的特點(diǎn)不斷進(jìn)行歸納和總結(jié)?,F(xiàn)在,RSI已經(jīng)成為被投資者應(yīng)用最廣泛的技術(shù)指標(biāo)之一。投資的一般原理認(rèn)為,投資者的買賣行為是各種因素綜合結(jié)果的反映,行情的變化最終取決于供求關(guān)系,而RSI指標(biāo)正是根據(jù)供求平衡的原理,通過測量某一個期間內(nèi)股價上漲總幅度占股價變化總幅度平均值的百分比,來評估多空力量的強(qiáng)弱程度,進(jìn)而提示具體操作的。RSI的應(yīng)用法則表面上比較復(fù)雜,包括了交叉、數(shù)值、形態(tài)和背離等多方面的判斷原則。
- 代碼實(shí)現(xiàn)
public Triple<List<Entry>, List<Entry>, List<Entry>> getRsiIndicator(List<CandleEntry> candleEntries) {
if (candleEntries == null || candleEntries.size() == 0) {
return new Triple<>(new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
}
List<Entry> rsiList = new ArrayList<>();
List<Entry> rsiList12 = new ArrayList<>();
List<Entry> rsiList24 = new ArrayList<>();
float lastSmValue6 = 0, lastSmValue12 = 0, lastSmValue24 = 0;
float lastSaValue6 = 0, lastSaValue12 = 0, lastSaValue24 = 0;
CandleEntry lastEntry = candleEntries.get(0);
int len = candleEntries.size();
for (int i = 1; i < len; i++) {
CandleEntry entry = candleEntries.get(i);
float m = Math.max(entry.getClose() - lastEntry.getClose(), 0);
float a = Math.abs(entry.getClose() - lastEntry.getClose());
if (i >= 5) {
lastSmValue6 = (m + 5 * lastSmValue6) / 6;
lastSaValue6 = (a + 5 * lastSaValue6) / 6;
rsiList.add(new Entry(lastSmValue6 / lastSaValue6 * 100, entry.getXIndex()));
}
if (i >= 11) {
lastSmValue12 = (m + 11 * lastSmValue12) / 12;
lastSaValue12 = (a + 11 * lastSaValue12) / 12;
rsiList12.add(new Entry(lastSmValue12 / lastSaValue12 * 100, entry.getXIndex()));
}
if (i >= 23) {
lastSmValue24 = (m + 23 * lastSmValue24) / 24;
lastSaValue24 = (a + 23 * lastSaValue24) / 24;
rsiList24.add(new Entry(lastSmValue24 / lastSaValue24 * 100, entry.getXIndex()));
}
lastEntry = candleEntries.get(i);
}
return new Triple<>(rsiList, rsiList12, rsiList24);
}
TRIX的實(shí)現(xiàn)
三重指數(shù)平滑平均線(TRIX)屬于中長線指標(biāo)。它過濾掉許多不必要的波動來反映股價的長期波動趨勢。在使用均線系統(tǒng)的交叉時,有時會出現(xiàn)騙線的情況,有時還會出現(xiàn)頻繁交叉的情況,通常還有一個時間上的確認(rèn)。為了解決這些問題,因而發(fā)明了TRIX這個指標(biāo)把均線的數(shù)值再一次地算出平均數(shù),并在此基礎(chǔ)上算出第三重的平均數(shù)。這樣就可以比較有效地避免頻繁出現(xiàn)交叉信號。 TRIX指標(biāo)又叫三重指數(shù)平滑移動平均指標(biāo),其英文全名為“Triple Exponentially Smoothed Average”,是一種研究股價趨勢的長期技術(shù)分析工具。
TRIX計(jì)算公式
百度百科代碼實(shí)現(xiàn)
/**
* EMA算法
* EMA(N) = 2/(N+1)*C + (N-1)/(N+1)*EMA', EMA'為前一天的ema; 通常N取12和26
*
* @param entries
* @param n
* @return
*/
public static List<Entry> getEMA(List<CandleEntry> entries, int n) {
List<Entry> result = new ArrayList<>();
float lastEma = entries.get(0).getClose();// 第一個EMA為第一個數(shù)據(jù)的價格
float[] emaFactor = getEMAFactor(n);
for (int i = n - 1; i < entries.size(); i++) {
float ema = emaFactor[0] * entries.get(i).getClose() + emaFactor[1] * lastEma;
result.add(new Entry(ema, entries.get(i).getXIndex()));
lastEma = ema;
}
return result;
}
/**
* EMA算法
* EMA(N) = 2/(N+1)*C + (N-1)/(N+1)*EMA', EMA'為前一天的ema; 通常N取12和26
*
* @param entries
* @param n
* @return
*/
public static List<Entry> getEMAFromEntry(List<Entry> entries, int n) {
List<Entry> result = new ArrayList<>();
float lastEma = entries.get(0).getVal();// 第一個EMA為第一個數(shù)據(jù)的價格
float[] emaFactor = getEMAFactor(n);
for (int i = n - 1; i < entries.size(); i++) {
float ema = emaFactor[0] * entries.get(i).getVal() + emaFactor[1] * lastEma;
result.add(new Entry(ema, entries.get(i).getXIndex()));
lastEma = ema;
}
return result;
}
private List<Entry> trixList;
private List<Entry> trixMaList;
public Pair<List<Entry>, List<Entry>> getTrix(List<CandleEntry> entries) {
int n = 12, m = 9;
if (entries == null) {
return new Pair<>(new ArrayList<>(), new ArrayList<>());
}
if (trixList == null) {
trixList = new ArrayList<>();
trixMaList = new ArrayList<>();
}
//clear;
trixList.clear();
trixMaList.clear();
List<Entry> ema1 = getEMA(entries, n);
List<Entry> ema2 = getEMAFromEntry(ema1, n);
List<Entry> ema3 = getEMAFromEntry(ema2, n);
int len = ema3.size();
for (int i = 1; i < len; i++) {
float trixValue = (ema3.get(i).getVal() - ema3.get(i - 1).getVal()) * 100 / ema3.get(i - 1).getVal();
trixList.add(new Entry(trixValue, ema3.get(i).getXIndex()));
}
float ma = 0.0f;
int index = m - 1;
len = trixList.size();
for (int i = 0; i < len; i++) {
if (i >= index) {
float sum = getSumFromEntry(i - index, i, trixList);
ma = sum / m;
trixMaList.add(new Entry(ma, trixList.get(i).getXIndex()));
}
}
return new Pair<>(trixList, trixMaList);
}
CCI的實(shí)現(xiàn)
順勢指標(biāo)又叫CCI指標(biāo),CCI指標(biāo)是美國股市技術(shù)分析 家唐納德·藍(lán)伯特(Donald Lambert)于20世紀(jì)80年代提出的,專門測量股價、外匯或者貴金屬交易是否已超出常態(tài)分布范圍。屬于超買超賣類指標(biāo)中較特殊的一種。波動于正無窮大和負(fù)無窮大之間。但是,又不需要以0為中軸線,這一點(diǎn)也和波動于正無窮大和負(fù)無窮大的指標(biāo)不同。
CCI的計(jì)算公式
計(jì)算公式代碼實(shí)現(xiàn)
private List<Entry> cciList;
private List<Float> tpList;
private List<Float> cciMaList;
private List<Float> mdList;
public List<Entry> getCciData(List<CandleEntry> entries){
int n = 20;
if (entries == null || entries.size() < n) {
return new ArrayList<>();
}
if (cciList == null) {
cciList = new ArrayList<>();
tpList = new ArrayList<>();
mdList = new ArrayList<>();
cciMaList = new ArrayList<>();
}
//clear
cciList.clear();
tpList.clear();
mdList.clear();
cciMaList.clear();
int len = entries.size();
for (int i = 0; i < len; i++) {
float tpValue = getTp(i, entries);
tpList.add(tpValue);
float maValue = getSum(Math.max(0, i - n + 1), i, tpList) / Math.min(n, i + 1);
cciMaList.add(maValue);
final int startIndex = Math.max(0, i - n + 1);
final int nbValues = i - startIndex + 1;
float absoluteDeviations = 0;
for (int j = startIndex; j <= i; j++) {
// For each period...
absoluteDeviations = absoluteDeviations + (Math.abs(tpList.get(j) - maValue));
}
float mdValue = absoluteDeviations / nbValues;
mdList.add(mdValue);
if (mdValue == 0) {
if (i >= n - 1) {
cciList.add(new Entry(0, i));
}
} else {
if (i >= n - 1) {
float cci = (tpList.get(i) - cciMaList.get(i)) / mdList.get(i) / 0.015f;
cciList.add(new Entry(cci, i));
}
}
}
return cciList;
}
private float getSum(Integer start, Integer end, List<Float> datas) {
float sum = 0;
for (int i = start; i <= end; i++) {
sum += datas.get(i);
}
return sum;
}
private float getTp(int index, List<CandleEntry> entries){
float maxPrice = entries.get(index).getHigh();
float minPrice = entries.get(index).getLow();
float closePrice = entries.get(index).getClose();
return (maxPrice + minPrice + closePrice) / 3;
}
ROC的實(shí)現(xiàn)
變動率指標(biāo)(ROC),是以當(dāng)日的收盤價和N天前的收盤價比較,通過計(jì)算股價某一段時間內(nèi)收盤價變動的比例,應(yīng)用價格的移動比較來測量價位動量,達(dá)到事先探測股價買賣供需力量的強(qiáng)弱,進(jìn)而分析股價的趨勢及其是否有轉(zhuǎn)勢的意愿,屬于反趨勢指標(biāo)之一。
ROC實(shí)現(xiàn)公式
實(shí)現(xiàn)公式代碼實(shí)現(xiàn)
private List<Entry> rocList;
private List<Entry> rocMaList;
public Pair<List<Entry>, List<Entry>> getRoc(List<CandleEntry> entries) {
int n = 12, m = 6;
if (entries == null) {
return new Pair<>(new ArrayList<>(), new ArrayList<>());
}
if (rocList == null) {
rocList = new ArrayList<>();
rocMaList = new ArrayList<>();
}
//clear;
rocList.clear();
rocMaList.clear();
int len = entries.size();
for (int i = n; i < len; i++) {
int nIndex = Math.max(i - n, 0);
float nPeriodsAgoValue = entries.get(nIndex).getClose();
float currentValue = entries.get(i).getClose();
float rocValue = (currentValue - nPeriodsAgoValue) / nPeriodsAgoValue * 100;
rocList.add(new Entry(rocValue, i));
}
len = rocList.size();
for (int i = 0; i < len; i++) {
if (i >= m - 1) {
float sum = getSumFromEntry(i - m + 1, i, rocList);
float maValue = sum / m;
rocMaList.add(new Entry(maValue, rocList.get(i).getXIndex()));
}
}
return new Pair<>(rocList, rocMaList);
}
后續(xù)
MACD的實(shí)現(xiàn) /KDJ的實(shí)現(xiàn)/ BOLL的實(shí)現(xiàn) / WR的實(shí)現(xiàn)