Android绘制股票k线图系列3-绘制k线


import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.animation.AnimationUtils;

import com.dlj.library.util.Log;
import com.dlj.library.util.Utils;

import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static com.kedll.kedelllibrary.utils.StockDateUtil.judgeTDNextDay;

public class KLineChartView extends GridChartView {
public static final int T_D_TYPE = 18259; //上海T+D等品种

/**
* 接口
*/
private KLineListener l;
private OnKLineChartClickListener clickL;// 单击接口
private OnLoadMoreListener onLoadMoreListener;// 加载更多接口
private boolean isLoadMore;// 是否加载更多

/**
* 数据
*/
private Vector<KLineData> data;
/**
* 左边要显示当前十字光标中心点的数据
*/
private float leftData;
/**
* 对应的时间
*/
private long date;

/**
* 默认上表纬线条数
*/
private final int DEFAULT_LATITUDE_UP_NUM = 4;
/**
* 默认下表纬线条数
*/
private final int DEFAULT_LATITUDE_DOWN_NUM = 2;
/**
* 默认经线条数
*/
private final int DEFAULT_LONGITUDE_NUM = 3;
/**
* 默认上表高度与总高度比例
*/
private final float DEFAULT_UP_RATIO = 0.75f;
/**
* 默认纬线颜色
*/
private final int DEFAULT_LATITUDE_COLOR = 0xffb7b7b7;
/**
* 默认经纬线宽
*/
private final float DEFAULT_LATLONGWIDTH = 0.8f;
/**
* 默认字体大小
*/
private final float DEFAULT_TEXT_SIZE = 9;
/**
* 默认最多显示数
*/
private final int DEFAULT_CANDLE_NUM = 20 * 3;

/**
* 控件高度
*/
private float viewHeight;
/**
* 控件宽度
*/
private float viewWidth;
/**
* 上表纬线条数
*/
protected int latitudesUpNum = DEFAULT_LATITUDE_UP_NUM;
/**
* 下表纬线条数
*/
protected int latitudesDownNum = DEFAULT_LATITUDE_DOWN_NUM;
/**
* 经线条数
*/
protected int longitudesNum = DEFAULT_LONGITUDE_NUM;
/**
* 上表纬线间距
*/
private float upLatitudesSpacing;
/**
* 下表纬线间距
*/
private float downLatitudesSpacing;
/**
* 经线间距
*/
private float longitudesSpacing;
/**
* 上表与下表间距
*/
private float spacing;
/**
* 经、纬线颜色
*/
private int latLngColor = DEFAULT_LATITUDE_COLOR;
/**
* 经纬线宽
*/
private float latLongWidth = DEFAULT_LATLONGWIDTH;
/**
* 字体大小
*/
private float textSize;
/**
* 上表底部
*/
protected float upChartBottom;
/**
* 下表底部
*/
protected float downChartBottom;
/**
* 上表高度
*/
protected float upChartHeight;
/**
* 下表高度
*/
protected float downChartHeight;
/**
* 上表高度与控件高度比
*/
private float upRatio = DEFAULT_UP_RATIO;

/**
* 上表最大数据
*/
private float upMaxData;
/**
* 上表最小数据
*/
private float upMinData;
/**
* 下表最大数据
*/
private float downMaxData;
/**
* 下表最小数据
*/
private float downMinData;
/**
* 上表的尺寸与数据比例
*/
private float upDataRatio;
/**
* 下表的尺寸与数据比例
*/
private float downDataRatio;

/**
* 最多显示数
*/
private int candleNum = DEFAULT_CANDLE_NUM;
/**
* 最多显示数上限
*/
private int maxCandleNum = DEFAULT_CANDLE_NUM * 4;
/**
* 最多显示数下限
*/
private int minCandleNum = DEFAULT_CANDLE_NUM / 4;
/**
* 数据间距
*/
private float dataSpacing;
/**
* 记录当前滚动到的位置
*/
private int position;
/**
* 加载更多的个数
*/
private int oldSize = 0;
/**
* 是否显示十字光标
*/
private boolean isShowCrossLine;
/**
* 主图指标
*/
private MainIndexType mMainIndexType;

/**
* 指标
*/
private IndexType mIndexType;
/**
*
*/

/**
* 手势相关
*/
private float downX;// 按下X坐标
private float downY;// 按下Y坐标
private float moveX;// 触摸中的X坐标
private float moveY;// 触摸中的Y坐标
private int touchMode;// 触摸模式
/**
* 拖拽模式
*/
private final int TOUCH_DRAG = 1;// 左右滑动模式
/**
* 缩放模式
*/
private final int TOUCH_ZOOM = 2;// 捏合模式
/**
* 吸附模式,即长按内容不滚动,仅光标滚动
*/
private final int TOUCH_ADSORPTION = 3;// 十字光标模式
// private float oldDistance;// 旧的移动距离
// private float newDistance;// 新的移动距离
private Runnable mRunnable;// 长按事件的线程
private boolean isMoved;// 是否触摸中
private boolean isReleased;// 手指是否离开屏幕
private boolean isStartMoved;// 是否可以执行OnTouch中的Move事件了
// private boolean isLeftRightMoved;// 是否在左右滑动
// private float distance;// 捏合事件中的捏合距离
private float crossX;// 十字光标X坐标
private float crossY;// 十字光标Y坐标

private ExecutorService executorService = Executors.newCachedThreadPool();
private NotifyRunnable notifyRunnable = new NotifyRunnable();// 更新数据的线程

/**
* 记录多点触摸时中点坐标
*/
private PointF mTouchPointCenter = new PointF();
/**
* 记录触摸时按下的起始坐标
*/
private PointF mTouchStartPoint = new PointF();
/**
* 分别记录触摸时中间坐标索引、触摸时candleNum、触摸时起始索引
*/
private int mTouchPosition = -1, mTouchCandleNum = 15,
mTouchStartPosition = 0;
/**
* 记录触摸起始x方向两点距离、两点原始距离
*/
private float mSavedXDist = 1f, mSavedDist = 1f;

/**
* 记录快速手势处理过程中,上一次手势的位移
*/
private float mLastFlingDist = 0;
/**
* 快速手势事件检测者
*/
private VelocityTracker mVelocityTracker;
/**
* 减速度运行上一次时间戳
*/
private long mDecelerationLastTime = 0;
/**
* 减速度运行过程中的当前坐标
*/
private PointF mDecelerationCurrentPoint = new PointF();
/**
* 记录减速度运行过程中的位移值
*/
private PointF mDecelerationVelocity = new PointF();
/**
* 设置是否将两边坐标值绘制在边框线外(注:如果设置成true,必须设置strokeLeft和strokeRight)
*/
private boolean isDrawOutside;

/**
* 记录上表各种颜色
*/
private int[] upColors;
/**
* 记录下表各种颜色
*/
private int[] downColors;

/**
* 是否显示小时分钟(true:显示yyyy/MM/dd HH:mm;false:显示yyyy/MM/dd)
*/
private boolean isShowTime;

/**
* 小数保留位数
*/
private int num = 2;// 默认保留2位

private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 0x1:
data = (Vector<KLineData>) msg.getData().getSerializable(
"data");
int mainIndex = msg.getData().getInt("mainindex");
if(mainIndex == 0){
mMainIndexType = MainIndexType.MA;
}else if(mainIndex == 1){
mMainIndexType = MainIndexType.BOLL;
}
mIndexType = (IndexType) msg.obj;

if (touchMode == 0) {
Log.i("KLineChartView", "postInvalidate============" + data.size());
postInvalidate();
}
break;

default:
break;
}
}
};

/**
* 主图指标类型
*
*
@author dingrui
*/
public enum MainIndexType {

/**
* 均线
*/
MA("MA"),

/**
* 布林指标
*/
BOLL("BOLL");

private String value;
private boolean isSelected = false;


MainIndexType(String value) {
this.value = value;
}

public String getValue() {
return value;
}

public boolean isSelected() {
return isSelected;
}

public void setSelected(boolean selected) {
isSelected = selected;
}
}

/**
* 指标类型
*
*
@author dingrui
*/
public enum IndexType {

/**
* 成交量
*/
VOL("VOL"),
/**
* 指数平滑异同平均线(MACD指标)
*/
MACD("MACD"),

/**
* 随机指标(KDJ)
*/
KDJ("KDJ"),
/**
* 随机指标(KD),同KDJ,只输出KD
*/
KD("KD"),
/**
* 强弱指标
*/
RSI("RSI"),
/**
* 乖离率(BIAS)是测量股价偏离均线大小程度的指标
*/
BIAS("BIAS"),
/**
* 情绪指标(BRAR)也称为人气意愿指标
*/
BRAR("BRAR"),
/**
* 顺势指标
*/
CCI("CCI"),
/**
* 动向指标
*/
DMI("DMI"),
/**
* 能量指标
*/
CR("CR"),
/**
* 心理线(PSY)指标是研究投资者对股市涨跌产生心理波动的情绪指标
*/
PSY("PSY"),
/**
* 平行线差指标
*/
DMA("DMA"),
/**
* 三重指数平滑平均线(TRIX)属于长线指标
*/
TRIX("TRIX");

private String value;
private boolean isSelected = false;


IndexType(String value) {
this.value = value;
}

public String getValue() {
return value;
}

public boolean isSelected() {
return isSelected;
}

public void setSelected(boolean selected) {
isSelected = selected;
}
}

public KLineChartView(Context context) {
super(context);
// TODO Auto-generated constructor stub
init();
}

public KLineChartView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init();
}

public KLineChartView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// TODO Auto-generated constructor stub
init();
}

/**
* 初始化
*/
private void init() {
this.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
touchMode = 0;
textSize = MyUtils.getInstance().dp2px(getContext(), DEFAULT_TEXT_SIZE);
spacing = textSize * 2;
position = 0;
isShowCrossLine = false;
mIndexType = IndexType.VOL;
mMainIndexType = MainIndexType.MA;
isDrawOutside = false;
isLoadMore = true;
mRunnable = new Runnable() {

@Override
public void run() {
// TODO Auto-generated method stub
if (isMoved || isReleased)
return;
isStartMoved = true;
touchMode = TOUCH_ADSORPTION;
}
};

}

@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub

super.onDraw(canvas);

