關於 Excel DDE Tick 資料變更事件的處理

透過看盤軟體來接收即時性的報價資料,最便利的工具莫過於 Excel 了。 諸多交易人幾乎是利用 Excel 透過 DDE 連結方式來取得報價資料並自行撰寫程式 (如 VBA) 來分析處理。而事實上, DDE 是一種老舊的傳輸規格 (Microsoft 已制定了 RTD 規格, Real Time Data, 用來取代並不穩定的 DDE 傳輸,但國內看盤軟體似乎並未支援),不僅 .NET Framework 沒有直接支援,要處理即時性的 DDE 接收,有些實做的地方還挺麻煩的。

舉個例,在 Excel 的工作表內,設定某一個 CELL 的公式 (formula)欄為:

CATDDE|'STOCK2330  '!CurPrice

代表的就是會接受來自看盤軟體 (本身即為 DDE Server)所傳送過來的資料,並且每次會即時更新跳動 (Tick)的資料。

稍微懂一些程式撰寫的交易人都知道,當某個 CELL 的資料發生變動時,只要寫好所對應的事件處理 (Event Handle)方法,就可以處理變動欄位的資料了。 Excel 預設所提供關於 CELL 資料變動處理的事件程序為 "WorkSheet_Change()",如下:

Private Sub Worksheet_Change(ByVal Target As  Range) 
         'do something
End Sub 

理想上很簡單,不是嗎? 問題是,如果 CELL 的欄位是屬於公式 (formula)型態的 (DDE 連結即為其中之一),那麼就無法利用上述的事件程序來處理。 因公式計算後所變動的資料,並不算在資料變動的事件內;屬於公式計算後所變動的資料,是需要利用 "Work_Calculate()" 程序,如下:

Private Sub Worksheet_Calculate() 
         'do something
End Sub 

老實說,我搞不懂 MS 幹嘛這樣分,我也不想搞懂,只要能達成我所想要的功能即可。 但真正的問題來了… 比較上述的程序,哪裡不一樣? _Change Event 有參數,反之 _Calculate Event 則沒有!

這可是相當相當的麻煩了! 因為透過第一個程序內的參數 (Range Object),可以很方便地得知是哪一個 CELL 的資料變動,但第二個程式則否。 所以若要知道在某一個工作表是哪一個 CELL 的資料變動,就必須寫 FOR LOOP 迴圈,一個一個來判斷是哪一個 CELL 欄位的資料變動。 我幾乎看到許多寫判斷 Tick 資料變動的程式,都是以該事件程序 (Worksheet_Calculate) 來處理。 當然,欄位不多還 OK,但是若是像我這樣,一個工作表是撈約 100 檔的權值成份股、約有 500 ~ 800 個 DDE 欄位的話,那肯定效能會大出問題,連動當然會影響到 Tick 資料的正確性了。 整整爬文了一整個早上,總算才找到真正正確處理 DDE CELL 型態的事件程序了。 不應該使用 "WorkSheet_Calculate()"、而是採用 "SetLinkOnData()" 程序才是。

參考 MSDN 對該程序 (SetLinkOnData Method) 的說明:
"Sets the name of a procedure that runs whenever a DDE link is updated."


如何用? 比想像還要麻煩。 你必須先登記所想要處理含 DDE Link CELL 的字串,然後再委託交給事先寫好的 VBA 巨集 (Marco) 來處理。如下:

ActiveWorkbook.SetLinkOnData _
    "CATDDE|'STOCK2330  '!Volume", _
    "my_Link_Update_Macro"

第一個參數是 DDE Link 的字串":第二個參數就是巨集的名稱。

記得,是要把值得關注的 DDE CELL 一個一個利用該程序來登記,若是要全部的 CELL 都要登記,那麼參考如下的寫法 (refer. DDE Link Change Event。):

' Obtain an array for the links to Excel workbooks
' in the active workbook.
Links = ActiveWorkbook.LinkSources(xlOLELinks)
' If the Links array is not empty, then open each
' linked workbook. If the array is empty, then
' display an error message.
If Not IsEmpty(Links) Then
  For I = 1 To Ubound(Links)
  ActiveWorkbook.SetLinkOnData Links(i), "LinkChange"
