Files
KissMe/KissMeConsole/Sources/test.swift

418 lines
13 KiB
Swift

//
// 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 = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><response><header><resultCode>00</resultCode><resultMsg>NORMAL SERVICE.</resultMsg></header><body><items><item><korSecnNm></korSecnNm><shotnIsin>900110</shotnIsin></item><item><korSecnNm></korSecnNm><shotnIsin>000250</shotnIsin></item><item><korSecnNm></korSecnNm><shotnIsin>000440</shotnIsin></item><item><korSecnNm></korSecnNm><shotnIsin>001000</shotnIsin></item><item><korSecnNm></korSecnNm><shotnIsin>001540</shotnIsin></item><item><korSecnNm></korSecnNm><shotnIsin>001810</shotnIsin></item><item><korSecnNm></korSecnNm><shotnIsin>001840</shotnIsin></item><item><korSecnNm></korSecnNm><shotnIsin>002230</shotnIsin></item><item><korSecnNm></korSecnNm><shotnIsin>002290</shotnIsin></item><item><korSecnNm></korSecnNm><shotnIsin>005860</shotnIsin></item></items><numOfRows>10</numOfRows><pageNo>1</pageNo><totalCount>1637</totalCount></body></response>"
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("&#039;알펜시아 입찰 방해&#039; 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()
}