try {
viewHeight = getHeight();
viewWidth = getWidth();
Log.w("KLineChartView", "viewHeight===" + viewHeight + " viewWidth=" + viewWidth);
// 计算上表高度
upChartHeight = (viewHeight - getStrokeWidth() * 2 - getStrokeTop()
- getStrokeBottom() - spacing)
* upRatio;
// 计算上表底部位置
upChartBottom = upChartHeight + getStrokeWidth() + getStrokeTop();
// 计算经线间距
longitudesSpacing = (viewWidth - (getStrokeWidth() * 2
+ getStrokeLeft() + getStrokeRight()))
/ (longitudesNum + 1);
// 计算上表纬线间距
upLatitudesSpacing = upChartHeight / latitudesUpNum;
// 计算下表高度
downChartHeight = (viewHeight - getStrokeWidth() * 2 - getStrokeTop()
- getStrokeBottom() - spacing)
* (1 - upRatio);
// 计算下表底部位置
downChartBottom = viewHeight - getStrokeWidth() - getStrokeBottom();
// 计算下表纬线间距
downLatitudesSpacing = downChartHeight / latitudesDownNum;
// 计算数据(蜡烛)间距
dataSpacing = (viewWidth - getStrokeWidth() * 2 - getStrokeLeft() - getStrokeRight())
/ candleNum;

// 计算上表最大、最小数值
upMaxData = 0;
upMinData = 0;
downMaxData = 0;
Log.i("KLineChart", "onDraw....viewHeight=" + viewHeight + " viewWidth=" + viewWidth);
if (data != null && data.size() > 0 && position < data.size() && position >= 0) {
upMaxData = (float) data.get(position).getHighPrice();// 最高价
upMinData = (float) data.get(position).getLowPrice();// 最低价
for (int i = position; i < data.size() && i < candleNum + position; i++) {
upMaxData = upMaxData < (float) data.get(i).getHighPrice() ? (float) data
.get(i).getHighPrice() : upMaxData;

upMinData = (float) (upMinData < data.get(i).getLowPrice() ? upMinData
: data.get(i).getLowPrice());

if (mMainIndexType == MainIndexType.BOLL) {
if (i >= 25) {
upMaxData = upMaxData < (float) data.get(i).getBoll()
.getUpper() ? (float) data.get(i).getBoll()
.getUpper() : upMaxData;

upMinData = (float) (upMinData < data.get(i).getBoll()
.getLower() ? upMinData : data.get(i).getBoll()
.getLower());
}
} else {
if (i >= 4) {
upMaxData = (float) (upMaxData < data.get(i)
.getDayMovingAverage().getMa5() ? data.get(i)
.getDayMovingAverage().getMa5() : upMaxData);
upMinData = (float) (upMinData < data.get(i)
.getDayMovingAverage().getMa5() ? upMinData
: data.get(i).getDayMovingAverage().getMa5());
if (i >= 9) {
upMaxData = (float) (upMaxData < data.get(i)
.getDayMovingAverage().getMa10() ? data
.get(i).getDayMovingAverage().getMa10()
: upMaxData);
upMinData = (float) (upMinData < data.get(i)
.getDayMovingAverage().getMa10() ? upMinData
: data.get(i).getDayMovingAverage()
.getMa10());
if (i >= 19) {
upMaxData = (float) (upMaxData < data.get(i)
.getDayMovingAverage().getMa20() ? data
.get(i).getDayMovingAverage().getMa20()
: upMaxData);
upMinData = (float) (upMinData < data.get(i)
.getDayMovingAverage().getMa20() ? upMinData
: data.get(i).getDayMovingAverage()
.getMa20());
}
}
}
}
}
if (mIndexType == IndexType.VOL ) {
// if (mIndexType == IndexType.VOL || mMainIndexType == MainIndexType.BOLL) {
// 计算成交量最大、最小
downMaxData = (float) data.get(position).getVolume().getNum();
downMinData = 0.0f;
for (int i = position; i < data.size()
&& i < candleNum + position; i++) {
downMaxData = (float) (downMaxData < data.get(i)
.getVolume().getNum() ? data.get(i).getVolume()
.getNum() : downMaxData);
downMaxData = (float) (downMaxData < data.get(i)
.getVolume().getMa5() ? data.get(i).getVolume()
.getMa5() : downMaxData);
downMaxData = (float) (downMaxData < data.get(i)
.getVolume().getMa10() ? data.get(i).getVolume()
.getMa10() : downMaxData);
downMaxData = (float) (downMaxData < data.get(i)
.getVolume().getMa20() ? data.get(i).getVolume()
.getMa20() : downMaxData);
}
} else if (mIndexType == IndexType.MACD) {
// 计算MACD最大、最小
downMaxData = (float) data.get(position).getMacd().getDiff();
downMinData = downMaxData;
for (int i = position; i < data.size()
&& i < candleNum + position; i++) {
downMaxData = (float) (downMaxData < data.get(i).getMacd()
.getDiff() ? data.get(i).getMacd().getDiff()
: downMaxData);
downMaxData = (float) (downMaxData < data.get(i).getMacd()
.getDea() ? data.get(i).getMacd().getDea()
: downMaxData);
downMaxData = (float) (downMaxData < data.get(i).getMacd()
.getMacd() ? data.get(i).getMacd().getMacd()
: downMaxData);

downMinData = (float) (downMinData > data.get(i).getMacd()
.getDiff() ? data.get(i).getMacd().getDiff()
: downMinData);
downMinData = (float) (downMinData > data.get(i).getMacd()
.getDea() ? data.get(i).getMacd().getDea()
: downMinData);
downMinData = (float) (downMinData > data.get(i).getMacd()
.getMacd() ? data.get(i).getMacd().getMacd()
: downMinData);
if (downMaxData >= 0.0 && downMinData <= 0.0) {
if (downMaxData - 0.0f >= 0.0f - downMinData) {
downMinData = 0.0f - (downMaxData - 0.0f);
} else {
downMaxData = 0.0f + (0.0f - downMinData);
}
} else if (downMaxData >= 0.0f && downMinData >= 0.0f) {
downMinData = 0.0f - (downMaxData - 0.0f);
} else {
downMaxData = 0.0f + (0.0f - downMinData);
}
}
float upSpacing = Math.abs(downMaxData - 0.0f);
float downSpacing = Math.abs(downMinData - 0.0f);
if (upSpacing > downSpacing) {
downMinData = 0.0f - upSpacing;
} else {
downMaxData = downSpacing + 0.0f;
}
}
// else if (mIndexType == IndexType.BOLL) {
// // 计算布林最大、最小
// downMaxData = (float) data.get(position).getBoll().getUpper();
// downMinData = (float) data.get(position).getBoll().getLower();
// for (int i = position; i < data.size()
// && i < candleNum + position; i++) {
// downMaxData = (float) (downMaxData < data.get(i).getBoll()
// .getUpper() ? data.get(i).getBoll().getUpper()
// : downMaxData);
//
// downMinData = (float) (downMinData > data.get(i).getBoll()
// .getLower() ? data.get(i).getBoll().getLower()
// : downMinData);
// }
// }
else if (mIndexType == IndexType.KDJ || mIndexType == IndexType.KD) {
// 计算KDJ、KD最大、最小
downMaxData = (float) data.get(position).getKdj().getK();
downMinData = downMaxData;
for (int i = position; i < data.size()
&& i < candleNum + position; i++) {
downMaxData = (float) (downMaxData < data.get(i).getKdj()
.getK() ? data.get(i).getKdj().getK() : downMaxData);
downMaxData = (float) (downMaxData < data.get(i).getKdj()
.getD() ? data.get(i).getKdj().getD() : downMaxData);

downMinData = (float) (downMinData > data.get(i).getKdj()
.getK() ? data.get(i).getKdj().getK() : downMinData);
downMinData = (float) (downMinData > data.get(i).getKdj()
.getD() ? data.get(i).getKdj().getD() : downMinData);

if (mIndexType != IndexType.KD) {
downMaxData = (float) (downMaxData < data.get(i)
.getKdj().getJ() ? data.get(i).getKdj().getJ()
: downMaxData);
downMinData = (float) (downMinData > data.get(i)
.getKdj().getJ() ? data.get(i).getKdj().getJ()
: downMinData);
}
}
} else if (mIndexType == IndexType.RSI) {
// 计算RSI最大、最小
downMaxData = (float) data.get(position).getRsi().getRsi6();
downMinData = downMaxData;
for (int i = position; i < data.size()
&& i < candleNum + position; i++) {
downMaxData = (float) (downMaxData < data.get(i).getRsi()
.getRsi6() ? data.get(i).getRsi().getRsi6()
: downMaxData);
downMaxData = (float) (downMaxData < data.get(i).getRsi()
.getRsi12() ? data.get(i).getRsi().getRsi12()
: downMaxData);
downMaxData = (float) (downMaxData < data.get(i).getRsi()
.getRsi24() ? data.get(i).getRsi().getRsi24()
: downMaxData);

downMinData = (float) (downMinData > data.get(i).getRsi()
.getRsi6() ? data.get(i).getRsi().getRsi6()
: downMinData);
downMinData = (float) (downMinData > data.get(i).getRsi()
.getRsi12() ? data.get(i).getRsi().getRsi12()
: downMinData);
downMinData = (float) (downMinData > data.get(i).getRsi()
.getRsi24() ? data.get(i).getRsi().getRsi24()
: downMinData);
}
} else if (mIndexType == IndexType.BIAS) {
// 计算BIAS最大、最小
downMaxData = (float) data.get(position).getBias().getBias1();
downMinData = downMaxData;
for (int i = position; i < data.size()
&& i < candleNum + position; i++) {
downMaxData = (float) (downMaxData < data.get(i).getBias()
.getBias1() ? data.get(i).getBias().getBias1()
: downMaxData);
downMaxData = (float) (downMaxData < data.get(i).getBias()
.getBias2() ? data.get(i).getBias().getBias2()
: downMaxData);
downMaxData = (float) (downMaxData < data.get(i).getBias()
.getBias3() ? data.get(i).getBias().getBias3()
: downMaxData);

downMinData = (float) (downMinData > data.get(i).getBias()
.getBias1() ? data.get(i).getBias().getBias1()
: downMinData);
downMinData = (float) (downMinData > data.get(i).getBias()
.getBias2() ? data.get(i).getBias().getBias2()
: downMinData);
downMinData = (float) (downMinData > data.get(i).getBias()
.getBias3() ? data.get(i).getBias().getBias3()
: downMinData);
}
} else if (mIndexType == IndexType.BRAR) {
// 计算BRAR最大、最小
downMaxData = (float) data.get(position).getBrar().getBr();
downMinData = downMaxData;
for (int i = position; i < data.size()
&& i < candleNum + position; i++) {
downMaxData = (float) (downMaxData < data.get(i).getBrar()
.getBr() ? data.get(i).getBrar().getBr()
: downMaxData);
downMaxData = (float) (downMaxData < data.get(i).getBrar()
.getAr() ? data.get(i).getBrar().getAr()
: downMaxData);

downMinData = (float) (downMinData > data.get(i).getBrar()
.getBr() ? data.get(i).getBrar().getBr()
: downMinData);
downMinData = (float) (downMinData > data.get(i).getBrar()
.getAr() ? data.get(i).getBrar().getAr()
: downMinData);
}
} else if (mIndexType == IndexType.CCI) {
// 计算CCI最大、最小
downMaxData = (float) data.get(position).getCci().getCci();
downMinData = downMaxData;
for (int i = position; i < data.size()
&& i < candleNum + position; i++) {
downMaxData = (float) (downMaxData < data.get(i).getCci()
.getCci() ? data.get(i).getCci().getCci()
: downMaxData);

downMinData = (float) (downMinData > data.get(i).getCci()
.getCci() ? data.get(i).getCci().getCci()
: downMinData);
}
} else if (mIndexType == IndexType.DMI) {
// 计算DMI最大、最小
downMaxData = (float) data.get(position).getDmi().getPdi();
downMinData = downMaxData;
for (int i = position; i < data.size()
&& i < candleNum + position; i++) {
downMaxData = (float) (downMaxData < data.get(i).getDmi()
.getPdi() ? data.get(i).getDmi().getPdi()
: downMaxData);
downMaxData = (float) (downMaxData < data.get(i).getDmi()
.getMdi() ? data.get(i).getDmi().getMdi()
: downMaxData);
downMaxData = (float) (downMaxData < data.get(i).getDmi()
.getAdx() ? data.get(i).getDmi().getAdx()
: downMaxData);
downMaxData = (float) (downMaxData < data.get(i).getDmi()
.getAdxr() ? data.get(i).getDmi().getAdxr()
: downMaxData);

downMinData = (float) (downMinData > data.get(i).getDmi()
.getPdi() ? data.get(i).getDmi().getPdi()
: downMinData);
downMinData = (float) (downMinData > data.get(i).getDmi()
.getMdi() ? data.get(i).getDmi().getMdi()
: downMinData);
downMinData = (float) (downMinData > data.get(i).getDmi()
.getAdx() ? data.get(i).getDmi().getAdx()
: downMinData);
downMinData = (float) (downMinData > data.get(i).getDmi()
.getAdxr() ? data.get(i).getDmi().getAdxr()
: downMinData);
}
} else if (mIndexType == IndexType.CR) {
// 计算CR最大、最小
downMaxData = (float) data.get(position).getCr().getCr();
downMinData = downMaxData;
for (int i = position; i < data.size()
&& i < candleNum + position; i++) {
downMaxData = (float) (downMaxData < data.get(i).getCr()
.getCr() ? data.get(i).getCr().getCr()
: downMaxData);
downMaxData = (float) (downMaxData < data.get(i).getCr()
.getMa1() ? data.get(i).getCr().getMa1()
: downMaxData);
downMaxData = (float) (downMaxData < data.get(i).getCr()
.getMa2() ? data.get(i).getCr().getMa2()
: downMaxData);
downMaxData = (float) (downMaxData < data.get(i).getCr()
.getMa3() ? data.get(i).getCr().getMa3()
: downMaxData);

downMinData = (float) (downMinData > data.get(i).getCr()
.getCr() ? data.get(i).getCr().getCr()
: downMinData);
downMinData = (float) (downMinData > data.get(i).getCr()
.getMa1() ? data.get(i).getCr().getMa1()
: downMinData);
downMinData = (float) (downMinData > data.get(i).getCr()
.getMa2() ? data.get(i).getCr().getMa2()
: downMinData);
downMinData = (float) (downMinData > data.get(i).getCr()
.getMa2() ? data.get(i).getCr().getMa2()
: downMinData);
}
} else if (mIndexType == IndexType.PSY) {
// 计算PSY最大、最小
downMaxData = (float) data.get(position).getPsy().getPsy();
downMinData = downMaxData;
for (int i = position; i < data.size()
&& i < candleNum + position; i++) {
downMaxData = (float) (downMaxData < data.get(i).getPsy()
.getPsy() ? data.get(i).getPsy().getPsy()
: downMaxData);

downMinData = (float) (downMinData > data.get(i).getPsy()
.getPsy() ? data.get(i).getPsy().getPsy()
: downMinData);
}
} else if (mIndexType == IndexType.DMA) {
// 计算DMA最大、最小
downMaxData = (float) data.get(position).getDma().getDif();
downMinData = downMaxData;
for (int i = position; i < data.size()
&& i < candleNum + position; i++) {
downMaxData = (float) (downMaxData < data.get(i).getDma()
.getDif() ? data.get(i).getDma().getDif()
: downMaxData);
downMaxData = (float) (downMaxData < data.get(i).getDma()
.getAma() ? data.get(i).getDma().getAma()
: downMaxData);

downMinData = (float) (downMinData > data.get(i).getDma()
.getDif() ? data.get(i).getDma().getDif()
: downMinData);
downMinData = (float) (downMinData > data.get(i).getDma()
.getAma() ? data.get(i).getDma().getAma()
: downMinData);
}
} else if (mIndexType == IndexType.TRIX) {
// 计算TRIX最大、最小
downMaxData = (float) data.get(position).getTrix().getTrix();
downMinData = downMaxData;
for (int i = position; i < data.size()
&& i < candleNum + position; i++) {
downMaxData = (float) (downMaxData < data.get(i).getTrix()
.getTrix() ? data.get(i).getTrix().getTrix()
: downMaxData);
downMaxData = (float) (downMaxData < data.get(i).getTrix()
.getMaTrix() ? data.get(i).getTrix().getMaTrix()
: downMaxData);

downMinData = (float) (downMinData > data.get(i).getTrix()
.getTrix() ? data.get(i).getTrix().getTrix()
: downMinData);
downMinData = (float) (downMinData > data.get(i).getTrix()
.getMaTrix() ? data.get(i).getTrix().getMaTrix()
: downMinData);
}
}
}
TextPaint tp = new TextPaint();
tp.setTextSize(textSize);
// tp.setTypeface(Typeface.DEFAULT_BOLD);
tp.setAntiAlias(true);
// float upDataWidth = tp.measureText(Parse.getInstance().parse2String(
// upMaxData));
// float downDataWidth = tp.measureText(Parse.getInstance()
// .parse2CNString(downMaxData));
float dataWidth = tp.measureText("19990909");
// if (spacing == 0.0f)
// setStrokeBottom(textSize);

// 计算上表与数据的比例
upDataRatio = upChartHeight / (upMaxData - upMinData);
// 计算下表与数据比例
downDataRatio = downChartHeight / (downMaxData - downMinData);

Paint paint = new Paint();
paint.setAntiAlias(true);

// 绘制纬线
drawLatitudes(canvas, paint);
// 绘制经线
drawLongitudes(canvas, paint);
// 绘制时间
drawTime(canvas, tp);
// 绘制蜡烛线
drawCandleLine(canvas, paint, tp);
// 绘制是上表折线
drawUpLine(canvas, paint);
// 绘制指标
drawIndex(canvas, paint);
// 绘制上表左边Y轴刻度
drawUpAxisXTitle(canvas, tp, dataWidth);
// 绘制下表左边Y轴刻度
drawDownAxisXTitle(canvas, tp, dataWidth);
// 绘制十字光标
drawCrossLine(canvas, paint, tp);
} catch (NullPointerException ex) {
ex.printStackTrace();
}
}

/**
* 绘制纬线
*
*
@param canvas
* @param paint
*/
private void drawLatitudes(Canvas canvas, Paint paint) {
Log.i("KLineChart", "drawLatitudes.....................");
Paint paint1 = new Paint();
paint1.setColor(latLngColor);
paint1.setStyle(Paint.Style.STROKE);
paint1.setStrokeWidth(latLongWidth);
paint1.setAntiAlias(true);
paint1.setPathEffect(new DashPathEffect(new float[]{4, 4}, 1));
Path path = new Path();
for (int i = 1; i <= latitudesUpNum; i++) {
/* canvas.drawLine(getStrokeLeft(), upLatitudesSpacing * i
+ getStrokeWidth() + getStrokeTop(), getWidth()
-
getStrokeRight(),
upLatitudesSpacing * i
+ getStrokeWidth() + getStrokeTop(), paint); */
path.moveTo(getStrokeLeft(), upLatitudesSpacing * i
+ getStrokeWidth() + getStrokeTop());
path.lineTo(getWidth()
-
getStrokeRight(), upLatitudesSpacing * i
+ getStrokeWidth() + getStrokeTop());

}
canvas.drawPath(path, paint1);
for (int i = 1; i <= latitudesDownNum; i++) {
canvas.drawLine(getStrokeLeft(),
(getHeight() - getStrokeWidth() - getStrokeBottom())
- downLatitudesSpacing * i, getWidth()
- getStrokeRight(),
(getHeight() - getStrokeWidth() - getStrokeBottom())
- downLatitudesSpacing * i, paint1);

}

}

/**
* 绘制经线
*
*
@param canvas
* @param paint
*/
private void drawLongitudes(Canvas canvas, Paint paint) {
Paint paint1 = new Paint();
paint1.setColor(latLngColor);
paint1.setStyle(Paint.Style.STROKE);
paint1.setStrokeWidth(latLongWidth);
paint1.setAntiAlias(true);
paint1.setPathEffect(new DashPathEffect(new float[]{4, 4}, 1));
Path path = new Path();
for (int i = 1; i <= longitudesNum; i++) {
float X = getStrokeLeft() + i * longitudesSpacing;
path.moveTo(X, getStrokeTop() + getStrokeWidth() / 2);
path.lineTo(X, upChartBottom);
path.moveTo(X, upChartBottom + spacing);
path.lineTo(X, downChartBottom);
/*
canvas.drawLine(X, getStrokeTop() + getStrokeWidth() / 2, X,
upChartBottom, paint);
canvas.drawLine(X, upChartBottom + spacing, X, downChartBottom,
paint);
*/
}
canvas.drawPath(path, paint1);
}

/**
* 绘制时间
*
*
@param canvas
* @param paint
*/
private void drawTime(Canvas canvas, TextPaint paint) {
try {
paint.setColor(getResources().getColor(R.color.text_color_5c5f66));
String startTime = "00:00";
String endTime = "00:00";
if (data != null && data.size() > position) {
startTime = MyUtils.getInstance().date2String(
"yyyy/MM/dd HH:mm:ss", data.get(position).getTime() * 1000);
endTime = position + candleNum >= data.size() ? MyUtils
.getInstance().date2String("yyyy/MM/dd HH:mm:ss",
data.get(data.size() - 1).getTime() * 1000)
: MyUtils.getInstance()
.date2String(
"yyyy/MM/dd HH:mm:ss",
data.get(position + candleNum - 1)
.getTime() * 1000);

if (isShowTime) {
startTime = startTime.substring(0, startTime.length() - 3);
endTime = endTime.substring(0, endTime.length() - 3);
} else {
if(data.get(0).getType() == T_D_TYPE){
startTime = judgeTDNextDay(startTime);
endTime = judgeTDNextDay(endTime);
}else {
startTime = startTime.substring(0, startTime.length() - 9);
endTime = endTime.substring(0, endTime.length() - 9);
}
}
}
canvas.drawText(startTime, getStrokeLeft() + getStrokeWidth() + 2,
upChartBottom + textSize, paint);
canvas.drawText(endTime, getWidth() - getStrokeRight()
- getStrokeWidth() - paint.measureText(endTime) - 2,
upChartBottom + textSize, paint);
}catch(ArrayIndexOutOfBoundsException ex){
ex.printStackTrace();
}catch(Exception ex){
ex.printStackTrace();
}
}



