...
This commit is contained in:
parent
ad6d00ac39
commit
b9ba8efc1a
@ -547,8 +547,11 @@ object TradingLogStore {
|
|||||||
reason = log
|
reason = log
|
||||||
).apply {
|
).apply {
|
||||||
CoroutineScope(Dispatchers.Default).launch {
|
CoroutineScope(Dispatchers.Default).launch {
|
||||||
if (((tradingDecision.investmentGrade?.name?.length ?: 0) > 0 && KisSession.tradeConfig.useGradeShare.contains(tradingDecision.investmentGrade?.name))
|
if (((tradingDecision.investmentGrade?.name?.length ?: 0) > 0 && KisSession.tradeConfig.useGradeShare.any {
|
||||||
) {
|
tradingDecision.investmentGrade?.name?.contains(
|
||||||
|
it
|
||||||
|
) ?: false
|
||||||
|
})) {
|
||||||
NewsService.sendTelegramMessage("${this@apply.decision} ${tradingDecision.stockName}[${tradingDecision.currentPrice}] ${log}")
|
NewsService.sendTelegramMessage("${this@apply.decision} ${tradingDecision.stockName}[${tradingDecision.currentPrice}] ${log}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -766,4 +766,64 @@ object KisTradeService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
suspend fun reserveSell(stockCode: String,
|
||||||
|
qty: String,
|
||||||
|
price: String,
|
||||||
|
targetDate : String) :Result<String> {
|
||||||
|
|
||||||
|
val config = KisSession.config
|
||||||
|
val isDomestic = stockCode.length == 6 && stockCode.all { it.isDigit() }
|
||||||
|
val baseUrl = if (config.isSimulation) vtsUrl else prodUrl
|
||||||
|
|
||||||
|
// 계좌번호 처리: 8자리면 01 자동 추가
|
||||||
|
var pureAccount = config.accountNo.replace("-", "").trim()
|
||||||
|
if (pureAccount.length == 8) pureAccount += "01"
|
||||||
|
|
||||||
|
val cano = pureAccount.take(8)
|
||||||
|
val acntPrdtCd = pureAccount.takeLast(2)
|
||||||
|
|
||||||
|
val trId = "CTSC0008U"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return try {
|
||||||
|
val response = client.post("$baseUrl/uapi/${if(isDomestic) "domestic" else "overseas"}-stock/v1/trading/order-resv") {
|
||||||
|
header("authorization", "Bearer ${config.tradeToken}")
|
||||||
|
header("appkey", if (config.isSimulation) config.vtsAppKey else config.realAppKey)
|
||||||
|
header("appsecret", if (config.isSimulation) config.vtsSecretKey else config.realSecretKey)
|
||||||
|
header("tr_id", trId)
|
||||||
|
header("custtype", "P") // [해결] 필수 헤더 추가
|
||||||
|
header("Content-Type", "application/json")
|
||||||
|
|
||||||
|
setBody(mapOf(
|
||||||
|
"CANO" to cano,
|
||||||
|
"ACNT_PRDT_CD" to acntPrdtCd,
|
||||||
|
"PDNO" to stockCode,
|
||||||
|
"ORD_DVSN_CD" to "00",
|
||||||
|
"SLL_BUY_DVSN_CD" to "01",
|
||||||
|
"ORD_QTY" to qty,
|
||||||
|
"ORD_UNPR" to price,
|
||||||
|
"ORD_OBJT_CBLC_DVSN_CD" to "10",
|
||||||
|
"RSVN_ORD_END_DT" to targetDate
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
val body = response.body<JsonObject>() // [해결] Polymorphic 직렬화 에러 방지
|
||||||
|
val rtCd = body["rt_cd"]?.jsonPrimitive?.content
|
||||||
|
val msg = body["msg1"]?.jsonPrimitive?.content ?: "메시지 없음"
|
||||||
|
|
||||||
|
if (rtCd == "0") {
|
||||||
|
// 응답의 output 객체에서 주문 번호(ODNO) 추출
|
||||||
|
val orderNo = body["output"]?.jsonObject?.get("ODNO")?.jsonPrimitive?.content
|
||||||
|
?: body["output"]?.jsonObject?.get("odno")?.jsonPrimitive?.content // API마다 대소문자가 다를 수 있음
|
||||||
|
?: ""
|
||||||
|
Result.success(orderNo) // 성공 시 주문 번호 반환
|
||||||
|
} else {
|
||||||
|
val msg = body["msg1"]?.jsonPrimitive?.content ?: "메시지 없음"
|
||||||
|
Result.failure(Exception("❌ 오류 ($rtCd): $msg"))
|
||||||
|
}
|
||||||
|
} catch (e: Exception) { Result.failure(e) }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -529,7 +529,7 @@ object AutoTradingManager {
|
|||||||
println("${holding.name} ${holding.profitRate.toDouble()} ${holding.valuationProfitAmount.toDouble()} ${KisSession.config.getValues(ConfigIndex.LOSS_MAX_MONEY)} , ${KisSession.config.getValues(ConfigIndex.LOSS_MINRATE)} , ${KisSession.config.getValues(ConfigIndex.STOP_LOSS)}")
|
println("${holding.name} ${holding.profitRate.toDouble()} ${holding.valuationProfitAmount.toDouble()} ${KisSession.config.getValues(ConfigIndex.LOSS_MAX_MONEY)} , ${KisSession.config.getValues(ConfigIndex.LOSS_MINRATE)} , ${KisSession.config.getValues(ConfigIndex.STOP_LOSS)}")
|
||||||
val profit = holding.profitRate.toDouble()
|
val profit = holding.profitRate.toDouble()
|
||||||
var targetPrice = holding.currentPrice.toDouble()
|
var targetPrice = holding.currentPrice.toDouble()
|
||||||
targetPrice = MarketUtil.roundToTickSize(targetPrice + (MarketUtil.getTickSize(targetPrice) * 3.0))
|
targetPrice = MarketUtil.roundToTickSize(targetPrice + (MarketUtil.getTickSize(targetPrice) * 3.0))
|
||||||
|
|
||||||
tradeService.postOrder(
|
tradeService.postOrder(
|
||||||
stockCode = holding.code,
|
stockCode = holding.code,
|
||||||
@ -814,6 +814,21 @@ object AutoTradingManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun cancelAllPendingSellOrders(
|
||||||
|
) {
|
||||||
|
// 1. 미체결 내역 조회
|
||||||
|
val unfilledResult = KisTradeService.fetchUnfilledOrders()
|
||||||
|
unfilledResult.onSuccess { response ->
|
||||||
|
response.filter { it.sll_buy_dvsn_cd == "01" }.forEach { order ->
|
||||||
|
TradingLogStore.addNotice(order.prdt_name,order.pdno,"[주문 취소] 정규장 시작전 모든 매도 주문 취소")
|
||||||
|
KisTradeService.cancelOrder(
|
||||||
|
order.ord_no, // 원주문번호
|
||||||
|
order.pdno
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 주문 시간 문자열을 Millis로 변환하는 유틸리티 (당일 주문 기준)
|
// 주문 시간 문자열을 Millis로 변환하는 유틸리티 (당일 주문 기준)
|
||||||
fun parseOrderTime(ordTmd: String): Long {
|
fun parseOrderTime(ordTmd: String): Long {
|
||||||
return try {
|
return try {
|
||||||
@ -908,8 +923,14 @@ object AutoTradingManager {
|
|||||||
} else {
|
} else {
|
||||||
val now = LocalTime.now()
|
val now = LocalTime.now()
|
||||||
val currentMinute = now.minute
|
val currentMinute = now.minute
|
||||||
if (now.hour == 9 && currentMinute % 2 == 1
|
if (now.hour == 8 && currentMinute < 50 && currentMinute > 45) {
|
||||||
) {
|
if (lastForceCheckMinute != currentMinute) {
|
||||||
|
cancelAllPendingSellOrders()
|
||||||
|
}
|
||||||
|
} else if (now.hour == 8 && currentMinute > 55 && currentMinute > 50) {
|
||||||
|
|
||||||
|
} else if (now.hour == 9 && currentMinute % 2 == 1
|
||||||
|
) {
|
||||||
if (lastForceCheckMinute != currentMinute) {
|
if (lastForceCheckMinute != currentMinute) {
|
||||||
TradingLogStore.addAnalyzer(
|
TradingLogStore.addAnalyzer(
|
||||||
" - ",
|
" - ",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user