You are on page 1of 5

以 Excel VBA 進行回溯測試分析

試算表中建立回溯測試的缺憾

以[範例 4.2.1]為基礎,可進一步進行以下分析:

1. 與同期間之股價指數或類股指數相比較。
2. 進行更廣泛期間、更廣泛股票之分析。可能的話,以同一規則測試不同股票,以其報酬率與指數
比較,進行統計檢定,以確認選股指標之有效性。
3. 調整指標參數。例如,上例心理線指標中的 10(N)、0.25 與 0.75 等,均為可調變參數。
4. 設定分批買進、分批賣出策略。例如,當心理線計算值低於 0.3 時,以 50%資金買進股票,低於
0.2 時,始投入 100%資金買進股票等。
5. 考慮交易成本。
6. 考慮其他指標,例如停損點、獲利滿足點等。這些買賣規則可以邏輯運算組合。例如,買進規則為
—「當心理線指標小於或等於 0.25 時」且「5 日均線往上突破 10 日均線」時買進;賣出規則為—
「當心理線指標大於或等於 0.75 時」或「投資損失達 10%」或「獲利達 20%」時賣出。

欲在 Excel 中以格位計算達成以上功能並不容易,因此在以下範例中,將改以 VBA 編碼設計的


表單系統完成之。
在完成回溯測試,找出有效的操作規則後,投資人下一步往往希望,以該買賣指標組合(此為投
資策略之一部分),過濾目前可投資的標的物,是否已經觸及買賣點,以在市場中進行操作。此即下
一子節,所擬建立之「即時操盤環境」的系統目標。

以 Excel VBA 進行回溯測試分析


既然在試算表格位環境中進行回溯測試,會面臨諸多問題,根本解決之道,即改用「VBA 編碼」
來做,但應該如何作呢?
以前一節的範例為基礎,接下來將逐步強化、複雜化該範例。(此即系統開發策略中所謂的「漸進
開發策略」)

以 VBA 建立心理線分析模型
以下我們分成幾個階段逐步讓原來建構在 Excel 試算環境中的系統逐步脫離 Excel 的環境。

[範例 4.2.2:以 VBA 程式碼進行格位計算,並將計算結果傳回格位中]


(參考「Ch4_2_VBA_v1.xlsm」檔案)
在本節第一個範例中,我們透過 VBA 程式碼計算原本 Excel 格位版本中 D 欄到 H 欄的計算,將
計算結果送回格位中,並將「投資報酬率」計算結果(G7),在表單介面輸出。
此外,為了讓「心理線指標回溯測試模型」更加具備彈性,我們把指標參數(心理線計算期間、心
理線判斷下限、心理線判斷上限與分析期間等四個參數),拉到表單輸出入介面中,如此一來,就無
須在程式中調整參數。
設計妥的心理線分析模型介面如圖 4.2.6 所示,使用到的控制項與屬性設定如表 4.2.3 所示。主要
程式碼(由 CommandButton1 之 Click 事件趨動)如表 4.2.4 所示。
圖 4.2.6 範例系統畫面

表 4.2.3 範例中的屬性修改
物件(控制項)名稱 修改的屬性名稱 修改前的屬性值 修改後的屬性值
Label1 Caption Label1 指標計算天數
Label2 Caption Label2 買進下限值
Label3 Caption Label3 賣出上限值
Label4 Caption Label4 測試筆數
Label5 Caption Label4 測試期間報酬率
TextBox1 Text Text1 10
TextBox2 Text Text2 0.25
TextBox3 Text Text3 0.75
TextBox4 Text Text4 326
TextBox5 Text Text5 (空值)
Command1 Caption Command1 執行
Command2 Caption Command2 離開
Frame1 Caption Frame1 心理線測試參數設定
Frame2 Caption Frame2 測試績效
UserForm1 Caption UserForm1 心理線回測系統

表 4.2.4 範例系統程式碼
行號 程式碼
1 Private Sub CommandButton1_Click()