/**
* 绘制蜡烛线
*
*
@param canvas
* @param paint
*/
private void drawCandleLine(Canvas canvas, Paint paint, TextPaint tp) {
if (data == null)
return;
paint.setStrokeWidth(2);
float startX = getStrokeWidth() + getStrokeLeft();
int index = 0;
float maxY = Float.MAX_VALUE;
float minY = 0;
float maxX = 0;
float minX = 0;
KLineData maxYEntity = null;
KLineData minYEntity = null;
// float oldDate;
// float oldX = 0.0f;
for (int i = position; i < data.size() && i < candleNum + position; i++) {
KLineData entity = data.get(i);
// String date = Parse.getInstance().isNull(entity.getDate());
// date = date.substring(0, 6);
double close = entity.getClose();
double open = entity.getOpen();

// 柱形图
float openY = upChartBottom
- (float) (open - upMinData) * upDataRatio;
float closeY = upChartBottom
- (float) (close - upMinData) * upDataRatio;
// 中线
float highY = upChartBottom
- (float) (entity.getHighPrice() - upMinData) * upDataRatio;
float lowY = upChartBottom
- (float) (entity.getLowPrice() - upMinData) * upDataRatio;

float endX = getStrokeWidth() + getStrokeLeft()
+ (dataSpacing * (index + 1) - dataSpacing * 0.25f);

if (highY < maxY) {
maxY = highY;
maxYEntity = entity;
maxX = endX;
}
if (lowY > minY) {
minY = lowY;
minYEntity = entity;
minX = endX;
}

// 绘制经线
// if (entity.isDrawLongitude()) {
// paint.setColor(latitudesColor);
//
// tp.setColor(0xff868F9B);
// String date = Parse.getInstance().isNull(entity.getTime());
// date = date.substring(0, 6);
// float textWidth = tp.measureText(date);
// float textY = upChartBottom + textSize * 2 / 2;
// float newX = 0.0f;
// if (((endX - startX) / 2 + startX) - (textWidth / 2) <=
// getStrokeLeft()
// + getStrokeWidth()) {
// newX = getStrokeWidth() + getStrokeLeft() + 2;
// } else if (viewWidth - getStrokeWidth() - getStrokeRight()
// - ((endX - startX) / 2 + startX) <= textWidth / 2) {
// newX = viewWidth - textWidth - 2;
// } else {
// newX = ((endX - startX) / 2 + startX) - (textWidth / 2);
// }
// if (i != position) {
// if (newX - oldX > textWidth + 2) {
// canvas.drawLine((endX - startX) / 2 + startX,
// getStrokeWidth() + getStrokeTop(),
// (endX - startX) / 2 + startX, upChartBottom,
// paint);
// canvas.drawLine((endX - startX) / 2 + startX,
// upChartBottom + spacing, (endX - startX) / 2
// + startX, downChartBottom, paint);
// canvas.drawText(date, newX, textY, tp);
// oldX = newX;
// }
// } else {
// canvas.drawLine((endX - startX) / 2 + startX,
// getStrokeWidth() + getStrokeTop(), (endX - startX)
// / 2 + startX, upChartBottom, paint);
// canvas.drawLine((endX - startX) / 2 + startX, upChartBottom
// + spacing, (endX - startX) / 2 + startX,
// downChartBottom, paint);
//
// canvas.drawText(date, newX, textY, tp);
// oldX = newX;
// }
// }
// oldDate = date;

if (openY < closeY) {
paint.setStyle(Style.FILL);
paint.setColor(getResources().getColor(R.color.green));
canvas.drawRect(startX, openY, endX, closeY, paint);
canvas.drawLine((endX - startX) / 2 + startX, highY,
(endX - startX) / 2 + startX, lowY, paint);
} else if (openY > closeY) {
paint.setStyle(Style.FILL);
paint.setColor(getResources().getColor(R.color.red));
canvas.drawRect(startX, closeY, endX, openY, paint);
paint.setStyle(Style.FILL);
canvas.drawLine((endX - startX) / 2 + startX, highY,
(endX - startX) / 2 + startX, closeY, paint);
canvas.drawLine((endX - startX) / 2 + startX, lowY,
(endX - startX) / 2 + startX, openY, paint);
} else {
if (i != 0) {
KLineData oldItem = data.get(i - 1);
double oldClose = oldItem.getClose();
if (close > oldClose) {
paint.setColor(getResources().getColor(R.color.red));
} else if (close < oldClose) {
paint.setColor(getResources().getColor(R.color.green));
} else {
double oldOpen = oldItem.getOpen();
if (open > oldOpen) {
paint.setColor(getResources().getColor(R.color.red));
} else if (open < oldOpen) {
paint.setColor(getResources().getColor(R.color.green));
} else {
paint.setColor(getResources().getColor(R.color.red));
}
}
} else {
paint.setColor(getResources().getColor(R.color.red));
}
paint.setStyle(Style.FILL);
canvas.drawLine(startX, openY, endX, openY, paint);
canvas.drawLine((endX - startX) / 2 + startX, highY,
(endX - startX) / 2 + startX, lowY, paint);
}

startX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* (index + 1);
index++;
// if (i == position) {
// tp.setColor(0xff868F9B);
// canvas.drawText(String.valueOf(entity.getDate()),
// getStrokeLeft() + getStrokeWidth() + 2, viewHeight, tp);
// }
}
/************在K线图上标记最高、最低价***********/
tp.setColor(getResources().getColor(R.color.color_333333));
if (maxYEntity != null) {
String h = Parse.getInstance().parse2String(maxYEntity.getHighPrice(), 2);
Rect bounds = new Rect();
tp.getTextBounds(h, 0, h.length(), bounds);
maxY += Utils.Dp2Px(getContext(), 10);
if (viewWidth / 2 < maxX) {
maxX = maxX - bounds.width() - Utils.Dp2Px(getContext(), 15);
drawAL(canvas, tp, (int) maxX + bounds.width() + Utils.Dp2Px(getContext(), 1), (int) maxY + bounds.height() / 2, (int) maxX + bounds.width() + Utils.Dp2Px(getContext(), 13), (int) maxY + bounds.height() / 2);
// Log.i(getClass().getSimpleName(), "getWidth()=" + getWidth() + )

} else {
maxX += Utils.Dp2Px(getContext(), 15);
drawAL(canvas, tp, (int) maxX - Utils.Dp2Px(getContext(), 1), (int) maxY + bounds.height() / 2, (int) maxX - Utils.Dp2Px(getContext(), 13), (int) maxY + bounds.height() / 2);
}
canvas.drawText(h, maxX, maxY + bounds.height(), tp);
}
if (minYEntity != null) {
String l = Parse.getInstance().parse2String(minYEntity.getLowPrice(), 2);
Rect bounds = new Rect();
tp.getTextBounds(l, 0, l.length(), bounds);
minY -= Utils.Dp2Px(getContext(), 10);
if (viewWidth / 2 < minX) {
minX = minX - bounds.width() - Utils.Dp2Px(getContext(), 15);
drawAL(canvas, tp, (int) minX + bounds.width() + Utils.Dp2Px(getContext(), 1), (int) minY - bounds.height() / 2, (int) minX + bounds.width() + Utils.Dp2Px(getContext(), 13), (int) minY - bounds.height() / 2);
} else {
minX += Utils.Dp2Px(getContext(), 15);
drawAL(canvas, tp, (int) minX - Utils.Dp2Px(getContext(), 1), (int) minY - bounds.height() / 2, (int) minX - Utils.Dp2Px(getContext(), 13), (int) minY - bounds.height() / 2);
}
canvas.drawText(l, minX, minY, tp);
}
/**************************/
}

/**
* 绘制上表折线
*
*
@param canvas
* @param paint
*/
private void drawUpLine(Canvas canvas, Paint paint) {
if (data == null || data.size() < position)
return;
paint.setStyle(Style.FILL);
paint.setStrokeWidth(1);
int index = 0;
if (mMainIndexType == MainIndexType.BOLL) {
int[] colors = {0xff187cef, 0xfff5a623, 0xfff80101};// 白,黄,红
upColors = colors;
Path path = new Path();
Path path1 = new Path();
Path path2 = new Path();
for (int i = position; i < data.size() && i < candleNum + position; i++) {
KLineData entity = data.get(i);
if (i < data.size() - 1 && i < candleNum + position - 1) {
if (i >= 25) {
float startUPY = upChartBottom
- ((float) entity.getBoll().getUpper() - upMinData)
* upDataRatio;
float endUPY = upChartBottom
- ((float) data.get(i + 1).getBoll().getUpper() - upMinData)
* upDataRatio;
float lineStartX = getStrokeWidth() + getStrokeLeft()
+ dataSpacing * index
+ (dataSpacing * 0.75f / 2);
float lineEndX = getStrokeWidth() + getStrokeLeft()
+ dataSpacing * (index + 1)
+ (dataSpacing * 0.75f / 2);
// paint.setColor(colors[0]);
// canvas.drawLine(lineStartX, startUPY, lineEndX, endUPY,
// paint);

float startMIDY = upChartBottom
- ((float) entity.getBoll().getmID() - upMinData)
* upDataRatio;
float endMIDY = upChartBottom
- ((float) data.get(i + 1).getBoll().getmID() - upMinData)
* upDataRatio;
// paint.setColor(colors[1]);
// canvas.drawLine(lineStartX, startMIDY, lineEndX,
// endMIDY, paint);

float startLOWY = upChartBottom
- ((float) entity.getBoll().getLower() - upMinData)
* upDataRatio;
float endLOWY = upChartBottom
- ((float) data.get(i + 1).getBoll().getLower() - upMinData)
* upDataRatio;
// paint.setColor(colors[2]);
// canvas.drawLine(lineStartX, startLOWY, lineEndX,
// endLOWY, paint);

if (i == position || (position <= 25 && i == 25)) {
path.moveTo(lineStartX, startUPY);
path1.moveTo(lineStartX, startMIDY);
path2.moveTo(lineStartX, startLOWY);
} else {
path.lineTo(lineEndX, endUPY);
path1.lineTo(lineEndX, endMIDY);
path2.lineTo(lineEndX, endLOWY);
}
}
}
index++;
}
paint.setStyle(Style.STROKE);
paint.setColor(colors[0]);
canvas.drawPath(path, paint);
paint.setColor(colors[1]);
canvas.drawPath(path1, paint);
paint.setColor(colors[2]);
canvas.drawPath(path2, paint);
} else {
int[] colors = {0xfff5a623, 0xff187cef, 0xffbd10e0};
upColors = colors;
Path path = new Path();
Path path1 = new Path();
Path path2 = new Path();
for (int i = position; i < data.size() && i < candleNum + position; i++) {
KLineData entity = data.get(i);
if (i < data.size() - 1 && i < candleNum + position - 1) {
if (i >= 4) {
float startMA5Y = upChartBottom
- ((float) entity.getDayMovingAverage()
.getMa5() - upMinData) * upDataRatio;
float endMA5Y = upChartBottom
- ((float) data.get(i + 1)
.getDayMovingAverage().getMa5() - upMinData)
* upDataRatio;
float lineStartX = getStrokeWidth() + getStrokeLeft()
+ dataSpacing * index
+ (dataSpacing * 0.75f / 2);
float lineEndX = getStrokeWidth() + getStrokeLeft()
+ dataSpacing * (index + 1)
+ (dataSpacing * 0.75f / 2);
// paint.setColor(colors[0]);
// canvas.drawLine(lineStartX, startMA5Y, lineEndX,
// endMA5Y, paint);
if (i == position || (position <= 4 && i == 4)) {
path.moveTo(lineStartX, startMA5Y);
} else {
path.lineTo(lineEndX, endMA5Y);
}
if (i >= 9) {
float startMA10Y = upChartBottom
- ((float) entity.getDayMovingAverage()
.getMa10() - upMinData)
* upDataRatio;
float endMA10Y = upChartBottom
- ((float) data.get(i + 1)
.getDayMovingAverage().getMa10() - upMinData)
* upDataRatio;
// paint.setColor(colors[1]);
// canvas.drawLine(lineStartX, startMA10Y, lineEndX,
// endMA10Y, paint);
if (i == position || (position <= 9 && i == 9)) {
path1.moveTo(lineStartX, startMA10Y);
} else {
path1.lineTo(lineEndX, endMA10Y);
}
if (i >= 19) {
float startMA20Y = upChartBottom
- ((float) entity.getDayMovingAverage()
.getMa20() - upMinData)
* upDataRatio;
float endMA20Y = upChartBottom
- ((float) data.get(i + 1)
.getDayMovingAverage()
.getMa20() - upMinData)
* upDataRatio;
// paint.setColor(colors[2]);
// canvas.drawLine(lineStartX, startMA20Y,
// lineEndX, endMA20Y, paint);
if (i == position || (position <= 19 && i == 19)) {
path2.moveTo(lineStartX, startMA20Y);
} else {
path2.lineTo(lineEndX, endMA20Y);
}
}
}
}
}
index++;
}
paint.setStyle(Style.STROKE);
paint.setColor(colors[0]);
canvas.drawPath(path, paint);
paint.setColor(colors[1]);
canvas.drawPath(path1, paint);
paint.setColor(colors[2]);
canvas.drawPath(path2, paint);
}
}

/**
* 绘制指标
*
*
@param canvas
* @param paint
*/
private void drawIndex(Canvas canvas, Paint paint) {
if (data == null) {
return;
}
if (mIndexType == IndexType.VOL)
drawVOL(canvas, paint);
else if (mIndexType == IndexType.MACD)
drawMACD(canvas, paint);
// else if (mIndexType == IndexType.BOLL)
// drawVOL(canvas, paint);
// drawBOLL(canvas, paint);
else if (mIndexType == IndexType.KDJ)
drawKDJ(canvas, paint);
else if (mIndexType == IndexType.KD)
drawKDJ(canvas, paint);
else if (mIndexType == IndexType.RSI)
drawRSI(canvas, paint);
else if (mIndexType == IndexType.BIAS)
drawBIAS(canvas, paint);
else if (mIndexType == IndexType.BRAR)
drawBRAR(canvas, paint);
else if (mIndexType == IndexType.CCI)
drawCCI(canvas, paint);
else if (mIndexType == IndexType.DMI)
drawDMI(canvas, paint);
else if (mIndexType == IndexType.CR)
drawCR(canvas, paint);
else if (mIndexType == IndexType.PSY)
drawPSY(canvas, paint);
else if (mIndexType == IndexType.DMA)
drawDMA(canvas, paint);
else if (mIndexType == IndexType.TRIX)
drawTRIX(canvas, paint);
}

/**
* 绘制成交量指标(vol指标)
*
*
@param canvas
* @param paint
*/
private void drawVOL(Canvas canvas, Paint paint) {
int redColor = getResources().getColor(R.color.red);
int greenColor = getResources().getColor(R.color.green);
int[] colors = {redColor,
greenColor};
if (data == null || data.size() < position)
return;
int index = 0;
for (int i = position; i < data.size() && i < candleNum + position; i++) {
KLineData entity = data.get(i);
if (entity.getClose() >= entity.getOpen()) {
paint.setStyle(Style.FILL);
paint.setColor(colors[0]);
} else {
paint.setStyle(Style.FILL);
paint.setColor(colors[1]);
}
float startX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* index;
float endX = getStrokeWidth() + getStrokeLeft()
+ (dataSpacing * (index + 1) - dataSpacing * 0.25f);
float highY = downChartBottom
- ((float) entity.getVolume().getNum() - downMinData)
* downDataRatio;
float lowY = downChartBottom - (0 - downMinData) * downDataRatio;
canvas.drawRect(startX, highY, endX, lowY, paint);
index++;
}
drawVOLMA(canvas, paint);
}

