使用 Coreplot 可视化股票图表 股票价格看起来非常平坦

问题描述 投票:0回答:1

我试过了,

  • 我将 y 轴设置得很窄,以使小幅价格变动显得正常,但没有帮助
  • API 结果检查正常
  • 其他图表类型(点/线...)没有解决问题

我只使用 yAxis,不需要 xAxis

这是我的整个代码

我的ChartViewController

    //
//  ChartViewController.swift
//  MCOS
//
//  Created by Burhan Cankurt on 01.09.23.
//

import UIKit
import CorePlot

class ChartViewController: UIViewController, CPTScatterPlotDataSource, CPTScatterPlotDelegate, CPTAxisDelegate {

    var ArrayStockClose: [(date: String, close: Double)] = []
    @IBOutlet weak var graphHostingView: CPTGraphHostingView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        chartViewStockClose(with: .fiveMinute)
    }
    
    func chartViewStockClose(with timeFrame: TimeFrame) {
        print("chartViewStockClose called") // Debug
        let fetcher = chartFetcherStockClose()
        chartLoadStockClose(with: timeFrame, fetcher: fetcher) { [weak self] result in
            print("chartLoadStockClose completion called") // Debug
            switch result {
            case .success(let data):
                self?.ArrayStockClose = data
                print("Daten im ViewController: \(data) und  zählung \(data.count)")
                DispatchQueue.main.async {
                    print("initializeGraph called") // Debug
                    // Hier können Sie Ihren Graphen initialisieren oder aktualisieren
                    self?.initializeGraph()
                }
            case .failure(let error):
                print("Error fetching data: \(error)")
            }
        }
    }
    
    func initializeGraph() {
        // Konfigurieren Sie die Ansicht und den Graphen
        configureGraphView(for: graphHostingView, plotData: ArrayStockClose, delegate: self) // Angenommen, Sie haben eine Funktion namens configureGraphView
        // Konfigurieren Sie den Plot
        configurePlot(for: graphHostingView, dataSource: self, delegate: self) // Angenommen, Sie haben eine Funktion namens configurePlot
    }
}

// Erweiterung für CorePlot Datenquelle und Delegat
extension ChartViewController {
    
    func numberOfRecords(for plot: CPTPlot) -> UInt {
        print("numberOfRecords called, count: \(ArrayStockClose.count)")
        return UInt(ArrayStockClose.count)
    }

    func number(for plot: CPTPlot, field: UInt, record: UInt) -> Any? {
        print("number called for field: \(field), record: \(record)")
        switch CPTScatterPlotField(rawValue: Int(field)) {
        case .X:
            return NSNumber(value: record)  // Da wir die X-Achse nicht verwenden, können wir einfach den Index verwenden
        case .Y:
            return NSNumber(value: ArrayStockClose[Int(record)].close)
        default:
            return nil
        }
    }
}

我的图表FetcherStock关闭

//
//  ChartFetcherStockClose.swift
//  MCOS
//
//  Created by Burhan Cankurt on 01.09.23.
//

import Foundation

import Foundation

class chartFetcherStockClose {
    func fetch(url: URL, completion: @escaping (Result<[(date: String, close: Double)], Error>) -> Void) {
        let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
            if let error = error {
                completion(.failure(error))
                return
            }
            guard let data = data else {
                completion(.failure(NSError(domain: "No data", code: 0, userInfo: nil)))
                return
            }
            do {
                let decoder = JSONDecoder()
                let stockData = try decoder.decode([StructStockClose].self, from: data)
                // Sortiere die Datenpunkte nach dem Datum
                let sortedStockData = stockData.sorted { $0.date < $1.date }
                // Erstelle ein leeres Array, um die Ergebnisse zu speichern.
                var resultArray: [(date: String, close: Double)] = []
                // Durchlaufe jedes Element in sortedStockData.
                for data in sortedStockData {
                    resultArray.append((date: data.date, close: data.close))
                }
                // Rufe den Completion Handler mit dem Ergebnis-Array auf.
                completion(.success(resultArray))
            } catch {
                completion(.failure(error))
            }
        }
        task.resume()
    }
}// Class End

我的图表加载库存关闭

//
//  ChartLoadStockClose.swift
//  MCOS
//
//  Created by Burhan Cankurt on 01.09.23.
//

