Show current stock balance

This commit is contained in:
2023-05-27 00:15:45 +09:00
parent 174206e1a3
commit fa6c18a99c
6 changed files with 317 additions and 14 deletions

View File

@@ -148,7 +148,7 @@ public struct Domestic {
/// - [v1_-006]
///
public struct StockBalanceRequest: OrderRequest {
public typealias KResult = String
public typealias KResult = BalanceResult
public var url: String {
"/uapi/domestic-stock/v1/trading/inquire-balance"
@@ -161,6 +161,7 @@ public struct Domestic {
"appkey": credential.appKey,
"appsecret": credential.appSecret,
"tr_id": trId,
"tr_cont": isNext ? "N": " ",
]
}
public var body: [String: Any] {
@@ -184,18 +185,20 @@ public struct Domestic {
private var trId: String {
if credential.isMock {
return "VTTC0803U"
return "VTTC8434R"
}
else {
return "TTTC0803U"
return "TTTC8434R"
}
}
public let accessToken: String
let isNext: Bool
public init(credential: Credential, accessToken: String) {
public init(credential: Credential, accessToken: String, isNext: Bool) {
self.credential = credential
self.accessToken = accessToken
self.isNext = isNext
}
}
@@ -203,7 +206,7 @@ public struct Domestic {
/// - [v1_-007]
///
public struct StockPossibleOrderRequest: OrderRequest {
public typealias KResult = OrderPossibleResult
public typealias KResult = PossibleOrderResult
public var url: String {
"/uapi/domestic-stock/v1/trading/inquire-psbl-order"
@@ -216,6 +219,7 @@ public struct Domestic {
"appkey": credential.appKey,
"appsecret": credential.appSecret,
"tr_id": trId,
"tr_cont": isNext ? "N": " ",
]
}
public var body: [String: Any] {
@@ -247,13 +251,15 @@ public struct Domestic {
let orderDivision: OrderDivision
let orderPrice: Int
let isNext: Bool
public init(credential: Credential, accessToken: String, productNo: String, orderDivision: OrderDivision, orderPrice: Int) {
public init(credential: Credential, accessToken: String, productNo: String, orderDivision: OrderDivision, orderPrice: Int, isNext: Bool) {
self.credential = credential
self.accessToken = accessToken
self.productNo = productNo
self.orderDivision = orderDivision
self.orderPrice = orderPrice
self.isNext = isNext
}
}
}
@@ -326,7 +332,7 @@ extension KissAccount {
}
public func getStockBalance() async throws -> Bool {
public func getStockBalance() async throws -> BalanceResult {
return try await withUnsafeThrowingContinuation { continuation in
guard let accessToken = accessToken else {
@@ -334,12 +340,20 @@ extension KissAccount {
return
}
// TODO: work
let request = Domestic.StockBalanceRequest(credential: credential, accessToken: accessToken, isNext: false)
request.query { result in
switch result {
case .success(let result):
continuation.resume(returning: result)
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}
public func canOrderStock() async throws -> Bool {
public func canOrderStock(productNo: String, division: OrderDivision, price: Int) async throws -> PossibleOrderResult {
return try await withUnsafeThrowingContinuation { continuation in
guard let accessToken = accessToken else {
@@ -347,7 +361,15 @@ extension KissAccount {
return
}
// TODO: work
let request = Domestic.StockPossibleOrderRequest(credential: credential, accessToken: accessToken, productNo: productNo, orderDivision: division, orderPrice: price, isNext: false)
request.query { result in
switch result {
case .success(let result):
continuation.resume(returning: result)
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}
}

View File

@@ -9,6 +9,7 @@ import Foundation
public enum YesNo: String, Codable {
case none = ""
case yes = "Y"
case no = "N"
}

View File

@@ -68,7 +68,238 @@ public struct OrderRevisionResult: Codable {
}
public struct OrderPossibleResult: Codable {
public struct BalanceResult: Codable {
public let resultCode: String
public let messageCode: String
public let message: String
public let straightInqueryCondition: String?
public let straightInqueryKey: String?
public let output1: [OutputDetail1]?
public let output2: [OutputDetail2]?
private enum CodingKeys: String, CodingKey {
case resultCode = "rt_cd"
case messageCode = "msg_cd"
case message = "msg1"
case straightInqueryCondition = "ctx_area_fk100"
case straightInqueryKey = "ctx_area_nk100"
case output1 = "output1"
case output2 = "output2"
}
public struct OutputDetail1: Codable {
///
public let productNo: String
///
public let productName: String
/// ()
public let tradeDivisionCode: String
///
public let previousDayBuyQuantity: String
///
public let previousDaySellQuantity: String
///
public let todayBuyQuantity: String
///
public let todaySellQuantity: String
///
public let holdingQuantity: String
///
public let orderPossibleQuantity: String
/// ( / )
public let averagePurchasePrice: String
///
public let purchaseAmount: String
///
public let currentPrice: String
///
public let evaluationAmount: String
/// ( - )
public let evaluationProfitLossAmount: String
///
public let evaluationProfitLossRate: String
///
public let evaluationEarningRate: String
///
public let loanDate: String
///
public let loanAmount: String
///
public let shortSellingAmount: String
///
public let expiredDate: String
///
public let fluctuationRate: String
///
public let netChangeFluctuation: String
///
public let marginRequirementRatioName: String
///
public let depositRateName: String
///
public let substitutePrice: String
///
public let stockLoanPrice: String
private enum CodingKeys: String, CodingKey {
case productNo = "pdno"
case productName = "prdt_name"
case tradeDivisionCode = "trad_dvsn_name"
case previousDayBuyQuantity = "bfdy_buy_qty"
case previousDaySellQuantity = "bfdy_sll_qty"
case todayBuyQuantity = "thdt_buyqty"
case todaySellQuantity = "thdt_sll_qty"
case holdingQuantity = "hldg_qty"
case orderPossibleQuantity = "ord_psbl_qty"
case averagePurchasePrice = "pchs_avg_pric"
case purchaseAmount = "pchs_amt"
case currentPrice = "prpr"
case evaluationAmount = "evlu_amt"
case evaluationProfitLossAmount = "evlu_pfls_amt"
case evaluationProfitLossRate = "evlu_pfls_rt"
case evaluationEarningRate = "evlu_erng_rt"
case loanDate = "loan_dt"
case loanAmount = "loan_amt"
case shortSellingAmount = "stln_slng_chgs"
case expiredDate = "expd_dt"
case fluctuationRate = "fltt_rt"
case netChangeFluctuation = "bfdy_cprs_icdc"
case marginRequirementRatioName = "item_mgna_rt_name"
case depositRateName = "grta_rt_name"
case substitutePrice = "sbst_pric"
case stockLoanPrice = "stck_loan_unpr"
}
}
public struct OutputDetail2: Codable {
/// ()
public let depositTotalAmount: String
/// (D+1 )
public let nextDayCalcAmount: String
/// (D+2 )
public let nextTwoDayCalcAmount: String
/// CMA
public let cmaEvaluationAmount: String
///
public let previousDayBuyAmount: String
///
public let todayBuyAmount: String
///
public let nextDayAutoRedemptionAmount: String
///
public let previousDaySellAmount: String
///
public let todaySellAmount: String
/// D+2
public let nextTwoDayAutoRedemptionAmount: String
///
public let previousDayExpensesAmount: String
///
public let todayExpensesAmount: String
///
public let totalLoanAmount: String
///
public let securitiesEvaluationAmount: String
///
public let totalEvaluationAmount: String
///
public let netAssetAmount: String
///
public let loanAutoRedemptionAllowable: YesNo
///
public let purchaseAmountSum: String
///
public let evaluationAmountSum: String
///
public let evaluationProfitLossAmountSum: String
///
public let shortSellingAmountSum: String
///
public let previousDayAssetEvalutionSum: String
///
public let assetFluctuationAmount: String
///
public let assetFluctuationRate: String
private enum CodingKeys: String, CodingKey {
case depositTotalAmount = "dnca_tot_amt"
case nextDayCalcAmount = "nxdy_excc_amt"
case nextTwoDayCalcAmount = "prvs_rcdl_excc_amt"
case cmaEvaluationAmount = "cma_evlu_amt"
case previousDayBuyAmount = "bfdy_buy_amt"
case todayBuyAmount = "thdt_buy_amt"
case nextDayAutoRedemptionAmount = "nxdy_auto_rdpt_amt"
case previousDaySellAmount = "bfdy_sll_amt"
case todaySellAmount = "thdt_sll_amt"
case nextTwoDayAutoRedemptionAmount = "d2_auto_rdpt_amt"
case previousDayExpensesAmount = "bfdy_tlex_amt"
case todayExpensesAmount = "thdt_tlex_amt"
case totalLoanAmount = "tot_loan_amt"
case securitiesEvaluationAmount = "scts_evlu_amt"
case totalEvaluationAmount = "tot_evlu_amt"
case netAssetAmount = "nass_amt"
case loanAutoRedemptionAllowable = "fncg_gld_auto_rdpt_yn"
case purchaseAmountSum = "pchs_amt_smtl_amt"
case evaluationAmountSum = "evlu_amt_smtl_amt"
case evaluationProfitLossAmountSum = "evlu_pfls_smtl_amt"
case shortSellingAmountSum = "tot_stln_slng_chgs"
case previousDayAssetEvalutionSum = "bfdy_tot_asst_evlu_amt"
case assetFluctuationAmount = "asst_icdc_amt"
case assetFluctuationRate = "asst_icdc_erng_rt"
}
}
}
public struct PossibleOrderResult: Codable {
public let resultCode: String
public let messageCode: String
public let message: String

View File

@@ -19,6 +19,7 @@ extension DomesticShop {
}
/// _ -
///
public struct Product10Request: SeibroRequest {
public typealias KResult = String

View File

@@ -53,14 +53,14 @@ class KissConsole {
return false
case .logout, .top, .buy, .sell, .cancel:
return true
case .openBag:
return true
case .loadShop, .updateShop, .look:
return false
case .showcase:
return false
case .loves, .love, .hate:
return false
case .openBag:
return false
}
}
}
@@ -119,12 +119,21 @@ class KissConsole {
case .loginReal: await onLogin(isMock: false)
case .logout: await onLogout()
case .top: await onTop(args)
case .buy: await onBuy(args)
case .sell: await onSell(args)
case .cancel: await onCancel(args)
case .openBag: await onOpenBag()
case .loadShop: await onLoadShop()
case .updateShop: await onUpdateShop()
case .look: await onLook(args)
case .showcase: await onShowcase()
case .loves: await onLoves()
case .love: await onLove(args)
case .hate: await onHate(args)
default:
print("Unknown command: \(line)")
}
@@ -323,6 +332,25 @@ extension KissConsole {
}
private func onOpenBag() async {
do {
let result = try await account!.getStockBalance()
if let output = result.output1 {
for item in output {
print("\(item)")
}
}
if let output = result.output2 {
for item in output {
print("\(item)")
}
}
} catch {
print("\(error)")
}
}
private func onLoadShop() async {
return await withUnsafeContinuation { continuation in
self.loadShop()
@@ -410,6 +438,26 @@ extension KissConsole {
}
}
}
private func onShowcase() async {
// TODO: write
}
private func onLoves() async {
}
private func onLove(_ args: [String]) async {
}
private func onHate(_ args: [String]) async {
}
}

View File

@@ -20,7 +20,7 @@ command | 설명
WIP `buy (ISCD) (수량)` | 구매
WIP `sell (ISCD) (수량)` | 판매
WIP `cancel (ISCD)` | 주문 취소
WIP `open bag` | 보유 종목 열람
`open bag` | 보유 종목 열람
`load shop` | data/shop-products.csv 로부터 전체 상품을 로딩
`update shop` | 금융위원회_KRX상장종목정보 로부터 전체 상품을 얻어서 data/shop-products.csv 로 저장
`look (상품명)` | (상품명) 에 해당되는 ISCD 를 표시함