※ Elliott Pattern Helper Add In
지난 글에 이어 '시나리오 2'를 진행하겠습니다. 선택된 종목과 지표에 대해, 지표를 포함하는 캔들 차트를 출력할 수 있도록 할 것입니다.
▶ (시나리오 2). 'FChart' 수정
시나리오 2를 위한 폼 개체 편집을 시작합니다. 지난 과정에서 만들었던 폼 'FChart'의 빈 페이지를 활용하겠습니다. VBAProject 트리 목록에서 'FChart'의 Context 메뉴 → '개체 보기'를 선택한 후 'Page2'를 클릭합니다.
지표 선택을 위한 콤보상자를 만들겠습니다. 도구상자에서 콤보상자를 선택(그림 1의 1)하고, 폼 위에 적절히 위치시킨 후(그림 1의 2), 이름을 'ComboBoxTI'로 수정합니다(그림 1의 3). 레이블은 적당히 입력하십시요.
그림 1. 지표 선택을 위한 콤보상자 추가 |
도구상자에서 텍스트 상자를 선택(그림 2-1의 1)하고, 폼 위에 적절히 위치시킨 후(그림 2-1의 2), 텍스트 상자의 이름을 'TextBoxP1'으로 수정합니다(그림 2-1의 3).
그림 2-1. 기간 설정을 위한 텍스트 상자 추가 1 |
동일한 방법으로 'TextBoxP2'와 'TextBoxP3'를 생성한 후 다음 그림 2-2와 같이 레이블을 적절히 입력합니다. ※ (주의) 입력한 이름이 정확한지 다시 한 번 확인하세요.
그림 2-2. 기간 설정을 위한 텍스트 상자 추가 2 |
이동평균을 계산해야 하는 경우, 기본값으로 지수(exponential)이동평균을 사용하는데 이를 단순이동평균으로 변경할 때 사용할 체크박스(확인란)를 생성합니다.
도구상자에서 체크박스를 선택(그림 3의 1)하고, 폼 위에 적절히 위치시킨 후(그림 3의 2), 체크박스의 이름을 'CheckBoxSMA'로 수정합니다(그림 2-1의 3). Caption은 적절히 입력하십시요.
그림 3. 단순이동평균 지정을 위한 체크박스 추가 |
페이지 이름 'Page2'를 적절히 수정하여 폼의 개체 편집을 완료합니다(그림 3의 4).
다음은 위에서 생성한 페이지를 초기화하기 위한 코드를 입력하도록 하겠습니다. VBAProject 트리 목록에서 'FChart'의 Context 메뉴 → '코드 보기'를 선택하여 소스코드 편집 모드로 들어간 후 기존의 'UserForm_Initialize' 모듈을 아래와 같이 수정합니다.
다음은 위에서 생성한 페이지를 초기화하기 위한 코드를 입력하도록 하겠습니다. VBAProject 트리 목록에서 'FChart'의 Context 메뉴 → '코드 보기'를 선택하여 소스코드 편집 모드로 들어간 후 기존의 'UserForm_Initialize' 모듈을 아래와 같이 수정합니다.
※ (수정 후 'FChart' 초기화 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''Private Sub UserForm_Initialize()
TextBoxCW.Value = 550
TextBoxCH.Value = 300
TextBoxCL.Value = 80
ComboBoxTI.AddItem "MACD", 0
ComboBoxTI.AddItem "RSI", 1
ComboBoxTI.AddItem "OBV", 2
Call DisableAllP
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
☞ 'DisableAllP'는 다음 소스를 참고하십시요.
'ComboBoxTI'에서 선택된 지표에 따라 'TextBoxP1', 'TextBoxP2' 및 'TextBoxP3'의 초기화 값을 달리 설정하도록 합니다. VBAProject 트리 목록에서 'FChart'의 Context 메뉴 → '개체 보기'를 선택하여 폼 개체편집 모드로 들어간 후 콤보상자 'ComboBoxTI'를 더블클릭합니다. 소스코드 편집 모드로 바뀌면서 이벤트 처리를 위한 Sub모듈의 뼈대가 생성되는데 다음 소스를 참고하여 입력합니다.
※ ('ComboBoxTI_Change' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''Private Sub ComboBoxTI_Change()
Select Case ComboBoxTI.ListIndex
Case 0
Call EnableAllP
TextBoxP1.Value = 5
TextBoxP2.Value = 34
TextBoxP3.Value = 5
Case 1
Call EnableP1
TextBoxP1.Value = 13
Case 2
Call EnableP1
TextBoxP1.Value = 9
End Select
End Sub
Private Sub DisableAllP()
TextBoxP1.Value = xlNullString
TextBoxP2.Value = xlNullString
TextBoxP3.Value = xlNullString
TextBoxP1.Enabled = False
TextBoxP2.Enabled = False
TextBoxP3.Enabled = False
End Sub
Private Sub EnableAllP()
TextBoxP1.Enabled = True
TextBoxP2.Enabled = True
TextBoxP3.Enabled = True
End Sub
Private Sub EnableP1()
TextBoxP2.Value = xlNullString
TextBoxP3.Value = xlNullString
TextBoxP1.Enabled = True
TextBoxP2.Enabled = False
TextBoxP3.Enabled = False
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
그림 1~3 과정에서 만든 'ComboBoxTI'와 'TextBoxP1', 'TextBoxP2', 'TextBoxP3' 그리고 'CheckBoxSMA'에서 선택된 값들을 조합하여 'MACD (지수 5 34 5)'와 같은 형태의 formatted string을 만들기 위한 함수를 작성합니다. 아래 소스를 복사하여 입력하십시요.
※ (함수 'indicator_str' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Function indicator_str() As String
Dim ns As String
On Error GoTo Skip:
Select Case ComboBoxTI.ListIndex
Case 0
ns = "MACD ("
If TextBoxP1.Value = xlNullString Then GoTo Skip:
If CInt(TextBoxP1.Value) > 0 Then
ns = ns & TextBoxP1.Value & " "
Else
GoTo Skip:
End If
If CInt(TextBoxP2.Value) > 0 Then
ns = ns & TextBoxP2.Value & " "
Else
GoTo Skip:
End If
If Not TextBoxP3.Value = xlNullString Then
ns = ns & CInt(TextBoxP3.Value) & ")"
Else
ns = Left(ns, Len(ns) - 1)
ns = ns & ")"
End If
Case 1
ns = "RSI ("
If CInt(TextBoxP1.Value) > 0 Then
ns = ns & TextBoxP1.Value & ")"
Else
GoTo Skip:
End If
Case 2
ns = "OBV"
If Not TextBoxP1.Value = xlNullString Then
ns = ns & " (" & CInt(TextBoxP1.Value) & ")"
Else
GoTo SkipMA:
End If
Case Else
GoTo Skip:
End Select
If CheckBoxSMA.Value = True Then
ns = Replace(ns, "(", "(단순 ")
Else
ns = Replace(ns, "(", "(지수 ")
End If
SkipMA:
indicator_str = ns
Skip:
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Function indicator_str() As String
Dim ns As String
On Error GoTo Skip:
Select Case ComboBoxTI.ListIndex
Case 0
ns = "MACD ("
If TextBoxP1.Value = xlNullString Then GoTo Skip:
If CInt(TextBoxP1.Value) > 0 Then
ns = ns & TextBoxP1.Value & " "
Else
GoTo Skip:
End If
If CInt(TextBoxP2.Value) > 0 Then
ns = ns & TextBoxP2.Value & " "
Else
GoTo Skip:
End If
If Not TextBoxP3.Value = xlNullString Then
ns = ns & CInt(TextBoxP3.Value) & ")"
Else
ns = Left(ns, Len(ns) - 1)
ns = ns & ")"
End If
Case 1
ns = "RSI ("
If CInt(TextBoxP1.Value) > 0 Then
ns = ns & TextBoxP1.Value & ")"
Else
GoTo Skip:
End If
Case 2
ns = "OBV"
If Not TextBoxP1.Value = xlNullString Then
ns = ns & " (" & CInt(TextBoxP1.Value) & ")"
Else
GoTo SkipMA:
End If
Case Else
GoTo Skip:
End Select
If CheckBoxSMA.Value = True Then
ns = Replace(ns, "(", "(단순 ")
Else
ns = Replace(ns, "(", "(지수 ")
End If
SkipMA:
indicator_str = ns
Skip:
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
폼 'FChart' 수정의 마지막 단계로, 'OK' 버튼 이벤트 매크로를 수정하겠습니다. 선택된 지표, 기간, 단순이동평균 여부를 'indicator_str' 함수를 사용하여 정해진 포맷으로 만든 후 'doChartging' 함수의 인자로 추가하여 호출합니다.
※ (수정 후 'ButtonOK_Click' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Sub ButtonOK_Click()
Me.Hide
sn = Selection.Cells(1, 1).Value
If ActiveSheet.Name = CHART_POSTFIX Then
If Cells(2, 2).Value <> xlNullString Then _
sn = Left(Cells(2, 2).Value, InStr(Cells(2, 2).Value, "-") - 1)
End If
Call doCharting(sn, _
CInt(TextBoxCW.Value), _
CInt(TextBoxCH.Value), _
CInt(TextBoxCL.Value), _
indicator_str())
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Sub ButtonOK_Click()
Me.Hide
sn = Selection.Cells(1, 1).Value
If ActiveSheet.Name = CHART_POSTFIX Then
If Cells(2, 2).Value <> xlNullString Then _
sn = Left(Cells(2, 2).Value, InStr(Cells(2, 2).Value, "-") - 1)
End If
Call doCharting(sn, _
CInt(TextBoxCW.Value), _
CInt(TextBoxCH.Value), _
CInt(TextBoxCL.Value), _
indicator_str())
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
▶ (시나리오 2). Module 수정
폼 'FChart'의 'OK' 버튼 클릭 시 호출되는 'doCharting'을 수정합니다.
폼 'FChart'의 'OK' 버튼 클릭 시 호출되는 'doCharting'을 수정합니다.
※ (수정 후 'doCharting' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub doCharting(sn, cw, ch, cl, istr)
Call prepareIndicators(istr, False)
istr = Replace(istr, "(", "")
istr = Replace(istr, ")", "")
istr = Replace(istr, " ", "-")
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)), istr)
End If
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
☞ 지난 글에서 'prepareIndicators' 함수를 작성했습니다. 호출하면서 두 번째 인자를 'False'로 넘겨주는데요, 이미 만들어진 'indicator_t' 구조체 배열('it_arr')에 해당 항목이 없을 경우에 추가하라는 의미입니다.
Sub doCharting(sn, cw, ch, cl, istr)
Call prepareIndicators(istr, False)
istr = Replace(istr, "(", "")
istr = Replace(istr, ")", "")
istr = Replace(istr, " ", "-")
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)), istr)
End If
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
☞ 지난 글에서 'prepareIndicators' 함수를 작성했습니다. 호출하면서 두 번째 인자를 'False'로 넘겨주는데요, 이미 만들어진 'indicator_t' 구조체 배열('it_arr')에 해당 항목이 없을 경우에 추가하라는 의미입니다.
☞ 'onChartChange'를 호출할 때 지표 정보를 포함하는 인자를 추가로 넘겨줍니다.
기존의 'onChartChange'는 ① 'fillChartRng' 함수를 호출하여 차트가 바라보는 데이터 범위-단일 Range 오브젝트를 선택된 종목의 데이터로 채우게 한 후, ② 'drawChartTWH'를 호출하여 차트를 출력하도록 합니다.
이것을, 차트뿐만 아니라 지표까지 출력해야 하므로, 단일 Range가 아니라 두 개 또는 세 개의 Range에 대해서도 처리될 수 있도록 수정해야 합니다. ☞ 지표의 이동평균(Signal)까지 포함하는 경우 필요한 Range는 세 개 입니다.
먼저 'fillChartRngMR' 함수를 신규로 작성하겠습니다.
※ (함수 'fillChartRngMR' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function fillChartRngMR(ParamArray varArgs() As Variant) As Variant
Dim rstr As String, cols As Variant, col_add As Integer
If UBound(varArgs) < 4 Then _
Err.Raise 8902, "fillChartRngMR", "ParamArray too short"
dsheet = varArgs(0) 'sheet to which the chart pointing
If dsheet = xlNullString Then _
Err.Raise 8902, "fillChartRngMR", "Sheet name null"
osheet = varArgs(1) 'sheet including original data of the chart
'if xlNullString, = dsheet
If osheet = xlNullString Then osheet = dsheet
If Not sheetExist(osheet) Then _
Err.Raise 8902, "fillChartRngMR", "Data sheet not exist"
On Error GoTo EH_fillChartRngMR:
If Not sheetExist(dsheet) Then
Set tmpWS = Worksheets.Add(After:=Worksheets(Worksheets.Count))
tmpWS.Name = dsheet
If varArgs(2) Then tmpWS.Visible = xlSheetHidden
Else
Set tmpWS = sheets(dsheet)
If varArgs(3) < 3 Then tmpWS.Cells.Clear 'dsheet contains data
End If
k = varArgs(3) - 1
With sheets(dsheet)
endRow = sheets(osheet).Cells(1, 1).End(xlDown).Row
.Cells(1, 1).value = WorksheetFunction.Max(endRow - varArgs(4) - 1, 0)
endRow = WorksheetFunction.Min(endRow, varArgs(4) + 1)
For j = 2 To 6
.Cells(1, j).value = sheets(osheet).Cells(1, j - 1).value
.Cells(2, j).FormulaR1C1 = "=IF(OFFSET('" & osheet & "'!RC[" & (-1) & _
"],R1C" & k & ",0)<>"""",OFFSET('" & osheet & _
"'!RC[" & (-1) & "],R1C" & k & ",0),"""")"
Next j
rstr = Cells(2, 2).Address + ":" + Cells(endRow, 6).Address
If UBound(varArgs) > 4 Then
cols = getIndicatorColumns(osheet, Replace(varArgs(5), "-", " "))
For i = LBound(cols) To UBound(cols)
Col = CInt(cols(i))
.Cells(1, j).value = sheets(osheet).Cells(1, Col).value
.Cells(2, j).FormulaR1C1 = "=IF(OFFSET('" & osheet & "'!RC[" & (-j + Col) & _
"],R1C" & k & ",0)<>"""",OFFSET('" & osheet & _
"'!RC[" & (-j + Col) & "],R1C" & k & ",0),"""")"
rstr = rstr & "," _
& Cells(2, j).Address + ":" + Cells(endRow, j).Address
j = j + 1
Next i
col_add = UBound(cols) - LBound(cols) + 1
End If
.Cells(2, 2).Resize(1, 5 + col_add).AutoFill _
Destination:=.Cells(2, 2).Resize(endRow, 5 + col_add), _
Type:=xlFillDefault
End With
fillChartRngMR = Split(rstr, ",")
Exit Function
EH_fillChartRngMR:
MsgBox "Error(" & Err.Number & ") " & Err.Description & " (on fillChartRngMR)"
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function fillChartRngMR(ParamArray varArgs() As Variant) As Variant
Dim rstr As String, cols As Variant, col_add As Integer
If UBound(varArgs) < 4 Then _
Err.Raise 8902, "fillChartRngMR", "ParamArray too short"
dsheet = varArgs(0) 'sheet to which the chart pointing
If dsheet = xlNullString Then _
Err.Raise 8902, "fillChartRngMR", "Sheet name null"
osheet = varArgs(1) 'sheet including original data of the chart
'if xlNullString, = dsheet
If osheet = xlNullString Then osheet = dsheet
If Not sheetExist(osheet) Then _
Err.Raise 8902, "fillChartRngMR", "Data sheet not exist"
On Error GoTo EH_fillChartRngMR:
If Not sheetExist(dsheet) Then
Set tmpWS = Worksheets.Add(After:=Worksheets(Worksheets.Count))
tmpWS.Name = dsheet
If varArgs(2) Then tmpWS.Visible = xlSheetHidden
Else
Set tmpWS = sheets(dsheet)
If varArgs(3) < 3 Then tmpWS.Cells.Clear 'dsheet contains data
End If
k = varArgs(3) - 1
With sheets(dsheet)
endRow = sheets(osheet).Cells(1, 1).End(xlDown).Row
.Cells(1, 1).value = WorksheetFunction.Max(endRow - varArgs(4) - 1, 0)
endRow = WorksheetFunction.Min(endRow, varArgs(4) + 1)
For j = 2 To 6
.Cells(1, j).value = sheets(osheet).Cells(1, j - 1).value
.Cells(2, j).FormulaR1C1 = "=IF(OFFSET('" & osheet & "'!RC[" & (-1) & _
"],R1C" & k & ",0)<>"""",OFFSET('" & osheet & _
"'!RC[" & (-1) & "],R1C" & k & ",0),"""")"
Next j
rstr = Cells(2, 2).Address + ":" + Cells(endRow, 6).Address
If UBound(varArgs) > 4 Then
cols = getIndicatorColumns(osheet, Replace(varArgs(5), "-", " "))
For i = LBound(cols) To UBound(cols)
Col = CInt(cols(i))
.Cells(1, j).value = sheets(osheet).Cells(1, Col).value
.Cells(2, j).FormulaR1C1 = "=IF(OFFSET('" & osheet & "'!RC[" & (-j + Col) & _
"],R1C" & k & ",0)<>"""",OFFSET('" & osheet & _
"'!RC[" & (-j + Col) & "],R1C" & k & ",0),"""")"
rstr = rstr & "," _
& Cells(2, j).Address + ":" + Cells(endRow, j).Address
j = j + 1
Next i
col_add = UBound(cols) - LBound(cols) + 1
End If
.Cells(2, 2).Resize(1, 5 + col_add).AutoFill _
Destination:=.Cells(2, 2).Resize(endRow, 5 + col_add), _
Type:=xlFillDefault
End With
fillChartRngMR = Split(rstr, ",")
Exit Function
EH_fillChartRngMR:
MsgBox "Error(" & Err.Number & ") " & Err.Description & " (on fillChartRngMR)"
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
☞ 기존의 'fillChartRng'와 동일한 기능을 하지만, 캔들차트 데이터 범위와 지표 데이터 범위를 함께 구성합니다.
☞ 실제 지표 데이터의 위치를 찾기 위해 'getIndicatorColumns' 함수를 호출합니다. 아래 소스를 참고하여 입력하십시요.
※ (함수 'getIndicatorColumns' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function getIndicatorColumns(sn, istr) As Variant
Dim sc As String, indi() As CStockIndicator, i_tp As indicator_t
Dim tstr As String, cols As String
On Error GoTo EH_getIndicatorColumn:
For i = 1 To UBound(ss_list)
If ss_list(i, 2) = sn Then sc = ss_list(i, 1)
Next i
i_tp = indicator_type(istr)
If i_tp.i_type = 0 Then GoTo MyExit:
tstr = i_tp.i_type & " " & i_tp.m_type
For i = LBound(i_tp.peri) To UBound(i_tp.peri)
tstr = tstr & " " & i_tp.peri(i)
Next i
indi = feeders.Item(sc).TIndicator
For i = LBound(indi) To UBound(indi)
Dim tin As CStockIndicator
Set tin = indi(i)
If tstr = tin.printMe() Then
cols = tin.Col
If (i_tp.i_type And idx_sig) = idx_sig Then _
cols = cols & " " & tin.Col + 1
GoTo MyExit:
End If
Next i
MyExit:
getIndicatorColumns = Split(cols, " ")
Exit Function
EH_getIndicatorColumn:
Debug.Print "Error(" & Err.Number & ") " & Err.Description & " [getIndicatorColumns]"
GoTo MyExit:
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function getIndicatorColumns(sn, istr) As Variant
Dim sc As String, indi() As CStockIndicator, i_tp As indicator_t
Dim tstr As String, cols As String
On Error GoTo EH_getIndicatorColumn:
For i = 1 To UBound(ss_list)
If ss_list(i, 2) = sn Then sc = ss_list(i, 1)
Next i
i_tp = indicator_type(istr)
If i_tp.i_type = 0 Then GoTo MyExit:
tstr = i_tp.i_type & " " & i_tp.m_type
For i = LBound(i_tp.peri) To UBound(i_tp.peri)
tstr = tstr & " " & i_tp.peri(i)
Next i
indi = feeders.Item(sc).TIndicator
For i = LBound(indi) To UBound(indi)
Dim tin As CStockIndicator
Set tin = indi(i)
If tstr = tin.printMe() Then
cols = tin.Col
If (i_tp.i_type And idx_sig) = idx_sig Then _
cols = cols & " " & tin.Col + 1
GoTo MyExit:
End If
Next i
MyExit:
getIndicatorColumns = Split(cols, " ")
Exit Function
EH_getIndicatorColumn:
Debug.Print "Error(" & Err.Number & ") " & Err.Description & " [getIndicatorColumns]"
GoTo MyExit:
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
☞ 위 소스와 같이 전역변수 'ss_list'로부터 종목코드를 조회하고, 해당 종목코드의 'CCandleFeeder'로부터 'pTIndicator' 배열을 얻은 후, 일치하는 지표의 column 정보를 획득합니다.
☞ 위 함수는 전역변수 'ss_list'가 선언된 모듈에 작성해야 합니다.
다음은 'drawChartTWHmR'을 신규로 작성할 차례입니다.
※ (함수 'drawChartTWHmR' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function drawChartTWHmR(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)(LBound(varArgs(0)))
cht.Chart.ChartType = varArgs(1)
If UBound(varArgs) > 6 Then
cht.Name = varArgs(7)
End If
For i = LBound(varArgs(0)) + 1 To UBound(varArgs(0))
With cht.Chart.SeriesCollection.NewSeries
.values = varArgs(0)(i)
On Error Resume Next ''' For Excel2003 compatibility '''''''''''''''''''
.AxisGroup = xlSecondary
On Error GoTo 0 ''' For Excel2003 compatibility '''''''''''''''''''
.Type = xlLine
.MarkerStyle = xlNone
If i > LBound(varArgs(0)) + 1 Then
.Border.LineStyle = xlDot
.Name = "Signal"
Else
.Format.Line.Weight = 2#
.Name = "Indicator"
End If
End With
Next i
Call rescaleChart(cht)
For k = 1 To 4
cht.Chart.Legend.LegendEntries(1).Delete
Next k
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
.OnAction = "onChartRefresh"
End With
End If
End If
Set CHTsheet = Nothing
Set cht = Nothing
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
☞ 캔들 차트는 차트의 'xlPrimary' 영역에, 지표와 Signal은 'xlSecondary' 영역에 출력하도록 했습니다.
☞ 차트의 캔들 영역과 지표 영역의 Scale 처리를 위해 'rescaleChart' 함수를 호출합니다. 아래 소스를 참고하십시요.
☞ 마찬가지로 차트가 스크롤될 때 Scale 처리를 위해 'onChartRefresh'를 호출합니다.
※ (함수 'rescaleChart' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function rescaleChart(ch)
On Error GoTo EH_rescaleChart:
scH = 2
scL = 3
s_max = WorksheetFunction.Round(WorksheetFunction.Max _
(ch.Chart.SeriesCollection(scH).values), 0)
s_min = WorksheetFunction.Round(WorksheetFunction.Min _
(ch.Chart.SeriesCollection(scL).values), 0)
pDiff = WorksheetFunction.Round((s_max - s_min) / 10, 0)
s_max = s_max + pDiff
s_min = s_min - pDiff
If ch.Chart.SeriesCollection.Count > 4 Then
scOSC = 5
s_min = s_min - 4 * pDiff
If InStr(ch.Name, "RSI") > 1 Then
With ch.Chart.Axes(xlValue, xlSecondary)
.MaximumScale = 400
.MinimumScale = 0
End With
Else
osc_max = WorksheetFunction.Max(ch.Chart.SeriesCollection(scOSC).values)
osc_min = WorksheetFunction.Min(ch.Chart.SeriesCollection(scOSC).values)
If ch.Chart.SeriesCollection.Count > 4 Then
sig_max = WorksheetFunction.Max _
(ch.Chart.SeriesCollection(scOSC+1).values)
sig_min = WorksheetFunction.Min _
(ch.Chart.SeriesCollection(scOSC+1).values)
osc_max = WorksheetFunction.Max(osc_max, sig_max)
osc_min = WorksheetFunction.Min(osc_min, sig_min)
End If
oDiff = (osc_max - osc_min) / 10
With ch.Chart.Axes(xlValue, xlSecondary)
.MaximumScale = osc_min + 48 * oDiff
.MinimumScale = osc_min - oDiff
.TickLabelPosition = xlNone
End With
End If
End If
With ch.Chart.Axes(xlValue, xlPrimary)
.MaximumScale = s_max
.MinimumScale = s_min
End With
Exit Function
EH_rescaleChart:
Debug.Print "Error(" & Err.Number & ") " & Err.Description & " [rescaleChart]"
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
※ (스클롤바 이벤트 매크로 'onChartRefresh' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub onChartRefresh()
Debug.Print "[onChartRefresh]1 " & ", " & Timer
Dim ch As ChartObject, x As Variant
On Error GoTo EH_onChartRefresh:
Set ch = ActiveSheet.ChartObjects(1)
Call rescaleChart(ch)
Set ch = Nothing
Debug.Print "[onChartRefresh]2 " & ", " & Timer
Exit Sub
EH_onChartRefresh:
Debug.Print "Error(" & Err.Number & ") " & Err.Description & " [onChartRefresh]"
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function drawChartTWHmR(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)(LBound(varArgs(0)))
cht.Chart.ChartType = varArgs(1)
If UBound(varArgs) > 6 Then
cht.Name = varArgs(7)
End If
For i = LBound(varArgs(0)) + 1 To UBound(varArgs(0))
With cht.Chart.SeriesCollection.NewSeries
.values = varArgs(0)(i)
On Error Resume Next ''' For Excel2003 compatibility '''''''''''''''''''
.AxisGroup = xlSecondary
On Error GoTo 0 ''' For Excel2003 compatibility '''''''''''''''''''
.Type = xlLine
.MarkerStyle = xlNone
If i > LBound(varArgs(0)) + 1 Then
.Border.LineStyle = xlDot
.Name = "Signal"
Else
.Format.Line.Weight = 2#
.Name = "Indicator"
End If
End With
Next i
Call rescaleChart(cht)
For k = 1 To 4
cht.Chart.Legend.LegendEntries(1).Delete
Next k
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
.OnAction = "onChartRefresh"
End With
End If
End If
Set CHTsheet = Nothing
Set cht = Nothing
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
☞ 캔들 차트는 차트의 'xlPrimary' 영역에, 지표와 Signal은 'xlSecondary' 영역에 출력하도록 했습니다.
☞ 차트의 캔들 영역과 지표 영역의 Scale 처리를 위해 'rescaleChart' 함수를 호출합니다. 아래 소스를 참고하십시요.
☞ 마찬가지로 차트가 스크롤될 때 Scale 처리를 위해 'onChartRefresh'를 호출합니다.
※ (함수 'rescaleChart' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function rescaleChart(ch)
On Error GoTo EH_rescaleChart:
scH = 2
scL = 3
s_max = WorksheetFunction.Round(WorksheetFunction.Max _
(ch.Chart.SeriesCollection(scH).values), 0)
s_min = WorksheetFunction.Round(WorksheetFunction.Min _
(ch.Chart.SeriesCollection(scL).values), 0)
pDiff = WorksheetFunction.Round((s_max - s_min) / 10, 0)
s_max = s_max + pDiff
s_min = s_min - pDiff
If ch.Chart.SeriesCollection.Count > 4 Then
scOSC = 5
s_min = s_min - 4 * pDiff
If InStr(ch.Name, "RSI") > 1 Then
With ch.Chart.Axes(xlValue, xlSecondary)
.MaximumScale = 400
.MinimumScale = 0
End With
Else
osc_max = WorksheetFunction.Max(ch.Chart.SeriesCollection(scOSC).values)
osc_min = WorksheetFunction.Min(ch.Chart.SeriesCollection(scOSC).values)
If ch.Chart.SeriesCollection.Count > 4 Then
sig_max = WorksheetFunction.Max _
(ch.Chart.SeriesCollection(scOSC+1).values)
sig_min = WorksheetFunction.Min _
(ch.Chart.SeriesCollection(scOSC+1).values)
osc_max = WorksheetFunction.Max(osc_max, sig_max)
osc_min = WorksheetFunction.Min(osc_min, sig_min)
End If
oDiff = (osc_max - osc_min) / 10
With ch.Chart.Axes(xlValue, xlSecondary)
.MaximumScale = osc_min + 48 * oDiff
.MinimumScale = osc_min - oDiff
.TickLabelPosition = xlNone
End With
End If
End If
With ch.Chart.Axes(xlValue, xlPrimary)
.MaximumScale = s_max
.MinimumScale = s_min
End With
Exit Function
EH_rescaleChart:
Debug.Print "Error(" & Err.Number & ") " & Err.Description & " [rescaleChart]"
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
※ (스클롤바 이벤트 매크로 'onChartRefresh' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub onChartRefresh()
Debug.Print "[onChartRefresh]1 " & ", " & Timer
Dim ch As ChartObject, x As Variant
On Error GoTo EH_onChartRefresh:
Set ch = ActiveSheet.ChartObjects(1)
Call rescaleChart(ch)
Set ch = Nothing
Debug.Print "[onChartRefresh]2 " & ", " & Timer
Exit Sub
EH_onChartRefresh:
Debug.Print "Error(" & Err.Number & ") " & Err.Description & " [onChartRefresh]"
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'onChartChange' 소스를 신규로 작성한 'fillCahrtRngMR'와 'drawChartTWHmR' 함수를 사용하도록 수정하겠습니다.
※ (수정 후 'onChartChange' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub onChartChange(ParamArray varArgs() As Variant)
If UBound(varArgs) < 3 Then _
Err.Raise 8902, "onChartChange", "ParamArray too short"
Dim rngs() As Range, chtRng As Variant, sn As String
Dim ch As ChartObject, sbar As ScrollBar, istr As String, cn As String
On Error GoTo EH_onChartChange:
Application.ScreenUpdating = False
sn = Cells(2, 2).value
If UBound(varArgs) > 3 Then sn = varArgs(4)
If sn = xlNullString Then Exit Sub
csheet = ActiveSheet.Name
If Not sheets(csheet).ChartObjects.Count = 0 Then
Set ch = sheets(csheet).ChartObjects(1)
istr = ch.Name
istr = Right(istr, Len(istr) - InStr(InStr(istr, "-") + 1, istr, "-"))
ch.Delete
Set sbar = Sheets(csheet).ScrollBars(1)
sbar.Delete
End If
If UBound(varArgs) > 4 Then
chtRng = fillChartRngMR(csheet & "_AUX", sn, True, 2, varArgs(3), varArgs(5))
cn = sn & "-" & varArgs(5)
Else
chtRng = fillChartRngMR(csheet & "_AUX", sn, True, 2, varArgs(3), istr)
cn = sn & "-" & istr
End If
sheets(csheet).Select
ReDim rngs(LBound(chtRng) To UBound(chtRng))
For i = LBound(chtRng) To UBound(chtRng)
Set rngs(i) = sheets(csheet & "_AUX").Range(chtRng(i))
Next i
endRow = sheets(sn).Cells(1, 1).End(xlDown).Row
drawChartTWHmR rngs, _
varArgs(0), varArgs(1), varArgs(2), csheet, _
csheet & "_AUX" & "!" & Cells(1, 1).Address, _
WorksheetFunction.Max(endRow - varArgs(3) - 1, 0), _
cn
Set ch = Nothing
Set sbar = Nothing
Application.ScreenUpdating = True
Exit Sub
EH_onChartChange:
MsgBox "Error(" & Err.Number & ") " & Err.Description & " [onChartChange]"
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub onChartChange(ParamArray varArgs() As Variant)
If UBound(varArgs) < 3 Then _
Err.Raise 8902, "onChartChange", "ParamArray too short"
Dim rngs() As Range, chtRng As Variant, sn As String
Dim ch As ChartObject, sbar As ScrollBar, istr As String, cn As String
On Error GoTo EH_onChartChange:
Application.ScreenUpdating = False
sn = Cells(2, 2).value
If UBound(varArgs) > 3 Then sn = varArgs(4)
If sn = xlNullString Then Exit Sub
csheet = ActiveSheet.Name
If Not sheets(csheet).ChartObjects.Count = 0 Then
Set ch = sheets(csheet).ChartObjects(1)
istr = ch.Name
istr = Right(istr, Len(istr) - InStr(InStr(istr, "-") + 1, istr, "-"))
ch.Delete
Set sbar = Sheets(csheet).ScrollBars(1)
sbar.Delete
End If
If UBound(varArgs) > 4 Then
chtRng = fillChartRngMR(csheet & "_AUX", sn, True, 2, varArgs(3), varArgs(5))
cn = sn & "-" & varArgs(5)
Else
chtRng = fillChartRngMR(csheet & "_AUX", sn, True, 2, varArgs(3), istr)
cn = sn & "-" & istr
End If
sheets(csheet).Select
ReDim rngs(LBound(chtRng) To UBound(chtRng))
For i = LBound(chtRng) To UBound(chtRng)
Set rngs(i) = sheets(csheet & "_AUX").Range(chtRng(i))
Next i
endRow = sheets(sn).Cells(1, 1).End(xlDown).Row
drawChartTWHmR rngs, _
varArgs(0), varArgs(1), varArgs(2), csheet, _
csheet & "_AUX" & "!" & Cells(1, 1).Address, _
WorksheetFunction.Max(endRow - varArgs(3) - 1, 0), _
cn
Set ch = Nothing
Set sbar = Nothing
Application.ScreenUpdating = True
Exit Sub
EH_onChartChange:
MsgBox "Error(" & Err.Number & ") " & Err.Description & " [onChartChange]"
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
☞ 차트 이름에 지표정보를 추가했습니다. 'CCandleFeeder'의 'refreshChart' 함수를 수정해야 합니다.
※ (수정 후 'CCandleFeeder'의 'refreshChart' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
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 InStr(ch.Name, pCandleSheet) > 0 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
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
☞ 하이라이트된 부분이 수정된 곳입니다.
지금까지 한 작업의 결과를 테스트해 보겠습니다. 먼저 'Schedule' 버튼을 클릭하여 'FSchedule' 폼이 팝업되면 종목과 지표를 선택한 후 'OK' 버튼을 클릭합니다. ☞ 이 과정을 선행하지 않으면 'CCandleFeeder' 오브젝트 목록(Collection)이 생성되지 않은 상태이므로 차트에 지표가 출력되지 않습니다.
※ (수정 후 'CCandleFeeder'의 'refreshChart' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
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 InStr(ch.Name, pCandleSheet) > 0 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
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
☞ 하이라이트된 부분이 수정된 곳입니다.
지금까지 한 작업의 결과를 테스트해 보겠습니다. 먼저 'Schedule' 버튼을 클릭하여 'FSchedule' 폼이 팝업되면 종목과 지표를 선택한 후 'OK' 버튼을 클릭합니다. ☞ 이 과정을 선행하지 않으면 'CCandleFeeder' 오브젝트 목록(Collection)이 생성되지 않은 상태이므로 차트에 지표가 출력되지 않습니다.
다음 그림과 같이 'Chart' 버튼을 클릭하여 폼이 팝업되면 지표를 선택하고 'OK' 버튼을 누릅니다.
그림 4-1. 테스트 결과 1 |
그림 4-2와 같이 지표가 포함된 캔들차트를 확인할 수 있습니다.
그림 4-2. 테스트 결과 2 |
일단 의도한대로 완성은 되었지만, 불편한 점이 있습니다. 차트 출력 시트('CHARTS')에서 지표를 전환하는 것이 불가능하군요.
작업을 조금 더 해서 차트에 포함된 지표의 전환이 쉬워지도록 개선해 보겠습니다. 'CHARTS' 시트의 생성은 'createChartSheet' 함수가 담당하므로, 'createChartSheet'을 수정하면 될 것입니다.
'CHARTS' 시트에 버튼을 하나 추가하고, 클릭할 경우 폼 'FChart'가 팝업되도록 하겠습니다.
※ (수정 후 'createChartSheet' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function createChartSheet(ParamArray varArgs() As Variant) As Boolean
If UBound(varArgs) < 5 Then _
Err.Raise 8902, "createChartSheet", "ParamArray too short"
Dim choices As String
createChartSheet = False
On Error GoTo EH_createChartSheet:
csname = varArgs(0)
If Not sheetExist(csname) Then
Set tmpWS = Worksheets.Add(After:=Worksheets(Worksheets.Count))
tmpWS.Name = csname
If UBound(varArgs) < 1 Then GoTo SkipControl:
If varArgs(1) = xlNullString Then GoTo SkipControl:
tmpWS.Cells(2, 1).value = "Charts:"
tmpWS.Cells(2, 2).Font.Size = 10
tmpWS.Columns(2).ColumnWidth = tmpWS.Columns(1).ColumnWidth * 1.8
tmpWS.Columns(3).ColumnWidth = tmpWS.Columns(1).ColumnWidth * 0.2
Set btn = tmpWS.Buttons.Add(tmpWS.Cells(2, 4).Width * 3, _
tmpWS.Cells(2, 4).Height, _
tmpWS.Cells(2, 4).Width, _
tmpWS.Cells(2, 4).Height)
btn.Name = "ButtonChange"
btn.OnAction = "'onChartChange " & varArgs(2) & ", " _
& varArgs(3) & ", " & varArgs(4) & ", " & varArgs(5) & "'"
btn.Characters.Text = "Change"
With btn.Characters.Font
' .Name = "Times New Roman"
' .FontStyle = "Regular"
.Size = 10
End With
Set btn = tmpWS.Buttons.Add(tmpWS.Cells(2, 5).Width * 4, _
tmpWS.Cells(2, 5).Height, _
tmpWS.Cells(2, 5).Width, _
tmpWS.Cells(2, 5).Height)
btn.Name = "ButtonIndicator"
btn.OnAction = "'Chart_Click True'"
btn.Characters.Text = "Indicator"
With btn.Characters.Font
' .Name = "Times New Roman"
' .FontStyle = "Regular"
.Size = 10
End With
Else
Set tmpWS = sheets(csname)
On Error Resume Next
For Each cht In tmpWS.ChartObjects
cht.Delete
Next cht
For Each bar In tmpWS.ScrollBars
bar.Delete
Next bar
On Error GoTo 0
GoTo SkipControl:
End If
If UBound(varArgs) < 1 Then GoTo SkipControl:
With tmpWS.Cells(2, 2).Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, _
Operator:=xlBetween, Formula1:=varArgs(1)
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
tmpWS.Cells(2, 2).Font.Size = 9
SkipControl:
createChartSheet = True
MyExit:
Exit Function
EH_createChartSheet:
MsgBox "Error[" & Err.Number & "] " & Err.Description & " [createChartSheet]"
GoTo MyExit:
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
☞ 추가한 버튼의 이벤트 매크로를 'Chart_Click'으로 지정했는데, boolean형 인자로 true를 넘겨줍니다. 'FChart'의 차트 크기를 지정하는 페이지를 비활성화하기 위한 것입니다.
Function createChartSheet(ParamArray varArgs() As Variant) As Boolean
If UBound(varArgs) < 5 Then _
Err.Raise 8902, "createChartSheet", "ParamArray too short"
Dim choices As String
createChartSheet = False
On Error GoTo EH_createChartSheet:
csname = varArgs(0)
If Not sheetExist(csname) Then
Set tmpWS = Worksheets.Add(After:=Worksheets(Worksheets.Count))
tmpWS.Name = csname
If UBound(varArgs) < 1 Then GoTo SkipControl:
If varArgs(1) = xlNullString Then GoTo SkipControl:
tmpWS.Cells(2, 1).value = "Charts:"
tmpWS.Cells(2, 2).Font.Size = 10
tmpWS.Columns(2).ColumnWidth = tmpWS.Columns(1).ColumnWidth * 1.8
tmpWS.Columns(3).ColumnWidth = tmpWS.Columns(1).ColumnWidth * 0.2
Set btn = tmpWS.Buttons.Add(tmpWS.Cells(2, 4).Width * 3, _
tmpWS.Cells(2, 4).Height, _
tmpWS.Cells(2, 4).Width, _
tmpWS.Cells(2, 4).Height)
btn.Name = "ButtonChange"
btn.OnAction = "'onChartChange " & varArgs(2) & ", " _
& varArgs(3) & ", " & varArgs(4) & ", " & varArgs(5) & "'"
btn.Characters.Text = "Change"
With btn.Characters.Font
' .Name = "Times New Roman"
' .FontStyle = "Regular"
.Size = 10
End With
Set btn = tmpWS.Buttons.Add(tmpWS.Cells(2, 5).Width * 4, _
tmpWS.Cells(2, 5).Height, _
tmpWS.Cells(2, 5).Width, _
tmpWS.Cells(2, 5).Height)
btn.Name = "ButtonIndicator"
btn.OnAction = "'Chart_Click True'"
btn.Characters.Text = "Indicator"
With btn.Characters.Font
' .Name = "Times New Roman"
' .FontStyle = "Regular"
.Size = 10
End With
Else
Set tmpWS = sheets(csname)
On Error Resume Next
For Each cht In tmpWS.ChartObjects
cht.Delete
Next cht
For Each bar In tmpWS.ScrollBars
bar.Delete
Next bar
On Error GoTo 0
GoTo SkipControl:
End If
If UBound(varArgs) < 1 Then GoTo SkipControl:
With tmpWS.Cells(2, 2).Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, _
Operator:=xlBetween, Formula1:=varArgs(1)
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
tmpWS.Cells(2, 2).Font.Size = 9
SkipControl:
createChartSheet = True
MyExit:
Exit Function
EH_createChartSheet:
MsgBox "Error[" & Err.Number & "] " & Err.Description & " [createChartSheet]"
GoTo MyExit:
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
☞ 추가한 버튼의 이벤트 매크로를 'Chart_Click'으로 지정했는데, boolean형 인자로 true를 넘겨줍니다. 'FChart'의 차트 크기를 지정하는 페이지를 비활성화하기 위한 것입니다.
☞ 'Chart_Click' 매크로를 아래 소스로 수정하십시요.
※ (수정 후 'Chart_Click' 소스)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub Chart_Click(ParamArray varArgs() As Variant)
Dim frm As FChart
Set frm = New FChart
Load frm
If Not UBound(varArgs) < 0 Then frm.MultiPage1.Pages(0).Enabled = False
frm.Show
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
☞ 하이라이트된 부분이 수정된 곳입니다.
Sub Chart_Click(ParamArray varArgs() As Variant)
Dim frm As FChart
Set frm = New FChart
Load frm
If Not UBound(varArgs) < 0 Then frm.MultiPage1.Pages(0).Enabled = False
frm.Show
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
☞ 하이라이트된 부분이 수정된 곳입니다.
모든 작업이 끝났습니다. 'CHARTS' 시트를 삭제한 후 다시 테스트해 보겠습니다.
그림 4-3. 테스트 결과 3 |
위 그림 4-3과 같이 버튼이 추가된 'CHARTS' 시트를 확인할 수 있습니다.
※ 다음 글에서 지표의 활용과 관련된 내용을 다루겠습니다.
댓글 없음:
댓글 쓰기