2013년 2월 4일 월요일

Excel에서 HTS DDE 활용하기 5 - Chart와 지표 III

※ Elliott Pattern Helper Add In
  • Download Add In for Excel 2007 
  • Download Add In for Excel 2003 

  지난 글에서 차트의 스크롤 기능을 구현해 보았습니다. 그런데 DDE를 통해 체결정보를 수신하여 캔들정보 시트에 반영할 때, 캔들의 저가나 고가 또는 종가가 변경될 뿐만 아니라 캔들의 시간단위마다 새로운 캔들이 생성될텐데요, 이를 차트에도 반영해야 할 것입니다.

  이번 글의 주제는 이미 생성되어 있는 차트를 DDE 이벤트에 따라 refresh하는 것입니다. ※ (참고) DDE 이벤트는 현재가, 체결량 등 DDE Item의 값이 변하는 것을 말합니다.

  차트의 스크롤 기능을 구현했던 과정을 상기해 보면, 차트의 데이터 소스의 값들은 실제 데이터가 아니라 실제 데이터를 가르키는 셀 수식(OFFSET)이었습니다. 따라서 캔들의 저가와 고가 및 종가는 별다른 처리를 하지 않아도 자체로 update됩니다.

  결국 새로운 캔들이 생성될 때만 차트를 refresh하면 되겠지요. 이를 위해 기존에 작성했던 'CCandleFeeder' 클래스에 'refreshChart' 함수를 하나 추가하고 필요한 부분을 수정할 것입니다.

  계속 진행하기에 앞서 출력되는 차트의 크기(width, height, length)를 소스에 하드코딩했던 것에서 사용자의 입력을 받아 처리할 수 있도록 수정하겠습니다. 
  • (수정 전 시나리오) 시트 위에서 종목명을 선택하고 'Chart' 버튼을 클릭하면 차트 출력 시트가 생성되면서 해당 종목의 캔들 차트가 표시된다. 
  • (수정 후 시나리오) 시트 위에서 종목명을 선택하고 'Chart' 버튼을 클릭하면 차트 크기를 지정하는 폼이 팝업된다. 크기를 지정하고 'OK' 버튼을 클릭하면 차트 출력 시트가 생성되면서 해당 종목의 캔들 차트가 표시된다.  

  다음 주제(기술적 지표)를 감안하여 다중 페이지가 포함된 UserForm(사용자 정의 폼)을 생성하여 사용합니다. 
  
  엑셀에서 메뉴 '개발 도구' → 'Visual Basic'을 선택하거나 키보드의 'Alt + F11'을 눌러 VBA 편집창을 띄웁니다.
  
  VBAProject 트리 목록에서 현재 작업 중인 파일의 Context 메뉴 → '삽입' → '사용자 정의 폼'를 선택하여 폼을 생성한 후 다음 그림 1과 같이 폼의 이름을 'FChart'로 수정하고, Caption은 적절히 입력해 줍니다.
  
그림 1-1. UserForm 'FChart' 생성 1

    도구상자의 '다중 페이지'를 선택(그림 1-2의 1)하고,  Form 위에 적당히 위치시킵니다(그림 1-2의 2).
  
그림 1-2. UserForm 'FChart' 생성 2
  
  도구상자의 '텍스트 상자'를 선택(그림 1-3의 1)하고, Form 위에 적당히 위치시킨 뒤 레이블을 'Width'로 만들어 줍니다(그림 1-3의 2). 텍스트 상자의 이름은 'TextBoxCW'로 수정합니다(그림 1-3의 3).
  
그림 1-3. UserForm 'FChart' 생성 3
  
  그림 1-3과 동일한 방법으로 차트의 높이와 캔들 수를 입력받기 위한 텍스트 상자를 'TextBoxCH'와 'TextBoxCL'의 이름으로 생성하고(그림 1-4의 1), 페이지의 이름을 적절히 수정합니다(그림 1-4의 2). ※ 텍스트 상자의 이름을 정확히 입력하셨는지  다시 한 번 확인하세요.
  