import Foundation

enum TimeFrame {
    case oneMinute
    case fiveMinute
    case fifteenMinute
    case thirtyMinute
    case oneHour
    case fourHour
    case oneDay
}

func chartLoadStockClose(with timeFrame: TimeFrame, fetcher: chartFetcherStockClose, completion: @escaping (Result<[(date: String, close: Double)], Error>) -> Void) {
    let timeFrameParameter: String
    switch timeFrame {
    case .oneMinute: timeFrameParameter = "1min"
    case .fiveMinute: timeFrameParameter = "5min"
    case .fifteenMinute: timeFrameParameter = "15min"
    case .thirtyMinute: timeFrameParameter = "30min"
    case .oneHour: timeFrameParameter = "1hour"
    case .fourHour: timeFrameParameter = "4hour"
    case .oneDay: timeFrameParameter = "1day"
    }
    
    let url = URL(string: "https://financialmodelingprep.com/api/v3/historical-chart/\(timeFrameParameter)/AAPL?apikey=BLABLABLA")!
    
    fetcher.fetch(url: url) { result in
        switch result {
        case .success(let data):
            // Verwende nur die letzten 48 Datenpunkte
            let filteredData = Array(data.suffix(48))
            completion(.success(filteredData))
        case .failure(let error):
            completion(.failure(error))
        }
    }
}

我的图表配置GraphView

//
//  ChartConfigureGraphView.swift
//  MCOS
//
//  Created by Burhan Cankurt on 01.09.23.
//

import CorePlot
import UIKit

func configureGraphView(for graphView: CPTGraphHostingView, plotData: [(date: String, close: Double)], delegate: CPTAxisDelegate) {
    print("configureGraphView called") // Debug
    graphView.allowPinchScaling = false
    // Configure graph
    let graph = CPTXYGraph(frame: graphView.bounds)
    graph.plotAreaFrame?.masksToBorder = false
    graphView.hostedGraph = graph
    graph.backgroundColor = UIColor.black.cgColor
    graph.paddingBottom = 40.0
    graph.paddingLeft = 50.0
    graph.paddingTop = 30.0
    graph.paddingRight = 5.0
    
    // Set plot space
    let yMin = plotData.min(by: { $0.close < $1.close })?.close ?? 0
    let yMax = plotData.max(by: { $0.close < $1.close })?.close ?? 0

    print("yMin: \(yMin)") // Debug
    print("yMax: \(yMax)") // Debug

    let yRange = yMax - yMin
    let paddingPercentage = 0.05

    print("yRange: \(yRange)") // Debug

    let yMinAdjusted = yMin - (yRange * paddingPercentage)
    let yMaxAdjusted = yMax + (yRange * paddingPercentage)

    print("yMinAdjusted: \(yMinAdjusted)") // Debug
    print("yMaxAdjusted: \(yMaxAdjusted)") // Debug
    
    guard let plotSpace = graph.defaultPlotSpace as? CPTXYPlotSpace else { return }

    plotSpace.yRange = CPTPlotRange(locationDecimal: CPTDecimalFromDouble(yMinAdjusted), lengthDecimal: CPTDecimalFromDouble(yMaxAdjusted - yMinAdjusted))
    
    // Configure axes
    let axisSet = graph.axisSet as! CPTXYAxisSet
    
    let axisTextStyle = CPTMutableTextStyle()
    axisTextStyle.color = CPTColor.white()
    axisTextStyle.fontName = "HelveticaNeue-Bold"
    axisTextStyle.fontSize = 10.0
    axisTextStyle.textAlignment = .center

    if let x = axisSet.xAxis {
        x.isHidden = true  // Versteckt die X-Achse
    }

    if let y = axisSet.yAxis {
        print("Configuring yAxis") // Debug
        y.majorIntervalLength = NSNumber(value: Double((yMaxAdjusted - yMinAdjusted) / 10.0))  // Dynamically adjust the interval
        y.minorTicksPerInterval = 5
        y.labelTextStyle = axisTextStyle
        y.axisConstraints = CPTConstraints(lowerOffset: 0.0)
        y.delegate = delegate
    }
}

我的结构

