Fix candle day, week command
This commit is contained in:
@@ -140,8 +140,7 @@ extension Domestic {
|
||||
public var result: KResult? = nil
|
||||
public let credential: Credential
|
||||
public var responseDataLoggable: Bool { true }
|
||||
public var traceable: Bool { true }
|
||||
|
||||
|
||||
|
||||
private var trId: String {
|
||||
"FHKST03010100"
|
||||
|
||||
@@ -575,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: [OutputPriceOptional]?
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case resultCode = "rt_cd"
|
||||
@@ -711,6 +711,84 @@ public struct PeriodPriceResult: Codable {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct OutputPriceOptional: Codable {
|
||||
/// 주식 영업 일자
|
||||
public let stockBusinessDate: String?
|
||||
|
||||
/// 주식 종가
|
||||
public let stockClosingPrice: String?
|
||||
|
||||
/// 주식 시가
|
||||
public let stockOpenningPrice: String?
|
||||
|
||||
/// 주식 최고가
|
||||
public let highestStockPrice: String?
|
||||
|
||||
/// 주식 최저가
|
||||
public let lowestStockPrice: String?
|
||||
|
||||
/// 누적 거래량
|
||||
public let accumulatedVolume: String?
|
||||
|
||||
/// 누적 거래 대금
|
||||
public let accumulatedTradingAmount: String?
|
||||
|
||||
/// 락 구분 코드
|
||||
public let exDivision: ExDivision?
|
||||
|
||||
/// 분할 비율
|
||||
public let partitionRate: String?
|
||||
|
||||
/// 분할변경여부
|
||||
public let partitionModifiable: YesNo?
|
||||
|
||||
/// 전일 대비 부호
|
||||
public let previousDayVariableRatioSign: String?
|
||||
|
||||
/// 전일 대비
|
||||
public let previousDayVariableRatio: String?
|
||||
|
||||
/// 재평가사유코드
|
||||
public let revaluationIssueReason: String?
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case stockBusinessDate = "stck_bsop_date"
|
||||
case stockClosingPrice = "stck_clpr"
|
||||
case stockOpenningPrice = "stck_oprc"
|
||||
case highestStockPrice = "stck_hgpr"
|
||||
case lowestStockPrice = "stck_lwpr"
|
||||
case accumulatedVolume = "acml_vol"
|
||||
case accumulatedTradingAmount = "acml_tr_pbmn"
|
||||
case exDivision = "flng_cls_code"
|
||||
case partitionRate = "prtt_rate"
|
||||
case partitionModifiable = "mod_yn"
|
||||
case previousDayVariableRatioSign = "prdy_vrss_sign"
|
||||
case previousDayVariableRatio = "prdy_vrss"
|
||||
case revaluationIssueReason = "revl_issu_reas"
|
||||
}
|
||||
|
||||
public var validObject: OutputPrice? {
|
||||
guard let stockBusinessDate = stockBusinessDate,
|
||||
let stockClosingPrice = stockClosingPrice,
|
||||
let stockOpenningPrice = stockOpenningPrice,
|
||||
let highestStockPrice = highestStockPrice,
|
||||
let lowestStockPrice = lowestStockPrice,
|
||||
let accumulatedVolume = accumulatedVolume,
|
||||
let accumulatedTradingAmount = accumulatedTradingAmount,
|
||||
let exDivision = exDivision,
|
||||
let partitionRate = partitionRate,
|
||||
let partitionModifiable = partitionModifiable,
|
||||
let previousDayVariableRatioSign = previousDayVariableRatioSign,
|
||||
let previousDayVariableRatio = previousDayVariableRatio,
|
||||
let revaluationIssueReason = revaluationIssueReason else {
|
||||
return nil
|
||||
}
|
||||
return OutputPrice(stockBusinessDate: stockBusinessDate, stockClosingPrice: stockClosingPrice, stockOpenningPrice: stockOpenningPrice, highestStockPrice: highestStockPrice, lowestStockPrice: lowestStockPrice, accumulatedVolume: accumulatedVolume, accumulatedTradingAmount: accumulatedTradingAmount, exDivision: exDivision, partitionRate: partitionRate, partitionModifiable: partitionModifiable, previousDayVariableRatioSign: previousDayVariableRatioSign, previousDayVariableRatio: previousDayVariableRatio, revaluationIssueReason: revaluationIssueReason)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct OutputPrice: Codable {
|
||||
/// 주식 영업 일자
|
||||
public let stockBusinessDate: String
|
||||
@@ -782,5 +860,21 @@ public struct PeriodPriceResult: Codable {
|
||||
self.previousDayVariableRatio = array[11]
|
||||
self.revaluationIssueReason = array[12]
|
||||
}
|
||||
|
||||
init(stockBusinessDate: String, stockClosingPrice: String, stockOpenningPrice: String, highestStockPrice: String, lowestStockPrice: String, accumulatedVolume: String, accumulatedTradingAmount: String, exDivision: ExDivision, partitionRate: String, partitionModifiable: YesNo, previousDayVariableRatioSign: String, previousDayVariableRatio: String, revaluationIssueReason: String) {
|
||||
self.stockBusinessDate = stockBusinessDate
|
||||
self.stockClosingPrice = stockClosingPrice
|
||||
self.stockOpenningPrice = stockOpenningPrice
|
||||
self.highestStockPrice = highestStockPrice
|
||||
self.lowestStockPrice = lowestStockPrice
|
||||
self.accumulatedVolume = accumulatedVolume
|
||||
self.accumulatedTradingAmount = accumulatedTradingAmount
|
||||
self.exDivision = exDivision
|
||||
self.partitionRate = partitionRate
|
||||
self.partitionModifiable = partitionModifiable
|
||||
self.previousDayVariableRatioSign = previousDayVariableRatioSign
|
||||
self.previousDayVariableRatio = previousDayVariableRatio
|
||||
self.revaluationIssueReason = revaluationIssueReason
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,33 +18,6 @@ let SecondsForOneDay: TimeInterval = 60 * 60 * 24
|
||||
|
||||
extension KissConsole {
|
||||
|
||||
var last250Days: (startDate: Date, endDate: Date) {
|
||||
var curDate = Date()
|
||||
if let (hour, _, _) = curDate.HHmmss_split {
|
||||
if hour < 9 {
|
||||
curDate.addTimeInterval(-SecondsForOneDay)
|
||||
}
|
||||
}
|
||||
let endDate = curDate.changing(hour: 0, min: 0, sec: 0)!
|
||||
let startDate = endDate.addingTimeInterval(-250 * SecondsForOneDay)
|
||||
return (startDate, endDate)
|
||||
}
|
||||
|
||||
|
||||
var last52Weeks: (startDate: Date, endDate: Date) {
|
||||
// TODO: 주당 가격을 얻기 위해, 거래 시작일을 마지막 장 개설일로 보정할 필요가 있을까?
|
||||
var curDate = Date()
|
||||
if let (hour, _, _) = curDate.HHmmss_split {
|
||||
if hour < 9 {
|
||||
curDate.addTimeInterval(-SecondsForOneDay)
|
||||
}
|
||||
}
|
||||
let endDate = curDate.changing(hour: 0, min: 0, sec: 0)!
|
||||
let startDate = endDate.addingTimeInterval(-52 * 7 * SecondsForOneDay)
|
||||
return (startDate, endDate)
|
||||
}
|
||||
|
||||
|
||||
enum CandleFilePeriod: String {
|
||||
case minute = "min"
|
||||
case day = "day"
|
||||
@@ -55,14 +28,23 @@ extension KissConsole {
|
||||
func candleFileUrl(productNo: String, period: CandleFilePeriod, day: String) -> URL {
|
||||
assert(day.count == 8)
|
||||
let subPath = "data/\(productNo)/\(period.rawValue)"
|
||||
let subFile = "\(subPath)/candle-\(day).csv"
|
||||
let subFile: String
|
||||
|
||||
switch period {
|
||||
case .minute:
|
||||
subFile = "\(subPath)/candle-\(day).csv"
|
||||
case .day:
|
||||
subFile = "\(subPath)/candle-day-250.csv"
|
||||
case .weak:
|
||||
subFile = "\(subPath)/candle-week-42.csv"
|
||||
}
|
||||
let fileUrl = URL.currentDirectory().appending(path: subFile)
|
||||
createSubpath(subPath)
|
||||
return fileUrl
|
||||
}
|
||||
|
||||
|
||||
func getCandle(productNo: String, period: PeriodDivision, startDate: Date, endDate: Date) async -> Bool {
|
||||
func getRecentCandle(productNo: String, period: PeriodDivision, count: Int) async -> Bool {
|
||||
do {
|
||||
guard currentCandleShortCode == nil else {
|
||||
print("Already candle collecting")
|
||||
@@ -73,38 +55,44 @@ extension KissConsole {
|
||||
currentCandleShortCode = nil
|
||||
}
|
||||
|
||||
var reqStartDate = startDate
|
||||
var reqEndDate = reqStartDate.addingTimeInterval(99 * SecondsForOneDay)
|
||||
if reqEndDate > endDate {
|
||||
reqEndDate = endDate
|
||||
}
|
||||
|
||||
var reqEndDate = Date()
|
||||
var reqStartDate = reqEndDate.addingTimeInterval(-period.secondsForPeriodRequest)
|
||||
var reqCount = 0
|
||||
|
||||
var candles = [Domestic.CandlePeriod]()
|
||||
var count = 0
|
||||
|
||||
|
||||
while true {
|
||||
count += 1
|
||||
reqCount += 1
|
||||
print("\(period) price \(productNo) from \(reqStartDate.yyyyMMdd_HHmmss_forTime) to \(reqEndDate.yyyyMMdd_HHmmss_forTime)")
|
||||
|
||||
let result = try await account!.getPeriodPrice(productNo: productNo, startDate: reqStartDate, endDate: reqEndDate, period: period)
|
||||
|
||||
if let prices = result.output2, prices.isEmpty == false {
|
||||
|
||||
if let prices = result.output2?.compactMap({ $0.validObject }), prices.isEmpty == false {
|
||||
candles.append(contentsOf: prices)
|
||||
if candles.count >= count {
|
||||
print("\(period) price finished")
|
||||
break
|
||||
}
|
||||
if let last = prices.last {
|
||||
if let (yyyy, mm, dd) = last.stockBusinessDate.yyyyMMdd {
|
||||
print("next: \(last.stockBusinessDate)")
|
||||
reqStartDate.change(year: yyyy, month: mm, day: dd+1)
|
||||
reqEndDate = reqStartDate.addingTimeInterval(99 * SecondsForOneDay)
|
||||
if reqEndDate > endDate {
|
||||
reqEndDate = endDate
|
||||
}
|
||||
reqEndDate.change(year: yyyy, month: mm, day: dd-1)
|
||||
reqStartDate = reqEndDate.addingTimeInterval(-period.secondsForPeriodRequest)
|
||||
}
|
||||
}
|
||||
try await Task.sleep(nanoseconds: 1_000_000_000 / PreferredCandleTPS)
|
||||
}
|
||||
else {
|
||||
print("\(period) price finished")
|
||||
break
|
||||
/// 만약에, 기간내에 데이터를 하나도 없을 경우 (ex. 거래정지 등),
|
||||
/// 이전 날짜로 몇번 더 올라가서 데이터를 다시 긁어본다.
|
||||
if reqCount < 5 {
|
||||
reqEndDate = reqStartDate.addingTimeInterval(-SecondsForOneDay)
|
||||
reqStartDate = reqEndDate.addingTimeInterval(-period.secondsForPeriodRequest)
|
||||
}
|
||||
else {
|
||||
print("\(period) price finished")
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,4 +187,13 @@ extension PeriodDivision {
|
||||
}
|
||||
return .minute
|
||||
}
|
||||
|
||||
var secondsForPeriodRequest: TimeInterval {
|
||||
switch self {
|
||||
case .daily: return 99 * SecondsForOneDay /// 한번에 요청으로 100건씩 가져옴. 시작날 ~ 종료날 포함이므로, 99
|
||||
case .weekly: return 99 * 7 * SecondsForOneDay
|
||||
case .monthly: return 99 * 28 * SecondsForOneDay
|
||||
case .yearly: return 99 * 365 * SecondsForOneDay
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -583,13 +583,9 @@ extension KissConsole {
|
||||
return
|
||||
}
|
||||
|
||||
let (startDate, endDate) = last250Days
|
||||
//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 {
|
||||
let success = await getCandle(productNo: productNo, period: .daily, startDate: startDate, endDate: endDate)
|
||||
let success = await getRecentCandle(productNo: productNo, period: .daily, count: 250)
|
||||
print("DONE \(success) \(productNo)")
|
||||
semaphore.signal()
|
||||
}
|
||||
@@ -598,14 +594,18 @@ extension KissConsole {
|
||||
|
||||
|
||||
private func onCandleDayAll() {
|
||||
let (startDate, endDate) = last250Days
|
||||
let all = getAllProducts()
|
||||
for item in all {
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
Task {
|
||||
let success = await getCandle(productNo: item.shortCode, period: .daily, startDate: startDate, endDate: endDate)
|
||||
let success = await getRecentCandle(productNo: item.shortCode, period: .daily, count: 250)
|
||||
print("DONE \(success) \(item.shortCode)")
|
||||
semaphore.signal()
|
||||
#if DEBUG
|
||||
if !success {
|
||||
exit(99)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
semaphore.wait()
|
||||
}
|
||||
@@ -614,7 +614,7 @@ extension KissConsole {
|
||||
|
||||
private func onCandleWeek(_ args: [String]) {
|
||||
if args.count == 1, args[0] == "all" {
|
||||
onCandleDayAll()
|
||||
onCandleWeekAll()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -624,10 +624,9 @@ extension KissConsole {
|
||||
return
|
||||
}
|
||||
|
||||
let (startDate, endDate) = last52Weeks
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
Task {
|
||||
let success = await getCandle(productNo: productNo, period: .weekly, startDate: startDate, endDate: endDate)
|
||||
let success = await getRecentCandle(productNo: productNo, period: .weekly, count: 52)
|
||||
print("DONE \(success) \(productNo)")
|
||||
semaphore.signal()
|
||||
}
|
||||
@@ -636,14 +635,18 @@ extension KissConsole {
|
||||
|
||||
|
||||
private func onCandleWeekAll() {
|
||||
let (startDate, endDate) = last52Weeks
|
||||
let all = getAllProducts()
|
||||
for item in all {
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
Task {
|
||||
let success = await getCandle(productNo: item.shortCode, period: .weekly, startDate: startDate, endDate: endDate)
|
||||
let success = await getRecentCandle(productNo: item.shortCode, period: .weekly, count: 52)
|
||||
print("DONE \(success) \(item.shortCode)")
|
||||
semaphore.signal()
|
||||
#if DEBUG
|
||||
if !success {
|
||||
exit(99)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
semaphore.wait()
|
||||
}
|
||||
|
||||
2
bin/data
2
bin/data
Submodule bin/data updated: 08024e32ce...3605948d54
Reference in New Issue
Block a user