You are on page 1of 23

每日 K 線交易策略系統設計(VBA 版)

雖然前節中,我們在 Excel 格位環境中設計出可以回測並建議交易的系統,但在後來的延伸中,

包括預算格日觸發價格與參數最佳化等功能,都必須使用 VBA 語言的幫忙。因此,在此節中,我們

將嘗試以 TS 軟體的架構但以 VBA 語言,建立同時可以回測並作出交易判斷的系統。

在本書第 N 章中,我們所設計的 VBA 回測系統,係以漸進開發的方式開發功能尚稱完整的系

統,但該系統並謂模仿 TradeStation 的架構,因此也失去了模組化的特性。在此,我們將另行嘗試,

提供讀者另一選擇。

說起來,在 Easy Language 的語法中,也只有類似「Cross over 與 Cross under」的指令是 EL 有

但 VB 沒有的,況且判斷「交叉」(Cross)的語法已經在前文中被克服了,那麼就沒有甚麼是 TS 作得

到但 VB 作不到的了。

在本節所提供的系統中,由上到下包含「選取分析期間」的「參數設定」分區、提供「測試策

略績效」的「策略測試」分區、提供策略最佳化參數的「最佳化」分區、提供「算出隔日策略促發

價格」的「交易建議」分區,系統介面如圖 1 所示,系統架構敘述如下:
圖1

系統架構敘述如下:

1. 「參數設定」分區。可以「Max. Bars Back」設定作為保留作為計算技術指標之資料筆數(例如算

出 10 與 20 日均線的指標,必須保留 20 筆資料最為指標計算之用),以「Last Date」設定最後測

試日期,以「Bars Test」設定總分析 K 線數(若為日 K 線,即分析該設定日數之期間)。設定妥後,

按下「導入資料」按鍵,即可驅動如表 1 的程式碼,以將所欲分析期間的資料由「Data_Source」

工作表搬移到「Data」工作表中。
表1

行號 程式碼

1 Private Sub CommandButton1_Click()

2 Dim I As Long

3 '==讀入設定參數=================================

4 MaxBarsBack = Val(TextBox1.Text)

5 LastD = Val(TextBox2.Text)

6 BarsTest = Val(TextBox3.Text)

7 '==由 Data_Source 工作表確定最後日期資料的最後列數===

8 Worksheets("Data_Source").Activate

9 For I = 2 To 5000

10 If Cells(I, 1) >= LastD Then

11 LastD_I = I

12 Exit For

13 End If

14 Next I

15 '==將實證資料讀入 D 陣列與 P 陣列中================


16 For I = LastD_I - BarsTest + 1 To LastD_I

17 D(I - (LastD_I - BarsTest), 1, 1) = Cells(I, 1)

18 D(I - (LastD_I - BarsTest), 2, 1) = Cells(I, 2)

19 D(I - (LastD_I - BarsTest), 3, 1) = Cells(I, 3)

20 D(I - (LastD_I - BarsTest), 4, 1) = Cells(I, 4)

21 D(I - (LastD_I - BarsTest), 5, 1) = Cells(I, 5)

22 D(I - (LastD_I - BarsTest), 6, 1) = Cells(I, 6)

23 D(I - (LastD_I - BarsTest), 7, 1) = Cells(I, 7)

24 P(I - (LastD_I - BarsTest), 1) = Cells(I, 1)

25 P(I - (LastD_I - BarsTest), 2) = Cells(I, 2)

26 P(I - (LastD_I - BarsTest), 3) = Cells(I, 3)

27 P(I - (LastD_I - BarsTest), 4) = Cells(I, 6)

28 Next I

29 End Sub

程式碼說明

第(4)~(6)行程式碼分別將「Max. Bars Back」、「Last Date」、「Bars Test」等變數分別讀入


MaxBarsBack、LastD、BarsTest(此三變數軍為宣告在驅動事件程序之外的全域變數)。

第(9)行程式碼先選取 Data_Source 工作表;然後在第(9)~(14)行間的迴圈中,依據 LastD 變數的設

定逐一比對 Data_Source 工作表第 1 欄之日期,以找出所要分析期間最後日期為第幾筆資料,並紀

