/// <summary> /// 編碼價格資訊函式 /// </summary> /// <param name="Buffer">緩衝區</param> /// <param name="Price">價格</param> /// <param name="ReferPrice">參考價</param> /// <param name="PriceFlag">價格旗標</param> /// <param name="BitIndex">起始位元索引(0=最右邊起始位元 依序向左遞增)</param> internal static void SetPrice(PacketBuffer Buffer, float Price, float ReferPrice, ref byte PriceFlag, int BitIndex) { int iValue = 0; if (ReferPrice == 0 || System.Math.Abs(Price - ReferPrice) > 255) { iValue = decimal.ToInt32(new decimal(Price) * 100); } else { iValue = decimal.ToInt32((new decimal(Price) * 100) - (new decimal(ReferPrice) * 100)); } int iNegative = (((iValue & 0x80000000) == 0) ? 0x00 : 0x80); if (iNegative == 0x80) { //如果是負數 iValue = ~iValue; //做2的補數(變成正數) ++iValue; } int iInteger = iValue / 100; int iDot = iValue % 100; if (iInteger == 0 && iDot > 0) { Buffer.Data[Buffer.Position++] = (byte)(iDot | iNegative); PriceFlag = BitConvert.SetValue(PriceFlag, BitIndex, 0); } else if (iInteger < 128 && iDot == 0) { Buffer.Data[Buffer.Position++] = (byte)(iInteger | iNegative); PriceFlag = BitConvert.SetValue(PriceFlag, BitIndex, 2); } else if (iInteger < 256) { Buffer.Data[Buffer.Position++] = (byte)iInteger; Buffer.Data[Buffer.Position++] = (byte)(iDot | iNegative); PriceFlag = BitConvert.SetValue(PriceFlag, BitIndex, 3); } else { Buffer.Data[Buffer.Position++] = (byte)(iInteger >> 8); Buffer.Data[Buffer.Position++] = (byte)(iInteger & 0xff); Buffer.Data[Buffer.Position++] = (byte)iDot; PriceFlag = BitConvert.SetValue(PriceFlag, BitIndex, 1); } }
/// <summary> /// 取得成交量資訊函式 /// </summary> /// <param name="type">成交量類型(請參考資料格式)</param> /// <param name="Buffer">ZBuffer類別</param> /// <returns>傳回值:成交量(或是其他型態)</returns> internal static uint GetVolumn(int type, PacketBuffer Buffer) { uint uVolumn = 0; switch (type) { case 0: uVolumn = (uint)Buffer[0]; break; case 1: uVolumn = (uint)(Buffer[0] << 8); uVolumn += (uint)Buffer[1]; break; case 2: uVolumn = (uint)(Buffer[0] << 16); uVolumn += (uint)(Buffer[1] << 8); uVolumn += Buffer[2]; break; case 3: uVolumn = (uint)(Buffer[0] << 24); uVolumn += (uint)(Buffer[1] << 16); uVolumn += (uint)(Buffer[2] << 8); uVolumn += Buffer[3]; break; } Buffer.Position += (type + 1); return uVolumn; }
/// <summary> /// 設定成交量資訊函式 /// </summary> /// <param name="Buffer">封包陣列</param> /// <param name="Volumn">成交量</param> /// <param name="VolumnFlag">成交量旗標</param> /// <param name="BitIndex">起始位元索引(0=最右邊起始位元 依序向左遞增)</param> internal static void SetVolumn(PacketBuffer Buffer, uint Volumn, ref byte VolumnFlag, int BitIndex) { byte[] bTmpData = new byte[4]; //建立一個暫存的陣列 byte i = 0; for (i = 0; i <= 3; i++) { bTmpData[i] = (byte)(Volumn & 0xff); if ((Volumn >>= 8) == 0) break; } VolumnFlag = BitConvert.SetValue(VolumnFlag, BitIndex, i); int iCount = i + 1; for (byte j = 0; j < iCount; j++) { Buffer.Data[Buffer.Position++] = bTmpData[i - j]; } }
/// <summary> /// 解碼價格資訊函式 /// </summary> /// <param name="type">價格類型(請參閱資料格式)</param> /// <param name="Buffer">ZBuffer類別</param> /// <param name="ReferPrice">參考價格</param> /// <returns>傳回值:股票價格</returns> internal static float GetPrice(int type, PacketBuffer Buffer, ref float ReferPrice) { double dPrice = 0; switch (type) { case 0: if ((Buffer[0] & 0x80) == 0) { dPrice = (Buffer[0] * 0.01); } else { dPrice = ((Buffer[0] & 0x7f) * 0.01); dPrice *= -1; } dPrice = ReferPrice + dPrice; ++Buffer.Position; break; case 1: dPrice = ((Buffer[0] << 8) + Buffer[1]); dPrice += (Buffer[2] * 0.01); Buffer.Position += 3; break; case 2: if ((Buffer[0] & 0x80) == 0) { dPrice = Buffer[0]; } else { dPrice = (Buffer[0] & 0x7f); dPrice *= -1; } dPrice = ReferPrice + dPrice; ++Buffer.Position; break; case 3: dPrice = Buffer[0]; if ((Buffer[1] & 0x80) == 0) { dPrice += (Buffer[1] * 0.01); } else { dPrice += ((Buffer[1] & 0x7f) * 0.01); dPrice *= -1; } dPrice = ReferPrice + dPrice; Buffer.Position += 2; break; } float fPrice = (float)System.Math.Round(dPrice, 2); if (ReferPrice == 0) { ReferPrice = fPrice; } return fPrice; }
internal static void Decode(MitakeIndex index, PacketBuffer Buffer) { byte bMode = 0, bFlag = 0; MitakeIndexTick cTick = null; //移動至資料結構 Buffer.Position = 7; DateTime cTime = Time.GetTime(Buffer); //取得時間 bool bHave = index.GetMitakeTick(cTime, ref cTick); cTick.SetFlag(2); MitakeIndexTick cPrevTick = index.GetPreviousTick(cTime, 2); if (!bHave) { if (cPrevTick != null) { cTick.Clone(cPrevTick, 2); } } //取得format bFlag = Buffer[0]; ++Buffer.Position; //取得成交總額 bMode = BitConvert.GetValue(bFlag, 6, 2); uint uVolume = Volumn.GetVolumn(bMode, Buffer); cTick.Volume = uVolume; if (uVolume > index.成交總額) { index.成交總額 = uVolume; } //取得成交張數 bMode = BitConvert.GetValue(bFlag, 4, 2); cTick.成交張數 = Volumn.GetVolumn(bMode, Buffer); //取得成交筆數 bMode = BitConvert.GetValue(bFlag, 2, 2); cTick.成交筆數 = Volumn.GetVolumn(bMode, Buffer); CalculateSingle(cTick, cPrevTick); ++index.UpdateCount; }
internal static TimerEvent Decode(PacketBuffer buffer, bool isDecode) { if (isDecode) { buffer.Position = 0; //從第0索引開始 int iLength = buffer[3]; //取得封包長度 TimerEvent cTimer = new TimerEvent(); cTimer.QuoteDateTime = Time.GetDateTime(buffer); cTimer.Trade = (byte)(buffer[0] & 0x03); ++buffer.Position; if (iLength == 9) { //表示有最後交易日期 cTimer.TradeDate = Time.GetDate(buffer); } else { cTimer.TradeDate = cTimer.QuoteDateTime.Date; } return cTimer; } else { return null; } }
internal static MitakeNotice Decode(int serial, PacketBuffer buffer) { int iBodySize = 0; string sTime = null, sText = null; int iSerial = 0; byte bNumber = 0, bCount = 0; iBodySize = buffer.Data[3] - 5; buffer.Position = 7; //移動至資料結構(時間欄位) //取得序號 iSerial = (buffer[0] << 8) + buffer[1]; buffer.Position += 2; bNumber = buffer[0]; //取得封包編號(0 = 標題) ++buffer.Position; if (bNumber == 0) { //取得封包個數 bCount = buffer[0]; ++buffer.Position; //取得公告時間 sTime = string.Format("{0}:{1}", buffer[0].ToString("0#"), buffer[1].ToString("0#")); buffer.Position += 2; iBodySize -= 6; } else { iBodySize -= 3; } if (iBodySize > 0) { sText = Encoding.GetEncoding("big5").GetString(buffer.Data, buffer.Position, iBodySize); } return __cNoticeUtil.Merge(serial, iSerial, bNumber, bCount, sTime, sText); //封包合併(如果合併完成會傳出公告資訊類別, 否則回傳null) }
internal static void Decode(int serial, PacketBuffer buffer) { byte bSize = 0, bMark = 0, bFlag = 0, bTemp = 0; MitakeSymbolInformation cSymbolInfo = new MitakeSymbolInformation(); bSize = buffer.Data[3]; buffer.Position = 7; //移動至資料結構 //判斷股票別(如果為0 表示無此資料) bFlag = buffer[0]; //取得市場別(0=集中市場 1=上櫃 2=期貨 3=興櫃) cSymbolInfo.市場別 = BitConvert.GetValue(bFlag, 6, 2); //取得是否為警示股 bTemp = BitConvert.GetValue(bFlag, 5, 1); cSymbolInfo.警示 = ((bTemp == 1) ? true : false); //取得是否為下市股票(五個交易日後移除) bTemp = BitConvert.GetValue(bFlag, 4, 1); cSymbolInfo.下市 = ((bTemp == 1) ? true : false); //取得市場分類(參閱解碼表代號) cSymbolInfo.市場分類 = BitConvert.GetValue(bFlag, 0, 4); ++buffer.Position; //取得股票代號(舊格式股票代號) cSymbolInfo.SymbolId = Encoding.UTF8.GetString(buffer.Data, buffer.Position, 5).Trim(); buffer.Position += 5; //取得股票名稱 cSymbolInfo.SymbolName = Encoding.UTF8.GetString(buffer.Data, buffer.Position, 9).Replace("\0", string.Empty); buffer.Position += 9; //期貨擴充(1:一般, 2:現月, 3:次月 PS:股票無使用) bMark = buffer[0]; cSymbolInfo.FutureMark = bMark; ++buffer.Position; string sSymbolId = string.Empty; if (cSymbolInfo.市場別 == 2) { //判斷是否為期貨 if (cSymbolInfo.市場分類 == 2) { //如果市場分類 == 2,則可能是選擇權(SID2 = 10Bytes) sSymbolId = Encoding.UTF8.GetString(buffer.Data, buffer.Position, 10).Trim(); buffer.Position += 10; } else { sSymbolId = Encoding.UTF8.GetString(buffer.Data, buffer.Position, 10).Trim(); buffer.Position += 13; } } else { //取得SID2 sSymbolId = Encoding.UTF8.GetString(buffer.Data, buffer.Position, 6).Trim(); buffer.Position += 6; //取得個股產業類別 cSymbolInfo.產業別 = Encoding.UTF8.GetString(buffer.Data, buffer.Position, 2); buffer.Position += 2; //取得個股證券類別 cSymbolInfo.證券別 = Encoding.UTF8.GetString(buffer.Data, buffer.Position, 2); buffer.Position += 2; } if (sSymbolId.Length > 0) { cSymbolInfo.SymbolId = sSymbolId; //轉換為標準台股商品代號格式 string sProductId = MitakeSymbolManager.Convert(cSymbolInfo.SymbolId, (cSymbolInfo.市場別 == 2) ? cSymbolInfo.市場分類 : 0); if (sProductId != null) { cSymbolInfo.SymbolId = sProductId; if (!MitakeSymbolManager.IsExist(sProductId)) { AddProductToExchange(cSymbolInfo); //將股票代號更新至交易所內 } MitakeSymbolManager.AddQuoteSymbolInformation(serial, cSymbolInfo); //將基本資訊加入代號管理員內 } } }
/// <summary> /// ZBuffer建構子 /// </summary> /// <param name="buffer">ZBuffer緩衝區</param> public PacketBuffer(PacketBuffer buffer) { __iLength = buffer.Length; __iSize = __iLength + 32; this.Data = buffer.Data; }
/// <summary> /// 加入新封包 /// </summary> /// <param name="buffer">來源ZBuffer封包</param> /// <returns>返回值:ture=成功 false=失敗</returns> public bool Add(PacketBuffer buffer) { return(Add(buffer.Data, 0, buffer.Length)); }
/// <summary> /// 檢查金融封包 /// </summary> /// <param name="item">來源封包</param> /// <returns>返回值:-1=未知封包 0=成功 1=末端斷包 2=封包長度不完整</returns> private static int VerifyPacket(PacketBuffer item) { if (item[0] == 0x01 && item[2] == 0x02) { if ((item.Position + 3) < item.Length) { int iSize = item[3] + 4; //取得封包的總長度(包含標頭) if ((item.Position + iSize) > item.Length) { --item.Position; return 1; } else { byte bEOF = item[iSize - 1]; if (bEOF == 0x4) { //檢查是否有正確的結束字元 if (Sockets.MitakePacket.GetChecksum(item, item.Position)) { return 0; //封包正確 } else { item.Position += (iSize - 1); return 2; } } else { item.Position += 3; //跳至內容之後開始尋找下一個封包 while (++item.Position < item.Length) if (item[0] == 0x02 && item[-2] == 0x01) break; item.Position -= 3; return 2; } } } } return -1; }
/// <summary> /// 加入新封包 /// </summary> /// <param name="buffer">來源ZBuffer封包</param> /// <returns>返回值:ture=成功 false=失敗</returns> public bool Add(PacketBuffer buffer) { return Add(buffer.Data, 0, buffer.Length); }
/// <summary> /// 建構子 /// </summary> /// <param name="Buffer">PacketBuffer 類別</param> public SocketToken(PacketBuffer Buffer) { __cStockEvent = new StockEvent(); __cMcpEvent = new McpPacketEvent(); __cPackage = new PacketBuffer(4096); __cTempBuffer = new PacketBuffer(MAX_BUFFER_SIZE); if (Buffer == null) { __cRecvBuffer = new PacketBuffer(MAX_BUFFER_SIZE); } else { __cRecvBuffer = Buffer; } }
/// <summary> /// 將暫存封包般移到主要緩衝區 /// </summary> internal void Move() { PacketBuffer cTemp = __cRecvBuffer; __cRecvBuffer = __cTempBuffer; __cTempBuffer = cTemp; __cTempBuffer.Length = 0; }
internal static void Decode(MitakeQuote quote, PacketBuffer Buffer) { byte bFlag = 0; int iFormatIndex = 7; float fReferPrice = 0; double[,] dPrices = new double[2,5]; double[,] dVolumes = new double[2,5]; int iSize = Buffer.Length - 1; if (iSize == 0) { //如果長度為0表示此回補已經回補完畢 return; } Buffer.Position = 15; //移動至資料結構 quote.即時資訊.Time = Time.GetTime(Buffer); bFlag = Buffer.Data[iFormatIndex++]; quote.ReferPrice = Price.GetPrice(BitConvert.GetValue(bFlag, 6, 2), Buffer, ref fReferPrice); quote.即時資訊.Price = Price.GetPrice(BitConvert.GetValue(bFlag, 4, 2), Buffer, ref fReferPrice); dPrices[0, 0] = Price.GetPrice(BitConvert.GetValue(bFlag, 2, 2), Buffer, ref fReferPrice); dPrices[1, 0] = Price.GetPrice(BitConvert.GetValue(bFlag, 0, 2), Buffer, ref fReferPrice); bFlag = Buffer.Data[iFormatIndex++]; quote.即時資訊.Volume = Volumn.GetVolumn(BitConvert.GetValue(bFlag, 6, 2), Buffer); quote.今日總成交量 = quote.即時資訊.Volume; quote.即時資訊.Single = Volumn.GetVolumn(BitConvert.GetValue(bFlag, 4, 2), Buffer); dVolumes[0, 0] = Volumn.GetVolumn(BitConvert.GetValue(bFlag, 2, 2), Buffer); dVolumes[1, 0] = Volumn.GetVolumn(BitConvert.GetValue(bFlag, 0, 2), Buffer); bFlag = Buffer.Data[iFormatIndex++]; quote.Open = Price.GetPrice(BitConvert.GetValue(bFlag, 6, 2), Buffer, ref fReferPrice); quote.High = Price.GetPrice(BitConvert.GetValue(bFlag, 4, 2), Buffer, ref fReferPrice); quote.Low = Price.GetPrice(BitConvert.GetValue(bFlag, 2, 2), Buffer, ref fReferPrice); quote.昨日最高價 = Price.GetPrice(BitConvert.GetValue(bFlag, 0, 2), Buffer, ref fReferPrice); bFlag = Buffer.Data[iFormatIndex++]; quote.昨日最低價 = Price.GetPrice(BitConvert.GetValue(bFlag, 6, 2), Buffer, ref fReferPrice); quote.昨日總成交量 = Volumn.GetVolumn(BitConvert.GetValue(bFlag, 4, 2), Buffer); quote.未平倉合約數 = Volumn.GetVolumn(BitConvert.GetValue(bFlag, 2, 2), Buffer); dPrices[0, 1] = Price.GetPrice(BitConvert.GetValue(bFlag, 0, 2), Buffer, ref fReferPrice); bFlag = Buffer.Data[iFormatIndex++]; dPrices[0, 2] = Price.GetPrice(BitConvert.GetValue(bFlag, 6, 2), Buffer, ref fReferPrice); dPrices[0, 3] = Price.GetPrice(BitConvert.GetValue(bFlag, 4, 2), Buffer, ref fReferPrice); dPrices[0, 4] = Price.GetPrice(BitConvert.GetValue(bFlag, 2, 2), Buffer, ref fReferPrice); dPrices[1, 1] = Price.GetPrice(BitConvert.GetValue(bFlag, 0, 2), Buffer, ref fReferPrice); bFlag = Buffer.Data[iFormatIndex++]; dPrices[1, 2] = Price.GetPrice(BitConvert.GetValue(bFlag, 6, 2), Buffer, ref fReferPrice); dPrices[1, 3] = Price.GetPrice(BitConvert.GetValue(bFlag, 4, 2), Buffer, ref fReferPrice); dPrices[1, 4] = Price.GetPrice(BitConvert.GetValue(bFlag, 2, 2), Buffer, ref fReferPrice); dVolumes[0, 1] = Volumn.GetVolumn(BitConvert.GetValue(bFlag, 0, 2), Buffer); bFlag = Buffer.Data[iFormatIndex++]; dVolumes[0, 2] = Volumn.GetVolumn(BitConvert.GetValue(bFlag, 6, 2), Buffer); dVolumes[0, 3] = Volumn.GetVolumn(BitConvert.GetValue(bFlag, 4, 2), Buffer); dVolumes[0, 4] = Volumn.GetVolumn(BitConvert.GetValue(bFlag, 2, 2), Buffer); dVolumes[1, 1] = Volumn.GetVolumn(BitConvert.GetValue(bFlag, 0, 2), Buffer); bFlag = Buffer.Data[iFormatIndex++]; dVolumes[1, 2] = Volumn.GetVolumn(BitConvert.GetValue(bFlag, 6, 2), Buffer); dVolumes[1, 3] = Volumn.GetVolumn(BitConvert.GetValue(bFlag, 4, 2), Buffer); dVolumes[1, 4] = Volumn.GetVolumn(BitConvert.GetValue(bFlag, 2, 2), Buffer); quote.即時均價 = Price.GetPrice(BitConvert.GetValue(bFlag, 0, 2), Buffer, ref fReferPrice); iFormatIndex = Buffer.Position; Buffer.Position += 2; bFlag = Buffer.Data[iFormatIndex++]; quote.累計買量 = Volumn.GetVolumn(BitConvert.GetValue(bFlag, 6, 2), Buffer); quote.累計賣量 = Volumn.GetVolumn(BitConvert.GetValue(bFlag, 4, 2), Buffer); quote.單筆買進巨量 = Volumn.GetVolumn(BitConvert.GetValue(bFlag, 2, 2), Buffer); quote.單筆賣出巨量 = Volumn.GetVolumn(BitConvert.GetValue(bFlag, 0, 2), Buffer); bFlag = Buffer.Data[iFormatIndex++]; quote.累計買進巨量 = Volumn.GetVolumn(BitConvert.GetValue(bFlag, 6, 2), Buffer); quote.累計賣出巨量 = Volumn.GetVolumn(BitConvert.GetValue(bFlag, 4, 2), Buffer); quote.即時量幅 = (float)(Volumn.GetVolumn(BitConvert.GetValue(bFlag, 2, 2), Buffer) * 0.01); quote.買進量百分比 = (byte)Volumn.GetVolumn(BitConvert.GetValue(bFlag, 0, 2), Buffer); for (int i = 0; i < 5; i++) { quote.委買委賣資訊.Bid[i] = new DOMPrice(dPrices[0, i], dVolumes[0, i]); quote.委買委賣資訊.Ask[i] = new DOMPrice(dPrices[1, i], dVolumes[1, i]); } quote.即時資訊.Bid = quote.委買委賣資訊.Bid[0]; quote.即時資訊.Ask = quote.委買委賣資訊.Ask[0]; ++quote.UpdateCount; }
internal StockEvent(byte header, int serial, byte type, PacketBuffer source) { this.Header = header; this.Serial = serial; this.Type = type; this.Source = source; }
/// <summary> /// 取得委託價函式 /// </summary> /// <param name="type">委託價格式(0=1Byte 1=2Byte)</param> /// <param name="buffer">即時資料Buffer</param> /// <returns>返回值:委託價格</returns> private static float EntrustPrice(byte type, PacketBuffer buffer) { double dPrice = 0; if (type == 0) { if (buffer[0] < 0xff) { //0xff=無價位 dPrice = buffer[0] * 0.01; } ++buffer.Position; } else { dPrice = ((buffer[0] << 8) + buffer[1]) * 0.01; buffer.Position += 2; } return (float)dPrice; }
internal static void Decode(MitakeQuote stock, PacketBuffer buffer) { DateTime cTime; bool isHave = false; int iSerial = 0; float fReferPrice = 0; byte bType = 0, bMode = 0, bVType = 0, bFlag = 0; MitakeQuoteTick cTick = null; int iSize = buffer.Length - 2; byte bSType = buffer.Data[6]; buffer.Position = 7; if ((bSType & 0xf) == 11) { iSerial = ((buffer[0] << 8) + buffer[1]); buffer.Position = 9; } else { iSerial = (buffer[0] << 16) + (buffer[1] << 8) + buffer[2]; buffer.Position = 10; } do { //取得類型 bType = BitConvert.GetValue(buffer[0], 7, 1); //取得時間 if ((bSType & 0x80) == 0) { cTime = Time.GetTime(buffer); } else { cTime = Time.GetOther(buffer); } isHave = stock.GetMitakeTick(iSerial, ref cTick); cTick.Time = cTime; bFlag = buffer[0]; //取得價量旗標 ++buffer.Position; cTick.類型 = bType; //類型 0=即時 1=盤後(此封包為盤後封包) //買賣型態(0=無法區分 1=買盤量 2=賣盤量) bVType = BitConvert.GetValue(bFlag, 2, 2); cTick.買賣盤 = bVType; //取得成交價模式 bMode = BitConvert.GetValue(bFlag, 6, 2); cTick.Price = Price.GetPrice(bMode, buffer, ref fReferPrice); Decode_S31.CalculatePrice(stock, iSerial, cTick.Price); //計算 開盤 最高 最低 //取得單量模式 bMode = BitConvert.GetValue(bFlag, 4, 2); cTick.Single = Volumn.GetVolumn(bMode, buffer); //取得委買價 cTick.Bid = new DOMPrice(cTick.Price - EntrustPrice(BitConvert.GetValue(bFlag, 1, 1), buffer), cTick.Bid.Size); //取得委賣價 cTick.Ask = new DOMPrice(cTick.Price + EntrustPrice(BitConvert.GetValue(bFlag, 0, 1), buffer), cTick.Ask.Size); if (!isHave) { stock.今日總成交額 += cTick.Price * cTick.Single; } if (iSerial > stock.即時資訊.Serial) { Decode_S31.CalculateEntrust(stock, cTick); //計算第一檔委買賣 } ++iSerial; } while (buffer.Position < iSize);//End While }
internal McpPacketEvent(Socket socket, PacketBuffer source, byte type, byte command) { this.ActiveSocket = socket; this.Source = source; this.Type = type; this.Command = command; }