// // test.swift // KissMeConsole // // Created by ened-book-m1 on 2023/05/16. // import Foundation import KissMe private func test_array_to_csv() { } private func test_login_get_volume_ranking() async { let isMock = false let credential: Credential do { /// isMock 이 true 이면, mock-server.json 에서 로딩하여 생성 /// isMock 이 false 이면, real-server.json 에서 로딩하여 생성 /// server.json 의 구조 /// { /// "isMock": true, /// "accountNo": "12345678-90" /// "appKey": "xxxxxxxx", /// "appSecret": "yyyyyyyyyyyyyyyyyy" /// } /// credential = try KissCredential(isMock: isMock) } catch { print(error) return } let account = KissAccount(credential: credential) do { if try await account.login() { let option = RankingOption(divisionClass: .equity, belongClass: .averageVolume) let result = try await account.getVolumeRanking(option: option) print("\(result)") } } catch { print(error) return } } private func test_json_result() { let str = "{\"rt_cd\":\"1\",\"msg_cd\":\"EGW00205\",\"msg1\":\"credentials_type이 유효하지 않습니다.(Bearer)\"}" do { let decoder = JSONDecoder() decoder.keyDecodingStrategy = .useDefaultKeys let data = Data(str.utf8) let result = try decoder.decode(VolumeRankResult.self, from: data) print("\(result)") } catch { print(error) } } private func test_xml_result() { /* let str = "
00NORMAL SERVICE.
이스트아시아홀딩스인베스트먼트리미티드900110삼천당제약000250중앙에너비스000440신라섬유001000안국약품001540무림에스피001810이화공영001840피에스텍002230삼일기업공사002290한일사료0058601011637
" let data = Data(str.utf8) class ResultHelper: NSObject, XMLParserDelegate { struct Result: Codable { } var result: Result? func parserDidStartDocument(_ parser: XMLParser) { } func parserDidEndDocument(_ parser: XMLParser) { } } do { let helper = ResultHelper() let parser = XMLParser(data: data) parser.shouldProcessNamespaces = true parser.delegate = helper if parser.parse() { print(helper.result) } } */ } private func fix_first_csv_header_field() { guard let enumerator = FileManager.subPathFiles("data") else { return } for case let fileUrl as URL in enumerator { guard fileUrl.pathExtension == "csv" else { continue } guard var stringCsv = try? String(contentsOfFile: fileUrl.path) else { print("Cannot load \(fileUrl)") continue } guard let range = stringCsv.range(of: ",\n") else { continue } stringCsv.remove(at: range.lowerBound) do { try stringCsv.write(toFile: fileUrl.path, atomically: true, encoding: .utf8) print("wrote \(fileUrl.lastPathComponent)") } catch { print(error) } } } private func check_candle_csv() { guard let enumerator = FileManager.subPathFiles("data") else { return } for case let fileUrl as URL in enumerator { let r = KissConsole.validateCandleMinute(fileUrl) switch r { case .ok, .invalidFileName: print("OK \(fileUrl)") continue default: assertionFailure() print("\(r) at \(fileUrl)") } } } func check_today_candle_exist() { guard let enumerator = FileManager.subPathFiles("data") else { return } var productUrls = [String: URL]() var candleUrls = [String: URL]() for case let fileUrl as URL in enumerator { guard true != fileUrl.isDirectoryExists else { let productNo = fileUrl.lastPathComponent if let _ = Int(productNo) { productUrls[productNo] = fileUrl } continue } guard fileUrl.pathExtension == "csv" else { continue } let fileName = fileUrl.lastPathComponent let periodDir = fileUrl.deletingLastPathComponent() let period = periodDir.lastPathComponent let productNoDir = periodDir.deletingLastPathComponent() let productNo = productNoDir.lastPathComponent guard let _ = Int(productNo), period == "min" else { continue } if Date().yyyyMMdd == fileName.parseCandleDate() { candleUrls[productNo] = fileUrl } } for productNo in productUrls.keys { guard nil == candleUrls[productNo] else { continue } print("\(productNo) have no today candle!!") } print("all scan finished") } private func move_candles_to_min_subdir() { // Move all of csv into min sub-directory // ex) data/000020/candle-20230530.csv --> /data/000020/min/candle-20230530.csv // guard let enumerator = FileManager.subPathFiles("data") else { return } var urls = [URL]() for case let fileUrl as URL in enumerator { guard fileUrl.pathExtension == "csv" else { continue } urls.append(fileUrl) } for fileUrl in urls { let fileName = fileUrl.lastPathComponent let upper = fileUrl.deletingLastPathComponent() let productNo = upper.lastPathComponent guard let _ = Int(productNo) else { continue } let newPath = upper.appending(path: "min") let newUrl = newPath.appending(path: fileName) //print("file: \(fileUrl) -> \(newUrl)") do { try FileManager.default.createDirectory(at: newPath, withIntermediateDirectories: true) try FileManager.default.moveItem(at: fileUrl, to: newUrl) } catch { print(error) exit(1) } } } private func update_candle_csv_header_field() { let symbols = Domestic.Candle.symbols() do { let csvUrls = try FileManager.collectCsv(period: .minute, candleDate: nil) for csvUrl in csvUrls { print("processing \(csvUrl.path)") let header = try String.readCsvHeader(fromFile: csvUrl) if symbols != header { let candles = try [Domestic.Candle].readCsv(fromFile: csvUrl, verifyHeader: false) try candles.writeCsv(toFile: csvUrl, localized: false) } } } catch { print(error) } } private func split_investor_csv() { guard let enumerator = FileManager.subPathFiles("data") else { return } var urls = [URL]() for case let fileUrl as URL in enumerator { guard fileUrl.pathExtension == "csv" else { continue } if fileUrl.lastPathComponent.prefix(9) == "investor-" { urls.append(fileUrl) } } do { for url in urls { let investorDir = url.deletingLastPathComponent() let productNoDir = investorDir.deletingLastPathComponent() let productNo = productNoDir.lastPathComponent let output = try [Domestic.Investor].readCsv(fromFile: url, verifyHeader: true) var months = [String: [Domestic.Investor]]() for item in output { let yyyyMM = String(item.stockBusinessDate.prefix(6)) if let _ = months[yyyyMM] { months[yyyyMM]!.append(item) } else { months[yyyyMM] = [item] } } for (month, items) in months { let descItems = items.sorted(by: { $0.stockBusinessDate > $1.stockBusinessDate }) guard descItems.count > 0 else { continue } let fileUrl = KissConsole.investorFileUrl(productNo: productNo, day: month+"01") try descItems.mergeCsv(toFile: fileUrl, merging: { this, file in var merged = this for old in file { if nil == this.first(where: { $0.stockBusinessDate == old.stockBusinessDate }) { merged.append(old) } } merged.sort(by: { $0.stockBusinessDate > $1.stockBusinessDate }) return merged }, localized: false) } try FileManager.default.removeItem(at: url) } } catch { print(error) } } private func split_prices_csv() { guard let enumerator = FileManager.subPathFiles("data") else { return } var urls = [URL]() for case let fileUrl as URL in enumerator { guard fileUrl.pathExtension == "csv" else { continue } if fileUrl.lastPathComponent.prefix(6) == "prices" { urls.append(fileUrl) } } do { for url in urls { print(url) let priceDir = url.deletingLastPathComponent() let productNoDir = priceDir.deletingLastPathComponent() let productNo = productNoDir.lastPathComponent let output = try [CapturePrice].readCsv(fromFile: url, verifyHeader: true) var months = [String: [CapturePrice]]() for item in output { let yyyyMM = String(item.stockBusinessDate.prefix(6)) if let _ = months[yyyyMM] { months[yyyyMM]!.append(item) } else { months[yyyyMM] = [item] } } for (month, items) in months { let descItems = items.sorted(by: { $0.stockDateTime > $1.stockDateTime }) guard descItems.count > 0 else { continue } let fileUrl = KissConsole.priceFileUrl(productNo: productNo, day: month+"01") try descItems.mergeCsv(toFile: fileUrl, merging: { this, file in var merged = file for old in file { if nil == this.first(where: { $0.stockDateTime == old.stockDateTime }) { merged.append(old) } } merged.sort(by: { $0.stockDateTime > $1.stockDateTime }) return merged }, localized: false) } try FileManager.default.removeItem(at: url) } } catch { print(error) } } private func update_shorts_csv_header_field() { let symbols = DomesticExtra.Shorts.symbols() do { let csvUrls = try FileManager.collectShorts() for csvUrl in csvUrls { print("processing \(csvUrl.path)") let header = try String.readCsvHeader(fromFile: csvUrl) if symbols != header { let candles = try [DomesticExtra.Shorts].readCsv(fromFile: csvUrl, verifyHeader: false) try candles.writeCsv(toFile: csvUrl, localized: false) } } } catch { print(error) } } private func test_decode_html_chars() { print("'알펜시아 입찰 방해' KH 자금총괄 구속영장 기각".htmlDecoded) } func test_request_naver_news_list() { let semaphore = DispatchSemaphore(value: 0) Task { let day = "20230723".yyyyMMdd_toDate! do { let list = try await DomesticNews.collectList(day: day) for item in list { print("\(item.title) :: \(item.press) :: \(item.url)") } } catch { print(error) } semaphore.signal() } semaphore.wait() }