Skip to content

zhwayne/SwiftKLine

Repository files navigation

SwiftKLine

一个轻量级、模块化且易于扩展的 K 线图表框架,专为 Swift 应用设计。

功能特点

核心架构

  • 模块化设计:数据加载、指标计算、渲染协调、交互和样式分层管理。
  • 高性能渲染:复用 renderer、缓存 legend、合并 redraw,并支持实时 tick 增量更新。
  • 扩展友好:可注册指标 renderer,支持自定义样式、主题和指标 key。
  • 协议驱动:通过 ChartItemProvider 接入历史分页、区间补数和实时流。
  • Swift 6 友好:数据提供者和 K 线数据模型要求 Sendable,加载流程使用 actor 隔离。

已实现功能

  • K 线蜡烛图绘制(阳线 / 阴线)
  • 手势交互(缩放、平移、十字线)
  • 实时数据订阅
  • 主指标:MA、EMA、WMA、BOLL、SAR
  • 副指标:MACD、RSI、VOL
  • 分时图模式
  • 自定义渲染器
  • 主题配置
  • 指标选择持久化
  • 更多高级指标(持续迭代中)

快速开始

安装

直接将 Sources/SwiftKLine 目录添加到工程,或在 Swift Package Manager 中引用本仓库。

目前项目处于早期阶段,后续版本可能包含破坏性更改,请谨慎使用。

基本使用

通过 ChartOptions 配置图表行为,ChartView 负责渲染;数据提供者通过 loadData(using:) 显式绑定或替换:

import UIKit
import SwiftKLine

let provider = BinanceDataProvider(symbol: "BTCUSDT", period: .m1)
let options = ChartOptions(
    appearance: .theme(.midnight),
    content: .candlestick,
    indicators: IndicatorSelectionState(
        mainIndicatorIDs: [.ma],
        subIndicatorIDs: [.vol, .macd]
    ),
    features: [.liveUpdates, .gapRecovery, .indicatorPersistence],
    plugins: .default
)
let chartView = ChartView(options: options)
chartView.loadData(using: provider)
view.addSubview(chartView)
  • ChartItemProvider 负责提供分页历史数据、按时间区间补数以及实时流。
  • 框架内置 ChartItemLoader,会在前后台切换时自动补齐缺失区间。
  • loadData(using:) 会重置当前数据、指标序列和分页状态,并启动新的 loader。
  • ChartOptions 负责图表装配;loadData(using:) 负责绑定或替换数据提供者。保留这两个步骤可以在周期切换、provider 替换和视图复用时保持行为明确。

切换主图样式

chartView.setContentStyle(.candlestick)
chartView.setContentStyle(.timeSeries)

ChartType 当前支持:

  • .candlestick:蜡烛图主图。
  • .timeSeries:分时图主图。

创建自定义数据源

实现 ChartItemProvider 即可接入任意行情源:

final class MyProvider: ChartItemProvider, @unchecked Sendable {
    func fetchChartItems(forPage page: Int) async throws -> [any ChartItem] { /* ... */ }
    func fetchChartItems(from start: Date, to end: Date) async throws -> [any ChartItem] { /* ... */ }
    func liveStream() -> AsyncStream<any ChartItem> { /* 可选 */ }
}

说明:

  • page == 0 表示最近一页,page 递增表示继续向更早历史分页。
  • fetchChartItems(from:to:) 用于前后台切换、网络恢复等场景的缺口补齐。
  • liveStream() 默认返回空流;只有需要实时行情时才需要实现。
  • Provider 必须是 AnyObject & Sendable。如果内部使用锁、actor 或不可变状态保证线程安全,可按需使用 @unchecked Sendable

K 线数据模型需实现 ChartItem

struct Candle: ChartItem {
    let open: Double
    let close: Double
    let high: Double
    let low: Double
    let volume: Double
    let value: Double
    let timestamp: Int // 秒级时间戳
}

指标选择持久化

ChartView 默认使用 UserDefaultsIndicatorSelectionStore 保存主/副图指标选择。可以注入自定义 store,或传入 nil 关闭持久化:

let view = ChartView(indicatorSelectionStore: nil)

监听指标变化:

chartView.indicatorSelectionChanged = { state in
    print(state.mainIndicators, state.subIndicators)
}

恢复默认指标:

chartView.resetIndicatorsToDefault()

配置与主题

使用内置主题

let dark = ChartConfiguration.themed(.midnight)
let light = ChartConfiguration.themed(.solaris)
let chartView = ChartView(configuration: dark)

自定义配置

let configuration = ChartConfiguration(
    candleStyle: CandleStyle(
        risingColor: .systemGreen,
        fallingColor: .systemRed,
        width: 8,
        gap: 2
    ),
    watermarkText: "SwiftKLine",
    layoutMetrics: LayoutMetrics(
        mainChartHeight: 320,
        timelineHeight: 16,
        indicatorHeight: 72,
        indicatorSelectorHeight: 34
    ),
    defaultMainIndicators: [.ma],
    defaultSubIndicators: [.vol, .macd]
)

扩展框架

扩展内置指标渲染

通过 PluginRegistryregisterRenderer(placement:provider:) 可为指定位置注册额外的渲染器。

let registry = PluginRegistry.default
registry.registerRenderer(placement: .overlay) { _, configuration in
    [MyOverlayRenderer()]
}
let options = ChartOptions(plugins: registry)

使用已存在的 IndicatorID 注册插件时,会替换当前 PluginRegistry 实例中的旧插件,并返回被替换的插件。不同 chart view 需要不同插件集合时,请使用独立的 registry 实例。

兼容旧 API

ChartOptions 是主要图表装配对象,ChartConfiguration 是视觉和内置指标展示配置对象。loadData(using:)setContentStyle(_:)resetIndicatorsToDefault() 等命令式 API 仍可用。

API 命名说明

  • ChartOptions 是主要图表装配对象。
  • ChartConfiguration 是视觉和内置指标展示配置对象。
  • 新代码优先使用 IndicatorSelectionState(mainIndicatorIDs:subIndicatorIDs:),不要优先使用 main/sub 标签。
  • ChartItem.timestamp 必须是 Unix 秒级时间戳;timestampSeconds 别名用于提高可读性。

自定义指标插件

通过 IndicatorPluginIndicatorCalculator 协议,可以在不修改内置 BuiltInIndicator 的前提下新增完整指标:

struct MyCalculator: IndicatorCalculator {
    let id = SeriesKey(indicatorID: "custom.myIndicator", name: "MY")

    func calculate(for items: [any ChartItem]) -> [Double?] {
        items.map { Optional($0.close) }
    }
}

struct MyPlugin: IndicatorPlugin {
    let id: IndicatorID = "custom.myIndicator"
    let title = "MY"
    let placement: IndicatorPlacement = .overlay
    let defaultSeriesKeys = [SeriesKey(indicatorID: "custom.myIndicator", name: "MY")]

    func makeCalculators(configuration: ChartConfiguration) -> [any IndicatorCalculator] {
        [MyCalculator()]
    }

    @MainActor func makeRenderers(configuration: ChartConfiguration) -> [any ChartRenderer] {
        [MyRenderer()]
    }
}

let registry = PluginRegistry.default
registry.register(MyPlugin())
let options = ChartOptions(plugins: registry)

许可证

本项目采用 MIT 许可证 - 详情请见 LICENSE 文件。

About

轻量级 iOS K 线图表框架,基于现代 Swift 与模块化架构打造,高性能且易扩展维护

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages