資訊系統/架構/產品‎ > ‎KGQ‎ > ‎GMDS相關文章‎ > ‎GMDS‎ > ‎

Feed-Server行情導入介面與Feed-API

張貼者:2012年8月27日 下午9:25Wei-Xiuang Wang   [ 已更新 2019年1月9日 上午9:55 ]

PatsRaw 與 PatsEmu 程式皆可含有Feed Server服務介面, 透過Feed-API輕鬆完成行情導入系統之工作,
可以獨立運行規劃其他市場行情或介接其他資訊源, 也可用來擴展特定商品(例如指數)或衍伸商品(例如指標),
整合進GMDS架構後, 透過GMDS強大之通訊與架構功能快速相容於原本發展在以GMDS為中台架構的各種應用系統中,
立即享用GMDS簡單便利的介接與開發功能, 同時系統提供可擴展自訂欄位的強悍功能, 應用上之變化與自由超乎想像!

PatsEmu-OBG

這邊以PatsEmu-OBG作介紹, 因為PatsEmu-OBG本身亦是GMDS的一種行情導入規格介面,

PatsEmu-OBG使用 /Source 參數 指定來源 TSHS-TfsRaw, 經由 TcpRDS 收取OBG格式的任意TCP Socket Server來源,
Socket Server透過OBG的通訊格式(五檔/十檔)提供資料, 便可將所需行情導入GMDS架構中

OBG Socket Server <-- TcpRDS <-- TSHS-TfsRaw <-- PatsEmu-OBG

由於PatsEmu-OBG指定 /Source 也是行情導入的功能, 因此搭配具有Feed-Server功能時,
若同時設立 /Source 和 /FeedPort 則是混合模式, 也可僅設立其中一種, 若不設 /Source 則是最基本的 Feed-Server 服務程式,
其它具有Feed-Server功能的PatsEmu與PatsRaw則於啟用 /FeedPort 時, 一律為混合模式運行

Feed-Server

所有PatsEmu(含PatsRaw)可使用 /FeedPort 參數功能 指定服務埠號 啟動 Feed-Server 服務

具有Feed-Server功能的PatsEmu/PatsRaw會含有修改行情之介面功能

Feed 命令
透過Feed命令, 可以針對已存在之商品進行欄位資料修改, 其輸入內容格式完全同Feed-API

SaveFieldList 命令
透過SaveFieldList此命令, 可將現行系統的欄位設定定義輸出到指定的檔案, 檔案為.csv檔格式

FieldList

"1","0","S-----------------------------","Symbol","商品代碼"
"92","0","S-------------------","ExtOriSymbol","原始商品代碼"
"93","0","S---------","ExchangeName","交易所別"
"94","0","S---------","ContractName","契約代碼"
"95","0","S---------------","ContractDate","契約日期"
"96","2","I","Quote Bias","時差"
"97","4","U","Quote Date(Dec)","日期"
"98","4","U","Quote Time(Dec)","時間"
"2","3","U","TPP","TicksPerPoint"
"3","0","S---------","TickSize","TickSize"
"4","4","U","ExpiryDate","到期日"
"5","4","U","LastTradeDate","最後交易日"
"6","0","S-------------------","Open","開盤價"
"8","0","S-------------------","High","最高價"
"10","0","S-------------------","Low","最低價"
"12","0","S-------------------","Close","收盤價"
"13","4","U","OpenInterest","未平倉"
"14","0","S-------------------","Reference","參考價"
"16","4","U","Price Time by GMT","報價時間"
"17","4","U","Tick Time by GMT","明細時間"
"60","4","U","Trade Date From Source","來源交易日期"
"61","4","U","Trade Time From Source","來源成交時間"
"18","0","S-------------------","Bid","買價"
"19","4","U","BidVol","買量"
"20","0","S-------------------","Offer","賣價"
"21","4","U","OfferVol","賣量"
"22","0","S-------------------","Last","現價"
"23","4","U","LastVol","現量"
"25","4","U","RFQ","RFQ Volume"
"27","4","U","TotalVol","總量"
"99","3","U","TickCount","成交筆"
"30","0","S-------------------","LimitUp","漲停價"
"32","0","S-------------------","LimitDown","跌停價"
"34","0","S-------------------","ExecutionUp","ExecutionUp"
"36","0","S-------------------","ExecutionDown","ExecutionDown"
"40","0","S-------------------","ImpliedBid","ImpliedBid"
"41","4","U","ImpliedBidVol","ImpliedBidVol"
"42","0","S-------------------","ImpliedOffer","ImpliedOffer"
"43","4","U","ImpliedOfferVol","ImpliedOfferVol"
"44","0","S-------------------","IndBid","IndBid"
"45","4","U","IndBidVol","IndBidVol"
"46","0","S-------------------","IndOffer","IndOffer"
"47","4","U","IndOfferVol","IndOfferVol"
"50","0","S-------------------","CurrStl","CurrStl"
"51","4","U","CurrStlVol","CurrStlVol"
"52","0","S-------------------","SODStl","SODStl"
"53","4","U","SODStlVol","SODStlVol"
"54","0","S-------------------","NewStl","NewStl"
"55","4","U","NewStlVol","NewStlVol"
"10264","1","U","DepthLimit","行情深度"
"100","0","S-------------------","Bid01","買價01"
"101","4","U","Bid01Vol","買量01"
"102","0","S-------------------","Bid02","買價02"
"103","4","U","Bid02Vol","買量02"
"104","0","S-------------------","Bid03","買價03"
"105","4","U","Bid03Vol","買量03"
"106","0","S-------------------","Bid04","買價04"
"107","4","U","Bid04Vol","買量04"
"108","0","S-------------------","Bid05","買價05"
"109","4","U","Bid05Vol","買量05"
"110","0","S-------------------","Bid06","買價06"
"111","4","U","Bid06Vol","買量06"
"112","0","S-------------------","Bid07","買價07"
"113","4","U","Bid07Vol","買量07"
"114","0","S-------------------","Bid08","買價08"
"115","4","U","Bid08Vol","買量08"
"116","0","S-------------------","Bid09","買價09"
"117","4","U","Bid09Vol","買量09"
"118","0","S-------------------","Bid10","買價10"
"119","4","U","Bid10Vol","買量10"
"200","0","S-------------------","Offer01","賣價01"
"201","4","U","Offer01Vol","賣量01"
"202","0","S-------------------","Offer02","賣價02"
"203","4","U","Offer02Vol","賣量02"
"204","0","S-------------------","Offer03","賣價03"
"205","4","U","Offer03Vol","賣量03"
"206","0","S-------------------","Offer04","賣價04"
"207","4","U","Offer04Vol","賣量04"
"208","0","S-------------------","Offer05","賣價05"
"209","4","U","Offer05Vol","賣量05"
"210","0","S-------------------","Offer06","賣價06"
"211","4","U","Offer06Vol","賣量06"
"212","0","S-------------------","Offer07","賣價07"
"213","4","U","Offer07Vol","賣量07"
"214","0","S-------------------","Offer08","賣價08"
"215","4","U","Offer08Vol","賣量08"
"216","0","S-------------------","Offer09","賣價09"
"217","4","U","Offer09Vol","賣量09"
"218","0","S-------------------","Offer10","賣價10"
"219","4","U","Offer10Vol","賣量10"


欄位定義檔格式
a. 欄位內容不可同時含有半形之單引號( ' )與雙引號 ( " )
b. 欄位內容如果有逗號或單引號,則首尾須以雙引號包起來
c. 欄位內容如果有逗號或雙引號,則首尾須以單引號包起來
d. 每行定一個Tag Field, 各欄欄內容以逗號( , )作分隔, 共須5欄依序為

1. Tag代碼, 例如 123 或 "123" 或 '123' 之設定方式皆可

2. 欄位長度, 依欄位格式設定長度

I: 1~8, 如為1代表數值範圍 -128~127
U: 1~8, 如為1代表數值範圍 0~255
S: 須設0, 實際欄位保留長度則是於欄位格式中填足對應長度

3. 欄位格式

I: 有號整數
U: 無號整數
S: 字串

4. 欄位說明1 (會秀在PatsEmu/PatsEmu的商品資料檢視表中)

5. 欄位說明2 (保留,但須存在)

可修改欄位定義檔擴增所需欄位, 透過 /FieldList 參數 可讓PatsEmu/PatsRaw改以指定的檔案作為欄位定義來源
原已定義之欄位與順序儘可能不作變動, 例如#1 固定是全域性的商品代碼作為唯一的識別Key用不應該被調整,
而10檔買賣#100~#119,#200~#219則是順序上已應用中的程式會透過欄位ID計算檔位所以也不應該被調整

Feed-API

與API PktEvCdll.dll 完全相同, 透過指定Feed-Server之Host後便可進行Data Feed了!
使用API函數
//fnPktEvCdll_SendPacket(char cType, const char *cpMessage, int len, bool bRealPush)
//    cType : 僅允許 0x20 ~ 0x7F , 配合Server端定義之配對設計
//    bRealPush : 是否即時發送, true 立即發送, false 儘可能即時發送
例:
char caData[] = "AAA,92=ABC,93=CME,6=156.50,8=158.00,10=155.80";
fnPktEvCdll_SendPacket('F', caData, strlen(caData) + 1, false);

例中參數說明:
bRealPush : 都設 false 即可
cType : 必須設 'F'
caData : AAA為#1商品代碼,後面為針對此商品,各Tag所想更新的內容, 所設商品若不存在系統自動新增
len : caData長度, 須含ZE

API範例程式

產生虛擬資料的程式範例


time_t    currentTime = 0;
struct tm *TM = NULL;
bool bIsConnectionOK = false;
void WWXWinDLLAPI MessageProcessFunction(char cType, const char *cpMessage, int len)
{
    static char buf[8192];
    if (len < sizeof(buf))
    {
        memcpy(buf, cpMessage, len);
        buf[len] = 0;//為了安全,放個ZE,預防資料不是ZE-String
    }
    switch (cType)
    {
        case 'M':
            if ((len == 7) && (strcmp(buf, "Hello~") == 0))
            {
                printf("\r                                                            \r");
                printf("Connection Start\n");
                //這裡設計初連上線(包括有斷線重連)後的一些重置動作
                {//模擬個資料發送
                    static unsigned long uCount = 0; //每次斷線再連會變成一個新商品
                    char caData[4096];
                    sprintf(caData, "ConnectUp(%lu),97=%d%02d%02d,98=%d", ++uCount, (TM->tm_year + 1900), (TM->tm_mon + 1), TM->tm_mday, ((TM->tm_hour * 3600) + (TM->tm_min * 60) + TM->tm_sec));
                    fnPktEvCdll_SendPacket('F', caData, strlen(caData) + 1, false);
                }
                break;
            }
        default:
            printf("\r                                                            \r");
            printf("[%c]len=%d,%s     \n", cType, len, buf);
            break;
    }
}

int main(int argc, char* argv[])
{
//................
        {

            fnPktEvCdll_SetupAppName("TestFeed");
            fnPktEvCdll_Start(caHost, MessageProcessFunction);    //啟動連線
            {
                unsigned long count = 0;
                char *cpConnectionStatus = fnPktEvCdll_GetConnectionStatus();

                //while (count < 1000) //約運行100秒自動結束,Console程式可以按<Ctrl>+'C'中斷
                while (1)
                {
                    time(&currentTime);
                    TM = localtime(&currentTime);
                    cpConnectionStatus = fnPktEvCdll_GetConnectionStatus();
                    bIsConnectionOK = (cpConnectionStatus[1] == 'O');
                    if (!bIsConnectionOK) //未正確連線的狀態才顯示
                        printf("\r%u %s\r", ++count, cpConnectionStatus);
                    else //if (bIsConnectionOK)
                    {//Feed測試, 模擬一些資料來丟
                        static unsigned long uCount = 0;//計次,單純有個資料看
                        char caData[4096];
                        sprintf(caData, "LastUpdate,92=Send%02dTestCount", TM->tm_sec);
                        fnPktEvCdll_SendPacket('F', caData, strlen(caData) + 1, false);
                        //"Send%02dTestCount"用秒產生不同商品的模擬資料(最多會有60個)
                        {//模擬買賣價
                            sprintf(caData, "Send%02dTestCount,18=1.%06d,19=%u", TM->tm_sec, (GetTickCount() % 1000) - 3, GetTickCount() % 29);
                            fnPktEvCdll_SendPacket('F', caData, strlen(caData) + 1, false);
                            sprintf(caData, "Send%02dTestCount,20=1.%06d,21=%u", TM->tm_sec, (GetTickCount() % 1000) + 3, GetTickCount() % 31);
                            fnPktEvCdll_SendPacket('F', caData, strlen(caData) + 1, false);
                        }
                        sprintf(caData, "Send%02dTestCount,13=%lu,22=1.%06d,61=%d%02d%02d%02d,27=%u", TM->tm_sec, ++uCount, GetTickCount() % 10000, TM->tm_hour, TM->tm_min, TM->tm_sec, (GetTickCount() % 1000), GetTickCount() % 1000000);
                        fnPktEvCdll_SendPacket('F', caData, strlen(caData) + 1, false);
                    }

                    Sleep(100);//短暫釋放資源, 由於是CallBack模式這裡並沒有須處理的部份, 只是不讓程式結束而已
                }
            }
            fnPktEvCdll_Stop();
        }
//................
}



範例程式產生之PatsEmu內容


Multi-DB功能

Server設定參見 GroupMap設定 API指定功能參見 2014-07-09

特別欄位說明


#97, #60
十進制數字日期 YYYYMMDD (前端連續0之位數會省略)

#98
十進制數字時間, hhmmss (前端連續0之位數會省略)

#61
十進制數字時間, hhmmssnnn (前端連續0之位數會省略)

#16, #17
日期時間, Unix time(or POSIX time, UTC), 數值內容為自1970-01-01 00:00:00開始所對應的日期時間之總秒數

#96
Bias時區設定, 當Feed API提供 #93 #94 的資料時, 系統會透過Bias設定檔規則, 自動提供該商品所需之 #96 數據內容
因此 #96 應避免透過Feed API來提供數據, 而是於系統上透過Bias設定檔來提供規則 (參考 時區表 , Bias設定檔說明 )
此欄位的提供能透過合適的偏差值設定, 當行情運作時能讓商品有對應交易日(#97)可以參考

#97, #98, #16
此三欄位於任何資料更新時, 系統會同時連帶更新
#97, #98 為依據更新當時之系統時間與 #96 之Bias設定換算所得之結果, 因此 #96必須在所有數據需求之前先提供

#27 TotalVol
當發送此欄位異動時, 系統會連帶更新 #23, #97, #98, #16, #17
如果想另外提供 #23 資訊作取代時, 若發送訊息時將 #23 置於 #27 之前將被系統之計算結果給覆蓋, 可將 #23 置於 #27 之後則能正確取代為所提供之數據

應用實例

市面上投顧最常用的行情系統(證期權股匯市全市場即時行情) 透過Feed-API很容易就可完成轉換...參考Feed-API(AGVS)

延伸架構

延伸應用


註解