...
This commit is contained in:
parent
1787b72499
commit
93d8b3f0aa
@ -2,8 +2,9 @@ package model
|
||||
|
||||
import java.time.LocalDateTime
|
||||
|
||||
const val feesAndTaxRate = 0.3
|
||||
const val minimumNetProfit = 0.8
|
||||
const val feesAndTaxRate = 0.33
|
||||
const val minimumNetProfit = 0.4
|
||||
const val buyWeight = 2.0
|
||||
|
||||
data class AppConfig(
|
||||
// [DB 저장 데이터]
|
||||
|
||||
@ -20,6 +20,7 @@ import androidx.compose.ui.unit.TextUnit
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import kotlinx.coroutines.launch
|
||||
import model.buyWeight
|
||||
import model.feesAndTaxRate
|
||||
import model.minimumNetProfit
|
||||
import network.KisTradeService
|
||||
@ -72,7 +73,7 @@ fun IntegratedOrderSection(
|
||||
}
|
||||
|
||||
var profitRate by remember(monitoringItem) {
|
||||
mutableStateOf(monitoringItem?.profitRate?.toString() ?: "0.8")
|
||||
mutableStateOf(monitoringItem?.profitRate?.toString() ?: minimumNetProfit.toString())
|
||||
}
|
||||
var stopLossRate by remember(monitoringItem) {
|
||||
mutableStateOf(monitoringItem?.stopLossRate?.toString() ?: "-1.5")
|
||||
@ -83,7 +84,7 @@ fun IntegratedOrderSection(
|
||||
val basePrice = (if (orderPrice.isEmpty()) curPriceNum else orderPrice.toDoubleOrNull() ?: 0.0)
|
||||
val inputQty = orderQty.replace(",", "").toIntOrNull() ?: 0
|
||||
|
||||
fun excuteTrade(willEnableAutoSell: Boolean,orderQty: String) {
|
||||
fun excuteTrade(willEnableAutoSell: Boolean, orderQty: String, profitRate1: Double?) {
|
||||
scope.launch {
|
||||
val tickSize = MarketUtil.getTickSize(basePrice)
|
||||
val oneTickLowerPrice = basePrice - tickSize
|
||||
@ -108,7 +109,7 @@ fun IntegratedOrderSection(
|
||||
|
||||
// 3. 실질 목표 수익률 계산
|
||||
// 사용자가 입력한 pRate와 (최소 순수익 + 제반 비용) 중 큰 값을 선택합니다.
|
||||
val effectiveProfitRate = maxOf(pRate, minimumNetProfit + feesAndTaxRate)
|
||||
val effectiveProfitRate = maxOf((profitRate1 ?: pRate) + feesAndTaxRate, minimumNetProfit + feesAndTaxRate)
|
||||
|
||||
// 4. 보정된 수익률을 적용하여 목표가 계산
|
||||
val calculatedTarget = MarketUtil.roundToTickSize(basePrice * (1 + effectiveProfitRate / 100.0))
|
||||
@ -152,25 +153,50 @@ fun IntegratedOrderSection(
|
||||
profitPossible : ${completeTradingDecision.profitPossible()+ append}
|
||||
safePossible : ${completeTradingDecision.safePossible()+ append}
|
||||
""".trimIndent())
|
||||
// 2. 조건 검사: 신뢰도 80 이상 AND 중기 점수 70 이상
|
||||
if (completeTradingDecision.confidence + append >= MIN_CONFIDENCE &&
|
||||
completeTradingDecision.shortPossible() + append >= MIN_SHORT_SCORE &&
|
||||
completeTradingDecision.profitPossible() + append >= MIN_POSSIBLE_SCORE &&
|
||||
completeTradingDecision.safePossible() + append >= MIN_SAFE_SCORE
|
||||
) {
|
||||
|
||||
println("🚀 [조건 만족] 강력 매수 시그널 포착 -> 자동 매수 진행 (1주) ${completeTradingDecision.stockCode}")
|
||||
// 3. 매수 실행 (자동 감시 켜기: true, 수량: 1주)
|
||||
// 수량은 필요에 따라 로직으로 계산하여 변경 가능 (예: 자산의 10% 등)
|
||||
excuteTrade(willEnableAutoSell = true, orderQty = "1")
|
||||
val weights = mapOf(
|
||||
"short" to 0.3, // 초단기 점수가 낮아도 전체에 미치는 영향 감소
|
||||
"profit" to 0.3,
|
||||
"safe" to 0.4 // 중장기 점수 비중 강화
|
||||
)
|
||||
|
||||
// 2. 토탈 스코어 계산
|
||||
val totalScore =
|
||||
(completeTradingDecision.shortPossible() * weights["short"]!!) +
|
||||
(completeTradingDecision.profitPossible() * weights["profit"]!!) +
|
||||
(completeTradingDecision.safePossible() * weights["safe"]!!)
|
||||
|
||||
// 3. 매수 결정 문턱값 (예: 70점 이상이면 매수 가능)
|
||||
val MIN_PURCHASE_SCORE = 70.0
|
||||
val HIGH_QUALITY_SCORE = 85.0 // 강력 추천 기준
|
||||
|
||||
if (totalScore >= MIN_PURCHASE_SCORE && completeTradingDecision.confidence > MIN_CONFIDENCE) {
|
||||
|
||||
// 4. 점수에 따른 가변 마진 적용
|
||||
// 토탈 스코어가 85점 이상이면 마진을 3.0으로 고정하거나 추가 가산(append) 적용
|
||||
val finalMargin = if (totalScore >= HIGH_QUALITY_SCORE) {
|
||||
println("💎 [우량주 포착] 토탈 스코어($totalScore)가 매우 높아 목표 마진을 3.0%로 상향합니다.")
|
||||
minimumNetProfit + (append * 1.5)
|
||||
} else {
|
||||
minimumNetProfit + append
|
||||
}
|
||||
|
||||
println("🚀 [매수 진행] 토탈 스코어: ${String.format("%.1f", totalScore)} -> 종목: ${completeTradingDecision.stockCode}")
|
||||
|
||||
// 5. 매수 실행 (계산된 finalMargin 전달)
|
||||
excuteTrade(
|
||||
willEnableAutoSell = true,
|
||||
orderQty = "1",
|
||||
profitRate1 = finalMargin
|
||||
)
|
||||
|
||||
} else {
|
||||
println("✋ [조건 미달] 매수 의견이나 점수 부족으로 관망")
|
||||
println("✋ [관망] 토탈 스코어(${String.format("%.1f", totalScore)})가 기준치($MIN_PURCHASE_SCORE) 미달")
|
||||
}
|
||||
}
|
||||
when (completeTradingDecision?.decision) {
|
||||
"BUY" -> {
|
||||
append = 3.0
|
||||
append = buyWeight
|
||||
println("[$stockCode] 매수 추천 resultCheck: ${completeTradingDecision?.reason}")
|
||||
resultCheck(completeTradingDecision)
|
||||
}
|
||||
@ -274,7 +300,7 @@ fun IntegratedOrderSection(
|
||||
// 매수 버튼
|
||||
Button(
|
||||
onClick = {
|
||||
excuteTrade(willEnableAutoSell,orderQty)
|
||||
excuteTrade(willEnableAutoSell, orderQty, profitRate.toDouble())
|
||||
},
|
||||
modifier = Modifier.weight(1f).padding(end = 4.dp),
|
||||
colors = ButtonDefaults.buttonColors(backgroundColor = Color(0xFFE03E2D))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user