※ Elliott Pattern Helper Add In
이번 글은 'Excel에서 HTS DDE 활용하기'의 세 번째 주제로서, 지수 또는 종목의 체결정보를 축적하는 문제를 풀어나가도록 하겠습니다.
문제를 정확히 정의하자면, 원하는 종목이나 지수에 대해 세 개의 DDE Item을 실시간으로 받아 원하는 시간 단위의 캔들(candle) 정보(시가, 고가, 저가, 종가 및 거래량)를 축적하는 것입니다(그림 1 참조).
그림 1. 60분 Candle |
우선, 필요한 세 개의 DDE Item은 무엇일까요? 체결가는 당연히 필요하고, 거래량 또한 문제에서 요구한 것이니 받아야 하겠지요. 나머지 하나는 바로 체결시간입니다. DDE를 통해 수신한 체결정보의 체결시간을 모른다면 캔들을 구분할 수 없을 것입니다.
시나리오는 최대한 간단히 하겠습니다. ※ 지난 글에서 완성한 엑셀 파일을 사용하여 진행합니다.
- 사용자가 'Schedule' 버튼을 클릭하면, 종목과 캔들의 단위시간 및 스케줄을 선택할 수 있는 폼(Form) 팝업된다.
- 모든 항목을 선택하고 'OK' 버튼을 클릭하면, 선택된 종목에 대해 스케줄된 시간 동안 선택된 단위의 캔들정보가 축적된다.
그림 2. DDE Schedule 폼 |
위 그림처럼, 다중 페이지의 두 번째 페이지가 비어 있으므로 그곳('Page2')에 종목과 캔들 단위시간을 선택할 수 있는 UI(사용자 인터페이스) 항목을 추가하면 되겠군요.
바로 시작하지요. 그림 3과 같이 '개발 도구' → 'Visual Basic'을 선택하거나 'Alt+F11'을 눌러 VBA 편집창을 띄웁니다.
그림 3. VBA 편집창 실행 |
VBAProject 트리 목록에서 'FSchedule' 폼을 더블클릭(그림 4의 1)한 뒤 'Page2'를 선택합니다(그림 4의 2).
그림 4. 사용자 정의 폼 'FSchedule' 선택 |
종목 선택을 위한 콤보 상자와 레이블을 각각 생성합니다(그림 5의 1). 콤보 상자 이름은 'ComboBoxSN'으로 합니다(그림 5의 2).
그림 5. 종목 선택을 위한 콤보 상자 생성 |
마찬가지 방법으로 다음 그림과 같이 캔들 단위시간을 선택하기 위한 콤보 상자를 생성하고 그 이름을 'ComboBoxCT'으로 합니다.
그림 6. 캔들 단위시간 선택을 위한 콤보 상자 생성 |
※ (참고) 이 시점에서 구현 범위에 제한을 조금 두겠습니다. 선택 가능한 종목은 작업 중인 엑셀 파일에서 DDE로 연결된 종목들로, 캔들의 시간 단위는 5분, 15분, 60분 및 1일입니다.
먼저 캔들선택 콤보 상자 'ComboBoxCT'의 초기화를 위한 소스코드를 입력하겠습니다. 그림 7-1과 같이 VBAProject 트리 목록에서 'FSchedule' 폼의 Context 메뉴 → '코드 보기'를 선택하여 소스코드 편집 모드로 들어갑니다.
그림 7-1. 'ComboBoxCT' 초기화 소스 입력 1 |
'UserForm_Initialize' sub모듈 내부에 하단의 소스를 복사하여 다음 그림과 같이 입력합니다.
그림 7-2. 'ComboBoxCT' 초기화 소스 입력 2 |
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
ComboBoxCT.AddItem "5분", 0
ComboBoxCT.AddItem "15분", 1
ComboBoxCT.AddItem "60분", 2
ComboBoxCT.AddItem "일", 3
ComboBoxCT.ListIndex = 0
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
다음 과정은 종목선택 콤보 상자 'ComboBoxSN'을 초기화하기 위한 소스를 입력하는 것인데, 두 단계를 거치도록 합니다.
첫째 단계는 엑셀 시트에서 DDE 셀을 검색하여 종목코드와 종목명으로 구성된 2차원 배열(array)를 출력하는 함수를 만드는 것이고, 두 번째 단계는 폼 초기화 모듈에서 이 함수를 호출한 후 종목선택 콤보 상자를 채우도록 하는 것입니다.
☞ 물론 폼에서 두 단계를 모두 처리할 수도 있겠지만, UI와 로직(logic)을 분리한다는 측면과 함수의 재활용 측면을 고려한 것입니다.
다음 그림 8과 같이 하단의 소스를 복사하여 시트에 포함된 DDE 연결 종목의 배열을 출력하는 함수 'getStockList'를 작성합니다. 폼이 아니라 모듈에 작성합니다.
그림 8. 시트에 포함된 DDE 연결 종목의 배열을 출력하는 함수 |
※ ('getStockList' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function getStockList() As Variant
Dim s_list As Variant
On Error GoTo EH_getStockList:
With ActiveSheet.UsedRange
r_from = .Cells.Row + 1
r_to = .Cells(.Cells.Count).Row
ReDim s_list(1 To r_to - r_from + 1, 1 To 2)
For i = r_from To r_to
s_code = .Cells(i, 1).Formula
If Left(s_code, 7) <> "=KHRun|" Then GoTo Continue:
idx_from = InStr(s_code, "|") + 1
idx_to = InStr(s_code, "!") - 1
s_code = Mid(s_code, idx_from, idx_to - idx_from + 1)
s_code = Replace(s_code, "'", "")
s_list(i - r_from + 1, 1) = s_code
s_list(i - r_from + 1, 2) = .Cells(i, 1).Value 'getStockName(s_code)
Continue:
Next i
End With
getStockList = s_list
Exit Function
EH_getStockList:
MsgBox "Error(" & Err.Number & ") " & Err.Description & " [getStockList]"
Err.Raise Err.Number, "getStockList", Err.Description
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
☞ 위 소스는 시트의 1열에서 DDE 셀을 찾아 셀의 수식에서 종목코드를 추출하고 종목명은 셀의 값으로 하여 배열을 채웁니다.
이제 폼의 초기화 모듈에서 위 함수를 호출하도록 폼의 소스를 수정하겠습니다. VBAProject 트리 목록에서 'FSchedule' 폼의 Context 메뉴 → '코드 보기'를 선택하여 폼의 소스 편집 모드로 들어간 후, 하단에서 소스를 복사하여 다음 그림과 같이 입력합니다.
그림 9. 'ComboBoxSN' 초기화 소스 입력 |
※ (소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
s_list = getStockList()
For i = LBound(s_list, 1) To UBound(s_list, 1)
If s_list(i, 1) <> "" Then _
ComboBoxSN.AddItem s_list(i, 2) & "(" & s_list(i, 1) & ")", i - 1
Next i
ComboBoxSN.ListIndex = i - 2
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
☞ 위 소스는 종목 선택을 위한 콤보 상자 'ComboBoxSN'를 '종목명(종목코드)' 형태의 목록으로 초기화합니다.
폼 개체 편집 모드로 돌아가 'Page2'의 Caption을 적절히 수정하십시요. 일단 파일을 저장하고, 완성한 폼을 확인해 볼까요? 시트 위의 'Schedule' 버튼을 클릭하면 다음 그림과 같이 폼이 팝업되는 것을 볼 수 있을 것입니다.
그림 10. 완성된 폼 |
이렇게 해서 시나리오의 1번 항목을 완료했습니다. 2번 항목은, 폼에서 'OK' 버튼을 클릭하면 선택된 종목에 대해 스케줄된 시간 동안 선택된 시간단위의 캔들정보가 축적되도록 하는 것이었습니다.
'캔들정보를 축적한다'는 것을 좀 더 명확히 하겠습니다. 현재 작업 중인 파일에 새로운 시트를 생성하여 그림 1과 같은 모양으로 일자/시간, 시가, 고가, 저가, 종가 및 거래량을 기록해 나가는 것입니다. 물론, 이전에 생성된 시트가 있다면 행을 추가해 나가는 방식입니다.
캔들정보를 축적하기 위해 생성하는 시트의 명명규칙은 '종목명-기간' 형태로 하겠습니다. 위 그림 10의 경우라면 'OK' 버튼을 클릭했을 때 'SK하이닉스-60분'의 이름으로 시트가 생성되겠지요?
지난 글에서 작성했던 폼의 'OK' 버튼 클릭 이벤트 처리 매크로를 상기해 보겠습니다.
그림 11. 'ButtonOK_Click' 매크로 |
'onSchedule' 모듈을 호출하는 것으로 되어 있군요. 호출 인자(parameter)는 스케줄 시작 시각과 종료 시각 두 개이구요. 'onSchedule' 모듈을 볼까요?
그림 12. 'onSchedule' 모듈 |
흐음.. 'onSchedule'의 인자를 두 개 더 추가해야겠습니다. 선택된 종목과 캔들의 시간단위를 추가로 넘겨주어야 하니까요. 그리고, 캔들정보를 축적할 시트는 스케줄 시각과 상관없이 생성해도 되기 때문에, 스케줄 처리를 하는 'Application.OnTime' 문장 앞에서 시트를 생성하도록 하겠습니다.
그 전에 현재 작업 중인 파일에 특정 이름의 시트가 존재하는지 확인하는 함수 'sheetExist'를 작성해보도록 하겠습니다. 다음 그림 13과 같이 하단에서 소스를 복사하여 위에서 작성한 'getStockList' 함수 아래 입력합니다.
그림 13. 시트 존재 여부를 확인하는 함수 작성 |
※ ('sheetExist' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function sheetExist(sh_name) As Boolean
sheetExist = False
On Error Resume Next
Dim tmpWS As Worksheet
Set tmpWS = Sheets(sh_name)
On Error GoTo 0
If Not tmpWS Is Nothing Then
sheetExist = True
End If
Set tmpWS = Nothing
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
※ ('prepareSheet' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function prepareSheet(sn, cu)Dim xlSheet As Worksheet
On Error GoTo EH_prepareSheet:
dde_sheet = ActiveSheet.Name
s_code = Right(sn, Len(sn) - InStr(sn, "("))
s_code = Replace(s_code, ")", "")
If s_code = Empty Or s_code = "" Then
MsgBox "Selected stock code null or empty"
Exit Function
End If
sh_name = Left(sn, InStr(sn, "(") - 1)
If sh_name = Empty Or sh_name = "" Then
MsgBox "Selected stock name null or empty"
Exit Function
End If
sh_name = sh_name & "-" & cu
ReDim ss_list(1 To 1, 1 To 2)
ss_list(1, 1) = s_code
ss_list(1, 2) = sh_name
If Not sheetExist(sh_name) Then
Set xlSheet = Worksheets.Add(After:=Worksheets(Worksheets.Count))
xlSheet.Name = sh_name
With xlSheet
.Cells(1, 1).Value = "일자 / 시간"
.Cells(1, 2).Value = "시가"
.Cells(1, 3).Value = "고가"
.Cells(1, 4).Value = "저가"
.Cells(1, 5).Value = "종가"
.Cells(1, 6).Value = "거래량"
End With
End If
Set xlSheet = Nothing
Exit Function
EH_prepareSheet:
MsgBox "Error(" & Err.Number & ") " & Err.Description & " [prepareSheet]"
Err.Raise Err.Number, "prepareSheet", Err.Description
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
☞ 위 소스는 DDE 셀들이 있는 시트의 이름을 전역변수에 저정하는 과정(그림 14의 1), 입력받은 인자로부터 위에서 언급했던 명명규칙에 따라 시트명을 조합하는 과정(그림 14의 2), 종목코드와 시트명을 전역변수 'ss_list'에 저장하는 과정(그림 14의 3), 시트 존재 여부를 확인하여 없을 경우 신규로 생성하는 과정(그림 14의 4)으로 구성됩니다.
☞ 'dde_sheet'와 'ss_list'는 다음 과정에서 작성할 캔들정보 축적 모듈에서 사용됩니다. 위 소스만 보면 변수 선언 과정 없이 사용되고 있는데요, 위 소스가 존재하는 모듈의 상단에 'Private dde_sheet As String'과 'Private ss_list As Variant'라고 두 줄에 걸쳐 선언해 주시면 됩니다.
☞ 'dde_sheet'와 'ss_list'는 다음 과정에서 작성할 캔들정보 축적 모듈에서 사용됩니다. 위 소스만 보면 변수 선언 과정 없이 사용되고 있는데요, 위 소스가 존재하는 모듈의 상단에 'Private dde_sheet As String'과 'Private ss_list As Variant'라고 두 줄에 걸쳐 선언해 주시면 됩니다.
'onSchedule' 모듈을 수정할 차례입니다. 다음 그림 15와 같이 수정하십시요.
그림 15. 'onSchedule' 모듈 수정 |
※ (수정된 'onSchedule' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub onSchedule(ts, te, sc, cu)
Call prepareSheet(sc, cu)
If Time > TimeValue(ts) And Time < TimeValue(te) Then
Application.OnTime Now, "Start_Click"
Else
Application.OnTime TimeValue(ts), "Start_Click"
End If
Application.OnTime TimeValue(te), "Stop_Click"
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
☞ 인자 두 개와 'Call prepareSheet(sc, cu)' 라인이 추가된 것을 확인하십시요.
폼 'FSchedule'의 'ButtonOK_Click' 모듈이 'onSchedule'을 호출하므로, 수정사항을 반영해야합니다. VBAProject 트리 목록에서 'FSchedule' 폼의 Context 메뉴 → '코드 보기'를 선택하여 폼의 소스 편집 모드로 들어간 후,'ButtonOK_Click'을 아래 소스로 대체하십시요.
※ (수정된 'ButtonOK_Click' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Sub ButtonOK_Click()Call onSchedule(ComboBoxTS.Text, ComboBoxTE.Text, _
ComboBoxSN.Text, ComboBoxCT.Text)
Me.Hide
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
테스트를 해 볼까요? 시트 위의 'Schedule' 버튼을 클릭하여 폼을 팝업시킨 후(그림 10 참조) 'OK' 버튼을 클릭하면 다음 그림과 같이 시트가 생성되는 것을 확인할 수 있습니다.
그림 16. 캔들정보 축적 시트 생성 테스트 |
마지막 남은 것은 사용자가 지정한 스케줄 시간 동안 캔들정보가 축적되도록 하는 작업입니다.
그림 15에서도 알 수 있지만, 정해진 시각에 실행되는 모듈은 'Start_Click'과 'Stop_Click'입니다. 'Stop_Click'은 DDE 셀의 change 이벤트에 대해 'SetLinkOnData'로 지정된 매크로를 해제하는 역할만 하도록 했었죠. 따라서 'Stop_Click'은 수정할 것이 전혀 없고, 'Start_Click'만을 우리의 시나리오에 맞도록 변경하면 될 것입니다.
우선 지난 글에서 완성한 'Start_Click' 소스를 보겠습니다.
그림 17. 'Start_Click' 모듈 |
'Start_Click'은 위 그림 17의 1과 같이 DDE 셀에 대해 이벤트 처리 매크로로 'onStart' 모듈을 지정할 뿐이며, 현재의 'onStart' 모듈은 시트의 11열에 변하는 거래량을 에코(echo)하는 단순한 기능만 하는 상태입니다(그림 17의 2). 이 부분을 수정해야 하겠군요. 새로운 Sub모듈 'storeCandleInfo'를 만들고, 'onStart'에서 호출하는 것으로 하겠습니다.
'storeCandleInfo'는 선택된 종목의 체결정보(현재가, 거래량, 체결량, 체결시간)를 조합하여 캔들정보로 축적하는데, 그 기능을 간략하게 정의해 보면 다음과 같습니다.
- 종목 코드를 input으로 받는다.
- 전역변수 'ss_list'에 저장된 종목에 한해서만 캔들정보를 축적한다.
- 체결정보는 전역변수 'dde_sheet'에 저장된 이름의 시트에서 해당 행(row)을 검색하여 읽어들인다.
- 캔들정보를 축적할 시트명은 전역변수 'ss_list'에서 참조한다.
- 위에서 참조한 시트명으로 캔들의 시간단위를 파악한다.
- 체결시간이 마지막으로 축적된 캔들에 포함되는 경우, 캔들의 고가/저가/종가 및 거래량을 update한다. 그렇지 않을 경우, 새로운 캔들정보(시트의 새로운 행)를 생성하는데, 시가/고가/저가/종가는 체결가(=현재가)로 채우고, 거래량은 체결량으로 채운다.
※ (수정된 'rowSearch' 함수 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Public Function rowSearch(s_name, col, c_str) As Integer
Dim found As Range
On Error GoTo EH_rowSearch:
rowSearch = 0
With Sheets(s_name)
Set found = .Columns(col).Find(What:=c_str, After:=.Cells(1, col), _
LookIn:=xlFormulas, LookAt:=xlPart, _
SearchOrder:=xlByRows, SearchDirection:=xlNext)
End With
If Not found Is Nothing Then rowSearch = found.Row
Exit Function
EH_rowSearch:
MsgBox "Error(" & Err.Number & ") " & Err.Description & " [rowSearch]"
Call Stop_Click
Err.Raise Err.Number, Err.Description, "rowSearch"
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
☞ 하이라이트 된 부분에서 볼 수 있듯이, 검색할 시트명을 인자로 추가했습니다.
위 기능 중 다섯 번째와 마지막 항목은 소스 파악을 쉽게 하기 위해 별도의 함수로 작성하겠습니다( 'candlesPerHour', 'updateCandle'과 'fillCandle'). 하단에서 소스를 복사하여 앞에서 작성했던 'getStockList' 위쪽에 다음 그림과 같이 입력합니다. ※ (참고) 그림 18 상단에 포함된 라인 'Private dde_sheet As String'과 'Private ss_list As Variant'의 추가는 앞에서 언급했었습니다.
그림 18. 'candlesPerHour', 'fillCandle', 'updateCandle' 함수 |
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function candlesPerHour(sh_name) As Integer
If InStr(sh_name, "-일") > 1 Then
candlesPerHour = -1
ElseIf InStr(sh_name, "-60분") > 1 Then
candlesPerHour = 1
ElseIf InStr(sh_name, "-15분") > 1 Then
candlesPerHour = 4
Else
candlesPerHour = 12
End If
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function fillCandle(sh_name, l, d, p, v)
With Sheets(sh_name)
.Cells(l, 1).Value = d
.Cells(l, 2).Value = p
.Cells(l, 3).Value = p
.Cells(l, 4).Value = p
.Cells(l, 5).Value = p
.Cells(l, 6).Value = v
End With
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function updateCandle(sh_name, l, p, v)
With Sheets(sh_name)
If p > .Cells(l, 3).Value Then .Cells(l, 3).Value = p
If p < .Cells(l, 4).Value Then .Cells(l, 4).Value = p
.Cells(l, 5).Value = p
.Cells(l, 6).Value = v
End With
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
이제 'storeCandleInfo' Sub모듈을 작성하겠습니다. 하단에서 소스를 복사하여 다음 그림과 같이 전역변수 'ss_list' 선언부 아래에 입력합니다.
그림 19. 'StoreCandleInfo' Sub모듈 작성 |
※ (소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub storeCandleInfo(s_code)
Static dde_cell As Integer 'the row of DDE cells of selected stock
Static prev_dt As String 'previous date
Static prev_tu As Integer 'previous time unit
Static prev_li As Integer 'row number of the row being updated
Static prev_vo As Double 'sum of volumes of prev candles of the same day
Static c_p_hr As Integer 'the number of candles per hour
On Error GoTo EH_storeCandleInfo:
If s_code = ss_list(1, 1) Then
sh_name = ss_list(1, 2)
If dde_cell = 0 Then dde_cell = rowSearch(dde_sheet, 2, "'" & s_code & "'")
If c_p_hr = 0 Then c_p_hr = candlesPerHour(sh_name)
'Debug.Print "c_p_hr " & c_p_hr
With Sheets(sh_name)
'Debug.Print "prev_li " & prev_li
If prev_li = 0 Then
If .Cells(2, 1).Value = "" Then
prev_li = 1
Else
'prev_li = .UsedRange.Cells(.Cells.Count).Row '===> Overflow
prev_li = .Cells(1, 1).End(xlDown).Row
End If
End If
'Debug.Print "prev_li " & prev_li
cp = Sheets(dde_sheet).Cells(dde_cell, 2).Value '현재가
cv = Sheets(dde_sheet).Cells(dde_cell, 3).Value '거래량
dv = Abs(Sheets(dde_sheet).Cells(dde_cell, 4).Value) '체결량
bt = Sheets(dde_sheet).Cells(dde_cell, 5).Value '체결시간
If prev_li = 1 Then
If c_p_hr = -1 Then GoTo DailyNewCandle:
NewCandle:
prev_tu = WorksheetFunction.Floor(TimeValue(Right(bt, 8)) _
* 24 * c_p_hr, 1)
Debug.Print "prev_tu " & prev_tu
HourlyNewCandle:
Dim hr As Integer, hrstr As String
hr = WorksheetFunction.Floor(prev_tu / c_p_hr, 1) 'prev_tu / c_p_hr
hrstr = hr
If hr < 10 Then hrstr = "0" & hr
If c_p_hr > 1 Then
mt = (prev_tu Mod c_p_hr) * (60 / c_p_hr)
If Len(mt) = 1 Then mt = "0" & mt
hr_mt = "-" & hrstr & ":" & mt & ":00"
ElseIf c_p_hr > 0 Then
hr_mt = "-" & prev_tu & ":00:00"
End If
DailyNewCandle:
prev_dt = Replace(Format(Date, "yyyy/mm/dd"), "-", "/")
Debug.Print "prev_dt & hr_mt " & prev_dt & hr_mt
prev_li = prev_li + 1
Call fillCandle(sh_name, prev_li, prev_dt & hr_mt, cp, dv)
Exit Sub
End If
If prev_dt = "" Then prev_dt = Left(.Cells(prev_li, 1).Value, 10)
If c_p_hr = -1 Then
If DateValue(prev_dt) <> Date Then
GoTo DailyNewCandle:
Else
Call updateCandle(sh_name, prev_li, cp, cv)
End If
Else
If prev_tu = 0 Then
'Debug.Print "prev_li " & prev_li
prev_tu = WorksheetFunction.Floor(TimeValue( _
Right(.Cells(prev_li, 1).Value, 8) _
) * 24 * c_p_hr, 1)
End If
If DateValue(prev_dt) <> Date Then
Debug.Print "Going to NewCandle"
GoTo NewCandle:
Else
cur_tu = WorksheetFunction.Floor(TimeValue(Right(bt, 8)) _
* 24 * c_p_hr, 1)
If prev_tu <> cur_tu Then
'Debug.Print prev_tu & "," & cur_tu
prev_vo = cv - dv
prev_tu = cur_tu
GoTo HourlyNewCandle:
Else
If prev_vo = 0 Then prev_vo = cv - dv - .Cells(prev_li, 6).Value
Call updateCandle(sh_name, prev_li, cp, cv - prev_vo)
End If
End If
End If
End With
End If
Exit Sub
EH_storeCandleInfo:
'MsgBox "Error(" & Err.Number & ") " & Err.Description & " [storeCandleInfo]"
Err.Raise Err.Number, "storeCandleInfo", Err.Description
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
☞ 위 소스에서 하이라이트 된 라인들이 위에서 정의한 'storeCandleInfo'의 기능들과 연관된 것들입니다.
'onStart' Sub모듈에서 'storeCandleInfo'를 호출하게만 하면 모든 작업이 끝나겠군요. 그림 20을 참조하여 수정하시기 바랍니다. 'rowSearch' 함수가 수정된 것 또한 확인하십시요.
그림 20. 'onStart' Sub모듈 수정 |
※ (수정된 'onStart' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub onStart(i)
On Error GoTo EH_onStart:
aLinks = ActiveWorkbook.LinkSources(xlOLELinks)
c_str = aLinks(i)
t_str = Replace(c_str, "KHRun|", "")
t_str = Replace(t_str, "!13", "")
Call storeCandleInfo(t_str)
Exit Sub
EH_onStart:
MsgBox "Error(" & Err.Number & ") " & Err.Description & Err.Source '" [onStart]"
Call Stop_Click
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
먼 길을 지루하게 온 듯한 기분입니다. 작업 중인 파일을 저장하신 후, 영웅문의 DDE 서비스를 실행시키고 작업하신 파일을 테스트해 보시기 바랍니다. 모든 것이 정상이라면, 다음 그림과 같이 캔들정보가 축적되는 것을 확인할 수 있을 것입니다.
그림 21. 테스트 |
꼭 필요했던 정보인데 잘 보고 갑니다! 감사합니다!
답글삭제고맙습니다.
삭제너무너무 감사합니다. 잘 배우겠습니다.
답글삭제많은 배웠습니다. 감사합니다.
답글삭제중간에 Function sheetExist 실행시 에러('Set tmpWS = Sheets(sh_name)'에서 "'9' 런타임 오류가 발생하였습니다: 아래 첨자 사용이 잘못되었습니다.")가 났지만 . . 기초가 없어서 인터넷 탐색해서 비슷한 sheet 찾기 함수가 있어서 대치하였더니 에러없이 실행되었습니다. 혹시 여기오는 분 중에 도움될까 하여 아래 함수를 적었습니다.
Function sheetExist(sheetToFind As String) As Boolean
sheetExist = False
For Each sheet In Worksheets
If sheetToFind = sheet.name Then
sheetExist = True
Exit Function
End If
Next sheet
End Function
( http://stackoverflow.com/questions/6040164/excel-vba-if-worksheetwsname-exists 의 소스에서 글자를 조금 고침 )
안녕하세요...관리자님..오차없이 잘 따라서 입력 했는데, 그림16처럼 캔들정보 축적시트 생성 테스트까지 쉬트별로 나눠 지는것까지 확인하고, StoreCmdleinfo도 2~3번 확인했고, 런타임오려도 없이 dde수신데이터는 받는데,
답글삭제이상하게 데이터 축적이 안되요..
혹시 잘못 입력한게 있을까 다시 확인했는데, 어디서 문제 인지 모르겠습니다. 확인할수 있는 방법이 있을까요?
안녕하세요?
삭제VBA 소스의 데이터 축적하는 부분에서 Breakpoint를 설정하고 변수들의 값들을 디버깅해보시기 바랍니다.
'엑셀 매크 VBA에서 디버하기(https://gusrealworld.tistory.com/39)' 참조하십시요.
해결되었습니다. 신경써 주셔서 감사합니다.
삭제작성자가 댓글을 삭제했습니다.
답글삭제