...
This commit is contained in:
parent
dec19983af
commit
7d03cc78b1
@ -179,7 +179,7 @@ fun main() = application {
|
|||||||
println("❌ [명령어 에러] ${command.joinToString(" ")} 실행 중 에러: ${e.message}")
|
println("❌ [명령어 에러] ${command.joinToString(" ")} 실행 중 에러: ${e.message}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mac OS 전용: '확인되지 않은 개발자' 보안(Gatekeeper) 해제 및 실행 권한 부여
|
* Mac OS 전용: '확인되지 않은 개발자' 보안(Gatekeeper) 해제 및 실행 권한 부여
|
||||||
* @param targetPath 권한을 풀 파일 또는 폴더의 절대 경로
|
* @param targetPath 권한을 풀 파일 또는 폴더의 절대 경로
|
||||||
|
|||||||
@ -24,6 +24,7 @@ data class StockHolding(
|
|||||||
val evlu_pfls_rt: String = "0.0", // 평가손익률
|
val evlu_pfls_rt: String = "0.0", // 평가손익률
|
||||||
val evlu_amt: String = "0" , // 평가금액
|
val evlu_amt: String = "0" , // 평가금액
|
||||||
val ord_psbl_qty : String = "0",
|
val ord_psbl_qty : String = "0",
|
||||||
|
val thdt_buyqty : String = "0",
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -151,8 +152,12 @@ data class UnifiedStockHolding(
|
|||||||
val evalAmount: String, // 평가금액
|
val evalAmount: String, // 평가금액
|
||||||
val isDomestic: Boolean, // 국내/해외 구분
|
val isDomestic: Boolean, // 국내/해외 구분
|
||||||
val availOrderCount : String,
|
val availOrderCount : String,
|
||||||
|
val thdtBuyQty: String,
|
||||||
|
|
||||||
)
|
){
|
||||||
|
// 당일 매수 여부 판별 (금일 매수 수량이 0보다 크면 당일 진입 종목)
|
||||||
|
val isTodayEntry: Boolean get() = thdtBuyQty.toInt() > 0
|
||||||
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class UnifiedBalance(
|
data class UnifiedBalance(
|
||||||
|
|||||||
@ -95,7 +95,7 @@ object KisTradeService {
|
|||||||
code = it.pdno, name = it.prdt_name, quantity = it.hldg_qty,
|
code = it.pdno, name = it.prdt_name, quantity = it.hldg_qty,
|
||||||
avgPrice = it.pchs_avg_pric, currentPrice = it.prpr,
|
avgPrice = it.pchs_avg_pric, currentPrice = it.prpr,
|
||||||
profitRate = it.evlu_pfls_rt, evalAmount = it.evlu_amt, isDomestic = true,
|
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 {
|
).apply {
|
||||||
if (it.hldg_qty.toLong() > 0) {
|
if (it.hldg_qty.toLong() > 0) {
|
||||||
// println("보유 종목 : ${it.prdt_name} , 수량 : ${it.hldg_qty}")
|
// println("보유 종목 : ${it.prdt_name} , 수량 : ${it.hldg_qty}")
|
||||||
@ -109,7 +109,7 @@ object KisTradeService {
|
|||||||
code = it.pdno, name = it.prdt_name, quantity = it.hldg_qty,
|
code = it.pdno, name = it.prdt_name, quantity = it.hldg_qty,
|
||||||
avgPrice = it.pchs_avg_pric, currentPrice = it.prpr,
|
avgPrice = it.pchs_avg_pric, currentPrice = it.prpr,
|
||||||
profitRate = it.evlu_pfls_rt, evalAmount = it.evlu_amt, isDomestic = false,
|
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 cano = pureAccount.take(8)
|
||||||
val acntPrdtCd = pureAccount.takeLast(2)
|
val acntPrdtCd = pureAccount.takeLast(2)
|
||||||
println("🚀 [잔고조회 시작] 계좌: ${config.realAccountNo}")
|
println("🚀 [잔고조회 시작] 계좌: ${config.realAccountNo} $markgetCode")
|
||||||
|
|
||||||
try {
|
try {
|
||||||
do {
|
do {
|
||||||
@ -585,12 +585,12 @@ object KisTradeService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!response.status.isSuccess()) {
|
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}"))
|
return Result.failure(Exception("HTTP Error: ${response.status}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
val body = response.body<StockBalanceResponse>()
|
val body = response.body<StockBalanceResponse>()
|
||||||
println("✅ [Step $pageCount] 수신 완료 - 종목 수: ${body.output1.size}")
|
println("✅ [Step $pageCount] $markgetCode 수신 완료 - 종목 수: ${body.output1.size}")
|
||||||
|
|
||||||
allHoldings.addAll(body.output1)
|
allHoldings.addAll(body.output1)
|
||||||
if (totalBalance == null) totalBalance = body
|
if (totalBalance == null) totalBalance = body
|
||||||
|
|||||||
@ -359,8 +359,14 @@ object AutoTradingManager {
|
|||||||
"거랙 차단 대상 : ${holding.currentPrice}[${holding.quantity}주] 보유, 수익률(${holding.profitRate.toDouble()})"
|
"거랙 차단 대상 : ${holding.currentPrice}[${holding.quantity}주] 보유, 수익률(${holding.profitRate.toDouble()})"
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
println("sellingAfterMarketOnePrice")
|
val targetProfitLimit = if (holding.isTodayEntry) {
|
||||||
if (holding != null && holding.quantity.toInt() > 0 && holding.availOrderCount.toInt() > 0 && holding.profitRate.toDouble() > KisSession.config.SELL_PROFIT) {
|
// 당일 매수 종목: 짧은 익절 (예: 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()
|
var targetPrice = holding.currentPrice.toDouble()
|
||||||
TradingLogStore.addAfterMarketLog(
|
TradingLogStore.addAfterMarketLog(
|
||||||
holding.name,
|
holding.name,
|
||||||
@ -376,7 +382,7 @@ object AutoTradingManager {
|
|||||||
orderDivision = if (marketCode.equals("Y")) "07" else "",
|
orderDivision = if (marketCode.equals("Y")) "07" else "",
|
||||||
marketCode = if (marketCode.equals("Y")) "KRX" else "NXT"
|
marketCode = if (marketCode.equals("Y")) "KRX" else "NXT"
|
||||||
).onSuccess { newOrderNo ->
|
).onSuccess { newOrderNo ->
|
||||||
println("✅ [재주문 완료] ${holding.name}: $newOrderNo")
|
println("✅ [${if(marketCode.equals("Y"))"시간외 단일가" else "대체거래소"} 주문 완료] ${holding.name}: $newOrderNo")
|
||||||
TradingLogStore.addSellLog(
|
TradingLogStore.addSellLog(
|
||||||
"${holding.name}[${holding.code}]",
|
"${holding.name}[${holding.code}]",
|
||||||
targetPrice.toString(),
|
targetPrice.toString(),
|
||||||
@ -760,7 +766,7 @@ object AutoTradingManager {
|
|||||||
lastForceCheckMinute = currentMinute // 실행 완료 기록
|
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) {
|
if (lastForceCheckMinute != currentMinute) {
|
||||||
TradingLogStore.addAnalyzer(
|
TradingLogStore.addAnalyzer(
|
||||||
" - ",
|
" - ",
|
||||||
@ -768,7 +774,11 @@ object AutoTradingManager {
|
|||||||
"⏰ [강제 스케줄 실행] 오후 ${now.hour}시 ${currentMinute}분 - 보유주식 시간외 단일가 또는 대체마켓 체크를 시작합니다.",
|
"⏰ [강제 스케줄 실행] 오후 ${now.hour}시 ${currentMinute}분 - 보유주식 시간외 단일가 또는 대체마켓 체크를 시작합니다.",
|
||||||
true
|
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 {
|
KisTradeService.fetchIntegratedBalance(code).getOrNull()?.let {
|
||||||
sellingAfterMarketOnePrice(KisTradeService, it, code)
|
sellingAfterMarketOnePrice(KisTradeService, it, code)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -88,7 +88,7 @@ fun SettingsScreen(onAuthSuccess: () -> Unit) {
|
|||||||
while (true) {
|
while (true) {
|
||||||
val now = java.time.LocalTime.now(java.time.ZoneId.of("Asia/Seoul"))
|
val now = java.time.LocalTime.now(java.time.ZoneId.of("Asia/Seoul"))
|
||||||
// 08:30 ~ 15:30 사이이고, 키값이 최소한 하나라도 존재할 때 자동 실행
|
// 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()) {
|
if (config.realAppKey.isNotEmpty() && config.vtsAppKey.isNotEmpty() && config.embedModelPath.isNotEmpty() && config.modelPath.isNotEmpty()) {
|
||||||
SystemSleepPreventer.wakeDisplay() // 모니터 켜기
|
SystemSleepPreventer.wakeDisplay() // 모니터 켜기
|
||||||
statusMessage = "⏰ 자동 실행 시간(08:30)입니다. 시스템을 가동합니다."
|
statusMessage = "⏰ 자동 실행 시간(08:30)입니다. 시스템을 가동합니다."
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user