ram 發表於 19-1-28 15:15

不用滴滴咿改寫吸嘉嘉感覺好帥(ADK)

上次把模擬資料用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上可以查看到


加入新的database觀察看看,確實可以選擇這個資料源

不過這個資料源要載入另一個dll不存在,所以出現訊息提示

就把之前接收模擬資訊源用的dll丟進去AB的安裝資料夾內

重開AB,還是有錯誤,原來是我的dll太舊了


不過上面的種種現象說明這個ADK開發的plugin是可以運作的,所以就來研究程式碼吧!{:4_661:}

因為這份ADK的IDE有很多版,想說就在這台AB的測試虛機中下載了小小的DevC

這個不用安裝,硬碟只吃60MB,把專案一開,居然是這樣寫


最重要的是按了編譯就真的出來新的dll了,這也表示值得花時間看下去

這個看下去我看了很久,看了好多天就不用說出來笑了{:4_679:}

重點是我改成功了,看影片


雖然手上收行情的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#帥{:4_186:}

ADK的程式碼像這樣,提到舊版的地方就是我修改過的{:4_624:}//////////////////////////////////////////////////////////////////////////////////////////////////////////
//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 == 'O')
                        g_nStatus = STATUS_CONNECTED;
                else if (cpStatus == '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;
//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;
}




ram 發表於 19-1-29 09:34

kuolung 發表於 19-1-28 20:56
最核心的 getquoteex 的程式沒 show 出來

WOW
kuolung大來出考題了{:4_620:}

不過這比較像是考我的抄襲能力耶

其實像上次用EXCEL作皮看報價,現在換用AB作皮而已

如果會收行情,收行情那塊就能把需要的資料都弄齊也能寫檔不會有什麼問題

也就是收行情本身也是能獨立運作的,AB是平行作業再收一份行情

這樣收行情與存檔的部分才不會因為AB要開開關關而受影響

看kuolung大也是另寫server,AB則透過server收行情與回補這也是相同的概念吧!

模擬資訊源那種行情源原本就有TickWriter可紀錄Tick,

要組成各種cycle的KD或轉成歷史也都沒什麼問題

所以如果存檔就在AB跑的PC上,那GetQuotesEx就是讀檔回補就可以了

很多情況下我只有想要報價而已,歷史對我來說沒什麼意義

在這裡就表現一下程式大概怎麼寫的想法,不然太過累贅就又不好讀了

以網路這份資料 webrtqt.fortunengine.com.tw/rtdata/k-chart/day-2330.txt 存檔作示範

用之前nes大那個CsvReader的dll,抄這份程式碼的作法

弄成很獨立完整加入就可以用的程式碼,像這樣(原本ADK的註解也保留)
typedef long (WINAPI *pWWXfunc_demoTest_LoadFile)(char *TxtFile);
static char WWXfunc_demoTest_LoadFile[] = "demoTest_LoadFile";/* DLL中對應的API名稱 */

typedef long (WINAPI *pWWXfunc_demoTest_ParserCsvLine)(long LineNo);
static char WWXfunc_demoTest_ParserCsvLine[] = "demoTest_ParserCsvLine";/* DLL中對應的API名稱 */

typedef char * (WINAPI *pWWXfunc_demoTest_GetField)(long FieldIndex);
static char WWXfunc_demoTest_GetField[] = "demoTest_GetField";/* DLL中對應的API名稱 */

//啟用指定函數
WWXfunc_DllFuncAdd(demoTest_LoadFile)
WWXfunc_DllFuncAdd(demoTest_ParserCsvLine)
WWXfunc_DllFuncAdd(demoTest_GetField)

#define CsvReadDllLibSource "CsvReader_x32.dll"

HMODULE hmCsvRead = NULL;

//////////////////////////////////////
// GetQuotesEx is a most important function
// for every data plugin
// it is called by AmiBroker everytime AmiBroker
// needs new data for given symbol.
//
// Internally AmiBroker caches response obtained
// from GetQuotes function but you may force it to
// get new data by sending appropriate message to AmiBroker
// main window.
//
//
// When AmiBroker calls GetQuotes function it allocates
// array of quotations of size equal to default number of bars as set in
// File->Database Settings,
// and fills the array with quotes that are already present in the
// database.
// Filled area covers array elements from zero to nLastValid
//
// In your DLL you can update the array with more recent quotes.
// Depending on the data source you can either fill entire array
// from the scratch (Metastock, TC2000, QP2 plugins do that)
// or just add/update a few recent bars and leave the remaining bars
// untouched (eSignal, myTrack, QuoteTracker plugins do that)