錄於 LastD_I 變數中。

第(16)~(28)行間的迴圈,將所欲分析期間的資料(分別為日期(Date)、時間(Time)、開盤價(Open)、

最高價(High)、最低價(Low)、收盤價(Close)與成交量(Volume)等),導入到 D 陣列中。並將日期

(Date)、時間(Time)、開盤價(Open)與收盤價(Close),導入到 P 陣列中。

D 陣列為一三維陣列,用以儲存分析資料,第一至三維分別為資料筆數、資料類別與資料源。資料

類別維度中,分別儲存日期(Date)、時間(Time)、開盤價(Open)、最高價(High)、最低價(Low)、收

盤價(Close)與成交量(Volume)等資料。

P 陣列為一二維陣列,用以儲存分析結果,第一維為資料筆數,第二維資料類別中,分別儲存日期

(Date)、時間(Time)、開盤價(Open)、收盤價(Close)、 對部位、相對部位、部位成本、部位價 、

對損益、獲利/虧損比例、累積損益。

2. 「策略測試」分區。此區域以「執行策略」按鍵驅動回測策略之執行,並將執行結果輸出到分區

中的輸出文字框中。按鍵驅動之程式碼如表 2 所示。

表2
行號 程式碼

1 Private Sub CommandButton2_Click()

2 Dim I, J As Long

3 '==讀入槓桿倍數與每點價 ================

4 Lev_M = Val(TextBox10.Text)

5 Point_V = Val(TextBox11.Text)

6 '==啟始化績效指標參數====================

7 PL_Final = 0: Profit_R = 0: Max_Cost = 0: Max_Gain = 0: Max_Loss = 0: LE_Count = 0:

SE_Count = 0

8 ‘==設定啟始參數並執行策略主流程===========

9 P1 = 6: P2 = 12 ‘設定啟始參數

10 Main ‘執行策略主流程

11 '==績效指標輸出======================

12 TextBox4.Text = Format(PL_Final * Point_V, "###,###,##0")

13 TextBox5.Text = Format(Profit_R, "0.00%")

14 TextBox6.Text = Format(Max_Gain * Point_V, "###,###,##0")

15 TextBox7.Text = Format(Max_Lost * Point_V, "###,###,##0")


16 TextBox8.Text = Str(LE_Count)

17 TextBox9.Text = Str(SE_Count)

18 TextBox12.Text = Format(Max_Cost * Point_V / Lev_M, "###,###,##0")

19 '==寫出資料到 Data 工作表中以資驗證=====

20 Worksheets("Data").Activate

21 For I = 2 To BarsTest + 1

22 Cells(I, 1) = D(I - 1, 1, 1)

23 Cells(I, 2) = D(I - 1, 2, 1)

24 Cells(I, 3) = D(I - 1, 3, 1)

25 Cells(I, 4) = D(I - 1, 4, 1)

26 Cells(I, 5) = D(I - 1, 5, 1)

27 Cells(I, 6) = D(I - 1, 6, 1)

28 Cells(I, 7) = D(I - 1, 7, 1)

29 Next I

30 '寫出資料到 Position 工作表中以資驗證

31 Worksheets("Position").Activate

32 For I = 2 To BarsTest + 1

33 Cells(I, 1) = P(I - 1, 1)
34 Cells(I, 2) = P(I - 1, 2)

35 Cells(I, 3) = P(I - 1, 3)

36 Cells(I, 4) = P(I - 1, 4)

37 Cells(I, 5) = P(I - 1, 5)

38 Cells(I, 6) = P(I - 1, 6)

39 Cells(I, 7) = P(I - 1, 7)

40 Cells(I, 8) = P(I - 1, 8)

41 Cells(I, 9) = P(I - 1, 9)

42 Cells(I, 10) = P(I - 1, 10)

43 Cells(I, 11) = P(I - 1, 11)

44 Next I

45 End Sub

程式碼說明

第(4)與(5)行程式碼讀入槓桿倍數與每點價 分別存入 Lev_M 與 Point_V。

第(7)行程式碼設定啟始化績效指標參數,PL_Final 用以儲存最後損益,Profit_R 用以儲存損益比例,

