Write candle data

This commit is contained in:
2023-05-29 15:49:39 +09:00
parent 51725b1826
commit 79ab809e9e
7 changed files with 150 additions and 39 deletions

View File

@@ -1,5 +1,5 @@
//
// Extensions.swift
// Foundation+Extensions.swift
// KissMe
//
// Created by ened-book-m1 on 2023/05/17.
@@ -39,6 +39,23 @@ extension Date {
}
extension String {
public var HHmmss: (Int, Int, Int)? {
guard utf8.count == 6 else {
return nil
}
let mmStartIndex = index(startIndex, offsetBy: 2)
let mmEndIndex = index(mmStartIndex, offsetBy: 2)
guard let hh = Int(String(prefix(2))),
let mm = Int(self[mmStartIndex..<mmEndIndex]),
let ss = Int(String(suffix(2))) else {
return nil
}
return (hh, mm, ss)
}
}
#if os(Linux) || os(Windows) || os(FreeBSD)
extension URL {
public static func currentDirectory() -> URL {

View File

@@ -134,7 +134,7 @@ extension KissAccount {
///
///
public func getMinutePrice(productNo: String, startTodayTime: Date) async throws -> MinutePriceResult {
public func getMinutePrice(productNo: String, startTodayTime: Date, more: Bool = false) async throws -> MinutePriceResult {
return try await withUnsafeThrowingContinuation { continuation in
guard let accessToken = accessToken else {
@@ -142,7 +142,7 @@ extension KissAccount {
return
}
let request = Domestic.StockTodayMinutePriceRequest(credential: credential, accessToken: accessToken, productNo: productNo, startTodayTime: startTodayTime.HHmmss, isNext: false)
let request = Domestic.StockTodayMinutePriceRequest(credential: credential, accessToken: accessToken, productNo: productNo, startTodayTime: startTodayTime.HHmmss, isNext: more)
request.query { result in
switch result {
case .success(let result):

View File

@@ -1,5 +1,5 @@
//
// ConsoleExtensions.swift
// Foundation+Extensions.swift
// KissMeConsole
//
// Created by ened-book-m1 on 2023/05/26.
@@ -50,4 +50,10 @@ extension Date {
components.second = sec
return Calendar.current.date(from: components)
}
public mutating func change(hour: Int, min: Int, sec: Int, timeZone: String = "KST") {
if let newDate = changing(hour: hour, min: min, sec: sec, timeZone: timeZone) {
self = newDate
}
}
}

View File

@@ -0,0 +1,60 @@
//
// KissConsole+CSV.swift
// KissMeConsole
//
// Created by ened-book-m1 on 2023/05/29.
//
import Foundation
import KissMe
extension KissConsole {
func writeShop(_ shopItems: [DomesticShop.Product], fileUrl: URL) {
var stringCsv: String = ""
let header = "baseDate,shortCode,isinCode,marketCategory,itemName,corporationNo,\n"
stringCsv.append(header)
for item in shopItems {
let stringItem = [item.baseDate,
item.shortCode,
item.isinCode,
item.marketCategory,
item.itemName.trimmingCharacters(in: .whitespaces),
item.corporationNo].joined(separator: ",")
stringCsv.append(stringItem)
stringCsv.append("\n")
}
do {
try stringCsv.write(toFile: fileUrl.path, atomically: true, encoding: .utf8)
print("wrote \(fileUrl.lastPathComponent) with \(shopItems.count)")
} catch {
print("\(error)")
}
}
func writeCandle(_ prices: [MinutePriceResult.OutputPrice], fileUrl: URL) {
var stringCsv: String = "stockBusinessDate,stockConclusionTime,accumulatedTradingAmount,currentStockPrice,secondStockPrice,highestStockPrice,lowestStockPrice,conclusionVolume"
let header = ""
stringCsv.append(header)
for item in prices {
let stringItem = [item.stockBusinessDate,
item.stockConclusionTime,
item.accumulatedTradingAmount,
item.currentStockPrice,
item.secondStockPrice,
item.highestStockPrice,
item.lowestStockPrice,
item.conclusionVolume].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)")
}
}
}

View File

@@ -164,10 +164,6 @@ extension KissConsole {
try? FileManager.default.createDirectory(at: subPath, withIntermediateDirectories: true)
}
private var shopProducts: URL {
URL.currentDirectory().appending(path: "data/shop-products.csv")
}
private func setProducts(_ products: [String: [DomesticShop.Product]]) {
productsLock.lock()
self.products = products
@@ -201,9 +197,13 @@ extension KissConsole {
return products.compactMap { $0.value.first(where: { $0.shortCode == shortCode }) }.first
}
private var shopProductsUrl: URL {
URL.currentDirectory().appending(path: "data/shop-products.csv")
}
private func loadShop(_ profile: Bool = false) {
let appTime1 = Date.appTime
guard let stringCsv = try? String(contentsOfFile: shopProducts.path) else {
guard let stringCsv = try? String(contentsOfFile: shopProductsUrl.path) else {
return
}
@@ -267,6 +267,7 @@ extension KissConsole {
}
}
extension KissConsole {
private func onLogin(isMock: Bool) async {
@@ -292,6 +293,7 @@ extension KissConsole {
_ = try await account?.logout()
credential = nil
account = nil
print("Success")
} catch {
print("\(error)")
}
@@ -433,16 +435,40 @@ extension KissConsole {
}
do {
let lastWeek = Date().addingTimeInterval(-60 * 60 * 24 * 7)
guard let startTime = lastWeek.changing(hour: 9, min: 0, sec: 0) else {
print("Invalid start time")
var nextTime = Date()
nextTime.change(hour: 17, min: 0, sec: 0)
var candles = [MinutePriceResult.OutputPrice]()
var count = 0
while count < 3 {
let more = (count > 0)
count += 1
print("minute price \(productNo) from \(nextTime.yyyyMMdd_HHmmss_forTime) \(more)")
let result = try await account!.getMinutePrice(productNo: productNo, startTodayTime: nextTime, more: more)
if let prices = result.output2 {
candles.append(contentsOf: prices)
if let last = prices.last {
if let (hh, mm, ss) = last.stockConclusionTime.HHmmss {
print("next: \(last.stockConclusionTime) / \(hh) \(mm) \(ss)")
nextTime.change(hour: hh, min: mm-1, sec: ss)
}
}
}
}
candles.sort(by: { $0.stockBusinessDate < $1.stockBusinessDate })
guard let minTime = candles.first?.stockBusinessDate else {
print("No price items")
return
}
let result = try await account!.getMinutePrice(productNo: productNo, startTodayTime: startTime)
// TODO: work on result
print(result)
let subPath = "data/\(productNo)"
let subFile = "\(subPath)/candle-\(minTime).csv"
let fileUrl = URL.currentDirectory().appending(path: subFile)
createSubpath(subPath)
writeCandle(candles, fileUrl: fileUrl)
} catch {
print("\(error)")
}
@@ -478,21 +504,7 @@ extension KissConsole {
}
}
var stringCsv: String = ""
let header = "baseDate,shortCode,isinCode,marketCategory,itemName,corporationNo,\n"
stringCsv.append(header)
for item in shopItems {
let stringItem = [item.baseDate, item.shortCode, item.isinCode, item.marketCategory, item.itemName.trimmingCharacters(in: .whitespaces), item.corporationNo].joined(separator: ",")
stringCsv.append(stringItem)
stringCsv.append("\n")
}
do {
try stringCsv.write(toFile: shopProducts.path, atomically: true, encoding: .utf8)
print("wrote \(shopProducts.lastPathComponent) with \(shopItems.count)")
} catch {
print("\(error)")
}
writeShop(shopItems, fileUrl: shopProductsUrl)
}
private func getAllProduct(baseDate: Date) async -> [DomesticShop.Product] {
@@ -562,6 +574,7 @@ extension KissConsole {
}
}
private func onLove(_ args: [String]) async {
guard let account = account else { return }
guard args.count > 0 else {

View File

@@ -27,7 +27,7 @@
341F5EFF2A10955D00962D48 /* OrderRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5EFE2A10955D00962D48 /* OrderRequest.swift */; };
341F5F012A11155100962D48 /* DomesticStockSearchResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5F002A11155100962D48 /* DomesticStockSearchResult.swift */; };
341F5F032A11A2BC00962D48 /* Credential.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5F022A11A2BC00962D48 /* Credential.swift */; };
341F5F072A14634F00962D48 /* KissExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5F062A14634F00962D48 /* KissExtensions.swift */; };
341F5F072A14634F00962D48 /* Foundation+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5F062A14634F00962D48 /* Foundation+Extensions.swift */; };
341F5F0B2A15115400962D48 /* KissShop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5F0A2A15115400962D48 /* KissShop.swift */; };
341F5F0D2A15222E00962D48 /* AuthRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5F0C2A15222E00962D48 /* AuthRequest.swift */; };
341F5F0F2A15223A00962D48 /* SeibroRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5F0E2A15223A00962D48 /* SeibroRequest.swift */; };
@@ -68,7 +68,7 @@
341F5EFE2A10955D00962D48 /* OrderRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderRequest.swift; sourceTree = "<group>"; };
341F5F002A11155100962D48 /* DomesticStockSearchResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomesticStockSearchResult.swift; sourceTree = "<group>"; };
341F5F022A11A2BC00962D48 /* Credential.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Credential.swift; sourceTree = "<group>"; };
341F5F062A14634F00962D48 /* KissExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KissExtensions.swift; sourceTree = "<group>"; };
341F5F062A14634F00962D48 /* Foundation+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Foundation+Extensions.swift"; sourceTree = "<group>"; };
341F5F0A2A15115400962D48 /* KissShop.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KissShop.swift; sourceTree = "<group>"; };
341F5F0C2A15222E00962D48 /* AuthRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequest.swift; sourceTree = "<group>"; };
341F5F0E2A15223A00962D48 /* SeibroRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeibroRequest.swift; sourceTree = "<group>"; };
@@ -183,7 +183,7 @@
341F5F0E2A15223A00962D48 /* SeibroRequest.swift */,
341F5F102A1685E700962D48 /* ShopRequest.swift */,
341F5F022A11A2BC00962D48 /* Credential.swift */,
341F5F062A14634F00962D48 /* KissExtensions.swift */,
341F5F062A14634F00962D48 /* Foundation+Extensions.swift */,
);
path = Common;
sourceTree = "<group>";
@@ -307,7 +307,7 @@
files = (
341F5EFB2A10909D00962D48 /* LoginResult.swift in Sources */,
341F5F0B2A15115400962D48 /* KissShop.swift in Sources */,
341F5F072A14634F00962D48 /* KissExtensions.swift in Sources */,
341F5F072A14634F00962D48 /* Foundation+Extensions.swift in Sources */,
341F5F032A11A2BC00962D48 /* Credential.swift in Sources */,
341F5EB02A0A80EC00962D48 /* KissMe.docc in Sources */,
341F5EFD2A10931B00962D48 /* DomesticStockSearch.swift in Sources */,

View File

@@ -10,7 +10,8 @@
341F5ED42A0A8B9000962D48 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5ED32A0A8B9000962D48 /* main.swift */; };
341F5F052A13B82F00962D48 /* test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5F042A13B82F00962D48 /* test.swift */; };
341F5F092A1463A100962D48 /* KissConsole.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5F082A1463A100962D48 /* KissConsole.swift */; };
349327F72A20E3E300097063 /* ConsoleExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349327F62A20E3E300097063 /* ConsoleExtensions.swift */; };
349327F72A20E3E300097063 /* Foundation+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349327F62A20E3E300097063 /* Foundation+Extensions.swift */; };
349843212A242AC900E85B08 /* KissConsole+CSV.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349843202A242AC900E85B08 /* KissConsole+CSV.swift */; };
34EE76862A1C391B009761D2 /* KissMe.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 341F5EDB2A0A8C4600962D48 /* KissMe.framework */; };
34EE76872A1C391B009761D2 /* KissMe.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 341F5EDB2A0A8C4600962D48 /* KissMe.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
/* End PBXBuildFile section */
@@ -44,7 +45,9 @@
341F5EDB2A0A8C4600962D48 /* KissMe.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = KissMe.framework; sourceTree = BUILT_PRODUCTS_DIR; };
341F5F042A13B82F00962D48 /* test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = test.swift; sourceTree = "<group>"; };
341F5F082A1463A100962D48 /* KissConsole.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KissConsole.swift; sourceTree = "<group>"; };
349327F62A20E3E300097063 /* ConsoleExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsoleExtensions.swift; sourceTree = "<group>"; };
349327F62A20E3E300097063 /* Foundation+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Foundation+Extensions.swift"; sourceTree = "<group>"; };
3498431E2A24287600E85B08 /* KissMeConsoleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KissMeConsoleTests.swift; sourceTree = "<group>"; };
349843202A242AC900E85B08 /* KissConsole+CSV.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KissConsole+CSV.swift"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -63,6 +66,7 @@
isa = PBXGroup;
children = (
341F5ED22A0A8B9000962D48 /* KissMeConsole */,
3498431D2A24284600E85B08 /* KissMeConsoleTests */,
341F5ED12A0A8B9000962D48 /* Products */,
341F5EDA2A0A8C4600962D48 /* Frameworks */,
);
@@ -82,7 +86,8 @@
341F5ED32A0A8B9000962D48 /* main.swift */,
341F5F042A13B82F00962D48 /* test.swift */,
341F5F082A1463A100962D48 /* KissConsole.swift */,
349327F62A20E3E300097063 /* ConsoleExtensions.swift */,
349843202A242AC900E85B08 /* KissConsole+CSV.swift */,
349327F62A20E3E300097063 /* Foundation+Extensions.swift */,
);
name = KissMeConsole;
path = ../../KissMeConsole/Sources;
@@ -96,6 +101,15 @@
name = Frameworks;
sourceTree = "<group>";
};
3498431D2A24284600E85B08 /* KissMeConsoleTests */ = {
isa = PBXGroup;
children = (
3498431E2A24287600E85B08 /* KissMeConsoleTests.swift */,
);
name = KissMeConsoleTests;
path = ../../KissMeConsole/Tests;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -156,9 +170,10 @@
buildActionMask = 2147483647;
files = (
341F5ED42A0A8B9000962D48 /* main.swift in Sources */,
349327F72A20E3E300097063 /* ConsoleExtensions.swift in Sources */,
349327F72A20E3E300097063 /* Foundation+Extensions.swift in Sources */,
341F5F092A1463A100962D48 /* KissConsole.swift in Sources */,
341F5F052A13B82F00962D48 /* test.swift in Sources */,
349843212A242AC900E85B08 /* KissConsole+CSV.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};