/**
* 绘制成交量MA折线
*
*
@param canvas
* @param paint
*/
private void drawVOLMA(Canvas canvas, Paint paint) {
int[] colors = {0xff187cef, 0xfff5a623, 0xffbd10e0};
downColors = colors;
paint.setStyle(Style.FILL);
paint.setStrokeWidth(1);
int index = 0;

Path path = new Path();
Path path1 = new Path();
Path path2 = new Path();
for (int i = position; i < data.size() - 1
&& i < candleNum + position - 1; i++) {
KLineData entity = data.get(i);
float lineStartX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* index +
(dataSpacing * 0.75f / 2);
float lineEndX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* (index + 1) +
(dataSpacing * 0.75f / 2);

if (i >= 4) {
float startVMA5Y = (float) (downChartBottom - (entity
.getVolume().getMa5() -
downMinData) * downDataRatio);
float endVMA5Y = (float) (downChartBottom - (data.get(i + 1)
.getVolume().getMa5() -
downMinData)
* downDataRatio);
// paint.setColor(colors[0]);
// canvas.drawLine(lineStartX, startVMA5Y, lineEndX, endVMA5Y,
// paint);
if (i == position || (position <= 4 && i == 4)) {
path.moveTo(lineStartX, startVMA5Y);
} else {
path.lineTo(lineEndX, endVMA5Y);
}
}
if (i >= 9) {
float startVMA10Y = (float) (downChartBottom - (entity
.getVolume().getMa10() -
downMinData) * downDataRatio);
float endVMA10Y = (float) (downChartBottom - (data.get(i + 1)
.getVolume().getMa10() -
downMinData)
* downDataRatio);
// paint.setColor(colors[1]);
// canvas.drawLine(lineStartX, startVMA10Y, lineEndX, endVMA10Y,
// paint);
if (i == position || (position <= 9 && i == 9)) {
path1.moveTo(lineStartX, startVMA10Y);
} else {
path1.lineTo(lineEndX, endVMA10Y);
}
}
if (i >= 19) {
float startVMA20Y = (float) (downChartBottom - (entity
.getVolume().getMa20() -
downMinData) * downDataRatio);
float endVMA20Y = (float) (downChartBottom - (data.get(i + 1)
.getVolume().getMa20() -
downMinData)
* downDataRatio);
// paint.setColor(colors[2]);
// canvas.drawLine(lineStartX, startVMA20Y, lineEndX, endVMA20Y,
// paint);
if (i == position || (position <= 19 && i == 19)) {
path2.moveTo(lineStartX, startVMA20Y);
} else {
path2.lineTo(lineEndX, startVMA20Y);
}
}
index++;
}
paint.setStyle(Style.STROKE);
paint.setColor(colors[0]);
canvas.drawPath(path, paint);
paint.setColor(colors[1]);
canvas.drawPath(path1, paint);
paint.setColor(colors[2]);
canvas.drawPath(path2, paint);
}

/**
* 绘制MACD指标
*
*
@param canvas
* @param paint
*/
private void drawMACD(Canvas canvas, Paint paint) {
int[] colors = {0xff187cef, 0xfff5a623, 0xfff80101};
int redColor = getResources().getColor(R.color.red);
int greenColor = getResources().getColor(R.color.green);
int[] colorss = {redColor, greenColor};
downColors = colors;
paint.setStyle(Style.FILL);
paint.setStrokeWidth(1);
int index = 0;
for (int i = position; i < data.size() && i < candleNum + position; i++) {
KLineData entity = data.get(i);
float lineX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* index + (dataSpacing * 0.75f / 2);
if (i >= 33) {
float MACD = (float) (downChartBottom - (entity.getMacd()
.getMacd() - downMinData) *
downDataRatio);
float zero = (float) (downChartBottom - (0 - downMinData)
* downDataRatio);
if (MACD < zero) {
paint.setColor(colorss[0]);
} else {
paint.setColor(colorss[1]);
}
canvas.drawLine(lineX, zero, lineX, MACD, paint);
}
index++;
}
index = 0;
Path path = new Path();
Path path1 = new Path();
for (int i = position; i < data.size() - 1
&& i < candleNum + position - 1; i++) {
KLineData entity = data.get(i);
float lineStartX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* index +
(dataSpacing * 0.75f / 2);
float lineEndX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* (index + 1) +
(dataSpacing * 0.75f / 2);

if (i >= 25) {
float startEMA26Y = (float) (downChartBottom - (entity
.getMacd().getDiff() -
downMinData) * downDataRatio);
float endEMA26Y = (float) (downChartBottom - (data.get(i + 1)
.getMacd().getDiff() -
downMinData)
* downDataRatio);
// paint.setColor(colors[0]);
// canvas.drawLine(lineStartX, startEMA26Y, lineEndX, endEMA26Y,
// paint);
if (i == position || (position <= 25 && i == 25)) {
path.moveTo(lineStartX, startEMA26Y);
} else {
path.lineTo(lineEndX, endEMA26Y);
}
}
if (i >= 33) {
float startEMA9Y = (float) (downChartBottom - (entity.getMacd()
.getDea() - downMinData) *
downDataRatio);
float endEMA9Y = (float) (downChartBottom - (data.get(i + 1)
.getMacd().getDea() -
downMinData)
* downDataRatio);
// paint.setColor(colors[1]);
// canvas.drawLine(lineStartX, startEMA9Y, lineEndX, endEMA9Y,
// paint);
if (i == position || (position <= 33 && i == 33)) {
path1.moveTo(lineStartX, startEMA9Y);
} else {
path1.lineTo(lineEndX, endEMA9Y);
}
}
index++;
}
paint.setStyle(Style.STROKE);
paint.setColor(colors[0]);
canvas.drawPath(path, paint);
paint.setColor(colors[1]);
canvas.drawPath(path1, paint);
}

/**
* 绘制BOLL指标
*
*
@param canvas
* @param paint
*/
private void drawBOLL(Canvas canvas, Paint paint) {
int[] colors = {0xff187cef, 0xfff5a623, 0xfff80101};// 白,黄,红
downColors = colors;
int index = 0;
paint.setStrokeWidth(1);
for (int i = position; i < data.size() - 1
&& i < candleNum + position - 1; i++) {
KLineData entity = data.get(i);
float lineStartX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* index +
(dataSpacing * 0.75f / 2);
float lineEndX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* (index + 1) +
(dataSpacing * 0.75f / 2);

if (i >= 25) {
// 中轨线
float startMIDY = (float) (downChartBottom - (entity.getBoll()
.getmID() - downMinData) *
downDataRatio);
float endMIDY = (float) (downChartBottom - (data.get(i + 1)
.getBoll().getmID() -
downMinData)
* downDataRatio);
paint.setColor(colors[0]);
canvas.drawLine(lineStartX, startMIDY, lineEndX, endMIDY, paint);
// 上轨线
float startUpY = (float) (downChartBottom - (entity.getBoll()
.getUpper() - downMinData) *
downDataRatio);
float endUpY = (float) (downChartBottom - (data.get(i + 1)
.getBoll().getUpper() -
downMinData)
* downDataRatio);
paint.setColor(colors[1]);
canvas.drawLine(lineStartX, startUpY, lineEndX, endUpY, paint);
// 下轨线
float startLowY = (float) (downChartBottom - (entity.getBoll()
.getLower() - downMinData) *
downDataRatio);
float endLowY = (float) (downChartBottom - (data.get(i + 1)
.getBoll().getLower() -
downMinData)
* downDataRatio);
paint.setColor(colors[2]);
canvas.drawLine(lineStartX, startLowY, lineEndX, endLowY, paint);
}
index++;
}
}

/**
* 绘制KDJ
*
*
@param canvas
* @param paint
*/
private void drawKDJ(Canvas canvas, Paint paint) {
int[] colors = {0xff187cef, 0xfff5a623, 0xfff80101};// 白,黄,红
downColors = colors;
int index = 0;
paint.setStrokeWidth(1);
Path path = new Path();
Path path1 = new Path();
Path path2 = new Path();
for (int i = position; i < data.size() - 1
&& i < candleNum + position - 1; i++) {
KLineData entity = data.get(i);
float lineStartX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* index +
(dataSpacing * 0.75f / 2);
float lineEndX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* (index + 1) +
(dataSpacing * 0.75f / 2);

if (i >= 8) {
float startKY = (float) (downChartBottom - (entity.getKdj()
.getK() - downMinData) *
downDataRatio);
float endKY = (float) (downChartBottom - (data.get(i + 1)
.getKdj().getK() - downMinData)
* downDataRatio);
// paint.setColor(colors[0]);
// canvas.drawLine(lineStartX, startKY, lineEndX, endKY, paint);

float startDY = (float) (downChartBottom - (entity.getKdj()
.getD() - downMinData) *
downDataRatio);
float endDY = (float) (downChartBottom - (data.get(i + 1)
.getKdj().getD() - downMinData)
* downDataRatio);
// paint.setColor(colors[1]);
// canvas.drawLine(lineStartX, startDY, lineEndX, endDY, paint);

if (i == position || (position <= 8 && i == 8)) {
path.moveTo(lineStartX, startKY);
path1.moveTo(lineStartX, startDY);
} else {
path.lineTo(lineEndX, endKY);
path1.lineTo(lineEndX, endDY);
}

if (mIndexType == IndexType.KDJ) {
float startJY = (float) (downChartBottom - (entity.getKdj()
.getJ() - downMinData) *
downDataRatio);
float endJY = (float) (downChartBottom - (data.get(i + 1)
.getKdj().getJ() -
downMinData)
* downDataRatio);
// paint.setColor(colors[2]);
// canvas.drawLine(lineStartX, startJY, lineEndX, endJY, paint);
if (i == position || (position <= 8 && i == 8)) {
path2.moveTo(lineStartX, startJY);
} else {
path2.lineTo(lineEndX, endJY);
}
}
}
index++;
}
paint.setStyle(Style.STROKE);
paint.setColor(colors[0]);
canvas.drawPath(path, paint);
paint.setColor(colors[1]);
canvas.drawPath(path1, paint);
if (mIndexType == IndexType.KDJ) {
paint.setColor(colors[2]);
canvas.drawPath(path2, paint);
}
}

/**
* 绘制RSI
*
*
@param canvas
* @param paint
*/
private void drawRSI(Canvas canvas, Paint paint) {
int[] colors = {0xff187cef, 0xfff5a623, 0xfff80101};// 白,黄,红
downColors = colors;
int index = 0;
paint.setStrokeWidth(1);
Path path = new Path();
Path path1 = new Path();
Path path2 = new Path();
for (int i = position; i < data.size() - 1
&& i < candleNum + position - 1; i++) {
KLineData entity = data.get(i);
float lineStartX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* index +
(dataSpacing * 0.75f / 2);
float lineEndX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* (index + 1) +
(dataSpacing * 0.75f / 2);

if (i >= 6) {
float startRSI1Y = (float) (downChartBottom - (entity.getRsi()
.getRsi6() - downMinData) *
downDataRatio);
float endRSI1Y = (float) (downChartBottom - (data.get(i + 1)
.getRsi().getRsi6() -
downMinData)
* downDataRatio);
// paint.setColor(colors[0]);
// canvas.drawLine(lineStartX, startRSI1Y, lineEndX, endRSI1Y,
// paint);
if (i == position || (position <= 6 && i == 6)) {
path.moveTo(lineStartX, startRSI1Y);
} else {
path.lineTo(lineEndX, endRSI1Y);
}

if (i >= 12) {
float startRSI2Y = (float) (downChartBottom - (entity
.getRsi().getRsi12() -
downMinData) * downDataRatio);
float endRSI2Y = (float) (downChartBottom - (data
.get(i +
1).getRsi().getRsi12() -
downMinData)
* downDataRatio);
// paint.setColor(colors[1]);
// canvas.drawLine(lineStartX, startRSI2Y, lineEndX, endRSI2Y,
// paint);
if (i == position || (position <= 12 && i == 12)) {
path1.moveTo(lineStartX, startRSI2Y);
} else {
path1.lineTo(lineEndX, endRSI2Y);
}
if (i >= 24) {
float startRSI3Y = (float) (downChartBottom - (entity
.getRsi().getRsi24() -
downMinData)
* downDataRatio);
float endRSI3Y = (float) (downChartBottom - (data
.get(i +
1).getRsi().getRsi24() -
downMinData)
* downDataRatio);
// paint.setColor(colors[2]);
// canvas.drawLine(lineStartX, startRSI3Y, lineEndX,
// endRSI3Y, paint);
if (i == position || (position <= 24 && i == 24)) {
path2.moveTo(lineStartX, startRSI3Y);
} else {
path2.lineTo(lineEndX, endRSI3Y);
}
}
}
}
index++;
}
paint.setStyle(Style.STROKE);
paint.setColor(colors[0]);
canvas.drawPath(path, paint);
paint.setColor(colors[1]);
canvas.drawPath(path1, paint);
paint.setColor(colors[2]);
canvas.drawPath(path2, paint);
}

/**
* 绘制BIAS
*
*
@param canvas
* @param paint
*/
private void drawBIAS(Canvas canvas, Paint paint) {
int[] colors = {0xff187cef, 0xfff5a623, 0xfff80101};// 白,黄,红
downColors = colors;
int index = 0;
paint.setStrokeWidth(1);
Path path = new Path();
Path path1 = new Path();
Path path2 = new Path();
for (int i = position; i < data.size() - 1
&& i < candleNum + position - 1; i++) {
KLineData entity = data.get(i);
float lineStartX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* index +
(dataSpacing * 0.75f / 2);
float lineEndX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* (index + 1) +
(dataSpacing * 0.75f / 2);

if (i >= 5) {
float startBIAS1Y = (float) (downChartBottom - (entity
.getBias().getBias1() -
downMinData) * downDataRatio);
float endBIAS1Y = (float) (downChartBottom - (data.get(i + 1)
.getBias().getBias1() -
downMinData)
* downDataRatio);
// paint.setColor(colors[0]);
// canvas.drawLine(lineStartX, startBIAS1Y, lineEndX, endBIAS1Y,
// paint);
if (i == position || (position <= 5 && i == 5)) {
path.moveTo(lineStartX, startBIAS1Y);
} else {
path.lineTo(lineEndX, endBIAS1Y);
}

if (i >= 11) {
float startBIAS2Y = (float) (downChartBottom - (entity
.getBias().getBias2() -
downMinData)
* downDataRatio);
float endBIAS2Y = (float) (downChartBottom - (data
.get(i +
1).getBias().getBias2() -
downMinData)
* downDataRatio);
// paint.setColor(colors[1]);
// canvas.drawLine(lineStartX, startBIAS2Y, lineEndX,
// endBIAS2Y, paint);
if (i == position || (position <= 11 && i == 11)) {
path1.moveTo(lineStartX, startBIAS2Y);
} else {
path1.lineTo(lineEndX, endBIAS2Y);
}
if (i >= 23) {
float startBIAS3Y = (float) (downChartBottom - (entity
.getBias().getBias3() -
downMinData)
* downDataRatio);
float endBIAS3Y = (float) (downChartBottom - (data
.get(i +
1).getBias().getBias3() -
downMinData)
* downDataRatio);
// paint.setColor(colors[2]);
// canvas.drawLine(lineStartX, startBIAS3Y, lineEndX,
// endBIAS3Y, paint);
if (i == position || (position <= 23 && i == 23)) {
path2.moveTo(lineStartX, startBIAS3Y);
} else {
path2.lineTo(lineEndX, endBIAS3Y);
}
}
}
}
index++;
}
paint.setStyle(Style.STROKE);
paint.setColor(colors[0]);
canvas.drawPath(path, paint);
paint.setColor(colors[1]);
canvas.drawPath(path1, paint);
paint.setColor(colors[2]);
canvas.drawPath(path2, paint);
}

