Add db command
This commit is contained in:
@@ -220,26 +220,44 @@ class CandleMinuteFileName {
|
||||
|
||||
extension KissConsole {
|
||||
|
||||
func collectCandleMinuteFiles() -> [String: [URL]] {
|
||||
guard let enumerator = FileManager.subPathFiles("data") else {
|
||||
func subPathForProduct(productNo: String?) -> FileManager.DirectoryEnumerator? {
|
||||
if let productNo = productNo {
|
||||
return FileManager.subPathFiles("data/\(productNo)")
|
||||
}
|
||||
else {
|
||||
return FileManager.subPathFiles("data")
|
||||
}
|
||||
}
|
||||
|
||||
func collectCandleMinuteFiles(productNo: String?, year: String?, month: String?) -> [String: [URL]] {
|
||||
guard let enumerator = subPathForProduct(productNo: productNo) else {
|
||||
return [:]
|
||||
}
|
||||
|
||||
let candleMinName = CandleMinuteFileName()
|
||||
var allCandles = [String: [URL]]()
|
||||
var candleFiles = [String: [URL]]()
|
||||
for case let fileUrl as URL in enumerator {
|
||||
guard let (productNo, _) = candleMinName.matchedUrl(fileUrl.path) else {
|
||||
guard let (fileProductNo, yyyyMMdd) = candleMinName.matchedUrl(fileUrl.path) else {
|
||||
continue
|
||||
}
|
||||
if let productNo = productNo, productNo != fileProductNo {
|
||||
continue
|
||||
}
|
||||
if let year = year, yyyyMMdd.prefix(4) != year {
|
||||
continue
|
||||
}
|
||||
if let month = month, yyyyMMdd.dropFirst(4).prefix(2) != month {
|
||||
continue
|
||||
}
|
||||
|
||||
if allCandles.keys.contains(productNo) {
|
||||
allCandles[productNo]!.append(fileUrl)
|
||||
if candleFiles.keys.contains(fileProductNo) {
|
||||
candleFiles[fileProductNo]!.append(fileUrl)
|
||||
}
|
||||
else {
|
||||
allCandles[productNo] = [fileUrl]
|
||||
candleFiles[fileProductNo] = [fileUrl]
|
||||
}
|
||||
}
|
||||
return allCandles
|
||||
return candleFiles
|
||||
}
|
||||
|
||||
func buildCandleMinuteDB(productNo: String, csvFiles: [URL], removeOldDB: Bool = false) {
|
||||
|
||||
@@ -104,6 +104,9 @@ class KissConsole: KissMe.ShopContext {
|
||||
// 웹소켓
|
||||
case real = "real"
|
||||
|
||||
// DB1
|
||||
case db = "db"
|
||||
|
||||
// 뉴스
|
||||
case news = "news"
|
||||
case newsAll = "news all"
|
||||
@@ -136,6 +139,8 @@ class KissConsole: KissMe.ShopContext {
|
||||
return true
|
||||
case .real:
|
||||
return true
|
||||
case .db:
|
||||
return true
|
||||
case .news, .newsAll:
|
||||
return false
|
||||
}
|
||||
@@ -283,6 +288,8 @@ class KissConsole: KissMe.ShopContext {
|
||||
case .test: onTest(args)
|
||||
|
||||
case .real: await onReal(args)
|
||||
|
||||
case .db: await onDB(args)
|
||||
|
||||
case .news: await onNews(args)
|
||||
case .newsAll: onNewsAll(args)
|
||||
@@ -1253,6 +1260,48 @@ extension KissConsole {
|
||||
}
|
||||
|
||||
|
||||
private func onDB(_ args: [String]) async {
|
||||
guard args.count >= 3 else {
|
||||
print("Missing options")
|
||||
return
|
||||
}
|
||||
guard args[0] == "candle" else {
|
||||
print("Missing candle or something")
|
||||
return
|
||||
}
|
||||
switch args[1] {
|
||||
case "build":
|
||||
onDB_Build(Array(args.dropFirst(2)))
|
||||
case "validate":
|
||||
onDB_Validate(Array(args.dropFirst(2)))
|
||||
case "count":
|
||||
onDB_Count(Array(args.dropFirst(2)))
|
||||
default:
|
||||
onDB_Select(Array(args.dropFirst(2)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func onDB_Build(_ args: [String]) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
private func onDB_Validate(_ args: [String]) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
private func onDB_Count(_ args: [String]) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
private func onDB_Select(_ args: [String]) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
private func onNews(_ args: [String]) async {
|
||||
guard args.count == 1, let day = args[0].yyyyMMdd_toDate else {
|
||||
print("Missing day")
|
||||
|
||||
@@ -52,14 +52,9 @@ struct DB1_CandleData_Tests: KissTestCase {
|
||||
let csvFiles = Self.collectCsv(productNo: productNo, yyyy: year, MM: month)
|
||||
let dataPath = URL.currentDirectory().appending(path: "data")
|
||||
|
||||
var itemCount = 0
|
||||
for csvFile in csvFiles {
|
||||
let candleMinName = CandleMinuteFileName()
|
||||
if let (_, yyyyMMdd) = candleMinName.matchedUrl(csvFile.path), let year = Int(yyyyMMdd.prefix(4)) {
|
||||
let yearDbPath = dataPath.appending(path: "\(productNo)/min/candle-\(year).db1")
|
||||
}
|
||||
|
||||
let yearDbPath = dataPath.appending(path: "\(productNo)/min/candle-\(year).db1")
|
||||
try? FileManager.default.removeItem(at: yearDbPath)
|
||||
try? FileManager.default.createDirectory(at: yearDbPath, withIntermediateDirectories: true)
|
||||
|
||||
do {
|
||||
@@ -74,6 +69,7 @@ struct DB1_CandleData_Tests: KissTestCase {
|
||||
try db.insertData(item: item)
|
||||
|
||||
assertEqual(candleData.candle, candle)
|
||||
itemCount += 1
|
||||
}
|
||||
|
||||
try db.commit()
|
||||
@@ -81,6 +77,7 @@ struct DB1_CandleData_Tests: KissTestCase {
|
||||
print("\(error)")
|
||||
}
|
||||
}
|
||||
Self.insertCount = itemCount
|
||||
}
|
||||
|
||||
let test_5_CountSamsungDB: () -> Void = {
|
||||
@@ -94,13 +91,17 @@ struct DB1_CandleData_Tests: KissTestCase {
|
||||
let db = try KissDB(directory: yearDbPath)
|
||||
try db.begin()
|
||||
|
||||
var itemCount = 0
|
||||
try db.selectData(into: { (dataItem: KissDB.DataItem) -> Bool in
|
||||
let candleData = CandleData(key: dataItem.key, data: dataItem.value)
|
||||
assertEqual(String(candleData.candleDate.prefix(6)), yyyyMM)
|
||||
itemCount += 1
|
||||
return true
|
||||
})
|
||||
|
||||
try db.rollback()
|
||||
|
||||
assertEqual(Self.insertCount, itemCount)
|
||||
} catch {
|
||||
print("\(error)")
|
||||
}
|
||||
@@ -109,6 +110,7 @@ struct DB1_CandleData_Tests: KissTestCase {
|
||||
static let samsungProductNo = "005930"
|
||||
static let year = "2023"
|
||||
static let month = "06"
|
||||
static var insertCount: Int = 0
|
||||
|
||||
static func collectCsv(productNo: String, yyyy: String, MM: String) -> [URL] {
|
||||
guard let enumerator = FileManager.subPathFiles("data/\(productNo)") else {
|
||||
|
||||
@@ -44,7 +44,7 @@ WIP `modify (PNO) (ONO) (가격) (수량)` | 주문 내역을 변경. (수량)
|
||||
`look (상품명)` | (상품명) 에 해당되는 PNO 를 표시함.
|
||||
`load index` | data/index-products.csv 로부터 전체 지수 상품을 로딩.
|
||||
`update index` | **KRX 지수** 로부터 전체 지수 상품을 얻어서 **data/index-products.csv** 로 저장.
|
||||
`holiday [yyyyMMdd]` | 휴장일 여부를 판단함. yyyymmDD 를 생략하면 오늘 날짜로 확인. **data/holiday.csv** 로 저장.
|
||||
`holiday [yyyyMMdd]` | 휴장일 여부를 판단함. yyyyMMdd 를 생략하면 오늘 날짜로 확인. **data/holiday.csv** 로 저장.
|
||||
WIP `showcase` | 추천 상품을 제안함.
|
||||
`loves` | 관심 종목 전체를 열람. profile.json 에 저장된 관심 종목을 표시함.
|
||||
`love (탭).(번호) (PNO)` | 관심 종목에 추가함. (번호) 를 지정하지 않으면 (탭) 마지막에 추가함.
|
||||
@@ -52,6 +52,10 @@ WIP `showcase` | 추천 상품을 제안함.
|
||||
`localize names` | csv field name 에 대해서 한글명을 제공하는 **data/localized-names.csv** 를 저장.
|
||||
`localize (on/off)`| 앞으로 저장하는 모든 csv file 의 field 에 (on) 이면 한글명으로, (off) 이면 영문으로 저장.
|
||||
`real (PNO) (on/off)` | 실시간 웹소켓을 접속하여 수신된 데이터를 기록합니다. (on) 이면 파일로 기록, (off) 이면 기록하지 않음.
|
||||
`db candle build [PNO] [yyyy] [MM] [dd]` | PNO 의 csv 파일로부터 지정된 yyyy, MM, dd 날짜에 대해서만 DB 로 빌드. **data/(PNO)/min/candle-(yyyy).db1** 파일에 저장.
|
||||
`db candle validate [PNO] [yyyy]` | PNO 의 yyyy DB에 기록된 분봉에 대해서 유효한지 검사.
|
||||
`db candle count [PNO] [yyyy]` | PNO 의 yyyy DB에 기록된 분봉 갯수를 열람.
|
||||
`db candle (PNO) [yyyyMMdd] [HH]` | PNO 의 yyyyMMdd 날짜의 HH 시간의 모든 분봉을 열람.
|
||||
|
||||
* PNO 는 `Product NO` 의 약자이고, 상품의 `단축코드` (shortCode) 와 동일합니다.
|
||||
* ONO 는 `Order NO` 의 약자이고, 고유한 주문번호 입니다.
|
||||
|
||||
Reference in New Issue
Block a user