...
This commit is contained in:
parent
ce63b5760a
commit
e94869b9e7
@ -614,6 +614,22 @@ object TradingLogStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun addNotice(name : String, code : String, log: String) {
|
fun addNotice(name : String, code : String, log: String) {
|
||||||
|
var isSendable = false
|
||||||
|
val current = System.currentTimeMillis()
|
||||||
|
|
||||||
|
if (KisSession.tradeConfig.useTagsShare.contains("NOTICE") &&
|
||||||
|
KisSession.tradeConfig.useLogKeywordsShare.any { log.contains(it) }) {
|
||||||
|
|
||||||
|
// 대소문자 구분 없이 key를 찾기 위해 원본 code를 가공하거나 그대로 사용
|
||||||
|
val lastSentTime = noticeFilter[code.uppercase()]
|
||||||
|
|
||||||
|
// 기록이 없거나(처음 보냄), 마지막 발송 기준 30분이 지났다면
|
||||||
|
if (lastSentTime == null || (current - lastSentTime > 1000 * 60 * 30L)) {
|
||||||
|
isSendable = true
|
||||||
|
noticeFilter[code.uppercase()] = current // 즉시 발송 시간 갱신하여 중복 방지
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if (decisionLogs.size > 1000) decisionLogs.removeAt(0)
|
if (decisionLogs.size > 1000) decisionLogs.removeAt(0)
|
||||||
decisionLogs.add(
|
decisionLogs.add(
|
||||||
@ -623,28 +639,24 @@ object TradingLogStore {
|
|||||||
decision = "NOTICE",
|
decision = "NOTICE",
|
||||||
confidence = 100.0,
|
confidence = 100.0,
|
||||||
reason = log
|
reason = log
|
||||||
).apply {
|
)
|
||||||
if (KisSession.tradeConfig.useTagsShare.contains(decision) && KisSession.tradeConfig.useLogKeywordsShare.any {
|
|
||||||
log.contains(
|
|
||||||
it
|
|
||||||
)
|
|
||||||
}) {
|
|
||||||
var current = System.currentTimeMillis()
|
|
||||||
var sendable = noticeFilter.filter { it.key.equals(code, true) && ((current - it.value) > 1000 * 60 * 30L)}.isNotEmpty()
|
|
||||||
if (sendable) {
|
|
||||||
CoroutineScope(Dispatchers.Default).launch {
|
|
||||||
NewsService.sendTelegramMessage("${this@apply.decision}$name[$code] ${log}")
|
|
||||||
|
|
||||||
}}
|
|
||||||
noticeFilter[code] = current
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
if (isSendable) {
|
||||||
|
applicationScope.launch {
|
||||||
|
try {
|
||||||
|
NewsService.sendTelegramMessage("NOTICE $name[$code] $log")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// 발송 실패 시 원상복구를 원한다면 주석 해제 (단, 일시적 네트웍 장애 시 도배 위험 있음)
|
||||||
|
// noticeFilter.remove(code.uppercase())
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val applicationScope = CoroutineScope(Dispatchers.Default + SupervisorJob())
|
||||||
var noticeFilter = hashMapOf<String, Long>()
|
var noticeFilter = hashMapOf<String, Long>()
|
||||||
fun addNotice(name : String, code : String, log: String, qty: Int? = null) {
|
fun addNotice(name : String, code : String, log: String, qty: Int? = null) {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
|
|||||||
@ -254,6 +254,7 @@ class TradeConfig {
|
|||||||
var plusFilter : Double = 15.0
|
var plusFilter : Double = 15.0
|
||||||
var excuteCountOnMin : Int = 2
|
var excuteCountOnMin : Int = 2
|
||||||
var autoSellOrder : Boolean = false
|
var autoSellOrder : Boolean = false
|
||||||
|
var excuteMinCheck : Int = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -347,7 +347,7 @@ object AutoTradingManager {
|
|||||||
TradingReportManager.updateExecution(orderNo, actualSellPrice, actualSellQty)
|
TradingReportManager.updateExecution(orderNo, actualSellPrice, actualSellQty)
|
||||||
|
|
||||||
println("🎊 [매칭 성공] 매도 완료: ${dbItem.name} | 매도가: ${actualSellPrice.toInt()}")
|
println("🎊 [매칭 성공] 매도 완료: ${dbItem.name} | 매도가: ${actualSellPrice.toInt()}")
|
||||||
|
TradingLogStore.addSellLog(dbItem.name,actualSellPrice.toString(),"SELL","매도 완료")
|
||||||
myOredsAndBalanceCodes.remove(dbItem.code)
|
myOredsAndBalanceCodes.remove(dbItem.code)
|
||||||
TradingReportManager.closePositionCycle(dbItem.code) // 사이클 종료 알림
|
TradingReportManager.closePositionCycle(dbItem.code) // 사이클 종료 알림
|
||||||
|
|
||||||
@ -532,6 +532,8 @@ object AutoTradingManager {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
var errMsg = ""
|
||||||
|
var isSuccess = false
|
||||||
if (KisSession.tradeConfig.autoSellOrder
|
if (KisSession.tradeConfig.autoSellOrder
|
||||||
&& holding != null && holding.quantity.toInt() > 0
|
&& holding != null && holding.quantity.toInt() > 0
|
||||||
&& holding.availOrderCount.toInt() > 0
|
&& holding.availOrderCount.toInt() > 0
|
||||||
@ -546,15 +548,17 @@ object AutoTradingManager {
|
|||||||
price = targetPrice.toInt().toString(),
|
price = targetPrice.toInt().toString(),
|
||||||
isBuy = false,
|
isBuy = false,
|
||||||
).onSuccess { newOrderNo ->
|
).onSuccess { newOrderNo ->
|
||||||
println("✅ [보유 주식 손절 처리] 매수가 기준 (${holding.avgPrice.toDouble()} 3호가 위[${targetPrice}] 매도 주문")
|
println("✅ [보유 주식 손절 처리] ${holding.name} 매수가 기준 (${holding.avgPrice.toDouble()} 3호가 위[${targetPrice}] 매도 주문")
|
||||||
|
isSuccess = true
|
||||||
}.onFailure { err->
|
}.onFailure { err->
|
||||||
println("✅ [보유 주식 손절 처리] 실패 ${err.message}")
|
println("✅ [보유 주식 손절 처리] ${holding.name} 실패 ${targetPrice} ${err.message}")
|
||||||
|
errMsg = err.message.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
TradingLogStore.addNotice(
|
TradingLogStore.addNotice(
|
||||||
"보유주식[${holding.name}]",
|
"보유주식[${holding.name}]",
|
||||||
holding.code,
|
holding.code,
|
||||||
"매수가 기준 (${holding.avgPrice.toDouble()} 3호가 위[${targetPrice}] 매도 주문"
|
"매수가 기준 (${holding.avgPrice.toDouble()} 3호가 위[${targetPrice}] 매도 주문 ${if (isSuccess) "성공" else "실패[${errMsg}]"}"
|
||||||
)
|
)
|
||||||
} else if (KisSession.config.stop_Loss
|
} else if (KisSession.config.stop_Loss
|
||||||
&& holding != null && holding.quantity.toInt() > 0
|
&& holding != null && holding.quantity.toInt() > 0
|
||||||
@ -785,7 +789,8 @@ object AutoTradingManager {
|
|||||||
var loadedTops = mutableListOf<Pair<String, String>>()
|
var loadedTops = mutableListOf<Pair<String, String>>()
|
||||||
|
|
||||||
fun poll100Stocks(): List<Pair<String, String>> {
|
fun poll100Stocks(): List<Pair<String, String>> {
|
||||||
val count = minOf(loadedTops.size, 150)
|
loadedTops.shuffle()
|
||||||
|
val count = minOf(loadedTops.size, 200)
|
||||||
if (count == 0) return emptyList()
|
if (count == 0) return emptyList()
|
||||||
|
|
||||||
// 앞의 100개를 복사
|
// 앞의 100개를 복사
|
||||||
@ -881,7 +886,7 @@ object AutoTradingManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (remainingCandidates.isEmpty()) {
|
if (remainingCandidates.isEmpty()) {
|
||||||
if (loadedTops.size < 100) {
|
if (loadedTops.size < 200) {
|
||||||
loadedTops.addAll(StockUniverseLoader.loadUniverse())
|
loadedTops.addAll(StockUniverseLoader.loadUniverse())
|
||||||
loadedTops.shuffle()
|
loadedTops.shuffle()
|
||||||
println("✅ 총 ${loadedTops.size}개의 종목이 로드되있음.")
|
println("✅ 총 ${loadedTops.size}개의 종목이 로드되있음.")
|
||||||
@ -966,7 +971,7 @@ object AutoTradingManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
isExecuted = true
|
isExecuted = true
|
||||||
} else if (now.hour == 9) {
|
} else if (now.hour == 9 && now.minute % KisSession.tradeConfig.excuteMinCheck == 0) {
|
||||||
TradingLogStore.addAnalyzer(
|
TradingLogStore.addAnalyzer(
|
||||||
" - ",
|
" - ",
|
||||||
" - ",
|
" - ",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user