From 944f621424e245a6fee521de254cbf71cf98e1c3 Mon Sep 17 00:00:00 2001 From: ened Date: Fri, 2 Jun 2023 10:23:28 +0900 Subject: [PATCH] Fix bugs on candle day request --- KissMe/Sources/Common/Request.swift | 8 +- .../Sources/Domestic/DomesticStockPrice.swift | 7 +- .../Domestic/DomesticStockSearch.swift | 87 ++++++++++++++++++- .../Domestic/DomesticStockSearchResult.swift | 44 ++++++++++ .../Sources/KissConsole+Candle.swift | 2 +- KissMeConsole/Sources/KissConsole.swift | 4 +- 6 files changed, 142 insertions(+), 10 deletions(-) diff --git a/KissMe/Sources/Common/Request.swift b/KissMe/Sources/Common/Request.swift index 1542fe8..2d28338 100644 --- a/KissMe/Sources/Common/Request.swift +++ b/KissMe/Sources/Common/Request.swift @@ -57,6 +57,7 @@ public protocol Request { var result: KResult? { get set } var timeout: TimeInterval { get } var responseDataLoggable: Bool { get } + var traceable: Bool { get } } @@ -72,6 +73,7 @@ extension Request { public var header: [String: String?] { [:] } public var timeout: TimeInterval { 15 } public var responseDataLoggable: Bool { true } + public var traceable: Bool { false } } @@ -112,7 +114,7 @@ extension Request { case .get: var queryItems = [URLQueryItem]() - for item in body { + for item in body.sorted(by: { $0.key < $1.key }) { if let value = item.value as? String { queryItems.append(URLQueryItem(name: item.key, value: value)) } @@ -121,6 +123,10 @@ extension Request { request.url?.append(queryItems: queryItems) } + if traceable, let url = request.url { + print("REQUEST \(method) \(url)") + } + request.setValue("application/json; charset=UTF-8", forHTTPHeaderField: "Content-Type") request.setValue("JSON", forHTTPHeaderField: "Format") request.setValue(userAgent, forHTTPHeaderField: "User-Agent") diff --git a/KissMe/Sources/Domestic/DomesticStockPrice.swift b/KissMe/Sources/Domestic/DomesticStockPrice.swift index e080ea1..4d1f5f9 100644 --- a/KissMe/Sources/Domestic/DomesticStockPrice.swift +++ b/KissMe/Sources/Domestic/DomesticStockPrice.swift @@ -139,9 +139,8 @@ extension Domestic { } public var result: KResult? = nil public let credential: Credential - public var responseDataLoggable: Bool { - return true - } + public var responseDataLoggable: Bool { true } + public var traceable: Bool { true } private var trId: String { @@ -160,7 +159,7 @@ extension Domestic { self.accessToken = accessToken self.productNo = productNo self.startDate = startDate - self.endDate = startDate + self.endDate = endDate self.period = period self.priceType = priceType } diff --git a/KissMe/Sources/Domestic/DomesticStockSearch.swift b/KissMe/Sources/Domestic/DomesticStockSearch.swift index 176192b..58a2469 100644 --- a/KissMe/Sources/Domestic/DomesticStockSearch.swift +++ b/KissMe/Sources/Domestic/DomesticStockSearch.swift @@ -8,7 +8,7 @@ import Foundation -public enum DivisionClassCode: String { +public enum DivisionClassCode: String, Codable { /// 전체 case all = "0" /// 보통주 @@ -18,6 +18,24 @@ public enum DivisionClassCode: String { } +public enum WeekdayDivision: String, Codable { + /// 일요일 + case sunday = "01" + /// 월요일 + case monday = "02" + /// 화요일 + case tueday = "03" + /// 수요일 + case wednesday = "04" + /// 목요일 + case thursday = "05" + /// 금요일 + case friday = "06" + /// 토요일 + case saturday = "07" +} + + public enum BelongClassCode: String, CustomStringConvertible { /// 평균거래량 case averageVolume = "0" @@ -102,6 +120,49 @@ extension Domestic { self.belongClass = belongClass } } + + + /// 국내주식주문 - 국내휴장일조회 + /// + public struct HolidayRequest: OrderRequest { + public typealias KResult = HolidyResult + + public var url: String { "/uapi/domestic-stock/v1/quotations/chk-holiday" } + public var method: Method { .post } + + public var header: [String: String?] { + [ + "authorization": "Bearer \(accessToken)", + "appkey": credential.appKey, + "appsecret": credential.appSecret, + "tr_id": trId, + "custtype": CustomerType.personal.rawValue, + ] + } + public var body: [String: Any] { + [ + "BASS_DT": baseDate, + "CTX_AREA_NK": String(repeating: " ", count: 20), + "CTX_AREA_FK": String(repeating: " ", count: 20), + ] + } + public var result: KResult? = nil + public let credential: Credential + + + private var trId: String { + "CTCA0903R" + } + + public let accessToken: String + let baseDate: String /// yyyyMMdd + + public init(credential: Credential, accessToken: String, baseDate: String) { + self.credential = credential + self.accessToken = accessToken + self.baseDate = baseDate + } + } } @@ -119,8 +180,9 @@ public struct RankingOption { // MARK: Stock Search extension KissAccount { + /// 상위 거래량 가져오기 + /// public func getVolumeRanking(option: RankingOption) async throws -> VolumeRankResult { - return try await withUnsafeThrowingContinuation { continuation in guard let accessToken = accessToken else { continuation.resume(throwing: GeneralError.invalidAccessToken) @@ -138,4 +200,25 @@ extension KissAccount { } } } + + /// 휴장일 확인하기 + /// + public func getHolyday(baseDate: Date) async throws -> HolidyResult { + return try await withUnsafeThrowingContinuation { continuation in + guard let accessToken = accessToken else { + continuation.resume(throwing: GeneralError.invalidAccessToken) + return + } + + let request = Domestic.HolidayRequest(credential: credential, accessToken: accessToken, baseDate: baseDate.yyyyMMdd) + request.query { result in + switch result { + case .success(let result): + continuation.resume(returning: result) + case .failure(let error): + continuation.resume(throwing: error) + } + } + } + } } diff --git a/KissMe/Sources/Domestic/DomesticStockSearchResult.swift b/KissMe/Sources/Domestic/DomesticStockSearchResult.swift index aa88684..5ff229c 100644 --- a/KissMe/Sources/Domestic/DomesticStockSearchResult.swift +++ b/KissMe/Sources/Domestic/DomesticStockSearchResult.swift @@ -104,3 +104,47 @@ public struct VolumeRankResult: Codable { } } } + + +public struct HolidyResult: Codable { + public let resultCode: String + public let messageCode: String + public let message: String + public let output: [OutputDetail]? + + private enum CodingKeys: String, CodingKey { + case resultCode = "rt_cd" + case messageCode = "msg_cd" + case message = "msg1" + case output = "output" + } + + public struct OutputDetail: Codable { + /// 기준일자 + public let baseDate: String + + /// 요일구분코드 + public let weekday: WeekdayDivision + + /// 영업일여부 + public let businessDayOpened: YesNo + + /// 거래일여부 + public let tradingDayOpened: YesNo + + /// 개장일여부 + public let peningDay: YesNo + + /// 결제일여부 + public let settlementDay: YesNo + + private enum CodingKeys: String, CodingKey { + case baseDate = "bass_dt" + case weekday = "wday_dvsn_cd" + case businessDayOpened = "bzdy_yn" + case tradingDayOpened = "tr_day_yn" + case peningDay = "opnd_yn" + case settlementDay = "sttl_day_yn" + } + } +} diff --git a/KissMeConsole/Sources/KissConsole+Candle.swift b/KissMeConsole/Sources/KissConsole+Candle.swift index 1bbbadc..4d3b272 100644 --- a/KissMeConsole/Sources/KissConsole+Candle.swift +++ b/KissMeConsole/Sources/KissConsole+Candle.swift @@ -53,7 +53,7 @@ extension KissConsole { func candleFileUrl(productNo: String, period: CandleFilePeriod, day: String) -> URL { - assert(day.count == 6) + assert(day.count == 8) let subPath = "data/\(productNo)/\(period.rawValue)" let subFile = "\(subPath)/candle-\(day).csv" let fileUrl = URL.currentDirectory().appending(path: subFile) diff --git a/KissMeConsole/Sources/KissConsole.swift b/KissMeConsole/Sources/KissConsole.swift index 6080e27..f9639eb 100644 --- a/KissMeConsole/Sources/KissConsole.swift +++ b/KissMeConsole/Sources/KissConsole.swift @@ -584,8 +584,8 @@ extension KissConsole { } let (startDate, endDate) = last250Days -// let startDate = Date().changing(year: 2022, month: 12, day: 1)! -// let endDate = Date().changing(year: 2022, month: 12, day: 30)! + //let startDate = Date().changing(year: 2023, month: 5, day: 1)! + //let endDate = Date().changing(year: 2023, month: 6, day: 1)! let semaphore = DispatchSemaphore(value: 0) Task {