本帖最後由 ram 於 18-8-1 15:44 編輯
凡是進入到需要I/O的階段,使用結構總是少不了的必備技能
而不管是通訊,檔案存取,API調用...都算是I/O
上次令我嚇傻的那個QM化作C#長這樣,只有2行
- public static extern IntPtr dllCreateItemQuoteMemory(string DBName, string cpItemName, IntPtr vpStructData, int iStructSize);
- public static extern IntPtr dllGetItemQuoteMemory(string DBName, string cpItemName);
複製代碼 原始的API說明是這樣
- //--------------------------------------------------------------------------------------------------------
- /* Quote-Manager 功能 */ //須有支援的API版本才提供
- //fnDbfTCdll_CreateItemQuoteMemory ==> 產生一個商品所需的記憶體結構對應空間
- // vpStructData : 可放好預設值,作為初值內容
- typedef DBFTCDLL_API void * (DBFTCDLLAPI *pWWXfunc_fnDbfTCdll_CreateItemQuoteMemory)(const char *cpDBName, const char *cpItemName, const void *vpStructData, int iStructSize);
- static char WWXfunc_fnDbfTCdll_CreateItemQuoteMemory[] = "_fnDbfTCdll_CreateItemQuoteMemory@16";//DLL中對應的API名稱
- //fnDbfTCdll_GetItemQuoteMemory ==> 取得商品記憶體結構對應空間
- typedef DBFTCDLL_API void * (DBFTCDLLAPI *pWWXfunc_fnDbfTCdll_GetItemQuoteMemory)(const char *cpDBName, const char *cpItemName);
- static char WWXfunc_fnDbfTCdll_GetItemQuoteMemory[] = "_fnDbfTCdll_GetItemQuoteMemory@8";//DLL中對應的API名稱
複製代碼
所以上次娶回的西夏婆可以這樣打扮
首先設計結構,就是自己想,需要怎樣的一筆紀錄來作資料保存
估阿估阿,擬下了這樣的內容,這裏就不收治裝費了- [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
- public struct PriceField20
- {//固定大小為20 bytes的價位資料空間,為用於像是有小數點的市場選擇使用string以便忠於源汁源味
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
- public string data;
- }
- [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
- public struct DataField32
- {//固定大小為32 bytes的資料空間
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
- public string data;
- }
- [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
- public struct PQdataField
- {//便於如買賣價量成對的設計
- public PriceField20 price;
- public Int32 qty;
- }
- [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
- public struct KDdataField
- {//便於KD的應用設計
- public Int32 timeKey;
- public Int64 Volume;
- public PriceField20 Refer;//參考價
- public PriceField20 Open;//開
- public PriceField20 High;//高
- public PriceField20 Low;//低
- public PriceField20 Close;//收
- }
- [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
- public struct ItemDatas
- {
- public DataField32 Symbol;//存放來源的代碼
- public DataField32 MySymbol;//自己要用的命名(可於第一次產生時依自己需求設計對應,例如下單的代碼)
- public Int64 Volume;//總量
- public PQdataField Last;//最新成交價和單量
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
- public PriceField20[] aPrice;//可放多個(這裡是設20)價位資料,例如 參考價,開,高,低 ...
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
- public PQdataField[] aBestBuy;//最佳10檔買價量
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
- public PQdataField[] aBestSell;//最佳10檔賣價量
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
- public KDdataField[] aKD_Day;//可放最近10日的日線資料
- //[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1440)]
- //public KDdataField[] aKD_Min;//可放一日的分線資料
- public ItemDatas(string symbol) //建構,用於產生第一次的C#實體空間結構
- {
- Symbol.data = symbol;
- MySymbol.data = "";
- Volume = 0;
- Last.price.data = "";
- Last.qty = 0;
- //array的部分要比照前面的規劃new出所需的大小
- aPrice = new PriceField20[20];
- aBestBuy = new PQdataField[10];
- aBestSell = new PQdataField[10];
- aKD_Day = new KDdataField[10];
- //aKD_Min = new KDdataField[1440];
- }
- }
複製代碼
再來有一個重點,腰要束緊才好看
- // Initialize unmanged memory to hold the struct.
- public static ItemDatas sItemDatas = new ItemDatas("(null)");//C#中為了SizeOf還是要建一個固定的比較方便
- public static IntPtr pItemDatas = Marshal.AllocHGlobal(Marshal.SizeOf(sItemDatas));//可便於指標方式的操作(這個可以不用)
複製代碼
然後就看心情上下其手了,把上次要打DDE資料那邊這樣加料
- public static void ItemProcessCallback(string DBName, string VarName, string Symbol, string NewValue, string OldValue)
- {
- DataCounting++;//程式啟動後資料更新次數
- IntPtr PtrItem = dllGetItemQuoteMemory(DBName, Symbol);
- if (PtrItem == IntPtr.Zero) //if (PtrItem.ToPointer() == null)
- {//尚未存在,建立
- PtrItem = dllCreateItemQuoteMemory(DBName, Symbol, pItemDatas, Marshal.SizeOf(sItemDatas));//這裡pItemDatas不可以用null
- //PtrItem = dllCreateItemQuoteMemory(DBName, Symbol, IntPtr.Zero, Marshal.SizeOf(sItemDatas));
- if (PtrItem != IntPtr.Zero) //if (PtrItem.ToPointer() != null)
- {
- ItemDatas s = new ItemDatas(Symbol);
- s.aPrice[0].data = dllReturnString(dllGetCurrTagValue("422"));//Refer,昨收
- s.aPrice[1].data = dllReturnString(dllGetCurrTagValue("130"));//Open
- s.aPrice[2].data = dllReturnString(dllGetCurrTagValue("131"));//High
- s.aPrice[3].data = dllReturnString(dllGetCurrTagValue("132"));//Low
- //s.aPrice[4].data = dllReturnString(dllGetCurrTagValue("121"));//Last/trade
- s.Volume = Convert.ToInt64(dllReturnString(dllGetCurrTagValue("133")), 10);//Volume
- //... 這裡可以設計載入日線資料 ....
- // Copy the struct to unmanaged memory.
- Marshal.StructureToPtr(s, PtrItem, false);
- }
- }
- else
- {
- ItemDatas s = (ItemDatas)Marshal.PtrToStructure(PtrItem, typeof(ItemDatas));//調出商品當前資料結構內容
- Int64 v = Convert.ToInt64(dllReturnString(dllGetCurrTagValue("133")), 10);//Volume
- if (v != s.Volume)
- {//有Tick
- if (v > s.Volume)
- {//確定總量是增加的才產生Tick, 否則視為修正而已
- s.Last.price.data = dllReturnString(dllGetCurrTagValue("121"));//Last/trade
- s.Last.qty = (Int32)(v - s.Volume);
- Console.WriteLine("Tick " + s.Symbol.data + " V: " + v + " Last: " + s.Last.price.data + "(" + s.Last.qty + ")");
- }
- s.Volume = v;//update
- }
- //沒有要抓變化就不用比對直接一率更新即可
- s.aPrice[0].data = dllReturnString(dllGetCurrTagValue("422"));//Refer,昨收
- s.aPrice[1].data = dllReturnString(dllGetCurrTagValue("130"));//Open
- s.aPrice[2].data = dllReturnString(dllGetCurrTagValue("131"));//High
- s.aPrice[3].data = dllReturnString(dllGetCurrTagValue("132"));//Low
- //s.aPrice[4].data = dllReturnString(dllGetCurrTagValue("121"));//Last/trade
- //成交價和舊的最佳買賣價比較產生內外盤, 只是概念表達,可以轉成數值作更多的判斷
- if (s.Last.price.data == s.aBestBuy[0].price.data)
- {//成交在買價(內盤)
- }
- else if (s.Last.price.data == s.aBestSell[0].price.data)
- {//成交在賣價(外盤)
- }
- //... 五檔更新 ... 省略, 看完這邊的示範應該都會自己寫了
- //... 這裡可以設計KD資料處理 .... 例如當日KD最新狀態 假設當日的放在 array 0
- s.aKD_Day[0].Refer.data = s.aPrice[0].data;//昨收
- s.aKD_Day[0].Open.data = s.aPrice[1].data;//Open
- s.aKD_Day[0].High.data = s.aPrice[2].data;//High
- s.aKD_Day[0].Low.data = s.aPrice[3].data;//Low
- s.aKD_Day[0].Volume = s.Volume;//日總量
- // Copy the struct to unmanaged memory.
- Marshal.StructureToPtr(s, PtrItem, false);
- }
複製代碼
說明都在code中有提了,縮排對齊和顏料的部分就比較抱歉啦
大概以下重點:
1. 指標的部分,IntPtr怎麼判斷null
2. 如何將填好資料的結構存放於API中的記憶體(dllCreateItemQuoteMemory)
3. 調出資料(dllGetItemQuoteMemory)怎麼由指標變成結構內容
4. 老孫上場大鬧洞房,行情資料什麼都有,愛怎麼玩自己玩
其他請自己領悟囉~
當然,上面的程式碼怎麼表現還是要看一下avi感受西夏婆熱情
TickRealtime.rar
(136.52 KB, 下載次數: 6, 售價: 1 金錢)
內容中左邊是XP x86版程式
右邊是遠端Win7 x64版程式
就跟MMORPG的道理一樣,程式那麼大動畫那麼炫都是假的,
其實就只是一點點數據跑來跑去而已,
然後依據數據撥放動畫撥放特效,再弄個CD不能跳過來拖你的時間
浪費了青春與生命也只是資料庫的幾欄數據跟別人不一樣而已,
一堆脫機外掛或內掛跑的比你勤,還能直接拋數據作弊,
就連安裝作業系統,也要弄出個無人職守,那麼弄程式自動化也一樣,
都已經知道要作什麼了還看什麼介面,瞎泌線圖根本廢物,
其實當你在等成交當訊號,抓買賣作訊號的人早先跑一步了
當你以為預掛好委託可以優先成交時,你只是委託簿上面人家參考的訊號而已...
所以訊號源真的超級重要的,策略和下單根本是其次
如果能放程式在券商後端收資料就好了
這裡放個觀測點,看有沒有懶人要直接收cs檔
Program.cs.rar
(5.75 KB, 下載次數: 6, 售價: 1000 金錢)
厲害的可以專案自建,要不然得先有上次的專案才好收喔!
還是有人純觀賞?!
|