This commit is contained in:
lunaticbum 2026-04-09 17:03:52 +09:00
parent dec19983af
commit 7d03cc78b1
5 changed files with 28 additions and 13 deletions

View File

@ -179,7 +179,7 @@ fun main() = application {
println("❌ [명령어 에러] ${command.joinToString(" ")} 실행 중 에러: ${e.message}")
}
}
/**
* Mac OS 전용: '확인되지 않은 개발자' 보안(Gatekeeper) 해제 실행 권한 부여
* @param targetPath 권한을 파일 또는 폴더의 절대 경로

View File

@ -24,6 +24,7 @@ data class StockHolding(
val evlu_pfls_rt: String = "0.0", // 평가손익률
val evlu_amt: String = "0" , // 평가금액
val ord_psbl_qty : String = "0",
val thdt_buyqty : String = "0",
)
@Serializable
@ -151,8 +152,12 @@ data class UnifiedStockHolding(
val evalAmount: String, // 평가금액
val isDomestic: Boolean, // 국내/해외 구분
val availOrderCount : String,
val thdtBuyQty: String,
)
){
// 당일 매수 여부 판별 (금일 매수 수량이 0보다 크면 당일 진입 종목)
val isTodayEntry: Boolean get() = thdtBuyQty.toInt() > 0
}
@Serializable
data class UnifiedBalance(

View File

@ -95,7 +95,7 @@ object KisTradeService {
code = it.pdno, name = it.prdt_name, quantity = it.hldg_qty,
avgPrice = it.pchs_avg_pric, currentPrice = it.prpr,
profitRate = it.evlu_pfls_rt, evalAmount = it.evlu_amt, isDomestic = true,
availOrderCount = it.ord_psbl_qty
availOrderCount = it.ord_psbl_qty, thdtBuyQty = it.thdt_buyqty
).apply {
if (it.hldg_qty.toLong() > 0) {
// println("보유 종목 : ${it.prdt_name} , 수량 : ${it.hldg_qty}")
@ -109,7 +109,7 @@ object KisTradeService {
code = it.pdno, name = it.prdt_name, quantity = it.hldg_qty,
avgPrice = it.pchs_avg_pric, currentPrice = it.prpr,
profitRate = it.evlu_pfls_rt, evalAmount = it.evlu_amt, isDomestic = false,
availOrderCount = it.ord_psbl_qty
availOrderCount = it.ord_psbl_qty, thdtBuyQty = it.thdt_buyqty
))
}
@ -558,7 +558,7 @@ object KisTradeService {
val cano = pureAccount.take(8)
val acntPrdtCd = pureAccount.takeLast(2)
println("🚀 [잔고조회 시작] 계좌: ${config.realAccountNo}")
println("🚀 [잔고조회 시작] 계좌: ${config.realAccountNo} $markgetCode")
try {
do {
@ -585,12 +585,12 @@ object KisTradeService {
}
if (!response.status.isSuccess()) {
println("❌ [Step $pageCount] HTTP 에러 발생: ${response.status}")
println("❌ [Step $pageCount] $markgetCode HTTP 에러 발생: ${response.status}")
return Result.failure(Exception("HTTP Error: ${response.status}"))
}
val body = response.body<StockBalanceResponse>()
println("✅ [Step $pageCount] 수신 완료 - 종목 수: ${body.output1.size}")
println("✅ [Step $pageCount] $markgetCode 수신 완료 - 종목 수: ${body.output1.size}")
allHoldings.addAll(body.output1)
if (totalBalance == null) totalBalance = body

View File

@ -359,8 +359,14 @@ object AutoTradingManager {
"거랙 차단 대상 : ${holding.currentPrice}[${holding.quantity}주] 보유, 수익률(${holding.profitRate.toDouble()})"
)
} else {
println("sellingAfterMarketOnePrice")
if (holding != null && holding.quantity.toInt() > 0 && holding.availOrderCount.toInt() > 0 && holding.profitRate.toDouble() > KisSession.config.SELL_PROFIT) {
val targetProfitLimit = if (holding.isTodayEntry) {
// 당일 매수 종목: 짧은 익절 (예: 1.0% 이상이면 즉시 매도)
KisSession.config.getValues(ConfigIndex.PROFIT_INDEX)+ KisSession.config.getValues(ConfigIndex.TAX_INDEX)
} else {
// 오래 보유한 종목: 기존 설정값 준수 (예: 3.0% 등)
KisSession.config.SELL_PROFIT
}
if (holding != null && holding.quantity.toInt() > 0 && holding.availOrderCount.toInt() > 0 && holding.profitRate.toDouble() > targetProfitLimit) {
var targetPrice = holding.currentPrice.toDouble()
TradingLogStore.addAfterMarketLog(
holding.name,
@ -376,7 +382,7 @@ object AutoTradingManager {
orderDivision = if (marketCode.equals("Y")) "07" else "",
marketCode = if (marketCode.equals("Y")) "KRX" else "NXT"
).onSuccess { newOrderNo ->
println("✅ [주문 완료] ${holding.name}: $newOrderNo")
println("✅ [${if(marketCode.equals("Y"))"시간외 단일가" else "대체거래소"} 주문 완료] ${holding.name}: $newOrderNo")
TradingLogStore.addSellLog(
"${holding.name}[${holding.code}]",
targetPrice.toString(),
@ -760,7 +766,7 @@ object AutoTradingManager {
lastForceCheckMinute = currentMinute // 실행 완료 기록
}
}
else if((now.hour == 8 || now.hour == 16 || now.hour == 17) && (currentMinute % 10 == 3)) {
else if((now.hour == 8 || now.hour == 16 || now.hour == 17) && (currentMinute % 10 == 1) || (currentMinute % 10 == 6)) {
if (lastForceCheckMinute != currentMinute) {
TradingLogStore.addAnalyzer(
" - ",
@ -768,7 +774,11 @@ object AutoTradingManager {
"⏰ [강제 스케줄 실행] 오후 ${now.hour}${currentMinute}분 - 보유주식 시간외 단일가 또는 대체마켓 체크를 시작합니다.",
true
)
listOf<String>("Y","X").forEach { code ->
var list = mutableListOf<String>("x")
if (now.hour != 8) {
list.add("y")
}
list.forEach { code ->
KisTradeService.fetchIntegratedBalance(code).getOrNull()?.let {
sellingAfterMarketOnePrice(KisTradeService, it, code)
}

View File

@ -88,7 +88,7 @@ fun SettingsScreen(onAuthSuccess: () -> Unit) {
while (true) {
val now = java.time.LocalTime.now(java.time.ZoneId.of("Asia/Seoul"))
// 08:30 ~ 15:30 사이이고, 키값이 최소한 하나라도 존재할 때 자동 실행
if (now.isAfter(java.time.LocalTime.of(8, 30)) && now.isBefore(java.time.LocalTime.of(15, 30))) {
if (now.isAfter(java.time.LocalTime.of(7, 40)) && now.isBefore(java.time.LocalTime.of(18, 0))) {
if (config.realAppKey.isNotEmpty() && config.vtsAppKey.isNotEmpty() && config.embedModelPath.isNotEmpty() && config.modelPath.isNotEmpty()) {
SystemSleepPreventer.wakeDisplay() // 모니터 켜기
statusMessage = "⏰ 자동 실행 시간(08:30)입니다. 시스템을 가동합니다."