Max_Cost 用以儲存交易過程最大投入金額(成本),Max_Gain 用以儲存最大獲利,Max_Loss 用以


儲存最大損失,LE_Count 用以儲存多頭進入次數,SE_Count 用以儲存空頭進入次數。

第(9)與(10)行程式碼分別用以設定啟始參數並執行策略主流程(Main),關於策略主流程(Main)程式

碼可參考表 3。

第(12)與(18)行程式碼用以輸出績效指標。其中「投資成本」係由「交易過程最大投入金額

(Max_Cost)*每點價 (Point_V)/槓桿比例(Lev_M)」。

第(20)與(29)行程式碼用以寫出資料到 Data 工作表中以資驗證。

第(31)與(44)行程式碼用以寫出資料到 Position 工作表中以資驗證

表3

行號 程式碼

1 Sub Main()

2 '==回測主流程==============================

3 For B = MaxBarsBack + 1 To BarsTest

4 P(B, 5) = P(B - 1, 5)

5 '趨勢指標 =>策略信號( 6 日與 12 日均線黃金交叉則作多,死亡交叉則作空)


6 If MA(6, B - 2, P1, 1) < MA(6, B - 2, P2, 1) And MA(6, B - 1, P1, 1) > MA(6, B - 1, P2, 1)

Then P(B, 5) = 1

7 If MA(6, B - 2, P1, 1) > MA(6, B - 2, P2, 1) And MA(6, B - 1, P1, 1) < MA(6, B - 1, P2, 1)

Then P(B, 5) = -1

8 '擺盪指標=>策略信號( 心理線值<0.3 則作多,心理線值>0.7 則作空)

9 If Psy(B - 1, 10, 1) < 0.3 Then P(B, 5) = 1

10 If Psy(B - 1, 10, 1) > 0.7 Then P(B, 5) = -1

11 '多頭停損與停利信號=>策略信號(若多頭損失超過 2%則作停損,若獲利超過 4%則作停利)

12 If P(B - 1, 10) > 0 And P(B - 1, 10) < -0.02 Then P(B, 5) = 0 '多頭停損

13 If P(B - 1, 10) > 0 And P(B - 1, 10) > 0.04 Then P(B, 5) = 0 '多頭停利

14 '空頭停損與停利信號=>策略信號(若空頭損失超過 2%則作停損,若獲利超過 4%則作停利)

15 If P(B - 1, 10) < 0 And P(B - 1, 10) > 0.02 Then P(B, 5) = 0 '空頭停損

16 If P(B - 1, 10) < 0 And P(B - 1, 10) < -0.04 Then P(B, 5) = 0 '空頭停利

17 '部位與績效計算

18 P(B, 6) = P(B, 5) - P(B - 1, 5)

19 If P(B, 5) <> 0 Then

20 If P(B - 1, 5) <> P(B, 5) Then

21 P(B, 7) = P(B, 5) * P(B, 3)


22 If P(B - 1, 5) = 0 Then '累計損益並考慮當開與昨收差異

23 PL_Acc = PL_Acc + P(B - 1, 9)

24 Else

25 PL_Acc = PL_Acc + P(B - 1, 9) + (P(B - 1, 5) - P(B, 5)) * (P(B, 3) - P(B - 1, 4))

26 End If

27 If P(B, 5) > 0 Then LE_Count = LE_Count + P(B, 5)

28 If P(B, 5) < 0 Then SE_Count = SE_Count + P(B, 5)

29 Else

30 P(B, 7) = P(B - 1, 7) '計算現金帳戶現

31 End If

32 P(B, 8) = -1 * P(B, 5) * P(B, 4) '計算當收資產帳戶價

33 P(B, 9) = -1 * (P(B, 8) + P(B, 7)) '計算當收投組淨

34 P(B, 10) = P(B, 9) / P(B, 7) '計算獲利率

35 If P(B, 7) > Max_Cost Then Max_Cost = P(B, 7)

36 End If

37 P(B, 11) = PL_Acc

38 If P(B, 11) < Max_Lost Then Max_Lost = P(B, 11)

39 If P(B, 11) > Max_Gain Then Max_Gain = P(B, 11)


40 Next B

41 PL_Final = P(B - 1, 5) * P(B - 1, 4) - P(B - 1, 7) + P(B - 1, 11)

42 If PL_Final < Max_Lost Then Max_Lost = PL_Final

43 If PL_Final > Max_Gain Then Max_Gain = PL_Final

44 Profit_R = (PL_Final / Max_Cost) * Lev_M

45 End Sub

程式碼說明

第(3)~(51)行程式碼為回測主流程迴圈。

第(4)行程式碼用以設定啟始絕對部位(先以前一日絕對部位為啟始值)。

第(6)行程式碼用以實現 6 日(P1 參數)與 12 日(P2 參數)均線黃金交叉信號,若黃金交叉發生,則設

定 對部位為多單 1 口(+1)。其中 MA 函數用以計算均線值,函數程式碼可參考表 4。

第(7)行程式碼用以實現 6 日(P1 參數)與 12 日(P2 參數)均線死亡交叉信號,若死亡交叉發生,則設

定 對部位為空單 1 口(-1)。

第(9)行程式碼用以實現心理線多頭策略,若心理線值<0.3,則設定 對部位為多單 1 口(+1)。其中

Psy 函數用以計算心理線值,函數程式碼可參考表 5。

第(10)行程式碼用以實現心理線空頭策略,若心理線值>0.7,則設定 對部位為空單 1 口(-1)。


第(12)行程式碼用以實現多頭停損,規則為「若多頭損失超過 2%則作停損出場(設定 P(B, 5) =

0)」,其中 P 陣列第二維之第 10 項資料為「獲利/虧損比例」。

第(13)行程式碼用以實現多頭停利,規則為「若多頭獲利超過 4%則作停利出場(設定 P(B, 5) =

0)」。

第(15)行程式碼用以實現空頭停損,規則為「若空頭損失超過 2%則作停損出場(設定 P(B, 5) =

0)」。

第(16)行程式碼用以實現空頭停利,規則為「若空頭獲利超過 4%則作停利出場(設定 P(B, 5) =

0)」。

第(18)~(39)行程式碼用以計算部位與績效。

第(18)行程式碼用以計算「相對部位」。

第(20)~(39)行程式碼計算現金帳戶現 (及操作所需成本)。計算過程先確認「 對部位」有無改變,

若有(即 P(B - 1, 5) <> P(B, 5)條件成立),於第(21)行以「 對部位(P(B, 5))*開盤價(P(B, 3))」算出部

位成本(P(B, 7)),若前日 對部位為 0(P(B - 1, 5) = 0),則以 對損益(P(B - 1, 9))累計入「累積損益」

