Files
KissMe/KissMeConsole/Sources/KissConsole+CSV.swift
2023-06-03 08:03:10 +09:00

172 lines
5.1 KiB
Swift

//
// KissConsole+CSV.swift
// KissMeConsole
//
// Created by ened-book-m1 on 2023/05/29.
//
import Foundation
import KissMe
extension KissConsole {
var shopProductsUrl: URL {
URL.currentDirectory().appending(path: "data/shop-products.csv")
}
func topProductsUrl(_ belong: BelongClassCode) -> URL {
URL.currentDirectory().appending(path: "data/top-\(belong.fileBelong).csv")
}
}
extension KissConsole {
func loadShop(_ profile: Bool = false) {
let appTime1 = Date.appTime
guard let stringCsv = try? String(contentsOfFile: shopProductsUrl.path) else {
return
}
let appTime2 = Date.appTime
if profile {
print("\tloading file \(appTime2 - appTime1) elapsed")
}
var products = [String: [DomesticShop.Product]]()
let rows = stringCsv.split(separator: "\n")
let appTime3 = Date.appTime
if profile {
print("\trow split \(appTime3 - appTime2) elapsed")
}
for (i, row) in rows.enumerated() {
let array = row.split(separator: ",").map { String($0) }
if i == 0, array[0] == "baseDate" {
continue
}
let product = DomesticShop.Product(array: array)
if var value = products[product.itemName] {
value.append(product)
products.updateValue(value, forKey: product.itemName)
}
else {
products[product.itemName] = [product]
}
}
let appTime4 = Date.appTime
if profile {
print("\tparse product \(appTime4 - appTime3) elapsed")
}
setProducts(products)
let totalCount = products.reduce(0, { $0 + $1.value.count })
print("load products \(totalCount) with \(products.count) key")
}
}
extension KissConsole {
enum CandleValidation: CustomStringConvertible {
case ok
case invalidFileName
case cannotRead
case invalidCsvHeader
case invalidBusinessDate
case invalidConclusionTime
var description: String {
switch self {
case .ok: return "ok"
case .invalidFileName: return "invalidFileName"
case .cannotRead: return "cannotRead"
case .invalidCsvHeader: return "invalidCsvHeader"
case .invalidBusinessDate: return "invalidBusinessDate"
case .invalidConclusionTime: return "invalidConclusionTime"
}
}
}
static private func validateCandleMinute(_ fileUrl: URL) -> CandleValidation {
// TODO:
return .ok
}
static private func validateCandlePeriod(_ fileUrl: URL) -> CandleValidation {
// TODO:
return .ok
}
static func validateCandle(_ fileUrl: URL) -> CandleValidation {
let fileNameFrag = fileUrl.lastPathComponent.split(separator: ".")
guard fileNameFrag.count == 2 else {
return .invalidFileName
}
let candlePrefix = "candle-"
guard fileNameFrag[0].prefix(candlePrefix.count) == candlePrefix, fileNameFrag[1] == "csv" else {
return .invalidFileName
}
let fileDateFrag = fileNameFrag[0].suffix(fileNameFrag[0].count - candlePrefix.count)
guard let stringCsv = try? String(contentsOfFile: fileUrl.path) else {
return .cannotRead
}
var candles = [Domestic.Candle]()
let rows = stringCsv.split(separator: "\n")
for (i, row) in rows.enumerated() {
let array = row.split(separator: ",").map { String($0) }
if i == 0 {
if array.count != 8 {
return .invalidCsvHeader
}
continue
}
let candle = Domestic.Candle(array: array)
candles.append(candle)
}
var curHH = 9, curMM = 0
for candle in candles.reversed() {
if candle.stockBusinessDate != fileDateFrag {
return .invalidBusinessDate
}
guard let (hh, mm, _) = candle.stockConclusionTime.HHmmss else {
return .invalidConclusionTime
}
guard hh == curHH, mm == curMM else {
return .invalidConclusionTime
}
// Finished to check
if hh == 18, mm == 0 {
break
}
curMM += 1
if curMM >= 60 {
curMM = 0
curHH += 1
}
}
return .ok
}
}
extension BelongClassCode {
var fileBelong: String {
switch self {
case .averageVolume: return "average-volume"
case .volumeIncreaseRate: return "volume-increase-rate"
case .averageVolumeTurnoverRate: return "average-volume-turnover-rate"
case .transactionValue: return "transaction-value"
case .averageTransactionValueTurnoverRate: return "average-transaction-value-turnover-rate"
}
}
}