그림 1-4. UserForm 'FChart' 생성 4
  
  다음 그림과 같이 도구상자의 '명령 단추'를 선택(그림 1-5의 1)하여 버튼을 생성하고(그림 1-5의 2) 이름을 'ButtonOK'로 수정합니다(그림 1-5의 3). Caption은 적절히 입력하십시요. 동일한 방법으로 'ButtonCancel'의 이름으로 버튼을 생성합니다.
  
그림 1-5. UserForm 'FChart' 생성 5
  
  'ButtonCancel'을 더블클릭하여 '코드 보기' 모드로 들어가 아래와 같이 입력합니다.
  
그림 2. 'ButtonCanel' 이벤트 입력
  
  ※ ('ButtonCancel_Click' 소스) 
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Sub ButtonCancel_Click()
    Unload Me
End Sub
 
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  폼 'FChart'를 초기화하기 위한 Sub모듈을 그림 3과 같이 입력합니다.

그림 3. 폼 초기화 모듈 입력

  ※ ('UserForm_Initialize' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Sub UserForm_Initialize()
    TextBoxCW.Value = 500
    TextBoxCH.Value = 350
    TextBoxCL.Value = 100
   
End Sub


''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

  VBAProject 트리 목록에서 폼 'FChart'의 Context 메뉴 → '개체 보기'를 선택하여 개체 편집 모드로 들어간 후 'ButtonOK'를 더블클릭하면 버튼의 이벤트 처리 모듈 'ButtonOK_Click'의 뼈대가 자동으로 생깁니다. 다음 그림과 같이 편집하겠습니다.
  
그림 4. 'ButtonOK' 이벤트 입력
  
  ※ ('ButtonOK_Click' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Sub ButtonOK_Click()
    Call doCharting(Selection.Cells(1, 1).Value, _
                    CInt(TextBoxCW.Value), _
                    CInt(TextBoxCH.Value), _
                    CInt(TextBoxCL.Value))
   
    Me.Hide
End Sub
 
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  ☞ 지난 글에서 작성했던 'doCharting'을 호출하는 것으로 하되, 인자를 세 개 더 넘겨줍니다. ※ 'doCharting'은 아래에서 수정하도록 하겠습니다. 
  
  폼 작성은 완료되었으니 시트의 'Chart' 버튼을 클릭했을 때 폼이 팝업되도록 수정해야 합니다. 버튼 'Chart'의 이벤트 처리 매크로 'Chart_Click'을 다음과 같이 수정합니다.

  ※ (수정 후 'Chart_Click' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub Chart_Click()
    Dim frm As FChart
  
    Set frm = New FChart
    Load frm
    frm.Show
End Sub

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

  폼의 'OK' 버튼을 클릭하면 차트 크기(width × height × length)를 인자로 넘겨주면서 'doCharting'을 호출하도록 기존의 'doCharting'을 수정하겠습니다. 다음 소스로 대체하시면 됩니다.
  
  ※ (수정 후 'doCharting' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub doCharting(sn, cw, ch, cl)
    sn_cs = sheets_cs(sn)
    sn_Arr = Split(sn_cs, ",")
    If UBound(sn_Arr) < 0 Then Exit Sub
   
    If cw = Empty Or cw = xlNullString Or cw < 50 Then cw = CHART_W
    If ch = Empty Or ch = xlNullString Or ch < 50 Then ch = CHART_H
    If cl = Empty Or cl = xlNullString Or cw < 0 Then cl = CHART_L
   
    If createChartSheet(CHART_POSTFIX, sn_cs, xlStockOHLC, cw, ch, cl) Then
        Sheets(CHART_POSTFIX).Select
        Call onChartChange(xlStockOHLC, cw, ch, cl, sn_Arr(LBound(sn_Arr)))
    End If
End Sub
 

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
   ☞ 위 소스를 보시면 변수 'CHART_W', 'CHART_H', 'CHART_L'과 'CHART_POSTFIX'가 선언도 되지 않은채 사용되고 있음을 알 수 있습니다. 이들은 차트 크기의 기본값과 차트출력 시트의 이름을 저장하는 상수입니다. 그림 5와 하단 소스를 참고하여 선언하십시요.

그림 5. 기존 모듈 수정
  
  ※ (상수 선언)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Public Const CHART_POSTFIX = "CHARTS"   'Chart sheet name
Public Const CHART_W = 500              'Default chart width
Public Const CHART_H = 350              'Default chart height
Public Const CHART_L = 100              'Default chart length


''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  
  현재까지 작업한 내용을 저장하고 테스트를 해 보겠습니다. 기존에 생성되어 있는 'CHARTS' 시트는 삭제한 후 'Chart' 버튼을 클릭하십시요.
  
그림 6. 폼 테스트
  
  차트 크기를 조절한 후 'OK' 버튼을 클릭하면 새롭게 차트출력 시트가 생성되면서 지정한 크기로 차트가 출력됩니다.
  
그림 7. 차트 테스트
  
  이제 원래 진행하고자 했던 주제 'DDE 이벤트를 반영한 차트 Refresh' 기능을 추가하겠습니다.
  
  'CCandleFeeder' 클래스는 DDE 이벤트에 따라 여러 종목의 캔들정보 시트를 update하기 위해 작성했습니다. 클래스 소스를 보면, 'CCandleFeeder'가 feed를 하는 시트는 멤버 변수 'pCandleSheet'에 저장된 값임을 어렵지 않게 파악할 수 있을 것입니다. 그렇다면 현재 차트출력 시트에 있는 차트가 동일한 시트에 대한 차트인지 어떻게 판단할 수 있을까요? 

  간단한 방법이 하나 있습니다. 엑셀의 ChartObject에는 이름을 붙일 수 있으므로, 차트를 생성할 때 이름을 붙여주고 차트가 전환될 때에는 이름을 바꿔주는 것이죠. 우선, 그 작업을 하겠습니다. 먼저 'drawChartTWH'를 수정하겠습니다.
  
  ※ (수정 후 'drawChartTWH' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function drawChartTWH(ParamArray varArgs() As Variant)
    Dim cht As ChartObject
    Dim CHTsheet As Worksheet
   
    Set CHTsheet = ActiveSheet
    If UBound(varArgs) > 3 Then
        If varArgs(4) = xlNullString Then GoTo UseActiveSheet:
        If Not sheetExist(varArgs(4)) Then
            Set CHTsheet = Worksheets.Add(After:=Worksheets(Worksheets.Count))
            CHTsheet.Name = varArgs(4)
        Else
            Set CHTsheet = sheets(varArgs(4))
        End If
UseActiveSheet:
    End If

    po_y = CHTsheet.ChartObjects.Count * (2 * Rows("1:1").RowHeight + varArgs(3)) _
           + 2 * Rows("1:1").RowHeight
    Set cht = CHTsheet.ChartObjects.Add(Left:=0, Width:=varArgs(2), _
                                        Top:=po_y + Rows("1:1").RowHeight, _
                                        Height:=varArgs(3))
   
    cht.Chart.SetSourceData Source:=varArgs(0)
    cht.Chart.ChartType = varArgs(1)
   
    If UBound(varArgs) > 4 Then
        If varArgs(5) <> xlNullString Then
        With CHTsheet.ScrollBars.Add(0, po_y, varArgs(2), Rows("1:1").RowHeight)
            '.Name = "ChartScroll"
            .Min = 0
            .Max = varArgs(6)
            .Value = varArgs(6)
            .SmallChange = 1
            .LargeChange = 1
            .LinkedCell = varArgs(5)
            .Display3DShading = True
        End With
        End If
    End If
   
    If UBound(varArgs) > 6 Then
        cht.Name = varArgs(7)
    End If
   
    Set CHTsheet = Nothing
    Set cht = Nothing
End Function


''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
   ☞ 하이라이트 된 부분만 추가하면 됩니다. 여덟 번째 인자 varArgs(7)이 있을 경우 차트에 이름을 붙이라는 것입니다. 인자를 ParamArray로 넘겨주는 이점이 있군요.
  차트가 전환될 때 호출되는 'onChartChange'도 약간 수정해야 합니다. 다음 소스를 참고하여 수정하십시요.
  
  ※ (수정 후 'onChartChange' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub onChartChange(ParamArray varArgs() As Variant)
    If UBound(varArgs) < 3 Then _
        Err.Raise 8902, "onChartChange", "ParamArray too short"
       
    Dim chtRng As String, sn As String
    On Error GoTo EH_onChartChange:
   
    sn = Cells(2, 2).Value
    If UBound(varArgs) > 3 Then sn = varArgs(4)
    If sn = xlNullString Then Exit Sub
   
    csheet = ActiveSheet.Name
    chtRng = fillChartRng(csheet & "_AUX", sn, False, 2, varArgs(3))
    sheets(csheet).Select
   
    endRow = sheets(sn).Cells(1, 1).End(xlDown).Row
    If ActiveSheet.ChartObjects.Count = 0 Then
        drawChartTWH sheets(csheet & "_AUX").Range(chtRng), _
                     varArgs(0), varArgs(1), varArgs(2), csheet, _
                     csheet & "_AUX" & "!" & Cells(1, 1).Address, _
                     WorksheetFunction.Max(endRow - varArgs(3) - 1, 0), _
                     sn
    Else
        Dim ch As ChartObject, sbar As ScrollBar
        Set ch = sheets(csheet).ChartObjects(1)
        ch.Chart.SetSourceData Source:=sheets(csheet & "_AUX").Range(chtRng)
        ch.Name = sn
        Set sbar = sheets(csheet).ScrollBars(1)
        sbar.Max = WorksheetFunction.Max(endRow - varArgs(3) - 1, 0)
        sbar.Value = WorksheetFunction.Max(endRow - varArgs(3) - 1, 0)
    End If
   
    Exit Sub

EH_onChartChange:
    MsgBox "Error(" & Err.Number & ") " & Err.Description & " [onChartChange]"
End Sub


''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
   ☞ 'drawChartTWH'를 호출할 때 추가된 인자로 차트명을 넘겨줍니다. 차트 생성이 아닌 전환의 경우, 이미 생성되어 있는 차트의 이름을 바꿉니다.
  
  'CCandleFeeder'가 차트를 refresh하는 함수를 만들겠습니다. 그런데, 차트가 어느 시트에 있는지, 즉 차트출력 시트명이 무엇인지 알려주어야 합니다. 다음 그림과 같이 하단의 소스를 참고하여 멤버 변수를 추가하고 이를 초기화하는 함수를 입력합니다.
  
그림 8. 'CCandleFeeder'의 멤버 추가

  클래스 소스 끝에 'refreshChart' 함수를 입력합니다. 하단 소스를 참고하십시요.
  
그림 9. 'refreshChart' 함수 작성
  
  'CCandleFeeder'의 'store' 모듈이 추가된 'refreshChart'를 호출하도록 수정합니다. 하단 소스를 참고하십시요.
  
  ※ (수정 후 'CCandleFeeder' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private pStockCode As String
Private pCandleSheet As String
Private pDDEsheet As String
Private pCHTsheet As String

Property Let StockCode(v As String)
    If v = Empty Or v = "" Then _
        Err.Raise 8901, "CCandleFeeder.Let StockCode", "Invalid parameter"
    pStockCode = v
End Property

Property Let CandleSheet(v As String)
    If v = Empty Or v = "" Then _
        Err.Raise 8901, "CCandleFeeder.Let CandleSheet", "Invalid parameter"
    pCandleSheet = v
End Property

Property Let DDEsheet(v As String)
    If v = Empty Or v = "" Then _
        Err.Raise 8901, "CCandleFeeder.Let DDEsheet", "Invalid parameter"
    pDDEsheet = v
End Property

Property Let CHTsheet(v As String)
    If v = Empty Or v = "" Then _
        Err.Raise 8901, "CCandleFeeder.Let CHTsheet", "Invalid parameter"
    pCHTsheet = v
End Property


Sub store(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 = pStockCode Then
        sh_name = pCandleSheet
        'Debug.Print "sh_name " & sh_name
        If dde_cell = 0 Then dde_cell = rowSearch(pDDEsheet, 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(pDDEsheet).Cells(dde_cell, 2).Value      '현재가
            cv = Sheets(pDDEsheet).Cells(dde_cell, 3).Value      '거래량
            dv = Abs(Sheets(pDDEsheet).Cells(dde_cell, 4).Value) '체결량
            bt = Sheets(pDDEsheet).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" 
                    hr_mt = "-" & hrstr & ":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, cv - prev_vo) 'dv)
                'Exit Sub
                GoTo ChartRefresh:

            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)
                    GoTo SkipChartRefreshing:
                End If
               
            Else
                If prev_tu = 0 Then
                    Debug.Print "prev_li " & prev_li
                    Debug.Print Right(.Cells(prev_li, 1).Value, 8)
                    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 Right(bt, 8)
                        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)
                        GoTo SkipChartRefreshing:
                    End If
                End If
               
            End If
        End With
       
ChartRefresh:
        Call refreshChart(pCHTsheet)
SkipChartRefreshing:

    End If
   
    Exit Sub
EH_storeCandleInfo:
    'MsgBox "Error(" & Err.Number & ") " & Err.Description & " [store]"
    Err.Raise Err.Number, "CCandleFeeder.store", Err.Description
End Sub

Private 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

Private 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

Private Function refreshChart(csheet)
    Dim ch As ChartObject, sbar As ScrollBar
    Debug.Print "Chart Refreshing..."
    If Not sheetExist(csheet) Then GoTo SkipChartRefreshing:
    On Error Resume Next
    Set ch = Sheets(csheet).ChartObjects(1)
    If Err.Number <> 0 Then
        Err.Clear
        GoTo SkipChartRefreshing:
    End If
    If Not ch.Name = pCandleSheet Then GoTo SkipChartRefreshing:
    Set sbar = Sheets(csheet).ScrollBars(1)
    sbar.Max = sbar.Max + 1
    sbar.Value = sbar.Value + 1
    Set ch = Nothing
    Set sbar = Nothing
SkipChartRefreshing:
    Debug.Print "End Chart Refreshing"
End Function


''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
   ☞ 하이라이트 된 부분이 수정 또는 추가된 부분입니다.

  마지막으로 'CCandleFeeder'의 멤버가 추가되었으므로, 오브젝트를 생성하는 부분을 수정해야 합니다. 

  ※ (소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub storeCandleInfo(s_code)
    Static feeders As Collection
    'On Error GoTo EH_storeCandleInfo:
   
    If feeders Is Nothing Then Set feeders = New Collection
   
    For i = LBound(ss_list) To UBound(ss_list)
        Dim cfeeder As CCandleFeeder
        On Error Resume Next
        Set cfeeder = feeders.Item(ss_list(i, 1))
        If Err.Number = 5 Then GoTo RegisterFeeder:
        On Error GoTo 0
        If Not cfeeder Is Nothing Then GoTo DoFeed:
       
        On Error GoTo EH_storeCandleInfo:
       
RegisterFeeder:
        Set cfeeder = New CCandleFeeder
        cfeeder.StockCode = ss_list(i, 1)
        cfeeder.CandleSheet = ss_list(i, 2)
        cfeeder.DDEsheet = dde_sheet
        cfeeder.CHTsheet = CHART_POSTFIX
        feeders.Add cfeeder, ss_list(i, 1)
       
DoFeed:
        cfeeder.store (s_code)
NextLoop:
    Next i
   
    Exit Sub
EH_storeCandleInfo:
    If Err.Number = 8901 Then
        Debug.Print "Error(8901) " & Err.Source
        Err.Clear
        GoTo NextLoop:
    End If
    MsgBox "Error(" & Err.Number & ") " & Err.Description & " [storeCandleInfo]"
    Err.Raise Err.Number, "storeCandleInfo", Err.Description
End Sub



''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  ☞ 하이라이트 된 라인만 추가하면 됩니다.
 
  모든 작업을 완료했습니다. 차트가 제대로 refresh되는지 확인해 볼까요? ※ (주의) 'fillChartRng'함수의 사소한 버그를 수정했습니다. 지난 글에서 다시 복사하여 사용하시기 바랍니다.

  ※ 다음 글부터  '기술적 지표'와 관련된 내용을 진행합니다.

댓글 없음:

댓글 쓰기