//
//  Structs.swift
//  MCOS
//
//  Created by Burhan Cankurt on 01.09.23.
//

import Foundation

struct StructStockClose: Decodable {
    let close: Double
    let date: String
}

我的图表配置图

//
//  ChartConfigurePlot.swift
//  MCOS
//
//  Created by Burhan Cankurt on 01.09.23.
//

import CorePlot
import UIKit

func configurePlot(for graphView: CPTGraphHostingView, dataSource: CPTScatterPlotDataSource, delegate: CPTScatterPlotDelegate) {
    print("configurePlot called") // Debug
    let plot = CPTScatterPlot()
    let plotLineStile = CPTMutableLineStyle()
    plotLineStile.lineJoin = .round
    plotLineStile.lineCap = .round
    plotLineStile.lineWidth = 2
    plotLineStile.lineColor = CPTColor.white()
    plot.dataLineStyle = plotLineStile
    plot.curvedInterpolationOption = .catmullCustomAlpha
    plot.interpolation = .curved
    plot.identifier = "coreplot-graph" as NSCoding & NSCopying & NSObjectProtocol
    guard let graph = graphView.hostedGraph else { return }
    plot.dataSource = dataSource
    plot.delegate = delegate
    graph.add(plot, to: graph.defaultPlotSpace)
}
ios swift core-plot stock
1个回答
0
投票

我解决了可视化问题,问题是无论您是否使用 xAxis,创建此代码后都需要时间戳

我的约会助手

//
//  DateHelpers.swift
//  MCOS
//
//  Created by Burhan Cankurt on 02.09.23.
//

import Foundation


func convertDateToTimestamp(_ date: String) -> Double {
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" // Anpassung an Ihr Datumsformat
    dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
    
    guard let dateObject = dateFormatter.date(from: date) else {
        print("Fehler beim Konvertieren des Datums: \(date)")
        return 0.0
    }
    
    let timestamp = dateObject.timeIntervalSince1970
    print("Zeitstempel für Datum \(date): \(timestamp)")
    return timestamp
}

并在我的 ChartViewController 中使用它

// Erweiterung für CorePlot Datenquelle und Delegat
extension ChartViewController {
    
    func numberOfRecords(for plot: CPTPlot) -> UInt {
        print("Anzahl der Datenpunkte: \(ArrayStockClose.count)")
        return UInt(ArrayStockClose.count)
    }

    func number(for plot: CPTPlot, field: UInt, record: UInt) -> Any? {
        switch CPTScatterPlotField(rawValue: Int(field)) {
        case .X:
            return NSNumber(value: convertDateToTimestamp(ArrayStockClose[Int(record)].date))  // Verwenden Sie den Zeitstempel
        case .Y:
            return NSNumber(value: ArrayStockClose[Int(record)].close)
        default:
            return nil
        }
    }
}

可视化工作正常,但现在我面临一个非常奇怪的问题,时间范围 1 分钟和 5 分钟工作正常,但如果使用超过 5 分钟的时间范围,我会收到此错误

Zeitstempel für Datum 2023-09-01 15:00:00: 1693580400.0
Zeitstempel für Datum 2023-09-01 15:15:00: 1693581300.0
Zeitstempel für Datum 2023-09-01 15:30:00: 1693582200.0
Zeitstempel für Datum 2023-09-01 15:45:00: 1693583100.0
Zeitstempel für Datum 2023-09-01 16:00:00: 1693584000.0
Anzahl der Datenpunkte: 48
Anzahl der Datenpunkte: 48
2023-09-03 23:13:45.924826+0200 MCOS[40996:1540827] [Render] CoreAnimation: Message::send_message() returned 0x1000000e
2023-09-03 23:13:45.925018+0200 MCOS[40996:1540827] [API] Failed to commit transaction (client=0x1d461d53) [0x1000000e (ipc/send) msg too large]

我尝试了什么?

  • Api 工作正常并为更高级别提供足够的数据点
  • 笔记本电脑有足够的资源来应对性能

奇怪:如果你将我的数据点从 48 减少到 20,例如,我会在更高的时间范围 15 分钟上加载图表,当我将其减少到 10 时,它还会加载更高的时间范围图表 30 分钟

知道问题可能是什么吗?

© www.soinside.com 2019 - 2024. All rights reserved.