2 ''宣告變數型態
3 Dim TimePeriod, TimeSpan As Integer
4 Dim LowBound, UpBound As Single
5 Dim i, j As Integer
6 '透過介面取得參數
7 TimePeriod = Val(TextBox1.Text) '取得心理線計算期間
8 LowBound = Val(TextBox2.Text) '取得心理線判斷下限
9 UpBound = Val(TextBox3.Text) '取得心理線判斷上限
10 TimeSpan = Val(TextBox4.Text) '取得分析期間
11 '清除輸出格位值
12 For i = 4 To 8
13 For j = 2 To 326
14 Cells(j, i) = ""
15 Next j
16 Next i
17 '設定模式初始值
18 Cells(TimePeriod, 6) = 2 '一開始無買賣行動
19 Cells(TimePeriod, 7) = 0 '一開始無股票部位
20 Cells(TimePeriod, 8) = 1 '一開始現金部位
21 '計算「D」欄
22 For i = 2 To TimeSpan
23 If Cells(i, 3) > 0 Then
24 Cells(i, 4) = 1
25 Else
26 Cells(i, 4) = 0
27 End If
28 Next i
29 '計算「E」~「H」欄
30 Dim UpSum As Single
31 For i = TimePeriod + 1 To TimeSpan
32 '計算「E」欄
33 UpSum = 0
34 For j = 1 To TimePeriod
35 UpSum = UpSum + Cells(i - j + 1, 4)
36 Next j
37 Cells(i, 5) = UpSum / TimePeriod
38 '計算「F」欄
39 If Cells(i, 5) <= LowBound Then
40 Cells(i, 6) = 1
41 ElseIf Cells(i, 5) >= UpBound Then
42 Cells(i, 6) = 3
43 Else
44 Cells(i, 6) = 2
45 End If
46 '計算「G」欄
47 If Cells(i - 1, 6) = 1 Then
48 Cells(i, 7) = Cells(i - 1, 8) / Cells(i, 2) + Cells(i - 1, 7)
49 ElseIf Cells(i - 1, 6) = 2 Then
50 Cells(i, 7) = Cells(i - 1, 7)
51 Else
52 Cells(i, 7) = 0
53 End If
54 '計算「H」欄
55 If Cells(i - 1, 6) = 1 Then
56 Cells(i, 8) = 0
57 ElseIf Cells(i - 1, 6) = 2 Then
58 Cells(i, 8) = Cells(i - 1, 8)
60 Else
61 Cells(i, 8) = Cells(i - 1, 7) * Cells(i, 2) + Cells(i - 1, 8)
62 End If
63 Next i
64 '將「投資報酬率」計算結果輸出
65 TextBox5.Text = Str(Format((Cells(TimeSpan, 7) * Cells(TimeSpan, 2) + Cells(TimeSpan,
8)) - 1, "0.0000"))
66 End Sub

表 4.2.4 程式碼說明如下:
行(1)與行(66)間的程式碼為,當 CommandButton1 被滑鼠左鍵 Click 驅動時執行的程序。
行(3)宣告 TimePeriod 與 TimeSpan 兩變數,分別用以儲存心理線參數計算期間與回溯測試資料
筆數。
行(4)宣告 LowBound 與 UpBound 兩變數,分別用以儲存判斷心理線指標為買進或賣出的判斷值。
行(5)宣告 i 與 j 兩變數,分別為用以控制外層迴圈與內層迴圈變化的指標變數。
行(7)至行(10)間的程式碼分別用以從 TextBox1, TextBox2, TextBox3 與 TextBox4 文字框中取得使
用者透過使用介面設定的「心理線參數計算期間」 、
「判斷心理線指標為買進的判斷 值」 、
「判斷心理線 指
標為賣出的判斷值」與「回溯測試資料筆數」,並存入相應的變數中。由於取得的值為字串資料型態,
因此必需透過 Val()函數將之轉為數值資料型態。
行(12)至行(16)間的程式碼用以將 D 欄(第 4 欄)至 H 欄(第 8 欄),以及第 2 列到第 326 列(資料的
總列數)中的格位清空。
行(18)至行(20)間的程式碼分別用以設定回溯測試的啟始條件,並將啟始條件值存入「試算表」相
應格位中。
行(22)至行(28)間的程式碼用以計算「D」(第四)欄資料,該欄資料係依據前一欄(「C」(第三)欄)資
料判斷若大於 0 則第四欄填「1」,否則填「0」。由於每一列資料都要如此處理,因此將此判斷結構置 於
一迴圈中,計算由第 2 列至第 TimeSpan 列的資料。
行(30)宣告 UpSum 變數,用以儲存過去一段時間(TimePeriod 變數決定時間長度)上漲天數總合。
行(31)至行(63)間的程式碼用以計算從「E」(第五)~「H」(第八)欄的資料,由於每一列都要計算,因
此將其置於迴圈中,由於第一筆買賣判斷至少要比 TimePeriod 長且第一列為標題列,因此迴圈由
TimePeriod + 1 開始,至 TimeSpan 結束。
行(33)至行(37)間的程式碼用以計算第「E」(第五)欄的資料,此欄資料計算過去 TimePeriod 天的
平均上漲天數,因此藉由一內部迴圈 (行(34)至行(36)間的程式碼)累計上漲天數總合,再除以
TimePeriod,即得平均上漲天數比率,將之存入第五欄中(行(37))。由於,UpSum 變數用以儲存過去
TimePeriod 天的上漲天數總合,在累計前必需設為 0(行(33))。
行(39)至行(45)間的程式碼用以計算第「F」(第六)欄的資料,此欄資料為判斷買賣行動,若為 1 則
買進(即當第「E」(第五)欄資料<=LowerBound 時,設為 1)、若為 3 則賣出(即當第「E」(第五)欄資料
>=UpBound 時,設為 3),否則不買不賣(即當第「E」(第五)欄資料不滿足上述兩條件時,設為 2)。因此
我們使用包含三種狀況的判斷結構,用以區別三種狀況的前提條件,以決定第「F」(第六)欄應該為 1
或 2 或 3。在確定買賣決策後,在第「G」(第七)與第「H」(第八)欄分別可以調整隔天之股票與現金部位。
行(47)至行(53)間的程式碼用以計算第「G」(第七)欄的資料(即股票部位)。若前一天(i-1)出現買訊
(第「F」(第六)欄的資料為 1),則投入第 i-1 天的資金並以第 i 天的開盤價(儲存於第「B」(第二)欄中)於
隔日買進(即 Cells(i - 1, 8) / Cells(i, 2)之計算),並加入前一天(i-1)的股票部位(Cells(i - 1, 7)),可得今
日(i)的股票部位;若前一天(i-1)出現「不買不賣」之訊號(第「F」(第六)欄的資料為 2),則今日(i)之股票
部位等同於前一日(i-1)之股票部位;若前一天(i-1)出現賣訊(第「F」(第六)欄的資料為 3)(不為 1 或 2 的
第三種狀況),則今日(i)之股票部位因全部賣出,將為 0。
行(55)至行(62)間的程式碼用以計算第「H」(第八)欄的資料(即現金部位)。若前一天(i-1)出現買訊
(第「F」(第六)欄的資料為 1),則今日(i)之現金部位應全數買進,將為 0;若前一天(i-1)出現「不買不賣」
之訊號(第「F」(第六)欄的資料為 2),則今日(i)之現金部位等同於前一日(i-1)之現金部位;若前一天(i-
1)出現賣訊(第「F」(第六)欄的資料為 3)(不為 1 或 2 的第三種狀況),則將第 i-1 天的股票以第 i 天的開
盤價(儲存於第「B」(第二)欄中)賣出(即 Cells(i - 1, 7) * Cells(i, 2)之計算),並加入前一天(i-1)的現金部
位(Cells(i - 1, 8)),可得今日(i)的現金部位。
行(65)用以計算期間的報酬率,計算方法為:(「期末股票+現金價值」 - 期初現金價值」) 「期初現
「 /
金價值」(但由於「期初現金價值」為 1,因此在程式碼中無需再「/1」)。其中期末股票價值以「(最後一期
的開盤價*股票部位)」求得。在此假設當日開盤價等於收盤價,此假設並不離譜,否則必須讀取最後
一天收盤價資料計算。計算結果輸出到 TextBox5 的文字框中。Format 函數可用以設定數值輸出格
式,"0.0000"表輸出格式為 1 位整數、4 位小數。

程式執行畫面如圖 4.2.7 所示。

圖 4.2.7 系統執行結果

You might also like