Implement KMI-0004 index set
This commit is contained in:
@@ -59,6 +59,63 @@ extension Date {
|
||||
let fullDate = yyyyMMdd + HHmmss
|
||||
return dateFormatter.date(from: fullDate)
|
||||
}
|
||||
|
||||
public var yyyyMMdd_split: (year: Int, month: Int, day: Int)? {
|
||||
let sets: Set<Calendar.Component> = [.year, .month, .day, .hour, .minute, .second]
|
||||
let components = Calendar.current.dateComponents(sets, from: self)
|
||||
guard let year = components.year, let month = components.month, let day = components.day else {
|
||||
return nil
|
||||
}
|
||||
return (year, month, day)
|
||||
}
|
||||
|
||||
public var HHmmss_split: (hour: Int, minute: Int, second: Int)? {
|
||||
let sets: Set<Calendar.Component> = [.year, .month, .day, .hour, .minute, .second]
|
||||
let components = Calendar.current.dateComponents(sets, from: self)
|
||||
guard let hour = components.hour, let minute = components.minute, let second = components.second else {
|
||||
return nil
|
||||
}
|
||||
return (hour, minute, second)
|
||||
}
|
||||
|
||||
public func changing(hour: Int?, min: Int?, sec: Int?, timeZone: String = "KST") -> Date? {
|
||||
let sets: Set<Calendar.Component> = [.year, .month, .day, .hour, .minute, .second]
|
||||
var components = Calendar.current.dateComponents(sets, from: self)
|
||||
components.timeZone = TimeZone(abbreviation: timeZone)
|
||||
if let hour = hour {
|
||||
components.hour = hour
|
||||
}
|
||||
if let min = min {
|
||||
components.minute = min
|
||||
}
|
||||
if let sec = sec {
|
||||
components.second = sec
|
||||
}
|
||||
components.nanosecond = 0
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
public func changing(year: Int, month: Int, day: Int, timeZone: String = "KST") -> Date? {
|
||||
let sets: Set<Calendar.Component> = [.year, .month, .day, .hour, .minute, .second]
|
||||
var components = Calendar.current.dateComponents(sets, from: self)
|
||||
components.timeZone = TimeZone(abbreviation: timeZone)
|
||||
components.year = year
|
||||
components.month = month
|
||||
components.day = day
|
||||
return Calendar.current.date(from: components)
|
||||
}
|
||||
|
||||
public mutating func change(year: Int, month: Int, day: Int, timeZone: String = "KST") {
|
||||
if let newDate = changing(year: year, month: month, day: day, timeZone: timeZone) {
|
||||
self = newDate
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ public struct Domestic {
|
||||
public typealias CandlePeriod = PeriodPriceResult.OutputPrice
|
||||
public typealias Top = VolumeRankResult.OutputDetail
|
||||
public typealias CurrentPrice = CurrentPriceResult.OutputDetail
|
||||
public typealias Investor = InvestorVolumeResult.OutputDetail
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -60,66 +60,6 @@ extension String {
|
||||
}
|
||||
|
||||
|
||||
extension Date {
|
||||
public var yyyyMMdd_split: (year: Int, month: Int, day: Int)? {
|
||||
let sets: Set<Calendar.Component> = [.year, .month, .day, .hour, .minute, .second]
|
||||
let components = Calendar.current.dateComponents(sets, from: self)
|
||||
guard let year = components.year, let month = components.month, let day = components.day else {
|
||||
return nil
|
||||
}
|
||||
return (year, month, day)
|
||||
}
|
||||
|
||||
public var HHmmss_split: (hour: Int, minute: Int, second: Int)? {
|
||||
let sets: Set<Calendar.Component> = [.year, .month, .day, .hour, .minute, .second]
|
||||
let components = Calendar.current.dateComponents(sets, from: self)
|
||||
guard let hour = components.hour, let minute = components.minute, let second = components.second else {
|
||||
return nil
|
||||
}
|
||||
return (hour, minute, second)
|
||||
}
|
||||
|
||||
public func changing(hour: Int?, min: Int?, sec: Int?, timeZone: String = "KST") -> Date? {
|
||||
let sets: Set<Calendar.Component> = [.year, .month, .day, .hour, .minute, .second]
|
||||
var components = Calendar.current.dateComponents(sets, from: self)
|
||||
components.timeZone = TimeZone(abbreviation: timeZone)
|
||||
if let hour = hour {
|
||||
components.hour = hour
|
||||
}
|
||||
if let min = min {
|
||||
components.minute = min
|
||||
}
|
||||
if let sec = sec {
|
||||
components.second = sec
|
||||
}
|
||||
components.nanosecond = 0
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
public func changing(year: Int, month: Int, day: Int, timeZone: String = "KST") -> Date? {
|
||||
let sets: Set<Calendar.Component> = [.year, .month, .day, .hour, .minute, .second]
|
||||
var components = Calendar.current.dateComponents(sets, from: self)
|
||||
components.timeZone = TimeZone(abbreviation: timeZone)
|
||||
components.year = year
|
||||
components.month = month
|
||||
components.day = day
|
||||
return Calendar.current.date(from: components)
|
||||
}
|
||||
|
||||
public mutating func change(year: Int, month: Int, day: Int, timeZone: String = "KST") {
|
||||
if let newDate = changing(year: year, month: month, day: day, timeZone: timeZone) {
|
||||
self = newDate
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension FileManager {
|
||||
|
||||
/// period: If nil, all period of csv collected.
|
||||
|
||||
@@ -15,7 +15,7 @@ extension KissConsole {
|
||||
if let output = result.output {
|
||||
print("Total output: \(output.count) productNo: \(productNo)")
|
||||
|
||||
var months = [String: [InvestorVolumeResult.OutputDetail]]()
|
||||
var months = [String: [Domestic.Investor]]()
|
||||
for item in output {
|
||||
let yyyyMM = String(item.stockBusinessDate.prefix(6))
|
||||
if let _ = months[yyyyMM] {
|
||||
|
||||
@@ -46,7 +46,7 @@ extension KissConsole {
|
||||
return true
|
||||
}
|
||||
|
||||
private func printCurrentPrice(_ output: CurrentPriceResult.OutputDetail) {
|
||||
private func printCurrentPrice(_ output: Domestic.CurrentPrice) {
|
||||
let productName = getProduct(shortCode: output.shortProductCode)?.itemName ?? ""
|
||||
print("\t종목명: ", productName)
|
||||
print("\t업종명: ", output.koreanMarketName, output.koreanBusinessTypeName ?? "")
|
||||
|
||||
@@ -23,7 +23,7 @@ extension KissConsole {
|
||||
}
|
||||
|
||||
|
||||
// MARK: 모든 prices.csv 에 컴마 데이터를 보정하는 임시코드
|
||||
// MARK: 모든 prices-yyyyMM01.csv 에 컴마 데이터를 보정하는 임시코드
|
||||
extension KissConsole {
|
||||
|
||||
private func onTest_001() {
|
||||
|
||||
@@ -8,21 +8,3 @@
|
||||
import Foundation
|
||||
|
||||
KissConsole().run()
|
||||
|
||||
|
||||
// 액면가가 1,000원 이상인 종목들 추려보자. (미챠...)
|
||||
// 액면가가 넘어가면, prices.csv 에 저장된 comma 값을 다시 수정해야 함.
|
||||
/*
|
||||
import KissMe
|
||||
|
||||
let path = URL(filePath: "/Users/ened/Kiss/KissMe/bin/data/065350/price/prices.csv")
|
||||
let data = try [CapturePrice].readCsv(fromFile: path, verifyHeader: true)
|
||||
|
||||
if let last = data.last {
|
||||
print(last)
|
||||
}
|
||||
|
||||
let shopProductsUrl = URL.currentDirectory().appending(path: "data/shop-products.csv")
|
||||
let context = ShopContext()
|
||||
context.loadShop(url: shopProductsUrl)
|
||||
*/
|
||||
|
||||
@@ -274,9 +274,9 @@ private func split_investor_csv() {
|
||||
let productNoDir = investorDir.deletingLastPathComponent()
|
||||
let productNo = productNoDir.lastPathComponent
|
||||
|
||||
let output = try [InvestorVolumeResult.OutputDetail].readCsv(fromFile: url, verifyHeader: true)
|
||||
let output = try [Domestic.Investor].readCsv(fromFile: url, verifyHeader: true)
|
||||
|
||||
var months = [String: [InvestorVolumeResult.OutputDetail]]()
|
||||
var months = [String: [Domestic.Investor]]()
|
||||
for item in output {
|
||||
let yyyyMM = String(item.stockBusinessDate.prefix(6))
|
||||
if let _ = months[yyyyMM] {
|
||||
|
||||
@@ -15,23 +15,71 @@ extension KissIndex {
|
||||
loadShop(url: KissIndex.shopProductsUrl)
|
||||
}
|
||||
|
||||
// TODO: config 를 로딩하여, 두 개의 전략중에 하나를 선택
|
||||
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
Task {
|
||||
let netSumLock = NSLock()
|
||||
var netSum = [String: Int]()
|
||||
|
||||
/// 외국인 매수의 물량이 3일 연속 증가이면, 긍정적 신호로 사용한다.
|
||||
/// 반대로 3일 연속 감소이면, 부정적 신호로 사용한다.
|
||||
///
|
||||
let investors = try await collectInvestors(date: date, recentCount: 3) { productNo, investors in
|
||||
if investors.count == 3,
|
||||
let netBuying1 = Int(investors[0].foreignNetBuyingQuantity),
|
||||
let netBuying2 = Int(investors[1].foreignNetBuyingQuantity),
|
||||
let netBuying3 = Int(investors[2].foreignNetBuyingQuantity) {
|
||||
|
||||
if (netBuying1 > 0 && netBuying2 > 0 && netBuying3 > 0) ||
|
||||
(netBuying1 < 0 && netBuying2 < 0 && netBuying3 < 0) {
|
||||
|
||||
let sum = netBuying1 + netBuying2 + netBuying3
|
||||
|
||||
netSumLock.lock()
|
||||
if let _ = netSum[productNo] {
|
||||
netSum[productNo]! += sum
|
||||
}
|
||||
else {
|
||||
netSum[productNo] = sum
|
||||
}
|
||||
netSumLock.unlock()
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var scoreMap = [String: Double]()
|
||||
for (productNo, _) in investors {
|
||||
let score: Double
|
||||
if let sum = netSum[productNo] {
|
||||
if sum < 0 {
|
||||
score = -log10(abs(Double(sum)))
|
||||
}
|
||||
else {
|
||||
score = log10(Double(sum))
|
||||
}
|
||||
}
|
||||
else {
|
||||
score = 0
|
||||
}
|
||||
|
||||
if let _ = scoreMap[productNo] {
|
||||
scoreMap[productNo]! += score
|
||||
}
|
||||
else {
|
||||
scoreMap[productNo] = score
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: work
|
||||
|
||||
normalizeAndWrite(scoreMap: scoreMap, includeName: true, kmi: kmi)
|
||||
|
||||
/// <<다른 전략>>
|
||||
/// 대상 날짜의 공매도 물량이 3일전의 공매도 물량보다 크면 선별한다.
|
||||
|
||||
semaphore.signal()
|
||||
}
|
||||
semaphore.wait()
|
||||
}
|
||||
|
||||
private func pickNearInvestorUrl(productNo: String, date: Date) {
|
||||
let subPath = "data/\(productNo)/investor"
|
||||
let subFile = "investor-\(date.yyyyMM01).csv"
|
||||
|
||||
let fileUrl = URL.currentDirectory().appending(path: subFile)
|
||||
|
||||
// TODO: work
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,6 +155,53 @@ extension KissIndex {
|
||||
}
|
||||
return prices
|
||||
}
|
||||
|
||||
func collectInvestors(date: Date, recentCount: Int, filter: @escaping (String, [Domestic.Investor]) -> Bool) async throws -> [(String,Domestic.Investor)] {
|
||||
let investors = try await withThrowingTaskGroup(of: (String, Domestic.Investor)?.self, returning: [(String, Domestic.Investor)].self) { taskGroup in
|
||||
let all = getAllProducts()
|
||||
let (yyyy, mm, dd) = date.yyyyMMdd_split!
|
||||
|
||||
for item in all {
|
||||
taskGroup.addTask {
|
||||
let investorUrl = KissIndex.pickNearInvestorUrl(productNo: item.shortCode, date: date)
|
||||
|
||||
let prevMonthDate = date.changing(year: yyyy, month: mm-1, day: dd)!
|
||||
let prevMonthInvestorUrl = KissIndex.pickNearInvestorUrl(productNo: item.shortCode, date: prevMonthDate)
|
||||
|
||||
var investors = try [Domestic.Investor].readCsv(fromFile: investorUrl)
|
||||
if let prevInvestors = try? [Domestic.Investor].readCsv(fromFile: prevMonthInvestorUrl) {
|
||||
investors.append(contentsOf: prevInvestors)
|
||||
}
|
||||
|
||||
var targetInvestors = [Domestic.Investor]()
|
||||
var prevDays = 1
|
||||
var desiredDate: Date? = date
|
||||
|
||||
while desiredDate != nil, prevDays < 20 {
|
||||
let selected = investors.filter { $0.stockBusinessDate == desiredDate!.yyyyMMdd }
|
||||
targetInvestors.append(contentsOf: selected)
|
||||
if targetInvestors.count >= recentCount {
|
||||
break
|
||||
}
|
||||
desiredDate = desiredDate!.changing(year: yyyy, month: mm, day: dd-prevDays)
|
||||
prevDays += 1
|
||||
}
|
||||
|
||||
if filter(item.shortCode, targetInvestors), let first = targetInvestors.first {
|
||||
return (item.shortCode, first)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var taskResult = [(String, Domestic.Investor)]()
|
||||
for try await result in taskGroup.compactMap( { $0 }) {
|
||||
taskResult.append(result)
|
||||
}
|
||||
return taskResult
|
||||
}
|
||||
return investors
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -173,13 +220,17 @@ extension KissIndex {
|
||||
|
||||
private static func pickNearPricesUrl(productNo: String, date: Date) -> URL {
|
||||
let subPath = "data/\(productNo)/price"
|
||||
let priceFile = "prices.csv"
|
||||
|
||||
// TODO: work month file
|
||||
//let monthFile = "prices-\(date.yyyyMM01).csv"
|
||||
let priceFile = "prices-\(date.yyyyMM01).csv"
|
||||
|
||||
return URL.currentDirectory().appending(path: "\(subPath)/\(priceFile)")
|
||||
}
|
||||
|
||||
private static func pickNearInvestorUrl(productNo: String, date: Date) -> URL {
|
||||
let subPath = "data/\(productNo)/investor"
|
||||
let investorFile = "investor-\(date.yyyyMM01).csv"
|
||||
|
||||
return URL.currentDirectory().appending(path: "\(subPath)/\(investorFile)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -187,12 +238,13 @@ extension KissIndex {
|
||||
|
||||
func normalizeAndWrite(scoreMap: [String: Double], includeName: Bool = false, kmi: KissIndexType) {
|
||||
|
||||
let totalScores = scoreMap.reduce(0, { $0 + $1.value })
|
||||
let positiveTotalScores = scoreMap.reduce(0, { $0 + ($1.value > 0 ? $1.value: 0) })
|
||||
let negativeTotalScores = abs(scoreMap.reduce(0, { $0 + ($1.value < 0 ? $1.value: 0) }))
|
||||
let scoreArray = scoreMap.map { ($0.key, $0.value) }.sorted(by: { $0.1 > $1.1 })
|
||||
|
||||
var outputs = [KissIndexResult.Output]()
|
||||
for array in scoreArray {
|
||||
let weight = Double(array.1) / Double(totalScores)
|
||||
let weight = Double(array.1) / (array.1 > 0 ? Double(positiveTotalScores): Double(negativeTotalScores))
|
||||
let name: String? = (includeName ? getProduct(shortCode: array.0)?.itemName: nil)
|
||||
let output = KissIndexResult.Output(shortCode: array.0, productName: name, weight: weight)
|
||||
outputs.append(output)
|
||||
|
||||
49
README.md
49
README.md
@@ -24,7 +24,7 @@ Command | 설명
|
||||
`cancel (PNO) (ONO) (수량)` | 주문 내역의 일부를 취소. (수량) 에 -82 로 입력하면 전체수량.
|
||||
WIP `modify (PNO) (ONO) (가격) (수량)` | 주문 내역을 변경. (수량) 에 -82 로 입력하면 전체수량.
|
||||
`open bag` | 보유 종목 열람. 보유 주식은 **data/account-stocks.csv** 파일로 저장. 잔고 상황은 **data/account-amount.csv** 파일로 저장.
|
||||
`now [PNO]` | 종목의 현재가 열람. PNO 은 생략 가능. **data/(PNO)/price/prices.csv** 파일로 저장.
|
||||
`now [PNO]` | 종목의 현재가 열람. PNO 은 생략 가능. **data/(PNO)/price/prices-(yyyyMM01).csv** 파일로 저장.
|
||||
`candle [PNO]` | 종목의 분봉 열람. PNO 은 생략 가능. **data/(PNO)/min/candle-(yyyyMMdd).csv** 파일로 저장.
|
||||
`candle all [resume]` | 모든 종목의 분봉 열람. cron job 으로 돌리기 위해서 추가. **data/(PNO)/min/candle-(yyyyMMdd).csv** 파일로 저장. (resume) 을 기입하면, 이미 받은 파일은 검사하여, 데이터에 오류가 있으면 다시 받고 오류가 없으면 새롭게 열람하지 않음.
|
||||
`candle day [PNO]` | 종목의 최근 250일 동안의 일봉 열람. PNO 은 생략 가능. **data/(PNO)/day/candle-(yyyyMMdd).csv** 파일로 저장.
|
||||
@@ -32,10 +32,10 @@ WIP `modify (PNO) (ONO) (가격) (수량)` | 주문 내역을 변경. (수량)
|
||||
`candle week [PNO]` | 종목의 최근 52주 동안의 주봉 열람. PNO 은 생략 가능. **data/(PNO)/week/candle-(yyyyMMdd).csv** 파일로 저장.
|
||||
`candle week all [resume]` | 모든 종목의 최근 52주 동안의 주봉 열람. cron job 으로 오전 장이 시작전에 미리 수집. **data/(PNO)/week/candle-(yyyyMMdd).csv** 파일로 저장.
|
||||
`candle validate (기간)` | (기간) 타입의 모든 csv 파일에 대해서 데이터가 유효한지 검사. (기간) 으로는 **min**, **day**, **week** 을 지정하고, 생략되면 **min** 으로 간주.
|
||||
`investor [PNO]` | 종목의 투자자 거래량 열람. PNO 은 생략 가능. **data/(PNO)/investor/investor-(yyyyMMdd).csv** 파일로 저장.
|
||||
`investor all` | 모든 종목의 투자자 거래량 열람. **data/(PNO)/investor/investor-(yyyyMMdd).csv** 파일로 저장.
|
||||
`shorts [PNO]` | 공매도 잔고를 열람. PNO 은 생략 가능. **data/shorts/(yyyy)/shorts-(yyyyMMdd).csv** 파일로 저장.
|
||||
`shorts all [resume]` | 모든 종목의 공매도 잔고를 열람. **data/shorts/(yyyy)/shorts-(yyyyMMdd).csv** 파일로 저장.
|
||||
`investor [PNO]` | 종목의 투자자 거래량 열람. PNO 은 생략 가능. **data/(PNO)/investor/investor-(yyyyMM01).csv** 파일로 저장.
|
||||
`investor all` | 모든 종목의 투자자 거래량 열람. **data/(PNO)/investor/investor-(yyyyMM01).csv** 파일로 저장.
|
||||
`shorts [PNO]` | 공매도 잔고를 열람. PNO 은 생략 가능. **data/shorts/(yyyy)/shorts-(yyyyMM01).csv** 파일로 저장.
|
||||
`shorts all [resume]` | 모든 종목의 공매도 잔고를 열람. **data/shorts/(yyyy)/shorts-(yyyyMM01).csv** 파일로 저장.
|
||||
`load shop` | data/shop-products.csv 로부터 전체 상품을 로딩.
|
||||
`update shop` | **금융위원회_KRX상장종목정보** 로부터 전체 상품을 얻어서 **data/shop-products.csv** 로 저장.
|
||||
`look (상품명)` | (상품명) 에 해당되는 PNO 를 표시함.
|
||||
@@ -67,24 +67,12 @@ KISS_ASSERT_COMMA_CSV_DATA | `true`, `1` 이면, CSV 데이터에 comma 문자
|
||||
|
||||
KissMeIndex 는 지표 집합(index set)을 추출하는 도구입니다.
|
||||
|
||||
## INPUT
|
||||
다음은 지표 데이터를 추출하는 예제입니다.
|
||||
|
||||
INPUT 으로는 다음과 같은 값을 제공합니다.
|
||||
|
||||
* 환경설정 : config.json 파일로 특정 지표에서 보정으로 필요로 하는 설정을 기입합니다.
|
||||
* 현재시간 : timestamp 값을 반드시 필요로 합니다. simulator 에서도 이 기능을 활용할 수 있습니다.
|
||||
|
||||
## OUTPUT
|
||||
|
||||
OUTPUT 은 다음과 같은 값을 json 형태로 제공합니다.
|
||||
|
||||
* shortCode : 추천종목 코드 번호입니다.
|
||||
* weight : [-1.0, 1.0] 사이의 가중치 값입니다. 음수이면 매도 성향이고, 양수이면 매수성향입니다.
|
||||
|
||||
## Example
|
||||
첫라인은 INPUT 이고, 이후의 json 데이터는 OUTPUT 입니다.
|
||||
|
||||
```bash
|
||||
./KissMeIndex KMI-0001 20230616 100000 config.json
|
||||
./KissMeIndex KMI-0005 20230616 105900 config.json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "OK",
|
||||
@@ -102,6 +90,27 @@ OUTPUT 은 다음과 같은 값을 json 형태로 제공합니다.
|
||||
}
|
||||
```
|
||||
|
||||
### INPUT
|
||||
|
||||
* (indexApp) KMI-(number) (date) (time) (config.json)
|
||||
* (indexApp) 는 지표를 추출하는 app binary 입니다. INPUT, OUTPUT 형식만 맞출 수 있다면, 다양한 도구를 통해서 만들 수 있습니다.
|
||||
* KMI-(number) 는 고유의 지표 번호입니다. 하나의 app 에서 여러 지표를 추출할 수 있습니다.
|
||||
* (date) 는 yyyyMMdd 형식의 날짜입니다.
|
||||
* (time) 는 HHmmss 형식의 시간입니다.
|
||||
* (config.json) 는 config 로 상세한 설정을 할 수 있는 json 파일입니다. 여기의 내용은 (indexApp) 과 KMI-(number) 에 따라서 다르게 구성될 수 있습니다.
|
||||
|
||||
### OUTPUT
|
||||
|
||||
json 파일 형식으로 결과를 제공합니다.
|
||||
|
||||
* `code`: 에러코드입니다. `200` 은 성공입니다.
|
||||
* `message`: 상세한 메시지를 의미합니다. 성공하면 `OK` 로 표시합니다.
|
||||
* `kmi`: 데이터로 제공되는 KMI 지표입니다.
|
||||
* `output`: 지표 데이터 배열입니다.
|
||||
* `shortCode` : 추천종목 코드 번호
|
||||
* `productName` : 종목명
|
||||
* `weight` : [-1.0, 1.0] 사이의 가중치 값입니다. 음수이면 매도 성향이고, 양수이면 매수성향입니다.
|
||||
|
||||
|
||||
# KissMeMatrix
|
||||
|
||||
|
||||
@@ -39,26 +39,6 @@
|
||||
}
|
||||
```
|
||||
|
||||
### INPUT
|
||||
* (indexApp) KMI-(number) (date) (time) (config.json)
|
||||
* (indexApp) 는 지표를 추출하는 app binary 입니다. INPUT, OUTPUT 형식만 맞출 수 있다면, 다양한 도구를 통해서 만들 수 있습니다.
|
||||
* KMI-(number) 는 고유의 지표 번호입니다. 하나의 app 에서 여러 지표를 추출할 수 있습니다.
|
||||
* (date) 는 yyyyMMdd 형식의 날짜입니다.
|
||||
* (time) 는 HHmmss 형식의 시간입니다.
|
||||
* (config.json) 는 config 로 상세한 설정을 할 수 있는 json 파일입니다. 여기의 내용은 (indexApp) 과 KMI-(number) 에 따라서 다르게 구성될 수 있습니다.
|
||||
|
||||
### OUTPUT
|
||||
|
||||
json 파일 형식으로 결과를 제공합니다.
|
||||
|
||||
* `code`: 에러코드. `200` 은 성공.
|
||||
* `message`: 상세한 메시지. 성공하면 `OK`.
|
||||
* `kmi`: 요청에 제공되는 KMI 지표
|
||||
* `output`: 지표 데이터
|
||||
* `shortCode` : 추천종목 코드 번호
|
||||
* `productName` : 종목명
|
||||
* `weight` : [-1.0, 1.0] 사이의 가중치 값. 음수이면 매도 성향이고, 양수이면 매수성향.
|
||||
|
||||
### Configuration
|
||||
|
||||
(config.json) 현재 지원하는 환경설정 정보가 없습니다.
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "KMI-0003 20230621 100000"
|
||||
argument = "KMI-0004 20230622 100000"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
|
||||
Reference in New Issue
Block a user