/**
* 绘制BRAR
*
*
@param canvas
* @param paint
*/
private void drawBRAR(Canvas canvas, Paint paint) {
int[] colors = {0xff187cef, 0xfff5a623};// 白,黄
downColors = colors;
int index = 0;
paint.setStrokeWidth(1);
Path path = new Path();
Path path1 = new Path();
for (int i = position; i < data.size() - 1
&& i < candleNum + position - 1; i++) {
KLineData entity = data.get(i);
float lineStartX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* index +
(dataSpacing * 0.75f / 2);
float lineEndX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* (index + 1) +
(dataSpacing * 0.75f / 2);

if (i >= 25) {
float startARY = (float) (downChartBottom - (entity.getBrar()
.getAr() - downMinData) *
downDataRatio);
float endARY = (float) (downChartBottom - (data.get(i + 1)
.getBrar().getAr() - downMinData)
* downDataRatio);
// paint.setColor(colors[0]);
// canvas.drawLine(lineStartX, startARY, lineEndX, endARY, paint);

if (i == position || (position <= 25 && i == 25)) {
path.moveTo(lineStartX, startARY);
} else {
path.lineTo(lineEndX, endARY);
}

if (i >= 26) {
float startBRY = (float) (downChartBottom - (entity
.getBrar().getBr() -
downMinData) * downDataRatio);
float endBRY = (float) (downChartBottom - (data.get(i + 1)
.getBrar().getBr() -
downMinData)
* downDataRatio);
// paint.setColor(colors[1]);
// canvas.drawLine(lineStartX, startBRY, lineEndX, endBRY,
// paint);
if (i == position || (position <= 26 && i == 26)) {
path1.moveTo(lineStartX, startBRY);
} else {
path1.lineTo(lineEndX, endBRY);
}
}
}
index++;
}
paint.setStyle(Style.STROKE);
paint.setColor(colors[0]);
canvas.drawPath(path, paint);
paint.setColor(colors[1]);
canvas.drawPath(path1, paint);
}

/**
* 绘制CCI
*
*
@param canvas
* @param paint
*/
private void drawCCI(Canvas canvas, Paint paint) {
int[] colors = {0xff187cef};// 白
downColors = colors;
int index = 0;
paint.setStrokeWidth(1);
Path path = new Path();
for (int i = position; i < data.size() - 1
&& i < candleNum + position - 1; i++) {
KLineData entity = data.get(i);
float lineStartX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* index +
(dataSpacing * 0.75f / 2);
float lineEndX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* (index + 1) +
(dataSpacing * 0.75f / 2);

if (i >= 13) {
float startCCIY = (float) (downChartBottom - (entity.getCci()
.getCci() - downMinData) *
downDataRatio);
float endCCIY = (float) (downChartBottom - (data.get(i + 1)
.getCci().getCci() -
downMinData)
* downDataRatio);
// paint.setColor(colors[0]);
// canvas.drawLine(lineStartX, startCCIY, lineEndX, endCCIY, paint);
if (i == position || (position <= 13 && i == 13)) {
path.moveTo(lineStartX, startCCIY);
} else {
path.lineTo(lineEndX, endCCIY);
}

}
index++;
}
paint.setStyle(Style.STROKE);
paint.setColor(colors[0]);
canvas.drawPath(path, paint);
}

/**
* 绘制CCI
*
*
@param canvas
* @param paint
*/
private void drawDMI(Canvas canvas, Paint paint) {
int[] colors = {0xff187cef, 0xfff5a623, 0xfff80101, 0xff74bd4f};// 白,黄,红,绿
downColors = colors;
int index = 0;
paint.setStrokeWidth(1);
Path path = new Path();
Path path1 = new Path();
Path path2 = new Path();
Path path3 = new Path();
for (int i = position; i < data.size() - 1
&& i < candleNum + position - 1; i++) {
KLineData entity = data.get(i);
float lineStartX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* index +
(dataSpacing * 0.75f / 2);
float lineEndX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* (index + 1) +
(dataSpacing * 0.75f / 2);

if (i >= 14) {
float startPDIY = (float) (downChartBottom - (entity.getDmi()
.getPdi() - downMinData) *
downDataRatio);
float endPDIY = (float) (downChartBottom - (data.get(i + 1)
.getDmi().getPdi() -
downMinData)
* downDataRatio);
// paint.setColor(colors[0]);
// canvas.drawLine(lineStartX, startPDIY, lineEndX, endPDIY, paint);
float startMDIY = (float) (downChartBottom - (entity.getDmi()
.getMdi() - downMinData) *
downDataRatio);
float endMDIY = (float) (downChartBottom - (data.get(i + 1)
.getDmi().getMdi() -
downMinData)
* downDataRatio);
// paint.setColor(colors[1]);
// canvas.drawLine(lineStartX, startMDIY, lineEndX, endMDIY, paint);
if (i == position || (position <= 14 && i == 14)) {
path.moveTo(lineStartX, startPDIY);
path1.moveTo(lineStartX, startMDIY);
} else {
path.lineTo(lineEndX, endPDIY);
path1.lineTo(lineEndX, endMDIY);
}
if (i >= 19) {
float startADXY = (float) (downChartBottom - (entity
.getDmi().getAdx() -
downMinData) * downDataRatio);
float endADXY = (float) (downChartBottom - (data.get(i + 1)
.getDmi().getAdx() -
downMinData)
* downDataRatio);
// paint.setColor(colors[2]);
// canvas.drawLine(lineStartX, startADXY, lineEndX, endADXY,
// paint);
if (i == position || (position <= 19 && i == 19)) {
path2.moveTo(lineStartX, startADXY);
} else {
path2.lineTo(lineEndX, endADXY);
}
if (i >= 25) {
float startADXRY = (float) (downChartBottom - (entity
.getDmi().getAdxr() -
downMinData)
* downDataRatio);
float endADXRY = (float) (downChartBottom - (data
.get(i +
1).getDmi().getAdxr() -
downMinData)
* downDataRatio);
// paint.setColor(colors[3]);
// canvas.drawLine(lineStartX, startADXRY, lineEndX,
// endADXRY, paint);
if (i == position || (position <= 25 && i == 25)) {
path3.moveTo(lineStartX, startADXRY);
} else {
path3.lineTo(lineEndX, endADXRY);
}
}
}
}
index++;
}
paint.setStyle(Style.STROKE);
paint.setColor(colors[0]);
canvas.drawPath(path, paint);
paint.setColor(colors[1]);
canvas.drawPath(path1, paint);
paint.setColor(colors[2]);
canvas.drawPath(path2, paint);
paint.setColor(colors[3]);
canvas.drawPath(path3, paint);
}

/**
* 绘制CR
*
*
@param canvas
* @param paint
*/
private void drawCR(Canvas canvas, Paint paint) {
int[] colors = {0xff187cef, 0xfff5a623, 0xfff80101, 0xff74bd4f};// 白,黄,红,绿
downColors = colors;
int index = 0;
paint.setStrokeWidth(1);
Path path = new Path();
Path path1 = new Path();
Path path2 = new Path();
Path path3 = new Path();
for (int i = position; i < data.size() - 1
&& i < candleNum + position - 1; i++) {
KLineData entity = data.get(i);
float lineStartX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* index +
(dataSpacing * 0.75f / 2);
float lineEndX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* (index + 1) +
(dataSpacing * 0.75f / 2);

if (i >= 26) {
float startCRY = (float) (downChartBottom - (entity.getCr()
.getCr() - downMinData) *
downDataRatio);
float endCRY = (float) (downChartBottom - (data.get(i + 1)
.getCr().getCr() - downMinData)
* downDataRatio);
// paint.setColor(colors[0]);
// canvas.drawLine(lineStartX, startCRY, lineEndX, endCRY, paint);

if (i == position || (position <= 26 && i == 26)) {
path.moveTo(lineStartX, startCRY);
} else {
path.lineTo(lineEndX, endCRY);
}

if (i >= 33) {
float startMA1Y = (float) (downChartBottom - (entity
.getCr().getMa1() -
downMinData) * downDataRatio);
float endMA1Y = (float) (downChartBottom - (data.get(i + 1)
.getCr().getMa1() -
downMinData)
* downDataRatio);
// paint.setColor(colors[1]);
// canvas.drawLine(lineStartX, startMA1Y, lineEndX, endMA1Y,
// paint);
if (i == position || (position <= 33 && i == 33)) {
path1.moveTo(lineStartX, startMA1Y);
} else {
path1.lineTo(lineEndX, endMA1Y);
}
if (i >= 40) {
float startMA2Y = (float) (downChartBottom - (entity
.getCr().getMa2() -
downMinData)
* downDataRatio);
float endMA2Y = (float) (downChartBottom - (data
.get(i +
1).getCr().getMa2() -
downMinData)
* downDataRatio);
// paint.setColor(colors[2]);
// canvas.drawLine(lineStartX, startMA2Y, lineEndX,
// endMA2Y, paint);
if (i == position || (position <= 40 && i == 40)) {
path2.moveTo(lineStartX, startMA2Y);
} else {
path2.lineTo(lineEndX, endMA2Y);
}
if (i >= 54) {
float startMA3Y = (float) (downChartBottom - (entity
.getCr().getMa3() -
downMinData)
* downDataRatio);
float endMA3Y = (float) (downChartBottom - (data
.get(i +
1).getCr().getMa3() -
downMinData)
* downDataRatio);
// paint.setColor(colors[3]);
// canvas.drawLine(lineStartX, startMA3Y, lineEndX,
// endMA3Y, paint);
if (i == position || (position <= 54 && i == 54)) {
path3.moveTo(lineStartX, startMA3Y);
} else {
path3.lineTo(lineEndX, endMA3Y);
}
}
}
}
}
index++;
}
paint.setStyle(Style.STROKE);
paint.setColor(colors[0]);
canvas.drawPath(path, paint);
paint.setColor(colors[1]);
canvas.drawPath(path1, paint);
paint.setColor(colors[2]);
canvas.drawPath(path2, paint);
paint.setColor(colors[3]);
canvas.drawPath(path3, paint);
}

/**
* 绘制PSY
*
*
@param canvas
* @param paint
*/
private void drawPSY(Canvas canvas, Paint paint) {
int[] colors = {0xff187cef};
downColors = colors;
int index = 0;
paint.setStrokeWidth(1);
Path path = new Path();
for (int i = position; i < data.size() - 1
&& i < candleNum + position - 1; i++) {
KLineData entity = data.get(i);
float lineStartX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* index +
(dataSpacing * 0.75f / 2);
float lineEndX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* (index + 1) +
(dataSpacing * 0.75f / 2);

if (i >= 12) {
float startPSYY = (float) (downChartBottom - (entity.getPsy()
.getPsy() - downMinData) *
downDataRatio);
float endPSYY = (float) (downChartBottom - (data.get(i + 1)
.getPsy().getPsy() -
downMinData)
* downDataRatio);
// paint.setColor(colors[0]);
// canvas.drawLine(lineStartX, startPSYY, lineEndX, endPSYY, paint);

if (i == position || (position <= 12 && i == 12)) {
path.moveTo(lineStartX, startPSYY);
} else {
path.lineTo(lineEndX, endPSYY);
}
}
index++;
}
paint.setStyle(Style.STROKE);
paint.setColor(colors[0]);
canvas.drawPath(path, paint);
}

/**
* 绘制DMA
*
*
@param canvas
* @param paint
*/
private void drawDMA(Canvas canvas, Paint paint) {
int[] colors = {0xff187cef, 0xfff5a623};// 白,黄
downColors = colors;
int index = 0;
paint.setStrokeWidth(1);
Path path = new Path();
Path path1 = new Path();
for (int i = position; i < data.size() - 1
&& i < candleNum + position - 1; i++) {
KLineData entity = data.get(i);
float lineStartX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* index +
(dataSpacing * 0.75f / 2);
float lineEndX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* (index + 1) +
(dataSpacing * 0.75f / 2);

if (i >= 49) {
float startDIFY = (float) (downChartBottom - (entity.getDma()
.getDif() - downMinData) *
downDataRatio);
float endDIFY = (float) (downChartBottom - (data.get(i + 1)
.getDma().getDif() -
downMinData)
* downDataRatio);
// paint.setColor(colors[0]);
// canvas.drawLine(lineStartX, startDIFY, lineEndX, endDIFY, paint);
if (i == position || (position <= 49 && i == 49)) {
path.moveTo(lineStartX, startDIFY);
} else {
path.lineTo(lineEndX, endDIFY);
}
if (i >= 58) {
float startAMAY = (float) (downChartBottom - (entity
.getDma().getAma() -
downMinData) * downDataRatio);
float endAMAY = (float) (downChartBottom - (data.get(i + 1)
.getDma().getAma() -
downMinData)
* downDataRatio);
// paint.setColor(colors[1]);
// canvas.drawLine(lineStartX, startAMAY, lineEndX, endAMAY,
// paint);
if (i == position || (position <= 58 && i == 58)) {
path1.moveTo(lineStartX, startAMAY);
} else {
path1.lineTo(lineEndX, endAMAY);
}
}
}
index++;
}
paint.setStyle(Style.STROKE);
paint.setColor(colors[0]);
canvas.drawPath(path, paint);
paint.setColor(colors[1]);
canvas.drawPath(path1, paint);
}

/**
* 绘制TRIX
*
*
@param canvas
* @param paint
*/
private void drawTRIX(Canvas canvas, Paint paint) {
int[] colors = {0xff187cef, 0xfff5a623};// 白,黄
downColors = colors;
int index = 0;
paint.setStrokeWidth(1);
Path path = new Path();
Path path1 = new Path();
for (int i = position; i < data.size() - 1
&& i < candleNum + position - 1; i++) {
KLineData entity = data.get(i);
float lineStartX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* index +
(dataSpacing * 0.75f / 2);
float lineEndX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* (index + 1) +
(dataSpacing * 0.75f / 2);

if (i >= 33) {
float startTRIXY = (float) (downChartBottom - (entity.getTrix()
.getTrix() - downMinData) *
downDataRatio);
float endTRIXY = (float) (downChartBottom - (data.get(i + 1)
.getTrix().getTrix() -
downMinData)
* downDataRatio);
// paint.setColor(colors[0]);
// canvas.drawLine(lineStartX, startTRIXY, lineEndX, endTRIXY,
// paint);
if (i == position || (position <= 33 && i == 33)) {
path.moveTo(lineStartX, startTRIXY);
} else {
path.lineTo(lineEndX, endTRIXY);
}
if (i >= 52) {
float startMATRIXY = (float) (downChartBottom - (entity
.getTrix().getMaTrix() -
downMinData)
* downDataRatio);
float endMATRIXY = (float) (downChartBottom - (data
.get(i +
1).getTrix().getMaTrix() -
downMinData)
* downDataRatio);
// paint.setColor(colors[1]);
// canvas.drawLine(lineStartX, startMATRIXY, lineEndX,
// endMATRIXY, paint);
if (i == position || (position <= 52 && i == 52)) {
path1.moveTo(lineStartX, startMATRIXY);
} else {
path1.lineTo(lineEndX, endMATRIXY);
}
}
}
index++;
}
paint.setStyle(Style.STROKE);
paint.setColor(colors[0]);
canvas.drawPath(path, paint);
paint.setColor(colors[1]);
canvas.drawPath(path1, paint);
}

/**
* 绘制上表左边Y刻度
*
*
@param canvas 画布
*
@param paint 画笔
*/
private void drawUpAxisXTitle(Canvas canvas, TextPaint paint,
float dataWidth) {
paint.setColor(getResources().getColor(R.color.text_color_5c5f66));
if (!isDrawOutside) {
float YData = upMaxData;
float spacing = (upMaxData - upMinData) / (latitudesUpNum);
for (int i = 0; i < latitudesUpNum + 1; i++) {
if (i == 0) {
canvas.drawText(
Parse.getInstance().parse2String(upMaxData, num),
getStrokeWidth() + getStrokeLeft() + 2,
getStrokeWidth() + getStrokeTop() + textSize, paint);
} else if (i == latitudesUpNum) {
canvas.drawText(
Parse.getInstance().parse2String(upMinData, num),
getStrokeWidth() + getStrokeLeft() + 2,
(getStrokeWidth() + getStrokeTop() + upLatitudesSpacing
* latitudesUpNum) - 2, paint);
} else {
canvas.drawText(Parse.getInstance()
.parse2String(YData, num), getStrokeWidth()
+ getStrokeLeft() + 2, getStrokeWidth()
+ getStrokeTop() +
textSize / 2
+ upLatitudesSpacing *
i, paint);
}
YData -= spacing;
}
} else {
float YData = upMaxData;
float spacing = (upMaxData - upMinData) / (latitudesUpNum);
for (int i = 0; i < latitudesUpNum + 1; i++) {
// if (i < 2) {
// paint.setColor(getResources().getColor(R.color.z_red));
// } else if (i > 2) {
// paint.setColor(getResources().getColor(R.color.z_green));
// } else {
// paint.setColor(getResources()
// .getColor(R.color.z_list_title));
// }
if (i == 0) {
canvas.drawText(
Parse.getInstance().parse2String(YData, num),
getStrokeLeft()
- getStrokeWidth()
/ 2
- 2
- paint.measureText(Parse.getInstance()
.parse2String(YData, num)),
getStrokeWidth() + getStrokeTop() + textSize
+ upLatitudesSpacing * i, paint);
} else if (i == latitudesUpNum) {
canvas.drawText(
Parse.getInstance().parse2String(YData, num),
getStrokeLeft()
- getStrokeWidth()
/ 2
- 2
- paint.measureText(Parse.getInstance()
.parse2String(YData, num)),
(getStrokeWidth() + getStrokeTop() + upLatitudesSpacing
* i) - 2, paint);
} else {
canvas.drawText(
Parse.getInstance().parse2String(YData, num),
getStrokeLeft()
- getStrokeWidth()
/ 2
- 2
- paint.measureText(Parse.getInstance()
.parse2String(YData, num)),
getStrokeWidth() + getStrokeTop() + textSize / 2
+ upLatitudesSpacing * i, paint);
}
YData -= spacing;
}
}

}