// GetQuotesEx function is functional equivalent fo GetQuotes but
// handles new Quotation format with 64 bit date/time stamp and floating point volume/open int
// and new Aux fields
// it also takes pointer to context that is reserved for future use (can be null)
// Called by AmiBroker 5.27 and above
PLUGINAPI int GetQuotesEx( LPCTSTR pszTicker, int nPeriodicity, int nLastValid, int nSize, struct Quotation *pQuotes, GQEContext *pContext)
{
        //AFX_MANAGE_STATE( AfxGetStaticModuleState() );

        if (!hmCsvRead)
        {
                hmCsvRead = LoadLibrary(CsvReadDllLibSource);
                if (hmCsvRead)
                {
                        WWXfunc_DllImport(hmCsvRead, demoTest_LoadFile);
                        WWXfunc_DllImport(hmCsvRead, demoTest_ParserCsvLine);
                        WWXfunc_DllImport(hmCsvRead, demoTest_GetField);
                }
        }//這段載入dll對應api的部分應該寫在Init()那邊就好,放這邊是便於看懂關聯性

        if (strcmp(pszTicker, "2330"))
                return 0;

        if (hmCsvRead)
        {
                if (nLastValid < 0)
                {
                        long LineCount = demoTest_LoadFile("2330.txt.csv");
                        if (nSize > LineCount)
                        {
                                long i;
                                for (i = LineCount; --i > 0; )
                                {
                                        if (demoTest_ParserCsvLine(i) > 7)//IndexDate,Date,Open,High,Low,Close,Volume
                                        {
                                                int year,mon,day;
                                                if (sscanf(demoTest_GetField(1), "%04d/%02d/%02d", &year, &mon, &day) == 3)
                                                {
                                                        nLastValid = atol(demoTest_GetField(0)) - 1;
                                                        //pQuotes[ nLastValid ].DateTime.Date;

                                                        //時間
                                                        pQuotes[ nLastValid ].DateTime.Date                = DAILY_MASK; // EOD
                                                        struct PackedDate &DateTime = pQuotes[ nLastValid ].DateTime.PackDate;
                                                        DateTime.Year                = year;
                                                        DateTime.Month                = mon;
                                                        DateTime.Day                = day;
                                                        DateTime.Hour                = 14;
                                                        DateTime.Minute                = 30;
                                                        DateTime.Second                = 0;
                                                        DateTime.MilliSec        = 0;
                                                        DateTime.MicroSec        = 0;

                                                        //KD
                                                        Set_float(pQuotes[ nLastValid ].Open        , demoTest_GetField(2)        );
                                                        Set_float(pQuotes[ nLastValid ].High        , demoTest_GetField(3)        );
                                                        Set_float(pQuotes[ nLastValid ].Low                , demoTest_GetField(4)        );
                                                        Set_float(pQuotes[ nLastValid ].Price        , demoTest_GetField(5)        );
                                                        //pQuotes[ nLastValid ].OpenInterest;
                                                        Set_float(pQuotes[ nLastValid ].Volume        , demoTest_GetField(6)        );
                                                        //pQuotes[ nLastValid ].AuxData1;
                                                        //pQuotes[ nLastValid ].AuxData2;
                                                }
                                        }
                                }
                                return ++nLastValid;
                        }
                }
        }
        return 0;
}

於AB上出來就是這樣


由DataWindow對照網頁內容

   IndexDateDateOpenHighLowCloseVolume
152017/2/2188188.5184184.5153703
右邊紅色的的量是最後一根(2019-01-28)

   IndexDateDateOpenHighLowCloseVolume
5102019/1/28229.5229.522822925986

其實這裡並不難,如果收行情那裡就直接用ADK的struct Quotation格式保存了資料

那GetQuotesEx可能就也只是以assign為主,頂多考慮各種KD是否要在這裡組出來

就像行情那裡也是,因為收行情那裡直接用ADK的struct RecentInfo保存資料,

所以GetRecentInf簡單成這樣 PLUGINAPI struct RecentInfo * GetRecentInfo( LPCTSTR pszTicker )
{
        if (hmDbfTCdll)
        {
                RecentItemRefer *spRecentRefer = GetRecentItemRefer(pszTicker);
                if (spRecentRefer)
                        return &(spRecentRefer->spRecentItem->sRecentInfo);
        }
        return NULL;
}
考慮線圖Tick進來則大概是這樣的作法,在行情這邊通知AB來重撈資料
PLUGINAPI struct RecentInfo * GetRecentInfo( LPCTSTR pszTicker )
{
        if (bTickNotify)
        {
                bTickNotify = false;
                PostMessage( g_hAmiBrokerWnd, WM_USER_STREAMING_UPDATE, 0, 0 );
        }

        if (hmDbfTCdll)
        {
                RecentItemRefer *spRecentRefer = GetRecentItemRefer(pszTicker);
                if (spRecentRefer)
                        return &(spRecentRefer->spRecentItem->sRecentInfo);
        }

        return NULL;
}

東抄西抄的...這份作業花了我好多時間阿{:4_158:}


flashbibby 發表於 19-1-29 10:49

高手推,不過標題讓我以為這篇文是什麼怪怪的東西{:4_186:}

heavenweaver 發表於 19-1-30 22:51

kuolung 發表於 19-1-30 07:31
我那是出考題啊 我只最近被群益的 skcom.dll 害慘了 想回來用 元大的 想說有人已經寫好了 就不用自己傷腦 ...

我還要感謝您提供了群益的 skcom.dll ,讓我可以去玩 群益 API 2.13.9 C# 實作 。這畫面就是美呀,看起來好專業!


頁: [1]
查看完整版本: 不用滴滴咿改寫吸嘉嘉感覺好帥(ADK)