【Java】SFC融媒体项目基于TA-Lib技术分析指标研究
0. 前言
1. TA-Lib介绍
2. TA-Lib数据准备
2.1 指标因子MasterData
2.2 指标结果数据
3. TA-Lib指标SAR
3.1 SAR介绍
2.2 SAR计算
3.3 SAR标准
3.4 SAR优点
3.5 SAR 实践
4. TA-Lib指标BOLL
4.1 BOLL介绍
4.2 BOLL计算
4.3 BOLL分析
4.4 Java实践
5. TA-Lib指标MACD
5.1 MACD介绍
5.2 MACD计算
5.3 MACD分析
5.4 MACD实践
6. 结束语
近期一个项目中有需要构建一个量化分析模块,能够实现常规的各种技术指标,并可以自由扩展添加客户创建的技术指标。同时,能够基于本地打造的数据平台,能够给出1-2中策略模型来打通整体数据从采集到最终生产的过程。经过调查,TA-Lib库中已经有超多实现的技术指标,可以节省从零开始造轮子的精力。本次给客户开发的平台都是基于J2EE开发的,所以采用了TA-Lib的Java版本JAR进行开发(主要是开发人员都是Java,项目组没有Python ,否则应该使用更加方便)。
TA-Lib是一个支持多平台的市场分析的工具集,自1999年发布以来已经有了十多年的历史。软件开发人员在对金融市场数据做技术分析时广泛使用。特点如下:
包括200项指标,如:ADX,MACD,RSI,Stochastic,Bollinger Bands等.. (更多信息)
K线图模式识别
开源API支持语言: C/C++, Java, Perl, Python 和 100% Managed .NET
TA-Lib安装:Java版本的Jar文件,直接上官网下载地址下载导入工程即可。
现在使用的股票数据是直接从上交所和深交所购买的数据,直接存储在MySQL中,所以,为了方便统计以及保持一致性,计算后的结果也同样存储到MySQL中。
计算不同的指标时需要使用的因子的管理维护,在本项目中存储到了MySQL中,基础配置数据如下:
计算出来的各个指标结果数据存储在MySQL中,下面是一只股票一个指标的示例数据。
抛物线转向(SAR)也称停损点转向,其全称叫“Stop and Reveres”,缩写“SAR”。是由美国技术分析大师威尔斯-威尔德(Wells Wilder)所创造的,是一种简单易学、比较准确的中短期技术分析工具。
SAR的计算工作主要是针对每个周期不断变化的SAR的计算,也就是停损价位的计算。在计算SAR之前,先要选定一段周期,比如n日或n周等,n天或周的参数一般为4日或4周。接下来判断这个周期的股价是在上涨还是下跌,然后再按逐步推理方法计算SAR值。
计算日SAR为例,每日SAR的计算公式如下:
其中:SAR(n)为第n日的SAR值,SAR(n-1)为第(n-1)日的值;AF为加速因子(或叫加速系数),EP为极点价(最高价或最低价)。
计算注意事项:
1、 一次计算SAR值时须由近期的明显高低点起的第n天开始。
2、如果是看涨的行情,则SAR(0)为近期底部最低价;如果是看跌行情,则SAR(0)为近期顶部的最高价。
3、加速因子AF有向上加速因子和向下加速因子的区分。若是看涨行情,则为向上加速因子;若是看跌行情,则为向下加速因子。
4、加速因子AF的初始值一直是以0.02为基数。如果是在看涨行情中买入股票后,某天的最高价比前一天的最高价还要高,则加速因子AF递增0.02,并入计算。但加速因子AF最高不超过0.2。反之,看跌行情中也以此类推。
5、如果在看涨行情中,计算出的某日的SAR值比当日或前一日的最低价高,则应以当日或前一日的最低价为该日的SAR值。如果在看跌行情中,计算出的某日的SAR值比当日或前一日的最高价低,则应以当日或前一日的最高价为某日的SAR值。总之,SAR值不得定于当日或前一日的行情价格变动幅度之内。
6、任何一次行情的转变,加速因子AF都必须重新由0.02起算。
7、SAR指标周期的计算基准周期的参数为2,如2日、2周、2月等,其计算周期的参数变动范围为2—8。
8、SAR指标的计算方法和过程比较烦琐,对于投资者来说只要掌握其演算过程和原理,在实际操作中并不需要投资者自己计算SAR值,更重要的是投资者要灵活掌握和运用SAR指标的研判方法和功能。
SAR指标的一般研判标准包括以下四方面:
1、当股票股价从SAR曲线下方开始向上突破SAR曲线时,为买入信号,预示着股价一轮上升行情可能展开,投资者应迅速及时地买进股票。
2、当股票股价向上突破SAR曲线后继续向上运动而SAR曲线也同时向上运动时,表明股价的上涨趋势已经形成,SAR曲线对股价构成强劲的支撑,投资者应坚决持股待涨或逢低加码买进股票。
3、当股票股价从SAR曲线上方开始向下突破SAR曲线时,为卖出信号,预示着股价一轮下跌行情可能展开,投资者应迅速及时地卖出股票。
4、当股票股价向下突破SAR曲线后继续向下运动而SAR曲线也同时向下运动,表明股价的下跌趋势已经形成,SAR曲线对股价构成巨大的压力,投资者应坚决持币观望或逢高减磅。
SAR指标的特殊研判标准包括以下四方面:
1、当SAR曲线向下运行的角度大于45度时,说明空方力量比较强大,股价的跌势比较迅猛,股价还将继续下跌。此时,投资者应坚决持币观望,不宜轻易抢反弹。
2、当SAR曲线向上运行的角度大于45度时,如果SAR曲线已经向上运行了很长一段时间并且股价短期内涨幅过大时,说明多方力量消耗过大,股价将随时可能反转向下。此时,投资者应密切关注SAR曲线的走势,一旦SAR指标发出明显的卖出信号就应坚决清仓离场。
3、当SAR曲线向上运行的角度大于45度时,如果SAR曲线刚刚向上运行,说明多方力量开始积聚,股价将继续向上攀升。此时,投资者应坚决持股待涨。
4、当SAR曲线向下运行的角度小于45度时,并且SAR曲线向下持续运行了很长一段时间以后﹝最少3个月以上﹞,一旦股价向上突破SAR曲线,则表明股价的中长期下跌趋势可能结束,投资者可以开始逢低买入股票。
5、当SAR曲线向上运行的角度小于45度时,如果SAR曲线已经向下运行了很长一段时间的低位盘整﹝最少3个月以上﹞时,说明空方的力量已经衰竭、多方的力量开始加强,股价的一轮新的涨升行情已经展开,股价将继续上涨。此时,投资者应坚决持股待涨。
SAR指标具有以下优点:
1、操作简单,买卖点明确,出现买卖信号即可进行操作,特别适合于入市时间不长、投资经验不丰富、缺乏买卖技巧的中小投资者使用。
2、适合于连续拉升的“牛股”,不会轻易被主力震仓和洗盘。
3、适合于连续阴跌的“熊股”,不会被下跌途中的反弹诱多所蒙骗。
4、适合于中短线的波段操作。
5、长期使用SAR指标虽不能买进最低价,也不能卖出最高价,但可以避免长期套牢的危险,同时又能避免错失牛股行情。
指标需要的基础计算数据已经存储在了MySQL中,按照TA-Lib函数的数据格式进行计算数据的检索。
取得股票行情数据
// 检索指定股票的交易数据
List lstFS = finSse.searchSARPrices(strStock);
if(lstFS == null || lstFS.isEmpty()){
logger.error("没有数据。 证券代码:" + strStock );
return;
}
strStatsDate = lstFS.get(0).getDate();
// 取得该股票的每日价格
int iSize = lstFS.size();
dHigh = new double[iSize];
dLow = new double[iSize];
for(int i=0; i
调用TA-Lib取得SAR计算结果并保存到数据库
// 调用财经库指标函数计算SAR值
FinStratModel finModel = new FinStratModel();
FinStratEntity finEntity = finModel.calSar(dHigh, dLow, Constants.ACCELERATION_FACTOR, Constants.ACCELERATION_FACTOR_MAX);
double dSarPrice[] = finEntity.getSarReal();
// 将计算结果保存到数据库
boolean blnExist = this.finSse.isExist(
strStock,
finFactor.getIndicatorID(),
finFactor.getFactorID(),
strStatsDate);
if(!blnExist){
this.finSse.saveStats(
strStock,
finFactor.getIndicatorID(),
finFactor.getFactorID(),
dSarPrice[dSarPrice.length - 2],
strStatsDate);
}
内部封装工具类引入TA-Lib核心包
import com.tictactec.ta.lib.Core;
import com.tictactec.ta.lib.MAType;
import com.tictactec.ta.lib.MInteger;
import com.tictactec.ta.lib.RetCode;
/**
* 财经指标计算库
*/
public class FinStratModel {
// Talib核心
private Core finLib;
内部封装TA-Lib的SAR方法
/**
* 计算停损点转向指标(SAR)
*
* @param inHigh 最高价
* @param inLow 最低价
* @param optAF 加速因子AF(因子 0.02)
* @param optMaxAF 加速因子AF最大值(因子 0.2)
* @return SAR计算结果数据
*/
public FinStratEntity calSar(double inHigh[], double inLow[], double optAF, double optMaxAF){
// 指标计算结果
FinStratEntity fiResult = new FinStratEntity();
int startIdx = 0;
int endIdx = inHigh.length - 1;
double[] sarReal = new double[inHigh.length];
RetCode retCode = this.finLib.sar(
startIdx,
endIdx,
inHigh,
inLow,
optAF,
optMaxAF,
new MInteger(),
new MInteger(),
sarReal);
if(retCode == RetCode.Success){
fiResult.setRetCode(0);
fiResult.setSarReal(sarReal);
}
return fiResult;
}
SAR统计结果集
最后,该计算数据可以封装为单独的RestAPI接口提供前端(APP、WEB等)调用,并生成图表显示。
布林线指标,即BOLL指标,其英文全称是“Bollinger Bands”,布林线(BOLL)由约翰·布林先生创造,其利用统计原理,求出股价的标准差及其信赖区间,从而确定股价的波动范围及未来走势,利用波带显示股价的安全高低价位,因而也被称为布林带。其上下限范围不固定,随股价的滚动而变化。布林指标和麦克指标MIKE一样同属路径指标,股价波动在上限和下限的区间之内,这条带状区的宽窄,随着股价波动幅度的大小而变化,股价涨跌幅度加大时,带状区变宽,涨跌幅度狭小盘整时,带状区则变窄。
布林线是由价格相关的三条轨道曲线组成,中轨线是一条简单移动平均线,即测量中期趋势,又作为割分上轨和下轨的基础,中轨线与上、下轨曲线间的间距由波动率决定。一般情况下价格线在由上下轨道组成的带状区间游走,而且随价格的变化而自动调整轨道的位置。上、下轨之间的带宽越大,表示价格波动越大,而上、下轨之间的带宽越小,则表示价格波动越小
BOLL指标的计算方法是最复杂的之一,其中引进了统计学中的标准差概念,涉及到中轨线(MB)、上轨线(UP)和下轨线(DN)的计算。另外,和其他指标的计算一样,由于选用的计算周期的不同,BOLL指标也包括日BOLL指标、周BOLL指标、月BOLL指标年BOLL指标以及分钟BOLL指标等各种类型。经常被用于股市研判的是日BOLL指标和周BOLL指标。虽然它们的计算时的取值有所不同,但基本的计算方法一样。
布林线指标的计算公式
注意:D=标准差的参数,一般为默认值: 2
说明:在股市分析软件中,BOLL指标一共由四条线组成,即上轨线UP 、中轨线MB、下轨线DN和价格线。其中上轨线UP是UP数值的连线,用黄色线表示;中轨线MB是MB数值的连线,用白色线表示;下轨线DN是DN数值的连线,用紫色线表示;价格线是以美国线表示,颜色为浅蓝色。和其他技术指标一样,在实战中,投资者不需要进行BOLL指标的计算,主要是了解BOLL的计算方法和过程,以便更加深入地掌握BOLL指标的实质,为运用指标打下基础。
1.当布林线的上、中、下轨线同时向上运行时,表明股价强势特征非常明显,股价短期内将继续上涨,投资者应坚决持股待涨或逢低买入。
2.当布林线的上、中、下轨线同时向下运行时,表明股价的弱势特征非常明显,股价短期内将继续下跌,投资者应坚决持币观望或逢高卖出。
3.当布林线的上轨线向下运行,而中轨线和下轨线却还在向上运行时,表明股价处于整理态势之中。如果股价是处于长期上升趋势时,则表明股价是上涨途中的强势整理,投资者可以持股观望或逢低短线买入;如果股价是处于长期下跌趋势时,则表明股价是下跌途中的弱势整理,投资者应以持币观望或逢高减仓为主。
4.布林线的上轨线向上运行,而中轨线和下轨线同时向下运行,表明股价将经历一轮下跌,下跌的幅度将由开口的大小决定,反之,布林线的下轨线向下运行,而中轨线和上轨线同时向上运行,表明股价将经历一轮上涨,上涨的幅度将由开口的大小决定。这里不做展开讨论。
5.当布林线的上、中、下轨线几乎同时处于水平方向横向运行时,则要看股价目前的走势处于什么样的情况下来判断。
1. BOLL函数参数说明
public RetCode bbands(
int startIdx, // 数据开始下标
int endIdx, // 数据结束下标
double inReal[], // 收盘价
int optInTimePeriod, // MA区间(MA5、MA10、MA20...)
double optInNbDevUp, // 上轨线标准差(默认为2)
double optInNbDevDn, // 下轨线标准差(默认为2)
MAType optInMAType, // MA线的类型:MAType.Sma
MInteger outBegIdx, // 输出数据开始下标
MInteger outNBElement, // 输出数据个数
double outRealUpperBand[], // 上轨线UP数据
double outRealMiddleBand[], // 中轨线MB数据
double outRealLowerBand[] ) // 下轨线DN数据
2. 取得股票行情数据
// 检索指定股票的交易数据
List lstFS = finSse.searchBollPrices(strStock);
if(lstFS == null || lstFS.isEmpty()){
logger.error("没有数据。 证券代码:" + strStock );
return;
}
strStatsDate = lstFS.get(0).getDate();
// 取得该股票的每日价格
int iSize = lstFS.size();
dClose = new double[iSize];
for(int i=0; i
调用TA-Lib取得BOLL计算结果并保存到数据库
// 调用财经库指标函数计算BOLL值
FinStratModel finModel = new FinStratModel();
FinStratEntity finEntity = finModel.calBoll(dInClose, Constants.TIME_PERIOD_BOLL, 2, 2);
double dUpperBand[] = fiEntity.getUpperBand();
double dMiddleBand[] = fiEntity.getMiddleBand();
double dLowerBand[] = fiEntity.getDownBand();
// 将计算结果保存到数据库
boolean blnExist = this.finSse.isExist(
strStock,
finFactor.getIndicatorID(),
finFactor.getFactorID(),
strStatsDate);
// 遍历财经指标因子,保存BOLL数据
for(TMgtFinFactor fin : lstFinFactor){
if(Constants.BOLL_UPPER.equals(fin.getFactorID())){
// 上轨线(UP)
this.finSse.saveStats(
strStock,
fin.getIndicatorID(),
fin.getFactorID(),
dUpperBand[0],
strStatsDate);
} else if(Constants.BOLL_MIDDLE.equals(fin.getFactorID())) {
// 中轨线(MB)
this.finSse.saveStats(
strStock,
fin.getIndicatorID(),
fin.getFactorID(),
dMiddleBand[0],
strStatsDate);
} else if(Constants.BOLL_LOWER.equals(fin.getFactorID())){
// 下轨线(DN)
this.finSse.saveStats(
strStock,
finr.getIndicatorID(),
fin.getFactorID(),
dLowerBand[0],
strStatsDate);
}
}
内部封装TA-Lib的BOLL方法
/**
* 计算布林线指标(BOLL:Bolinger Bands)
*
* @param inReal 收盘价
* @param optTimePeriod 均线天数(因子)
* @param optNbDevUp 上轨线标准差(因子 默认为2)
* @param optNbDevDn 下轨线标准差(因子 默认为2)
* @return BOLL计算结果
*/
public FinStratEntity calBoll(double inReal[], int optTimePeriod, double optNbDevUp, double optNbDevDn){
// 指标计算结果
FinStratEntity fiResult = new FinStratEntity();
int startIdx = 0;
int endIdx = inReal.length - 1;
MAType maType = MAType.Sma;
double upperBand[] = new double[inReal.length];
double middleBand[] = new double[inReal.length];
double lowerBand[] = new double[inReal.length];
RetCode retCode = this.finLib.bbands(
startIdx,
endIdx,
inReal,
optTimePeriod,
optNbDevUp,
optNbDevDn,
maType,
new MInteger(),
new MInteger(),
upperBand,
middleBand,
lowerBand);
if(retCode == RetCode.Success){
fiResult.setRetCode(0);
fiResult.setUpperBand(upperBand);
fiResult.setMiddleBand(middleBand);
fiResult.setDownBand(lowerBand);
}
return fiResult;
}
BOLL统计结果集
最后,该计算数据可以封装为单独的RestAPI接口提供前端(APP、WEB等)调用,并生成图表显示。
MACD(Moving Average Convergence and Divergence)是Geral Appel 于1979年提出的,利用收盘价的短期(常用为12日)指数移动平均线与长期(常用为26日)指数移动平均线之间的聚合与分离状况,对买进、卖出时机作出研判的技术指标。
DIF(蓝线): 计算12天平均和26天平均的差
Signal(DEM或DEA或MACD) (红线): 计算macd9天均值
Histogram (柱): 计算macd与signal的差值
MACD在应用上应先行计算出快速(一般选12日)移动平均值与慢速(一般选26日)移动平均值。以这两个数值作为测量两者(快速与慢速线)间的“差离值”依据。所谓“差离值”(DIF),即12日EMA数值减去26日EMA数值。因此,在持续的涨势中,12日EMA在26日EMA之上。其间的正差离值(+DIF)会愈来愈大。反之在跌势中,差离值可能变负(-DIF),也愈来愈大。至于行情开始回转,正或负差离值要缩小到一定的程度,才真正是行情反转的信号。MACD的反转信号界定为“差离值”的9日移动平均值(9日EMA)。 在MACD的指数平滑移动平均线计算公式中,都分别加T+1交易日的份量权值,以现在流行的参数12和26为例,其公式如下:
计算移动平均值(EMA)
首先计算出快速移动平均线(即EMA1)和慢速移动平均线(即EMA2),以此两个数值,来作为测量两者(快慢速线)间的离差值(DIF)的依据,然后再求DIF的N周期的平滑移动平均线DEA(也叫MACD、DEM)线。以EMA1的参数为12日EMA2的参数为26日,DIF的参数为9日为例来看看MACD的计算过程
根据离差值计算其9日的EMA,即离差平均值,是所求的MACD值。为了不与指标原名相混淆,此值又名DEA或DEM。计算出的DIF和DEA的数值均为正值或负值。用(DIF-DEA)×2即为MACD柱状图。故MACD指标是由两线一柱组合起来形成,快速线为DIF,慢速线为DEA,柱状图为MACD。
在各类投资中,有以下方法供投资者参考:
MACD金叉:DIFF 由下向上突破 DEA,为买入信号。
MACD死叉:DIFF 由上向下突破 DEA,为卖出信号。
MACD 绿转红:MACD 值由负变正,市场由空头转为多头。
MACD 红转绿:MACD 值由正变负,市场由多头转为空头。
DIFF 与 DEA 均为正值,即都在零轴线以上时,大势属多头市场,DIFF 向上突破 DEA,可作买入信号。
DIFF 与 DEA 均为负值,即都在零轴线以下时,大势属空头市场,DIFF 向下跌破 DEA,可作卖出信号。
当 DEA 线与 K 线趋势发生背离时为反转信号。
DEA 在盘整局面时失误率较高,但如果配合RSI 及KDj指标可适当弥补缺点。
MACD函数参数说明
public RetCode macd(
int startIdx, // 数据开始下标
int endIdx, // 数据结束下标
double inReal[], // 收盘价
int optInFastPeriod, // 快速移动平均线期间
int optInSlowPeriod, // 慢速移动平均线期间
int optInSignalPeriod, // Signal期间
MInteger outBegIdx, // 输出数据开始下标
MInteger outNBElement, // 输出数据个数
double outMACD[], // DIF线:12天平均和26天平均的差
double outMACDSignal[], // DEA线:MACD9天均值
double outMACDHist[] ) // MACD柱线:macd与signal的差值
取得股票行情数据
// 检索指定股票的交易数据
List lstFS = finSseBLO.searchMacdPrices(strStock);
if(lstFS == null || lstFS.isEmpty()){
logger.error("没有数据。 证券代码:" + strStock );
return;
}
strStatsDate = lstFS.get(0).getDate();
// 取得该股票的每日价格
int iSize = lstFS.size();
dClose = new double[iSize];
for(int i=0; i
调用TA-Lib取得BOLL计算结果并保存到数据库
// 调用财经库指标函数计算BOLL值
FinStratModel finModel = new FinStratModel();
FinStratEntity finEntity = finModel.calMacd(
dClose,
iFastPeriod,
iSlowPeriod,
iSignalPeriod);
// 快线DIF
double dDifMacd[] = fiEntity.getDifMacd();
// 慢线DEA
double dDeaMacd[] = fiEntity.getDeaMacd();
// 柱图MACD
double dHistMacd[] = fiEntity.getHistMacd();
// 将计算结果保存到数据库
boolean blnExist = this.finSse.isExist(
strStock,
finFactor.getIndicatorID(),
finFactor.getFactorID(),
strStatsDate);
// 遍历财经指标因子,保存MACD数据
for(TMgtFinFactor fin : lstFinFactor){
if(Constants.MACD_DIF.equals(fin.getFactorID())){
// 上轨线(UP)
this.finSse.saveStats(
strStock,
fin.getIndicatorID(),
fin.getFactorID(),
dDifMacd[dDifMacd.length - 1],
strStatsDate);
}else if(Constants.MACD_DEA.equals(fin.getFactorID())) {
// 中轨线(MB)
this.finSse.saveStats(
strStock,
fin.getIndicatorID(),
fin.getFactorID(),
dDeaMacd[dDeaMacd.length - 1],
strStatsDate);
}else if(Constants.MACD_HIST.equals(fin.getFactorID())){
// 下轨线(DN)
this.finSse.saveStats(
strStock,
finr.getIndicatorID(),
fin.getFactorID(),
dDeaMacd[dDeaMacd.length - 1],
strStatsDate);
}
}
内部封装TA-Lib的BOLL方法
/**
* 计算平滑异同移动平均线(MACD)
*
* @param inReal 收盘价
* @param optFastPeriod 快速移动平均线(因子 12日EMA)
* @param optSlowPeriod 慢速移动平均线(因子 26日EMA)
* @param optSignalPeriod DEA移动平均线(因子 9日EMA)
* @return RSI数据
*/
public FinStratEntity calMacd(double inReal[], int optFastPeriod, int optSlowPeriod, int optSignalPeriod){
// 指标计算结果
FinStratEntity fiResult = new FinStratEntity();
// 基础计算库
int startIdx = 0;
int endIdx = inReal.length - 1;
double[] macd = new double[inReal.length];
double[] macdSignal = new double[inReal.length];
double[] macdHist = new double[inReal.length];
RetCode retCode = this.finLib.macd(
startIdx,
endIdx,
inReal,
optFastPeriod,
optSlowPeriod,
optSignalPeriod,
new MInteger(),
new MInteger(),
macd,
macdSignal,
macdHist);
if(retCode == RetCode.Success){
fiResult.setRetCode(0);
fiResult.setDifMacd(upperBand);
fiResult.setDeaMacd(middleBand);
fiResult.setHistMacd(lowerBand);
}
return fiResult;
}
MACD统计结果集
最后,该计算数据可以封装为单独的RestAPI接口提供前端(APP、WEB等)调用,并生成图表显示。
基于TA-Lib的库文件,在项目中实现了客户指定的十几个指标,其余的就不一一列表。所有技术指标的计算方式类似,具体在使用的时候去参照源文件的函数定义。
参考网址:
https://www.ricequant.com/community/topic/62//8
https://www.zhihu.com/question/21614106
https://www.zhihu.com/question/39951384