/**
* 绘制下表Y轴X坐标
*
*
@param canvas
* @param paint
*/
private void drawDownAxisXTitle(Canvas canvas, TextPaint paint,
float dataWidth) {
paint.setColor(getResources().getColor(R.color.text_color_5c5f66));
float YData = downMinData;
float spacing = (downMaxData - downMinData) / (latitudesDownNum);

String text;

if (!isDrawOutside) {
for (int i = 0; i < latitudesDownNum + 1; i++) {
if (mIndexType == IndexType.VOL || mMainIndexType == MainIndexType.BOLL) {
text = Parse.getInstance().parse2CNStringWan(YData, 2,
false);
} else {
text = Parse.getInstance().parse2String(YData, num);
}
if (i == latitudesDownNum) {
canvas.drawText(text, getStrokeWidth() + getStrokeLeft()
+ 2, downChartBottom + textSize
- downLatitudesSpacing * i, paint);
} else if (i == 0) {
canvas.drawText(text, getStrokeWidth() + getStrokeLeft()
+ 2,
downChartBottom - downLatitudesSpacing * i - 2,
paint);
} else {
canvas.drawText(text, getStrokeWidth() + getStrokeLeft()
+ 2, downChartBottom + textSize / 2
- downLatitudesSpacing * i, paint);
}
YData += spacing;
}

} else {
for (int i = 0; i < latitudesDownNum + 1; i++) {
if (mIndexType == IndexType.VOL) {
text = Parse.getInstance().parse2CNStringWan(YData, 2,
false);
} else if (mIndexType == IndexType.MACD
// || mIndexType == IndexType.BOLL
|| mIndexType == IndexType.KDJ
|| mIndexType == IndexType.KD
|| mIndexType == IndexType.RSI
|| mIndexType == IndexType.BIAS
|| mIndexType == IndexType.BRAR
|| mIndexType == IndexType.CCI
|| mIndexType == IndexType.DMI
|| mIndexType == IndexType.CR
|| mIndexType == IndexType.PSY
|| mIndexType == IndexType.DMA
|| mIndexType == IndexType.TRIX) {
text = Parse.getInstance().parse2String(YData, num);
} else
text = Parse.getInstance().parse2CNStringWan(YData, 2,
false);
if (i == latitudesDownNum) {
canvas.drawText(text, getStrokeLeft() - getStrokeWidth()
/ 2 - 2 - paint.measureText(text),
downChartBottom
+ textSize - downLatitudesSpacing * i, paint);
} else if (i == 0) {
canvas.drawText(text, getStrokeLeft() - getStrokeWidth()
/ 2 - 2 - paint.measureText(text),
downChartBottom
- downLatitudesSpacing * i - 2, paint);
} else {
canvas.drawText(text, getStrokeLeft() - getStrokeWidth()
/ 2 - 2 - paint.measureText(text),
downChartBottom
+ textSize / 2 - downLatitudesSpacing * i, paint);
}
YData += spacing;
}
}
}

/**
* 绘制十字光标
*
*
@param canvas
* @param paint
*/
private void drawCrossLine(Canvas canvas, Paint paint, TextPaint tp) {
if (isShowCrossLine) {
paint.setStyle(Style.FILL);
paint.setColor(getContext().getResources().getColor(
R.color.cross_line_color));
paint.setStrokeWidth(1);
canvas.drawLine(getStrokeWidth() + getStrokeLeft(), crossY,
viewWidth - getStrokeWidth() - getStrokeRight(), crossY,
paint);
canvas.drawLine(crossX, getStrokeTop() + getStrokeWidth(), crossX,
upChartBottom, paint);
canvas.drawLine(crossX, upChartBottom + spacing, crossX,
downChartBottom, paint);

tp.setColor(Color.WHITE);
// float textWidth =
// tp.measureText(Parse.getInstance().parse2String(
// leftData));
float size = MyUtils.getInstance().dp2px(getContext(), 10);
paint.setStrokeWidth(textSize + 6);
String leftDatas = Parse.getInstance().parse2String(leftData, num);
float topS = crossY - (textSize + 6) / 2 <= getStrokeTop()
+ getStrokeWidth() ? getStrokeTop() +
getStrokeWidth()
+ (textSize + 6) / 2
: crossY;
topS = topS + (textSize + 6) / 2 >= upChartBottom ? upChartBottom
- (textSize + 6) / 2 : topS;
float dataWidth = tp.measureText(leftDatas);
if (!isDrawOutside) {
canvas.drawLine(getStrokeLeft() + getStrokeWidth() / 2
+ dataWidth + size, topS, getStrokeLeft()
+ getStrokeWidth() / 2, topS, paint);
canvas.drawText(leftDatas, getStrokeLeft() + getStrokeWidth()
/ 2 + size / 2,
topS + textSize / 2 - 3, tp);

/**
* 绘制时间
*/
String timeDatas;
if (isShowTime) {
timeDatas = MyUtils.getInstance().date2String("yyyy/MM/dd HH:mm", date);
} else {
if(data.get(0).getType() == T_D_TYPE){
timeDatas = MyUtils.getInstance().date2String("yyyy/MM/dd HH:mm:ss", date);
timeDatas = judgeTDNextDay(timeDatas);
}else {
timeDatas = MyUtils.getInstance().date2String("yyyy/MM/dd", date);

}
}
dataWidth = tp.measureText(timeDatas);
float timeY = upChartBottom + textSize / 2;
float drawTimeX = crossX - (dataWidth + size) / 2;
if (drawTimeX <= getStrokeLeft() + getStrokeWidth() / 2) {
drawTimeX = getStrokeLeft() + getStrokeWidth() / 2;
} else if (drawTimeX >= getWidth() - getStrokeRight()
- getStrokeWidth() / 2 - dataWidth - size) {
drawTimeX = getWidth() - getStrokeRight() - getStrokeWidth() / 2
- dataWidth - size;
}
canvas.drawLine(drawTimeX, timeY, drawTimeX + dataWidth + size, timeY, paint);
canvas.drawText(timeDatas, drawTimeX + size / 2, timeY + textSize / 2, tp);
} else {
size = MyUtils.getInstance().dp2px(getContext(), 1);
canvas.drawLine(getStrokeLeft() - getStrokeWidth() / 2
- dataWidth - size, topS, getStrokeLeft()
- getStrokeWidth() / 2, topS, paint);
canvas.drawText(leftDatas, getStrokeLeft() - getStrokeWidth()
/ 2 - dataWidth - size / 2,
topS + textSize / 2 - 3, tp);

/**
* 绘制时间
*/
String timeDatas;
if (isShowTime) {
timeDatas = MyUtils.getInstance().date2String("yyyy/MM/dd HH:mm", date);
} else {
timeDatas = MyUtils.getInstance().date2String("yyyy/MM/dd", date);
}
dataWidth = tp.measureText(timeDatas);
float timeY = upChartBottom + textSize / 2;
float drawTimeX = crossX - (dataWidth + size) / 2;
if (drawTimeX <= getStrokeLeft() + getStrokeWidth() / 2) {
drawTimeX = getStrokeLeft() + getStrokeWidth() / 2;
} else if (drawTimeX >= getWidth() - getStrokeRight()
- getStrokeWidth() / 2 - dataWidth - size) {
drawTimeX = getWidth() - getStrokeRight() - getStrokeWidth() / 2
- dataWidth - size;
}
canvas.drawLine(drawTimeX, timeY, drawTimeX + dataWidth + size, timeY, paint);
canvas.drawText(timeDatas, drawTimeX + size / 2, timeY + textSize / 2, tp);
}

}
}

/**
* 画箭头
*
*
@param sx
* @param sy
* @param ex
* @param ey
*/
public void drawAL(Canvas canvas, Paint paint, int sx, int sy, int ex, int ey) {
double H = 8; // 箭头高度
double L = 3.5; // 底边的一半
int x3 = 0;
int y3 = 0;
int x4 = 0;
int y4 = 0;
double awrad = Math.atan(L / H); // 箭头角度
double arraow_len = Math.sqrt(L * L + H * H); // 箭头的长度
double[] arrXY_1 = rotateVec(ex - sx, ey - sy, awrad, true, arraow_len);
double[] arrXY_2 = rotateVec(ex - sx, ey - sy, -awrad, true, arraow_len);
double x_3 = ex - arrXY_1[0]; // (x3,y3)是第一端点
double y_3 = ey - arrXY_1[1];
double x_4 = ex - arrXY_2[0]; // (x4,y4)是第二端点
double y_4 = ey - arrXY_2[1];
Double X3 = new Double(x_3);
x3 = X3.intValue();
Double Y3 = new Double(y_3);
y3 = Y3.intValue();
Double X4 = new Double(x_4);
x4 = X4.intValue();
Double Y4 = new Double(y_4);
y4 = Y4.intValue();
// 画线
canvas.drawLine(sx, sy, ex, ey, paint);
Path triangle = new Path();
triangle.moveTo(ex, ey);
triangle.lineTo(x3, y3);
triangle.lineTo(x4, y4);
triangle.close();
canvas.drawPath(triangle, paint);
}

// 计算
public double[] rotateVec(int px, int py, double ang, boolean isChLen, double newLen) {
double mathstr[] = new double[2];
// 矢量旋转函数,参数含义分别是x分量、y分量、旋转角、是否改变长度、新长度
double vx = px * Math.cos(ang) - py * Math.sin(ang);
double vy = px * Math.sin(ang) + py * Math.cos(ang);
if (isChLen) {
double d = Math.sqrt(vx * vx + vy * vy);
vx = vx / d * newLen;
vy = vy / d * newLen;
mathstr[0] = vx;
mathstr[1] = vy;
}
return mathstr;
}


@TargetApi(Build.VERSION_CODES.FROYO)
@Override
public boolean onTouchEvent(MotionEvent event) {
obtainVelocityTracker(event);
if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) {
releaseVelocityTracker();
}

switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
// 按下
if (data != null)
stopDeceleration();
downX = event.getX();
downY = event.getY();
if (downX < getStrokeLeft()
|| downX > getWidth() - getStrokeRight()) {
return super.onTouchEvent(event);
}
moveX = event.getRawX();
moveY = event.getRawY();
// 记录触摸起始点坐标
mTouchStartPoint.set(event.getX(), event.getY());
touchMode = 0;
// if (downX < getStrokeLeft() + getStrokeWidth() / 2) {
// return false;
// }
isMoved = false;
isReleased = false;
isStartMoved = false;
// isLeftRightMoved = false;
getParent().requestDisallowInterceptTouchEvent(true);
if (mRunnable != null) {
removeCallbacks(mRunnable);
postDelayed(mRunnable, 200);
}
return true;

case MotionEvent.ACTION_POINTER_DOWN:
// 多点
if (downX < getStrokeLeft()
|| downX > getWidth() - getStrokeRight()) {
return super.onTouchEvent(event);
}
if (data == null)
return false;
// oldDistance = spacing(event);

// 多点触摸一些起始性数据的记录
if (event.getPointerCount() >= 2) {

mSavedXDist = ChartUtils.getXDist(event);
mSavedDist = ChartUtils.spacing(event);

if (mSavedDist > 10f) {
isMoved = true;
touchMode = TOUCH_ZOOM;
}

// 取得多点触摸的两点的中点
ChartUtils.midPoint(mTouchPointCenter, event);
// 得到触摸所在的位置,保持缩放后,触摸位置不变
mTouchPosition = calculationTouchPosition(mTouchPointCenter);
mTouchCandleNum = candleNum;
mTouchStartPosition = position;
}

return true;

case MotionEvent.ACTION_MOVE:
// 触摸
if (downX < getStrokeLeft()
|| downX > getWidth() - getStrokeRight()) {
return super.onTouchEvent(event);
}
if (data == null)
return false;
// 子控件相对于父布局若达到滚动条件,则让父布局拦截触摸事件
if (Math.abs(event.getRawY() - moveY) > 50
&& Math.abs(event.getRawX() - moveX) < 150
&& touchMode == 0) {
isMoved = true;
getParent().requestDisallowInterceptTouchEvent(false);
}
// 左右边侧触摸时,忽略事件
// if (downX < getStrokeLeft() + getStrokeWidth() / 2) {
// return false;
// }
if (touchMode == TOUCH_ZOOM) {
// 处理缩放
return performZoom(event);
} else if (Math.abs(Math.abs(event.getX()) - Math.abs(downX)) > 50
&& Math.abs(Math.abs(event.getY()) - Math.abs(downY)) < 150
&& touchMode == 0) {
isMoved = true;
touchMode = TOUCH_DRAG;
}
if (touchMode == TOUCH_DRAG) {
return performDrag(event);
} else if (touchMode == TOUCH_ADSORPTION) {
return performAsorption(event);
}
return true;

case MotionEvent.ACTION_POINTER_UP:
if (downX < getStrokeLeft()
|| downX > getWidth() - getStrokeRight()) {
return super.onTouchEvent(event);
}
touchMode = 0;
ChartUtils.velocityTrackerPointerUpCleanUpIfNecessary(event,
mVelocityTracker);
return true;

case MotionEvent.ACTION_UP:
if (downX < getStrokeLeft()
|| downX > getWidth() - getStrokeRight()) {
return super.onTouchEvent(event);
}
// 对一次完整的触摸时间做计算统计,判断是否为快速手势事件
final VelocityTracker velocityTracker = mVelocityTracker;
final int pointerId = event.getPointerId(0);
velocityTracker.computeCurrentVelocity(1000,
ChartUtils.getMaximumFlingVelocity());
final float velocityY = velocityTracker.getYVelocity(pointerId);
final float velocityX = velocityTracker.getXVelocity(pointerId);
// 重置上一次fling的距离为0
mLastFlingDist = 0;
if (Math.abs(velocityX) > ChartUtils.getMinimumFlingVelocity()) {

if (touchMode == TOUCH_DRAG) {
mDecelerationLastTime = AnimationUtils
.currentAnimationTimeMillis();
mDecelerationCurrentPoint = new PointF(event.getX(),
event.getY());
mDecelerationVelocity = new PointF(velocityX, velocityY);

ChartUtils.postInvalidateOnAnimation(this);
}
}
if (touchMode == 0 && Math.abs(downX - event.getX()) < 30
&& Math.abs(downY - event.getY()) < 30) {
if (clickL != null)
clickL.click(this);
}
// 拿起
touchMode = 0;
getParent().requestDisallowInterceptTouchEvent(false);
isReleased = true;
isShowCrossLine = false;
if (l != null && data != null)
l.transferData(this, false, crossX, upColors, downColors, data,
(position + candleNum) >= data.size() ? data.size() - 1
: position +
candleNum, mIndexType, num);
invalidate();

releaseVelocityTracker();
return true;

default:
break;
}
return super.onTouchEvent(event);
}