(PL_Acc)變數中,否則需進一步考慮「當開與昨收差異」(透過「P(B - 1, 5) - P(B, 5)」( 對部位變

量)乘上「當日開盤減去昨日收盤」(P(B, 3) - P(B - 1, 4))。

於第(27)行,若 對部位大於 0,則增加多頭進入次數累計;於第(28)行,若 對部位小於 0,則增

加空頭進入次數累計。

於第(30)行,若「 對部位」無改變(即 P(B - 1, 5) <> P(B, 5)條件不成立),則以昨日成本作為今日部


位成本。

於第(32)、(33)、(34)行,分別計算「當日收盤資產帳戶價 」、「當日收盤投組淨 」、「獲利率」,

並存入 P 陣列中。

於第(35)行,若「部位成本」(P(B, 7))大於目前「最大部位成本」(Max_Cost),則重設「最大部位

成本」(Max_Cost)為「部位成本」(P(B, 7))。

於第(37)行,設定「累積損益」為累積損益量(PL_Acc)。

於第(38)行,若「累積損益」(P(B, 11))小於目前「最大損失」(Max_Lost),則重設「最大損失」

(Max_Lost)為「累積損益」(P(B, 11))。

於第(39)行,若「累積損益」(P(B, 11))大於目前「最大獲利」(Max_Gain),則重設「最大獲利」

(Max_Gain)為「累積損益」(P(B, 11))。

於第(41)行,計算「最後損益」(PL_Final),計算方法為「 對部位」(P(B - 1, 5))*「收盤價」(P(B -

1, 4))減去「部位成本」(P(B - 1, 7))再加上「累積損益」(P(B - 1, 11))。

於第(42)行,若「最後損益」(PL_Final)小於目前「最大損失」(Max_Lost),則重設「最大損失」

(Max_Lost)為「最後損益」(PL_Final)。

於第(43)行,若「最後損益」(PL_Final)大於目前「最大獲利」(Max_Gain),則重設「最大獲利」

(Max_Gain)為「最後損益」(PL_Final)。

於第(39)行,計算「損益比例」(Profit_R),計算方法為最後損益」(PL_Final)除以「最大成本」

(Max_Cost)乘上「槓桿倍數」(Lev_M)。
表 4 計算均線之函數

行號 MA 函數程式碼

1 Function MA(D_Type As Integer, Bar As Long, Para As Integer, D_S As Integer) As Double

2 Dim Sum As Double

3 Sum = 0

4 For I = 1 To Para

5 Sum = Sum + D(Bar - I + 1, D_Type, D_S)

6 Next I

7 If Para > 0 Then MA = Sum / Para

8 End Function

程式碼說明

MA 為計算移動平均函數,第一個參數為欲平均的資料類別(例如 6 為收盤價),第二個參數為開始

回算日,第三個參數表計算的回溯日數,第四個參數為資料源設定。

第(3)行設定累計啟始值。
第(4)~(6)行以迴圈累計欲平均的資料項加總。

第(7)行計算出資料平均並作為函數回傳值。

表 5 計算心理線值之函數

行號 Psy 程式碼

1 Function Psy(Bar As Long, Para As Integer, D_S As Integer) As Double

2 Dim Sum As Double

3 Sum = 0

4 For I = 1 To Para

5 If D(Bar - I + 1, 6, D_S) > D(Bar - I, 6, D_S) Then Sum = Sum + 1

6 Next I

7 If Para > 0 Then Psy = Sum / Para

8 End Function

程式碼說明
PSY 為計算心理線值函數,第一個參數為為開始回算日,第二個參數表計算的回溯日數,第三個

參數為資料源設定。

第(3)行設定累計啟始值。

第(4)~(6)行以迴圈累計上漲天數(以 D(Bar - I + 1, 6, D_S) > D(Bar - I, 6, D_S)條件判斷)於 Sum 變數

中。

第(7)行計算出心理線值,其為上漲天數(Sum)除以回測天數(Para)。

3. 「最佳化」分區。此區用以設定不同策略參數範圍組合,分別測試該參數組合下的策略績效,以

找出策略參數組合範圍內之最佳績效參數組合,並將執行結果輸出到設定之外部 案中。按鍵驅

動之程式碼如表 6 所示。

表6

行號 程式碼

1 Private Sub CommandButton4_Click()


2 Dim I, J As Long

3 Dim FileName As String

4 '==績效指標起始值設定==========

5 PL_Final = 0: Profit_R = 0: Max_Cost = 0: Max_Gain = 0: Max_Loss = 0: LE_Count = 0:

SE_Count = 0

6 FileName = TextBox16.Text

7 '==最佳化區域==========

8 Open ThisWorkbook.Path & "\" & FileName For Output As #1

9 For P1 = 6 To 10 Step 1

10 For P2 = 12 To 20 Step 1

11 MAIN

12 Print #1, "P1="; P1, "P2="; P2, "ROI="; Format(Profit_R, "0.00%")

13 PL_Acc = 0: L_Final = 0: Profit_R = 0: Max_Cost = 0: Max_Gain = 0: Max_Loss = 0:

LE_Count = 0: SE_Count = 0

14 Next P2

15 Next P1

16 Close #1

17 End Sub
程式碼說明

第(5)行作績效指標起始值設定。

第(6)行讀入輸出檔名。第(8)行打開輸出檔案。

第(9)~(14)行以雙層迴圈,以不同短均線(P1 變數)與長均線(P2 變數)的組合,執行 MAIN 程序巨集,

以得到在不同參數組合下的報酬率(Profit_R),並寫出到輸出檔案中。行(13)重設績效指標起始值。

第(16)行關閉輸出檔案。

圖 2 為最佳化輸出結果。

圖2
4. 「交易建議」分區。此區以隔日投資標的之價格變動範圍不同價格跳動單位測試是否符合策略信

號的驅動條件,並作出策略執行建議輸出。按鍵驅動之程式碼如表 7 所示

表7

行號 程式碼

1 Private Sub CommandButton5_Click()

2 Dim I As Single

3 Dim LastC As Single

4 Test_Range = Val(TextBox14.Text)

5 Tune_Step = Val(TextBox15.Text)

6 LastC =D(BarsTest, 6, 1)

7 Test_Lp = LastC * (1 - Test_Range)

8 Test_Up = LastC * (1 + Test_Range)

9 TextBox13.Text = ""

10 '==上漲區間內不同價格之測試==========

11 For I = LastC To Test_Up Step Tune_Step


12 D(BarsTest + 1, 6, 1) = I

13 '測試 6 日均線與 12 日均線黃金交叉

14 If MA(6, BarsTest, 6, 1) < MA(6, BarsTest, 12, 1) And MA(6, BarsTest + 1, 6, 1) > MA(6,

BarsTest + 1, 12, 1) Then

15 If CheckBox1.Value = True Then

16 TextBox13.Text = TextBox13.Text + "LE, +1, " & Str(I - Tune_Step)

17 Else

18 TextBox13.Text = TextBox13.Text + "LE, +1, " & Str(I)

19 End If

20 Exit For

21 End If

22 Next I

23 '==下跌區間內不同價格之測試==========

24 For I = LastC To Test_Lp Step -1 * Tune_Step

25 D(BarsTest + 1, 6, 1) = I

26 '測試 6 日均線與 12 日均線死亡交叉

27 If MA(6, BarsTest, 6, 1) > MA(6, BarsTest, 12, 1) And MA(6, BarsTest + 1, 6, 1) < MA(6,

BarsTest + 1, 12, 1) Then


28 If CheckBox1.Value = True Then

29 TextBox13.Text = TextBox13.Text + "SE, -1, " & Str(I + Tune_Step)

30 Else

41 TextBox13.Text = TextBox13.Text + "SE, -1, " & Str(I)

42 End If

43 Exit For

44 End If

45 Next I

46 End Sub

程式碼說明

第(4)行程式碼讀入標的資產在下一交易日之價格變動範圍。

第(5)行程式碼讀入標的資產之價格跳動單位。

第(6)行程式碼取得最後交易日之收盤價格。

第(7)行程式碼算出下一交易日之標的資產上限價格。

第(8)行程式碼算出下一交易日之標的資產下限價格。

第(11)~(22)行間程式碼,以不同可能上漲價格測試策略條件的前提條件以推算明日價格上漲區間內
是否會觸發策略信號,若是,則輸出到文字框中。在此例中,以 金交叉為例測試多頭買進信號。

行(12)取得此次迴圈之測試價格;行(14)測試黃金交叉條件;特別的是本系統提供「提前交易」選

項(以「提前交易」檢核框(CheckBox1)設定),若是,則於輸出文字框中 TextBox13 提前一檔作提示

(行(16)),若否,則同檔提示(行(18))。(註:前檔提示用於在下一價格跳動單位即會觸發時提前告

知投資人交易,以免同時有許多使用同一策略,以致於策略觸發時,無法成交,當然也有可能價

格反轉,提前交易可能產生誤判)

第(24)~(45)行間程式碼,以不同可能下跌價格測試策略條件的前提條件以推算明日價格下跌區間內

是否會觸發策略信號,若是,則輸出到文字框中。在此例中,以死亡交叉為例測試空頭賣出信號。

原理同第(11)~(22)行間程式碼,不再贅述。

本例仿效 TradeStation 的軟體架構以 VBA 語言寫出一個簡單的回測環境,只要讀入最新報價資

料,本範例亦可在每日交易的基礎上,建議隔日交易進出價格。

本範例系統的重點在於提出一可客製化的架構,而不擬提供完整功能的回測功能。使用者可以

藉由以下方式更改程式碼,以達到「設定分析投資標的與時間」、「自動策略信號」、「自定績效

指標」、「自定最佳化條件」、「自動測試驅動策略」等不同功能。

You might also like