2012年7月30日 星期一

談談 C#.NET 連結 DDE Server 的設計觀


DDE (Dynamic Data Exchange)?,這似乎已經是微軟過時的一種通訊傳遞的技術了。 但是只要是跑券商提供的看盤交易應用軟體,諸如 永豐 e-leader元大 yeswin日盛 hts 等,都必然有提供 DDE 連結的功能。 探究原因,Excel 肯定是佔最大的因素了,因為一般交易者可以很容易地透過 Excel,抓取看盤軟體正在跳動(Tick)的即時金融商品資訊,在不需要太懂程式設計語法的情況下,也能利用 Excel 強大的統計功能,或者利用簡單的 VBScript 語法,撰寫指標或統計數據等。
先前我就曾經利用 Excel 撰寫過即時的「漲/跌/平 家統計數據」了,詳見:「利用 Excel 實現權值成分的漲跌平家走勢圖」。 不過,目前我正在研究其中關於大盤即時 “量" 的變化,也就是觀察 Top-100 的期貨成份股,在每一分鐘內,統計所有即時跳動(Tick)的成交買價量與賣價量。 所以幾乎每一秒,只要一有跳動,就必須觸發(trigger)統計運算的邏輯,把 100 支以上的權值成份股整個迴圈跑過一次。 不知道是否因為我對 VBScript 不習慣,還是寫法有問題,在 Excel 內的處理效能上還是來得不佳,喔,甚至還曾幾次出現過當掉的現象,而這在即時看盤中,當然是很忌諱的 ; 另外,我也可能想要開發個能同時連多個報價來源 DDE Server 的 “中介(intermediate)" Server,除了可以方便調整想要擷取的資料來源外,還能兼容有 “容錯(fault-tolerance)" 的功能。 反正啊,能具有高度的客製化(customization),以及無限想像的延展性(scalability),更是我想要的,而這些當然就要寫程式自行來去開發擴展囉。
DDE 是個老舊的傳輸技術,從微軟官方的角度,係制訂了 DDEML (Dynamic Data Exchange Management Library) 的規格,並提供給 Developer 最高階的連接方式就是 Windows 32-bit 的 APIs(Application Programming Interfaces),在實際 Windows-32 的作業系統下,是被實作在 “User32.DLL"。 所以,最適合用來開發 DDE-based 的程式語言,當屬可以直接連接 Win-32 APIs 的,諸如 VB6, C++ 等,開發上對於 DDE 的實際連結,會來得容易許多。
anyway, 我還是喜歡利用 .NET C# 來寫程式,最主要只有一個原因,我對它比較熟悉!
而我在一般關於「程式交易討論區」看到有些網友發言,說 .NET 並不支援 DDE! 這句話初看到挺覺得奇怪的,其實正確地來講,應該是說 .NET Framework 並沒有提供 DDEML 的 Wrapper 成為 .NET 元件,所以若要從 .NET 應用程式連結 DDE Server 的話,就必須自行實作呼叫底層(相對於 .NET)的 Win-32 APIs。 一個簡單的流程如下:
  C#/VB .NET Client → .NET DDEML Object(自行撰寫,因為官方沒有提供) → Win-32 DDEML APIs
西方的一個老諺語: “Don’t Reinvent the Wheel (不要重覆再造輪子)。" 那個 .NET DDEML Wrapper 物件,是否要自行撰寫,有待商榷! 若要自行撰寫,那就確定了,是要從造一個新的輪子開始,而且還要很熟悉 DDE 相關的通訊細節才行! 建議啦,這類的 “輪子建設" 工作,先查詢一下 Google,這可是 Google 最大的功用! 發現到,其實真的已經有許多其他行家已經造好可以在 .NET 環境開發的 “DDE 連結 輪子" 了。 包括 美國、中國大陸、甚至日本等都有人在造。 而其中這個: NDde ,看來應該是最為完整的開源 (open-source)專案了。 還包括文件、範例,甚至原始碼等,是可以充分在 .NET 2.0 環境下執行的,下載回來解壓縮放置某一個目錄後 (ex. “\Program Files\Ndde"),把你的 .NET 專案 Add Reference 該目錄內有個 “NDde.DLL" 檔案即可。 這使得寫 C# DDE Client 變得相當簡單,我個人已測過連結 e-leader DDE 來源,完全沒有問題!
要透過 C#/VB .NET 撰寫連結 DDE Server 的 Client 端程式,只要參考 NDde 目錄內的 /Samples 範例檔即可。 另外底下是我自己先暫時寫的一個小小控制程式,主要是測試是否可以確實連結 DDE Server 並取得 Topic/Item 的回傳資料。