/**
* (non-Javadoc)
*
*
@see View#computeScroll()
* <p/>
* 计算控件内容滚动。 此处的滚动并非视图的真正滚动,而是内容展示的滚动,根据手势记录下来的轨迹参数进行平滑的内容切换展示。
*/
@Override
public void computeScroll() {
if (data == null)
return;

int size = data.size();
if (mDecelerationVelocity.x == 0.f) {
// 滚动结束
return;
}

// 记录当前时间
final long currentTime = AnimationUtils.currentAnimationTimeMillis();

// 递减加速度范围(0-0.99],此值必须小于1且大于0的值,决定滚动的速度的快慢,越接近0速度越快
mDecelerationVelocity.x *= 0.9;

final float timeInterval = (float) (currentTime - mDecelerationLastTime) / 1000.f;

float distanceX = mDecelerationVelocity.x * timeInterval;

mDecelerationCurrentPoint.x += distanceX;

MotionEvent event = MotionEvent.obtain(currentTime, currentTime,
MotionEvent.ACTION_MOVE, mDecelerationCurrentPoint.x,
mDecelerationCurrentPoint.y, 0);
// 当前滚动的距离
float currFlingDist = event.getX() - mTouchStartPoint.x;
if (mLastFlingDist == 0)
mLastFlingDist = currFlingDist;
// 两次滚动距离的差,据此来计算滚动了多少个k线柱,两次滚动的值大于1个K线柱体的时候重绘视图
float fingDist = currFlingDist - mLastFlingDist;
if (Math.abs(fingDist) > dataSpacing) {
mLastFlingDist = currFlingDist;
if (fingDist < 0) {
isMoved = true;
// isLeftRightMoved = true;
if (size < candleNum) {
return;
} else {
int scaleCandle = (int) Math.abs(fingDist / dataSpacing);
for (int i = scaleCandle - 1; i >= 0; i--) {
position++;
if (position >= size - candleNum) {
position = size - candleNum;
invalidate();
break;
}
invalidate();
}
}
} else {
isMoved = true;
// isLeftRightMoved = true;
if (size < candleNum) {
return;
} else {
int scaleCandle = (int) Math.abs(fingDist / dataSpacing);
for (int i = scaleCandle - 1; i >= 0; i--) {
position--;
if (position <= 0) {
position = 0;
invalidate();
break;
}
invalidate();
}
}
}
}

event.recycle();
mDecelerationLastTime = currentTime;
if (Math.abs(mDecelerationVelocity.x) >= 1) {
ChartUtils.postInvalidateOnAnimation(this); // This causes
// computeScroll to
// fire, recommended for
// this by Google
} else {
stopDeceleration();
}
}

/**
* 减速运行结束,停止滚动
*/
public void stopDeceleration() {
mDecelerationVelocity = new PointF(0.f, 0.f);
}

private void obtainVelocityTracker(MotionEvent event) {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(event);
}

private void releaseVelocityTracker() {
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
}

/**
* 处理拖拽视图事件。
*
*
@param event
* @return
*/
private boolean performDrag(MotionEvent event) {
// 左右滑动事件
float indexX = event.getRawX() - moveX;
if (indexX < 0 - dataSpacing / 2) {
moveX = event.getRawX();
isMoved = true;
// isLeftRightMoved = true;
if (this.data.size() < candleNum) {
return false;
}

int scaleCandle = (int) Math.abs(indexX / dataSpacing);
if (scaleCandle == 0)
scaleCandle = 1;
position += scaleCandle;
if (position >= this.data.size() - candleNum) {
position = this.data.size() - candleNum;
}
invalidate();
return true;
} else if (indexX > dataSpacing / 2) {
moveX = event.getRawX();
isMoved = true;
// isLeftRightMoved = true;
if (this.data.size() < candleNum) {
return false;
}
int scaleCandle = (int) Math.abs(indexX / dataSpacing);
if (scaleCandle == 0)
scaleCandle = 1;
position -= scaleCandle;
if (position <= 0) {
position = 0;
}
invalidate();
if (isLoadMore && position == 0) {
isLoadMore = false;
if (onLoadMoreListener != null)
onLoadMoreListener.onLoadMore();
}
return true;
}
return true;
}

/**
* 处理十字光标视图事件。
*
*
@param event
* @return
*/
private boolean performAsorption(MotionEvent event) {
if (isStartMoved) {
if (data != null && data.size() > 0) {
calculationCrossLine(event);
return true;
}
}
return true;
}

/**
* 多点触摸,根据手势进行放大或者缩小。
*
*
@param event
*/
@TargetApi(Build.VERSION_CODES.ECLAIR)
private boolean performZoom(MotionEvent event) {
if (event.getPointerCount() >= 2) {
float totalDist = ChartUtils.spacing(event);
if (totalDist > 10f) {
float xDist = ChartUtils.getXDist(event);
// x轴方向 scale
float scaleX = xDist / mSavedXDist;

// 是否缩小
boolean isZoomingOut = (scaleX < 1);
// Log.d(VIEW_LOG_TAG,
// "touchPostion:"+mTouchPosition+",xDist:"+xDist+",mSavedXDist:"+mSavedXDist+",isZoomingOut:"+isZoomingOut+",scaleX:"+scaleX);
if (!isZoomingOut) {
if (candleNum <= minCandleNum) {
// 无法继续放大
return false;
}
} else {
if (candleNum >= maxCandleNum) {
// 无法继续缩小
return false;
}
}
isMoved = true;
// Log.d(VIEW_LOG_TAG,
// "position:"+position+",candleNum:"+candleNum);
// 计算缩放后的position位置
if (mTouchPosition != -1)
position = (int) (mTouchPosition - (mTouchPosition - mTouchStartPosition)
/ scaleX);
// 防止position超出边界
if (position < 0)
position = 0;
// 计算缩放后的candelNum大小
candleNum = (int) (mTouchCandleNum / scaleX);

invalidate();
}
}
return true;
}

/**
* 计算十字光标位置
*
*
@param event
*/
private void calculationCrossLine(MotionEvent event) {
float startX = getStrokeWidth() + getStrokeLeft();
int index = 0;
for (int i = position; i < data.size() && i < candleNum + position; i++) {
KLineData entity = data.get(i);
// 柱形图
float openY = upChartBottom
- ((float) entity.getOpen() - upMinData) * upDataRatio;
float closeY = upChartBottom
- ((float) entity.getClose() - upMinData) * upDataRatio;
// 中线
// float highY = upChartBottom - (entity.getHigh() - upMinData)
// * upDataRatio;
// float lowY = upChartBottom - (entity.getLow() - upMinData)
// * upDataRatio;

float endX = getStrokeWidth() + getStrokeLeft()
+ (dataSpacing * (index + 1) - dataSpacing * 0.25f);

if (event.getX() > startX && event.getX() < endX) {
isShowCrossLine = true;
crossX = (endX - startX) / 2 + startX;
if (openY < closeY) {// 绿色
crossY = closeY;
} else if (openY > closeY) {// 红色
crossY = closeY;
} else {// 红色
crossY = openY;
}
leftData = Parse.getInstance().parseFloat(
Parse.getInstance()
.parse2String(entity.getClose(), num));
date = entity.getTime() * 1000;
if (l != null) {
l.transferData(this, true, crossX, upColors, downColors,
data, i, mIndexType, num);
}
invalidate();
return;
}
startX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* (index + 1);
index++;
}
}

/**
* 计算触摸所在的数据位置
*/
private int calculationTouchPosition(PointF point) {
float startX = getStrokeWidth() + getStrokeLeft();
int index = 0;
for (int i = position; i < data.size() && i < candleNum + position && i >= 0; i++) {

KLineData entity = data.get(i);
// 柱形图
// float openY = upChartBottom
// - ((float) entity.getOpen() - upMinData) * upDataRatio;
// float closeY = upChartBottom
// - ((float) entity.getClose() - upMinData) * upDataRatio;
// 中线
// float highY = upChartBottom - (entity.getHigh() - upMinData)
// * upDataRatio;
// float lowY = upChartBottom - (entity.getLow() - upMinData)
// * upDataRatio;

float endX = getStrokeWidth() + getStrokeLeft()
+ (dataSpacing * (index + 1) - dataSpacing * 0.25f);

if (point.x > startX && point.x < endX) {
return i;
}
startX = getStrokeWidth() + getStrokeLeft() + dataSpacing
* (index + 1);
index++;
}
return -1;
}


/**
* 获取字体大小(像素单位)
*
*
@return
*/
public float getTextSize() {
return textSize;
}

/**
* 设置字体大小(像素单位)
*
*
@param textSize
*/
public void setTextSize(float textSize) {
this.textSize = textSize;
}

/**
* 获取上表与下表间距
*
*
@return
*/
public float getSpacing() {
return spacing;
}

/**
* 设置上表与下表间距
*
*
@param spacing
*/
public void setSpacing(float spacing) {
if (spacing < MyUtils.getInstance().dp2px(getContext(),
DEFAULT_TEXT_SIZE)) {
spacing = MyUtils.getInstance().dp2px(getContext(),
DEFAULT_TEXT_SIZE) * 2;
} else {
this.spacing = spacing;
}
}

/**
* 获取上表底部与控件顶部距离(是负值)
*
*
@return
*/
public float getUpChartBottom() {
return upChartBottom;
}

/**
* 获取
*
*
@return
*/
public float getUpChartHeight() {
return Math.abs(upChartHeight);
}

/**
* 获取下表高度
*
*
@return
*/
public float getDownChartHeight() {
return downChartHeight;
}

/**
* 设置数据
*
*
@param data
*/
public synchronized void setData(Vector<KLineData> data, IndexType type, MainIndexType mainIndexType) {

if (this.data == null) {
if (data == null || data.size() < candleNum) {
position = 0;
} else {
position = data.size() - candleNum;
}
} else {
if (data == null || data.size() < candleNum) {
position = 0;
} else if (position > data.size() - candleNum) {
position = data.size() - candleNum;
} else if (position < 0) {
position = 0;
} else if (isLoadMore) {
position += oldSize;
oldSize = 0;
if (position > data.size() - candleNum) {
position = data.size() - candleNum;
}
}
}

notifyRunnable.setData(data, type, mainIndexType);
executorService.execute(notifyRunnable);
}

/**
* 设置时间显示样式(true:显示yyyy/MM/dd HH:mm;false:显示yyyy/MM/dd)
*
*
@param isShowTime
*/

public void setShowTime(boolean isShowTime) {
this.isShowTime = isShowTime;
}

/**
* 清除K线
*/
public void clean() {
this.data = null;
invalidate();
}

/**
* 更新数据、指标的线程
*
*
@author dingrui
*/
class NotifyRunnable implements Runnable {

private Vector<KLineData> dataOld;
private IndexType type;
private MainIndexType mainIndexType;

public NotifyRunnable() {
dataOld = null;
type = IndexType.VOL;
}

public void setData(Vector<KLineData> data, IndexType type, MainIndexType mainIndexType) {
this.dataOld = data;
this.type = type;
this.mainIndexType = mainIndexType;
}

public IndexType getType() {
return type;
}

@Override
public void run() {
// TODO Auto-generated method stub
//加入同步锁
synchronized (this) {
if (null == dataOld) {
return;
}
Vector<KLineData> data = new Vector<>();
for (int i = 0; i < dataOld.size(); i++) {
KLineData oldItem = dataOld.get(i);
KLineData item = new KLineData();
item.setType(oldItem.getType());
item.setTime(oldItem.getTime());
item.setClose(oldItem.getClose());
item.setOpen(oldItem.getOpen());
item.setLowPrice(oldItem.getLowPrice());
item.setHighPrice(oldItem.getHighPrice());
item.setCjl(oldItem.getCjl());
item.setCje(oldItem.getCje());
data.add(item);
}
if (mainIndexType == MainIndexType.BOLL) {
data = IndexCalculation.calculationBOLL(data);
}
if (type == IndexType.VOL) {
data = IndexCalculation.calculationVol(data);
} else if (type == IndexType.MACD) {
// 计算MACD
data = IndexCalculation.calculationMACD(data);
}/* else if (type == IndexType.BOLL) {
// 计算布林指标
data = IndexCalculation.calculationBOLL(data);
data = IndexCalculation.calculationVol(data);
}*/
else if (type == IndexType.KDJ || type == IndexType.KD) {
// 计算KDJ
data = IndexCalculation.calculationKDJ(data);
} else if (type == IndexType.RSI) {
// 计算RSI
data = IndexCalculation.calculationRSI(data);
} else if (type == IndexType.BIAS) {
// 计算BIAS
data = IndexCalculation.calculationBIAS(data);
} else if (type == IndexType.BRAR) {
// 计算BRAR
data = IndexCalculation.calculationBRAR(data);
} else if (type == IndexType.CCI) {
// 计算CCI
data = IndexCalculation.calculationCCI(data);
} else if (type == IndexType.DMI) {
// 计算DMI
data = IndexCalculation.calculationDMI(data);
} else if (type == IndexType.CR) {
// 计算CR
data = IndexCalculation.calculationCR(data);
} else if (type == IndexType.PSY) {
// 计算PSY
data = IndexCalculation.calculationPSY(data);
} else if (type == IndexType.DMA) {
// 计算DMA
data = IndexCalculation.calculationDMA(data);
} else if (type == IndexType.TRIX) {
// 计算TRIX
data = IndexCalculation.calculationTRIX(data);
}

Bundle bundle = new Bundle();
bundle.putSerializable("data", data);
if (mainIndexType == MainIndexType.MA) {
bundle.putInt("mainindex", 0);
} else if (mainIndexType == MainIndexType.BOLL) {
bundle.putInt("mainindex", 1);
}
Message msg = handler.obtainMessage();
msg.what = 0x1;
msg.setData(bundle);
msg.obj = type;
handler.sendMessage(msg);
}
}
}

public IndexType getIndexType() {
return notifyRunnable.getType();
}

/**
* 是否设置了将坐标绘制在框外
*
*
@return
*/
public boolean isDrawOutside() {
return isDrawOutside;
}

/**
* 设置是否将两边坐标值绘制在边框线外(注:如果设置成true,必须设置strokeLeft和strokeRight)
*
*
@param strokeLeft 左边距
*
@param strokeRight 右边距
*/
public void setDrawOutside(boolean isDrawOutside, float strokeLeft,
float strokeRight) {
this.isDrawOutside = isDrawOutside;
if (isDrawOutside == false) {
setStrokeLeft(1.0f);
setStrokeRight(1.0f);
} else {
setStrokeLeft(strokeLeft);
setStrokeRight(strokeRight);
}
invalidate();
}

/**
* 设置当前显示k线数量
*
*
@param candleNum
*/
public void setCandleNum(int candleNum) {
this.candleNum = candleNum;
if (data == null || data.size() < candleNum) {
position = 0;
} else {
position = data.size() - candleNum;
}
}

/**
* 设置当前显示K线数量上限
*
*
@param maxCandleNum
*/
public void setMaxCandleNum(int maxCandleNum) {
this.maxCandleNum = maxCandleNum;
}

/**
* 设置当前显示K线数量下限
*
*
@param minCandleNum
*/
public void setMinCandleNum(int minCandleNum) {
this.minCandleNum = minCandleNum;
}

/**
* 加载完成并开启加载更多接口
*
*
@param oldDataSize 加载更多后的数据长度
*/
public void loadMoreFinish(int oldDataSize) {
isLoadMore = true;
oldSize = oldDataSize;
}

/**
* 小数保留位数
*
*
@param num
*/
public void setNum(int num) {
this.num = num;
invalidate();
}

/**
* 设置接口
*
*
@param l
*/
public void setKLineListener(KLineListener l) {
this.l = l;
}

/**
* 接口
*
*
@author dingrui
*/
public interface KLineListener {

public void transferData(View view, boolean isMoved, float touchX,
int[] upColors, int[] downColors, Vector<KLineData> data,
int position, IndexType mIndexType, int num);
}

/**
* 设置点击事件接口
*
*
@param l
*/
public void setOnKLineChartClickListener(OnKLineChartClickListener l) {
this.clickL = l;
}

/**
* 单击事件接口
*
*
@author dingrui
*/
public interface OnKLineChartClickListener {
public void click(View v);
}

/**
* 设置加载更多接口
*
*
@param onLoadMoreListener
*/
public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
this.onLoadMoreListener = onLoadMoreListener;
}

/**
* 加载更多接口
*/
public interface OnLoadMoreListener {
public void onLoadMore();
}
}
package com.kedll.kedelllibrary.stock;

import java.io.Serializable;

public class KLineData implements Serializable {
    /**
     * 区分交易品种
     */
    private int type;

    /**
     * 是否绘制时间和经线
     */
    private boolean isDrawLongitude;

    /**
     * 时间
     */
    private long time;
    /**
     * 开盘价
     */
    private double open;
    /**
     * 收盘价
     */
    private double close;
    /**
     * 最高价
     */
    private double highPrice;
    /**
     * 最低价
     */
    private double lowPrice;
    /**
     * 成交额原始数据(非累加)
     */
    private double cje;
    /**
     * 成交量原始数据(非累加)
     */
    private double cjl;
    /**
     * 涨跌
     */
    private double change;
    /**
     * 涨跌幅
     */
    private double changep;
    /**
     * 均线
     */
    private DayMovingAverage dayMovingAverage;

    /** 指标相关 */
    /**
     * 成交量
     */
    private Volume volume;
    /**
     * 指数平滑异同平均线(MACD指标)
     */
    private MACD macd;
    /**
     * 动向指标
     */
    private DMI dmi;
    /**
     * 威廉指标
     */
    private WR wr;
    /**
     * 布林线
     */
    private BOLL boll;
    /**
     * 随机指标(KDJ)
     */
    private KDJ kdj;
    /**
     * OBV指标(统计成交量变动的趋势来推测股价趋势)
     */
    private OBV obv;
    /**
     * 强弱指标
     */
    private RSI rsi;
    /**
     * 停损转向操作点指标
     */
    private SAR sar;
    /**
     * 乖离率(BIAS)是测量股价偏离均线大小程度的指标
     */
    private BIAS bias;
    /**
     * 情绪指标(BRAR)也称为人气意愿指标
     */
    private BRAR brar;
    /**
     * 顺势指标
     */
    private CCI cci;
    /**
     * 能量指标
     */
    private CR cr;
    /**
     * 心理线(PSY)指标是研究投资者对股市涨跌产生心理波动的情绪指标
     */
    private PSY psy;
    /**
     * 平行线差指标
     */
    private DMA dma;
    /**
     * 三重指数平滑平均线(TRIX)属于长线指标
     */
    private TRIX trix;

    public KLineData() {

    }

    /**
     * 构造函数
     *
     * @param time      时间
     * @param open      开盘价
     * @param close     收盘价
     * @param highPrice 最高价
     * @param lowPrice  最低价
     * @param cje       成交额
     * @param cjl       成交量
     */
    public KLineData(long time, double open, double close, double highPrice,
                     double lowPrice, double cje, double cjl) {
        this.time = time;
        this.open = open;
        this.close = close;
        this.highPrice = highPrice;
        this.lowPrice = lowPrice;
        this.cje = cje;
        this.cjl = cjl;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    public boolean isDrawLongitude() {
        return isDrawLongitude;
    }

    public void setDrawLongitude(boolean isDrawLongitude) {
        this.isDrawLongitude = isDrawLongitude;
    }

    public long getTime() {
        return time;
    }

    public void setTime(long time) {
        this.time = time;
    }

    public double getOpen() {
        return open;
    }

    public void setOpen(double open) {
        this.open = open;
    }

    public double getClose() {
        return close;
    }

    public void setClose(double close) {
        this.close = close;
    }

    public double getHighPrice() {
        return highPrice;
    }

    public void setHighPrice(double highPrice) {
        this.highPrice = highPrice;
    }

    public double getLowPrice() {
        return lowPrice;
    }

    public void setLowPrice(double lowPrice) {
        this.lowPrice = lowPrice;
    }

    public double getCje() {
        return cje;
    }

    public void setCje(double cje) {
        this.cje = cje;
    }

    public double getCjl() {
        return cjl;
    }

    public void setCjl(double cjl) {
        this.cjl = cjl;
    }

    public double getChange() {
        return change;
    }

    public void setChange(double change) {
        this.change = change;
    }

    public double getChangep() {
        return changep;
    }

    public void setChangep(double changep) {
        this.changep = changep;
    }

    public DayMovingAverage getDayMovingAverage() {
        return dayMovingAverage == null ? new DayMovingAverage(0, 0, 0)
                                        : dayMovingAverage;
    }

    public void setDayMovingAverage(DayMovingAverage dayMovingAverage) {
        this.dayMovingAverage = dayMovingAverage;
    }

    public Volume getVolume() {
        return volume == null ? new Volume(0, 0, 0, 0) : volume;
    }

    public void setVolume(Volume volume) {
        this.volume = volume;
    }

    public MACD getMacd() {
        return macd;
    }

    public void setMacd(MACD macd) {
        this.macd = macd;
    }

    public DMI getDmi() {
        return dmi;
    }

    public void setDmi(DMI dmi) {
        this.dmi = dmi;
    }

    public WR getWr() {
        return wr;
    }

    public void setWr(WR wr) {
        this.wr = wr;
    }

    public BOLL getBoll() {
        return boll;
    }

    public void setBoll(BOLL boll) {
        this.boll = boll;
    }

    public KDJ getKdj() {
        return kdj;
    }

    public void setKdj(KDJ kdj) {
        this.kdj = kdj;
    }

    public OBV getObv() {
        return obv;
    }

    public void setObv(OBV obv) {
        this.obv = obv;
    }

    public RSI getRsi() {
        return rsi;
    }

    public void setRsi(RSI rsi) {
        this.rsi = rsi;
    }

    public SAR getSar() {
        return sar;
    }

    public void setSar(SAR sar) {
        this.sar = sar;
    }

    public BIAS getBias() {
        return bias;
    }

    public void setBias(BIAS bias) {
        this.bias = bias;
    }

    public BRAR getBrar() {
        return brar;
    }

    public void setBrar(BRAR brar) {
        this.brar = brar;
    }

    public CCI getCci() {
        return cci;
    }

    public void setCci(CCI cci) {
        this.cci = cci;
    }

    public CR getCr() {
        return cr;
    }

    public void setCr(CR cr) {
        this.cr = cr;
    }

    public PSY getPsy() {
        return psy;
    }

    public void setPsy(PSY psy) {
        this.psy = psy;
    }

    public DMA getDma() {
        return dma;
    }

    public void setDma(DMA dma) {
        this.dma = dma;
    }

    public TRIX getTrix() {
        return trix;
    }

    public void setTrix(TRIX trix) {
        this.trix = trix;
    }

    /**
     * 均线
     *
     * @author dingrui
     */
    public static class DayMovingAverage implements Serializable {
        /**
         * 5日均线
         */
        private double ma5;
        /**
         * 10日均线
         */
        private double ma10;
        /**
         * 20日均线
         */
        private double ma20;

        public DayMovingAverage() {

        }

        public DayMovingAverage(double ma5, double ma10, double ma20) {
            this.ma5 = ma5;
            this.ma10 = ma10;
            this.ma20 = ma20;
        }

        public double getMa5() {
            return ma5;
        }

        public void setMa5(double ma5) {
            this.ma5 = ma5;
        }

        public double getMa10() {
            return ma10;
        }

        public void setMa10(double ma10) {
            this.ma10 = ma10;
        }

        public double getMa20() {
            return ma20;
        }

        public void setMa20(double ma20) {
            this.ma20 = ma20;
        }

    }

    /**
     * 成交量指标
     *
     * @author dingrui
     */
    public static class Volume implements Serializable {
        /**
         * 成交量
         */
        private double num;
        /**
         * 均线
         */
        private double ma5;
        private double ma10;
        private double ma20;

        public Volume(double num, double ma5, double ma10, double ma20) {
            this.num = num;
            this.ma5 = ma5;
            this.ma10 = ma10;
            this.ma20 = ma20;
        }

        public double getNum() {
            return num;
        }

        public void setNum(double num) {
            this.num = num;
        }

        public double getMa5() {
            return ma5;
        }

        public void setMa5(double ma5) {
            this.ma5 = ma5;
        }

        public double getMa10() {
            return ma10;
        }

        public void setMa10(double ma10) {
            this.ma10 = ma10;
        }

        public double getMa20() {
            return ma20;
        }

        public void setMa20(double ma20) {
            this.ma20 = ma20;
        }

    }

    /**
     * 指数平滑异同平均线(MACD指标)
     *
     * @author dingrui
     */
    public static class MACD implements Serializable {
        private double diff;
        private double dea;
        private double macd;

        public MACD(double diff, double dea, double macd) {
            this.diff = diff;
            this.dea = dea;
            this.macd = macd;
        }

        public double getDiff() {
            return diff;
        }

        public void setDiff(double diff) {
            this.diff = diff;
        }

        public double getDea() {
            return dea;
        }

        public void setDea(double dea) {
            this.dea = dea;
        }

        public double getMacd() {
            return macd;
        }

        public void setMacd(double macd) {
            this.macd = macd;
        }
    }

    /**
     * 动向指标
     *
     * @author dingrui
     */
    public static class DMI implements Serializable {
        private double pdi;
        private double mdi;
        private double adx;
        private double adxr;

        public DMI(double pdi, double mdi, double adx, double adxr) {
            this.pdi = pdi;
            this.mdi = mdi;
            this.adx = adx;
            this.adxr = adxr;
        }

        public double getPdi() {
            return pdi;
        }

        public void setPdi(double pdi) {
            this.pdi = pdi;
        }

        public double getMdi() {
            return mdi;
        }

        public void setMdi(double mdi) {
            this.mdi = mdi;
        }

        public double getAdx() {
            return adx;
        }

        public void setAdx(double adx) {
            this.adx = adx;
        }

        public double getAdxr() {
            return adxr;
        }

        public void setAdxr(double adxr) {
            this.adxr = adxr;
        }
    }

    /**
     * 威廉指标
     *
     * @author dingrui
     */
    public class WR implements Serializable {
        private double wr1;
        private double wr2;

        public WR(double wr1, double wr2) {
            this.wr1 = wr1;
            this.wr2 = wr2;
        }

        public double getWr1() {
            return wr1;
        }

        public void setWr1(double wr1) {
            this.wr1 = wr1;
        }

        public double getWr2() {
            return wr2;
        }

        public void setWr2(double wr2) {
            this.wr2 = wr2;
        }
    }

    /**
     * 布林线
     *
     * @author dingrui
     */
    public static class BOLL implements Serializable {
        private double upper;
        private double mID;
        private double lower;

        public BOLL(double upper, double mID, double lower) {
            this.upper = upper;
            this.mID = mID;
            this.lower = lower;
        }

        public double getUpper() {
            return upper;
        }

        public void setUpper(double upper) {
            this.upper = upper;
        }

        public double getmID() {
            return mID;
        }

        public void setmID(double mID) {
            this.mID = mID;
        }

        public double getLower() {
            return lower;
        }

        public void setLower(double lower) {
            this.lower = lower;
        }
    }

    /**
     * 随机指标(KDJ)
     *
     * @author dingrui
     */
    public static class KDJ implements Serializable {
        private double K;
        private double D;
        private double J;

        public KDJ(double K, double D, double J) {
            this.K = K;
            this.D = D;
            this.J = J;
        }

        public double getK() {
            return K;
        }

        public void setK(double k) {
            K = k;
        }

        public double getD() {
            return D;
        }

        public void setD(double d) {
            D = d;
        }

        public double getJ() {
            return J;
        }

        public void setJ(double j) {
            J = j;
        }
    }

    /**
     * OBV指标(统计成交量变动的趋势来推测股价趋势)
     *
     * @author dingrui
     */
    public class OBV implements Serializable {
        private double obv;

        public OBV(double obv) {
            this.obv = obv;
        }

        public double getObv() {
            return obv;
        }

        public void setObv(double obv) {
            this.obv = obv;
        }
    }

    /**
     * 强弱指标
     *
     * @author dingrui
     */
    public static class RSI implements Serializable {
        private double rsi6;
        private double rsi12;
        private double rsi24;

        public RSI(double rsi6, double rsi12, double rsi24) {
            this.rsi6 = rsi6;
            this.rsi12 = rsi12;
            this.rsi24 = rsi24;
        }

        public double getRsi6() {
            return rsi6;
        }

        public void setRsi6(double rsi6) {
            this.rsi6 = rsi6;
        }

        public double getRsi12() {
            return rsi12;
        }

        public void setRsi12(double rsi12) {
            this.rsi12 = rsi12;
        }

        public double getRsi24() {
            return rsi24;
        }

        public void setRsi24(double rsi24) {
            this.rsi24 = rsi24;
        }
    }

    /**
     * 停损转向操作点指标
     *
     * @author dingrui
     */
    public class SAR implements Serializable {
        private double sar;

        public SAR(double sar) {
            this.sar = sar;
        }

        public double getSar() {
            return sar;
        }

        public void setSar(double sar) {
            this.sar = sar;
        }
    }

    /**
     * 乖离率(BIAS)是测量股价偏离均线大小程度的指标
     *
     * @author dingrui
     */
    public static class BIAS implements Serializable {
        private double bias1;// 5
        private double bias2;// 10
        private double bias3;// 20

        public BIAS(double bias1, double bias2, double bias3) {
            this.bias1 = bias1;
            this.bias2 = bias2;
            this.bias3 = bias3;
        }

        public double getBias1() {
            return bias1;
        }

        public void setBias1(double bias1) {
            this.bias1 = bias1;
        }

        public double getBias2() {
            return bias2;
        }

        public void setBias2(double bias2) {
            this.bias2 = bias2;
        }

        public double getBias3() {
            return bias3;
        }

        public void setBias3(double bias3) {
            this.bias3 = bias3;
        }

    }

    /**
     * 情绪指标(BRAR)也称为人气意愿指标
     *
     * @author dingrui
     */
    public static class BRAR implements Serializable {
        private double br;
        private double ar;

        public BRAR(double br, double ar) {
            this.br = br;
            this.ar = ar;
        }

        public double getBr() {
            return br;
        }

        public void setBr(double br) {
            this.br = br;
        }

        public double getAr() {
            return ar;
        }

        public void setAr(double ar) {
            this.ar = ar;
        }

    }

    /**
     * 顺势指标
     *
     * @author dingrui
     */
    public static class CCI implements Serializable {
        private double cci;

        public CCI(double cci) {
            this.cci = cci;
        }

        public double getCci() {
            return cci;
        }

        public void setCci(double cci) {
            this.cci = cci;
        }
    }

    /**
     * 能量指标
     *
     * @author dingrui
     */
    public static class CR implements Serializable {
        private double cr;
        private double ma1;
        private double ma2;
        private double ma3;

        public CR(double cr, double ma1, double ma2, double ma3) {
            this.cr = cr;
            this.ma1 = ma1;
            this.ma2 = ma2;
            this.ma3 = ma3;
        }

        public double getCr() {
            return cr;
        }

        public void setCr(double cr) {
            this.cr = cr;
        }

        public double getMa1() {
            return ma1;
        }

        public void setMa1(double ma1) {
            this.ma1 = ma1;
        }

        public double getMa2() {
            return ma2;
        }

        public void setMa2(double ma2) {
            this.ma2 = ma2;
        }

        public double getMa3() {
            return ma3;
        }

        public void setMa3(double ma3) {
            this.ma3 = ma3;
        }

    }

    /**
     * 心理线(PSY)指标是研究投资者对股市涨跌产生心理波动的情绪指标
     *
     * @author dingrui
     */
    public static class PSY implements Serializable {
        private double psy;

        public PSY(double psy) {
            this.psy = psy;
        }

        public double getPsy() {
            return psy;
        }

        public void setPsy(double psy) {
            this.psy = psy;
        }
    }

    /**
     * 平行线差指标
     *
     * @author dingrui
     */
    public static class DMA implements Serializable {
        private double dif;
        private double ama;

        public DMA(double dif, double ama) {
            this.dif = dif;
            this.ama = ama;
        }

        public double getDif() {
            return dif;
        }

        public void setDif(double dif) {
            this.dif = dif;
        }

        public double getAma() {
            return ama;
        }

        public void setAma(double ama) {
            this.ama = ama;
        }
    }

    /**
     * 三重指数平滑平均线(TRIX)属于长线指标
     *
     * @author dingrui
     */
    public static class TRIX implements Serializable {
        private double trix;
        private double maTrix;

        public TRIX(double trix, double maTrix) {
            this.trix = trix;
            this.maTrix = maTrix;
        }

        public double getTrix() {
            return trix;
        }

        public void setTrix(double trix) {
            this.trix = trix;
        }

        public double getMaTrix() {
            return maTrix;
        }

        public void setMaTrix(double maTrix) {
            this.maTrix = maTrix;
        }
    }
}

关注公众号“大模型全栈程序员”回复“小程序”获取1000个小程序打包源码。更多免费资源在http://www.gitweixin.com/?p=2627

发表评论

邮箱地址不会被公开。 必填项已用*标注