上次把模擬資料用DDE打到EXCEL上
再用AmiBroker的Plug-In去收雖然用C#寫蠻簡單的(ptid=145893 #8樓)
但是有個EXCEL有時還是感覺很礙眼,還有DDE的欄位設定囉唆又難看
之前也看ADK說VC6和DevC可以用,只是不知怎麼開始
寫程式總是看別人寫出來後覺得簡單,自己要從頭開始寫都覺得很難
終於孤狗到一個可用的ADK資料,看起來就是和以前舊公司所收藏的到的API有關
總是要有個起頭,想說街口轉1000索討試試看無妨,就收到了網頁所描述神奇的C++專案程式源碼了
先把bin的dll丟進AmiBroker的Plugins的資料夾內,有vc,devc,bcb好幾個版本,先試其中一個32位元的
果然順利在AmiBroker上可以查看到
Plugin查看
加入新的database觀察看看,確實可以選擇這個資料源
不過這個資料源要載入另一個dll不存在,所以出現訊息提示
就把之前接收模擬資訊源用的dll丟進去AB的安裝資料夾內
重開AB,還是有錯誤,原來是我的dll太舊了
不支援功能的訊息
原來是dll版本太舊的樣子
不過上面的種種現象說明這個ADK開發的plugin是可以運作的,所以就來研究程式碼吧!
因為這份ADK的IDE有很多版,想說就在這台AB的測試虛機中下載了小小的DevC
這個不用安裝,硬碟只吃60MB,把專案一開,居然是這樣寫
DevC的ADK專案
最重要的是按了編譯就真的出來新的dll了,這也表示值得花時間看下去
這個看下去我看了很久,看了好多天就不用說出來笑了
重點是我改成功了,看影片
AB-RealtimeADK.rar
(38.98 KB, 下載次數: 19, 售價: 1 金錢)
雖然手上收行情的api比較舊還是可以用的啦! 程式裏不要調用新功能就可以了
看一下報價畫面
看別人的程式真的好簡單,註解比程式碼還多全部一起算
ADK的部分不到400行,收行情的部分也300多行而已
如果之前在舊公司有備份到feed server就好了,不管券商行情多難用都可以變簡單
之後我也想試試x64是否也行,又下了DevC5也是可攜版(不用安裝)不過很大要360MB
果然也是順利編譯x86和x64的版本,後來拿去另一邊有VC10的試,也是都不用改
選Win32就邊出x32的版,選x64就編譯出x64的版,把自己編譯的都拿去試過AB全部OK
裡面還有BCB5和BCB6的版,裡面附有一個小工具,只要BCB編譯後用小工具處理過AB就也可以使用
不過我沒有BCB可以試,就不知道是怎樣的情況了
結論是 還蠻好玩的 比接DDE直接方便 比寫C#帥
ADK的程式碼像這樣,提到舊版的地方就是我修改過的- //////////////////////////////////////////////////////////////////////////////////////////////////////////
- //ADK的基本定義與宣告
- #ifndef _USRDLL
- #define _USRDLL /* 注意! 用ADK的 Plugin.h 來寫dll的話要設立此 define , VC專案是會自動設立 */
- #endif
- #include "../Plugin.h" //官方原始檔案, 碰都不用碰就能爽爽用
- //#include "../Plugin_Legacy.h" //若需支援老舊的AmiBroker可透過此定義檔做轉換 ( Plugin.h 裡面直接有include )
- //#include "Data_DbfTCdll2.cpp" // 使用 DbfTCdll2 連接 DTS (HFOCX範例), 想用其他資料來源換掉這行即可
- #include "Data_DbfTCdll2(KGQ).cpp" //因為是舊版的,少了Tick Manager功能,改寫在這個cpp嘗試
- //以下為ADK相關, 這個檔以ADK功能為主
- //-----------------------------------------------------------------------------------------------------------------
- // These are the only two lines you need to change
- #define PLUGIN_NAME "FTW-DbfTCdll2" // "?RT data Plug-in" //"Sample AmiBroker Plug-in"
- #define VENDOR_NAME "ftw.tw" // "Amibroker.com"
- #define PLUGIN_VERSION 10000
- #define PLUGIN_ID PIDCODE( 'F', 'T', 'W', 'D' ) //在AmiBroker的全部Plug-in中需為unique,若需多個相同方式的dll改這裏不一樣即可
- #define THIS_PLUGIN_TYPE PLUGIN_TYPE_DATA //設成為資料源模式( Chart-Data or real-time , Tick資料也是比照Chart-Data要生給AB抓而不是AB自己會累積產生)
- /* // PLUGIN_TYPE Note!!
- 詳見 ADK/adk.html 1.2 INTERFACE ARCHITECTURE
- 基本上 AmiBroker 判斷PLUGIN是否有提供以下介面函式
- GetQuotesEx - 歷史數據(chart-data) ... 會來撈一個array的歷史資料(如KD) (Tick也是要這樣處理)
- GetRecentInfo - 即時數據(real-time) ... 會來撈報價如 trade, bid/ask, days high/low, etc...
- #define PLUGIN_TYPE_AFL 1 //PLUGIN_TYPE_AFL 功能模式吧... 好像只是提供一些功能方便於AmiBroker取值
- For AFL plugins this second initialization phase happens when AFL engine starts
- for a very first time initializing its function table. Then AmiBroker performs the following operations:
- AmiBroker calls SetSiteInterface() function exported by the plug in. The site interface is used later in DLL for calling back various AmiBroker functions (including allocating/freeing memory, reading/writing AFL variables, calling back AFL functions)
- AmiBroker calls Init() function from the plug in DLL that should be used for initializing working variables/allocating extra memory if necessary
- AmiBroker calls GetFunctionTable() from the plug in DLL. In this step the AFL functions provided by the DLL are added to the internal AmiBroker dispatch tables allowing futher calls of these functions.
- Note that this is done only once after loading DLLs in the newer versions of AmiBroker (4.10 and up).
- #define PLUGIN_TYPE_DATA 2 //PLUGIN_TYPE_DATA 資料源模式, 於AmiBroker中會出現在 Data Source 中可以選擇
- 1.需提供 SetTimeBase 回應 AmiBroker 可接受什麼時間間隔等級的資料
- 2.可透過 GetStatus 讓 AmiBroker 知道資料源的連線狀況 且會於介面右下角顯示對應的狀態與訊息
- 3.當於AmiBroker的選單進入 File->Database Settings 選擇此資料源確認後, 就會呼叫 GetQuotesEx
- (a)如果是舊版的AmiBroker則是呼叫 GetQuotes 如不想支援舊版可以不用設計 GetQuotes
- (b)若要支援舊版的AmiBroker可以透過 Plugin_Legacy.h 的定義和新格式做轉換
- (c)於AmiBroker的選單進入 Symbol->New 新建一個商品代碼時確定後也會呼叫 GetQuotesEx
- (d)可透過 ::SendMessage( g_hAmiBrokerWnd, WM_USER_STREAMING_UPDATE, 0, 0 ); 的方式通知AmiBroker呼叫 GetQuotesEx 更新資料
- For Data plugins the second initialization phase happens when given data source is selected
- for the very first time in current AmiBroker session.
- Then AmiBroker just calls Init() function from the plugin that should be used for initializing working variables/allocating extra memory if necessary.
- No other function is called for data plugins at this time.
- #define PLUGIN_TYPE_AFL_AND_DATA 3
- 看就明白這是 AFL + DATA 混合的模式
- #define PLUGIN_TYPE_OPTIMIZER 4
- */
- /* // real-time 注意這幾個
- GetPluginStatus() function is optional and used mostly by real-time plugins to provide visual feedback on current plugin status. It provides a way to display status information in the AmiBroker's status bar. For example implementation of GetPluginStatus() function please check QuoteTracker plugin source.
- The following two functions are implemented only by real-time plugins:
- PLUGINAPI struct RecentInfo * GetRecentInfo( LPCTSTR pszTicker ); // RT plugins only
- PLUGINAPI int GetSymbolLimit( void ); // RT plugins only
- GetRecentInfo() function is exported only by real-time plugins and provides the information about the most recent trade, bid/ask, days high/low, etc (updated by streaming data).
- It is called by AmiBroker's real-time quote window on each window refresh (occurs several times a second). The function takes ticker symbol and returns the pointer to RecentInfo structure described above.
- GetSymbolLimit() function is exported only by real-time plugins.
- It returns the maximum number of streaming symbols that plugin and/or external data source can handle.
- The result of this function is used to limit the number of symbols that are displayed in real-time quote window
- */
- ////////////////////////////////////////
- // Data section
- ////////////////////////////////////////
- static struct PluginInfo oPluginInfo =
- {
- sizeof( struct PluginInfo ),
- THIS_PLUGIN_TYPE,
- PLUGIN_VERSION,
- PLUGIN_ID,
- PLUGIN_NAME,
- VENDOR_NAME,
- 0, // certificate code - set it to zero for private plug-ins
- 527000 // 這裡設計只用新版的 GetQuotesEx 不再用舊的 GetQuotes 所以限制要求最低版本要AmiBroker 5.27以上
- };
- // the site interface for callbacks
- struct SiteInterface gSite;
- enum {
- //用來表示資訊源狀態
- STATUS_WAIT,
- STATUS_CONNECTED,
- STATUS_DISCONNECTED,
- STATUS_SHUTDOWN
- };
- int g_nStatus = STATUS_SHUTDOWN;
- ///////////////////////////////////////////////////////////
- // Basic plug-in interface functions exported by DLL
- ///////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////
- // COMMON EXPORTED FUNCTONS
- //
- // Each AmiBroker plug-in DLL must export the following
- // functions:
- // 1. GetPluginInfo - called when DLL is loaded
- // 2. Init - called when AFL engine is being initialized
- // 3. Release - called when AFL engine is being closed
- PLUGINAPI int GetPluginInfo( struct PluginInfo *pInfo )
- {
- *pInfo = oPluginInfo;
- return TRUE;
- }
- /* // for 設計 PLUGIN_TYPE_DATA 所以不需要這個
- // SiteInterface structure <== 回callAmiBroker的內建函式透過此結構 看.h檔內容 "Plugin.h"
- // defines call-back function pointers
- // the structure is filled with correct
- // pointers by the AmiBroker and passed to DLL via SetSiteInterface() function call
- //
- // SiteInterface is used as a way to call-back AmiBroker built-in functions
- //
- PLUGINAPI int SetSiteInterface( struct SiteInterface *pInterface )
- {
- gSite = *pInterface;
- return TRUE;
- }
- */
- PLUGINAPI int Init(void)
- {
- if (!hmDbfTCdll)
- hmDbfTCdll = LoadLibrary(DbfTCdllLibSource);
- if (hmDbfTCdll)
- {
- WWXfunc_DllImport(hmDbfTCdll, fnDbfTCdll_SelectDataSet);
- WWXfunc_DllImport(hmDbfTCdll, fnDbfTCdll_InitUser);
- WWXfunc_DllImport(hmDbfTCdll, fnDbfTCdll_Start);
- WWXfunc_DllImport(hmDbfTCdll, fnDbfTCdll_Stop);
- WWXfunc_DllImport(hmDbfTCdll, fnDbfTCdll_GetConnectionStatus);
- WWXfunc_DllImport(hmDbfTCdll, fnDbfTCdll_CallBack_Register);
- WWXfunc_DllImport(hmDbfTCdll, fnDbfTCdll_GetCurrTagValue);
- WWXfunc_DllImport(hmDbfTCdll, fnDbfTCdll_GetPrevTagValue);
- WWXfunc_DllImport(hmDbfTCdll, fnDbfTCdll_CreateStringIdMapping);
- WWXfunc_DllImport(hmDbfTCdll, fnDbfTCdll_GetStringId);
- WWXfunc_DllImport(hmDbfTCdll, fnDbfTCdll_CreateItemQuoteMemory);
- WWXfunc_DllImport(hmDbfTCdll, fnDbfTCdll_GetItemQuoteMemory);
- WWXfunc_DllImport(hmDbfTCdll, fnDbfTCdll_GetQueueCount);
- /*
- WWXfunc_DllImport(hmDbfTCdll, fnDbfTCdll_STManCreateGroup);
- WWXfunc_DllImport(hmDbfTCdll, fnDbfTCdll_STManCreateProduct);
- WWXfunc_DllImport(hmDbfTCdll, fnDbfTCdll_STManGetTickHandle);
- WWXfunc_DllImport(hmDbfTCdll, fnDbfTCdll_STManGetTickMemory);
- */ //舊版的沒這個只能先拿掉
- if (fnDbfTCdll_CallBack_Register)
- {
- //CallBack 模式
- fnDbfTCdll_CallBack_Register(TagDataProcessFunction, 1);// 1 - By Tag, 每個商品的每個Tag更新都會呼叫
- fnDbfTCdll_CallBack_Register(ItemProcessFunction, 2);// 2 - By Item, 有更新的商品會呼叫 (傳入之cpVarName,cpNewValue,cpOldValue等參數為NULL)
- /*
- if (fnDbfTCdll_STManCreateGroup)
- {
- unsigned long uGroupIndex = fnDbfTCdll_STManCreateGroup("RecentInfoDataItem", sizeof(RecentInfoDataItem), NULL, 64, 256);
- unsigned long uProductIndex = fnDbfTCdll_STManCreateProduct(uGroupIndex);
- vpQuoteIndexHandle = fnDbfTCdll_STManGetTickHandle(uGroupIndex, uProductIndex);
- if (!vpQuoteIndexHandle)
- MessageBox(0, "Dll file "DbfTCdllLibSource" STMan Err! Memory crash!!", PLUGIN_NAME" Init Error!", MB_OK);
- }
- else
- MessageBox(0, "Dll file "DbfTCdllLibSource" not support STMan", PLUGIN_NAME" Init Error!", MB_OK);
- */ //舊版的沒這個只能先拿掉
- }
- else
- {
- FreeLibrary(hmDbfTCdll);
- hmDbfTCdll = NULL;
- MessageBox(0, "Dll file "DbfTCdllLibSource" load faild!!", PLUGIN_NAME" Init Error!", MB_OK);
- }
- }
- else
- {
- MessageBox(0,
- "Dll file "DbfTCdllLibSource" not found!!\n"
- "請將檔案置於AmiBroker的工作環境資料夾內"
- , PLUGIN_NAME" Init Error!"
- , MB_OK
- );
- }
- if (hmDbfTCdll)
- {
- fnDbfTCdll_InitUser(PLUGIN_NAME); // 直接用PLUGIN_NAME當User,同一資訊源相同User只能一個在線; 可改成用參數提供設定
- fnDbfTCdll_SelectDataSet(caDB_list);
- if (fnDbfTCdll_Start(caDTS_host))
- g_nStatus = STATUS_WAIT;
- }
- return 1; // default implementation does nothing
- };
- PLUGINAPI int Release(void)
- {
- if (hmDbfTCdll)
- fnDbfTCdll_Stop();
- return 1; // default implementation does nothing
- };
- HWND g_hAmiBrokerWnd = NULL;
- /////////////////////////////////
- // Forward declaration of Timer callback function
- //////////////////////////////////
- //VOID CALLBACK OnTimerProc( HWND, UINT, UINT_PTR, DWORD );
- ///////////////////////////////////////
- // Notify function implementation
- //
- // Notify() is called by AmiBroker
- // in the various circumstances including:
- // 1. database is loaded/unloaded
- // 2. right mouse button is clicked in the
- // plugin status area of AmiBroker's status bar.
- //
- // The implementation may provide special handling
- // of such events.
- ///////////////////////////////////////
- PLUGINAPI int Notify(struct PluginNotification *pn)
- {
- //AFX_MANAGE_STATE( AfxGetStaticModuleState() );
- if( g_hAmiBrokerWnd == NULL )
- {
- g_hAmiBrokerWnd = pn->hMainWnd;
- if (pn->nReason & REASON_DATABASE_LOADED)
- {//Amibroker已經準備好接收資料
- //::MessageBox(0, "REASON_DATABASE_LOADED", "STATUS_CONNECTED", MB_OK);
- }
- //if (pn->nReason & REASON_DATABASE_UNLOADED)
- //{
- // ::MessageBox(0, "REASON_DATABASE_UNLOADED", NULL, MB_OK);
- //}
- //if (pn->nReason & REASON_STATUS_RMBCLICK)
- // ::MessageBox(0, "REASON_STATUS_RMBCLICK", NULL, MB_OK);
- }
- return 1;
- }
- ////////////////////////////////////////
- // GetStatus function is called periodically
- // (in on-idle processing) to retrieve the status of the plugin
- // Returned status information (see PluginStatus structure definition)
- // contains numeric status code as well as short and long
- // text descriptions of status.
- //
- // The highest nibble (4-bit part) of nStatus code
- // represents type of status:
- // 0 - OK, 1 - WARNING, 2 - MINOR ERROR, 3 - SEVERE ERROR
- // that translate to color of status area:
- // 0 - green, 1 - yellow, 2 - red, 3 - violet
- PLUGINAPI int GetStatus( struct PluginStatus *status )
- {
- char *cpStatus = "GetConnectionStatus() failed!";
- if (hmDbfTCdll)
- {
- cpStatus = fnDbfTCdll_GetConnectionStatus();
- if (cpStatus[1] == 'O')
- g_nStatus = STATUS_CONNECTED;
- else if (cpStatus[1] == 'X')
- g_nStatus = STATUS_DISCONNECTED;
- else
- g_nStatus = STATUS_WAIT;
- }
- switch( g_nStatus )
- {
- case STATUS_WAIT:
- status->nStatusCode = 0x10000000;
- strcpy( status->szShortMessage, "WAIT" );
- strcpy( status->szLongMessage, cpStatus );
- status->clrStatusColor = RGB( 255, 255, 0 );
- break;
- case STATUS_CONNECTED:
- status->nStatusCode = 0x00000000;
- strcpy( status->szShortMessage, "OK" );
- strcpy( status->szLongMessage, vpQuoteIndexHandle?cpStatus:DbfTCdllLibSource"api too old " );
- status->clrStatusColor = RGB( 0, 255, 0 );
- break;
- case STATUS_DISCONNECTED:
- status->nStatusCode = 0x20000000;
- strcpy( status->szShortMessage, "ERR" );
- strcpy( status->szLongMessage, cpStatus );
- status->clrStatusColor = RGB( 255, 0, 0 );
- break;
- case STATUS_SHUTDOWN:
- status->nStatusCode = 0x30000000;
- strcpy( status->szShortMessage, "DOWN" );
- strcpy( status->szLongMessage, "Connection is shut down.\nThe dll file '"DbfTCdllLibSource"' can't load." );
- status->clrStatusColor = RGB( 192, 0, 192 );
- break;
- default:
- strcpy( status->szShortMessage, "Unkn" );
- strcpy( status->szLongMessage, cpStatus );
- status->clrStatusColor = RGB( 255, 255, 255 );
- break;
- }
- return 1;
- }
- PLUGINAPI int SetTimeBase( int nTimeBase )
- {
- //char txt[128];
- //sprintf(txt, "%d", nTimeBase);
- //::MessageBox(0, "SetTimeBase", txt, MB_OK);
- //return ( nTimeBase >= 60 && nTimeBase <= ( 24 * 60 * 60 ) ) ? 1 : 0; //1分線 ~ 日線
- return ( nTimeBase >= 0 && nTimeBase <= ( 24 * 60 * 60 ) ) ? 1 : 0; // Ticker ~ 日線
- }
- //ADK for RT
- //-----------------------------------------------------------------------------------------------------------------
- ////////////////////////////////////////
- // GetSymbolLimit function is called by AmiBroker
- // to find out the maximum number of real-time streaming symbols
- // that can be displayed in the real-time quote window.
- ///////////////////////////////////////
- // GetSymbolLimit function is optional, used only by real-time plugins
- PLUGINAPI int GetSymbolLimit( void )
- {//告知AmiBroker, 可以向本plugin註冊最多幾個symbol
- if (hmDbfTCdll)
- return 99999;
- return 0;
- }
- // GetRecentInfo function is optional, used only by real-time plugins
- PLUGINAPI struct RecentInfo * GetRecentInfo( LPCTSTR pszTicker )
- {//HFOCX可用的代碼可以看這裏==> http://hfocx.dm.ftw.tw/0025/?Quote=All&xml=1
- if (hmDbfTCdll)
- {
- RecentItemRefer *spRecentRefer = GetRecentItemRefer(pszTicker);
- if (spRecentRefer)
- return &(spRecentRefer->spRecentItem->sRecentInfo);
- }
- return NULL;
- }
- BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
- {
- switch (ul_reason_for_call)
- {
- case DLL_THREAD_ATTACH:
- case DLL_THREAD_DETACH:
- break;
- case DLL_PROCESS_ATTACH:
- break;
- case DLL_PROCESS_DETACH:
- break;
- }
- return TRUE;
- }
複製代碼
|