Next I
Else
  MsgBox "This workbook does not contain any links " & _
             "to other workbooks"
End If
End Sub

Sub LinkChange()
  MsgBox "linked"
End Sub

只不過這樣的話,就與使用 "Worksheet_Change()" 幾乎沒什麼兩樣了。

若都只是使用 VBA 來撰寫程式的話那也還好,還不至於太麻煩,而若是採用 Excel + C#.NET 呢? 像我現在就是利用 C#.NET 程式來動態載入 (import)某一個 CSV 檔案,內含了所需要處理的權值成份股、代碼、權重等 (每一次重新會載入,因為這些資料,例如權重常會變動),並 "餵" 到 Excel 的工作表中來展現並處理。 使用 C#.NET 對我而言比用 VBA 簡單而且方便多了,而且也相當容易除錯 (DEBUG),並且處理效能會好上很多。 但是上述那個 "SetLinkOnData()" 程序中的第二個參數指定,截至目前為止,絕對是必須使用巨集 (Macro)的方式來處理方可! 無法在此宣告使用 C# 某一個 Class 的 Method,真的相當麻煩! (是有一種方法,透過該 Macro,再回頭呼叫 C#,但似乎相當難搞)

唉,所以我現在的作法就是,利用 C# 動態載入 CSV 檔案至 Excel 的工作表,並可接受即時的 DDE 報價來源; 而後當某一檔股票的成交量變動時,(這一段就是利用 SetLinkOnData() 來處理,然後再比對是哪一列 (Row)所在的股票成交量發生變動) 再利用自行所撰寫的巨集程式,來寫入到如 Access or SqlLite 的資料庫內;再回頭利用 C# 每隔一分鐘去資料庫撈出資料來統計彙整,並展在 Excel 的工作表。

算是有些畸形的作法,很無奈,這也算是權宜之計,一切都不得已受限於目前實做技術的障礙而妥協的一種作法。 反正,能建立起所屬於自己的交易模型才是最重要的!

文章導覽

   

