...
This commit is contained in:
@@ -270,6 +270,11 @@ class TradeConfig {
|
||||
var isUpcomingDividend : Boolean = false
|
||||
var buyTickOffset : Int = 4
|
||||
var sellTickOffset : Int = 4
|
||||
var useGrade5: Boolean = true
|
||||
var useGrade4: Boolean = true
|
||||
var useGrade3: Boolean = true
|
||||
var useGrade2: Boolean = true
|
||||
var useGrade1: Boolean = true
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -254,7 +254,7 @@ object AutoTradingManager {
|
||||
}
|
||||
}
|
||||
|
||||
return if (isOverheated) {
|
||||
val finalGrade = if (isOverheated) {
|
||||
when (rawGrade) {
|
||||
InvestmentGrade.LEVEL_5_STRONG_RECOMMEND -> InvestmentGrade.LEVEL_4_BALANCED_RECOMMEND
|
||||
InvestmentGrade.LEVEL_4_BALANCED_RECOMMEND -> InvestmentGrade.LEVEL_3_CAUTIOUS_RECOMMEND
|
||||
@@ -264,6 +264,19 @@ object AutoTradingManager {
|
||||
} else {
|
||||
rawGrade
|
||||
}
|
||||
|
||||
// 🌟 [추가] 사용자가 비활성화한 등급인지 체크하여 매수 원천 차단
|
||||
val isEnabled = when (finalGrade) {
|
||||
InvestmentGrade.LEVEL_5_STRONG_RECOMMEND -> KisSession.tradeConfig.useGrade5
|
||||
InvestmentGrade.LEVEL_4_BALANCED_RECOMMEND -> KisSession.tradeConfig.useGrade4
|
||||
InvestmentGrade.LEVEL_3_CAUTIOUS_RECOMMEND -> KisSession.tradeConfig.useGrade3
|
||||
InvestmentGrade.LEVEL_2_HIGH_RISK -> KisSession.tradeConfig.useGrade2
|
||||
InvestmentGrade.LEVEL_1_SPECULATIVE -> KisSession.tradeConfig.useGrade1
|
||||
else -> false
|
||||
}
|
||||
|
||||
// 비활성화된 등급이라면 LEVEL_0_SPECULATIVE(관망) 반환
|
||||
return if (isEnabled) finalGrade else InvestmentGrade.LEVEL_0_SPECULATIVE
|
||||
}
|
||||
|
||||
fun excuteTrade(
|
||||
|
||||
@@ -298,9 +298,9 @@ fun TradingDecisionLog() {
|
||||
modifier = Modifier.padding(top = 10.dp, bottom = 8.dp)
|
||||
)
|
||||
}
|
||||
|
||||
// ConfigIndex.BUY_WEIGHT_INDEX,
|
||||
var defaults = arrayOf(
|
||||
ConfigIndex.TAX_INDEX, ConfigIndex.PROFIT_INDEX, ConfigIndex.BUY_WEIGHT_INDEX,
|
||||
ConfigIndex.TAX_INDEX, ConfigIndex.PROFIT_INDEX,
|
||||
ConfigIndex.MAX_BUDGET_INDEX, ConfigIndex.MAX_PRICE_INDEX, ConfigIndex.MIN_PRICE_INDEX,
|
||||
ConfigIndex.MIN_PURCHASE_SCORE_INDEX, ConfigIndex.SELL_PROFIT,
|
||||
ConfigIndex.MAX_COUNT_INDEX, ConfigIndex.MAX_HOLDING_COUNT,
|
||||
@@ -434,14 +434,34 @@ fun TradingDecisionLog() {
|
||||
arrayOf(ConfigIndex.GRADE_1_BUY, ConfigIndex.GRADE_1_PROFIT, ConfigIndex.GRADE_1_ALLOCATIONRATE),
|
||||
)
|
||||
|
||||
for (items in defaults2) {
|
||||
// 🌟 [수정] index를 활용해 Level 번호(5~1)를 역추산하도록 withIndex() 사용
|
||||
for ((indexLevel, items) in defaults2.withIndex()) {
|
||||
val common = findLongestCommonSubstring(items.first().label, items.last().label)
|
||||
val levelNum = 5 - indexLevel // 5, 4, 3, 2, 1
|
||||
|
||||
item(span = { GridItemSpan(maxLineSpan) }) {
|
||||
Text(
|
||||
common,
|
||||
style = MaterialTheme.typography.body1,
|
||||
modifier = Modifier.padding(top = 10.dp, bottom = 8.dp)
|
||||
// 🌟 [핵심] 제목 텍스트 대신 사용 여부 스위치 부착
|
||||
SettingSwitchField(
|
||||
modifier = Modifier.fillMaxWidth().padding(top = 10.dp, bottom = 8.dp),
|
||||
label = "$common (LEVEL_$levelNum) 자동매수",
|
||||
initialChecked = when (levelNum) {
|
||||
5 -> tradeConfig.useGrade5
|
||||
4 -> tradeConfig.useGrade4
|
||||
3 -> tradeConfig.useGrade3
|
||||
2 -> tradeConfig.useGrade2
|
||||
else -> tradeConfig.useGrade1
|
||||
},
|
||||
onCheckedChange = { isChecked ->
|
||||
when (levelNum) {
|
||||
5 -> tradeConfig.useGrade5 = isChecked
|
||||
4 -> tradeConfig.useGrade4 = isChecked
|
||||
3 -> tradeConfig.useGrade3 = isChecked
|
||||
2 -> tradeConfig.useGrade2 = isChecked
|
||||
1 -> tradeConfig.useGrade1 = isChecked
|
||||
}
|
||||
KisSession.saveTradeConfig() // 즉시 저장
|
||||
},
|
||||
helperText = "체크 해제 시 해당 등급 판정이 나와도 매수하지 않습니다."
|
||||
)
|
||||
}
|
||||
|
||||
@@ -457,7 +477,7 @@ fun TradingDecisionLog() {
|
||||
KisSession.config.setValues(configKey, newValue)
|
||||
}
|
||||
|
||||
// labelText 업데이트 로직 (기존과 동일)
|
||||
// labelText 업데이트 로직
|
||||
labelText = if (configKey.name.contains("PROFIT")) {
|
||||
getRemaining(configKey.label, common) + ": 기준율(${KisSession.config.getValues(ConfigIndex.PROFIT_INDEX)}) * 비율(${KisSession.config.getValues(configKey)}) + 세금(${KisSession.config.getValues(ConfigIndex.TAX_INDEX)}) = ${(localText.toDoubleOrNull() ?: 0.0) * KisSession.config.getValues(ConfigIndex.PROFIT_INDEX) + KisSession.config.getValues(ConfigIndex.TAX_INDEX)}"
|
||||
} else if (configKey.name.contains("ALLOCATIONRATE")) {
|
||||
@@ -490,79 +510,117 @@ fun TradingDecisionLog() {
|
||||
Text("자동 매매 시간 설정", fontWeight = FontWeight.Bold, color = Color.Blue)
|
||||
Spacer(Modifier.height(8.dp))
|
||||
|
||||
// 시작 시간 (HH:mm)
|
||||
TimeInputRow("자동 시작", tradeConfig.auto_start_time) { tradeConfig.auto_start_time = it
|
||||
KisSession.saveTradeConfig() }
|
||||
// 종료 시간 (HH:mm)
|
||||
TimeInputRow("자동 종료", tradeConfig.auto_end_time) { tradeConfig.auto_end_time = it
|
||||
KisSession.saveTradeConfig() }
|
||||
// 🌟 [수정] 자동 시작/종료를 한 줄로
|
||||
Row(horizontalArrangement = Arrangement.SpaceEvenly) {
|
||||
TimeInputRow(
|
||||
modifier = Modifier.weight(1f),
|
||||
label = "자동 시작",
|
||||
initialTime = tradeConfig.auto_start_time
|
||||
) {
|
||||
tradeConfig.auto_start_time = it
|
||||
KisSession.saveTradeConfig()
|
||||
}
|
||||
TimeInputRow(
|
||||
modifier = Modifier.weight(1f),
|
||||
label = "자동 종료",
|
||||
initialTime = tradeConfig.auto_end_time
|
||||
) {
|
||||
tradeConfig.auto_end_time = it
|
||||
KisSession.saveTradeConfig()
|
||||
}
|
||||
}
|
||||
|
||||
Divider(Modifier.padding(vertical = 8.dp))
|
||||
|
||||
// 매수 금지 시간 설정
|
||||
TimeInputRow("매수 시작", tradeConfig.start_buy_time) { tradeConfig.start_buy_time = it
|
||||
KisSession.saveTradeConfig() }
|
||||
TimeInputRow("매수 종료", tradeConfig.end_buy_time) { tradeConfig.end_buy_time = it
|
||||
KisSession.saveTradeConfig() }
|
||||
// 🌟 [수정] 매수 시작/종료를 한 줄로
|
||||
Row(horizontalArrangement = Arrangement.SpaceEvenly) {
|
||||
TimeInputRow(
|
||||
modifier = Modifier.weight(1f),
|
||||
label = "매수 시작",
|
||||
initialTime = tradeConfig.start_buy_time
|
||||
) {
|
||||
tradeConfig.start_buy_time = it
|
||||
KisSession.saveTradeConfig()
|
||||
}
|
||||
TimeInputRow(
|
||||
modifier = Modifier.weight(1f),
|
||||
label = "매수 종료",
|
||||
initialTime = tradeConfig.end_buy_time
|
||||
) {
|
||||
tradeConfig.end_buy_time = it
|
||||
KisSession.saveTradeConfig()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(16.dp))
|
||||
|
||||
Text("⚙️ 기타 고급 설정", style = MaterialTheme.typography.h6, modifier = Modifier.padding(8.dp))
|
||||
Text("⚙️️ 기타 고급 설정", style = MaterialTheme.typography.h6, modifier = Modifier.padding(8.dp))
|
||||
Row(horizontalArrangement = Arrangement.SpaceEvenly) {
|
||||
SettingInputField(
|
||||
modifier = Modifier.weight(1.0f, true),
|
||||
label = "매수 분석 현 변동율 처저 기준",
|
||||
modifier = Modifier.weight(1.0f, true).padding(end = 4.dp),
|
||||
label = "매수 분석 최저 기준 (%)",
|
||||
initialValue = (tradeConfig.minusFilter * -1).toString(),
|
||||
onSave = {
|
||||
tradeConfig.minusFilter = abs(it.toDouble())
|
||||
KisSession.saveTradeConfig()
|
||||
},
|
||||
helperText = "현제 변동율이 이것보다 커야 분석 함."
|
||||
helperText = "이 수치보다 커야 분석"
|
||||
)
|
||||
SettingInputField(
|
||||
modifier = Modifier.weight(1.0f, true),
|
||||
label = "매수 분석 현 변동율 최고 기준",
|
||||
modifier = Modifier.weight(1.0f, true).padding(start = 4.dp),
|
||||
label = "매수 분석 최고 기준 (%)",
|
||||
initialValue = (tradeConfig.plusFilter).toString(),
|
||||
onSave = {
|
||||
tradeConfig.plusFilter = it.toDouble()
|
||||
KisSession.saveTradeConfig()
|
||||
},
|
||||
helperText = "현제 변동율이 이것보다 작아야 분석 함."
|
||||
helperText = "이 수치보다 작아야 분석"
|
||||
)
|
||||
}
|
||||
// Boolean 설정들
|
||||
|
||||
// 🌟 [수정] 미체결 자동 취소(스위치, 시간, 갭 비율) 3개를 한 줄로 병합
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(vertical = 4.dp)
|
||||
) {
|
||||
SettingSwitchField(
|
||||
label = "미체결 자동 취소 (매수)",
|
||||
modifier = Modifier.weight(1.2f).padding(end = 4.dp),
|
||||
label = "미체결 자동취소", // 라벨 축소
|
||||
initialChecked = tradeConfig.auto_cancel_pending_buy,
|
||||
helperText = "지정 시간 경과 시 미체결 매수 주문 취소",
|
||||
onCheckedChange = { tradeConfig.auto_cancel_pending_buy = it
|
||||
helperText = "매수 미체결 시 취소",
|
||||
onCheckedChange = {
|
||||
tradeConfig.auto_cancel_pending_buy = it
|
||||
KisSession.saveTradeConfig()
|
||||
}
|
||||
)
|
||||
|
||||
SettingInputField(
|
||||
label = "자동 취소 대기 시간 (분)",
|
||||
modifier = Modifier.weight(1f).padding(horizontal = 4.dp),
|
||||
label = "대기 시간 (분)",
|
||||
initialValue = (tradeConfig.auto_cancel_pending_time / (60 * 1000)).toString(),
|
||||
onSave = {
|
||||
val minutes = it.toLongOrNull() ?: 60L
|
||||
tradeConfig.auto_cancel_pending_time = minutes * 60 * 1000
|
||||
KisSession.saveTradeConfig()
|
||||
},
|
||||
helperText = "현재: ${tradeConfig.auto_cancel_pending_time / 1000}초 후 취소"
|
||||
helperText = "${tradeConfig.auto_cancel_pending_time / 1000}초 후 대조"
|
||||
)
|
||||
|
||||
SettingInputField(
|
||||
label = "자동 취소 갭 비율",
|
||||
modifier = Modifier.weight(1f).padding(start = 4.dp),
|
||||
label = "취소 갭 비율",
|
||||
initialValue = (tradeConfig.auto_cancel_pending_rate).toString(),
|
||||
onSave = {
|
||||
val rate = it.toDoubleOrNull() ?: 2.0
|
||||
tradeConfig.auto_cancel_pending_rate = rate
|
||||
KisSession.saveTradeConfig()
|
||||
},
|
||||
helperText = "현재: ${tradeConfig.auto_cancel_pending_time / 1000}초 후 취소"
|
||||
helperText = "이탈 시 취소"
|
||||
)
|
||||
}
|
||||
|
||||
Row(horizontalArrangement = Arrangement.SpaceEvenly) {
|
||||
SettingSwitchField (
|
||||
@@ -1121,20 +1179,24 @@ fun FilterChipWithRightClick(
|
||||
* 시:분 입력을 위한 전용 컴포저블
|
||||
*/
|
||||
@Composable
|
||||
fun TimeInputRow(label: String, initialTime: String, onTimeChange: (String) -> Unit) {
|
||||
// 💡 화면에 즉시 글자를 보여주기 위한 로컬 상태
|
||||
fun TimeInputRow(
|
||||
modifier: Modifier = Modifier, // 🌟 modifier 파라미터 추가
|
||||
label: String,
|
||||
initialTime: String,
|
||||
onTimeChange: (String) -> Unit
|
||||
) {
|
||||
var localText by remember(initialTime) { mutableStateOf(initialTime) }
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp),
|
||||
modifier = modifier.padding(vertical = 4.dp, horizontal = 4.dp), // 🌟 수정
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(label, modifier = Modifier.width(80.dp), fontSize = 13.sp, fontWeight = FontWeight.Medium)
|
||||
// 🌟 글자 크기와 너비를 약간 줄여서 한 줄에 두 개가 들어가도 예쁘게 설정
|
||||
Text(label, modifier = Modifier.width(65.dp), fontSize = 12.sp, fontWeight = FontWeight.Medium)
|
||||
|
||||
OutlinedTextField(
|
||||
value = localText,
|
||||
onValueChange = {
|
||||
// 5글자(HH:mm) 제한 및 입력 제어
|
||||
if (it.length <= 5) {
|
||||
localText = it
|
||||
}
|
||||
@@ -1143,7 +1205,6 @@ fun TimeInputRow(label: String, initialTime: String, onTimeChange: (String) -> U
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.onFocusChanged { focusState ->
|
||||
// 💡 포커스를 잃었을 때(입력 완료 시) 실제 데이터 객체에 저장
|
||||
if (!focusState.isFocused) {
|
||||
onTimeChange(localText)
|
||||
}
|
||||
@@ -1151,12 +1212,12 @@ fun TimeInputRow(label: String, initialTime: String, onTimeChange: (String) -> U
|
||||
singleLine = true,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
imeAction = ImeAction.Done,
|
||||
keyboardType = KeyboardType.Number // 숫자 키패드 유도
|
||||
keyboardType = KeyboardType.Number
|
||||
),
|
||||
keyboardActions = KeyboardActions(
|
||||
onDone = { onTimeChange(localText) }
|
||||
),
|
||||
textStyle = androidx.compose.ui.text.TextStyle(fontSize = 14.sp)
|
||||
textStyle = androidx.compose.ui.text.TextStyle(fontSize = 13.sp)
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user