|
|
|
|
# CHKLineChart
|
|
|
|
|
|
|
|
|
|
![s1.png](/screenshots/s1.png)
|
|
|
|
|
![s2.png](/screenshots/s2.png)![s3.png](/screenshots/s3.png)
|
|
|
|
|
![s4.png](/screenshots/s4.png)![s5.png](/screenshots/s5.png)
|
|
|
|
|
|
|
|
|
|
> 纯Swift4.0代码编写的K线图表组件,支持:MA,EMA,KDJ,MACD,RSI等技术指标显示。集成使用简单,二次开发扩展强大。
|
|
|
|
|
|
|
|
|
|
## Features
|
|
|
|
|
|
|
|
|
|
- 完美支持Swift4.0编译。
|
|
|
|
|
- 线图丰富,蜡烛图,时分图,柱状图,提供画线扩展模型。
|
|
|
|
|
- 目前支持MA,EMA,BOLL,SAR,KDJ,MACD,RSI等技术指标,提供指标算法扩展模型。
|
|
|
|
|
- 支持使用代码创建视图或使用xib/storyboard创建视图。
|
|
|
|
|
- 样式提供更多配置,满足更多商业定制。
|
|
|
|
|
- 底层采用CALayer+UIBezierPath绘制图表,大大提高性能。
|
|
|
|
|
|
|
|
|
|
## Requirements
|
|
|
|
|
|
|
|
|
|
- iOS 8+
|
|
|
|
|
- Xcode 8+
|
|
|
|
|
- Swift 4.0+
|
|
|
|
|
- iPhone/iPad
|
|
|
|
|
|
|
|
|
|
## Installation
|
|
|
|
|
|
|
|
|
|
### CocoaPods
|
|
|
|
|
|
|
|
|
|
[CocoaPods](http://cocoapods.org/) is a dependency manager for Cocoa projects.
|
|
|
|
|
|
|
|
|
|
You can install it with the following command:
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
$ gem install cocoapods
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
To integrate Log into your Xcode project using CocoaPods, specify it in your Podfile:
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
use_frameworks!
|
|
|
|
|
|
|
|
|
|
pod 'CHKLineChartKit'
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Manual
|
|
|
|
|
|
|
|
|
|
打开文件夹/CHKLineChart/Carthage/Build/iOS/,复制CHKLineChartKit.framework到你的项目文件夹中。在Project -> Target -> General -> Embedded Binaries,点+,导入CHKLineChartKit.framework。
|
|
|
|
|
|
|
|
|
|
## Example
|
|
|
|
|
|
|
|
|
|
详细例子,打开Example/Example.xcworkspace,参考ChartCustomViewController的例子。
|
|
|
|
|
|
|
|
|
|
应用代码片段:
|
|
|
|
|
|
|
|
|
|
```swift
|
|
|
|
|
|
|
|
|
|
import CHKLineChartKit
|
|
|
|
|
|
|
|
|
|
class ChartCustomViewController: UIViewController {
|
|
|
|
|
|
|
|
|
|
/// 数据源
|
|
|
|
|
var klineDatas = [KlineChartData]()
|
|
|
|
|
|
|
|
|
|
/// 图表
|
|
|
|
|
lazy var chartView: CHKLineChartView = {
|
|
|
|
|
let chartView = CHKLineChartView(frame: CGRect.zero)
|
|
|
|
|
chartView.style = .base //默认样式
|
|
|
|
|
chartView.delegate = self
|
|
|
|
|
return chartView
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
override func viewDidLoad() {
|
|
|
|
|
self.view.addSubview(self.chartView)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override func viewDidLayoutSubviews() {
|
|
|
|
|
self.chartView.frame = self.view.bounds
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: - 实现K线图表的委托方法
|
|
|
|
|
extension ChartCustomViewController: CHKLineChartDelegate {
|
|
|
|
|
|
|
|
|
|
/// 图表显示数据总数
|
|
|
|
|
func numberOfPointsInKLineChart(chart: CHKLineChartView) -> Int {
|
|
|
|
|
return self.klineDatas.count
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 提供图表数据源
|
|
|
|
|
func kLineChart(chart: CHKLineChartView, valueForPointAtIndex index: Int) -> CHChartItem {
|
|
|
|
|
let data = self.klineDatas[index]
|
|
|
|
|
let item = CHChartItem()
|
|
|
|
|
item.time = data.time
|
|
|
|
|
item.openPrice = CGFloat(data.openPrice)
|
|
|
|
|
item.highPrice = CGFloat(data.highPrice)
|
|
|
|
|
item.lowPrice = CGFloat(data.lowPrice)
|
|
|
|
|
item.closePrice = CGFloat(data.closePrice)
|
|
|
|
|
item.vol = CGFloat(data.vol)
|
|
|
|
|
return item
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 自定义Y轴坐标值显示内容
|
|
|
|
|
func kLineChart(chart: CHKLineChartView, labelOnYAxisForValue value: CGFloat, atIndex index: Int, section: CHSection) -> String {
|
|
|
|
|
var strValue = ""
|
|
|
|
|
if section.key == "volume" {
|
|
|
|
|
if value / 1000 > 1 {
|
|
|
|
|
strValue = (value / 1000).ch_toString(maxF: section.decimal) + "K"
|
|
|
|
|
} else {
|
|
|
|
|
strValue = value.ch_toString(maxF: section.decimal)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
strValue = value.ch_toString(maxF: section.decimal)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return strValue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 自定义X轴坐标值显示内容
|
|
|
|
|
func kLineChart(chart: CHKLineChartView, labelOnXAxisForIndex index: Int) -> String {
|
|
|
|
|
let data = self.klineDatas[index]
|
|
|
|
|
let timestamp = data.time
|
|
|
|
|
let dayText = Date.ch_getTimeByStamp(timestamp, format: "MM-dd")
|
|
|
|
|
let timeText = Date.ch_getTimeByStamp(timestamp, format: "HH:mm")
|
|
|
|
|
var text = ""
|
|
|
|
|
//跨日,显示日期
|
|
|
|
|
if dayText != self.chartXAxisPrevDay && index > 0 {
|
|
|
|
|
text = dayText
|
|
|
|
|
} else {
|
|
|
|
|
text = timeText
|
|
|
|
|
}
|
|
|
|
|
self.chartXAxisPrevDay = dayText
|
|
|
|
|
return text
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// 调整每个分区的小数位保留数
|
|
|
|
|
///
|
|
|
|
|
/// - parameter chart:
|
|
|
|
|
/// - parameter section:
|
|
|
|
|
///
|
|
|
|
|
/// - returns:
|
|
|
|
|
func kLineChart(chart: CHKLineChartView, decimalAt section: Int) -> Int {
|
|
|
|
|
return 2
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Custom Index(开发自定义指标)
|
|
|
|
|
|
|
|
|
|
本K线图表最大的一个亮点就是提供了非常容易的指标开发入口。
|
|
|
|
|
如何开发自己的指标呢?步骤如下:
|
|
|
|
|
|
|
|
|
|
**1. 开发者需要实现CHChartAlgorithmProtocol。例子参考CHChartAlgorithm枚举。**
|
|
|
|
|
|
|
|
|
|
```swift
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
常用技术指标算法
|
|
|
|
|
*/
|
|
|
|
|
public enum CHChartAlgorithm: CHChartAlgorithmProtocol {
|
|
|
|
|
|
|
|
|
|
case none //无算法
|
|
|
|
|
case timeline //时分
|
|
|
|
|
case ma(Int) //简单移动平均数
|
|
|
|
|
case ema(Int) //指数移动平均数
|
|
|
|
|
case kdj(Int, Int, Int) //随机指标
|
|
|
|
|
case macd(Int, Int, Int) //指数平滑异同平均线
|
|
|
|
|
case boll(Int, Int) //布林线
|
|
|
|
|
case sar(Int, CGFloat, CGFloat) //停损转向操作点指标(判定周期,加速因子初值,加速因子最大值)
|
|
|
|
|
case sam(Int) //SAM指标公式
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
处理算法
|
|
|
|
|
|
|
|
|
|
- parameter datas:
|
|
|
|
|
|
|
|
|
|
- returns:
|
|
|
|
|
*/
|
|
|
|
|
public func handleAlgorithm(_ datas: [CHChartItem]) -> [CHChartItem] {
|
|
|
|
|
switch self {
|
|
|
|
|
case .none:
|
|
|
|
|
return datas
|
|
|
|
|
case .timeline:
|
|
|
|
|
return self.handleTimeline(datas: datas)
|
|
|
|
|
case let .ma(num):
|
|
|
|
|
return self.handleMA(num, datas: datas)
|
|
|
|
|
case let .ema(num):
|
|
|
|
|
return self.handleEMA(num, datas: datas)
|
|
|
|
|
case let .kdj(p1, p2, p3):
|
|
|
|
|
return self.handleKDJ(p1, p2: p2, p3: p3, datas: datas)
|
|
|
|
|
case let .macd(p1, p2, p3):
|
|
|
|
|
return self.handleMACD(p1, p2: p2, p3: p3, datas: datas)
|
|
|
|
|
case let .boll(num, k):
|
|
|
|
|
return self.handleBOLL(num, k: k, datas: datas)
|
|
|
|
|
case let .sar(num, minAF, maxAF):
|
|
|
|
|
return self.handleSAR(num,minAF: minAF, maxAF: maxAF, datas: datas)
|
|
|
|
|
case let .sam(num):
|
|
|
|
|
return self.handleSAM(num, datas: datas)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
......
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**2. extension CHSeries,编写自己的线组。**
|
|
|
|
|
|
|
|
|
|
```swift
|
|
|
|
|
|
|
|
|
|
// MARK: - 工厂方法
|
|
|
|
|
extension CHSeries {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
返回一个MACD系列样式
|
|
|
|
|
*/
|
|
|
|
|
public class func getMACD(_ difc: UIColor,
|
|
|
|
|
deac: UIColor,
|
|
|
|
|
barc: UIColor,
|
|
|
|
|
upStyle: (color: UIColor, isSolid: Bool),
|
|
|
|
|
downStyle: (color: UIColor, isSolid: Bool),
|
|
|
|
|
section: CHSection) -> CHSeries {
|
|
|
|
|
let series = CHSeries()
|
|
|
|
|
series.key = CHSeriesKey.macd
|
|
|
|
|
let dif = CHChartModel.getLine(difc, title: "DIF", key: "\(CHSeriesKey.macd)_DIF")
|
|
|
|
|
dif.section = section
|
|
|
|
|
let dea = CHChartModel.getLine(deac, title: "DEA", key: "\(CHSeriesKey.macd)_DEA")
|
|
|
|
|
dea.section = section
|
|
|
|
|
let bar = CHChartModel.getBar(upStyle: upStyle, downStyle: downStyle, titleColor: barc, title: "MACD", key: "\(CHSeriesKey.macd)_BAR")
|
|
|
|
|
bar.section = section
|
|
|
|
|
series.chartModels = [bar, dif, dea]
|
|
|
|
|
return series
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**3. 如果现有的线模型无法满足你,你可以新建类继承CHChartModel,重载drawSerie方法。**
|
|
|
|
|
|
|
|
|
|
```swift
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 圆点样式模型
|
|
|
|
|
*/
|
|
|
|
|
open class CHRoundModel: CHChartModel {
|
|
|
|
|
|
|
|
|
|
open override func drawSerie(_ startIndex: Int, endIndex: Int) -> CAShapeLayer {
|
|
|
|
|
......
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: - 工厂方法
|
|
|
|
|
extension CHChartModel {
|
|
|
|
|
|
|
|
|
|
//生成一个圆点样式
|
|
|
|
|
class func getRound(upStyle: (color: UIColor, isSolid: Bool),
|
|
|
|
|
downStyle: (color: UIColor, isSolid: Bool),
|
|
|
|
|
titleColor: UIColor, title: String,
|
|
|
|
|
plotPaddingExt: CGFloat,
|
|
|
|
|
key: String) -> CHRoundModel {
|
|
|
|
|
let model = CHRoundModel(upStyle: upStyle, downStyle: downStyle,
|
|
|
|
|
titleColor: titleColor, plotPaddingExt: plotPaddingExt)
|
|
|
|
|
model.title = title
|
|
|
|
|
model.key = key
|
|
|
|
|
return model
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**4. 自定义自己的图表CHKLineChartStyle,把指标算法和线组加入。**
|
|
|
|
|
|
|
|
|
|
```swift
|
|
|
|
|
|
|
|
|
|
let style = CHKLineChartStyle()
|
|
|
|
|
......
|
|
|
|
|
|
|
|
|
|
//配置图表处理算法
|
|
|
|
|
style.algorithms = [
|
|
|
|
|
CHChartAlgorithm.ema(12), //计算MACD,必须先计算到同周期的EMA
|
|
|
|
|
CHChartAlgorithm.ema(26), //计算MACD,必须先计算到同周期的EMA
|
|
|
|
|
CHChartAlgorithm.macd(12, 26, 9),
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
let trendSection = CHSection()
|
|
|
|
|
let macdSeries = CHSeries.getMACD(
|
|
|
|
|
UIColor.ch_hex(0xDDDDDD),
|
|
|
|
|
deac: UIColor.ch_hex(0xF9EE30),
|
|
|
|
|
barc: UIColor.ch_hex(0xF600FF),
|
|
|
|
|
upStyle: upcolor, downStyle: downcolor,
|
|
|
|
|
section: trendSection)
|
|
|
|
|
macdSeries.title = "MACD(12,26,9)"
|
|
|
|
|
macdSeries.symmetrical = true
|
|
|
|
|
trendSection.series = [macdSeries]
|
|
|
|
|
|
|
|
|
|
style.sections = [priceSection, volumeSection, trendSection]
|
|
|
|
|
|
|
|
|
|
let chartView = CHKLineChartView(frame: CGRect.zero)
|
|
|
|
|
chartView.style = style
|
|
|
|
|
......
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**5. 运行程序调试你的指标是否计算对了。**
|
|
|
|
|
|
|
|
|
|
## Custom Style(开发自定义样式)
|
|
|
|
|
|
|
|
|
|
通用的方案是,扩展CHKLineChartStyle编写自己的样式。
|
|
|
|
|
|
|
|
|
|
```swift
|
|
|
|
|
|
|
|
|
|
// MARK: - 扩展样式
|
|
|
|
|
public extension CHKLineChartStyle {
|
|
|
|
|
|
|
|
|
|
//实现一个最基本的样式,开发者可以自由扩展配置样式
|
|
|
|
|
public static var best: CHKLineChartStyle {
|
|
|
|
|
let style = CHKLineChartStyle()
|
|
|
|
|
......
|
|
|
|
|
return style
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.chartView.style = .best
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Contribution(贡献更多指标)
|
|
|
|
|
|
|
|
|
|
本人现在很少专注K线图表的开发工作,大部分时间投入到区块链的研究与开发工作,如果你感兴趣,可以[联系我](#Author)。
|
|
|
|
|
|
|
|
|
|
如果你对本K线指标的开发感兴趣,请fork项目,给大家Pull requests更多技术指标。
|
|
|
|
|
|
|
|
|
|
## Donations
|
|
|
|
|
|
|
|
|
|
如果大家觉得非常好用的话,不忘打赏一下小弟,给小弟一些鼓励。
|
|
|
|
|
|
|
|
|
|
> 支付宝:
|
|
|
|
|
|
|
|
|
|
![支付宝](/screenshots/donations/alipay.jpeg)
|
|
|
|
|
|
|
|
|
|
> 微信支付:
|
|
|
|
|
|
|
|
|
|
![微信支付](/screenshots/donations/wepay.png)
|
|
|
|
|
|
|
|
|
|
> 接收以下数字货币:
|
|
|
|
|
|
|
|
|
|
- **BTC**: 16XyEUNgwF3KX6UyMEWtpQDWWXkmqgH7V8
|
|
|
|
|
- **ETH**: 0x4fffdaa5dbba850ae41aa6d031a6dffd91614608
|
|
|
|
|
- **LTC**: LLevkg1aUiECvY6Uda1bvDbqa38zykjLyR
|
|
|
|
|
|
|
|
|
|
## Author
|
|
|
|
|
<span id="Author"><span>
|
|
|
|
|
|
|
|
|
|
- Author: Chance
|
|
|
|
|
- Email: zhiquan911@qq.com
|
|
|
|
|
- QQ Group:522031421
|
|
|
|
|
|
|
|
|
|
## License
|
|
|
|
|
|
|
|
|
|
Released under [MIT License.](https://github.com/zhiquan911/CHKLineChart/blob/master/LICENSE)
|