TDControl.cs

using System;
using System.Text;

using NDde.Client;

namespace TradeDDE.Control
{
    public class TDControl
    {
        private DdeClient client;

        public void Connect(string service, string topic)
        {
            client = new DdeClient(service, topic);

            try
            {
                // Connect to the server.  It must be running or an exception will be thrown.
                client.Connect();

                //Start Advise
                this.startAdvise(this.client);
            }
            catch (Exception thrown)
            {
                throw new Exception("無法連結 DDE Server \n" + thrown.Message);
             }
        }

        private void startAdvise(DdeClient client)
        {
            // Advise Loop
            client.StartAdvise("VolAmount", 1, true, 60000);
            client.Advise += OnAdvise;
        }

        private static void OnAdvise(object sender, DdeAdviseEventArgs args)
        {
            Console.WriteLine("OnAdvise: " + args.Text);
        }

        public void DisConnect() 
        {
            try
            {
                client.Disconnect();
            }
            catch (Exception thrown)
            {
                throw new Exception("無法離線 DDE Server \n" + thrown.Message);
            }
        }
    }
}
單元測試程式程式碼如下(利用 NUnit Test Framework),利用它可以先取代 UI Form 的執行,而直接觀察在 Console 的執行結果。
TDControlTest.cs

using System;
using System.Text;

using TradeDDE.Control;
using NDde.Client;
using NUnit.Framework;

namespace TradeDDE.Control.Test
{
    [TestFixture]
    public class TDControlTest
    {
        private TDControl control;

        [SetUp]
        protected void SetUp()
        {
            control = new TDControl();
        }

        [Test]
        public void tesConnect()
        {
            try
            {
                control.Connect("myapp", "myservice");
            }
            catch (Exception thrown)
            {
                Console.WriteLine(thrown.Message);
            }
        }
    }
}
順帶提一下 IDE 工具。 對於這類要自行開發小程式的開發工具而言,在 Java 這邊的首選當然就是 Eclipse (或者衍生的 EasyEclipse)。 .NET 這邊呢? Visual Studio .NET 2005/2008 這可是要付費的,而且還不便宜! 不過這兩三年來,微軟真是佛心來著,竟然也提供完全免費的 Visual Studio 2005/2008 Express 系列,雖然是 By 個別語言就要個別下載 (C#/VB .NET 各一套),但也真的夠用了,還是挺好用的呢。
screenshot_vs2008_express_c#
唯有一個美中不足的地方,MS 還是不夠大方,不允許 3rd party 在 vs express 的版本上 “加值",也就是無法撰寫 add-in 的擴充功能程式,"plug-in" 到 vs express 的平台上。 影響最大的是什麼呢? 你無法在 express 的環境內執行 unit-test,諸如下載回來的 NUnit,你只能在 IDE 的環境外,自行透過 NUnit 內建的 GUI 測試工具來測試,而如此就不容易與 IDE 的 DEBUG 機制整合在一起。
倒是也有另外一套非屬於 MS 的 .NET 開源專案— SharpDevelop,也是提供在 .NET 的 IDE 開發工具,完全免費,甚至還整合了 C#/VB/F# .NET 等 OOP 語言,也提供了無限的擴展功能,耗費資源也小,執行效率也僅比 VS Express 稍慢一些些而已,看來前景還挺看好的。 截至目前為止,SharpDevelop 3.0 beta-2 版本(2008/08/22),是完全相容於 .NET Framework 3.5 環境,但是呢,我利用它的 Form Developer 開發 Windows Form 會出問題,雖然該社群網站似乎有提供說明解決方案,不過,總覺得很不安心,拉一拉表單畫面就要提心吊膽出錯,實在沒道理,所以現在我暫時只用它來開啟已開發好如 NDde 的專案。 很不錯的一點是,SharpDevelop 完全相容 VS Express 的 Solution/Project 格式,完全互通! 總的來說,現在我開發個 C#.NET 應用程式,大概會打開至少一個 VS Express 2008,以及一個 SharpDevelop 的 IDE,系統執行效率也不至於受多大影響。
screenshot_sharpdevelop3b2_with_unit_test

沒有留言: