// // ChartView.m // ChartView // // Created by Simon Zhou on 14-6-11. // Copyright (c) 2014年 muchinfo. All rights reserved. // #import "ChartView.h" #import "ChartData.h" #import "ChartCalculateUtils.h" #define TAG_BUTTON_MACD 1000 #define TAG_BUTTON_KDJ 1001 #define TAG_BUTTON_RSI 1002 @implementation ChartView { /// X轴相关 /// X轴宽度,通过视图宽度-价格标签宽度-边框Padding计算得出 CGFloat _xAxisWidth; /// X轴左边距,即价格标签宽度 CGFloat _xAxisPaddingLeft; /// X轴右边距,默认为5.0f(因为要显示最后一个时间标签) CGFloat _xAxisPaddingRight; CGFloat _excessXAxisWidth; /// Y轴相关 /// Y轴高度,通过视图高度-边框Padding计算得出 CGFloat _yAxisHeight; /// 当前可视Y轴最大值 CGFloat _yAxisMaxValue; /// 当前可视Y轴最小值 CGFloat _yAxisMinValue; /// K起点 /// 坐标原点 CGPoint _kLineOrigin; /// K线相关 /// K线形状最小宽度 CGFloat _kLineMinWidth; /// K线形状最大宽度 CGFloat _kLineMaxWidth; /// K线形状之间的间隔,默认为1.0f CGFloat _kLinePadding; /// K线形状宽度,默认为5.0f CGFloat _kLineWidth; /// 可显示K线数量,由_xAxisWidth/_kLineWidth 计算得出 NSInteger _kLineCount; /// 当前可视K线数据起始下标 NSInteger _kLineStartIndex; /// 当前可视K线数据 NSInteger _kLineEndIndex; /// 十字线相关 /// 是否显示十字线 BOOL _isShowTipLine; /// 十字线当前K线下标 NSInteger _tipLineIndex; /// 十字线Y轴坐标 CGFloat _tipLineYAxis; /// MACD相关 /// 指标框下边距 CGFloat _indicatorPaddingBottom; /// 指标原点 CGPoint _indicatorOrigin; /// MACD可视指标最大值 CGFloat _indicatorMaxValue; /// MACD可视指标最小值 CGFloat _indicatorMinValue; /// VOL相关 /// VOL可视指标最大值 CGFloat _indicatorVOLMaxValue; /// VOL可视指标最小值 CGFloat _indicatorVOLMiniValue; /// KDJ相关 /// KDJ可视指标最大值 CGFloat _indicatorKDJMaxValue; /// KDJ可视指标最小值 CGFloat _indicatorKDJMiniValue; /// RSI相关 /// RSI可视指标最大值 CGFloat _indicatorRSIMaxValue; /// RSI可视指标最小值 CGFloat _indicatorRSIMiniValue; /// CCI相关 /// CCI可视指标最大值 CGFloat _indicatorCCIMaxValue; /// CCI可视指标最小值 CGFloat _indicatorCCIMiniValue; /// DMA相关 /// DMA可视指标最大值 CGFloat _indicatorDMAMaxValue; /// DMA可视指标最小值 CGFloat _indicatorDMAMiniValue; /// BIAS相关 /// BIAS可视指标最大值 CGFloat _indicatorBIASMaxValue; /// BIAS可视指标最小值 CGFloat _indicatorBIASMiniValue; /// PSY相关 /// PSY可视指标最大值 CGFloat _indicatorPSYMaxValue; /// PSY可视指标最小值 CGFloat _indicatorPSYMiniValue; /// CR相关 /// CR可视指标最大值 CGFloat _indicatorCRMaxValue; /// CR可视指标最小值 CGFloat _indicatorCRMiniValue; /// 交互相关 CGPoint _startTouchPosition; CGFloat _startScale; /// 分时图相关 /// 分时图最早数据开始X轴(因有时开盘时间与第一口价格有时间差) CGFloat _tsStartXPonit; /// 现价相关 /// 行情现价 NSDecimalNumber *_price; /// 现价报价时间 NSDate *_priceTime; /// FIXME: 临时变量 BOOL _added; } #pragma mark - 重载方法 - (void)layoutSubviews { // NSLog(@"%s",__func__); } - (void)drawRect:(CGRect)rect { if (!_chartDataArray) { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetRGBFillColor(context, _bgRed, _bgGreen, _bgBlue, 1.0f); CGContextFillRect(context, self.bounds); return; } /// 更新数据的方法 [self updateData]; /// 画框图表架 [self drawBorder]; /// 画图表X轴 [self drawXAxis]; /// 画图表Y轴 [self drawYAxis]; if (_chartViewType == ChartViewTypeKL) { if (_isBBGoods) { /// K线 [self drawBBTSPlanLine]; /// 画平均线 [self drawBBAverageLine]; } else { /// K线 [self drawKLine]; /// 画平均线 [self drawAverageLine]; if (_isShowIndicator) { /// 需要显示指标 switch (_chartTargetType) { case MACD: { /// 指标为MACD /// 初始化MACD可视化数据 [self initMACDData]; /// 画MACD指标的方法 [self drawMACD]; break; } case VOL:{ /// 指标为VOL /// 初始化VOL可视化数据 [self initVOLData]; /// 画VOL指标的方法 [self drawVOL]; break; } case KDJ: { /// 指标为KDJ /// 初始化KDJ可视化数据 [self initKDJData]; /// 画KDJ指标的方法 [self drawKDJ]; break; } case CCI: { /// 指标为CCI /// 初始化CCI可视化数据 [self initCCIData]; /// 画CCI指标的方法 [self drawCCI]; break; } case PSY: { /// 指标为PSY /// 初始化PSY可视化数据 [self initPSYData]; /// 画PSY指标的方法 [self drawPSY]; break; } case BIAS: { /// 指标为BIAS /// 初始化BIAS可视化数据 [self initBIASData]; /// 画BIAS指标的方法 [self drawBIAS]; break; } case KD: { /// 指标为KD /// 初始化KD可视化数据 [self initKDJData]; /// 画KD指标的方法 [self drawKD]; break; } case DMA: { /// 指标为DMA /// 初始化DMA可视化数据 [self initDMAData]; /// 画DMA指标的方法 [self drawDMA]; break; } default: break; } } } } else if (_chartViewType == ChartViewTypeImmediately) { // 即时图 /// 即时线 [self drawImmediatelyLine]; } else if (_chartViewType == ChartViewTypeTSPlan) { // 分时图 /// 分时图 [self drawTSPlanLine]; /// 分时图平均线 [self drawTSAverageLine]; } // 画现价的方法 [self drawPrice]; } #pragma mark - 初始化 /** * @brief 初始化图表 (图表初始化时调用) */ - (void)initChartView { // 视图整体相关 if (!_lineColor) _lineColor = [UIColor colorWithRed:50.0f/225.0f green:50.0f/225.0f blue:50.0f/225.0f alpha:1.0f]; if (!_titleColor) _titleColor = [UIColor whiteColor]; if (!_titleFont) _titleFont = [UIFont systemFontOfSize:8.0f]; // K线阴块颜色 _decKRed = 1.0f; _decKGreen = 0.0f; _decKBlue = 0.0f; _decKAlpha = 1.0f; // K线阳块颜色 _aesKRed = 0.0f; _aesKGreen = 1.0f; _aesKBlue = 0.0f; _aesKAlpha = 1.0f; // K线平块颜色 _samKRed = 1.0f; _samKGreen = 1.0f; _samKBlue = 1.0f; _samKAlpha = 1.0f; // 十字线颜色 _tipRed = 1.0f; _tipGreen = 1.0f; _tipBlue = 1.0f; _tipAlpha = 1.0f; if (!_tipTitleColor) _tipTitleColor = [UIColor whiteColor]; // K线MA5颜色 _kMA5Red = 1.0f; _kMA5Green = 0.0f; _kMA5Blue = 1.0f; _kMA5Alpha = 0.5f; // K线MA10颜色 1.0f, 0.3f, 0, 0.5f _kMA10Red = 1.0f; _kMA10Green = 0.3f; _kMA10Blue = 0.0f; _kMA10Alpha = 0.5f; // K线MA15颜色 0, 1.0f, 0, 0.5f _kMA15Red = 0.0f; _kMA15Green = 1.0f; _kMA15Blue = 0.0f; _kMA15Alpha = 0.5f; // 分时线颜色 168.0f/255.0f, 217.0f/255.0f, 243.0f/255.0f, 1.0f _tsRed = 168.0f/255.0f; _tsGreen = 217.0f/255.0f; _tsBlue = 243.0f/255.0f; _tsAlpha = 1.0f; // 分时MA线 1.0f, 1.0f, 0, 1.0f _tsMARed = 1.0f; _tsMAGreen = 1.0f; _tsMABlue = 0.0f; _tsMAAlpha = 1.0f; // MACD DIF线颜色 1.0f, 0, 0, 0.5f _macdDIFRed = 1.0f; _macdDIFGreen = 0.0f; _macdDIFBlue = 0.0f; _macdDIFAlpha = 0.5f; // MACD DEA线颜色 0, 1.0f, 0, 0.5f _macdDEARed = 0.0f; _macdDEAGreen = 1.0f; _macdDEABlue = 0.0f; _macdDEAAlpha = 0.5f; //X轴相关 _xAxisPaddingLeft = 5.0f; //X轴左边距 // _ts_remove_count = 0; //Y轴相关 _yAxisPaddingTop = 35.0f; //Y轴上边距,默认为10.0f(因为要显示最高标签与平均线说明标签) _yAxisPaddingBottom = 35.0f; //Y轴上边距,主要由视图高度-指标框高度(可能为0)计算得出 //K线相关 _kLineMinWidth = 1.0f; //K线形状最小宽度 _kLineMaxWidth = 20.0f; //K线形状最大宽度 _kLinePadding = 2.0f; //K线形状之间的间隔 _kLineWidth = 5.0f; //K线形状宽度,默认为5.0f // _minUnit = [[NSDecimalNumber decimalNumberWithString:@"0.01"] retain]; //交互相关 _panGestureIncrement = 1; //现价 _isShowPrice = YES; //指标相关 if (_chartViewType == ChartViewTypeKL) { _isShowIndicator = YES; if (_indicatorHight == 0.0f) _indicatorHight = 70.0f; _indicatorPaddingBottom = 5.0f; } else { //分时图不显示指标 _isShowIndicator = NO; _indicatorHight = 0; _indicatorPaddingBottom = 0; } } /** * @brief 初始化整个视图,主要包括计算相关数据 (设置数据时调用) */ - (void)initData { /// 如果没有任何图表数据 不做任何处理 if (_chartDataArray.count == 0) return; /// ************** X轴相关 *************** /// 计算X轴左边距 NSDecimalNumberHandler *behavior = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundDown scale:0 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO]; ChartData *chartData = [_chartDataArray objectAtIndex:0]; NSDecimalNumber *widthDecimalNumber = [[chartData.closed decimalNumberByRoundingAccordingToBehavior:behavior] decimalNumberByAdding:_minUnit]; _xAxisPaddingRight = [[widthDecimalNumber description] sizeWithAttributes:@{NSFontAttributeName:_titleFont}].width + 10.0f; ///n计算X轴宽度 _xAxisWidth = self.bounds.size.width - _xAxisPaddingLeft - _xAxisPaddingRight; if (_chartViewType == ChartViewTypeKL || _chartViewType == ChartViewTypeImmediately) { /// ************** K线相关 *************** /// 计算可显示K线数量 _kLineCount = (_xAxisWidth / (_kLineWidth + _kLinePadding)); if (_kLineCount < 0) _kLineCount = 0; /// 把多余的右边空间加到左边 _excessXAxisWidth = _xAxisWidth - (_kLineWidth + _kLinePadding)*_kLineCount-1.0f; _xAxisPaddingRight += _excessXAxisWidth; _xAxisWidth -= _excessXAxisWidth; /// 当前可视K线数据起始下标 (默认最新的数据在第一条) _kLineStartIndex = _chartDataArray.count > _kLineCount ? _kLineCount - 1 : _chartDataArray.count - 1; /// 当前可视K线数据结束下标 _kLineEndIndex = 0; } else { /// ************** 分时相关 *************** _excessXAxisWidth = 0; /// 遍历计算计划内的有效时间 _kLineCount = 0; for (NSDictionary *item in _reckonDetails) { _kLineCount += [self diffMinuteWithFromDate:item[@"openTime"] toDate:item[@"reckonTime"]]; } if (_kLineCount < 0) _kLineCount = 0; _kLineStartIndex = _chartDataArray.count-1; _kLineEndIndex = 0; } //************** Y轴相关 *************** /// 计算Y轴高度 _yAxisHeight = self.bounds.size.height - _yAxisPaddingTop - _yAxisPaddingBottom - _indicatorHight - _indicatorPaddingBottom; /// ************** 坐标原点 *************** _kLineOrigin = CGPointMake(_xAxisPaddingLeft,_yAxisHeight + _yAxisPaddingTop); /// ************** 指标原点 *************** _indicatorOrigin = CGPointMake(_kLineOrigin.x, _kLineOrigin.y + _yAxisPaddingBottom + _indicatorHight); if (_chartViewType != ChartViewTypeImmediately) { /// 初始化平均线数据以及MACD指标数据 [self initAverageLineDataWithIndex:_chartDataArray.count-1]; /// 初始化平均线数据以及VOL指标数据 [self initVOLLineDataWithIndex:_chartDataArray.count-1]; /// 初始化KDJ指标数据 [self initKDJLineDataWithIndex:_chartDataArray.count-1]; /// 初始化CCI指标数据 [self initCCILineDataWithIndex:_chartDataArray.count-1]; /// 初始化BIAS指标数据 [self initBIASLineDataWithIndex:_chartDataArray.count-1]; /// 初始化PSY指标数据 [self initPSYLineDataWithIndex:_chartDataArray.count-1]; /// 初始化DMA指标数据 [self initDMALineDataWithIndex:_chartDataArray.count-1]; /// 回调方法通知上层当前有数据的指标列表 BOOL hasMACD = NO; BOOL hasVOL = NO; BOOL hasKDJ = NO; BOOL hasRSI = NO; BOOL hasCCI = NO; BOOL hasDMA = NO; BOOL hasBIAS = NO; BOOL hasPSY = NO; for (ChartData *chartData in self.chartDataArray) { if (chartData.macd && ![chartData.macd isEqualToNumber:[NSDecimalNumber zero]] && !hasMACD) hasMACD = YES; if (chartData.vol5 && ![chartData.vol5 isEqualToNumber:[NSDecimalNumber zero]] && !hasVOL) hasVOL = YES; if (chartData.kt && ![chartData.kt isEqualToNumber:[NSDecimalNumber zero]] && !hasKDJ) hasKDJ = YES; if (chartData.rsi1 && ![chartData.rsi1 isEqualToNumber:[NSDecimalNumber zero]] && !hasRSI) hasRSI = YES; if (chartData.cci && ![chartData.cci isEqualToNumber:[NSDecimalNumber zero]] && !hasCCI) hasCCI = YES; if (chartData.dma && ![chartData.dma isEqualToNumber:[NSDecimalNumber zero]] && !hasDMA) hasDMA = YES; if (chartData.bias1 && ![chartData.bias1 isEqualToNumber:[NSDecimalNumber zero]] && !hasBIAS) hasBIAS = YES; if (chartData.psy && ![chartData.psy isEqualToNumber:[NSDecimalNumber zero]] && !hasPSY) hasPSY = YES; } NSMutableArray *targets = [NSMutableArray arrayWithCapacity:0]; if (hasMACD) [targets addObject:@"MACD"]; if (hasVOL) [targets addObject:@"VOL"]; if (hasKDJ) [targets addObject:@"KDJ"]; if (hasRSI) [targets addObject:@"RSI"]; if (hasCCI) [targets addObject:@"CCI"]; if (hasDMA) [targets addObject:@"DMA"]; if (hasBIAS) [targets addObject:@"BIAS"]; if (hasPSY) [targets addObject:@"PSY"]; if (self.delegate) [self.delegate onFinishInitDataWithTargets:targets]; } } #pragma mark - 公开方法 /** * @brief 初始化方法,一般在buildView时调用 * * @param chartViewType 图表类型 * @param frame frame * * @return self */ - (nullable instancetype)initWithType:(ChartViewType)chartViewType frame:(CGRect)frame { /// 设置视图最小宽度与最小高度 if (frame.size.width < 160.0f) frame.size.width = 160.0f; if (frame.size.height < 200.0f) frame.size.height = 200.0f; /// 类型 _chartViewType = chartViewType; self = [super initWithFrame:frame]; if (self) { /// 初始化图表 [self initChartView]; /// 初始化图表交互的相关手势 [self initGestureRecognizer]; } return self; } /** * @brief 切换图表类型的方法,一般在用户点击分时图或K线周期时调用 * * @param chartViewType 目标切换图表类型 * @param chartDataArray 图表数据 */ - (void)changeChartType:(ChartViewType)chartViewType chartDataArray:(nullable NSMutableArray *)chartDataArray { _chartViewType = chartViewType; /// 显示K线图以及指标 if (_chartViewType == ChartViewTypeKL && _isShowIndicator) { if (_indicatorHight == 0.0f) _indicatorHight = 70.0f; _indicatorPaddingBottom = 5.0f; } else { /// 分时图不显示指标 _indicatorHight = 0; _indicatorPaddingBottom = 0; } _yAxisHeight = self.bounds.size.height - _yAxisPaddingTop - _yAxisPaddingBottom - _indicatorHight - _indicatorPaddingBottom; self.chartDataArray = chartDataArray; if (_price) { _price = nil; } if (_priceTime) { _priceTime = nil; } [self setNeedsDisplay]; } /** * @brief 切换图表指标类型的方法 */ - (void)changeChartTargetType:(ChartTargetType)chartTargetType { /// 调用上层方法重新描绘图表 [self setNeedsDisplay]; } /** * @brief 追加图表数据的方法,一般在图表刷新(包括自动刷新)时调用 * * @param appendChartDataArray 追加的图表数据 */ - (void)appendChartDataArray:(nullable NSMutableArray *)appendChartDataArray { if (appendChartDataArray.count == 0) return; //判断追加完数据后要不要刷新图表 BOOL isNeedRefresh = YES; if (_kLineEndIndex != 0) isNeedRefresh = NO; //判断追加的最后一条数据是否原第一条数据 NSInteger appendChartDataEndIndex = _chartDataArray.count-1+appendChartDataArray.count-1; ChartData *appendLastChartData = [appendChartDataArray objectAtIndex:appendChartDataArray.count-1]; ChartData *sourceFirstChartData = [_chartDataArray objectAtIndex:0]; if ([appendLastChartData.startTime compare:sourceFirstChartData.startTime] == NSOrderedSame) { [_chartDataArray removeObject:sourceFirstChartData]; appendChartDataEndIndex --; } /// 追加数据 [appendChartDataArray addObjectsFromArray:_chartDataArray]; _chartDataArray = appendChartDataArray; /// 计算平均线等数据 if (_chartViewType == ChartViewTypeKL || _chartViewType == ChartViewTypeImmediately) { /// 初始化平均线数据以及MACD指标数据 [self initAverageLineDataWithIndex:appendChartDataEndIndex]; /// 初始化平均线数据以及VOL指标数据 [self initVOLLineDataWithIndex:appendChartDataEndIndex]; /// 初始化KDJ指标数据 [self initKDJLineDataWithIndex:appendChartDataEndIndex]; /// 初始化CCI指标数据 [self initCCILineDataWithIndex:appendChartDataEndIndex]; /// 初始化BIAS指标数据 [self initBIASLineDataWithIndex:appendChartDataEndIndex]; /// 初始化PSY指标数据 [self initPSYLineDataWithIndex:appendChartDataEndIndex]; /// 初始化DMA指标数据 [self initDMALineDataWithIndex:appendChartDataEndIndex]; } if (isNeedRefresh) [self setNeedsDisplay]; } /** * @brief 对外公开设置图表数据的方法,内部会调用initData方法 * * @param chartDataArray 图表数据 */ - (void)setChartDataArray:(nullable NSMutableArray *)chartDataArray { if (_chartDataArray) { if (_chartDataArray != chartDataArray) { _chartDataArray = chartDataArray; } } else { _chartDataArray = chartDataArray; } /// 初始化数据 [self initData]; } /** * @brief 让图表恢复正常状态的方法。可在十字线显示时离开ViewController等情况下调用。 */ - (void)restoreNormalState { _isShowTipLine = NO; [self setNeedsDisplay]; } /** 清空图表的方法 */ - (void)clear { if (_chartDataArray) { _chartDataArray = nil; } [self setNeedsDisplay]; } /** * @brief 追加行情现价的方法。 * * @param price 行情现价 * @param priceTime 行情时间 * @param lastVolume 成交量 * */ - (ChartErrorType)appendQuotaPrice:(nullable NSDecimalNumber *)price priceTime:(nullable NSDate *)priceTime lastVolume:(nullable NSDecimalNumber *)lastVolume { if (_cycleInterval == 0.0f) { /// 没有设置周期间隔秒数则 return ChartErrorTypeNotSetCycleInterval; } ChartData *chartDataLast = [_chartDataArray objectAtIndex:0]; /// 如果行情时间比图表最近时间还要早则不做任务处理 if ([priceTime compare:chartDataLast.startTime] == NSOrderedAscending) { return ChartErrorTypeQuotaTimeOldest; } /// 获取下一个周期开始时间和下两个周期开始时间 NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; NSInteger cycle = 0; switch ((NSInteger)_cycleInterval) { case 60: cycle = 1; break; case 5 * 60: cycle = 4; break; case 15 * 60: cycle = 14; break; case 30 * 60: cycle = 29; break; case 60 * 60: cycle = 59; break; case 60 * 60 * 2: cycle = (60 * 2) - 1; break; case 60 * 60 * 4: cycle = (60 * 4) - 1; break; case 60 * 60 * 24: cycle = (60 * 24) - 1; break; default: break; } NSInteger seconds = cycle * 60 - [[[dateFormatter stringFromDate:chartDataLast.startTime] substringWithRange:NSMakeRange(16, 2)] integerValue]; NSDate *nextOneDate = [[NSDate alloc] initWithTimeInterval:seconds sinceDate:chartDataLast.startTime]; NSDate *nextTwoDate = [[NSDate alloc] initWithTimeInterval:_cycleInterval*2 sinceDate:chartDataLast.startTime]; if ([priceTime compare:nextTwoDate] != NSOrderedAscending) { /// 行情时间已经超时一个数据块时间周期 if (self.delegate) { [self.delegate requestRefreshChartDataWithErrorCode:ChartErrorTypeQuotaTimeout]; } } else { /// 行情时间在可接收范围之内,则再判断行情数据是图表最近时间块内,还是下一个时间周期块 if ([priceTime compare:nextOneDate] != NSOrderedAscending) { /// Warning:目前遇到下一个周期不是整数的问题,暂时直接处理 priceTime = [chartDataLast.startTime dateByAddingTimeInterval:_cycleInterval]; ChartData *chartData = [[ChartData alloc] init]; chartData.opened = price; chartData.closed = price; chartData.highest = price; chartData.lowest = price; chartData.startTime = priceTime; chartData.totleVolume = lastVolume; [_chartDataArray insertObject:chartData atIndex:0]; /// 触发图表数据最新时间变更回调 if (self.delegate) [self.delegate onChangeDataLasttime:priceTime]; } else { /// 行情时间属于图表最近时间周期块 chartDataLast.closed = price; if ([price compare:chartDataLast.highest] == NSOrderedDescending) { chartDataLast.highest = price; } if ([price compare:chartDataLast.lowest] == NSOrderedAscending) { chartDataLast.lowest = price; } if (chartDataLast.totleVolume && lastVolume) { chartDataLast.totleVolume = [chartDataLast.totleVolume decimalNumberByAdding:lastVolume]; } } /// 记录现价和时间 if (_price) { if (_price != price) { _price = price; } } else { _price = price; } if (_priceTime) { if (_priceTime != priceTime) { _priceTime = priceTime; } } else { _priceTime = priceTime; } /// 计算平均线等数据 if (_chartViewType == ChartViewTypeKL || _chartViewType == ChartViewTypeImmediately) { /// 初始化平均线数据以及MACD指标数据 /// 刷新最近一条数据就可以(错) [self initAverageLineDataWithIndex:_chartDataArray.count-1]; /// 初始化平均线数据以及VOL指标数据 [self initVOLLineDataWithIndex:_chartDataArray.count-1]; /// 初始化KDJ指标数据 [self initKDJLineDataWithIndex:_chartDataArray.count-1]; /// 初始化CCI指标数据 [self initCCILineDataWithIndex:_chartDataArray.count-1]; /// 初始化BIAS指标数据 [self initBIASLineDataWithIndex:_chartDataArray.count-1]; /// 初始化PSY指标数据 [self initPSYLineDataWithIndex:_chartDataArray.count-1]; /// 初始化DMA指标数据 [self initDMALineDataWithIndex:_chartDataArray.count-1]; } else { /// 初始化平均线数据以及MACD指标数据 /// 刷新最近一条数据就可以(错) [self initAverageLineDataWithIndex:_chartDataArray.count-1]; } /// 调用父类方法 重新去描绘图表 [self setNeedsDisplay]; } return ChartErrorTypeNone; } #pragma mark - 颜色设置 /** * @brief 设置K线阴块颜色的方法 * * @param decKRed K线阴块红色值 * @param decKGreen K线阴块绿色值 * @param decKBlue K线阴块蓝色值 * @param decKAlpha K线阴块alpha值 */ - (void)setDecKRed:(CGFloat)decKRed decKGreen:(CGFloat)decKGreen decKBlue:(CGFloat)decKBlue decKAlpha:(CGFloat)decKAlpha { _decKRed = decKRed; _decKGreen = decKGreen; _decKBlue = decKBlue; _decKAlpha = decKAlpha; } /** * @brief 设置K线阳块颜色的方法 * * @param aesKRed K线阳块红色值 * @param aesKGreen K线阳块绿色值 * @param aesKBlue K线阳块蓝色值 * @param aesKAlpha K线阳块alpha值 */ - (void)setAesKRed:(CGFloat)aesKRed aesKGreen:(CGFloat)aesKGreen aesKBlue:(CGFloat)aesKBlue aesKAlpha:(CGFloat)aesKAlpha { _aesKRed = aesKRed; _aesKGreen = aesKGreen; _aesKBlue = aesKBlue; _aesKAlpha = aesKAlpha; } /** * @brief 设置开高低收报价字体颜色为绿色时的颜色 */ - (void)setPriceGreenColor:(nullable UIColor *)priceGreenColor { if (!_priceGreenColor) { _priceGreenColor = priceGreenColor; } else { _priceGreenColor = nil; _priceGreenColor = priceGreenColor; } } /** * @brief 设置K线平块颜色的方法 * * @param samKRed K线平块红色值 * @param samKGreen K线平块绿色值 * @param samKBlue K线平块蓝色值 * @param samKAlpha K线平块alpha值 */ - (void)setSamKRed:(CGFloat)samKRed samKGreen:(CGFloat)samKGreen samKBlue:(CGFloat)samKBlue samKAlpha:(CGFloat)samKAlpha { _samKRed = samKRed; _samKGreen = samKGreen; _samKBlue = samKBlue; _samKAlpha = samKAlpha; } /** * @brief 设置十字线颜色的方法 * * @param tipRed 十字线红色值 * @param tipGreen 十字线绿色值 * @param tipBlue 十字线蓝色值 * @param tipAlpha 十字线alpha值 * @param tipTitleColor 十字线标题颜色对象 */ - (void)setTipRed:(CGFloat)tipRed tipGreen:(CGFloat)tipGreen tipBlue:(CGFloat)tipBlue tipAlpha:(CGFloat)tipAlpha tipTitleColor:(nullable UIColor *)tipTitleColor { _tipRed = tipRed; _tipGreen = tipGreen; _tipBlue = tipBlue; _tipAlpha = tipAlpha; if (_tipTitleColor) { if (_tipTitleColor != tipTitleColor) { _tipTitleColor = tipTitleColor; } } else { _tipTitleColor = tipTitleColor; } } /** * @brief 设置分时图昨收线颜色的方法 * * @param preCloseLineRed 昨收线红色值 * @param preCloseLineGreen 昨收线绿色值 * @param preCloseLineBlue 昨收线蓝色值 * @param preCloseLineAlpha 昨收线alpha值 */ - (void)setPreCloseLineRed:(CGFloat)preCloseLineRed preCloseLineGreen:(CGFloat)preCloseLineGreen preCloseLineBlue:(CGFloat)preCloseLineBlue preCloseLineAlpha:(CGFloat)preCloseLineAlpha { _preCloseLineRed = preCloseLineRed; _preCloseLineGreen = preCloseLineGreen; _preCloseLineBlue = preCloseLineBlue; _preCloseLineAlpha = preCloseLineAlpha; } /** * @brief 设置K线MA5平均线颜色的方法 * * @param kMA5Red K线MA5平均线红色值 * @param kMA5Green K线MA5平均线绿色值 * @param kMA5Blue K线MA5平均线蓝色值 * @param kMA5Alpha K线MA5平均线alpha值 */ - (void)setkMA5Red:(CGFloat)kMA5Red kMA5Green:(CGFloat)kMA5Green kMA5Blue:(CGFloat)kMA5Blue kMA5Alpha:(CGFloat)kMA5Alpha { _kMA5Red = kMA5Red; _kMA5Green = kMA5Green; _kMA5Blue = kMA5Blue; _kMA5Alpha = kMA5Alpha; } /** * @brief 设置K线MA10平均线颜色的方法 * * @param kMA10Red K线MA10平均线红色值 * @param kMA10Green K线MA10平均线绿色值 * @param kMA10Blue K线MA10平均线蓝色值 * @param kMA10Alpha K线MA10平均线alpha值 */ - (void)setkMA10Red:(CGFloat)kMA10Red kMA10Green:(CGFloat)kMA10Green kMA10Blue:(CGFloat)kMA10Blue kMA10Alpha:(CGFloat)kMA10Alpha { _kMA10Red = kMA10Red; _kMA10Green = kMA10Green; _kMA10Blue = kMA10Blue; _kMA10Alpha = kMA10Alpha; } /** * @brief 设置K线MA15平均线颜色的方法 * * @param kMA15Red K线MA15平均线红色值 * @param kMA15Green K线MA15平均线绿色值 * @param kMA15Blue K线MA15平均线蓝色值 * @param kMA15Alpha K线MA15平均线alpha值 */ - (void)setkMA15Red:(CGFloat)kMA15Red kMA15Green:(CGFloat)kMA15Green kMA15Blue:(CGFloat)kMA15Blue kMA15Alpha:(CGFloat)kMA15Alpha { _kMA15Red = kMA15Red; _kMA15Green = kMA15Green; _kMA15Blue = kMA15Blue; _kMA15Alpha = kMA15Alpha; } /** * @brief 设置分时线颜色的方法 * * @param tsRed 分时线红色值 * @param tsGreen 分时线绿色值 * @param tsBlue 分时线蓝色值 * @param tsAlpha 分时线alpha值 */ - (void)setTsRed:(CGFloat)tsRed tsGreen:(CGFloat)tsGreen tsBlue:(CGFloat)tsBlue tsAlpha:(CGFloat)tsAlpha { _tsRed = tsRed; _tsGreen = tsGreen; _tsBlue = tsBlue; } /** * @brief 设置分时MA线颜色的方法 * * @param tsMARed 分时MA线红色值 * @param tsMAGreen 分时MA线绿色值 * @param tsMABlue 分时MA线蓝色值 * @param tsMAAlpha 分时MA线alpha值 */ - (void)setTsMARed:(CGFloat)tsMARed tsMAGreen:(CGFloat)tsMAGreen tsMABlue:(CGFloat)tsMABlue tsMAAlpha:(CGFloat)tsMAAlpha { _tsMARed = tsMARed; _tsMAGreen = tsMAGreen; _tsMABlue = tsMABlue; _tsMAAlpha = tsMAAlpha; } /** * @brief 设置MACD DIF线颜色的方法 * * @param macdDIFRed MACD DIF线红色值 * @param macdDIFGreen MACD DIF线绿色值 * @param macdDIFBlue MACD DIF线蓝色值 * @param macdDIFAlpha MACD DIF线alpha值 */ - (void)setMacdDIFRed:(CGFloat)macdDIFRed macdDIFGreen:(CGFloat)macdDIFGreen macdDIFBlue:(CGFloat)macdDIFBlue macdDIFAlpha:(CGFloat)macdDIFAlpha { _macdDIFRed = macdDIFRed; _macdDIFGreen = macdDIFGreen; _macdDIFBlue = macdDIFBlue; _macdDIFAlpha = macdDIFAlpha; } /** * @brief 设置MACD DEA线颜色的方法 * * @param macdDEARed MACD DEA线红色值 * @param macdDEAGreen MACD DEA线绿色值 * @param macdDEABlue MACD DEA线蓝色值 * @param macdDEAAlpha MACD DEA线alpha值 */ - (void)setMacdDEARed:(CGFloat)macdDEARed macdDEAGreen:(CGFloat)macdDEAGreen macdDEABlue:(CGFloat)macdDEABlue macdDEAAlpha:(CGFloat)macdDEAAlpha { _macdDEARed = macdDEARed; _macdDEAGreen = macdDEAGreen; _macdDEABlue = macdDEABlue; _macdDEAAlpha = macdDEAAlpha; } /** * @brief 设置RSI RSI1线颜色的方法 * * @param rsi1Red RSI RSI1线红色值 * @param rsi1Green RSI RSI1线绿色值 * @param rsi1Blue RSI RSI1线蓝色值 * @param rsi1Alpha RSI RSI1线alpha值 */ - (void)setRSI1Red:(CGFloat)rsi1Red rsi1Green:(CGFloat)rsi1Green rsi1Blue:(CGFloat)rsi1Blue rsi1Alpha:(CGFloat)rsi1Alpha { _rsi1Red = rsi1Red; _rsi1Green = rsi1Green; _rsi1Blue = rsi1Blue; _rsi1Alpha = rsi1Alpha; } /** * @brief 设置RSI RSI2线颜色的方法 * * @param rsi2Red RSI RSI2线红色值 * @param rsi2Green RSI RSI2线绿色值 * @param rsi2Blue RSI RSI2线蓝色值 * @param rsi2Alpha RSI RSI2线alpha值 */ - (void)setRSI2Red:(CGFloat)rsi2Red rsi2Green:(CGFloat)rsi2Green rsi2Blue:(CGFloat)rsi2Blue rsi2Alpha:(CGFloat)rsi2Alpha { _rsi2Red = rsi2Red; _rsi2Green = rsi2Green; _rsi2Blue = rsi2Blue; _rsi2Alpha = rsi2Alpha; } /** * @brief 设置RSI RSI3线颜色的方法 * * @param rsi3Red RSI RSI3线红色值 * @param rsi3Green RSI RSI3线绿色值 * @param rsi3Blue RSI RSI3线蓝色值 * @param rsi3Alpha RSI RSI3线alpha值 */ - (void)setRSI3Red:(CGFloat)rsi3Red rsi3Green:(CGFloat)rsi3Green rsi3Blue:(CGFloat)rsi3Blue rsi3Alpha:(CGFloat)rsi3Alpha { _rsi3Red = rsi3Red; _rsi3Green = rsi3Green; _rsi3Blue = rsi3Blue; _rsi3Alpha = rsi3Alpha; } /** * @brief 设置KT KT线颜色的方法 * * @param ktRed KT KT线红色值 * @param ktGreen KT KT线绿色值 * @param ktBlue KT KT线蓝色值 * @param ktAlpha KT KT线alpha值 */ - (void)setKTRed:(CGFloat)ktRed ktGreen:(CGFloat)ktGreen ktBlue:(CGFloat)ktBlue ktAlpha:(CGFloat)ktAlpha { _ktRed = ktRed; _ktGreen = ktGreen; _ktBlue = ktBlue; _ktAlpha = ktAlpha; } /** * @brief 设置DT DT线颜色的方法 * * @param dtRed DT DT线红色值 * @param dtGreen DT DT线绿色值 * @param dtBlue DT DT线蓝色值 * @param dtAlpha DT DT线alpha值 */ - (void)setDTRed:(CGFloat)dtRed dtGreen:(CGFloat)dtGreen dtBlue:(CGFloat)dtBlue dtAlpha:(CGFloat)dtAlpha { _dtRed = dtRed; _dtGreen = dtGreen; _dtBlue = dtBlue; _dtAlpha = dtAlpha; } /** * @brief 设置JT JT线颜色的方法 * * @param jtRed JT JT线红色值 * @param jtGreen JT JT线绿色值 * @param jtBlue JT JT线蓝色值 * @param jtAlpha JT JT线alpha值 */ - (void)setJTRed:(CGFloat)jtRed jtGreen:(CGFloat)jtGreen jtBlue:(CGFloat)jtBlue jtAlpha:(CGFloat)jtAlpha { _jtRed = jtRed; _jtBlue = jtBlue; _jtGreen = jtGreen; _jtAlpha = jtAlpha; } /** * @brief 设置CCI CCI线颜色的方法 * * @param cciRed CCI CCI线红色值 * @param cciGreen CCI CCI线绿色值 * @param cciBlue CCI CCI线蓝色值 * @param cciAlpha CCI CCI线alpha值 */ - (void)setCCIRed:(CGFloat)cciRed cciGreen:(CGFloat)cciGreen cciBlue:(CGFloat)cciBlue cciAlpha:(CGFloat)cciAlpha { _cciRed = cciRed; _cciGreen = cciGreen; _cciBlue = cciBlue; _cciAlpha = cciAlpha; } /** * @brief 设置DMA线颜色的方法 * * @param dmaRed DMA线红色值 * @param dmaGreen DMA线绿色值 * @param dmaBlue DMA线蓝色值 * @param dmaAlpha DMA线alpha值 */ - (void)setDMARed:(CGFloat)dmaRed dmaGreen:(CGFloat)dmaGreen cciBlue:(CGFloat)dmaBlue cciAlpha:(CGFloat)dmaAlpha { _dmaRed = dmaRed; _dmaGreen = dmaGreen; _dmaBlue = dmaBlue; _dmaAlpha = dmaAlpha; } /** * @brief 设置AMA线颜色的方法 * * @param amaRed AMA线红色值 * @param amaGreen AMA线绿色值 * @param amaBlue AMA线蓝色值 * @param amaAlpha AMA线alpha值 */ - (void)setAMARed:(CGFloat)amaRed amaGreen:(CGFloat)amaGreen cciBlue:(CGFloat)amaBlue cciAlpha:(CGFloat)amaAlpha { _amaRed = amaRed; _amaGreen = amaGreen; _amaBlue = amaBlue; _amaAlpha = amaAlpha; } /** * @brief 设置BIAS BIAS1线颜色的方法 * * @param bias1Red BIAS BIAS1线红色值 * @param bias1Green BIAS BIAS1线绿色值 * @param bias1Blue BIAS BIAS1线蓝色值 * @param bias1Alpha BIAS BIAS1线alpha值 */ - (void)setBIAS1Red:(CGFloat)bias1Red bias1Green:(CGFloat)bias1Green bias1Blue:(CGFloat)bias1Blue bias1Alpha:(CGFloat)bias1Alpha { _bias1Red = bias1Red; _bias1Green = bias1Green; _bias1Blue = bias1Blue; _bias1Alpha = bias1Alpha; } /** * @brief 设置BIAS BIAS2线颜色的方法 * * @param bias2Red BIAS BIAS2线红色值 * @param bias2Green BIAS BIAS2线绿色值 * @param bias2Blue BIAS BIAS2线蓝色值 * @param bias2Alpha BIAS BIAS2线alpha值 */ - (void)setBIAS2Red:(CGFloat)bias2Red bias2Green:(CGFloat)bias2Green bias2Blue:(CGFloat)bias2Blue bias2Alpha:(CGFloat)bias2Alpha { _bias2Red = bias2Red; _bias2Green = bias2Green; _bias2Blue = bias2Blue; _bias2Alpha = bias2Alpha; } /** * @brief 设置BIAS BIAS3线颜色的方法 * * @param bias3Red BIAS BIAS3线红色值 * @param bias3Green BIAS BIAS3线绿色值 * @param bias3Blue BIAS BIAS3线蓝色值 * @param bias3Alpha BIAS BIAS3线alpha值 */ - (void)setBIAS3Red:(CGFloat)bias3Red bias3Green:(CGFloat)bias3Green bias3Blue:(CGFloat)bias3Blue bias3Alpha:(CGFloat)bias3Alpha { _bias3Red = bias3Red; _bias3Green = bias3Green; _bias3Blue = bias3Blue; _bias3Alpha = bias3Alpha; } /** * @brief 设置PSY PSY线颜色的方法 * * @param psyRed PSY PSY线红色值 * @param psyGreen PSY PSY线绿色值 * @param psyBlue PSY PSY线蓝色值 * @param psyAlpha PSY PSY线alpha值 */ - (void)setPSYRed:(CGFloat)psyRed psyGreen:(CGFloat)psyGreen psyBlue:(CGFloat)psyBlue psyAlpha:(CGFloat)psyAlpha { _psyRed = psyRed; _psyGreen = psyGreen; _psyBlue = psyBlue; _psyAlpha = psyAlpha; } /** * @brief 设置PSYMA PSYMA线颜色的方法 * * @param psymaRed PSYMA PSYMA线红色值 * @param psymaGreen PSYMA PSYMA线绿色值 * @param psymaBlue PSYMA PSYMA线蓝色值 * @param psymaAlpha PSYMA PSYMA线alpha值 */ - (void)setPSYMARed:(CGFloat)psymaRed psymaGreen:(CGFloat)psymaGreen psymaBlue:(CGFloat)psymaBlue psymaAlpha:(CGFloat)psymaAlpha { _psymaRed = psymaRed; _psymaGreen = psymaGreen; _psymaBlue = psymaBlue; _psymaAlpha = psymaAlpha; } #pragma mark - 画坐标轴相关 /** * @brief 更新数据的方法,主要用于更新图表 */ - (void)updateData { //当前可视坐标最高价=当前可视最高价+几个点(这几个点应该从当前可视最高与最低价点差计算得出) NSDecimalNumber *maxValue = [self maxPriceAtVisible]; NSDecimalNumber *minValue = [self minPriceAtVisible]; // 这里有可能最大值和最小值相等 if ([maxValue compare:minValue] == NSOrderedSame) { ChartData *chartData = _chartDataArray[0]; maxValue = [chartData.closed decimalNumberByAdding:[_minUnit decimalNumberByMultiplyingBy:[[NSDecimalNumber alloc] initWithInt:20]]]; } //如果当前是分时图,要重新计算最高最低价,以便让昨收线在中间 if (_chartViewType == ChartViewTypeTSPlan) { NSDecimalNumber *diffMax = [ChartCalculateUtils abs:[_preClose decimalNumberBySubtracting:maxValue]]; NSDecimalNumber *diffMin = [ChartCalculateUtils abs:[_preClose decimalNumberBySubtracting:minValue]]; if ([diffMax compare:diffMin] == NSOrderedDescending) { //最高与昨收的差比最低的大 maxValue = [_preClose decimalNumberByAdding:diffMax]; minValue = [_preClose decimalNumberBySubtracting:diffMax]; } else { //反之 maxValue = [_preClose decimalNumberByAdding:diffMin]; minValue = [_preClose decimalNumberBySubtracting:diffMin]; } } //最多10个点的高低值 NSDecimalNumberHandler *behavior = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundDown scale:0 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO]; NSInteger stepValue = [[[[[maxValue decimalNumberBySubtracting:minValue] decimalNumberByDividingBy:_minUnit] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"10"]] decimalNumberByRoundingAccordingToBehavior:behavior] integerValue]; if (stepValue > 10) stepValue = 10; NSString *stepString = [NSString stringWithFormat:@"%d",(int)stepValue]; _yAxisMaxValue = [[maxValue decimalNumberByAdding:[_minUnit decimalNumberByMultiplyingBy:[NSDecimalNumber decimalNumberWithString:stepString]]] floatValue]; _yAxisMinValue = [[minValue decimalNumberBySubtracting:[_minUnit decimalNumberByMultiplyingBy:[NSDecimalNumber decimalNumberWithString:stepString]]] floatValue]; } /** * @brief 画框架 */ - (void)drawBorder { CGContextRef context = UIGraphicsGetCurrentContext(); //整体相关 CGFloat red = 1.0, green = 1.0, blue = 1.0, alpha = 1.0; CGContextSetRGBFillColor(context, _bgRed, _bgGreen, _bgBlue, 1.0f); CGContextFillRect(context, self.bounds); //边框相关 [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; CGContextSetRGBStrokeColor(context, red, green, blue, alpha); CGContextSetLineWidth(context, 1.0f); CGContextAddRect(context, CGRectMake(_kLineOrigin.x, _yAxisPaddingTop, _xAxisWidth, _yAxisHeight)); #ifdef DEBUG // NSLog(@"%s _yAxisHeight:%f", __func__, _yAxisHeight); #endif NSString *targetTitle = [[NSString alloc] init]; //指标相关 if (_isShowIndicator) { if (_chartViewType == ChartViewTypeKL) { CGContextAddRect(context, CGRectMake(_indicatorOrigin.x, _indicatorOrigin.y-_indicatorHight, _xAxisWidth, _indicatorHight)); CGContextStrokePath(context); if (_chartTargetType == MACD) { //MACD标题 targetTitle = @"MACD(12,26,9)"; } else if (_chartTargetType == VOL) { //VOL标题 targetTitle = @"VOL(5,10)"; } else if (_chartTargetType == KDJ) { //KDJ标题 targetTitle = @"KDJ(9,3,3)"; } else if (_chartTargetType == RSI) { //RSI标题 targetTitle = @"RSI(6,12,24)"; } else if (_chartTargetType == CCI) { //CCI标题 targetTitle = @"CCI(14)"; } else if (_chartTargetType == DMA) { //DMA标题 targetTitle = @"DMA(10,50,10)"; } else if (_chartTargetType == KD) { //KD标题 targetTitle = @"KD(9,3)"; } else if (_chartTargetType == BIAS) { //BIAS标题 targetTitle = @"BIAS(6,12,24)"; } else if (_chartTargetType == PSY) { //PSY标题 targetTitle = @"PSY(12,6)"; } } CGFloat priceXOffset = _xAxisPaddingLeft + _xAxisWidth; // 价格左边距 // 写数据 NSMutableAttributedString *tipString = [[NSMutableAttributedString alloc] initWithString:targetTitle attributes:@{NSFontAttributeName:_titleFont, NSForegroundColorAttributeName:_titleColor}]; [tipString drawAtPoint:CGPointMake(priceXOffset - 60.0f, _indicatorOrigin.y - _indicatorHight - 15.0f)]; } } /** * @brief 画X轴 */ - (void)drawXAxis { //时间格式化 NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; /// 分时图 dateFormatter.dateFormat = _chartViewType == ChartViewTypeTSPlan ? @"HH:mm" : @"MM-dd HH:mm"; if (_chartViewType == ChartViewTypeTSPlan) {//分时图 //开盘时间 [_lineColor setFill]; [_titleColor set]; [[dateFormatter stringFromDate:_tsStartTime] drawAtPoint:_kLineOrigin withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; //收盘时间 [_titleColor set]; CGFloat dateStringWidth = [[dateFormatter stringFromDate:_tsCloseTime] sizeWithAttributes:@{NSFontAttributeName:_titleFont}].width; [_titleColor set]; [[dateFormatter stringFromDate:_tsCloseTime] drawAtPoint:CGPointMake(_kLineOrigin.x + _xAxisWidth - dateStringWidth, _kLineOrigin.y) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; } else {//K线或即时线 //起始时间 ChartData *startChartData = [_chartDataArray objectAtIndex:_kLineStartIndex]; [_lineColor setFill]; [_titleColor set]; [[dateFormatter stringFromDate:startChartData.startTime] drawAtPoint:_kLineOrigin withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; //结束时间,如果K线数量不足整屏则不显示结束时间 if (_chartDataArray.count >= _kLineCount) { ChartData *endChartData = [_chartDataArray objectAtIndex:_kLineEndIndex]; CGFloat dateStringWidth = [[dateFormatter stringFromDate:endChartData.startTime] sizeWithAttributes:@{NSFontAttributeName:_titleFont}].width; [_titleColor set]; [[dateFormatter stringFromDate:endChartData.startTime] drawAtPoint:CGPointMake(_kLineOrigin.x + _xAxisWidth - dateStringWidth, _kLineOrigin.y) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; } } } /** * @brief 画Y轴 */ - (void)drawYAxis { //当前可视坐标最高价=当前可视最高价+几个点(这几个点应该从当前可视最高与最低价点差计算得出) NSDecimalNumber *maxValue = [self maxPriceAtVisible]; NSDecimalNumber *minValue = [self minPriceAtVisible]; // 这里有可能最大值和最小值相等 if ([maxValue compare:minValue] == NSOrderedSame) { ChartData *chartData = _chartDataArray[0]; maxValue = [chartData.closed decimalNumberByAdding:[_minUnit decimalNumberByMultiplyingBy:[[NSDecimalNumber alloc] initWithInt:20]]]; } //如果当前是分时图,要重新计算最高最低价,以便让昨收线在中间 if (_chartViewType == ChartViewTypeTSPlan) { NSDecimalNumber *diffMax = [ChartCalculateUtils abs:[_preClose decimalNumberBySubtracting:maxValue]]; NSDecimalNumber *diffMin = [ChartCalculateUtils abs:[_preClose decimalNumberBySubtracting:minValue]]; if ([diffMax compare:diffMin] == NSOrderedDescending) { //最高与昨收的差比最低的大 maxValue = [_preClose decimalNumberByAdding:diffMax]; minValue = [_preClose decimalNumberBySubtracting:diffMax]; } else { //反之 maxValue = [_preClose decimalNumberByAdding:diffMin]; minValue = [_preClose decimalNumberBySubtracting:diffMin]; } } CGFloat red = 1.0, green = 1.0, blue = 1.0, alpha = 1.0; [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetRGBStrokeColor(context, red, green, blue, alpha); //画线 CGContextSetLineWidth(context, 1.0f); //当前可视最高价线 CGContextMoveToPoint(context, _kLineOrigin.x, [self yPointWithPrice:maxValue]); CGContextAddLineToPoint(context, _xAxisPaddingLeft + _xAxisWidth,[self yPointWithPrice:maxValue]); //当前可视最低价线 CGContextMoveToPoint(context, _kLineOrigin.x, [self yPointWithPrice:minValue]); CGContextAddLineToPoint(context, _xAxisPaddingLeft + _xAxisWidth,[self yPointWithPrice:minValue]); //二等分价线 NSDecimalNumber *averagePrice = [[[maxValue decimalNumberBySubtracting:minValue] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"2"]] decimalNumberByAdding:minValue]; if (_chartViewType != ChartViewTypeTSPlan) { CGContextMoveToPoint(context, _kLineOrigin.x, [self yPointWithPrice:averagePrice]); CGContextAddLineToPoint(context, _xAxisPaddingLeft + _xAxisWidth,[self yPointWithPrice:averagePrice]); } //四等分价线(高) NSDecimalNumber *quarterHighPrice = [averagePrice decimalNumberByAdding:[[averagePrice decimalNumberBySubtracting:minValue] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"2"]]]; CGContextMoveToPoint(context, _kLineOrigin.x, [self yPointWithPrice:quarterHighPrice]); CGContextAddLineToPoint(context, _xAxisPaddingLeft + _xAxisWidth,[self yPointWithPrice:quarterHighPrice]); //四等分价线(低) NSDecimalNumber *quarterLowPrice = [averagePrice decimalNumberBySubtracting:[[averagePrice decimalNumberBySubtracting:minValue] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"2"]]]; CGContextMoveToPoint(context, _kLineOrigin.x, [self yPointWithPrice:quarterLowPrice]); CGContextAddLineToPoint(context, _xAxisPaddingLeft + _xAxisWidth,[self yPointWithPrice:quarterLowPrice]); CGContextStrokePath(context); //写价格 CGFloat priceXOffset = _xAxisPaddingLeft + _xAxisWidth; //价格左边距 NSInteger digitCount = [ChartCalculateUtils getDecimalDigits:_minUnit]; //K线最高价 [_titleColor set]; NSString *maxPriceString = [ChartCalculateUtils notRounding:maxValue afterPoint:digitCount]; [maxPriceString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, [self yPointWithPrice:maxValue] - [maxPriceString sizeWithAttributes:@{NSFontAttributeName:_titleFont}].height/2) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; //K线最低价 NSString *minPriceString = [ChartCalculateUtils notRounding:minValue afterPoint:digitCount]; [minPriceString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, [self yPointWithPrice:minValue] - [maxPriceString sizeWithAttributes:@{NSFontAttributeName:_titleFont}].height/2) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; //二等分价 if (_chartViewType != ChartViewTypeTSPlan) { NSString *averagePriceString = [ChartCalculateUtils notRounding:averagePrice afterPoint:digitCount]; [averagePriceString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, [self yPointWithPrice:averagePrice] - [averagePriceString sizeWithAttributes:@{NSFontAttributeName:_titleFont}].height/2) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; } //四等分价(高) NSString *quarterHighPriceString = [ChartCalculateUtils notRounding:quarterHighPrice afterPoint:digitCount]; [quarterHighPriceString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, [self yPointWithPrice:quarterHighPrice] - [quarterHighPriceString sizeWithAttributes:@{NSFontAttributeName:_titleFont}].height/2) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; //四等分价(低) NSString *quarterLowPriceString = [ChartCalculateUtils notRounding:quarterLowPrice afterPoint:digitCount]; [quarterLowPriceString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, [self yPointWithPrice:quarterLowPrice] - [quarterLowPriceString sizeWithAttributes:@{NSFontAttributeName:_titleFont}].height/2) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; //分时图画昨收线与昨收价 if (_chartViewType == ChartViewTypeTSPlan) { CGContextSetRGBStrokeColor(context, _preCloseLineRed, _preCloseLineGreen, _preCloseLineBlue, _preCloseLineAlpha); CGFloat dashes[] = { 4, 3 }; CGContextSetLineDash( context, 0.0, dashes, 2 ); CGContextMoveToPoint(context, _kLineOrigin.x, [self yPointWithPrice:_preClose]); CGContextAddLineToPoint(context, _xAxisPaddingLeft + _xAxisWidth,[self yPointWithPrice:_preClose]); CGContextStrokePath(context); CGContextSetLineDash(context, 0.0, dashes, 0); [[UIColor colorWithRed:_preCloseLineRed green:_preCloseLineGreen blue:_preCloseLineBlue alpha:_preCloseLineAlpha] set]; NSString *preCloseString = [ChartCalculateUtils notRounding:_preClose afterPoint:digitCount]; [preCloseString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, [self yPointWithPrice:_preClose] - [preCloseString sizeWithAttributes:@{NSFontAttributeName:_titleFont}].height/2) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; } } #pragma mark - 画K线相关 /** * @brief 画K线的方法 */ - (void)drawKLine { CGContextRef context = UIGraphicsGetCurrentContext(); CGFloat currentXPonit = _kLineOrigin.x + 1.0f; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if ([chartData.closed compare:chartData.opened] == NSOrderedAscending) { //close < open CGContextSetRGBFillColor(context, _decKRed, _decKGreen, _decKBlue, _decKAlpha); CGContextAddRect(context, CGRectMake(currentXPonit, [self yPointWithPrice:chartData.opened], _kLineWidth, [self yPointWithPrice:chartData.closed] - [self yPointWithPrice:chartData.opened])); CGContextFillPath(context); if ([chartData.highest compare:chartData.opened] == NSOrderedDescending) { //high > open CGContextSetRGBStrokeColor(context, _decKRed, _decKGreen, _decKBlue, _decKAlpha); CGContextSetLineWidth(context, 1.0f); CGContextMoveToPoint(context, currentXPonit + _kLineWidth/2, [self yPointWithPrice:chartData.highest]); CGContextAddLineToPoint(context, currentXPonit + _kLineWidth/2, [self yPointWithPrice:chartData.opened]); CGContextStrokePath(context); } if ([chartData.lowest compare:chartData.closed] == NSOrderedAscending) { //low < close CGContextSetRGBStrokeColor(context, _decKRed, _decKGreen, _decKBlue, _decKAlpha); CGContextSetLineWidth(context, 1.0f); CGContextMoveToPoint(context, currentXPonit + _kLineWidth/2, [self yPointWithPrice:chartData.closed]); CGContextAddLineToPoint(context, currentXPonit + _kLineWidth/2, [self yPointWithPrice:chartData.lowest]); CGContextStrokePath(context); } } else if ([chartData.closed compare:chartData.opened] == NSOrderedDescending) { //close > open CGContextSetRGBFillColor(context, _aesKRed, _aesKGreen, _aesKBlue, _aesKAlpha); CGContextAddRect(context, CGRectMake(currentXPonit, [self yPointWithPrice:chartData.closed], _kLineWidth, [self yPointWithPrice:chartData.opened] - [self yPointWithPrice:chartData.closed])); CGContextFillPath(context); if ([chartData.highest compare:chartData.closed] == NSOrderedDescending) { CGContextSetRGBStrokeColor(context, _aesKRed, _aesKGreen, _aesKBlue, _aesKAlpha); //high > close CGContextSetLineWidth(context, 1.0f); CGContextMoveToPoint(context, currentXPonit + _kLineWidth/2, [self yPointWithPrice:chartData.highest]); CGContextAddLineToPoint(context, currentXPonit + _kLineWidth/2, [self yPointWithPrice:chartData.closed]); CGContextStrokePath(context); } if ([chartData.lowest compare:chartData.opened] == NSOrderedAscending) { //low < close CGContextSetRGBStrokeColor(context, _aesKRed, _aesKGreen, _aesKBlue, _aesKAlpha); //low < open CGContextSetLineWidth(context, 1.0f); CGContextMoveToPoint(context, currentXPonit + _kLineWidth/2, [self yPointWithPrice:chartData.opened]); CGContextAddLineToPoint(context, currentXPonit + _kLineWidth/2, [self yPointWithPrice:chartData.lowest]); CGContextStrokePath(context); } CGContextStrokePath(context); } else { //close == open CGContextSetRGBStrokeColor(context, _samKRed, _samKGreen, _samKBlue, _samKAlpha); CGContextSetLineWidth(context, 1.0f); CGContextMoveToPoint(context, currentXPonit, [self yPointWithPrice:chartData.closed]); CGContextAddLineToPoint(context, currentXPonit + _kLineWidth, [self yPointWithPrice:chartData.closed]); if ([chartData.highest compare:chartData.closed] == NSOrderedDescending) { //high > close CGContextSetLineWidth(context, 1.0f); CGContextMoveToPoint(context, currentXPonit + _kLineWidth/2, [self yPointWithPrice:chartData.highest]); CGContextAddLineToPoint(context, currentXPonit + _kLineWidth/2, [self yPointWithPrice:chartData.closed]); } if ([chartData.lowest compare:chartData.closed] == NSOrderedAscending) { //low < open CGContextSetLineWidth(context, 1.0f); CGContextMoveToPoint(context, currentXPonit + _kLineWidth/2, [self yPointWithPrice:chartData.closed]); CGContextAddLineToPoint(context, currentXPonit + _kLineWidth/2, [self yPointWithPrice:chartData.lowest]); } CGContextStrokePath(context); } //是否需要显示十字线 if (_isShowTipLine) { /// 是否需要长显示开高低收 [self showOHLPPriceWithIsKLine:YES isShow:NO]; if (_tipLineIndex == i) { /// 画垂直线 CGContextSetRGBStrokeColor(context, _tipRed, _tipGreen, _tipBlue, _tipAlpha); CGContextSetLineWidth(context, 1.0f); CGContextMoveToPoint(context, currentXPonit + _kLineWidth/2, _yAxisPaddingTop); CGContextAddLineToPoint(context, currentXPonit + _kLineWidth/2, _kLineOrigin.y); /// 画水平线 CGContextMoveToPoint(context, _kLineOrigin.x, _tipLineYAxis); CGContextAddLineToPoint(context, _kLineOrigin.x + _xAxisWidth , _tipLineYAxis); CGContextStrokePath(context); /// 写数据 NSInteger digitCount = [ChartCalculateUtils getDecimalDigits:_minUnit]; NSString *ma5 = [ChartCalculateUtils notRounding:chartData.ma5 afterPoint:digitCount]; UIColor *profileColor = nil; if ([chartData.closed compare:chartData.opened] == NSOrderedDescending) profileColor = [UIColor colorWithRed:_aesKRed green:_aesKGreen blue:_aesKBlue alpha:1.0]; else if ([chartData.closed compare:chartData.opened] == NSOrderedAscending) profileColor = [UIColor colorWithRed:_decKRed green:_decKGreen blue:_decKBlue alpha:1.0]; else profileColor = _titleColor; /// 写数据 NSMutableAttributedString *MAString = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"MA5:%@ ", ma5 ? ma5 : @"--"] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_kMA5Red green:_kMA5Green blue:_kMA5Blue alpha:_kMA5Alpha], NSFontAttributeName:_titleFont}]; NSString *ma10 = [ChartCalculateUtils notRounding:chartData.ma10 afterPoint:digitCount]; [MAString appendAttributedString:[[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"MA10:%@ ",ma10 ? ma10 : @"--"] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_kMA10Red green:_kMA10Green blue:_kMA10Blue alpha:_kMA10Alpha], NSFontAttributeName:_titleFont}]]; NSString *ma15 = [ChartCalculateUtils notRounding:chartData.ma15 afterPoint:digitCount]; [MAString appendAttributedString:[[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"MA15:%@ ",ma15 ? ma15 : @"--"] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_kMA15Red green:_kMA15Green blue:_kMA15Blue alpha:_kMA15Alpha], NSFontAttributeName:_titleFont}]]; NSAttributedString *tipString = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"\n开:%@ 高:%@ 低:%@ 收:%@", [ChartCalculateUtils notRounding:chartData.opened afterPoint:digitCount], [ChartCalculateUtils notRounding:chartData.highest afterPoint:digitCount] ,[ChartCalculateUtils notRounding:chartData.lowest afterPoint:digitCount],[ChartCalculateUtils notRounding:chartData.closed afterPoint:digitCount]] attributes:@{NSForegroundColorAttributeName:profileColor, NSFontAttributeName:_titleFont}]; // 横屏一排显示就够了 if (self.frame.size.width < self.frame.size.height) { [tipString drawAtPoint:CGPointMake(_kLineOrigin.x, 12.0f)]; } else { [MAString appendAttributedString:tipString]; } [MAString drawAtPoint:CGPointMake(_kLineOrigin.x, 0)]; //纵轴时间 NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; if (self.cycleInterval == 30 * 24 * 60 * 60) { dateFormatter.dateFormat = @"MM-dd"; } else { dateFormatter.dateFormat = @"MM-dd HH:mm"; } NSString *dateTime = [dateFormatter stringFromDate:chartData.startTime]; CGSize dateTimeSize = [dateTime sizeWithAttributes:@{NSFontAttributeName:_titleFont}]; CGContextSetRGBFillColor(context, _tipRed, _tipGreen, _tipBlue, _tipAlpha); CGFloat x = currentXPonit+_kLineWidth/2-dateTimeSize.width/2; if (x < _xAxisPaddingLeft) x = _xAxisPaddingLeft; else if (x > _xAxisPaddingLeft + _xAxisWidth - dateTimeSize.width) x = _xAxisPaddingLeft + _xAxisWidth - dateTimeSize.width; CGContextAddRect(context, CGRectMake(x, _kLineOrigin.y, dateTimeSize.width, dateTimeSize.height)); CGContextFillPath(context); [_tipTitleColor set]; [dateTime drawAtPoint:CGPointMake(x, _kLineOrigin.y) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _tipTitleColor}]; //横轴价格 CGFloat priceXOffset = _xAxisPaddingLeft + _xAxisWidth; //价格左边距 NSInteger decimalNumber = [ChartCalculateUtils getDecimalDigits:_minUnit]; NSDecimalNumber *yPrice = [self priceWithYPoint:_tipLineYAxis]; NSString *priceString = [ChartCalculateUtils notRounding:yPrice afterPoint:decimalNumber]; CGSize priceStringSize = [priceString sizeWithAttributes:@{NSFontAttributeName:_titleFont}]; CGContextSetRGBFillColor(context, _tipRed, _tipGreen, _tipBlue, _tipAlpha); CGContextAddRect(context, CGRectMake(priceXOffset, _tipLineYAxis-priceStringSize.height/2, priceXOffset +_xAxisPaddingRight, priceStringSize.height)); CGContextFillPath(context); [_tipTitleColor set]; [priceString drawAtPoint:CGPointMake(priceXOffset+_excessXAxisWidth, _tipLineYAxis-priceStringSize.height/2) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _tipTitleColor}]; } } else { /// 是否需要长显示开高低收 [self showOHLPPriceWithIsKLine:YES isShow:YES]; } currentXPonit += _kLineWidth + _kLinePadding; } } #pragma mark - 十字线相关 /** * @brief 通过x坐标获取对应K线数据下标 * * @param xPoint x坐标 * * @return K线数据下标 */ - (NSInteger)tipIndexWithXPoint:(CGFloat)xPoint { NSInteger tipIndex = NSNotFound; CGFloat currentXPonit = _kLineOrigin.x + 1.0f; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { //要把K线的间隔也算上 CGRect kLineRect = CGRectMake(currentXPonit, _yAxisPaddingTop, _kLineWidth+_kLinePadding, _yAxisHeight); if (CGRectContainsPoint(kLineRect, CGPointMake(xPoint, _yAxisPaddingTop+10.0f))) { tipIndex = i; break; } currentXPonit += _kLineWidth + _kLinePadding; } return tipIndex; } /** * @brief 通过x坐标获取对应分时数据下标 * * @param xPoint x坐标 * * @return 分时数据下标 */ - (NSInteger)tipIndexTSPlanWithXPoint:(CGFloat)xPoint { NSInteger tipIndex = NSNotFound; CGFloat currentXPonit = _tsStartXPonit; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { //要把K线的间隔也算上 CGRect kLineRect = CGRectMake(currentXPonit, _yAxisPaddingTop, _xAxisWidth/_kLineCount, _yAxisHeight); if (CGRectContainsPoint(kLineRect, CGPointMake(xPoint, _yAxisPaddingTop+10.0f))) { tipIndex = i; break; } currentXPonit += _xAxisWidth/_kLineCount; } return tipIndex; } #pragma mark - 图表数据计算相关 /** * @brief 初始计算各平均线数据的方法 * * @param index 需要刷新数据的0-index的范围 */ - (void)initAverageLineDataWithIndex:(NSInteger)index { //当前总合,主要用于分时图 NSDecimalNumber *totalPrice = [NSDecimalNumber zero]; NSDecimalNumber *totalNumber = [NSDecimalNumber zero]; for (NSInteger i=index ; i>=0 ; i--) { /// m5 if (index-i>=4) { ChartData *chartData = nil; NSDecimalNumber *totleDecimalNumber = [NSDecimalNumber zero]; for (NSInteger j=i+4; j>=i ; j--) { chartData = [_chartDataArray objectAtIndex:j]; totleDecimalNumber = [totleDecimalNumber decimalNumberByAdding:chartData.closed]; } chartData.ma5 = [totleDecimalNumber decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"5"]]; } /// m10 if (index-i>=9) { ChartData *chartData = nil; NSDecimalNumber *totleDecimalNumber = [NSDecimalNumber zero]; for (NSInteger j=i+9; j>=i ; j--) { chartData = [_chartDataArray objectAtIndex:j]; totleDecimalNumber = [totleDecimalNumber decimalNumberByAdding:chartData.closed]; } chartData.ma10 = [totleDecimalNumber decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"10"]]; } /// m15 if (index-i>=14) { ChartData *chartData = nil; NSDecimalNumber *totleDecimalNumber = [NSDecimalNumber zero]; for (NSInteger j=i+14; j>=i ; j--) { chartData = [_chartDataArray objectAtIndex:j]; totleDecimalNumber = [totleDecimalNumber decimalNumberByAdding:chartData.closed]; } chartData.ma15 = [totleDecimalNumber decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"15"]]; } /// m50 if (index-i>=49) { ChartData *chartData = nil; NSDecimalNumber *totleDecimalNumber = [NSDecimalNumber zero]; for (NSInteger j=i+49 ; j>=i ; j--) { chartData = [_chartDataArray objectAtIndex:j]; totleDecimalNumber = [totleDecimalNumber decimalNumberByAdding:chartData.closed]; } chartData.ma50 = [totleDecimalNumber decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"50"]]; } //****************** MACD ******************** //EMA12 if (index-i>=11) { if (index-i == 11) { //第一个EMA12是前12个收盘价代数平均 NSDecimalNumber *totleDecimalNumber = [NSDecimalNumber zero]; ChartData *chartData = nil; for (NSInteger j=i+11 ; j>=i ; j--) { chartData = [_chartDataArray objectAtIndex:j]; totleDecimalNumber = [totleDecimalNumber decimalNumberByAdding:chartData.closed]; } chartData.ema12 = [totleDecimalNumber decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"12"]]; } else { //今日EMA(12) = 2/(12+1)×今日收盘价 + 11/(12+1)×昨日EMA(12)<-错的 EMA12 = 前一日EMA12 X 11/13 + 今日收盘 X 2/13 ChartData *chartData = [_chartDataArray objectAtIndex:i]; ChartData *yesterdayChartData = [_chartDataArray objectAtIndex:i+1]; chartData.ema12 = [[[[ChartCalculateUtils notRoundingWithDecimalNumber:yesterdayChartData.ema12 afterPoint:5] decimalNumberByMultiplyingBy:[NSDecimalNumber decimalNumberWithString:@"11"]] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"13"]] decimalNumberByAdding:([[chartData.closed decimalNumberByMultiplyingBy:[NSDecimalNumber decimalNumberWithString:@"2"]] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"13"]])]; } } //EMA26 & DIF if (index-i>=25) { if (index-i == 25) { NSDecimalNumber *totleDecimalNumber = [NSDecimalNumber zero]; ChartData *chartData = nil; for (NSInteger j=i+25 ; j>=i ; j--) { chartData = [_chartDataArray objectAtIndex:j]; totleDecimalNumber = [totleDecimalNumber decimalNumberByAdding:chartData.closed]; } chartData.ema26 = [totleDecimalNumber decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"26"]]; chartData.dif = [chartData.ema12 decimalNumberBySubtracting:chartData.ema26]; } else { //今日EMA(26)=2/(26+1)×今日收盘价+25/(26+1)×昨日EMA(26)<-错的 EMA26 = 前一日EMA26 X 25/27 + 今日收盘 X 2/27 ChartData *chartData = [_chartDataArray objectAtIndex:i]; ChartData *yesterdayChartData = [_chartDataArray objectAtIndex:i+1]; chartData.ema26 = [[[[ChartCalculateUtils notRoundingWithDecimalNumber:yesterdayChartData.ema26 afterPoint:5] decimalNumberByMultiplyingBy:[NSDecimalNumber decimalNumberWithString:@"25"]] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"27"]] decimalNumberByAdding:([[chartData.closed decimalNumberByMultiplyingBy:[NSDecimalNumber decimalNumberWithString:@"2"]] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"27"]])]; chartData.dif = [chartData.ema12 decimalNumberBySubtracting:chartData.ema26]; } } //DEA & MACD if (index-i>=34) { if (index-i == 34) { ChartData *chartData = nil; NSDecimalNumber *totleDecimalNumber = [NSDecimalNumber zero]; for (NSInteger j=i+9 ; j>=i ; j--) { chartData = [_chartDataArray objectAtIndex:j]; totleDecimalNumber = [totleDecimalNumber decimalNumberByAdding:chartData.dif]; } chartData.dea = [totleDecimalNumber decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"9"]]; // macd = (dif-dea)*2 chartData.macd = [[NSDecimalNumber decimalNumberWithString:@"2"] decimalNumberByMultiplyingBy:([chartData.dif decimalNumberBySubtracting:chartData.dea])]; } else { //今日DEA=(前一日DEA X 8/10 + 今日DIF X 2/10) ChartData *chartData = [_chartDataArray objectAtIndex:i]; ChartData *yesterdayChartData = [_chartDataArray objectAtIndex:i+1]; chartData.dea = [[[ChartCalculateUtils notRoundingWithDecimalNumber:yesterdayChartData.dea afterPoint:5] decimalNumberByMultiplyingBy:[NSDecimalNumber decimalNumberWithString:@"0.8"]] decimalNumberByAdding:([chartData.dif decimalNumberByMultiplyingBy:[NSDecimalNumber decimalNumberWithString:@"0.2"]])]; chartData.macd = [[NSDecimalNumber decimalNumberWithString:@"2"] decimalNumberByMultiplyingBy:([chartData.dif decimalNumberBySubtracting:chartData.dea])]; } } ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (i == 0 || !chartData.isSupp) { totalPrice = [totalPrice decimalNumberByAdding:chartData.closed]; totalNumber = [totalNumber decimalNumberByAdding:[NSDecimalNumber decimalNumberWithString:@"1"]]; chartData.tsma = [totalPrice decimalNumberByDividingBy:totalNumber]; } else { if (i != _chartDataArray.count - 1) { // 这里去对补的数据不进行处理 ChartData *yesterdayChartData = [_chartDataArray objectAtIndex:i+1]; // 如果是补的数据 当前的平均数据为上一口的数据 chartData.tsma = yesterdayChartData.tsma; } } } } /** * @brief 初始计算VOL线数据的方法 * * @param index 需要刷新数据的0-index的范围 */ - (void)initVOLLineDataWithIndex:(NSInteger)index { for (NSInteger i=index ; i>=0 ; i--) { //期5为周期算 if (index - i >= 4) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; NSDecimalNumber *averagevolume= [NSDecimalNumber zero]; //算出周期里面收盘价的总和 for (NSInteger j=i+4 ; j>=i ; j--) { chartData = [_chartDataArray objectAtIndex:j]; if (chartData.totleVolume) averagevolume = [averagevolume decimalNumberByAdding:chartData.totleVolume]; } //vol5 = sum(totalVolume, N)/N chartData.vol5 = [averagevolume decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"5"]]; } //期10为周期算 if (index - i >= 9) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; NSDecimalNumber *averagevolume= [NSDecimalNumber zero]; //算出周期里面收盘价的总和 for (NSInteger j=i+9 ; j>=i ; j--) { chartData = [_chartDataArray objectAtIndex:j]; if (chartData.totleVolume) averagevolume = [averagevolume decimalNumberByAdding:chartData.totleVolume]; } //BIAS = sum(totalVolume, N)/N chartData.vol10 = [averagevolume decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"10"]]; } } } /** * @brief 初始计算KDJ线数据的方法 * * @param index 需要刷新数据的0-index的范围 */ - (void)initKDJLineDataWithIndex:(NSInteger)index { for (NSInteger i=index ; i>=0 ; i--) { /// 取前九根为一周期 if (index - i >= 8) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; NSDecimalNumber *highDecimalNumber = chartData.highest; NSDecimalNumber *lowDecimalNumber = chartData.lowest; /// 循环算出周期里面的最高值和最低值 for (NSInteger j=i; j-i<8; j++) { ChartData *yesterdayData = [_chartDataArray objectAtIndex:j+1]; if ([highDecimalNumber compare:yesterdayData.highest] == NSOrderedAscending) { highDecimalNumber = yesterdayData.highest; } if ([lowDecimalNumber compare:yesterdayData.lowest] == NSOrderedDescending) { lowDecimalNumber = yesterdayData.lowest; } } /// 如果最高价和最低价相等 则默认rsv值为50 if ([lowDecimalNumber compare:highDecimalNumber] == NSOrderedSame) { chartData.rsv = [NSDecimalNumber decimalNumberWithString:@"50"]; } else { chartData.rsv = [[[chartData.closed decimalNumberBySubtracting:lowDecimalNumber] decimalNumberByDividingBy:[highDecimalNumber decimalNumberBySubtracting:lowDecimalNumber]] decimalNumberByMultiplyingBy:[NSDecimalNumber decimalNumberWithString:@"100"]]; } /// 如果前一日的KT值不存在则默认为50 if (!((ChartData *)[_chartDataArray objectAtIndex:i+1]).kt) { ((ChartData *)[_chartDataArray objectAtIndex:i+1]).kt = [NSDecimalNumber decimalNumberWithString:@"50"]; } /// 如果前一日的DT值不存在则默认为50 if (!((ChartData *)[_chartDataArray objectAtIndex:i+1]).dt) { ((ChartData *)[_chartDataArray objectAtIndex:i+1]).dt = [NSDecimalNumber decimalNumberWithString:@"50"]; } NSInteger digitCount = [ChartCalculateUtils getDecimalDigits:_minUnit]; /// KT = 2/3*前一日的KT+1/3*当日的RSV chartData.kt = [NSDecimalNumber decimalNumberWithString:[ChartCalculateUtils notRounding:[[[[NSDecimalNumber decimalNumberWithString:@"2"] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"3"]] decimalNumberByMultiplyingBy:((ChartData *)[_chartDataArray objectAtIndex:i+1]).kt] decimalNumberByAdding:[[[NSDecimalNumber decimalNumberWithString:@"1"] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"3"]] decimalNumberByMultiplyingBy:chartData.rsv]] afterPoint:digitCount]]; /// DT = 2/3*前一日的DT+1/3*当日的KT chartData.dt = [NSDecimalNumber decimalNumberWithString:[ChartCalculateUtils notRounding:[[[[NSDecimalNumber decimalNumberWithString:@"2"] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"3"]] decimalNumberByMultiplyingBy:((ChartData *)[_chartDataArray objectAtIndex:i+1]).dt] decimalNumberByAdding:[[[NSDecimalNumber decimalNumberWithString:@"1"] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"3"]] decimalNumberByMultiplyingBy:chartData.kt]] afterPoint:digitCount]]; /// JT = 3*当前的KT-2*当日的DT chartData.jt = [[[NSDecimalNumber decimalNumberWithString:@"3"] decimalNumberByMultiplyingBy:chartData.kt] decimalNumberBySubtracting:[[NSDecimalNumber decimalNumberWithString:@"2"] decimalNumberByMultiplyingBy:chartData.dt]]; } } } /** * @brief 初始计算CCI线数据的方法 * * @param index 需要刷新数据的0-index的范围 */ - (void)initCCILineDataWithIndex:(NSInteger)index { for (NSInteger i=index ; i>=0 ; i--) { /// 取14根为一周期 if (index - i >=13) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; ///TP = (highest + lowest + close)/3 chartData.tp = [[[chartData.highest decimalNumberByAdding:chartData.lowest] decimalNumberByAdding:chartData.closed] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"3"]]; /// MA = N日的TP的和/N NSDecimalNumber *totleDecimalNumber = [NSDecimalNumber zero]; /// 循环算出周期里面收盘价的总和 for (NSInteger j=i+13; j>=i ; j--) { chartData = [_chartDataArray objectAtIndex:j]; if (chartData.tp) totleDecimalNumber = [totleDecimalNumber decimalNumberByAdding:chartData.tp]; } chartData.ma = [totleDecimalNumber decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"14"]]; /// MD = N日的|((N)TP-MA)|的和/N(平均绝对方差) NSDecimalNumber *totalMDSum = [NSDecimalNumber zero]; NSDecimalNumber *decimal = [NSDecimalNumber zero]; /// 循环算出周期里面收盘价的总和 for (NSInteger j=i+13 ; j>=i ; j--) { ChartData *nowChartData = [_chartDataArray objectAtIndex:j]; if (chartData.ma && nowChartData.tp) decimal = [nowChartData.tp decimalNumberBySubtracting:chartData.ma]; /// 如果算出来的值为负数 则去绝对值 if ([decimal compare:[NSDecimalNumber zero]] == NSOrderedAscending) { decimal = [decimal decimalNumberByMultiplyingBy:[NSDecimalNumber decimalNumberWithString:@"-1"]]; } totalMDSum = [totalMDSum decimalNumberByAdding:decimal]; } chartData.md = [totalMDSum decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"14"]]; /// CCI = (TP-MA)/MD/0.015 if (chartData.tp && chartData.ma && chartData.md && [chartData.md compare:[NSDecimalNumber zero]] != NSOrderedSame) chartData.cci = [[chartData.tp decimalNumberBySubtracting:chartData.ma] decimalNumberByDividingBy:[chartData.md decimalNumberByMultiplyingBy:[NSDecimalNumber decimalNumberWithString:@"0.015"]]]; } } } /** * @brief 初始计算DMA线数据的方法 * * @param index 需要刷新数据的0-index的范围 */ - (void)initDMALineDataWithIndex:(NSInteger)index { for (NSInteger i=index ; i>=0 ; i--) { //以10为一周期进行计算 if (index - i >= 9) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; //DMA = MA10 - MA50 if (chartData.ma10 && chartData.ma50) chartData.dma = [chartData.ma10 decimalNumberBySubtracting:chartData.ma50]; NSDecimalNumber *totalAMASum = [NSDecimalNumber zero]; //算出周期里面dma的和 for (NSInteger j=i+9 ; j>=i ; j--) { chartData = [_chartDataArray objectAtIndex:j]; if (chartData.dma) totalAMASum = [totalAMASum decimalNumberByAdding:chartData.dma]; } chartData.ama = [totalAMASum decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"10"]]; } } } /** * @brief 初始计算BIAS线数据的方法 * * @param index 需要刷新数据的0-index的范围 */ - (void)initBIASLineDataWithIndex:(NSInteger)index { for (NSInteger i=index ; i>=0 ; i--) { //期6为周期算 if (index - i >= 5) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; NSDecimalNumber *totalCloseSum = [NSDecimalNumber zero]; //算出周期里面收盘价的总和 for (NSInteger j=i+5 ; j>=i ; j--) { chartData = [_chartDataArray objectAtIndex:j]; totalCloseSum = [totalCloseSum decimalNumberByAdding:chartData.closed]; } if ([totalCloseSum compare:[NSDecimalNumber zero]] != NSOrderedSame) { //BIAS = (closed - N(closed))/N(closed)*100 chartData.bias1 = [[[chartData.closed decimalNumberBySubtracting:[totalCloseSum decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"6"]]] decimalNumberByDividingBy:[totalCloseSum decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"6"]]] decimalNumberByMultiplyingBy:[NSDecimalNumber decimalNumberWithString:@"100"]]; } else { chartData.bias1 = [NSDecimalNumber zero]; } } //期12为周期算 if (index - i >= 11) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; NSDecimalNumber *totalCloseSum = [NSDecimalNumber zero]; //算出周期里面收盘价的总和 for (NSInteger j=i+11 ; j>=i ; j--) { chartData = [_chartDataArray objectAtIndex:j]; totalCloseSum = [totalCloseSum decimalNumberByAdding:chartData.closed]; } if ([totalCloseSum compare:[NSDecimalNumber zero]] != NSOrderedSame) { //BIAS = (closed - N(closed))/N(closed)*100 chartData.bias2 = [[[chartData.closed decimalNumberBySubtracting:[totalCloseSum decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"12"]]] decimalNumberByDividingBy:[totalCloseSum decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"12"]]] decimalNumberByMultiplyingBy:[NSDecimalNumber decimalNumberWithString:@"100"]]; } else { chartData.bias2 = [NSDecimalNumber zero]; } } //期24为周期算 if (index - i >= 23) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; NSDecimalNumber *totalCloseSum = [NSDecimalNumber zero]; //算出周期里面收盘价的总和 for (NSInteger j=i+23 ; j>=i ; j--) { chartData = [_chartDataArray objectAtIndex:j]; totalCloseSum = [totalCloseSum decimalNumberByAdding:chartData.closed]; } if ([totalCloseSum compare:[NSDecimalNumber zero]] != NSOrderedSame) { //BIAS = (closed - N(closed))/N(closed)*100 chartData.bias3 = [[[chartData.closed decimalNumberBySubtracting:[totalCloseSum decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"24"]]] decimalNumberByDividingBy:[totalCloseSum decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"24"]]] decimalNumberByMultiplyingBy:[NSDecimalNumber decimalNumberWithString:@"100"]]; } else { chartData.bias3 = [NSDecimalNumber zero]; } } } } /** * @brief 初始计算PSY线数据的方法 * * @param index 需要刷新数据的0-index的范围 */ - (void)initPSYLineDataWithIndex:(NSInteger)index { for (NSInteger i=index ; i>=0 ; i--) { //取前12根为一周期 if (index - i >= 12) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; NSDecimalNumber *upFlagDecimalNumber = [NSDecimalNumber zero]; //循环算出周期里面上涨的天数 for (NSInteger j=i; j-i<12; j++) { ChartData *nowChartData = [_chartDataArray objectAtIndex:j]; ChartData *yesterdayData = [_chartDataArray objectAtIndex:j+1]; if ([nowChartData.closed compare:yesterdayData.closed] == NSOrderedDescending) { upFlagDecimalNumber = [upFlagDecimalNumber decimalNumberByAdding:[NSDecimalNumber decimalNumberWithString:@"1"]]; } } //PSY = 上涨的天数/周期 * 100 chartData.psy = [[upFlagDecimalNumber decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"12"]] decimalNumberByMultiplyingBy:[NSDecimalNumber decimalNumberWithString:@"100"]]; } //取前6根为一周期 if (index - i >= 6) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; NSDecimalNumber *sumPsyDecimal = [NSDecimalNumber zero]; //循环算出周期里面上涨的天数 for (NSInteger j=i; j-i<6; j++) { ChartData *nowChartData = [_chartDataArray objectAtIndex:j]; if (nowChartData.psy) { sumPsyDecimal = [sumPsyDecimal decimalNumberByAdding:nowChartData.psy]; } } //PSYMA = PSY的M日简单移动平均 chartData.psyma = [sumPsyDecimal decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"6"]]; } } } #pragma mark - 画平均线相关 /** * @brief 画平均线的方法(MACD相关计算目前也放在这个方法完成) */ - (void)drawAverageLine { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(context, 1.0f); /// MA5 CGContextSetRGBStrokeColor(context, _kMA5Red, _kMA5Green, _kMA5Blue, _kMA5Alpha); CGFloat currentXPoint = _kLineOrigin.x + 1.0f+_kLineWidth/2; BOOL isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.ma5) { /// 前4条数据 } else if (chartData.ma5 && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yPointWithPrice:chartData.ma5]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yPointWithPrice:chartData.ma5]); CGContextMoveToPoint(context, currentXPoint, [self yPointWithPrice:chartData.ma5]); } currentXPoint += _kLineWidth + _kLinePadding; } CGContextStrokePath(context); //MA10 CGContextSetRGBStrokeColor(context, _kMA10Red, _kMA10Green, _kMA10Blue, _kMA10Alpha); currentXPoint = _kLineOrigin.x + 1.0f+_kLineWidth/2; isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.ma10) { //前9条数据 } else if (chartData.ma10 && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yPointWithPrice:chartData.ma10]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yPointWithPrice:chartData.ma10]); CGContextMoveToPoint(context, currentXPoint, [self yPointWithPrice:chartData.ma10]); } currentXPoint += _kLineWidth + _kLinePadding; } CGContextStrokePath(context); //MA15 CGContextSetRGBStrokeColor(context, _kMA15Red, _kMA15Green, _kMA15Blue, _kMA15Alpha); currentXPoint = _kLineOrigin.x + 1.0f+_kLineWidth/2; isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.ma15) { //前14条数据 } else if (chartData.ma15 && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yPointWithPrice:chartData.ma15]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yPointWithPrice:chartData.ma15]); CGContextMoveToPoint(context, currentXPoint, [self yPointWithPrice:chartData.ma15]); } currentXPoint += _kLineWidth + _kLinePadding; } CGContextStrokePath(context); if (!_isShowTipLine) { // 获取最后一根数据 ChartData *chartData = [_chartDataArray objectAtIndex:0]; NSInteger digitCount = [ChartCalculateUtils getDecimalDigits:_minUnit]; //平均线说明 CGFloat currentX = _kLineOrigin.x; //MA5 NSString *ma5 = [ChartCalculateUtils notRounding:chartData.ma5 afterPoint:digitCount]; NSAttributedString *MA5 = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"MA5:%@", ma5 ? ma5 : @"--"] attributes:@{NSFontAttributeName:_titleFont, NSForegroundColorAttributeName:[UIColor colorWithRed:_kMA5Red green:_kMA5Green blue:_kMA5Blue alpha:_kMA5Alpha]}]; CGSize titleSize = [MA5 size]; [MA5 drawAtPoint:CGPointMake(currentX, _yAxisPaddingTop - 18.0f)]; currentX += titleSize.width + 4.0f; //MA10 NSString *ma10 = [ChartCalculateUtils notRounding:chartData.ma10 afterPoint:digitCount]; NSAttributedString *MA10 = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"MA10:%@", ma10 ? ma10 : @"--"] attributes:@{NSFontAttributeName:_titleFont, NSForegroundColorAttributeName:[UIColor colorWithRed:_kMA10Red green:_kMA10Green blue:_kMA10Blue alpha:_kMA10Alpha]}]; titleSize = [MA10 size]; [MA10 drawAtPoint:CGPointMake(currentX, _yAxisPaddingTop - 18.0f)]; currentX += titleSize.width + 4.0f; //MA15 NSString *ma15 = [ChartCalculateUtils notRounding:chartData.ma15 afterPoint:digitCount]; NSAttributedString *MA15 = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"MA15:%@", ma15 ? ma15 : @"--"] attributes:@{NSFontAttributeName:_titleFont, NSForegroundColorAttributeName:[UIColor colorWithRed:_kMA15Red green:_kMA15Green blue:_kMA15Blue alpha:_kMA15Alpha]}]; titleSize = [MA15 size]; [MA15 drawAtPoint:CGPointMake(currentX, _yAxisPaddingTop - 18.0f)]; } } /** * @brief 画平均线的方法(MACD相关计算目前也放在这个方法完成) */ - (void)drawBBAverageLine { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(context, 1.0f); //MA5 CGContextSetRGBStrokeColor(context, _kMA5Red, _kMA5Green, _kMA5Blue, _kMA5Alpha); CGFloat currentXPoint = _kLineOrigin.x; BOOL isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.ma5) { //前4条数据 } else if (chartData.ma5 && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yPointWithPrice:chartData.ma5]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yPointWithPrice:chartData.ma5]); CGContextMoveToPoint(context, currentXPoint, [self yPointWithPrice:chartData.ma5]); } currentXPoint += _xAxisWidth/_kLineCount; } CGContextStrokePath(context); //MA10 CGContextSetRGBStrokeColor(context, _kMA10Red, _kMA10Green, _kMA10Blue, _kMA10Alpha); currentXPoint = _kLineOrigin.x; isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.ma10) { //前9条数据 } else if (chartData.ma10 && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yPointWithPrice:chartData.ma10]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yPointWithPrice:chartData.ma10]); CGContextMoveToPoint(context, currentXPoint, [self yPointWithPrice:chartData.ma10]); } currentXPoint += _xAxisWidth/_kLineCount; } CGContextStrokePath(context); //MA15 CGContextSetRGBStrokeColor(context, _kMA15Red, _kMA15Green, _kMA15Blue, _kMA15Alpha); currentXPoint = _kLineOrigin.x; isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.ma15) { //前14条数据 } else if (chartData.ma15 && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yPointWithPrice:chartData.ma15]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yPointWithPrice:chartData.ma15]); CGContextMoveToPoint(context, currentXPoint, [self yPointWithPrice:chartData.ma15]); } currentXPoint += _xAxisWidth/_kLineCount; } CGContextStrokePath(context); if (!_isShowTipLine) { // 获取最后一根数据 ChartData *chartData = [_chartDataArray objectAtIndex:0]; NSInteger digitCount = [ChartCalculateUtils getDecimalDigits:_minUnit]; //平均线说明 CGFloat currentX = _kLineOrigin.x; //MA5 NSString *ma5 = [ChartCalculateUtils notRounding:chartData.ma5 afterPoint:digitCount]; NSAttributedString *MA5 = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"MA5:%@", ma5 ? ma5 : @"--"] attributes:@{NSFontAttributeName:_titleFont, NSForegroundColorAttributeName:[UIColor colorWithRed:_kMA5Red green:_kMA5Green blue:_kMA5Blue alpha:_kMA5Alpha]}]; CGSize titleSize = [MA5 size]; [MA5 drawAtPoint:CGPointMake(currentX, _yAxisPaddingTop - 18.0f)]; currentX += titleSize.width + 4.0f; //MA10 NSString *ma10 = [ChartCalculateUtils notRounding:chartData.ma10 afterPoint:digitCount]; NSAttributedString *MA10 = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"MA10:%@", ma10 ? ma10 : @"--"] attributes:@{NSFontAttributeName:_titleFont, NSForegroundColorAttributeName:[UIColor colorWithRed:_kMA10Red green:_kMA10Green blue:_kMA10Blue alpha:_kMA10Alpha]}]; titleSize = [MA10 size]; [MA10 drawAtPoint:CGPointMake(currentX, _yAxisPaddingTop - 18.0f)]; currentX += titleSize.width + 4.0f; //MA15 NSString *ma15 = [ChartCalculateUtils notRounding:chartData.ma15 afterPoint:digitCount]; NSAttributedString *MA15 = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"MA15:%@", ma15 ? ma15 : @"--"] attributes:@{NSFontAttributeName:_titleFont, NSForegroundColorAttributeName:[UIColor colorWithRed:_kMA15Red green:_kMA15Green blue:_kMA15Blue alpha:_kMA15Alpha]}]; titleSize = [MA15 size]; [MA15 drawAtPoint:CGPointMake(currentX, _yAxisPaddingTop - 18.0f)]; } } #pragma mark - 画即时图相关 /** * @brief 画即时图的方法 */ - (void)drawImmediatelyLine { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetRGBStrokeColor(context, 1.0f, 1.0, 1.0f, 1.0f); BOOL isInit = NO; CGFloat currentXPonit = _kLineOrigin.x + 1.0f; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!isInit) { CGContextMoveToPoint(context, currentXPonit, [self yPointWithPrice:chartData.closed]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPonit, [self yPointWithPrice:chartData.closed]); CGContextMoveToPoint(context, currentXPonit, [self yPointWithPrice:chartData.closed]); } currentXPonit += _kLineWidth + _kLinePadding; } CGContextStrokePath(context); currentXPonit = _kLineOrigin.x + 1.0f; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; /// 是否需要显示十字线 if (_isShowTipLine) { if (_tipLineIndex == i) { /// 画垂直线 CGContextSetRGBStrokeColor(context, 1.0f, 1.0f, 1.0f, 1.0f); CGContextSetLineWidth(context, 1.0f); CGContextMoveToPoint(context, currentXPonit + _kLineWidth/2, _yAxisPaddingTop); CGContextAddLineToPoint(context, currentXPonit + _kLineWidth/2, _kLineOrigin.y); /// 画水平线 CGContextMoveToPoint(context, _kLineOrigin.x, _tipLineYAxis); CGContextAddLineToPoint(context, _kLineOrigin.x + _xAxisWidth , _tipLineYAxis); CGContextStrokePath(context); /// 写数据 NSInteger digitCount = [ChartCalculateUtils getDecimalDigits:_minUnit]; NSString *tipString = [NSString stringWithFormat:@"Open:%@ High:%@ Low:%@ Close:%@" ,[ChartCalculateUtils notRounding:chartData.opened afterPoint:digitCount] ,[ChartCalculateUtils notRounding:chartData.highest afterPoint:digitCount] ,[ChartCalculateUtils notRounding:chartData.lowest afterPoint:digitCount] ,[ChartCalculateUtils notRounding:chartData.closed afterPoint:digitCount] ]; UIColor *profileColor = nil; if ([chartData.closed compare:chartData.opened] == NSOrderedDescending) profileColor = [UIColor colorWithRed:_aesKRed green:_aesKGreen blue:_aesKBlue alpha:1.0]; else if ([chartData.closed compare:chartData.opened] == NSOrderedAscending) profileColor = [UIColor colorWithRed:_decKRed green:_decKGreen blue:_decKBlue alpha:1.0]; else profileColor = _titleColor; [profileColor set]; [tipString drawAtPoint:CGPointMake(_kLineOrigin.x, _yAxisPaddingTop - [tipString sizeWithAttributes:@{NSFontAttributeName:_titleFont}].height) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; /// 纵轴时间 NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; dateFormatter.dateFormat = @"MM-dd HH:mm"; NSString *dateTime = [dateFormatter stringFromDate:chartData.startTime]; CGSize dateTimeSize = [dateTime sizeWithAttributes:@{NSFontAttributeName:_titleFont}]; CGContextSetRGBFillColor(context, 1.0f, 1.0f, 1.0f, 0.9f); CGFloat x = currentXPonit+_kLineWidth/2-dateTimeSize.width/2; if (x < _xAxisPaddingLeft) x = _xAxisPaddingLeft; else if (x > _xAxisPaddingLeft + _xAxisWidth - dateTimeSize.width) x = _xAxisPaddingLeft + _xAxisWidth - dateTimeSize.width; CGContextAddRect(context, CGRectMake(x, _kLineOrigin.y, dateTimeSize.width, dateTimeSize.height)); CGContextFillPath(context); [[UIColor blackColor] set]; [dateTime drawAtPoint:CGPointMake(x, _kLineOrigin.y) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _tipTitleColor}]; /// 横轴价格 CGFloat priceXOffset = _xAxisPaddingLeft + _xAxisWidth; //价格左边距 NSInteger decimalNumber = [ChartCalculateUtils getDecimalDigits:_minUnit]; NSDecimalNumber *yPrice = [self priceWithYPoint:_tipLineYAxis]; NSString *priceString = [ChartCalculateUtils notRounding:yPrice afterPoint:decimalNumber]; CGSize priceStringSize = [priceString sizeWithAttributes:@{NSFontAttributeName:_titleFont}]; CGContextSetRGBFillColor(context, 1.0f, 1.0f, 1.0f, 0.9f); CGContextAddRect(context, CGRectMake(priceXOffset, _tipLineYAxis-priceStringSize.height/2, priceXOffset +_xAxisPaddingRight, priceStringSize.height)); CGContextFillPath(context); [[UIColor blackColor] set]; [priceString drawAtPoint:CGPointMake(priceXOffset+_excessXAxisWidth, _tipLineYAxis-priceStringSize.height/2) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _tipTitleColor}]; break; } } currentXPonit += _kLineWidth + _kLinePadding; } } #pragma mark - 画分时图相关 /** * @brief 画分时图的方法 */ - (void)drawTSPlanLine { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetRGBStrokeColor(context, _tsRed, _tsGreen, _tsBlue, _tsAlpha); CGContextSetLineWidth(context, 1.0f); NSMutableArray *pointArray = [[NSMutableArray alloc] init]; /// FIXME: 临时性解决有完整数据(交易日已完整休市)后,总数据条数对不上的问题 if (self.chartDataArray.count > 0) { ChartData *lastData = self.chartDataArray[0]; if ([lastData.startTime compare:self.tsCloseTime] == NSOrderedSame && !_added) { _kLineCount = self.chartDataArray.count; _added = YES; } } /// 判断最早的数据时间是否开盘时间 BOOL isInit = NO; NSInteger diffTime = [self diffMinuteWithFromDate:_tsStartTime toDate:((ChartData *)[_chartDataArray objectAtIndex:_chartDataArray.count-1]).startTime]; _tsStartXPonit = _kLineOrigin.x; if (diffTime != 0) { /// 在昨价线上画一条到最早数据的直线 _tsStartXPonit += diffTime * (_xAxisWidth/_kLineCount); CGContextMoveToPoint(context, _kLineOrigin.x, [self yPointWithPrice:_preClose]); CGContextAddLineToPoint(context, _tsStartXPonit, [self yPointWithPrice:_preClose]); isInit = YES; /// 记录第一个点 [pointArray addObject:[NSValue valueWithCGPoint:CGPointMake(_kLineOrigin.x, [self yPointWithPrice:_preClose])]]; /// 记录第二个点 [pointArray addObject:[NSValue valueWithCGPoint:CGPointMake(_tsStartXPonit, [self yPointWithPrice:_preClose])]]; } CGFloat currentXPonit = _tsStartXPonit; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; /// 记录位置 CGPoint point = CGPointMake(currentXPonit, [self yPointWithPrice:chartData.closed]); [pointArray addObject:[NSValue valueWithCGPoint:point]]; if (!isInit) { CGContextMoveToPoint(context, currentXPonit, [self yPointWithPrice:chartData.closed]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPonit, [self yPointWithPrice:chartData.closed]); CGContextMoveToPoint(context, currentXPonit, [self yPointWithPrice:chartData.closed]); } currentXPonit += _xAxisWidth/_kLineCount; } CGContextStrokePath(context); if (pointArray.count > 0) { /// 画填充 CGContextMoveToPoint(context, _kLineOrigin.x, _kLineOrigin.y); for (int i=0 ; i=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; /// 是否需要显示十字线 if (_isShowTipLine) { if (_tipLineIndex == i) { /// 画垂直线 CGContextSetRGBStrokeColor(context, _tipRed, _tipGreen, _tipBlue, _tipAlpha); CGContextSetLineWidth(context, 1.0f); CGContextMoveToPoint(context, currentXPonit, _yAxisPaddingTop); CGContextAddLineToPoint(context, currentXPonit, _kLineOrigin.y); /// 画水平线 CGContextMoveToPoint(context, _kLineOrigin.x, _tipLineYAxis); CGContextAddLineToPoint(context, _kLineOrigin.x + _xAxisWidth , _tipLineYAxis); CGContextStrokePath(context); UIColor *profileColor = nil; if ([chartData.closed compare:chartData.opened] == NSOrderedDescending) profileColor = [UIColor colorWithRed:_aesKRed green:_aesKGreen blue:_aesKBlue alpha:1.0]; else if ([chartData.closed compare:chartData.opened] == NSOrderedAscending) profileColor = [UIColor colorWithRed:_decKRed green:_decKGreen blue:_decKBlue alpha:1.0]; else profileColor = _titleColor; /// 写数据 NSInteger digitCount = [ChartCalculateUtils getDecimalDigits:_minUnit]; NSString *tipString = [NSString stringWithFormat:@"开:%@ 高:%@ 低:%@ 收:%@" ,[ChartCalculateUtils notRounding:chartData.opened afterPoint:digitCount] ,[ChartCalculateUtils notRounding:chartData.highest afterPoint:digitCount] ,[ChartCalculateUtils notRounding:chartData.lowest afterPoint:digitCount] ,[ChartCalculateUtils notRounding:chartData.closed afterPoint:digitCount] ]; [profileColor set]; [tipString drawAtPoint:CGPointMake(_kLineOrigin.x, _yAxisPaddingTop - [tipString sizeWithAttributes:@{NSFontAttributeName:_titleFont}].height) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: profileColor}]; /// 纵轴时间 NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; dateFormatter.dateFormat = _chartViewType == ChartViewTypeTSPlan ? @"HH:mm" : @"MM-dd HH:mm"; NSString *dateTime = [dateFormatter stringFromDate:chartData.startTime]; CGSize dateTimeSize = [dateTime sizeWithAttributes:@{NSFontAttributeName:_titleFont}]; CGContextSetRGBFillColor(context, _tipRed, _tipGreen, _tipBlue, _tipAlpha); CGFloat x = currentXPonit+_kLineWidth/2-dateTimeSize.width/2; if (x < _xAxisPaddingLeft) x = _xAxisPaddingLeft; else if (x > _xAxisPaddingLeft + _xAxisWidth - dateTimeSize.width) x = _xAxisPaddingLeft + _xAxisWidth - dateTimeSize.width; CGContextAddRect(context, CGRectMake(x, _kLineOrigin.y, dateTimeSize.width, dateTimeSize.height)); CGContextFillPath(context); [_tipTitleColor set]; [dateTime drawAtPoint:CGPointMake(x, _kLineOrigin.y) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _tipTitleColor}]; /// 横轴价格 CGFloat priceXOffset = _xAxisPaddingLeft + _xAxisWidth; /// 价格左边距 NSInteger decimalNumber = [ChartCalculateUtils getDecimalDigits:_minUnit]; NSDecimalNumber *yPrice = [self priceWithYPoint:_tipLineYAxis]; NSString *priceString = [ChartCalculateUtils notRounding:yPrice afterPoint:decimalNumber]; CGSize priceStringSize = [priceString sizeWithAttributes:@{NSFontAttributeName:_titleFont}]; CGContextSetRGBFillColor(context, _tipRed, _tipGreen, _tipBlue, _tipAlpha); CGContextAddRect(context, CGRectMake(priceXOffset, _tipLineYAxis-priceStringSize.height/2, priceXOffset +_xAxisPaddingRight, priceStringSize.height)); CGContextFillPath(context); [_tipTitleColor set]; [priceString drawAtPoint:CGPointMake(priceXOffset+_excessXAxisWidth, _tipLineYAxis-priceStringSize.height/2) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _tipTitleColor}]; break; } } currentXPonit += _xAxisWidth/_kLineCount; } } /// 是否需要常显示开高低收 - (void)showOHLPPriceWithIsKLine:(BOOL)isKine isShow:(BOOL)isShow { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetRGBStrokeColor(context, _tsRed, _tsGreen, _tsBlue, _tsAlpha); CGContextSetLineWidth(context, 1.0f); /// 不需要显示 不做任何处理 if (!_isShowOHLP) { return; } /// 数据为空不做任何处理 if (self.chartDataArray.count == 0) { return; } ChartData *chartData = [self.chartDataArray firstObject]; UIColor *profileColor = nil; if ([chartData.closed compare:chartData.opened] == NSOrderedDescending) profileColor = [UIColor colorWithRed:_aesKRed green:_aesKGreen blue:_aesKBlue alpha:1.0]; else if ([chartData.closed compare:chartData.opened] == NSOrderedAscending) profileColor = [UIColor colorWithRed:_decKRed green:_decKGreen blue:_decKBlue alpha:1.0]; else profileColor = _titleColor; /// 写数据 NSInteger digitCount = [ChartCalculateUtils getDecimalDigits:_minUnit]; NSAttributedString *tipString = isShow ? [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"开:%@ 高:%@ 低:%@ 收:%@", [ChartCalculateUtils notRounding:chartData.opened afterPoint:digitCount], [ChartCalculateUtils notRounding:chartData.highest afterPoint:digitCount], [ChartCalculateUtils notRounding:chartData.lowest afterPoint:digitCount], [ChartCalculateUtils notRounding:chartData.closed afterPoint:digitCount]] attributes:@{NSFontAttributeName:_titleFont, NSForegroundColorAttributeName:profileColor}] : [[NSAttributedString alloc] initWithString:@""]; CGPoint point = isKine ? CGPointMake(_kLineOrigin.x, _yAxisPaddingTop - [tipString size].height + 15.0) : CGPointMake(_kLineOrigin.x, _yAxisPaddingTop - [tipString size].height + 15.0); [tipString drawAtPoint:point]; CGContextFillPath(context); } /** * @brief 画分时图平均线的方法 */ - (void)drawTSAverageLine { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(context, 1.0f); /// MA5 CGContextSetRGBStrokeColor(context, _tsMARed, _tsMAGreen, _tsMABlue, _tsMAAlpha); CGFloat currentXPoint =_tsStartXPonit; BOOL isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (chartData.tsma && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yPointWithPrice:chartData.tsma]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yPointWithPrice:chartData.tsma]); } currentXPoint += _xAxisWidth/_kLineCount; } CGContextStrokePath(context); if (!_isShowTipLine) { /// 平均线说明 CGFloat currentX = _kLineOrigin.x; /// MA5 [[UIColor colorWithRed:_tsMARed green:_tsMAGreen blue:_tsMABlue alpha:_tsMAAlpha] set]; CGSize titleSize = [@"MA" sizeWithAttributes:@{NSFontAttributeName:_titleFont}]; [@"MA" drawAtPoint:CGPointMake(currentX, _yAxisPaddingTop - titleSize.height) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; } } #pragma mark - 数字货币分时图 /** * @brief 数字火币画分时图的方法 */ - (void)drawBBTSPlanLine { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(context, 1.0f); CGContextSetRGBStrokeColor(context, _tsRed, _tsGreen, _tsBlue, _tsAlpha); CGFloat currentXPoint = _kLineOrigin.x; BOOL isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (chartData.tsma && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yPointWithPrice:chartData.closed]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yPointWithPrice:chartData.closed]); } currentXPoint += _xAxisWidth/_kLineCount; } CGContextStrokePath(context); currentXPoint = _kLineOrigin.x; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; /// 是否需要显示十字线 if (_isShowTipLine) { if (_tipLineIndex == i) { CGContextSetLineWidth(context, 1.0f); CGContextMoveToPoint(context, currentXPoint, _yAxisPaddingTop); CGContextAddLineToPoint(context, currentXPoint, _kLineOrigin.y); /// 画水平线 CGContextMoveToPoint(context, _kLineOrigin.x, _tipLineYAxis); CGContextAddLineToPoint(context, _kLineOrigin.x + _xAxisWidth , _tipLineYAxis); CGContextStrokePath(context); UIColor *profileColor = nil; if ([chartData.closed compare:chartData.opened] == NSOrderedDescending) profileColor = [UIColor colorWithRed:_aesKRed green:_aesKGreen blue:_aesKBlue alpha:1.0]; else if ([chartData.closed compare:chartData.opened] == NSOrderedAscending) profileColor = [UIColor colorWithRed:_decKRed green:_decKGreen blue:_decKBlue alpha:1.0]; else profileColor = _titleColor; /// 写数据 NSInteger digitCount = [ChartCalculateUtils getDecimalDigits:_minUnit]; NSString *ma5 = [ChartCalculateUtils notRounding:chartData.ma5 afterPoint:digitCount]; /// 写数据 NSMutableAttributedString *MAString = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"MA5:%@ ", ma5 ? ma5 : @"--"] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_kMA5Red green:_kMA5Green blue:_kMA5Blue alpha:_kMA5Alpha], NSFontAttributeName:_titleFont}]; NSString *ma10 = [ChartCalculateUtils notRounding:chartData.ma10 afterPoint:digitCount]; [MAString appendAttributedString:[[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"MA10:%@ ",ma10 ? ma10 : @"--"] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_kMA10Red green:_kMA10Green blue:_kMA10Blue alpha:_kMA10Alpha], NSFontAttributeName:_titleFont}]]; NSString *ma15 = [ChartCalculateUtils notRounding:chartData.ma15 afterPoint:digitCount]; [MAString appendAttributedString:[[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"MA15:%@ ",ma15 ? ma15 : @"--"] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_kMA15Red green:_kMA15Green blue:_kMA15Blue alpha:_kMA15Alpha], NSFontAttributeName:_titleFont}]]; NSAttributedString *tipString = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"\n开:%@ 高:%@ 低:%@ 收:%@", [ChartCalculateUtils notRounding:chartData.opened afterPoint:digitCount], [ChartCalculateUtils notRounding:chartData.highest afterPoint:digitCount] ,[ChartCalculateUtils notRounding:chartData.lowest afterPoint:digitCount],[ChartCalculateUtils notRounding:chartData.closed afterPoint:digitCount]] attributes:@{NSForegroundColorAttributeName:profileColor, NSFontAttributeName:_titleFont}]; /// 横屏一排显示就够了 if (self.frame.size.width < self.frame.size.height) { [tipString drawAtPoint:CGPointMake(_kLineOrigin.x, 12.0f)]; } else { [MAString appendAttributedString:tipString]; } [MAString drawAtPoint:CGPointMake(_kLineOrigin.x, 0)]; /// 纵轴时间 NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; dateFormatter.dateFormat = @"MM-dd HH:mm"; NSString *dateTime = [dateFormatter stringFromDate:chartData.startTime]; CGSize dateTimeSize = [dateTime sizeWithAttributes:@{NSFontAttributeName:_titleFont}]; CGContextSetRGBFillColor(context, _tipRed, _tipGreen, _tipBlue, _tipAlpha); CGFloat x = currentXPoint+_kLineWidth/2-dateTimeSize.width/2; if (x < _xAxisPaddingLeft) x = _xAxisPaddingLeft; else if (x > _xAxisPaddingLeft + _xAxisWidth - dateTimeSize.width) x = _xAxisPaddingLeft + _xAxisWidth - dateTimeSize.width; CGContextAddRect(context, CGRectMake(x, _kLineOrigin.y, dateTimeSize.width, dateTimeSize.height)); CGContextFillPath(context); [_tipTitleColor set]; [dateTime drawAtPoint:CGPointMake(x, _kLineOrigin.y) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _tipTitleColor}]; /// 横轴价格 CGFloat priceXOffset = _xAxisPaddingLeft + _xAxisWidth; //价格左边距 NSInteger decimalNumber = [ChartCalculateUtils getDecimalDigits:_minUnit]; NSDecimalNumber *yPrice = [self priceWithYPoint:_tipLineYAxis]; NSString *priceString = [ChartCalculateUtils notRounding:yPrice afterPoint:decimalNumber]; CGSize priceStringSize = [priceString sizeWithAttributes:@{NSFontAttributeName:_titleFont}]; CGContextSetRGBFillColor(context, _tipRed, _tipGreen, _tipBlue, _tipAlpha); CGContextAddRect(context, CGRectMake(priceXOffset, _tipLineYAxis-priceStringSize.height/2, priceXOffset +_xAxisPaddingRight, priceStringSize.height)); CGContextFillPath(context); [_tipTitleColor set]; [priceString drawAtPoint:CGPointMake(priceXOffset+_excessXAxisWidth, _tipLineYAxis-priceStringSize.height/2) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _tipTitleColor}]; break; } } currentXPoint += _xAxisWidth/_kLineCount; } } #pragma mark - MACD指标相关 /** * @brief 初始化MACD的可视化的最大值和最小值的方法 */ - (void)initMACDData { //可视MACD最大值与最小值 _indicatorMaxValue = [[self maxMACDValueAtVisible] floatValue]; _indicatorMinValue = [[self minMACDValueAtVisible] floatValue]; } /** * @brief 画MACD指标的方法 */ - (void)drawMACD { if ( isnan([self yMACDPointWithValue:[NSDecimalNumber zero]])) return; CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(context, 1.0f); /// 画0线与标题 CGFloat priceXOffset = _xAxisPaddingLeft + _xAxisWidth; /// 价格左边距 CGFloat red = 1.0, green = 1.0, blue = 1.0, alpha = 1.0; [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; /// 向red等设置值 CGContextSetRGBStrokeColor(context, red, green, blue, alpha); CGContextMoveToPoint(context, _indicatorOrigin.x, [self yMACDPointWithValue:[NSDecimalNumber zero]]); CGContextAddLineToPoint(context, _indicatorOrigin.x + _xAxisWidth,[self yMACDPointWithValue:[NSDecimalNumber zero]]); CGContextStrokePath(context); CGSize zeroTitleSize = [@"0" sizeWithAttributes:@{NSFontAttributeName:_titleFont}]; [_titleColor set]; [@"0" drawAtPoint:CGPointMake(priceXOffset, [self yMACDPointWithValue:[NSDecimalNumber zero]]-zeroTitleSize.height/2) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; /// 最大与最小值标题 NSString *maxString = [ChartCalculateUtils notRounding:[self maxMACDValueAtVisible] afterPoint:[ChartCalculateUtils getDecimalDigits:_minUnit]]; [maxString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, _indicatorOrigin.y - _indicatorHight) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; NSString *minString = [ChartCalculateUtils notRounding:[self minMACDValueAtVisible] afterPoint:[ChartCalculateUtils getDecimalDigits:_minUnit]];//负数 [minString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, _indicatorOrigin.y - [minString sizeWithAttributes:@{NSFontAttributeName:_titleFont}].height) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; /// MACD标题 CGFloat currentXPonit = _indicatorOrigin.x; /// 画MACD柱 currentXPonit = _kLineOrigin.x + 1.0f; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (chartData.macd) { if ([chartData.macd compare:[NSDecimalNumber zero]] == NSOrderedAscending) { //close < open CGContextSetRGBFillColor(context, _decKRed, _decKGreen, _decKBlue, _decKAlpha); CGContextAddRect(context, CGRectMake(currentXPonit, [self yMACDPointWithValue:[NSDecimalNumber zero]], _kLineWidth, [self yMACDPointWithValue:chartData.macd] - [self yMACDPointWithValue:[NSDecimalNumber zero]])); CGContextFillPath(context); } else if ([chartData.macd compare:[NSDecimalNumber zero]] == NSOrderedDescending) { //close < open CGContextSetRGBFillColor(context, _aesKRed, _aesKGreen, _aesKBlue, _aesKAlpha); CGContextAddRect(context, CGRectMake(currentXPonit, [self yMACDPointWithValue:[NSDecimalNumber zero]], _kLineWidth, [self yMACDPointWithValue:chartData.macd] - [self yMACDPointWithValue:[NSDecimalNumber zero]])); CGContextFillPath(context); } } currentXPonit += _kLineWidth + _kLinePadding; } //画DIF线 CGContextSetRGBStrokeColor(context, _macdDIFRed, _macdDIFGreen, _macdDIFBlue, _macdDIFAlpha); CGFloat currentXPoint = _kLineOrigin.x + 1.0f; BOOL isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.dif) { //前25条数据 } else if (chartData.dif && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yMACDPointWithValue:chartData.dif]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yMACDPointWithValue:chartData.dif]); CGContextMoveToPoint(context, currentXPoint, [self yMACDPointWithValue:chartData.dif]); } currentXPoint += _kLineWidth + _kLinePadding; } CGContextStrokePath(context); //画DEA线 CGContextSetRGBStrokeColor(context, _macdDEARed, _macdDEAGreen, _macdDEABlue, _macdDEAAlpha); currentXPoint = _kLineOrigin.x + 1.0f; isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.dea) { //前34条数据 } else if (chartData.dea && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yMACDPointWithValue:chartData.dea]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yMACDPointWithValue:chartData.dea]); CGContextMoveToPoint(context, currentXPoint, [self yMACDPointWithValue:chartData.dea]); } currentXPoint += _kLineWidth + _kLinePadding; } CGContextStrokePath(context); currentXPonit = _kLineOrigin.x + 1.0f; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; //是否需要显示十字线 if (_isShowTipLine) { if (_tipLineIndex == i) { //画垂直线 CGContextSetRGBStrokeColor(context, _tipRed, _tipGreen, _tipBlue, _tipAlpha); CGContextSetLineWidth(context, 1.0f); CGContextMoveToPoint(context, currentXPonit + _kLineWidth/2, [self yMACDPointWithValue:[self maxMACDValueAtVisible]]); CGContextAddLineToPoint(context, currentXPonit + _kLineWidth/2, [self yMACDPointWithValue:[self minMACDValueAtVisible]]); CGContextStrokePath(context); //写数据 NSMutableAttributedString *tipString = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"DIF:%@ ",[ChartCalculateUtils notRounding:chartData.dif afterPoint:2]] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_macdDIFRed green:_macdDIFGreen blue:_macdDIFBlue alpha:_macdDIFAlpha], NSFontAttributeName:_titleFont}]; NSAttributedString *stringTwo = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"DEA:%@ ",[ChartCalculateUtils notRounding:chartData.dea afterPoint:2]] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_macdDEARed green:_macdDEAGreen blue:_macdDEABlue alpha:_macdDEAAlpha], NSFontAttributeName:_titleFont}]; NSAttributedString *stringThree = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"MACD:%@",[ChartCalculateUtils notRounding:chartData.macd afterPoint:2]] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_macdDEARed green:_macdDEAGreen blue:_macdDEABlue alpha:_macdDEAAlpha], NSFontAttributeName:_titleFont}]; [tipString appendAttributedString:stringTwo]; [tipString appendAttributedString:stringThree]; [tipString drawAtPoint:CGPointMake(_kLineOrigin.x, [self yMACDPointWithValue:[self maxMACDValueAtVisible]] - 12.0f)]; break; } } currentXPonit += _kLineWidth + _kLinePadding; } } #pragma mark - VOL指标相关 /** * @brief 初始化VOL指标可视区数据 */ - (void)initVOLData { //获取KDJ可视区最大值与最小值 _indicatorVOLMaxValue = [[self maxVOLValueAtVisible] floatValue]; _indicatorVOLMiniValue = [[self miniVOLValueAtVisible] floatValue]; } /** * @brief 画VOL指标的方法 */ - (void)drawVOL { if (isnan([self yVOLPointWithValue:[NSDecimalNumber zero]])) { return; } CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(context, 1.0f); //画0线与标题 CGFloat priceXOffset = _xAxisPaddingLeft + _xAxisWidth; //价格左边距 CGFloat red = 1.0, green = 1.0, blue = 1.0, alpha = 1.0; [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; // 向red等设置值 CGContextSetRGBStrokeColor(context, red, green, blue, alpha); CGContextMoveToPoint(context, _indicatorOrigin.x, [self yVOLPointWithValue:[NSDecimalNumber zero]]); CGContextAddLineToPoint(context, _indicatorOrigin.x + _xAxisWidth,[self yVOLPointWithValue:[NSDecimalNumber zero]]); CGContextStrokePath(context); [_titleColor set]; //最大与最小值标题 NSString *maxString = [ChartCalculateUtils notRounding:[self maxVOLValueAtVisible] afterPoint:[ChartCalculateUtils getDecimalDigits:self.numMinUnit]]; [maxString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, _indicatorOrigin.y - _indicatorHight) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; NSString *minString = [ChartCalculateUtils notRounding:[self miniVOLValueAtVisible] afterPoint:[ChartCalculateUtils getDecimalDigits:self.numMinUnit]];//负数 [minString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, _indicatorOrigin.y - [minString sizeWithAttributes:@{NSFontAttributeName:_titleFont}].height) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; CGFloat currentXPonit = _indicatorOrigin.x; //画VOL柱 currentXPonit = _kLineOrigin.x + 1.0f; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (chartData.totleVolume) { if ([chartData.macd compare:[NSDecimalNumber zero]] == NSOrderedAscending) { //close < open CGContextSetRGBFillColor(context, _decKRed, _decKGreen, _decKBlue, _decKAlpha); CGContextAddRect(context, CGRectMake(currentXPonit, [self yVOLPointWithValue:[NSDecimalNumber zero]], _kLineWidth, [self yVOLPointWithValue:chartData.totleVolume] - [self yVOLPointWithValue:[self miniVOLValueAtVisible]])); CGContextFillPath(context); } else if ([chartData.macd compare:[NSDecimalNumber zero]] != NSOrderedAscending) { CGContextSetRGBFillColor(context, _aesKRed, _aesKGreen, _aesKBlue, _aesKAlpha); CGContextAddRect(context, CGRectMake(currentXPonit, [self yVOLPointWithValue:[NSDecimalNumber zero]], _kLineWidth, [self yVOLPointWithValue:chartData.totleVolume] - [self yVOLPointWithValue:[self miniVOLValueAtVisible]])); CGContextFillPath(context); } } currentXPonit += _kLineWidth + _kLinePadding; } //画vol5线 CGContextSetRGBStrokeColor(context, _macdDIFRed, _macdDIFGreen, _macdDIFBlue, _macdDIFAlpha); CGFloat currentXPoint = _kLineOrigin.x + 1.0f; BOOL isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.vol5) { //前5条数据 } else if (chartData.vol10 && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yVOLPointWithValue:chartData.vol5]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yVOLPointWithValue:chartData.vol5]); CGContextMoveToPoint(context, currentXPoint, [self yVOLPointWithValue:chartData.vol5]); } currentXPoint += _kLineWidth + _kLinePadding; } CGContextStrokePath(context); //画vol10线 CGContextSetRGBStrokeColor(context, _macdDEARed, _macdDEAGreen, _macdDEABlue, _macdDEAAlpha); currentXPoint = _kLineOrigin.x + 1.0f; isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.vol10) { //前10条数据 } else if (chartData.vol10 && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yVOLPointWithValue:chartData.vol10]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yVOLPointWithValue:chartData.vol10]); CGContextMoveToPoint(context, currentXPoint, [self yVOLPointWithValue:chartData.vol10]); } currentXPoint += _kLineWidth + _kLinePadding; } CGContextStrokePath(context); currentXPonit = _kLineOrigin.x + 1.0f; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; //是否需要显示十字线 if (_isShowTipLine) { if (_tipLineIndex == i) { //画垂直线 CGContextSetRGBStrokeColor(context, _tipRed, _tipGreen, _tipBlue, _tipAlpha); CGContextSetLineWidth(context, 1.0f); CGContextMoveToPoint(context, currentXPonit + _kLineWidth/2, [self yVOLPointWithValue:[self maxVOLValueAtVisible]]); CGContextAddLineToPoint(context, currentXPonit + _kLineWidth/2, [self yVOLPointWithValue:[self miniVOLValueAtVisible]]); CGContextStrokePath(context); //写数据 NSString *volume = [ChartCalculateUtils notRounding:chartData.totleVolume afterPoint:2]; NSMutableAttributedString *tipString = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"VOLUME:%@ ",volume ? volume : @"--"] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_aesKRed green:_aesKGreen blue:_aesKBlue alpha:_aesKAlpha], NSFontAttributeName:_titleFont}]; NSString *vol5 = [ChartCalculateUtils notRounding:chartData.vol5 afterPoint:2]; NSAttributedString *stringTwo = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"MA5:%@ ", vol5 ? vol5 : @"--"] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_macdDIFRed green:_macdDIFGreen blue:_macdDIFBlue alpha:_macdDIFAlpha], NSFontAttributeName:_titleFont}]; NSString *vol10 = [ChartCalculateUtils notRounding:chartData.vol10 afterPoint:2]; NSAttributedString *stringThree = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"MA10:%@", vol10 ? vol10 : @"--"] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_macdDEARed green:_macdDEAGreen blue:_macdDEABlue alpha:_macdDEAAlpha], NSFontAttributeName:_titleFont}]; [tipString appendAttributedString:stringTwo]; [tipString appendAttributedString:stringThree]; [tipString drawAtPoint:CGPointMake(_kLineOrigin.x, [self yVOLPointWithValue:[self maxVOLValueAtVisible]] - 12.0f)]; break; } } currentXPonit += _kLineWidth + _kLinePadding; } } #pragma mark - KDJ指标相关 /** * @brief 初始化KDJ指标可视区数据 */ - (void)initKDJData { //获取KDJ可视区最大值与最小值 _indicatorKDJMaxValue = [[self maxKDJValueAtVisible] floatValue]; _indicatorKDJMiniValue = [[self miniKDJValueAtVisible] floatValue]; } /** * @brief 画KDJ指标的方法 */ - (void)drawKDJ { if (isnan([self yKDJPointWithValue:[NSDecimalNumber zero]])) { return; } CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(context, 1.0f); //画0线与标题 CGFloat priceXOffset = _xAxisPaddingLeft + _xAxisWidth; //价格左边距 CGFloat red = 1.0, green = 1.0, blue = 1.0, alpha = 1.0; [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; // 向red等设置值 [_titleColor set]; //上下区间值 20、80 NSString *upString = [ChartCalculateUtils notRounding:[NSDecimalNumber decimalNumberWithString:@"80"] afterPoint:[ChartCalculateUtils getDecimalDigits:_minUnit]]; [upString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, [self yKDJPointWithValue:[NSDecimalNumber decimalNumberWithString:@"80"]]) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; NSString *downString = [ChartCalculateUtils notRounding:[NSDecimalNumber decimalNumberWithString:@"20"] afterPoint:[ChartCalculateUtils getDecimalDigits:_minUnit]]; [downString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, [self yKDJPointWithValue:[NSDecimalNumber decimalNumberWithString:@"20"]]) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; //RSI标题 CGFloat currentXPonit = _indicatorOrigin.x; //画80线 [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; // 向red等设置值 CGContextSetRGBStrokeColor(context, red, green, blue, alpha); CGContextMoveToPoint(context, _kLineOrigin.x, [self yKDJPointWithValue:[NSDecimalNumber decimalNumberWithString:@"80"]]); CGContextAddLineToPoint(context, _xAxisPaddingLeft + _xAxisWidth, [self yKDJPointWithValue:[NSDecimalNumber decimalNumberWithString:@"80"]]); CGContextStrokePath(context); //画20线 [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; // 向red等设置值 CGContextSetRGBStrokeColor(context, red, green, blue, alpha); CGContextMoveToPoint(context, _kLineOrigin.x, [self yKDJPointWithValue:[NSDecimalNumber decimalNumberWithString:@"20"]]); CGContextAddLineToPoint(context, _xAxisPaddingLeft + _xAxisWidth, [self yKDJPointWithValue:[NSDecimalNumber decimalNumberWithString:@"20"]]); CGContextStrokePath(context); //画kt线 CGContextSetRGBStrokeColor(context, _ktRed, _ktGreen, _ktBlue, _ktAlpha); CGFloat currentXPoint = _kLineOrigin.x + _kLineWidth/2 + 1.0f; BOOL isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.kt) { //前9根没有 } else if (chartData.kt && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yKDJPointWithValue:chartData.kt]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yKDJPointWithValue:chartData.kt]); CGContextMoveToPoint(context, currentXPoint, [self yKDJPointWithValue:chartData.kt]); } currentXPoint += _kLineWidth + _kLinePadding; } CGContextStrokePath(context); //画dt线 CGContextSetRGBStrokeColor(context, _dtRed, _dtGreen, _dtBlue, _dtAlpha); currentXPoint = _kLineOrigin.x + _kLineWidth/2 + 1.0f; isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.dt) { //前9根没有 } else if (chartData.dt && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yKDJPointWithValue:chartData.dt]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yKDJPointWithValue:chartData.dt]); CGContextMoveToPoint(context, currentXPoint, [self yKDJPointWithValue:chartData.dt]); } currentXPoint += _kLineWidth + _kLinePadding; } CGContextStrokePath(context); //画jt线 CGContextSetRGBStrokeColor(context, _jtRed, _jtGreen, _jtBlue, _jtAlpha); currentXPoint = _kLineOrigin.x + _kLineWidth/2 + 1.0f; isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.jt) { //前9根没有 } else if (chartData.jt && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yKDJPointWithValue:chartData.jt]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yKDJPointWithValue:chartData.jt]); CGContextMoveToPoint(context, currentXPoint, [self yKDJPointWithValue:chartData.jt]); } currentXPoint += _kLineWidth + _kLinePadding; } CGContextStrokePath(context); currentXPonit = _kLineOrigin.x + _kLineWidth/2 + 1.0f; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; //是否需要显示十字线 if (_isShowTipLine) { if (_tipLineIndex == i) { //画垂直线 CGContextSetRGBStrokeColor(context, _tipRed, _tipGreen, _tipBlue, _tipAlpha); CGContextSetLineWidth(context, 1.0f); CGContextMoveToPoint(context, currentXPonit, [self yKDJPointWithValue:[self maxKDJValueAtVisible]]); CGContextAddLineToPoint(context, currentXPonit, [self yKDJPointWithValue:[self miniKDJValueAtVisible]]); CGContextStrokePath(context); //写数据 NSMutableAttributedString *tipString = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"K:%@ ",[ChartCalculateUtils notRounding:chartData.kt afterPoint:2]] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_ktRed green:_ktGreen blue:_ktBlue alpha:_ktAlpha], NSFontAttributeName:_titleFont}]; NSAttributedString *stringTwo = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"D:%@ ",[ChartCalculateUtils notRounding:chartData.dt afterPoint:2]] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_dtRed green:_dtGreen blue:_dtBlue alpha:_dtBlue], NSFontAttributeName:_titleFont}]; NSAttributedString *stringThree = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"J:%@",[ChartCalculateUtils notRounding:chartData.jt afterPoint:2]] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_jtRed green:_jtGreen blue:_jtBlue alpha:_jtAlpha], NSFontAttributeName:_titleFont}]; [tipString appendAttributedString:stringTwo]; [tipString appendAttributedString:stringThree]; [tipString drawAtPoint:CGPointMake(_kLineOrigin.x, [self yKDJPointWithValue:[self maxKDJValueAtVisible]] - 12.0f)]; break; } } currentXPonit += _xAxisWidth/_kLineCount; } } #pragma mark - KD指标相关 /** * @brief 画KD指标的方法 */ - (void)drawKD { if (isnan([self yKDJPointWithValue:[NSDecimalNumber zero]])) return; CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(context, 1.0f); //画0线与标题 CGFloat priceXOffset = _xAxisPaddingLeft + _xAxisWidth; //价格左边距 CGFloat red = 1.0, green = 1.0, blue = 1.0, alpha = 1.0; [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; // 向red等设置值 [_titleColor set]; //上下区间值 20、80 NSString *upString = [ChartCalculateUtils notRounding:[NSDecimalNumber decimalNumberWithString:@"80"] afterPoint:[ChartCalculateUtils getDecimalDigits:_minUnit]]; [upString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, [self yKDJPointWithValue:[NSDecimalNumber decimalNumberWithString:@"80"]]) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; NSString *downString = [ChartCalculateUtils notRounding:[NSDecimalNumber decimalNumberWithString:@"20"] afterPoint:[ChartCalculateUtils getDecimalDigits:_minUnit]]; [downString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, [self yKDJPointWithValue:[NSDecimalNumber decimalNumberWithString:@"20"]]) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; //RSI标题 CGFloat currentXPonit = _indicatorOrigin.x; //画80线 [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; // 向red等设置值 CGContextSetRGBStrokeColor(context, red, green, blue, alpha); CGContextMoveToPoint(context, _kLineOrigin.x, [self yKDJPointWithValue:[NSDecimalNumber decimalNumberWithString:@"80"]]); CGContextAddLineToPoint(context, _xAxisPaddingLeft + _xAxisWidth, [self yKDJPointWithValue:[NSDecimalNumber decimalNumberWithString:@"80"]]); CGContextStrokePath(context); //画20线 [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; // 向red等设置值 CGContextSetRGBStrokeColor(context, red, green, blue, alpha); CGContextMoveToPoint(context, _kLineOrigin.x, [self yKDJPointWithValue:[NSDecimalNumber decimalNumberWithString:@"20"]]); CGContextAddLineToPoint(context, _xAxisPaddingLeft + _xAxisWidth, [self yKDJPointWithValue:[NSDecimalNumber decimalNumberWithString:@"20"]]); CGContextStrokePath(context); //画kt线 CGContextSetRGBStrokeColor(context, _ktRed, _ktGreen, _ktBlue, _ktAlpha); CGFloat currentXPoint = _kLineOrigin.x + _kLineWidth/2 + 1.0f; BOOL isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.kt) { //前9根没有 } else if (chartData.kt && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yKDJPointWithValue:chartData.kt]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yKDJPointWithValue:chartData.kt]); CGContextMoveToPoint(context, currentXPoint, [self yKDJPointWithValue:chartData.kt]); } currentXPoint += _kLineWidth + _kLinePadding; } CGContextStrokePath(context); //画dt线 CGContextSetRGBStrokeColor(context, _dtRed, _dtGreen, _dtBlue, _dtBlue); currentXPoint = _kLineOrigin.x + _kLineWidth/2 + 1.0f; isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.dt) { //前9根没有 } else if (chartData.dt && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yKDJPointWithValue:chartData.dt]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yKDJPointWithValue:chartData.dt]); CGContextMoveToPoint(context, currentXPoint, [self yKDJPointWithValue:chartData.dt]); } currentXPoint += _kLineWidth + _kLinePadding; } CGContextStrokePath(context); currentXPonit = _kLineOrigin.x + _kLineWidth/2 + 1.0f; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; //是否需要显示十字线 if (_isShowTipLine) { if (_tipLineIndex == i) { //画垂直线 CGContextSetRGBStrokeColor(context, _tipRed, _tipGreen, _tipBlue, _tipAlpha); CGContextSetLineWidth(context, 1.0f); CGContextMoveToPoint(context, currentXPonit, [self yKDJPointWithValue:[self maxKDJValueAtVisible]]); CGContextAddLineToPoint(context, currentXPonit, [self yKDJPointWithValue:[self miniKDJValueAtVisible]]); CGContextStrokePath(context); //写数据 NSMutableAttributedString *tipString = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"K:%@ ",[ChartCalculateUtils notRounding:chartData.kt afterPoint:2]] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_ktRed green:_ktGreen blue:_ktBlue alpha:_ktAlpha], NSFontAttributeName:_titleFont}]; NSAttributedString *stringTwo = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"D:%@",[ChartCalculateUtils notRounding:chartData.dt afterPoint:2]] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_dtRed green:_dtGreen blue:_dtBlue alpha:_dtBlue], NSFontAttributeName:_titleFont}]; [tipString appendAttributedString:stringTwo]; [tipString drawAtPoint:CGPointMake(_kLineOrigin.x, [self yKDJPointWithValue:[self maxKDJValueAtVisible]] - 12.0f)]; break; } } currentXPonit += _xAxisWidth/_kLineCount; } } #pragma mark - RSI指标相关 /** * @brief 初始化RSI指标可视区数据 */ - (void)initRSIData { //获取RSI可视区最大值与最小值 _indicatorRSIMaxValue = [[self maxRSIValueAtVisible] floatValue]; _indicatorRSIMiniValue = [[self miniRSIValueAtVisible] floatValue]; } /** * @brief 画RSI指标的方法 */ - (void)drawRSI { if (isnan([self yRSIPointWithValue:[NSDecimalNumber zero]])) return; CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(context, 1.0f); //画0线与标题 CGFloat priceXOffset = _xAxisPaddingLeft + _xAxisWidth; //价格左边距 CGFloat red = 1.0, green = 1.0, blue = 1.0, alpha = 1.0; [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; // 向red等设置值 CGContextSetRGBStrokeColor(context, red, green, blue, alpha); CGContextMoveToPoint(context, _indicatorOrigin.x, [self yRSIPointWithValue:[NSDecimalNumber zero]]); CGContextAddLineToPoint(context, _indicatorOrigin.x + _xAxisWidth,[self yRSIPointWithValue:[NSDecimalNumber zero]]); CGContextStrokePath(context); [_titleColor set]; //上下区间值 20、80 NSString *upString = [ChartCalculateUtils notRounding:[NSDecimalNumber decimalNumberWithString:@"80"] afterPoint:[ChartCalculateUtils getDecimalDigits:_minUnit]]; [upString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, [self yRSIPointWithValue:[NSDecimalNumber decimalNumberWithString:@"80"]]) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; NSString *downString = [ChartCalculateUtils notRounding:[NSDecimalNumber decimalNumberWithString:@"20"] afterPoint:[ChartCalculateUtils getDecimalDigits:_minUnit]]; [downString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, [self yRSIPointWithValue:[NSDecimalNumber decimalNumberWithString:@"20"]]) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; //RSI标题 CGFloat currentXPonit = _indicatorOrigin.x; //画80线 [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; // 向red等设置值 CGContextSetRGBStrokeColor(context, red, green, blue, alpha); CGContextMoveToPoint(context, _kLineOrigin.x, [self yRSIPointWithValue:[NSDecimalNumber decimalNumberWithString:@"80"]]); CGContextAddLineToPoint(context, _xAxisPaddingLeft + _xAxisWidth, [self yRSIPointWithValue:[NSDecimalNumber decimalNumberWithString:@"80"]]); CGContextStrokePath(context); //画20线 [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; // 向red等设置值 CGContextSetRGBStrokeColor(context, red, green, blue, alpha); CGContextMoveToPoint(context, _kLineOrigin.x, [self yRSIPointWithValue:[NSDecimalNumber decimalNumberWithString:@"20"]]); CGContextAddLineToPoint(context, _xAxisPaddingLeft + _xAxisWidth, [self yRSIPointWithValue:[NSDecimalNumber decimalNumberWithString:@"20"]]); CGContextStrokePath(context); //画RSI1线 CGContextSetRGBStrokeColor(context, 1.0f, 1.0f, 1.0f, 1.0f); CGFloat currentXPoint = _kLineOrigin.x + _kLineWidth/2 + 1.0f; BOOL isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.rsi1) { //前6根没有 } else if (chartData.rsi1 && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yRSIPointWithValue:chartData.rsi1]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yRSIPointWithValue:chartData.rsi1]); CGContextMoveToPoint(context, currentXPoint, [self yRSIPointWithValue:chartData.rsi1]); } currentXPoint += _kLineWidth + _kLinePadding; } CGContextStrokePath(context); //画RSI2线 CGContextSetRGBStrokeColor(context, 1.0f, 1.0f, 1.0f, 1.0f); currentXPoint = _kLineOrigin.x + _kLineWidth/2 + 1.0f; isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.rsi2) { //前12根没有 } else if (chartData.rsi2 && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yRSIPointWithValue:chartData.rsi2]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yRSIPointWithValue:chartData.rsi2]); CGContextMoveToPoint(context, currentXPoint, [self yRSIPointWithValue:chartData.rsi2]); } currentXPoint += _kLineWidth + _kLinePadding; } CGContextStrokePath(context); //画RSI3线 CGContextSetRGBStrokeColor(context, 1.0f, 1.0f, 1.0f, 1.0f); currentXPoint = _kLineOrigin.x + _kLineWidth/2 + 1.0f; isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.rsi3) { //前24根没有 } else if (chartData.rsi3 && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yRSIPointWithValue:chartData.rsi3]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yRSIPointWithValue:chartData.rsi3]); CGContextMoveToPoint(context, currentXPoint, [self yRSIPointWithValue:chartData.rsi3]); } currentXPoint += _kLineWidth + _kLinePadding; } CGContextStrokePath(context); currentXPonit = _kLineOrigin.x + _kLineWidth/2 + 1.0f; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; //是否需要显示十字线 if (_isShowTipLine) { if (_tipLineIndex == i) { //画垂直线 CGContextSetRGBStrokeColor(context, _tipRed, _tipGreen, _tipBlue, _tipAlpha); CGContextSetLineWidth(context, 1.0f); CGContextMoveToPoint(context, currentXPonit, [self yRSIPointWithValue:[self maxRSIValueAtVisible]]); CGContextAddLineToPoint(context, currentXPonit, [self yRSIPointWithValue:[self miniRSIValueAtVisible]]); CGContextStrokePath(context); //写数据 NSString *tipString = [NSString stringWithFormat:@"RSI1:%@ RSI2:%@ RSI3:%@" ,[ChartCalculateUtils notRounding:chartData.rsi1 afterPoint:2] ,[ChartCalculateUtils notRounding:chartData.rsi2 afterPoint:2] ,[ChartCalculateUtils notRounding:chartData.rsi3 afterPoint:2] ]; UIColor *profileColor = nil; if ([chartData.closed compare:chartData.opened] == NSOrderedDescending) profileColor = [UIColor redColor]; else if ([chartData.closed compare:chartData.opened] == NSOrderedAscending) profileColor = _priceGreenColor; else profileColor = _titleColor; [profileColor set]; [tipString drawAtPoint:CGPointMake(_kLineOrigin.x, [self yRSIPointWithValue:[self maxRSIValueAtVisible]] - 12.0f) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; break; } } currentXPonit += _xAxisWidth/_kLineCount; } } #pragma mark - CCI指标相关 /** * @brief 初始化CCI指标可视区数据 */ - (void)initCCIData { //获取RSI可视区最大值与最小值 _indicatorCCIMaxValue = [[self maxCCIValueAtVisible] floatValue]; _indicatorCCIMiniValue = [[self miniCCIValueAtVisible] floatValue]; } /** * @brief 画CCI指标的方法 */ - (void)drawCCI { if (isnan([self yCCIPointWithValue:[NSDecimalNumber zero]])) return; CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(context, 1.0f); //画0线与标题 CGFloat priceXOffset = _xAxisPaddingLeft + _xAxisWidth; //价格左边距 CGFloat red = 1.0, green = 1.0, blue = 1.0, alpha = 1.0; [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; // 向red等设置值 CGContextSetRGBStrokeColor(context, red, green, blue, alpha); CGContextMoveToPoint(context, _indicatorOrigin.x, [self yCCIPointWithValue:[NSDecimalNumber zero]]); CGContextAddLineToPoint(context, _indicatorOrigin.x + _xAxisWidth,[self yCCIPointWithValue:[NSDecimalNumber zero]]); CGContextStrokePath(context); [_titleColor set]; //上中下区间值 100、0、-100 NSString *upString = [ChartCalculateUtils notRounding:[NSDecimalNumber decimalNumberWithString:@"100"] afterPoint:[ChartCalculateUtils getDecimalDigits:_minUnit]]; [upString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, [self yCCIPointWithValue:[NSDecimalNumber decimalNumberWithString:@"100"]]) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; NSString *midString = [ChartCalculateUtils notRounding:[NSDecimalNumber decimalNumberWithString:@"0"] afterPoint:[ChartCalculateUtils getDecimalDigits:_minUnit]]; [midString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, [self yCCIPointWithValue:[NSDecimalNumber decimalNumberWithString:@"0"]]) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; NSString *downString = [ChartCalculateUtils notRounding:[NSDecimalNumber decimalNumberWithString:@"-100"] afterPoint:[ChartCalculateUtils getDecimalDigits:_minUnit]]; [downString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, [self yCCIPointWithValue:[NSDecimalNumber decimalNumberWithString:@"-100"]]) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; //CCI标题 CGFloat currentXPonit = _indicatorOrigin.x; //画0线 [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; // 向red等设置值 CGContextSetRGBStrokeColor(context, red, green, blue, alpha); CGContextMoveToPoint(context, _kLineOrigin.x, [self yCCIPointWithValue:[NSDecimalNumber decimalNumberWithString:@"0"]]); CGContextAddLineToPoint(context, _xAxisPaddingLeft + _xAxisWidth, [self yCCIPointWithValue:[NSDecimalNumber decimalNumberWithString:@"0"]]); CGContextStrokePath(context); //画100线 [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; // 向red等设置值 CGContextSetRGBStrokeColor(context, red, green, blue, alpha); CGContextMoveToPoint(context, _kLineOrigin.x, [self yCCIPointWithValue:[NSDecimalNumber decimalNumberWithString:@"100"]]); CGContextAddLineToPoint(context, _xAxisPaddingLeft + _xAxisWidth, [self yCCIPointWithValue:[NSDecimalNumber decimalNumberWithString:@"100"]]); CGContextStrokePath(context); //画-100线 [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; // 向red等设置值 CGContextSetRGBStrokeColor(context, red, green, blue, alpha); CGContextMoveToPoint(context, _kLineOrigin.x, [self yCCIPointWithValue:[NSDecimalNumber decimalNumberWithString:@"-100"]]); CGContextAddLineToPoint(context, _xAxisPaddingLeft + _xAxisWidth, [self yCCIPointWithValue:[NSDecimalNumber decimalNumberWithString:@"-100"]]); CGContextStrokePath(context); //画CCI线 CGContextSetRGBStrokeColor(context, _cciRed, _cciGreen, _cciBlue, _cciAlpha); CGFloat currentXPoint = _kLineOrigin.x + _kLineWidth/2 + 1.0f; BOOL isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.cci) { //前14根没有 } else if (chartData.cci && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yCCIPointWithValue:chartData.cci]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yCCIPointWithValue:chartData.cci]); CGContextMoveToPoint(context, currentXPoint, [self yCCIPointWithValue:chartData.cci]); } currentXPoint += _kLineWidth + _kLinePadding; } CGContextStrokePath(context); currentXPonit = _kLineOrigin.x + _kLineWidth/2 + 1.0f; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; //是否需要显示十字线 if (_isShowTipLine) { if (_tipLineIndex == i) { //画垂直线 CGContextSetRGBStrokeColor(context, _tipRed, _tipGreen, _tipBlue, _tipAlpha); CGContextSetLineWidth(context, 1.0f); CGContextMoveToPoint(context, currentXPonit, [self yCCIPointWithValue:[self maxCCIValueAtVisible]]); CGContextAddLineToPoint(context, currentXPonit, [self yCCIPointWithValue:[self miniCCIValueAtVisible]]); CGContextStrokePath(context); if (chartData.cci) { //写数据 NSMutableAttributedString *tipString = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"CCI:%@",[ChartCalculateUtils notRounding:chartData.cci afterPoint:2]] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_cciRed green:_cciGreen blue:_cciBlue alpha:_cciAlpha], NSFontAttributeName:_titleFont}]; [tipString drawAtPoint:CGPointMake(_kLineOrigin.x, [self yCCIPointWithValue:[self maxCCIValueAtVisible]] - 12.0f)]; } break; } } currentXPonit += _xAxisWidth/_kLineCount; } } #pragma mark - DMA指标相关 /** * @brief 初始化DMA指标可视区数据 */ - (void)initDMAData { //获取DMA可视区最大值与最小值 _indicatorDMAMaxValue = [[self maxDMAValueAtVisible] floatValue]; _indicatorDMAMiniValue = [[self miniDMAValueAtVisible] floatValue]; } /** * @brief 画DMA指标的方法 */ - (void)drawDMA { if (isnan([self yDMAPointWithValue:[NSDecimalNumber zero]])) return; CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(context, 1.0f); //画0线与标题 CGFloat priceXOffset = _xAxisPaddingLeft + _xAxisWidth; //价格左边距 CGFloat red = 1.0, green = 1.0, blue = 1.0, alpha = 1.0; [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; // 向red等设置值 CGContextSetRGBStrokeColor(context, red, green, blue, alpha); CGContextMoveToPoint(context, _indicatorOrigin.x, [self yDMAPointWithValue:[NSDecimalNumber zero]]); CGContextAddLineToPoint(context, _indicatorOrigin.x + _xAxisWidth,[self yDMAPointWithValue:[NSDecimalNumber zero]]); CGContextStrokePath(context); [_titleColor set]; NSDecimalNumber *maxValue = [self maxDMAValueAtVisible]; NSDecimalNumber *miniValue = [self miniDMAValueAtVisible]; NSDecimalNumber *midValue = [[miniValue decimalNumberByAdding:maxValue] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"2"]]; NSString *upString = [ChartCalculateUtils notRounding:maxValue afterPoint:[ChartCalculateUtils getDecimalDigits:_minUnit]]; [upString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, [self yDMAPointWithValue:maxValue]) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; NSString *midString = [ChartCalculateUtils notRounding:midValue afterPoint:[ChartCalculateUtils getDecimalDigits:_minUnit]]; [midString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, [self yDMAPointWithValue:midValue]) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; NSString *downString = [ChartCalculateUtils notRounding:miniValue afterPoint:[ChartCalculateUtils getDecimalDigits:_minUnit]]; [downString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, [self yDMAPointWithValue:miniValue] - 8.0f) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; CGFloat currentXPonit = _indicatorOrigin.x; //画1线 [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; // 向red等设置值 CGContextSetRGBStrokeColor(context, red, green, blue, alpha); CGContextMoveToPoint(context, _kLineOrigin.x, [self yDMAPointWithValue:maxValue]); CGContextAddLineToPoint(context, _xAxisPaddingLeft + _xAxisWidth, [self yDMAPointWithValue:maxValue]); CGContextStrokePath(context); //画-1线 [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; // 向red等设置值 CGContextSetRGBStrokeColor(context, red, green, blue, alpha); CGContextMoveToPoint(context, _kLineOrigin.x, [self yDMAPointWithValue:midValue]); CGContextAddLineToPoint(context, _xAxisPaddingLeft + _xAxisWidth, [self yDMAPointWithValue:midValue]); CGContextStrokePath(context); //画-2线 [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; // 向red等设置值 CGContextSetRGBStrokeColor(context, red, green, blue, alpha); CGContextMoveToPoint(context, _kLineOrigin.x, [self yDMAPointWithValue:miniValue]); CGContextAddLineToPoint(context, _xAxisPaddingLeft + _xAxisWidth, [self yDMAPointWithValue:miniValue]); CGContextStrokePath(context); //画DMA线 CGContextSetRGBStrokeColor(context, _dmaRed, _dmaGreen, _dmaBlue, _dmaAlpha); CGFloat currentXPoint = _kLineOrigin.x + _kLineWidth/2 + 1.0f; BOOL isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.dma) { //前10根没有 } else if (chartData.dma && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yDMAPointWithValue:chartData.dma]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yDMAPointWithValue:chartData.dma]); CGContextMoveToPoint(context, currentXPoint, [self yDMAPointWithValue:chartData.dma]); } currentXPoint += _kLineWidth + _kLinePadding; } CGContextStrokePath(context); //画AMA线 CGContextSetRGBStrokeColor(context, _amaRed, _amaGreen, _amaBlue, _amaAlpha); currentXPoint = _kLineOrigin.x + _kLineWidth/2 + 1.0f; isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.ama) { //前10根没有 } else if (chartData.ama && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yDMAPointWithValue:chartData.ama]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yDMAPointWithValue:chartData.ama]); CGContextMoveToPoint(context, currentXPoint, [self yDMAPointWithValue:chartData.ama]); } currentXPoint += _kLineWidth + _kLinePadding; } CGContextStrokePath(context); currentXPonit = _kLineOrigin.x + _kLineWidth/2 + 1.0f; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; //是否需要显示十字线 if (_isShowTipLine) { if (_tipLineIndex == i) { //画垂直线 CGContextSetRGBStrokeColor(context, _tipRed, _tipGreen, _tipBlue, _tipAlpha); CGContextSetLineWidth(context, 1.0f); CGContextMoveToPoint(context, currentXPonit, [self yDMAPointWithValue:[self maxDMAValueAtVisible]]); CGContextAddLineToPoint(context, currentXPonit, [self yDMAPointWithValue:[self miniDMAValueAtVisible]]); CGContextStrokePath(context); //写数据 NSMutableAttributedString *tipString = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"DIF:%@ ",[ChartCalculateUtils notRounding:chartData.dma afterPoint:2]] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_dmaRed green:_dmaGreen blue:_dmaBlue alpha:_dmaAlpha], NSFontAttributeName:_titleFont}]; NSAttributedString *stringTwo = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"AMA:%@",[ChartCalculateUtils notRounding:chartData.ama afterPoint:2]] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_amaRed green:_amaGreen blue:_amaBlue alpha:_amaAlpha], NSFontAttributeName:_titleFont}]; [tipString appendAttributedString:stringTwo]; [tipString drawAtPoint:CGPointMake(_kLineOrigin.x, [self yDMAPointWithValue:[self maxDMAValueAtVisible]] - 12.0f)]; break; } } currentXPonit += _xAxisWidth/_kLineCount; } } #pragma mark - BIAS指标相关 /** * @brief 初始化BIAS指标可视区数据 */ - (void)initBIASData { //获取BIAS可视区最大值与最小值 _indicatorBIASMaxValue = [[self maxBIASValueAtVisible] floatValue]; _indicatorBIASMiniValue = [[self miniBIASValueAtVisible] floatValue]; } /** * @brief 画DMA指标的方法 */ - (void)drawBIAS { if (isnan([self yBIASPointWithValue:[NSDecimalNumber zero]])) return; CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(context, 1.0f); //画0线与标题 CGFloat priceXOffset = _xAxisPaddingLeft + _xAxisWidth; //价格左边距 CGFloat red = 1.0, green = 1.0, blue = 1.0, alpha = 1.0; [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; // 向red等设置值 CGContextSetRGBStrokeColor(context, red, green, blue, alpha); CGContextMoveToPoint(context, _indicatorOrigin.x, [self yBIASPointWithValue:[NSDecimalNumber zero]]); CGContextAddLineToPoint(context, _indicatorOrigin.x + _xAxisWidth,[self yBIASPointWithValue:[NSDecimalNumber zero]]); CGContextStrokePath(context); [_titleColor set]; CGFloat currentXPonit = _indicatorOrigin.x; NSDecimalNumber *maxValue = [self maxBIASValueAtVisible]; NSDecimalNumber *miniValue = [self miniBIASValueAtVisible]; NSDecimalNumber *midValue = [[miniValue decimalNumberByAdding:maxValue] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"2"]]; NSString *upString = [ChartCalculateUtils notRounding:maxValue afterPoint:[ChartCalculateUtils getDecimalDigits:_minUnit]]; [upString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, [self yBIASPointWithValue:maxValue]) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; NSString *midString = [ChartCalculateUtils notRounding:midValue afterPoint:[ChartCalculateUtils getDecimalDigits:_minUnit]]; [midString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, [self yBIASPointWithValue:midValue]) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; //画1线 [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; // 向red等设置值 CGContextSetRGBStrokeColor(context, red, green, blue, alpha); CGContextMoveToPoint(context, _kLineOrigin.x, [self yBIASPointWithValue:maxValue]); CGContextAddLineToPoint(context, _xAxisPaddingLeft + _xAxisWidth, [self yBIASPointWithValue:maxValue]); CGContextStrokePath(context); //画-1线 [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; // 向red等设置值 CGContextSetRGBStrokeColor(context, red, green, blue, alpha); CGContextMoveToPoint(context, _kLineOrigin.x, [self yBIASPointWithValue:midValue]); CGContextAddLineToPoint(context, _xAxisPaddingLeft + _xAxisWidth, [self yBIASPointWithValue:midValue]); CGContextStrokePath(context); //画BIAS1线 CGContextSetRGBStrokeColor(context, _bias1Red, _bias1Green, _bias1Blue, _bias1Alpha); CGFloat currentXPoint = _kLineOrigin.x + _kLineWidth/2 + 1.0f; BOOL isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.bias1) { //前6根没有 } else if (chartData.bias1 && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yBIASPointWithValue:chartData.bias1]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yBIASPointWithValue:chartData.bias1]); CGContextMoveToPoint(context, currentXPoint, [self yBIASPointWithValue:chartData.bias1]); } currentXPoint += _kLineWidth + _kLinePadding; } CGContextStrokePath(context); //画BIAS2线 CGContextSetRGBStrokeColor(context, _bias2Red, _bias2Green, _bias2Blue, _bias2Alpha); currentXPoint = _kLineOrigin.x + _kLineWidth/2 + 1.0f; isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.bias2) { //前12根没有 } else if (chartData.bias2 && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yBIASPointWithValue:chartData.bias2]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yBIASPointWithValue:chartData.bias2]); CGContextMoveToPoint(context, currentXPoint, [self yBIASPointWithValue:chartData.bias2]); } currentXPoint += _kLineWidth + _kLinePadding; } CGContextStrokePath(context); //画BIAS3线 CGContextSetRGBStrokeColor(context, _bias3Red, _bias3Green, _bias3Blue, _bias3Alpha); currentXPoint = _kLineOrigin.x + _kLineWidth/2 + 1.0f; isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.bias3) { //前24根没有 } else if (chartData.bias3 && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yBIASPointWithValue:chartData.bias3]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yBIASPointWithValue:chartData.bias3]); CGContextMoveToPoint(context, currentXPoint, [self yBIASPointWithValue:chartData.bias3]); } currentXPoint += _kLineWidth + _kLinePadding; } CGContextStrokePath(context); currentXPonit = _kLineOrigin.x + _kLineWidth/2 + 1.0f; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; //是否需要显示十字线 if (_isShowTipLine) { if (_tipLineIndex == i) { //画垂直线 CGContextSetRGBStrokeColor(context, _tipRed, _tipGreen, _tipBlue, _tipAlpha); CGContextSetLineWidth(context, 1.0f); CGContextMoveToPoint(context, currentXPonit, [self yBIASPointWithValue:[self maxBIASValueAtVisible]]); CGContextAddLineToPoint(context, currentXPonit, [self yBIASPointWithValue:[self miniBIASValueAtVisible]]); CGContextStrokePath(context); //写数据 NSMutableAttributedString *tipString = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"BIAS1:%@ ",[ChartCalculateUtils notRounding:chartData.bias1 afterPoint:2]] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_bias1Red green:_bias1Green blue:_bias1Blue alpha:_bias1Alpha], NSFontAttributeName:_titleFont}]; NSAttributedString *stringTwo = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"BIAS2:%@ ",[ChartCalculateUtils notRounding:chartData.bias2 afterPoint:2]] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_bias2Red green:_bias2Green blue:_bias2Blue alpha:_bias2Alpha], NSFontAttributeName:_titleFont}]; NSAttributedString *stringThree = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"BIAS2:%@",[ChartCalculateUtils notRounding:chartData.bias3 afterPoint:2]] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_bias3Red green:_bias3Green blue:_bias3Blue alpha:_bias3Alpha], NSFontAttributeName:_titleFont}]; [tipString appendAttributedString:stringTwo]; [tipString appendAttributedString:stringThree]; [tipString drawAtPoint:CGPointMake(_kLineOrigin.x, [self yBIASPointWithValue:[self maxBIASValueAtVisible]] - 12.0f)]; break; } } currentXPonit += _xAxisWidth/_kLineCount; } } #pragma mark - PSY指标相关 /** * @brief 初始化PSY指标可视区数据 */ - (void)initPSYData { //获取BIAS可视区最大值与最小值 _indicatorPSYMaxValue = [[self maxPSYValueAtVisible] floatValue]; _indicatorPSYMiniValue = [[self miniPSYValueAtVisible] floatValue]; } /** * @brief 画PSY指标的方法 */ - (void)drawPSY { if (isnan([self yPSYPointWithValue:[NSDecimalNumber zero]])) return; CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(context, 1.0f); //画0线与标题 CGFloat priceXOffset = _xAxisPaddingLeft + _xAxisWidth; //价格左边距 CGFloat red = 1.0, green = 1.0, blue = 1.0, alpha = 1.0; [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; // 向red等设置值 CGContextSetRGBStrokeColor(context, red, green, blue, alpha); CGContextMoveToPoint(context, _indicatorOrigin.x, [self yPSYPointWithValue:[NSDecimalNumber zero]]); CGContextAddLineToPoint(context, _indicatorOrigin.x + _xAxisWidth,[self yPSYPointWithValue:[NSDecimalNumber zero]]); CGContextStrokePath(context); [_titleColor set]; CGFloat currentXPonit = _indicatorOrigin.x; NSString *upString = [ChartCalculateUtils notRounding:[NSDecimalNumber decimalNumberWithString:@"50"] afterPoint:[ChartCalculateUtils getDecimalDigits:_minUnit]]; [upString drawAtPoint:CGPointMake(priceXOffset + _excessXAxisWidth, [self yPSYPointWithValue:[NSDecimalNumber decimalNumberWithString:@"50"]]) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; //画50线 [_lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; // 向red等设置值 CGContextSetRGBStrokeColor(context, red, green, blue, alpha); CGContextMoveToPoint(context, _kLineOrigin.x, [self yPSYPointWithValue:[NSDecimalNumber decimalNumberWithString:@"50"]]); CGContextAddLineToPoint(context, _xAxisPaddingLeft + _xAxisWidth, [self yPSYPointWithValue:[NSDecimalNumber decimalNumberWithString:@"50"]]); CGContextStrokePath(context); //画PSY线 CGContextSetRGBStrokeColor(context, _psyRed, _psyGreen, _psyBlue, _psyAlpha); CGFloat currentXPoint = _kLineOrigin.x + _kLineWidth/2 + 1.0f; BOOL isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.psy) { //前12根没有 } else if (chartData.psy && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yPSYPointWithValue:chartData.psy]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yPSYPointWithValue:chartData.psy]); CGContextMoveToPoint(context, currentXPoint, [self yPSYPointWithValue:chartData.psy]); } currentXPoint += _kLineWidth + _kLinePadding; } CGContextStrokePath(context); //画PSYMA线 CGContextSetRGBStrokeColor(context, _psymaRed, _psymaGreen, _psymaBlue, _psymaAlpha); currentXPoint = _kLineOrigin.x + _kLineWidth/2 + 1.0f; isInit = NO; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (!chartData.psyma) { //前6根没有 } else if (chartData.psyma && !isInit) { CGContextMoveToPoint(context, currentXPoint, [self yPSYPointWithValue:chartData.psyma]); isInit = YES; } else { CGContextAddLineToPoint(context, currentXPoint, [self yPSYPointWithValue:chartData.psyma]); CGContextMoveToPoint(context, currentXPoint, [self yPSYPointWithValue:chartData.psyma]); } currentXPoint += _kLineWidth + _kLinePadding; } CGContextStrokePath(context); currentXPonit = _kLineOrigin.x + _kLineWidth/2 + 1.0f; for (NSInteger i=_kLineStartIndex ; i>=_kLineEndIndex ; i--) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; //是否需要显示十字线 if (_isShowTipLine) { if (_tipLineIndex == i) { //画垂直线 CGContextSetRGBStrokeColor(context, _tipRed, _tipGreen, _tipBlue, _tipAlpha); CGContextSetLineWidth(context, 1.0f); CGContextMoveToPoint(context, currentXPonit, [self yPSYPointWithValue:[self maxPSYValueAtVisible]]); CGContextAddLineToPoint(context, currentXPonit, [self yPSYPointWithValue:[self miniPSYValueAtVisible]]); CGContextStrokePath(context); //写数据 NSMutableAttributedString *tipString = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"PSY:%@ ",[ChartCalculateUtils notRounding:chartData.psy afterPoint:2]] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_psyRed green:_psyGreen blue:_psyBlue alpha:_psyAlpha], NSFontAttributeName:_titleFont}]; NSAttributedString *stringTwo = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"PSYMA:%@",[ChartCalculateUtils notRounding:chartData.psyma afterPoint:2]] attributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:_psymaRed green:_psymaGreen blue:_psymaBlue alpha:_psymaAlpha], NSFontAttributeName:_titleFont}]; [tipString appendAttributedString:stringTwo]; [tipString drawAtPoint:CGPointMake(_kLineOrigin.x, [self yPSYPointWithValue:[self maxPSYValueAtVisible]] - 12.0f)]; break; } } currentXPonit += _xAxisWidth/_kLineCount; } } #pragma mark - 画现价相关 /** * @brief 画现价的方法 */ - (void)drawPrice { if (!_isShowPrice) return; CGContextRef context = UIGraphicsGetCurrentContext(); //横轴价格 CGFloat priceXOffset = _xAxisPaddingLeft + _xAxisWidth; //价格左边距 NSInteger decimalNumber = [ChartCalculateUtils getDecimalDigits:_minUnit]; NSString *priceString = [ChartCalculateUtils notRounding:_price afterPoint:decimalNumber]; CGSize priceStringSize = [priceString sizeWithAttributes:@{NSFontAttributeName:_titleFont}]; //最大最小值判断 CGFloat priceYOffset = [self yPointWithPrice:_price]-priceStringSize.height/2; NSDecimalNumber *max = [self maxPriceAtVisible]; NSDecimalNumber *min = [self minPriceAtVisible]; // 这里有可能最大值和最小值相等 if ([max compare:min] == NSOrderedSame) { ChartData *chartData = _chartDataArray[0]; max = [chartData.closed decimalNumberByAdding:[_minUnit decimalNumberByMultiplyingBy:[[NSDecimalNumber alloc] initWithInt:20]]]; } if ([_price compare:max] == NSOrderedDescending) priceYOffset = _yAxisPaddingTop - priceStringSize.height; if ([_price compare:min] == NSOrderedAscending) priceYOffset = _kLineOrigin.y; if (priceYOffset != NAN) { CGContextSetRGBFillColor(context, 1.0f, 1.0f, 0.0f, 0.5f); CGContextAddRect(context, CGRectMake(priceXOffset, priceYOffset, priceXOffset +_xAxisPaddingRight, priceStringSize.height)); CGContextFillPath(context); [[UIColor blackColor] set]; [priceString drawAtPoint:CGPointMake(priceXOffset+_excessXAxisWidth, priceYOffset) withAttributes:@{NSFontAttributeName: _titleFont, NSForegroundColorAttributeName: _titleColor}]; CGFloat red = 1.0, green = 1.0, blue = 1.0, alpha = 1.0; //画100线 [[UIColor grayColor] getRed:&red green:&green blue:&blue alpha:&alpha]; // 向red等设置值 CGContextSetRGBStrokeColor(context, red, green, blue, alpha); CGContextMoveToPoint(context, _kLineOrigin.x, [self yPointWithPrice:_price]); CGContextAddLineToPoint(context, _xAxisPaddingLeft + _xAxisWidth, [self yPointWithPrice:_price]); CGFloat arr[] = {3, 1}; //下面最后一个参数“2”代表排列的个数。 CGContextSetLineDash(context, 0, arr, 2); //画线 CGContextDrawPath(context, kCGPathStroke); } } #pragma mark - K线数值计算相关 /** * @brief 获取当前可视区K线最大价格值的方法 * * @return 当前可视区K线最大价格值 */ - (nullable NSDecimalNumber *)maxPriceAtVisible { if (_chartDataArray == nil || _chartDataArray.count == 0) { return [NSDecimalNumber zero]; } NSDecimalNumber *maxValue = [NSDecimalNumber zero]; for (NSInteger i=_kLineEndIndex ; i<=_kLineStartIndex ; i++) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if ([chartData.opened compare:maxValue] == NSOrderedDescending) maxValue = chartData.opened; if ([chartData.closed compare:maxValue] == NSOrderedDescending) maxValue = chartData.closed; if ([chartData.highest compare:maxValue] == NSOrderedDescending) maxValue = chartData.highest; if (chartData.ma5) { if ([chartData.ma5 compare:maxValue] == NSOrderedDescending) maxValue = chartData.ma5; } if (chartData.ma10) { if ([chartData.ma10 compare:maxValue] == NSOrderedDescending) maxValue = chartData.ma10; } if (chartData.ma15) { if ([chartData.ma15 compare:maxValue] == NSOrderedDescending) maxValue = chartData.ma15; } } return maxValue ? maxValue : [NSDecimalNumber zero]; } /** * @brief 获取当前可视区K线最小价格值的方法 * * @return 当前可视区K线最小价格值 */ - (nullable NSDecimalNumber *)minPriceAtVisible { if (_chartDataArray == nil || _chartDataArray.count == 0) { return [NSDecimalNumber zero]; } NSDecimalNumber *minValue = [NSDecimalNumber maximumDecimalNumber]; for (NSInteger i=_kLineEndIndex ; i<=_kLineStartIndex ; i++) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if ([chartData.opened compare:minValue] == NSOrderedAscending) minValue = chartData.opened; if ([chartData.closed compare:minValue] == NSOrderedAscending) minValue = chartData.closed; if ([chartData.lowest compare:minValue] == NSOrderedAscending) minValue = chartData.lowest; if (chartData.ma5) { if ([chartData.ma5 compare:minValue] == NSOrderedAscending) minValue = chartData.ma5; } if (chartData.ma10) { if ([chartData.ma10 compare:minValue] == NSOrderedAscending) minValue = chartData.ma10; } if (chartData.ma15) { if ([chartData.ma15 compare:minValue] == NSOrderedAscending) minValue = chartData.ma15; } } return minValue ? minValue : [NSDecimalNumber zero]; } /** * @brief 获取指定价格的K线Y轴坐标 * * @param price 目标价格 * * @return 指定价格的K线Y轴坐标 */ - (CGFloat)yPointWithPrice:(nullable NSDecimalNumber *)price { CGFloat yPoint = _yAxisHeight - (_yAxisHeight/(_yAxisMaxValue - _yAxisMinValue)) * ([price floatValue] - _yAxisMinValue) + _yAxisPaddingTop; return yPoint ; } /** * @brief 获取指定Y轴坐标的价格 * * @param yPoint 目标Y轴坐标 * * @return 指定Y轴坐标的价格 */ - (nullable NSDecimalNumber *)priceWithYPoint:(CGFloat)yPoint { float priceValue = _yAxisMinValue + (_yAxisHeight + _yAxisPaddingTop - yPoint)/(_yAxisHeight/(_yAxisMaxValue - _yAxisMinValue)); return [NSDecimalNumber decimalNumberWithString:[NSString stringWithFormat:@"%f",priceValue]]; } #pragma mark - 整体指标相关 /** * @brief 设置是否需要显示指标 * * @param isShowIndicator 是否需要显示指标 */ - (void)setIsShowIndicator:(BOOL)isShowIndicator { _isShowIndicator = isShowIndicator; if (!_isShowIndicator) { _indicatorHight = 0; _indicatorPaddingBottom = 0; } } /// 是否显示开高低收 /// @param isShowOHLP isShowOHLP - (void)setIsShowOHLP:(BOOL)isShowOHLP { _isShowOHLP = isShowOHLP; } #pragma mark - MACD数值计算相关 /** * @brief 获取当前可视区MACD线最大值的方法 * * @return 当前可视区MACD线最大值 */ - (nullable NSDecimalNumber *)maxMACDValueAtVisible { if (_chartDataArray == nil || _chartDataArray.count == 0) { return [NSDecimalNumber zero]; } NSDecimalNumber *maxValue = [NSDecimalNumber zero]; for (NSInteger i=_kLineEndIndex ; i<=_kLineStartIndex ; i++) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (chartData.dif) { if ([chartData.dif compare:maxValue] == NSOrderedDescending) maxValue = chartData.dif; } if (chartData.dea) { if ([chartData.dea compare:maxValue] == NSOrderedDescending) maxValue = chartData.dea; } if (chartData.macd) { if ([chartData.macd compare:maxValue] == NSOrderedDescending) maxValue = chartData.macd; } } return maxValue; } /** * @brief 获取当前可视区MACD线最小值的方法 * * @return 当前可视区MACD线最小值 */ - (nullable NSDecimalNumber *)minMACDValueAtVisible { if (_chartDataArray == nil || _chartDataArray.count == 0) { return [NSDecimalNumber zero]; } NSDecimalNumber *minValue = [NSDecimalNumber zero]; for (NSInteger i=_kLineEndIndex ; i<=_kLineStartIndex ; i++) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (chartData.dif) { if ([chartData.dif compare:minValue] == NSOrderedAscending) minValue = chartData.dif; } if (chartData.dea) { if ([chartData.dea compare:minValue] == NSOrderedAscending) minValue = chartData.dea; } if (chartData.macd) { if ([chartData.macd compare:minValue] == NSOrderedAscending) minValue = chartData.macd; } } return minValue; } /** * @brief 获取指定值的MACD线Y轴坐标 * * @param value 目标价格 * * @return 指定值的MACD线Y轴坐标 */ - (CGFloat)yMACDPointWithValue:(nullable NSDecimalNumber *)value { CGFloat yPoitn = _indicatorHight - (_indicatorHight/(_indicatorMaxValue - _indicatorMinValue)) * ([value floatValue] - _indicatorMinValue) + _kLineOrigin.y + _yAxisPaddingBottom; return yPoitn; } #pragma mark - VOL数值计算相关 /** * @brief 获取当前可视区VOL线最大值的方法 * * @return 当前可视区VOL线最大值 */ - (nullable NSDecimalNumber *)maxVOLValueAtVisible { if (_chartDataArray == nil || _chartDataArray.count == 0) { return [NSDecimalNumber zero]; } NSDecimalNumber *maxValue = [NSDecimalNumber zero]; for (NSInteger i=_kLineEndIndex ; i<=_kLineStartIndex ; i++) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (chartData.totleVolume) { if ([chartData.totleVolume compare:maxValue] == NSOrderedDescending) maxValue = chartData.totleVolume; } } return maxValue; } /** * @brief 获取当前可视区VOL线最大值的方法 * * @return 当前可视区VOL线最大值 */ - (nullable NSDecimalNumber *)miniVOLValueAtVisible { if (_chartDataArray == nil || _chartDataArray.count == 0) { return [NSDecimalNumber zero]; } NSDecimalNumber *minValue = [NSDecimalNumber zero]; for (NSInteger i=_kLineEndIndex ; i<=_kLineStartIndex ; i++) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (chartData.totleVolume) { if ([chartData.totleVolume compare:minValue] != NSOrderedDescending) minValue = chartData.totleVolume; } } return minValue; } /** * @brief 获取指定值的VOL线Y轴坐标 * * @param value 目标价格 * * @return 指定值的VOL线Y轴坐标 */ - (CGFloat)yVOLPointWithValue:(nullable NSDecimalNumber *)value { CGFloat yPoitn = _indicatorHight - (_indicatorHight/(_indicatorVOLMaxValue - _indicatorVOLMiniValue)) * ([value floatValue] - _indicatorVOLMiniValue) + _kLineOrigin.y + _yAxisPaddingBottom; return yPoitn; } #pragma mark - KDJ数值计算相关 /** * @brief 获取当前可视区KDJ线最大值的方法 * * @return 当前可视区KDJ线最大值 */ - (nullable NSDecimalNumber *)maxKDJValueAtVisible { return [NSDecimalNumber decimalNumberWithString:@"130"]; } /** * @brief 获取当前可视区KDJ线最小值的方法 * * @return 当前可视区KDJ线最小值 */ - (nullable NSDecimalNumber *)miniKDJValueAtVisible { return [NSDecimalNumber decimalNumberWithString:@"-30"]; } /** * @brief 获取指定值的KDJ线Y轴坐标 * * @param value 目标价格 * * @return 指定值的KDJ线Y轴坐标 */ - (CGFloat)yKDJPointWithValue:(nullable NSDecimalNumber *)value { CGFloat yPoitn = _indicatorHight - (_indicatorHight/(_indicatorKDJMaxValue - _indicatorKDJMiniValue)) * ([value floatValue] - _indicatorKDJMiniValue) + _kLineOrigin.y + _yAxisPaddingBottom; return yPoitn; } #pragma mark - RSI数值计算相关 /** * @brief 获取当前可视区RSI线最大值的方法 * * @return 当前可视区RSI线最大值 */ - (nullable NSDecimalNumber *)maxRSIValueAtVisible { return [NSDecimalNumber decimalNumberWithString:@"100"]; } /** * @brief 获取当前可视区RSI线最小值的方法 * * @return 当前可视区RSI线最小值 */ - (nullable NSDecimalNumber *)miniRSIValueAtVisible { return [NSDecimalNumber decimalNumberWithString:@"0"]; } /** * @brief 获取指定值的RSI线Y轴坐标 * * @param value 目标价格 * * @return 指定值的RSI线Y轴坐标 */ - (CGFloat)yRSIPointWithValue:(NSDecimalNumber *)value { CGFloat yPoitn = _indicatorHight - (_indicatorHight/(_indicatorRSIMaxValue - _indicatorRSIMiniValue)) * ([value floatValue] - _indicatorRSIMiniValue) + _kLineOrigin.y + _yAxisPaddingBottom; return yPoitn; } #pragma mark - CCI数值计算相关 /** * @brief 获取当前可视区CCI线最大值的方法 * * @return 当前可视区CCI线最大值 */ - (nullable NSDecimalNumber *)maxCCIValueAtVisible { if (_chartDataArray == nil || _chartDataArray.count == 0) { return [NSDecimalNumber zero]; } NSDecimalNumber *maxValue = [NSDecimalNumber zero]; for (NSInteger i=_kLineEndIndex ; i<=_kLineStartIndex ; i++) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (chartData.cci) { if ([chartData.cci compare:maxValue] == NSOrderedDescending) maxValue = chartData.cci; } } return maxValue; } /** * @brief 获取当前可视区CCI线最小值的方法 * * @return 当前可视区CCI线最小值 */ - (nullable NSDecimalNumber *)miniCCIValueAtVisible { if (_chartDataArray == nil || _chartDataArray.count == 0) { return [NSDecimalNumber zero]; } NSDecimalNumber *minValue = [NSDecimalNumber zero]; for (NSInteger i=_kLineEndIndex ; i<=_kLineStartIndex ; i++) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (chartData.cci) { if ([chartData.cci compare:minValue] != NSOrderedDescending) minValue = chartData.cci; } } return minValue; } /** * @brief 获取指定值的CCI线Y轴坐标 * * @param value 目标价格 * * @return 指定值的CCI线Y轴坐标 */ - (CGFloat)yCCIPointWithValue:(nullable NSDecimalNumber *)value { CGFloat yPoitn = _indicatorHight - (_indicatorHight/(_indicatorCCIMaxValue - _indicatorCCIMiniValue)) * ([value floatValue] - _indicatorCCIMiniValue) + _kLineOrigin.y + _yAxisPaddingBottom; return yPoitn; } #pragma mark - DMA数值计算相关 /** * @brief 获取当前可视区DMA线最大值的方法 * * @return 当前可视区DMA线最大值 */ - (nullable NSDecimalNumber *)maxDMAValueAtVisible { if (_chartDataArray == nil || _chartDataArray.count == 0) { return [NSDecimalNumber zero]; } NSDecimalNumber *maxValue = [NSDecimalNumber zero]; for (NSInteger i=_kLineEndIndex ; i<=_kLineStartIndex ; i++) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (chartData.dma) { if ([chartData.dma compare:maxValue] == NSOrderedDescending) maxValue = chartData.dma; } if (chartData.ama) { if ([chartData.ama compare:maxValue] == NSOrderedDescending) maxValue = chartData.ama; } } return maxValue; } /** * @brief 获取当前可视区DMA线最小值的方法 * * @return 当前可视区DMA线最小值 */ - (nullable NSDecimalNumber *)miniDMAValueAtVisible { if (_chartDataArray == nil || _chartDataArray.count == 0) { return [NSDecimalNumber zero]; } NSDecimalNumber *minValue = [NSDecimalNumber zero]; for (NSInteger i=_kLineEndIndex ; i<=_kLineStartIndex ; i++) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (chartData.dma) { if ([chartData.dma compare:minValue] != NSOrderedDescending) minValue = chartData.dma; } if (chartData.ama) { if ([chartData.ama compare:minValue] != NSOrderedDescending) minValue = chartData.ama; } } return minValue; } /** * @brief 获取指定值的DMA线Y轴坐标 * * @param value 目标价格 * * @return 指定值的DMA线Y轴坐标 */ - (CGFloat)yDMAPointWithValue:(nullable NSDecimalNumber *)value { CGFloat yPoitn = _indicatorHight - (_indicatorHight/(_indicatorDMAMaxValue - _indicatorDMAMiniValue)) * ([value floatValue] - _indicatorDMAMiniValue) + _kLineOrigin.y + _yAxisPaddingBottom; return yPoitn; } #pragma mark - BIAS数值计算相关 /** * @brief 获取当前可视区BIAS线最大值的方法 * * @return 当前可视区BIAS线最大值 */ - (nullable NSDecimalNumber *)maxBIASValueAtVisible { if (_chartDataArray == nil || _chartDataArray.count == 0) { return [NSDecimalNumber zero]; } NSDecimalNumber *maxValue = [NSDecimalNumber zero]; for (NSInteger i=_kLineEndIndex ; i<=_kLineStartIndex ; i++) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (chartData.bias1) { if ([chartData.bias1 compare:maxValue] == NSOrderedDescending) maxValue = chartData.bias1; } if (chartData.bias2) { if ([chartData.bias2 compare:maxValue] == NSOrderedDescending) maxValue = chartData.bias2; } if (chartData.bias3) { if ([chartData.bias3 compare:maxValue] == NSOrderedDescending) maxValue = chartData.bias3; } } return maxValue; } /** * @brief 获取当前可视区BIAS线最小值的方法 * * @return 当前可视区BIAS线最小值 */ - (nullable NSDecimalNumber *)miniBIASValueAtVisible { if (_chartDataArray == nil || _chartDataArray.count == 0) { return [NSDecimalNumber zero]; } NSDecimalNumber *minValue = [NSDecimalNumber zero]; for (NSInteger i=_kLineEndIndex ; i<=_kLineStartIndex ; i++) { ChartData *chartData = [_chartDataArray objectAtIndex:i]; if (chartData.bias1) { if ([chartData.bias1 compare:minValue] != NSOrderedDescending) minValue = chartData.bias1; } if (chartData.bias2) { if ([chartData.bias2 compare:minValue] != NSOrderedDescending) minValue = chartData.bias2; } if (chartData.bias3) { if ([chartData.bias3 compare:minValue] != NSOrderedDescending) minValue = chartData.bias3; } } return minValue; } /** * @brief 获取指定值的BIAS线Y轴坐标 * * @param value 目标价格 * * @return 指定值的BIAS线Y轴坐标 */ - (CGFloat)yBIASPointWithValue:(nullable NSDecimalNumber *)value { CGFloat yPoitn = _indicatorHight - (_indicatorHight/(_indicatorBIASMaxValue - _indicatorBIASMiniValue)) * ([value floatValue] - _indicatorBIASMiniValue) + _kLineOrigin.y + _yAxisPaddingBottom; return yPoitn; } #pragma mark - PSY数值计算相关 /** * @brief 获取当前可视区PSY线最大值的方法 * * @return 当前可视区PSY线最大值 */ - (NSDecimalNumber *)maxPSYValueAtVisible { return [NSDecimalNumber decimalNumberWithString:@"100"]; } /** * @brief 获取当前可视区PSY线最小值的方法 * * @return 当前可视区PSY线最小值 */ - (NSDecimalNumber *)miniPSYValueAtVisible { return [NSDecimalNumber decimalNumberWithString:@"0"]; } /** * @brief 获取指定值的PSY线Y轴坐标 * * @param value 目标价格 * * @return 指定值的PSY线Y轴坐标 */ - (CGFloat)yPSYPointWithValue:(nullable NSDecimalNumber *)value { CGFloat yPoitn = _indicatorHight - (_indicatorHight/(_indicatorPSYMaxValue - _indicatorPSYMiniValue)) * ([value floatValue] - _indicatorPSYMiniValue) + _kLineOrigin.y + _yAxisPaddingBottom; return yPoitn; } #pragma mark - 分时图计算相关 /** * @brief 获取两个时间之间的分钟数 * * @param fromDate 开始时间 * @param toDate 结束时间 * * @return 分钟数 */ - (NSInteger)diffMinuteWithFromDate:(NSDate *)fromDate toDate:(NSDate *)toDate { NSCalendar* chineseClendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; NSUInteger unitFlags = NSCalendarUnitMinute; NSDateComponents *cps = [chineseClendar components:unitFlags fromDate:fromDate toDate:toDate options:0]; return [cps minute]/(_cycleInterval/60); /// 使用5分钟线需要除以5得到多余区间 } #pragma mark - 手势交互 /** * @brief 初始化和图标进行交互的相关手势 */ - (void)initGestureRecognizer { /// 拖动手势 UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(onPanGesture:)]; panGestureRecognizer.minimumNumberOfTouches = 1; panGestureRecognizer.maximumNumberOfTouches = 1; [self addGestureRecognizer:panGestureRecognizer]; /// 捏合手势 UIPinchGestureRecognizer *pinchGestureRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(onPinchGesture:)]; [self addGestureRecognizer:pinchGestureRecognizer]; /// 长按手势 UILongPressGestureRecognizer *longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(onLongPressGesture:)]; longPressGestureRecognizer.delegate = self; [self addGestureRecognizer:longPressGestureRecognizer]; } /** * @brief 移动手势进行移动时执行的方法 */ - (void)onPanGesture:(id)sender { UIPanGestureRecognizer *panGestureRecognizer = (UIPanGestureRecognizer *)sender; if (panGestureRecognizer.state == UIGestureRecognizerStateBegan) {/// 拖动手势手势开始 CGPoint point = [panGestureRecognizer locationInView:self]; _startTouchPosition = point; } else if (panGestureRecognizer.state == UIGestureRecognizerStateChanged){/// 拖动手势进行移动 if (!_isShowTipLine) { /// 移动K线 /// 如果当前是分时图则什么都不做 if (_chartViewType == ChartViewTypeTSPlan && !self.isBBGoods) return; /// Warnning:这里取translationInView可能有问题 CGPoint point = [panGestureRecognizer locationInView:self]; if (_startTouchPosition.x < point.x) { /// 向右滑 if (_kLineStartIndex == _chartDataArray.count-1) return; _startTouchPosition.x = point.x; if (_kLineStartIndex+_panGestureIncrement <= _chartDataArray.count-1) { _kLineStartIndex += _panGestureIncrement; _kLineEndIndex += _panGestureIncrement; } else { /// 到达最前面 NSInteger t = _chartDataArray.count-1 - _kLineStartIndex; _kLineStartIndex += t; _kLineEndIndex += t; /// 说明当前已经到达第一个图表数据 if (t <= 1) { if (_chartDataArray.count != 0) { /// 触发该方法 告诉上层当前已经拖动到第一个数据 if (self.delegate) [self.delegate onPanChartDataToTop]; } } } [self setNeedsDisplay]; } else if (_startTouchPosition.x > point.x) { /// 向左滑 if (_kLineEndIndex == 0) return; _startTouchPosition.x = point.x; if (_kLineEndIndex-_panGestureIncrement >= 0) { _kLineStartIndex -= _panGestureIncrement; _kLineEndIndex -= _panGestureIncrement; } else { /// 到达最后面 NSInteger t = _kLineEndIndex; _kLineStartIndex -= t; _kLineEndIndex -= t; } [self setNeedsDisplay]; } } else { /// 移动十字线 CGPoint point = [panGestureRecognizer locationInView:self]; /// 判断是否在图表区域内 if (CGRectContainsPoint(CGRectMake(_kLineOrigin.x, _yAxisPaddingTop, _xAxisWidth, _yAxisHeight), point)) { //判断是否能获取点击位置上的K线 NSInteger tipIndex = NSNotFound; if (_chartViewType != ChartViewTypeTSPlan) tipIndex = [self tipIndexWithXPoint:point.x]; else tipIndex = [self tipIndexTSPlanWithXPoint:point.x]; //分时图 if (tipIndex != NSNotFound) { _tipLineIndex = tipIndex; _tipLineYAxis = point.y; [self setNeedsDisplay]; } } } } } /** * @brief 捏合手势进行捏合时执行的方法 */ - (void)onPinchGesture:(id)sender { //如果当前是分时图则什么都不做 if (_chartViewType == ChartViewTypeTSPlan) return; UIPinchGestureRecognizer *pinchGestureRecognizer = (UIPinchGestureRecognizer *)sender; //捏合手势开始 if (pinchGestureRecognizer.state == UIGestureRecognizerStateBegan) { _startScale = pinchGestureRecognizer.scale; } else if (pinchGestureRecognizer.state == UIGestureRecognizerStateChanged) {//捏合手势进行捏合 if (pinchGestureRecognizer.scale - _startScale > 0.05f) { _startScale = pinchGestureRecognizer.scale; //放大到最大 if (_kLineWidth >= _kLineMaxWidth) return; _kLineWidth++; NSInteger lastKLineCount = _kLineCount; // _kLineCount = (_xAxisWidth / (_kLineWidth + _kLinePadding)) - _ts_remove_count; _kLineCount = (_xAxisWidth / (_kLineWidth + _kLinePadding)); if (_kLineCount < 0) _kLineCount = 0; //判断当前最大显示数量是否已经小于原先最大显示数量(这一层好像是多余了,应该都是小于的) if (_kLineCount < lastKLineCount) { //判断原先已经显示的数量是否已经大于现在最大数量 if (_kLineStartIndex-_kLineEndIndex+1 > _kLineCount) { //是的话就要减少显示数量了 if (_kLineStartIndex == _chartDataArray.count-1) { //动后面 _kLineEndIndex += (_kLineStartIndex-_kLineEndIndex+1-_kLineCount); } else { //动前面 _kLineStartIndex -= (_kLineStartIndex-_kLineEndIndex+1-_kLineCount); } } } [self setNeedsDisplay]; } else if (_startScale - pinchGestureRecognizer.scale > 0.05f) { _startScale = pinchGestureRecognizer.scale; //缩小 if (_kLineWidth <= _kLineMinWidth) return; _kLineWidth--; NSInteger lastKLineCount = _kLineCount; // _kLineCount = (_xAxisWidth / (_kLineWidth + _kLinePadding)) - _ts_remove_count; _kLineCount = (_xAxisWidth / (_kLineWidth + _kLinePadding)); if (_kLineCount < 0) _kLineCount = 0; //判断当前最大显示数据是否已经大于原先最大显示数量 if (_kLineCount > lastKLineCount) { //判断原先已经显示的数量是否已经小于现在最大数量,同时还能增加显示数量 if ((_kLineStartIndex-_kLineEndIndex+1<_kLineCount) && (_kLineStartIndex-_kLineEndIndex+1<_chartDataArray.count)) { //是的话就要增加显示数量了 if (_kLineStartIndex == _chartDataArray.count-1) { //动后面 _kLineEndIndex -= (_kLineCount - (_kLineStartIndex-_kLineEndIndex+1)); if (_kLineEndIndex<0) _kLineEndIndex=0; } else { //动前面 _kLineStartIndex += (_kLineCount - (_kLineStartIndex-_kLineEndIndex+1)); if (_kLineStartIndex>_chartDataArray.count-1) _kLineStartIndex=_chartDataArray.count-1; } } } [self setNeedsDisplay]; } } } /** * @brief 长按手势进行长按时执行的方法 */ - (void)onLongPressGesture:(id)sender { UILongPressGestureRecognizer *longPressGestureRecognizer = (UILongPressGestureRecognizer *)sender; if (longPressGestureRecognizer.state == UIGestureRecognizerStateBegan) {//手势开始进行 CGPoint point = [longPressGestureRecognizer locationInView:self]; //判断是否在K线区域内 if (CGRectContainsPoint(CGRectMake(_kLineOrigin.x, _yAxisPaddingTop, _xAxisWidth, _yAxisHeight), point)) { //判断是否能获取点击位置上的K线 NSInteger tipIndex = NSNotFound; if (_chartViewType != ChartViewTypeTSPlan) { tipIndex = [self tipIndexWithXPoint:point.x]; } else { //分时 tipIndex = [self tipIndexTSPlanWithXPoint:point.x]; } if (tipIndex != NSNotFound) { //开始长按 _isShowTipLine = YES; _tipLineIndex = tipIndex; _tipLineYAxis = point.y; [self setNeedsDisplay]; } } } else if (longPressGestureRecognizer.state == UIGestureRecognizerStateEnded) { //长按松开 CGPoint point = [longPressGestureRecognizer locationInView:self]; _startTouchPosition = point; _isShowTipLine = NO; [self setNeedsDisplay]; } } #pragma mark - UIGestureRecognizerDelegate - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { if ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]) return YES; return NO; } - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { if ([gestureRecognizer isMemberOfClass:[UIPanGestureRecognizer class]]) { CGPoint translation = [(UIPanGestureRecognizer*)gestureRecognizer translationInView:self]; if (fabs(translation.y) > fabs(translation.x)) { //上下方向 return NO; } } return YES; } @end