共有 31 則迴響

  1. 你好,我試著建立您說的方式,但出現下面問題:
    1) 我的DDE接收資料正常
    2) 每當DDE資料變動,我就會出現一次下面錯誤訊息
    無法執行巨集”XXXXXXXXX”。該巨集可能無法在此活頁簿中使用,或者已停用所有巨集”
    3) 我在想很有可能是權限問題?我是Excel 2007,我看過巨集的security設定,能開的我都開了

    請問您有遇過這問題嗎?謝謝。

  2. 小弟想問一個問題
    在excel欄位裡打上”=CATDDE|’STOCK2330 ‘!CurPrice” 即顯示台積電的目前成交價
    那如果小弟要抓取股票代號2330的名稱時,應該使用哪個英文字母呢?

    “=CATDDE|’STOCK6153 ‘!CurPrice
    也就是,上面的CurPrice要變成什麼東西,在excel裡才會直接顯示”台積電”呢?
    感謝!!~

  3. 1:一台電腦為SERVER 用EXCEL接期貨商五種商品的DDE 其EXCEL內容如下
    名稱 代碼 昨收 開盤 最高 最低 成交 總量
    台指近 WTX& 7000 7500 7700 7200 7350 200000



    共五種商品
    2:其餘五台為CLIENT 分別各接一種商品的dde
    請教
    1: 如何連成區域網路
    2: SERVER端的EXCEL DDE ( 台指近 WTX& 7000 7500 7700 7200 7350 200000 ) 只要固定傳給 CLIENT端 即可
    專此拜託賜教 謝謝

  4. 請問一下版大,請問一下能否回應我上篇回覆者Frank的連絡email給我呢?
    因為我正在網路上找尋VC支援dde的sample code,也找了好久都沒進展,
    所以能幫忙一下嗎?謝謝囉!

    • Hi,
      1. 其他讀者的 Email 我不方便擅自給人。
      2. 如你有相關的問題,建議你可以至「程式交易聚寶盆」論壇提問討論,比較容易得到解答的。

  5. 請教!
    我依照上述方式,將這串程式貼在EXCEL VBA的macro1之前,如下

    Option Explicit
    ActiveWorkbook.SetLinkOnData “MMSDDE|FUSA!’HSI&.404′”, “my_Link_Update_Macro”

    Sub Macro1()

    End Sub

    sub my_Link_Update_Macro()

    End sub

    tick跳動時,會出現這樣的錯誤:
    編譯錯誤:不正確的外部程序(”MMSDDE|FUSA!’HSI&.404′”被VBA反白)
    我試著去切別的DDE公式,或是將Active~這串貼到別的地方,仍然出現相同的錯誤
    請教這需要如何處理?

  6. 我是以VC2005來開發

    我目前遇到一個問題

    DDE連線的格式 如下
    Server|topic!item

    當我使用 康和e閃電當作資料來源時 很正常 可以取得資料

    可是 當我使用康和全都賺當資料來源時
    MMSDDE|FUSA!’WTX&.101′

    他的item 出現了這個單引號 ‘ ‘
    這是代表了甚麼呢?
    我無法接收其資料
    富邦eo1也讓我遇到了相同的問題

  7. I find that my windows xp prof computer does not contain the file of
    nddeagnt.exe. Would windows xp support DDE Communication??

    Is it the reason that DDe Client on another computer cannot communicate with DDE Server which are build by C #?? As I find that this file is critical to
    start conversation between client and server in dde network.

    When excel client and DDE Server are in the same computer, they can communicate.
    But when excel client and DDE Server are on another computer, they cannot communicate even after DDE server on windows XP has been DDE Share by DDEShare.exe of assigning sharename and trust permission.

    I have tried NDDE C# DDE Client also. The result is the same.
    In the excel, I type:

    =’\\machinename\NDDE$’|’myapp$’!Number1

    Where myapp$ is the share name with myapp as application name.

    Please help!!!

    • 唉 Kitty= Ah Hing:

      你可真有心。 你發問寫的問題的時間,早已經可以在 Msdn 查到的,不是嗎?

      不同的電腦,要透過 DDE 傳輸,這就成為了 Network DDE 的傳輸了。

      1. 那個 NDDE Package 應該是沒有支援 Netowork DDE 的。
      2. 你自己需要實現 (implement) Network DDE 協定(protocol) at Client/Server 端均要。
      3. Netowork DDE 規格,不建議實做,MS 好像已經放棄支援該規格了。

  8. If there is a DDE Server C#, How can excel act as DDE Client to connect to DDE Server??
    Such as browsing C# DDE Server Windows Form Application EXE File?? HOW?? Or I am something wrong??

    Similar to the link below:
    http://support.microsoft.com/kb/181946

    How can the following translate in excel working??
    Private Sub cmdConnect_Click()
    txtData.linkMode = vbLinkNone
    txtData.linkTopic = “\\\NDDE$|DDETEST$
    txtData.LinkItem = “Text1”
    txtData.LinkMode = vbLinkManual
    txtData.LinkRequest
    End Sub

    • Ndde 這個 OpenSource Package 已經都有包括 Client/Server 的範例。 照其實現一個簡單的雛型,不可能會有問題的。 有問題的仍是在於對 How-to 的搜尋能力不足。

  9. Dear KenMing,

    你好! 我有些問題想請教你.我有一個與你類似的Program.

    在DDE Server, 是C# NDde Windows Form Application.在表單上,有二個Labels with random numbers. 它們是侮秒刷新一次.

    在DDe Client, 是Excel. 在Sheet1 上, 有二個Cells. 它們是聯繫Server Forms 的Labels. 如果Label number in server 刷新, Cell in Excel 都會刷新.

    Questions:
    (1) 有沒有C# NDde DDE Server 與我情況類似的Sample Code??
    (2) 如何在Client Excel 設定和VBA Sample Code??

    Any Instructions??

    Please help!!

    • Hi Ah Hing:
      我已在 Msn 告訴你,作為一個 Programmer,要具備的是 Coding 的基本常識與找 How-how 的能力。 你的問題不在於 如何實做 DDE,而是在於欠缺上述兩者的基本功夫。

  10. Dear KenMing,

    I have the project to do similar to your case.
    In DDE Server, I will use C# windows form application with NDde. It will have 2 labels with random numbers refresh every second.

    In Client, it is excel with two cells showing value from the 2 labels number in the server and keep refresh when it change in the server.

    I have the following questions:
    (1) Any sample code in the server C# NDde??
    (2) How to setup in the excel client??

    Please help!!

  11. 大大不好意思,再問一個問題,
    SetLinkOnData 是否有類似 Application.EnableEvents = True or False 的功能,
    如此可以確保被觸發的巨集跑完後, SetLinkOnData才會再次被觸發?
    Thanks.

    • Hello~

      我還是建議要查閱 MSDN 對該程序的解釋喔。
      我自己被這種畸形的作法很不能接受,現在又改回使用 C#.NET 了。 !^^

  12. 感謝大大分享,
    有個問題想請問大大,
    當SetLinkOnData被驅動執行其他巨集時, 當該巨集尚未執行完成時,
    若另一SetLinkOnData又被變更而必須執行該巨集時,
    兩者會不會衝突? or 該如何確保兩者都被執行, or 第二個觸發可以被取消?
    thanks.
    oskwu

  13. Kenming
    I subscribe AAstock for live stock quotes. How can I capture the stock data and feed it in the Excel spreadsheet?
    Is there any source I could buy this application?

    Thanks help
    lkj

  14. 版主您好:
    小弟是新股民,在找知識時找到您這網頁,覺得我的問題應可向您求得解答。
    我要如何把excel透過dde方式向看盤軟體(我用的是新壽証istock)取得的資料每個tick每個tick往下填入儲存格呢?(若能另開新sheet填入更好)
    感激不盡

  15. 請問您為何不用C#直接抓DDE的報價進資料庫,而要用EXCEL抓呢?您上次做的範例程式相當好用阿?您那篇”關於股票 Tick 跳動時單量顏色的判斷原則 (含程式碼片段)“也是用C#寫的,請問您為何後來會想改用EXCEL呢?有什麼比較特殊的考量嗎?

    我利用您的C#程式為藍本,把以前用VB6、EXCEL寫的DDE程式都改版了,效能好非常多,個人非常感恩,覺得您真是佛心來的。其中有一支的目的和您之前的計畫有些雷同,都是在統計個股的內外盤撮合量。不過領先的效果還有待提升,其行為和2秒大盤差不多;對於力道的掌握也不好,向上20點和向下100點看起來一樣(冏)。可能要在加權的參數上下點功夫吧。若有機會或可交流一下彼此的想法,說不定會有新的靈感出現也不一定。

    感恩。

    • 相當無奈 🙁

      我發現當我建了約有 100 個 Topic 吧? DDE Connection 在程式執行期間會莫名奇妙消失到只剩最後一條建立的連線。 而且程式完全沒有顯示任何錯誤訊息。

      我 Debug 許久,確定不是我自己撰寫程式的問題,應該主要是出現在 NDde 這個 Package 上,難道您沒有這個問題嗎?

      方便的話,是否可以 Email 您的 Source Code 呢? 難道是我有些茫點? 問題找了很久最終才不得已放棄的。 🙁

      P.S. 可以的話,您可以 Msn 聯絡我。
      kenming.wang(at)msa.hinet.net (at 請改為 @)

  16. 謝謝版主您這麼快的回覆
    剛剛小弟是路過
    結果發現您這裡真的經營的很好
    小弟以後會常來學習的
    謝謝您

  17. 版主您好
    對於DDE傳輸資料到看盤軟體的問題
    小弟真的有無限的無奈

    例如今天台指期的成交量為112875(全都賺)
    但資料傳到小弟的看盤軟體 AmiBroker 後
    小弟將分線300分鐘顯示的量全部加總才只有48474
    也就是loss掉了超過50%
    成交量流失那麼多
    您說這資料還有參考價值嗎?

    以上的問題
    不知您所提到的方法能否解決
    懇請您解惑
    小弟已經無奈很久了
    感激不盡

    • 這狀況未來會更嚴重~
      期交所已經準備將在進一步提升期貨報價的即時性..也就是tick會來的更多…
      所以找尋新的報價方式.將勢在必行~

發佈回覆給「oskwu」的留言 取消回覆

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *