반응형
🔍 문제가 된 VBA 코드
vba
If TimeValue(ws.Cells(rr, 1).Value) <= TimeSerial(Hour(Now), Minute(Now) - functionType, 0) Then
❗ 주요 에러 발생 원인 3가지
① ws.Cells(rr, 1).Value 값이 빈 셀이거나 잘못된 시간 형식일 경우
- TimeValue() 함수는 유효한 시간 문자열이 들어와야 동작합니다.
- 예: "08:34:05"는 OK, "" 또는 "종가"는 에러 발생
🔧 해결 방법: IsDate()로 값 검사 추가
vba
If IsDate(ws.Cells(rr, 1).Value) Then
If TimeValue(ws.Cells(rr, 1).Value) <= TimeSerial(Hour(Now), Minute(Now) - functionType, 0) Then
' 처리
End If
End If
② Minute(Now) - functionType 결과가 음수가 되는 경우
- 예: Now = 09:02, functionType = 5 → Minute(Now) - 5 = -3
→ TimeSerial(9, -3, 0)는 에러 발생
🔧 해결 방법: DateAdd() 사용
vba
Dim 기준시간 As Date
기준시간 = DateAdd("n", -functionType, Now) ' functionType분 전 시간
If IsDate(ws.Cells(rr, 1).Value) Then
If TimeValue(ws.Cells(rr, 1).Value) <= TimeValue(기준시간) Then
rStart = rr + 1
Exit For
End If
End If
③ 시트에서 가져온 시간이 "hh:mm:ss"가 아닌 문자열일 경우
- 엑셀에서 포맷은 시간처럼 보여도 내부 값이 문자열이면 에러
🔧 권장 포맷: hh:mm:ss 형식으로 입력되도록 하고, 반드시 Format(..., "hh:nn:ss")로 저장
✅ 최종 권장 코드 (안정형)
vba
Dim 기준시간 As Date
기준시간 = DateAdd("n", -functionType, Now)
If IsDate(ws.Cells(rr, 1).Value) Then
If TimeValue(ws.Cells(rr, 1).Value) <= TimeValue(기준시간) Then
rStart = rr + 1
Exit For
End If
End If
📘If TimeValue(Now) > TimeValue("15:45:00") Then 이 줄에서 에러가 발생하는 경우
🔸 1. 시스템 시간이 날짜+시간이 아닌 '날짜만 있는 경우'
- Now는 일반적으로 2025-04-15 15:32:10 처럼 날짜와 시간이 함께 있는 Date형입니다.
- 하지만 Excel 또는 VBA 환경 설정에 따라 Now가 "yyyy-mm-dd" 형식으로만 인식되면 TimeValue(Now) 자체가 에러를 유발할 수 있습니다.
✅ 해결책: Time() 함수를 사용하세요.
vba
If Time > TimeValue("15:45:00") Then
✔️ Time은 시스템의 현재 "시간"만 반환하므로 TimeValue(Now)보다 안전합니다.
🔸 2. TimeValue("15:45:00") 문자열이 유효하지 않은 형식일 경우
- "15:45" 또는 "15:45:00" 형식은 일반적으로 허용되지만, 시스템 로케일 또는 Excel 버전 설정에 따라 "오후 3:45" 같은 포맷을 필요로 할 수도 있습니다.
✅ 해결책: TimeSerial 함수 사용
vba
If Time > TimeSerial(15, 45, 0) Then
→ 이 방식이 가장 안전하고, 시간 비교에 권장되는 공식 방식입니다.
✅ 최종 추천 코드 (오류 방지 완성형)
vba
If Time > TimeSerial(15, 45, 0) Then
isRunning = False
MsgBox "장이 종료되었습니다. 수집을 자동 중지합니다.", vbExclamation
Exit Sub
End If
📘전체 Excel VBA 소스 코드
vba
' 모듈 전체: 실시간 수집 + 기술분석 계산 + 버튼 제어
Dim isRunning As Boolean
Dim startTime As Double
Dim nextRunTime As Date
Dim rStart As Long, rr As Long
Dim priceRange As Range, volRange As Range
Dim functionType As Variant
'시작
Sub 시작버튼_Click()
If isRunning Then Exit Sub
isRunning = True
Application.OnTime Now + TimeValue("00:00:01"), "기록반복"
End Sub
'중지
Sub 중지버튼_Click()
If isRunning Then
On Error Resume Next
Application.OnTime EarliestTime:=nextRunTime, Procedure:="기록반복", Schedule:=False
isRunning = False
MsgBox "수집이 중지되었습니다.", vbInformation
End If
End Sub
'초기화
Sub 초기화버튼_Click()
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
If MsgBox("데이터를 초기화할까요?", vbYesNo + vbQuestion, "초기화 확인") = vbYes Then
ws.Rows("7:" & ws.Rows.Count).ClearContents
MsgBox "초기화 완료!"
End If
End Sub
'반복 호출
Sub 기록반복()
If Not isRunning Then Exit Sub
' 장 종료 여부 확인
If Time > TimeSerial(15, 45, 0) Then
isRunning = False
MsgBox "장이 종료되었습니다. 수집을 자동 중지합니다.", vbExclamation
Exit Sub
End If
' 실시간 데이터 저장
기록저장
' 다음 예약
nextRunTime = Now + TimeValue("00:00:01")
Application.OnTime EarliestTime:=nextRunTime, Procedure:="기록반복", Schedule:=True
End Sub
' 실시간 데이터 저장 + 기술지표 계산(이동평균선,볼린저밴드)
Sub 기록저장()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
Dim r As Long: r = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row + 1
' 실시간 수집 (6행 기준 DDE 데이터 사용)
ws.Cells(r, 1).Value = "'" & Format(Now, "yyyy/mm/dd") ' 일자
ws.Cells(r, 2).Value = Format(Now, "hh:nn:ss") ' 시간
ws.Cells(r, 3).Value = ws.Range("C6").Value ' 종목코드
ws.Cells(r, 4).Value = ws.Range("D6").Value ' 종목명
ws.Cells(r, 5).Value = ws.Range("E6").Value ' 현재가
ws.Cells(r, 6).Value = ws.Range("F6").Value ' 기준가
ws.Cells(r, 7).Value = ws.Range("G6").Value ' 전일대비
ws.Cells(r, 8).Value = ws.Range("H6").Value ' 등락률
ws.Cells(r, 9).Value = ws.Range("I6").Value ' 거래량
ws.Cells(r, 10).Value = ws.Range("J6").Value ' 거래대금
ws.Cells(r, 11).Value = ws.Range("K6").Value ' 체결량
ws.Cells(r, 12).Value = ws.Range("L6").Value ' 체결강도
ws.Cells(r, 13).Value = ws.Range("M6").Value ' 상한가
ws.Cells(r, 14).Value = ws.Range("N6").Value ' 하한가
ws.Cells(r, 15).Value = ws.Range("O6").Value ' 시가
ws.Cells(r, 16).Value = ws.Range("P6").Value ' 고가
ws.Cells(r, 17).Value = ws.Range("Q6").Value ' 저가
ws.Cells(r, 18).Value = ws.Range("R6").Value ' 종가
ws.Cells(r, 19).Value = ws.Range("S6").Value ' 전일종가
ws.Cells(r, 20).Value = ws.Range("T6").Value ' 우선매도잔량
ws.Cells(r, 21).Value = ws.Range("U6").Value ' 우선매수잔량
ws.Cells(r, 22).Value = ws.Range("V6").Value ' 우선매도건수
ws.Cells(r, 23).Value = ws.Range("W6").Value ' 우선매수건수
ws.Cells(r, 24).Value = ws.Range("X6").Value ' 총매도잔량
ws.Cells(r, 25).Value = ws.Range("Y6").Value ' 총매수잔량
ws.Cells(r, 26).Value = ws.Range("Z6").Value ' 총매도건수
ws.Cells(r, 27).Value = ws.Range("AA6").Value ' 총매수건수
ws.Cells(r, 28).Value = ws.Range("AB6").Value ' 미결제약정
ws.Cells(r, 29).Value = ws.Range("AC6").Value ' 미결제전일대비
ws.Cells(r, 30).Value = ws.Range("AD6").Value ' 이론가
ws.Cells(r, 31).Value = ws.Range("AE6").Value ' 전일시가
ws.Cells(r, 32).Value = ws.Range("AF6").Value ' 전일고가
ws.Cells(r, 33).Value = ws.Range("AG6").Value ' 전일저가
' 기술 분석 (현재가: 열 6 기준)
Dim ma5 As Double, ma10 As Double, ma20 As Double, ma60 As Double, ma120 As Double
Dim bbAvg As Double, bbStd As Double
Dim hasEnoughData As Boolean: hasEnoughData = False
On Error Resume Next
If r >= 6 + 120 Then hasEnoughData = True
If Not hasEnoughData Then Exit Sub
On Error GoTo 0
' 이동평균선
ma5 = WorksheetFunction.Average(ws.Range("E" & r - 4 & ":E" & r))
ma10 = WorksheetFunction.Average(ws.Range("E" & r - 9 & ":E" & r))
ma20 = WorksheetFunction.Average(ws.Range("E" & r - 19 & ":E" & r))
ma60 = WorksheetFunction.Average(ws.Range("E" & r - 59 & ":E" & r))
ma120 = WorksheetFunction.Average(ws.Range("E" & r - 119 & ":E" & r))
' 볼린저 밴드
Set last20 = ws.Range("E" & r - 19 & ":E" & r)
bbStd = WorksheetFunction.StDev(last20)
bbAvg = ma20
' 결과 화면 디스플레이 (열 순서: 35 ~ 42)
ws.Cells(r, 35).Value = ma5
ws.Cells(r, 36).Value = ma10
ws.Cells(r, 37).Value = ma20
ws.Cells(r, 38).Value = ma60
ws.Cells(r, 39).Value = ma120
ws.Cells(r, 40).Value = bbAvg + 2 * bbStd
ws.Cells(r, 41).Value = bbAvg
ws.Cells(r, 42).Value = bbAvg - 2 * bbStd
' --- 봉 차트 계산 영역 추가 ---
Dim minuteNow As Date: minuteNow = Int(Now * 24 * 60) / (24 * 60)
' Helper function: 봉 생성 함수
For Each functionType In Array(1, 5, 10) ' 1분봉, 5분봉, 10분봉
rStart = 7
For rr = r - 1 To 7 Step -1
If ws.Cells(rr, 1).Value = "" Then Exit For
If IsDate(ws.Cells(rr, 2).Value) Then
If TimeValue(ws.Cells(rr, 1).Value) <= TimeSerial(Hour(Now), Minute(Now) - functionType, 0) Then
rStart = rr + 1
Exit For
End If
End If
Next rr
' 시가, 종가, 고가, 저가 계산
If r >= rStart Then
Set priceRange = ws.Range("E" & rStart & ":E" & r)
Set volRange = ws.Range("I" & rStart & ":I" & r)
Dim o As Double, h As Double, l As Double, c As Double, v As Double
o = ws.Cells(rStart, 5).Value
h = WorksheetFunction.Max(priceRange)
l = WorksheetFunction.Min(priceRange)
c = ws.Cells(r, 5).Value
v = WorksheetFunction.Sum(volRange)
' 결과 셀 위치: 1분봉(열 43), 5분봉(열 44), 10분봉(열 45)
Select Case functionType
Case 1: ws.Cells(r, 43).Value = c ' 1분봉 종가로 표시
Case 5: ws.Cells(r, 44).Value = c
Case 10: ws.Cells(r, 45).Value = c
End Select
End If
Next
End Sub
📝 적용해 보시고 모르는것 있으시면 댓글 달아주세요. 확인해서 알려드릴께요 !!!
반응형