From f80a2ffb0c7186574e740525e54425fedc0c3d08 Mon Sep 17 00:00:00 2001 From: ened Date: Fri, 2 Jun 2023 02:19:32 +0900 Subject: [PATCH] Implement candle period --- KissMe/Sources/Domestic/DomesticStock.swift | 1 + .../Domestic/DomesticStockPriceResult.swift | 33 +++++++++++- KissMeConsole/Sources/KissConsole+CSV.swift | 35 +++++++++++-- .../Sources/KissConsole+Candle.swift | 52 +++++++++++++++---- bin/data | 2 +- 5 files changed, 108 insertions(+), 15 deletions(-) diff --git a/KissMe/Sources/Domestic/DomesticStock.swift b/KissMe/Sources/Domestic/DomesticStock.swift index 9012149..0025f94 100644 --- a/KissMe/Sources/Domestic/DomesticStock.swift +++ b/KissMe/Sources/Domestic/DomesticStock.swift @@ -10,6 +10,7 @@ import Foundation public struct Domestic { public typealias Candle = MinutePriceResult.OutputPrice + public typealias CandlePeriod = PeriodPriceResult.OutputPrice } diff --git a/KissMe/Sources/Domestic/DomesticStockPriceResult.swift b/KissMe/Sources/Domestic/DomesticStockPriceResult.swift index 520a91d..67c6ae3 100644 --- a/KissMe/Sources/Domestic/DomesticStockPriceResult.swift +++ b/KissMe/Sources/Domestic/DomesticStockPriceResult.swift @@ -40,7 +40,7 @@ public enum MarketWarning: String, Codable { /// 기간분류코드 -public enum PeriodDivision: String, Codable { +public enum PeriodDivision: String, Codable, CustomStringConvertible { /// 일봉 case daily = "D" /// 주봉 @@ -49,6 +49,15 @@ public enum PeriodDivision: String, Codable { case monthly = "M" /// 년봉 case yearly = "Y" + + public var description: String { + switch self { + case .daily: return "daily" + case .weekly: return "weekly" + case .monthly: return "monthly" + case .yearly: return "yearly" + } + } } @@ -543,6 +552,10 @@ public struct MinutePriceResult: Codable { case conclusionVolume = "cntg_vol" } + public var stockFullDate: String { + return stockBusinessDate + stockConclusionTime + } + public init(array: [String]) { self.stockBusinessDate = array[0] self.stockConclusionTime = array[1] @@ -562,7 +575,7 @@ public struct PeriodPriceResult: Codable { public let messageCode: String public let message: String public let output1: OutputSummary? - public let output2: [OutputPrice] + public let output2: [OutputPrice]? private enum CodingKeys: String, CodingKey { case resultCode = "rt_cd" @@ -753,5 +766,21 @@ public struct PeriodPriceResult: Codable { case previousDayVariableRatio = "prdy_vrss" case revaluationIssueReason = "revl_issu_reas" } + + public init(array: [String]) { + self.stockBusinessDate = array[0] + self.stockClosingPrice = array[1] + self.stockOpenningPrice = array[2] + self.highestStockPrice = array[3] + self.lowestStockPrice = array[4] + self.accumulatedVolume = array[5] + self.accumulatedTradingAmount = array[6] + self.exDivision = ExDivision(rawValue: array[7])! + self.partitionRate = array[8] + self.partitionModifiable = YesNo(rawValue: array[9])! + self.previousDayVariableRatioSign = array[10] + self.previousDayVariableRatio = array[11] + self.revaluationIssueReason = array[12] + } } } diff --git a/KissMeConsole/Sources/KissConsole+CSV.swift b/KissMeConsole/Sources/KissConsole+CSV.swift index adc21a4..4ec320c 100644 --- a/KissMeConsole/Sources/KissConsole+CSV.swift +++ b/KissMeConsole/Sources/KissConsole+CSV.swift @@ -60,7 +60,7 @@ extension KissConsole { } static func writeShop(_ shopItems: [DomesticShop.Product], fileUrl: URL) { - var stringCsv: String = "" + var stringCsv = "" let header = "baseDate,shortCode,isinCode,marketCategory,itemName,corporationNo\n" stringCsv.append(header) for item in shopItems { @@ -83,8 +83,8 @@ extension KissConsole { } static func writeCandle(_ prices: [Domestic.Candle], fileUrl: URL) { - var stringCsv: String = "stockBusinessDate,stockConclusionTime,accumulatedTradingAmount,currentStockPrice,secondStockPrice,highestStockPrice,lowestStockPrice,conclusionVolume\n" - let header = "" + var stringCsv = "" + let header = "stockBusinessDate,stockConclusionTime,accumulatedTradingAmount,currentStockPrice,secondStockPrice,highestStockPrice,lowestStockPrice,conclusionVolume\n" stringCsv.append(header) for item in prices { let stringItem = [item.stockBusinessDate, @@ -106,6 +106,35 @@ extension KissConsole { } } + static func writeCandle(_ prices: [Domestic.CandlePeriod], fileUrl: URL) { + var stringCsv = "" + let header = "stockBusinessDate,stockClosingPrice,stockOpenningPrice,highestStockPrice,lowestStockPrice,accumulatedVolume,accumulatedTradingAmount,exDivision,partitionRate,partitionModifiable,previousDayVariableRatioSign,previousDayVariableRatio,revaluationIssueReason\n" + stringCsv.append(header) + for item in prices { + let stringItem = [item.stockBusinessDate, + item.stockClosingPrice, + item.stockOpenningPrice, + item.highestStockPrice, + item.lowestStockPrice, + item.accumulatedVolume, + item.accumulatedTradingAmount, + item.exDivision.rawValue, + item.partitionRate, + item.partitionModifiable.rawValue, + item.previousDayVariableRatioSign, + item.previousDayVariableRatio, + item.revaluationIssueReason].joined(separator: ",") + stringCsv.append(stringItem) + stringCsv.append("\n") + } + do { + try stringCsv.write(toFile: fileUrl.path, atomically: true, encoding: .utf8) + print("wrote \(fileUrl.lastPathComponent) with \(prices.count)") + } catch { + print(error) + } + } + enum CandleValidation: CustomStringConvertible { case ok diff --git a/KissMeConsole/Sources/KissConsole+Candle.swift b/KissMeConsole/Sources/KissConsole+Candle.swift index f84cae5..1fd0c8a 100644 --- a/KissMeConsole/Sources/KissConsole+Candle.swift +++ b/KissMeConsole/Sources/KissConsole+Candle.swift @@ -60,16 +60,37 @@ extension KissConsole { defer { currentCandleShortCode = nil } - - var nextTime = Date() - var candles = [Domestic.Candle]() + + var nextTime = startDate + var candles = [Domestic.CandlePeriod]() var count = 0 - let result = try await account!.getPeriodPrice(productNo: productNo, startDate: startDate, endDate: endDate, period: .daily) + while true { + count += 1 + + let result = try await account!.getPeriodPrice(productNo: productNo, startDate: startDate, endDate: endDate, period: period) + + if let prices = result.output2, prices.isEmpty == false { + candles.append(contentsOf: prices) + if let last = prices.last { + + // TODO: nextTime 갱신을 처리한다... + } + try await Task.sleep(nanoseconds: 1_000_000_000 / PreferredCandleTPS) + } + else { + print("\(period) price finished") + } + } -// let fileUrl = candleFileUrl(productNo: productNo, period: "min", day: minTime) -// KissConsole.writeCandle(candles, fileUrl: fileUrl) + candles.sort(by: { $0.stockBusinessDate > $1.stockBusinessDate }) + guard let maxTime = candles.first?.stockBusinessDate else { + print("No price items") + return false + } + let fileUrl = candleFileUrl(productNo: productNo, period: period.filePeriod, day: maxTime) + KissConsole.writeCandle(candles, fileUrl: fileUrl) return true } catch { print(error) @@ -125,13 +146,13 @@ extension KissConsole { } } - candles.sort(by: { $0.stockBusinessDate < $1.stockBusinessDate }) - guard let minTime = candles.first?.stockBusinessDate else { + candles.sort(by: { $0.stockFullDate > $1.stockFullDate }) + guard let maxTime = candles.first?.stockBusinessDate else { print("No price items") return false } - let fileUrl = candleFileUrl(productNo: productNo, period: .minute, day: minTime) + let fileUrl = candleFileUrl(productNo: productNo, period: .minute, day: maxTime) KissConsole.writeCandle(candles, fileUrl: fileUrl) return true } catch { @@ -140,3 +161,16 @@ extension KissConsole { } } } + + +extension PeriodDivision { + var filePeriod: KissConsole.CandleFilePeriod { + switch self { + case .daily: return .day + case .weekly: return .weak + case .monthly: assertionFailure() + case .yearly: assertionFailure() + } + return .minute + } +} diff --git a/bin/data b/bin/data index d102289..08024e3 160000 --- a/bin/data +++ b/bin/data @@ -1 +1 @@ -Subproject commit d102289c456fe97d145ad5bae7d237075b9b3f57 +Subproject commit 08024e32ce3235a4df32f6337609c025df1347ba