...
This commit is contained in:
parent
62feed6078
commit
ef1847f115
@ -1,11 +1,16 @@
|
|||||||
|
import ConfigTable.grade_1_allocationrate
|
||||||
import ConfigTable.grade_1_buy
|
import ConfigTable.grade_1_buy
|
||||||
import ConfigTable.grade_1_profit
|
import ConfigTable.grade_1_profit
|
||||||
|
import ConfigTable.grade_2_allocationrate
|
||||||
import ConfigTable.grade_2_buy
|
import ConfigTable.grade_2_buy
|
||||||
import ConfigTable.grade_2_profit
|
import ConfigTable.grade_2_profit
|
||||||
|
import ConfigTable.grade_3_allocationrate
|
||||||
import ConfigTable.grade_3_buy
|
import ConfigTable.grade_3_buy
|
||||||
import ConfigTable.grade_3_profit
|
import ConfigTable.grade_3_profit
|
||||||
|
import ConfigTable.grade_4_allocationrate
|
||||||
import ConfigTable.grade_4_buy
|
import ConfigTable.grade_4_buy
|
||||||
import ConfigTable.grade_4_profit
|
import ConfigTable.grade_4_profit
|
||||||
|
import ConfigTable.grade_5_allocationrate
|
||||||
import ConfigTable.grade_5_buy
|
import ConfigTable.grade_5_buy
|
||||||
import ConfigTable.grade_5_profit
|
import ConfigTable.grade_5_profit
|
||||||
import ConfigTable.max_count
|
import ConfigTable.max_count
|
||||||
@ -195,6 +200,11 @@ fun main() = application {
|
|||||||
GRADE_2_PROFIT = it[grade_2_profit],
|
GRADE_2_PROFIT = it[grade_2_profit],
|
||||||
GRADE_1_BUY = it[grade_1_buy],
|
GRADE_1_BUY = it[grade_1_buy],
|
||||||
GRADE_1_PROFIT = it[grade_1_profit],
|
GRADE_1_PROFIT = it[grade_1_profit],
|
||||||
|
GRADE_1_ALLOCATIONRATE = it[grade_1_allocationrate],
|
||||||
|
GRADE_2_ALLOCATIONRATE = it[grade_2_allocationrate],
|
||||||
|
GRADE_3_ALLOCATIONRATE = it[grade_3_allocationrate],
|
||||||
|
GRADE_4_ALLOCATIONRATE = it[grade_4_allocationrate],
|
||||||
|
GRADE_5_ALLOCATIONRATE = it[grade_5_allocationrate],
|
||||||
MAX_COUNT = it[max_count],
|
MAX_COUNT = it[max_count],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,15 +47,34 @@ object ConfigTable : Table("app_config") {
|
|||||||
val min_purchase_score = double("min_purchase_score").default( 65.0)
|
val min_purchase_score = double("min_purchase_score").default( 65.0)
|
||||||
val sell_profit = double("sell_profit").default( 1.0)
|
val sell_profit = double("sell_profit").default( 1.0)
|
||||||
val grade_5_buy = integer("grade_5_buy").default(0)
|
val grade_5_buy = integer("grade_5_buy").default(0)
|
||||||
val grade_5_profit = double("grade_5_profit").default(1.8)
|
|
||||||
val grade_4_buy = integer("grade_4_buy").default(1)
|
val grade_4_buy = integer("grade_4_buy").default(1)
|
||||||
val grade_4_profit = double("grade_4_profit").default(1.3)
|
|
||||||
val grade_3_buy = integer("grade_3_buy").default(1)
|
val grade_3_buy = integer("grade_3_buy").default(1)
|
||||||
val grade_3_profit = double("grade_3_profit").default(0.9)
|
|
||||||
val grade_2_buy = integer("grade_2_buy").default(2)
|
val grade_2_buy = integer("grade_2_buy").default(2)
|
||||||
val grade_2_profit = double("grade_2_profit").default(0.7)
|
|
||||||
val grade_1_buy = integer("grade_1_buy").default(3)
|
val grade_1_buy = integer("grade_1_buy").default(3)
|
||||||
|
val grade_5_profit = double("grade_5_profit").default(1.8)
|
||||||
|
val grade_4_profit = double("grade_4_profit").default(1.3)
|
||||||
|
val grade_3_profit = double("grade_3_profit").default(0.9)
|
||||||
|
val grade_2_profit = double("grade_2_profit").default(0.7)
|
||||||
val grade_1_profit = double("grade_1_profit").default(0.5)
|
val grade_1_profit = double("grade_1_profit").default(0.5)
|
||||||
|
|
||||||
|
val grade_5_allocationrate = double("grade_5_allocationrate").default(1.0)
|
||||||
|
val grade_4_allocationrate = double("grade_4_allocationrate").default(0.8)
|
||||||
|
val grade_3_allocationrate = double("grade_3_allocationrate").default(0.6)
|
||||||
|
val grade_2_allocationrate = double("grade_2_allocationrate").default(0.4)
|
||||||
|
val grade_1_allocationrate = double("grade_1_allocationrate").default(0.3)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
val max_count = integer("max_count").default(20)
|
val max_count = integer("max_count").default(20)
|
||||||
override val primaryKey = PrimaryKey(id)
|
override val primaryKey = PrimaryKey(id)
|
||||||
}
|
}
|
||||||
@ -260,6 +279,11 @@ object DatabaseFactory {
|
|||||||
GRADE_2_PROFIT = it[ConfigTable.grade_2_profit],
|
GRADE_2_PROFIT = it[ConfigTable.grade_2_profit],
|
||||||
GRADE_1_BUY = it[ConfigTable.grade_1_buy],
|
GRADE_1_BUY = it[ConfigTable.grade_1_buy],
|
||||||
GRADE_1_PROFIT = it[ConfigTable.grade_1_profit],
|
GRADE_1_PROFIT = it[ConfigTable.grade_1_profit],
|
||||||
|
GRADE_1_ALLOCATIONRATE = it[ConfigTable.grade_1_allocationrate],
|
||||||
|
GRADE_2_ALLOCATIONRATE = it[ConfigTable.grade_2_allocationrate],
|
||||||
|
GRADE_3_ALLOCATIONRATE = it[ConfigTable.grade_3_allocationrate],
|
||||||
|
GRADE_4_ALLOCATIONRATE = it[ConfigTable.grade_4_allocationrate],
|
||||||
|
GRADE_5_ALLOCATIONRATE = it[ConfigTable.grade_5_allocationrate],
|
||||||
MAX_COUNT = it[ConfigTable.max_count],
|
MAX_COUNT = it[ConfigTable.max_count],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -300,6 +324,12 @@ object DatabaseFactory {
|
|||||||
it[grade_2_profit] = config.GRADE_2_PROFIT
|
it[grade_2_profit] = config.GRADE_2_PROFIT
|
||||||
it[grade_1_buy] = config.GRADE_1_BUY
|
it[grade_1_buy] = config.GRADE_1_BUY
|
||||||
it[grade_1_profit] = config.GRADE_1_PROFIT
|
it[grade_1_profit] = config.GRADE_1_PROFIT
|
||||||
|
it[grade_5_allocationrate] = config.GRADE_5_ALLOCATIONRATE
|
||||||
|
it[grade_4_allocationrate] = config.GRADE_4_ALLOCATIONRATE
|
||||||
|
it[grade_3_allocationrate] = config.GRADE_3_ALLOCATIONRATE
|
||||||
|
it[grade_2_allocationrate] = config.GRADE_2_ALLOCATIONRATE
|
||||||
|
it[grade_1_allocationrate] = config.GRADE_1_ALLOCATIONRATE
|
||||||
|
|
||||||
it[max_count] = config.MAX_COUNT
|
it[max_count] = config.MAX_COUNT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,7 +25,15 @@ enum class ConfigIndex(val index : Int,val label : String) {
|
|||||||
GRADE_4_PROFIT(GRADE_5_PROFIT.index + 1, "안정적 투자 목표 수익 비율"),
|
GRADE_4_PROFIT(GRADE_5_PROFIT.index + 1, "안정적 투자 목표 수익 비율"),
|
||||||
GRADE_3_PROFIT(GRADE_4_PROFIT.index + 1, "보수적 투자 목표 수익 비율"),
|
GRADE_3_PROFIT(GRADE_4_PROFIT.index + 1, "보수적 투자 목표 수익 비율"),
|
||||||
GRADE_2_PROFIT(GRADE_3_PROFIT.index + 1, "하이리스크,리턴 목표 수익 비율"),
|
GRADE_2_PROFIT(GRADE_3_PROFIT.index + 1, "하이리스크,리턴 목표 수익 비율"),
|
||||||
GRADE_1_PROFIT(GRADE_2_PROFIT.index + 1, "공격적초단기 목표 수익 비율");
|
GRADE_1_PROFIT(GRADE_2_PROFIT.index + 1, "공격적초단기 목표 수익 비율"),
|
||||||
|
|
||||||
|
|
||||||
|
GRADE_5_ALLOCATIONRATE(GRADE_1_PROFIT.index + 1, "강력 추천 투자 목표 투자금 비율"),
|
||||||
|
GRADE_4_ALLOCATIONRATE(GRADE_5_ALLOCATIONRATE.index + 1, "안정적 투자 목표 투자금 비율"),
|
||||||
|
GRADE_3_ALLOCATIONRATE(GRADE_4_ALLOCATIONRATE.index + 1, "보수적 투자 목표 투자금 비율"),
|
||||||
|
GRADE_2_ALLOCATIONRATE(GRADE_3_ALLOCATIONRATE.index + 1, "하이리스크,리턴 목표 투자금 비율"),
|
||||||
|
GRADE_1_ALLOCATIONRATE(GRADE_2_ALLOCATIONRATE.index + 1, "공격적초단기 목표 투자금 비율");
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun get(index : Int) = ConfigIndex.entries[index]
|
fun get(index : Int) = ConfigIndex.entries[index]
|
||||||
}
|
}
|
||||||
@ -82,6 +90,13 @@ data class AppConfig(
|
|||||||
var GRADE_3_PROFIT : Double = 0.9,
|
var GRADE_3_PROFIT : Double = 0.9,
|
||||||
var GRADE_2_PROFIT : Double = 0.7,
|
var GRADE_2_PROFIT : Double = 0.7,
|
||||||
var GRADE_1_PROFIT : Double = 0.5,
|
var GRADE_1_PROFIT : Double = 0.5,
|
||||||
|
|
||||||
|
var GRADE_5_ALLOCATIONRATE : Double = 1.0,
|
||||||
|
var GRADE_4_ALLOCATIONRATE : Double = 0.8,
|
||||||
|
var GRADE_3_ALLOCATIONRATE : Double = 0.6,
|
||||||
|
var GRADE_2_ALLOCATIONRATE : Double = 0.4,
|
||||||
|
var GRADE_1_ALLOCATIONRATE : Double = 0.3,
|
||||||
|
|
||||||
var MAX_COUNT : Int = 20,
|
var MAX_COUNT : Int = 20,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@ -111,7 +126,15 @@ data class AppConfig(
|
|||||||
ConfigIndex.GRADE_3_BUY -> {GRADE_3_BUY = value.toInt()}
|
ConfigIndex.GRADE_3_BUY -> {GRADE_3_BUY = value.toInt()}
|
||||||
ConfigIndex.GRADE_2_BUY -> {GRADE_2_BUY = value.toInt()}
|
ConfigIndex.GRADE_2_BUY -> {GRADE_2_BUY = value.toInt()}
|
||||||
ConfigIndex.GRADE_1_BUY -> {GRADE_1_BUY = value.toInt()}
|
ConfigIndex.GRADE_1_BUY -> {GRADE_1_BUY = value.toInt()}
|
||||||
|
|
||||||
|
|
||||||
ConfigIndex.MAX_COUNT_INDEX -> {MAX_COUNT = value.toInt()}
|
ConfigIndex.MAX_COUNT_INDEX -> {MAX_COUNT = value.toInt()}
|
||||||
|
|
||||||
|
ConfigIndex.GRADE_5_ALLOCATIONRATE -> {GRADE_5_ALLOCATIONRATE = value}
|
||||||
|
ConfigIndex.GRADE_4_ALLOCATIONRATE -> {GRADE_4_ALLOCATIONRATE = value}
|
||||||
|
ConfigIndex.GRADE_3_ALLOCATIONRATE -> {GRADE_3_ALLOCATIONRATE = value}
|
||||||
|
ConfigIndex.GRADE_2_ALLOCATIONRATE -> {GRADE_2_ALLOCATIONRATE = value}
|
||||||
|
ConfigIndex.GRADE_1_ALLOCATIONRATE -> {GRADE_1_ALLOCATIONRATE = value}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun getValues(index :ConfigIndex) : Double {
|
fun getValues(index :ConfigIndex) : Double {
|
||||||
@ -148,6 +171,14 @@ data class AppConfig(
|
|||||||
ConfigIndex.GRADE_3_PROFIT -> {GRADE_3_PROFIT}
|
ConfigIndex.GRADE_3_PROFIT -> {GRADE_3_PROFIT}
|
||||||
ConfigIndex.GRADE_2_PROFIT -> {GRADE_2_PROFIT}
|
ConfigIndex.GRADE_2_PROFIT -> {GRADE_2_PROFIT}
|
||||||
ConfigIndex.GRADE_1_PROFIT -> {GRADE_1_PROFIT}
|
ConfigIndex.GRADE_1_PROFIT -> {GRADE_1_PROFIT}
|
||||||
|
|
||||||
|
ConfigIndex.GRADE_5_ALLOCATIONRATE -> {GRADE_5_ALLOCATIONRATE}
|
||||||
|
ConfigIndex.GRADE_4_ALLOCATIONRATE -> {GRADE_4_ALLOCATIONRATE}
|
||||||
|
ConfigIndex.GRADE_3_ALLOCATIONRATE -> {GRADE_3_ALLOCATIONRATE}
|
||||||
|
ConfigIndex.GRADE_2_ALLOCATIONRATE -> {GRADE_2_ALLOCATIONRATE}
|
||||||
|
ConfigIndex.GRADE_1_ALLOCATIONRATE -> {GRADE_1_ALLOCATIONRATE}
|
||||||
|
|
||||||
|
|
||||||
ConfigIndex.MAX_COUNT_INDEX -> {MAX_COUNT.toDouble()}
|
ConfigIndex.MAX_COUNT_INDEX -> {MAX_COUNT.toDouble()}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -215,59 +215,3 @@ data class ExecutionData(
|
|||||||
val qty: String,
|
val qty: String,
|
||||||
val isFilled: Boolean
|
val isFilled: Boolean
|
||||||
)
|
)
|
||||||
|
|
||||||
enum class InvestmentGrade(
|
|
||||||
val displayName: String,
|
|
||||||
val description: String,
|
|
||||||
val shortWeight: Double = 0.0,
|
|
||||||
val midWeight: Double = 0.0,
|
|
||||||
val longWeight: Double = 0.0,
|
|
||||||
val profitGuide: ConfigIndex,
|
|
||||||
val buyGuide: ConfigIndex,
|
|
||||||
) {
|
|
||||||
LEVEL_5_STRONG_RECOMMEND(
|
|
||||||
displayName = "최상급 추천",
|
|
||||||
description = "단기·중기·장기 모두 우수하고, 신뢰도 매우 높은 범용 매수 추천",
|
|
||||||
shortWeight = 1.0,
|
|
||||||
midWeight = 1.0,
|
|
||||||
longWeight = 1.0,
|
|
||||||
profitGuide = ConfigIndex.GRADE_5_PROFIT,
|
|
||||||
buyGuide = ConfigIndex.GRADE_5_BUY,
|
|
||||||
),
|
|
||||||
LEVEL_4_BALANCED_RECOMMEND(
|
|
||||||
displayName = "균형 추천",
|
|
||||||
description = "중기·장기 기본은 양호하고, 단기 성과도 준수한 안정형 추천",
|
|
||||||
shortWeight = 0.8,
|
|
||||||
midWeight = 1.0,
|
|
||||||
longWeight = 1.0,
|
|
||||||
profitGuide = ConfigIndex.GRADE_4_PROFIT,
|
|
||||||
buyGuide = ConfigIndex.GRADE_4_BUY,
|
|
||||||
),
|
|
||||||
LEVEL_3_CAUTIOUS_RECOMMEND(
|
|
||||||
displayName = "보수적 추천",
|
|
||||||
description = "중기/장기 기본은 양호하지만, 단기 변동성이 높아 신중히 접근해야 함",
|
|
||||||
shortWeight = 0.6,
|
|
||||||
midWeight = 1.0,
|
|
||||||
longWeight = 1.0,
|
|
||||||
profitGuide = ConfigIndex.GRADE_3_PROFIT,
|
|
||||||
buyGuide = ConfigIndex.GRADE_3_BUY,
|
|
||||||
),
|
|
||||||
LEVEL_2_HIGH_RISK(
|
|
||||||
displayName = "고위험 추천",
|
|
||||||
description = "단기/초단기 성과만 강하고, 중기·장기가 애매하여 리스크가 큰 투자",
|
|
||||||
shortWeight = 1.0,
|
|
||||||
midWeight = 0.4,
|
|
||||||
longWeight = 0.4,
|
|
||||||
profitGuide = ConfigIndex.GRADE_2_PROFIT,
|
|
||||||
buyGuide = ConfigIndex.GRADE_2_BUY,
|
|
||||||
),
|
|
||||||
LEVEL_1_SPECULATIVE(
|
|
||||||
displayName = "순수 공격적 선택",
|
|
||||||
description = "단기/초단기 성과에만 의존하는 단기 급등형 공격적 투자",
|
|
||||||
shortWeight = 1.0,
|
|
||||||
midWeight = 0.2,
|
|
||||||
longWeight = 0.2,
|
|
||||||
profitGuide = ConfigIndex.GRADE_1_PROFIT,
|
|
||||||
buyGuide = ConfigIndex.GRADE_1_BUY,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|||||||
@ -31,6 +31,7 @@ import kotlinx.serialization.json.putJsonArray
|
|||||||
import kotlinx.serialization.json.putJsonObject
|
import kotlinx.serialization.json.putJsonObject
|
||||||
import model.ConfigIndex
|
import model.ConfigIndex
|
||||||
import model.KisSession
|
import model.KisSession
|
||||||
|
import model.RankingStock
|
||||||
import okhttp3.MediaType.Companion.toMediaType
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
@ -258,12 +259,16 @@ object RagService {
|
|||||||
} else {
|
} else {
|
||||||
println("✋ [$stockName] 기술 점수 미달로 분석 중단 ${scores.toString()}")
|
println("✋ [$stockName] 기술 점수 미달로 분석 중단 ${scores.toString()}")
|
||||||
TradingLogStore.addAnalyzer(stockName, stockCode, "기술 점수 미달로 분석 중단")
|
TradingLogStore.addAnalyzer(stockName, stockCode, "기술 점수 미달로 분석 중단")
|
||||||
|
if (FinancialAnalyzer.isBuyConsiderationMet(financialStmt)) {
|
||||||
|
TradingLogStore.addLog(tradingDecision,"WATCH","우량주로 판단되나 거래량 혹은 최근 거래 점수 미달로 재분석 대상에 추가")
|
||||||
|
AutoTradingManager.addToReanalysis(RankingStock(mksc_shrn_iscd = stockCode,hts_kor_isnm = stockName))
|
||||||
|
}
|
||||||
tradingDecision.confidence = 1.0
|
tradingDecision.confidence = 1.0
|
||||||
result(tradingDecision, false)
|
result(tradingDecision, false)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println("🚨 [$stockName] ${FinancialAnalyzer.toString(financialStmt)} 재무 안전벨트 미달")
|
println("🚨 [$stockName] ${FinancialAnalyzer.toString(financialStmt)} 재무 안전벨트 미달")
|
||||||
TradingLogStore.addAnalyzer(stockName, stockCode, "재무 안전벨트 미달로 분석 중단 ${FinancialAnalyzer.getInvestmentStatus(financialStmt)}")
|
TradingLogStore.addAnalyzer(stockName, stockCode, "재무 안전벨트 미달로 분석 중단 ${FinancialAnalyzer.toString(financialStmt)}")
|
||||||
tradingDecision.confidence = 1.0
|
tradingDecision.confidence = 1.0
|
||||||
result(tradingDecision, false)
|
result(tradingDecision, false)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,7 +28,6 @@ import kotlinx.serialization.Serializable
|
|||||||
import model.CandleData
|
import model.CandleData
|
||||||
import model.ConfigIndex
|
import model.ConfigIndex
|
||||||
import model.ExecutionData
|
import model.ExecutionData
|
||||||
import model.InvestmentGrade
|
|
||||||
import model.KisSession
|
import model.KisSession
|
||||||
import model.RankingStock
|
import model.RankingStock
|
||||||
import model.RankingType
|
import model.RankingType
|
||||||
@ -103,7 +102,7 @@ object AutoTradingManager {
|
|||||||
println("🚀 [자동매수 실행] ${completeTradingDecision.stockName}")
|
println("🚀 [자동매수 실행] ${completeTradingDecision.stockName}")
|
||||||
if (completeTradingDecision.confidence < 10) {
|
if (completeTradingDecision.confidence < 10) {
|
||||||
addToReanalysis(RankingStock(mksc_shrn_iscd = completeTradingDecision.stockCode,hts_kor_isnm = completeTradingDecision.stockName))
|
addToReanalysis(RankingStock(mksc_shrn_iscd = completeTradingDecision.stockCode,hts_kor_isnm = completeTradingDecision.stockName))
|
||||||
TradingLogStore.addLog(completeTradingDecision,"HOLD","분석 신뢰도 오류 인지로 재분석 대기열에 추가")
|
TradingLogStore.addLog(completeTradingDecision,"RETRY","분석 신뢰도 오류 인지로 재분석 대기열에 추가")
|
||||||
}else if (completeTradingDecision != null && !completeTradingDecision.stockCode.isNullOrEmpty()) {
|
}else if (completeTradingDecision != null && !completeTradingDecision.stockCode.isNullOrEmpty()) {
|
||||||
var basePrice = completeTradingDecision.currentPrice
|
var basePrice = completeTradingDecision.currentPrice
|
||||||
var stockCode = completeTradingDecision.stockCode
|
var stockCode = completeTradingDecision.stockCode
|
||||||
@ -129,19 +128,10 @@ object AutoTradingManager {
|
|||||||
var investmentGrade : InvestmentGrade = AutoTradingManager.getInvestmentGrade(completeTradingDecision,totalScore, completeTradingDecision.confidence)
|
var investmentGrade : InvestmentGrade = AutoTradingManager.getInvestmentGrade(completeTradingDecision,totalScore, completeTradingDecision.confidence)
|
||||||
|
|
||||||
val finalMargin = baseProfit * KisSession.config.getValues(investmentGrade.profitGuide)
|
val finalMargin = baseProfit * KisSession.config.getValues(investmentGrade.profitGuide)
|
||||||
// println("""
|
|
||||||
// 사명 : ${completeTradingDecision.corpName}
|
|
||||||
// 신뢰도 : ${completeTradingDecision.confidence + append}
|
|
||||||
// 단기성 : ${completeTradingDecision.shortPossible() + append}
|
|
||||||
// 수익성 : ${completeTradingDecision.profitPossible()+ append}
|
|
||||||
// 안전성 : ${completeTradingDecision.safePossible()+ append}
|
|
||||||
// ${investmentGrade.displayName} : ${investmentGrade.description}
|
|
||||||
// 총점 : ${totalScore}
|
|
||||||
// """.trimIndent())
|
|
||||||
println("🚀 [매수 진행] 토탈 스코어: ${String.format("%.1f", totalScore)} -> 종목: ${completeTradingDecision.stockCode}")
|
println("🚀 [매수 진행] 토탈 스코어: ${String.format("%.1f", totalScore)} -> 종목: ${completeTradingDecision.stockCode}")
|
||||||
|
|
||||||
// basePrice(현재가 혹은 지정가)를 기준으로 매수 가능 수량 산출 (최소 1주 보장)
|
// basePrice(현재가 혹은 지정가)를 기준으로 매수 가능 수량 산출 (최소 1주 보장)
|
||||||
val gradeRate = (1.0 - (investmentGrade.ordinal * 0.1))
|
val gradeRate = (1.0 - (investmentGrade.ordinal * 0.12))
|
||||||
val maxQty = (KisSession.config.getValues(ConfigIndex.MAX_COUNT_INDEX) * gradeRate).roundToInt()
|
val maxQty = (KisSession.config.getValues(ConfigIndex.MAX_COUNT_INDEX) * gradeRate).roundToInt()
|
||||||
maxBudget = maxBudget * gradeRate
|
maxBudget = maxBudget * gradeRate
|
||||||
val calculatedQty = if (basePrice > 0) {
|
val calculatedQty = if (basePrice > 0) {
|
||||||
@ -159,7 +149,7 @@ object AutoTradingManager {
|
|||||||
|
|
||||||
} else if(totalScore >= (minScore * 0.85) && completeTradingDecision.confidence + append >= (MIN_CONFIDENCE * 0.85)) {
|
} else if(totalScore >= (minScore * 0.85) && completeTradingDecision.confidence + append >= (MIN_CONFIDENCE * 0.85)) {
|
||||||
addToReanalysis(RankingStock(mksc_shrn_iscd = completeTradingDecision.stockCode,hts_kor_isnm = completeTradingDecision.stockName))
|
addToReanalysis(RankingStock(mksc_shrn_iscd = completeTradingDecision.stockCode,hts_kor_isnm = completeTradingDecision.stockName))
|
||||||
TradingLogStore.addLog(completeTradingDecision,"HOLD","✋ [관망] 토탈 스코어[$totalScore] 또는 신뢰도[${completeTradingDecision.confidence}] 미달 이나 약간의 오차로 재분석 대기열에 추가")
|
TradingLogStore.addLog(completeTradingDecision,"RETRY","✋ [관망] 토탈 스코어[$totalScore] 또는 신뢰도[${completeTradingDecision.confidence}] 미달 이나 약간의 오차로 재분석 대기열에 추가")
|
||||||
} else {
|
} else {
|
||||||
TradingLogStore.addLog(completeTradingDecision,"HOLD","✋ [관망] 토탈 스코어(${String.format("%.1f[${minScore}]", totalScore)}) 또는 신뢰도 (${String.format("%.1f[${MIN_CONFIDENCE}]", completeTradingDecision.confidence)}) 미달")
|
TradingLogStore.addLog(completeTradingDecision,"HOLD","✋ [관망] 토탈 스코어(${String.format("%.1f[${minScore}]", totalScore)}) 또는 신뢰도 (${String.format("%.1f[${MIN_CONFIDENCE}]", completeTradingDecision.confidence)}) 미달")
|
||||||
}
|
}
|
||||||
@ -285,7 +275,7 @@ object AutoTradingManager {
|
|||||||
|
|
||||||
if (it.message?.contains("주문가능금액을 초과") == true) {
|
if (it.message?.contains("주문가능금액을 초과") == true) {
|
||||||
AutoTradingManager.addToReanalysis(RankingStock(mksc_shrn_iscd = stockCode,hts_kor_isnm = stockName))
|
AutoTradingManager.addToReanalysis(RankingStock(mksc_shrn_iscd = stockCode,hts_kor_isnm = stockName))
|
||||||
TradingLogStore.addLog(decision,"BUY","${it.message ?: " 매수 실패"} => 재분석 대기열에 추가")
|
TradingLogStore.addLog(decision,"WATCH","${it.message ?: " 매수 실패"} => 재분석 대기열에 추가")
|
||||||
} else {
|
} else {
|
||||||
TradingLogStore.addLog(decision,"BUY",it.message ?: "매수 실패")
|
TradingLogStore.addLog(decision,"BUY",it.message ?: "매수 실패")
|
||||||
}
|
}
|
||||||
@ -382,6 +372,11 @@ object AutoTradingManager {
|
|||||||
balance.holdings.forEach { holding ->
|
balance.holdings.forEach { holding ->
|
||||||
if (BLACKLISTEDSTOCKCODES.contains(holding.code)){
|
if (BLACKLISTEDSTOCKCODES.contains(holding.code)){
|
||||||
println("❌ 차단 처리된 주식 : ${holding.name}")
|
println("❌ 차단 처리된 주식 : ${holding.name}")
|
||||||
|
TradingLogStore.addAnalyzer(
|
||||||
|
holding.name,
|
||||||
|
holding.code,
|
||||||
|
"거랙 차단 대상 : ${holding.currentPrice}[${holding.quantity}주] 보유, 수익률(${holding.profitRate.toDouble()})"
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
if (holding != null && holding.quantity.toInt() > 0 && holding.availOrderCount.toInt() > 0 && holding.profitRate.toDouble() > KisSession.config.SELL_PROFIT) {
|
if (holding != null && holding.quantity.toInt() > 0 && holding.availOrderCount.toInt() > 0 && holding.profitRate.toDouble() > KisSession.config.SELL_PROFIT) {
|
||||||
println("${holding.name} - 매수 : ${holding.avgPrice} - 현재 : ${holding.currentPrice} ")
|
println("${holding.name} - 매수 : ${holding.avgPrice} - 현재 : ${holding.currentPrice} ")
|
||||||
@ -414,10 +409,13 @@ object AutoTradingManager {
|
|||||||
"SELL",
|
"SELL",
|
||||||
"🎊 보유 주식 매도 주문 실패[${it.message}] "
|
"🎊 보유 주식 매도 주문 실패[${it.message}] "
|
||||||
)
|
)
|
||||||
// println("❌ [재주문 실패] ${holding.name}: ${it.message}")
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
TradingLogStore.addAnalyzer(
|
||||||
|
"보유주식[${holding.name}]",
|
||||||
|
holding.code,
|
||||||
|
"수익률 미달 : ${holding.currentPrice}[${holding.quantity}주] 보유, 수익률(${holding.profitRate.toDouble()})"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
delay(200) // API 호출 부하 방지
|
delay(200) // API 호출 부하 방지
|
||||||
}
|
}
|
||||||
@ -560,9 +558,14 @@ object AutoTradingManager {
|
|||||||
return batch
|
return batch
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun executeMarketLoop() {
|
suspend fun checkBalance() : UnifiedBalance? {
|
||||||
val balance = KisTradeService.fetchIntegratedBalance().getOrNull()
|
val balance = KisTradeService.fetchIntegratedBalance().getOrNull()
|
||||||
|
if (AUTOSELL) balance?.let { resumePendingSellOrders(KisTradeService, it) }
|
||||||
|
return balance
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun executeMarketLoop() {
|
||||||
|
val balance = checkBalance()
|
||||||
if (AUTOSELL) balance?.let { resumePendingSellOrders(KisTradeService, it) }
|
if (AUTOSELL) balance?.let { resumePendingSellOrders(KisTradeService, it) }
|
||||||
|
|
||||||
val myCash = balance?.deposit?.replace(",", "")?.toLongOrNull() ?: 0L
|
val myCash = balance?.deposit?.replace(",", "")?.toLongOrNull() ?: 0L
|
||||||
@ -622,9 +625,31 @@ object AutoTradingManager {
|
|||||||
println("남은 후보군 개수 : ${totalCount}")
|
println("남은 후보군 개수 : ${totalCount}")
|
||||||
delay(100)
|
delay(100)
|
||||||
}
|
}
|
||||||
|
sellSchedule()
|
||||||
}
|
}
|
||||||
println("⏱️ [Cycle End] ${LocalTime.now()}")
|
println("⏱️ [Cycle End] ${LocalTime.now()}")
|
||||||
}
|
}
|
||||||
|
private var lastForceCheckMinute = -1 // 마지막으로 강제 체크를 수행한 '분'을 저장
|
||||||
|
suspend fun sellSchedule() {
|
||||||
|
|
||||||
|
val now = LocalTime.now()
|
||||||
|
val currentMinute = now.minute
|
||||||
|
println("매도 스케줄 체크")
|
||||||
|
if (now.hour == 9 && (currentMinute == 1 || currentMinute == 15 || currentMinute == 40)) {
|
||||||
|
if (lastForceCheckMinute != currentMinute) {
|
||||||
|
TradingLogStore.addAnalyzer(" - ", " - ", "⏰ [강제 스케줄 실행] 오전 9시 ${currentMinute}분 - 보유주식 매도 체크를 시작합니다.", true)
|
||||||
|
println("⏰ [강제 스케줄 실행] 오전 9시 ${currentMinute}분 - 보유주식 매도 체크를 시작합니다.")
|
||||||
|
checkBalance()
|
||||||
|
lastForceCheckMinute = currentMinute // 실행 완료 기록
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// else if(now.hour % 2 == 1 && (currentMinute == 43)) {
|
||||||
|
// TradingLogStore.addAnalyzer(" - ", " - ", "⏰ [강제 스케줄 실행] 오전 9시 ${currentMinute}분 - 보유주식 매도 체크를 시작합니다.", true)
|
||||||
|
// println("⏰ [강제 스케줄 실행] 오전 ${now.hour}시 ${currentMinute}분 - 보유주식 매도 체크를 시작합니다.")
|
||||||
|
// checkBalance()
|
||||||
|
// lastForceCheckMinute = currentMinute // 실행 완료 기록
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun finalizeMarketClose(now: LocalTime) {
|
suspend fun finalizeMarketClose(now: LocalTime) {
|
||||||
when {
|
when {
|
||||||
@ -1035,7 +1060,7 @@ class TechnicalAnalyzer {
|
|||||||
val disparityDaily = (currentPrice / ma20Daily) * 100
|
val disparityDaily = (currentPrice / ma20Daily) * 100
|
||||||
|
|
||||||
if (disparityDaily > 115.0) { // 20일선보다 15% 이상 떠 있으면 감점 시작
|
if (disparityDaily > 115.0) { // 20일선보다 15% 이상 떠 있으면 감점 시작
|
||||||
val penalty = ((disparityDaily - 115.0) * 1).toInt() // 초과분 1%당 2점 감점
|
val penalty = ((disparityDaily - 115.0) * 0.5).toInt() // 초과분 1%당 2점 감점
|
||||||
short -= penalty
|
short -= penalty
|
||||||
ultra -= (penalty / 2) // 초단기에도 영향
|
ultra -= (penalty / 2) // 초단기에도 영향
|
||||||
println("⚠️ [과열 감점] 일봉 이격도(${String.format("%.1f", disparityDaily)}%): -${penalty}점")
|
println("⚠️ [과열 감점] 일봉 이격도(${String.format("%.1f", disparityDaily)}%): -${penalty}점")
|
||||||
@ -1046,9 +1071,9 @@ class TechnicalAnalyzer {
|
|||||||
if (weekly.size >= 3) {
|
if (weekly.size >= 3) {
|
||||||
val weeklyChange = calculateChange(weekly.takeLast(3))
|
val weeklyChange = calculateChange(weekly.takeLast(3))
|
||||||
if (weeklyChange > 30.0) { // 3주간 30% 이상 급등 시
|
if (weeklyChange > 30.0) { // 3주간 30% 이상 급등 시
|
||||||
mid -= 15
|
mid -= 10
|
||||||
short -= 7
|
short -= 5
|
||||||
println("⚠️ [과열 감점] 주봉 급등(${String.format("%.1f", weeklyChange)}%): -15점")
|
println("⚠️ [과열 감점] 주봉 급등(${String.format("%.1f", weeklyChange)}%): -10점")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1436,3 +1461,67 @@ fun CandleData.toScalpingCandle(): Candle {
|
|||||||
fun List<CandleData>.toScalpingList(): List<Candle> {
|
fun List<CandleData>.toScalpingList(): List<Candle> {
|
||||||
return this.map { it.toScalpingCandle() }
|
return this.map { it.toScalpingCandle() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum class InvestmentGrade(
|
||||||
|
val displayName: String,
|
||||||
|
val description: String,
|
||||||
|
val shortWeight: Double = 0.0,
|
||||||
|
val midWeight: Double = 0.0,
|
||||||
|
val longWeight: Double = 0.0,
|
||||||
|
val profitGuide: ConfigIndex,
|
||||||
|
val buyGuide: ConfigIndex,
|
||||||
|
val allocationRate: ConfigIndex,
|
||||||
|
) {
|
||||||
|
LEVEL_5_STRONG_RECOMMEND(
|
||||||
|
displayName = "최상급 추천",
|
||||||
|
description = "단기·중기·장기 모두 우수하고, 신뢰도 매우 높은 범용 매수 추천",
|
||||||
|
shortWeight = 1.0,
|
||||||
|
midWeight = 1.0,
|
||||||
|
longWeight = 1.0,
|
||||||
|
profitGuide = ConfigIndex.GRADE_5_PROFIT,
|
||||||
|
buyGuide = ConfigIndex.GRADE_5_BUY,
|
||||||
|
allocationRate = ConfigIndex.GRADE_5_ALLOCATIONRATE,
|
||||||
|
),
|
||||||
|
LEVEL_4_BALANCED_RECOMMEND(
|
||||||
|
displayName = "균형 추천",
|
||||||
|
description = "중기·장기 기본은 양호하고, 단기 성과도 준수한 안정형 추천",
|
||||||
|
shortWeight = 0.8,
|
||||||
|
midWeight = 1.0,
|
||||||
|
longWeight = 1.0,
|
||||||
|
profitGuide = ConfigIndex.GRADE_4_PROFIT,
|
||||||
|
buyGuide = ConfigIndex.GRADE_4_BUY,
|
||||||
|
allocationRate = ConfigIndex.GRADE_4_ALLOCATIONRATE,
|
||||||
|
),
|
||||||
|
LEVEL_3_CAUTIOUS_RECOMMEND(
|
||||||
|
displayName = "보수적 추천",
|
||||||
|
description = "중기/장기 기본은 양호하지만, 단기 변동성이 높아 신중히 접근해야 함",
|
||||||
|
shortWeight = 0.6,
|
||||||
|
midWeight = 1.0,
|
||||||
|
longWeight = 1.0,
|
||||||
|
profitGuide = ConfigIndex.GRADE_3_PROFIT,
|
||||||
|
buyGuide = ConfigIndex.GRADE_3_BUY,
|
||||||
|
allocationRate = ConfigIndex.GRADE_3_ALLOCATIONRATE,
|
||||||
|
),
|
||||||
|
LEVEL_2_HIGH_RISK(
|
||||||
|
displayName = "고위험 추천",
|
||||||
|
description = "단기/초단기 성과만 강하고, 중기·장기가 애매하여 리스크가 큰 투자",
|
||||||
|
shortWeight = 1.0,
|
||||||
|
midWeight = 0.4,
|
||||||
|
longWeight = 0.4,
|
||||||
|
profitGuide = ConfigIndex.GRADE_2_PROFIT,
|
||||||
|
buyGuide = ConfigIndex.GRADE_2_BUY,
|
||||||
|
allocationRate = ConfigIndex.GRADE_2_ALLOCATIONRATE,
|
||||||
|
),
|
||||||
|
LEVEL_1_SPECULATIVE(
|
||||||
|
displayName = "순수 공격적 선택",
|
||||||
|
description = "단기/초단기 성과에만 의존하는 단기 급등형 공격적 투자",
|
||||||
|
shortWeight = 1.0,
|
||||||
|
midWeight = 0.2,
|
||||||
|
longWeight = 0.2,
|
||||||
|
profitGuide = ConfigIndex.GRADE_1_PROFIT,
|
||||||
|
buyGuide = ConfigIndex.GRADE_1_BUY,
|
||||||
|
allocationRate = ConfigIndex.GRADE_1_ALLOCATIONRATE,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,11 +21,11 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import model.ConfigIndex
|
import model.ConfigIndex
|
||||||
import model.InvestmentGrade
|
|
||||||
import model.KisSession
|
import model.KisSession
|
||||||
import model.RankingStock
|
import model.RankingStock
|
||||||
import network.KisTradeService
|
import network.KisTradeService
|
||||||
import service.AutoTradingManager
|
import service.AutoTradingManager
|
||||||
|
import service.InvestmentGrade
|
||||||
import util.MarketUtil
|
import util.MarketUtil
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|||||||
@ -35,7 +35,7 @@ fun TradingDecisionLog() {
|
|||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
var searchQuery by remember { mutableStateOf("") }
|
var searchQuery by remember { mutableStateOf("") }
|
||||||
var selectedFilters by remember { mutableStateOf(setOf("전체")) }
|
var selectedFilters by remember { mutableStateOf(setOf("전체")) }
|
||||||
val filterOptions = listOf("전체", "BUY", "SELL", "HOLD", "SETTING","ANALYZER","PASS")
|
val filterOptions = listOf("전체", "BUY", "SELL", "HOLD", "SETTING","ANALYZER","PASS","WATCH","RETRY")
|
||||||
var llmAnalyser by remember { mutableStateOf(AutoTradingManager.llmAnalyser) }
|
var llmAnalyser by remember { mutableStateOf(AutoTradingManager.llmAnalyser) }
|
||||||
LaunchedEffect(AutoTradingManager.llmAnalyser) {
|
LaunchedEffect(AutoTradingManager.llmAnalyser) {
|
||||||
llmAnalyser = AutoTradingManager.llmAnalyser
|
llmAnalyser = AutoTradingManager.llmAnalyser
|
||||||
@ -162,6 +162,8 @@ fun TradingDecisionLog() {
|
|||||||
"HOLD" -> Color.DarkGray
|
"HOLD" -> Color.DarkGray
|
||||||
"ANALYZER" -> Color.Green
|
"ANALYZER" -> Color.Green
|
||||||
"PASS" -> Color.Yellow
|
"PASS" -> Color.Yellow
|
||||||
|
"RETRY" -> Color(0xFF00BCD4) // [추가] 하늘색 (재분석/대기열)
|
||||||
|
"WATCH" -> Color(0xFF4CAF50) // [추가] 연초록 (관심 종목 감시)
|
||||||
else -> Color.DarkGray
|
else -> Color.DarkGray
|
||||||
},
|
},
|
||||||
fontWeight = FontWeight.ExtraBold
|
fontWeight = FontWeight.ExtraBold
|
||||||
@ -182,7 +184,7 @@ fun TradingDecisionLog() {
|
|||||||
columns = GridCells.Fixed(2), // 2열 병렬 배치
|
columns = GridCells.Fixed(2), // 2열 병렬 배치
|
||||||
horizontalArrangement = Arrangement.spacedBy(6.dp),
|
horizontalArrangement = Arrangement.spacedBy(6.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(6.dp),
|
verticalArrangement = Arrangement.spacedBy(6.dp),
|
||||||
modifier = Modifier.fillMaxWidth().fillMaxHeight().background(Color.White)
|
modifier = Modifier.fillMaxWidth().weight(0.5f).background(Color.White)
|
||||||
) {
|
) {
|
||||||
var firstSet = mutableSetOf<ConfigIndex>()
|
var firstSet = mutableSetOf<ConfigIndex>()
|
||||||
item(span = { GridItemSpan(maxLineSpan) }) { // 2열을 모두 차지함
|
item(span = { GridItemSpan(maxLineSpan) }) { // 2열을 모두 차지함
|
||||||
@ -260,6 +262,15 @@ fun TradingDecisionLog() {
|
|||||||
singleLine = true
|
singleLine = true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
LazyVerticalGrid(
|
||||||
|
columns = GridCells.Fixed(3), // 2열 병렬 배치
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(6.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(6.dp),
|
||||||
|
modifier = Modifier.fillMaxWidth().weight(0.5f).background(Color.White)
|
||||||
|
) {
|
||||||
|
var firstSet = mutableSetOf<ConfigIndex>()
|
||||||
item(span = { GridItemSpan(maxLineSpan) }) { // 2열을 모두 차지함
|
item(span = { GridItemSpan(maxLineSpan) }) { // 2열을 모두 차지함
|
||||||
Text(
|
Text(
|
||||||
"💰매수 정책 및 기대 수익률",
|
"💰매수 정책 및 기대 수익률",
|
||||||
@ -268,16 +279,11 @@ fun TradingDecisionLog() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
var defaults2 = arrayOf(
|
var defaults2 = arrayOf(
|
||||||
arrayOf(ConfigIndex.GRADE_5_BUY,
|
arrayOf(ConfigIndex.GRADE_5_BUY, ConfigIndex.GRADE_5_PROFIT,ConfigIndex.GRADE_5_ALLOCATIONRATE),
|
||||||
ConfigIndex.GRADE_5_PROFIT,),
|
arrayOf(ConfigIndex.GRADE_4_BUY, ConfigIndex.GRADE_4_PROFIT,ConfigIndex.GRADE_4_ALLOCATIONRATE),
|
||||||
arrayOf(ConfigIndex.GRADE_4_BUY,
|
arrayOf(ConfigIndex.GRADE_3_BUY, ConfigIndex.GRADE_3_PROFIT,ConfigIndex.GRADE_3_ALLOCATIONRATE),
|
||||||
ConfigIndex.GRADE_4_PROFIT,),
|
arrayOf(ConfigIndex.GRADE_2_BUY, ConfigIndex.GRADE_2_PROFIT,ConfigIndex.GRADE_2_ALLOCATIONRATE),
|
||||||
arrayOf(ConfigIndex.GRADE_3_BUY,
|
arrayOf(ConfigIndex.GRADE_1_BUY, ConfigIndex.GRADE_1_PROFIT,ConfigIndex.GRADE_1_ALLOCATIONRATE),
|
||||||
ConfigIndex.GRADE_3_PROFIT,),
|
|
||||||
arrayOf(ConfigIndex.GRADE_2_BUY,
|
|
||||||
ConfigIndex.GRADE_2_PROFIT,),
|
|
||||||
arrayOf(ConfigIndex.GRADE_1_BUY,
|
|
||||||
ConfigIndex.GRADE_1_PROFIT,),
|
|
||||||
)
|
)
|
||||||
for (items in defaults2) {
|
for (items in defaults2) {
|
||||||
val common = findLongestCommonSubstring(items.first().label,items.last().label)
|
val common = findLongestCommonSubstring(items.first().label,items.last().label)
|
||||||
@ -316,6 +322,8 @@ fun TradingDecisionLog() {
|
|||||||
getRemaining(configKey.label,common) + ": 기준율(${KisSession.config.getValues(ConfigIndex.PROFIT_INDEX)}) * 성향별 비율(${KisSession.config.getValues(configKey)}) + 세금제비용(${KisSession.config.getValues(
|
getRemaining(configKey.label,common) + ": 기준율(${KisSession.config.getValues(ConfigIndex.PROFIT_INDEX)}) * 성향별 비율(${KisSession.config.getValues(configKey)}) + 세금제비용(${KisSession.config.getValues(
|
||||||
ConfigIndex.TAX_INDEX)}) = ${(localText.toDouble() * KisSession.config.getValues(ConfigIndex.PROFIT_INDEX)) + KisSession.config.getValues(
|
ConfigIndex.TAX_INDEX)}) = ${(localText.toDouble() * KisSession.config.getValues(ConfigIndex.PROFIT_INDEX)) + KisSession.config.getValues(
|
||||||
ConfigIndex.TAX_INDEX)}"
|
ConfigIndex.TAX_INDEX)}"
|
||||||
|
} else if (configKey.name.contains("ALLOCATIONRATE")) {
|
||||||
|
getRemaining(configKey.label,common) + ": 최대 ${KisSession.config.getValues(ConfigIndex.MAX_BUDGET_INDEX) * newValue}원 투자}"
|
||||||
} else {
|
} else {
|
||||||
getRemaining(configKey.label,common) + ": -${localText} 호가 매수}"
|
getRemaining(configKey.label,common) + ": -${localText} 호가 매수}"
|
||||||
}
|
}
|
||||||
@ -325,6 +333,8 @@ fun TradingDecisionLog() {
|
|||||||
getRemaining(configKey.label,common) + ": 기준율(${KisSession.config.getValues(ConfigIndex.PROFIT_INDEX)}) * 성향별 비율(${KisSession.config.getValues(configKey)}) + 세금제비용(${KisSession.config.getValues(
|
getRemaining(configKey.label,common) + ": 기준율(${KisSession.config.getValues(ConfigIndex.PROFIT_INDEX)}) * 성향별 비율(${KisSession.config.getValues(configKey)}) + 세금제비용(${KisSession.config.getValues(
|
||||||
ConfigIndex.TAX_INDEX)}) = ${(localText.toDouble() * KisSession.config.getValues(ConfigIndex.PROFIT_INDEX)) + KisSession.config.getValues(
|
ConfigIndex.TAX_INDEX)}) = ${(localText.toDouble() * KisSession.config.getValues(ConfigIndex.PROFIT_INDEX)) + KisSession.config.getValues(
|
||||||
ConfigIndex.TAX_INDEX)} "
|
ConfigIndex.TAX_INDEX)} "
|
||||||
|
} else if (configKey.name.contains("ALLOCATIONRATE")) {
|
||||||
|
getRemaining(configKey.label,common) + ": 최대 ${KisSession.config.getValues(ConfigIndex.MAX_BUDGET_INDEX) * localText.toDouble() }원 투자}"
|
||||||
} else {
|
} else {
|
||||||
getRemaining(configKey.label,common) + ": -${localText} 호가 매수}"
|
getRemaining(configKey.label,common) + ": -${localText} 호가 매수}"
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user