using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Runtime.InteropServices; using System.Runtime.Serialization.Json; using System.Text; //---------------------------------------------------------------- //Module Name: $safeprojectname$ //Purpose: //CopyRight: Muchinfo //History: //---------------------------------------------------------------- //DateTime 2016/6/4 14:12:07 //Author //Description Create //---------------------------------------------------------------- using Muchinfo.MTPClient.Data; using Muchinfo.MTPClient.Data.Enums; using Muchinfo.MTPClient.Data.Model; using Muchinfo.MTPClient.Data.Model.Account; using Muchinfo.MTPClient.Data.Model.Analysis; using Muchinfo.MTPClient.Data.Model.Sale; using Muchinfo.MTPClient.Data.Quote; using Muchinfo.MTPClient.Data.Quote.Structs; namespace Muchinfo.MTPClient.Adapter.Quote { public class QuoteDateAdapter { private DateTime baseDateTime = new DateTime(1970, 1, 1, 8, 0, 0); // 一笔周期数据长度 private const int CYCLE_LENGTH = 36; private const int TIK_LENGTH = 40; //一笔分笔数据 private const int HEAD_LENGTH = 74; private const int LENGTH = 36; private const int c_goodsLength = 228; ////u商品字节长度 private const int c_SaleGoodsLength = 56; ////发售商品长度 private const int c_planheadLength = 8; ////结算计划长度 private const int c_planRunSteps = 16; ////运行阶段时间数据长度 /// /// 请求历史周期时间 /// /// /// /// /// /// /// /// public byte[] HistoryCycleBytesRequst(QuoteGoods goods, DateTime startTime, DateTime endTime, CycleType type, int count) { if (type == CycleType.TimeSharing) { type = CycleType.Minutes1; } var totalSeconds = (int)((endTime - baseDateTime).TotalSeconds - (startTime - baseDateTime).TotalSeconds); using (MemoryStream ms = new MemoryStream()) { byte[] block = new byte[] { }; Int16 exchangeCode = Convert.ToInt16(goods.ExchHqCode.Substring(0, 3)); block = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(exchangeCode)); ms.Write(block, 0, block.Length); block = Encoding.UTF8.GetBytes(goods.GoodsHqCode.ToUpper().PadRight(64, '\0')); ms.Write(block, 0, block.Length); block = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)type)); ms.Write(block, 0, block.Length); block = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(count)); ms.Write(block, 0, block.Length); Int32 utcTime = (int)(startTime - baseDateTime).TotalSeconds; block = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(utcTime)); ms.Write(block, 0, block.Length); block = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(totalSeconds)); ms.Write(block, 0, block.Length); return ms.ToArray(); } } public GoodsHistoryCycle HistoryCycleBytesRespone(byte[] content) { if (content.Length < HEAD_LENGTH) { throw new Exception("数据长度过小Length:" + content.Length); } byte[] block = new byte[2]; int index = 0; Array.Copy(content, index, block, 0, 2); index += 2; Int16 exchangeCode = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(block, 0)); block = new byte[64]; Array.Copy(content, index, block, 0, 64); var goodsCode = Encoding.UTF8.GetString(block); goodsCode = goodsCode.Substring(0, goodsCode.IndexOf('\0')); ///处理商品有垃圾数据问题 var goodsHistory = new GoodsHistoryCycle(exchangeCode + string.Empty, goodsCode, goodsCode); index += 64; block = new byte[2]; Array.Copy(content, index, block, 0, 2); goodsHistory.CycleType = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(block, 0)); index += 2; Array.Copy(content, index, block, 0, 2); goodsHistory.decimalPlace = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(block, 0)); index += 2; block = new byte[4]; Array.Copy(content, index, block, 0, 4); goodsHistory.Count = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(block, 0)); index += 4; if (goodsHistory.CycleType != (int)CycleType.Tik) { block = new byte[content.Length - HEAD_LENGTH]; Array.Copy(content, index, block, 0, block.Length); goodsHistory.OhlcDataPoints = ConvertOHLC(block, goodsHistory.Count, goodsHistory.decimalPlace); } else { block = new byte[content.Length - HEAD_LENGTH]; Array.Copy(content, index, block, 0, block.Length); goodsHistory.SubDataPoints = ConvertTik(block, goodsHistory.Count, goodsHistory.decimalPlace); } return goodsHistory; } /// /// 历史K线 /// /// K线数据 /// /// /// private List ConvertOHLC(byte[] OHLCContent, int count, int decimalPlace) { var results = new List(); if (OHLCContent.Length != LENGTH * count) { throw new Exception("历史K线数据长度错误Length:" + OHLCContent.Length); } long index = 0; var powDecimal = Math.Pow(10, decimalPlace); byte[] block = new byte[4]; for (int i = 0; i < count; i++) { var ohlcPoints = new OHLCDataPoints(); block = new byte[4]; Array.Copy(OHLCContent, index, block, 0, 4); ohlcPoints.Open = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(block, 0)) / powDecimal; index += 4; Array.Copy(OHLCContent, index, block, 0, 4); ohlcPoints.High = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(block, 0)) / powDecimal; index += 4; Array.Copy(OHLCContent, index, block, 0, 4); ohlcPoints.Low = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(block, 0)) / powDecimal; index += 4; Array.Copy(OHLCContent, index, block, 0, 4); ohlcPoints.Close = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(block, 0)) / powDecimal; #if DEBUG Console.WriteLine(ohlcPoints.Close); #endif index += 4; block = new byte[8]; Array.Copy(OHLCContent, index, block, 0, 8); ohlcPoints.Volume = BitConverter.ToDouble(block, 0); index += 8; Array.Copy(OHLCContent, index, block, 0, 8); ohlcPoints.TotleTurnovers = BitConverter.ToDouble(block, 0); index += 8; block = new byte[4]; Array.Copy(OHLCContent, index, block, 0, 4); var datetime = baseDateTime.AddSeconds(IPAddress.NetworkToHostOrder(BitConverter.ToInt32(block, 0))); #if DEBUG Console.WriteLine(datetime.ToString("yyyy-MM-dd HH:mm:ss")); #endif ohlcPoints.Date = datetime.ToOADate(); index += 4; results.Add(ohlcPoints); } return results; } /// /// 转换Tik数据 /// /// /// /// 行情小数位 /// private List ConvertTik(byte[] TikContent, int count, int decimalPlace) { var results = new List(); if (TikContent.Length != TIK_LENGTH * count) { throw new Exception("历史Tik线数据长度错误Length:" + TikContent.Length); } long index = 0; var powDecimal = Math.Pow(10, decimalPlace); byte[] blockPrice = new byte[4]; byte[] blockVolume = new byte[8]; for (int i = 0; i < count; i++) { var penPoints = new SubPenData(decimalPlace); Array.Copy(TikContent, index, blockPrice, 0, 4); penPoints.Price = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(blockPrice, 0)) / powDecimal; index += 4; Array.Copy(TikContent, index, blockVolume, 0, 8); penPoints.CompleteQte = BitConverter.ToDouble(blockVolume, 0); index += 8; Array.Copy(TikContent, index, blockPrice, 0, 4); penPoints.BidPrice = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(blockPrice, 0)) / powDecimal; index += 4; Array.Copy(TikContent, index, blockVolume, 0, 8); penPoints.BidVolume = BitConverter.ToDouble(blockVolume, 0); index += 8; Array.Copy(TikContent, index, blockPrice, 0, 4); penPoints.AskPrice = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(blockPrice, 0)) / powDecimal; index += 4; Array.Copy(TikContent, index, blockVolume, 0, 8); penPoints.AskVolume = BitConverter.ToDouble(blockVolume, 0); index += 8; Array.Copy(TikContent, index, blockPrice, 0, 4); var datetime = baseDateTime.AddSeconds(IPAddress.NetworkToHostOrder(BitConverter.ToInt32(blockPrice, 0))); #if DEBUG Console.WriteLine(datetime.ToString("yyyy-MM-dd HH:mm:ss")); #endif penPoints.Time = datetime; index += 4; results.Add(penPoints); } results.Reverse(); return results; } /// /// 从行情获取商品组与商品信息. /// /// 数据内容 /// 商品组信息 /// 商品信息 public List ConvertGoodsWithsGoodsGroup(byte[] contentBytes, int count, ref List goodsGroups) { var results = new List(); var dicGoodsGroups = new Dictionary(); if (contentBytes.Length != c_goodsLength * count) { throw new Exception("商品数据长度错误Length:" + contentBytes.Length); } long index = 0; // var powDecimal = Math.Pow(10, decimalPlace); byte[] block4b = new byte[4]; byte[] block8b = new byte[8]; byte[] blockstring = new byte[64]; for (int i = 0; i < count; i++) { Array.Copy(contentBytes, index, blockstring, 0, 64); var goodsCode = Encoding.UTF8.GetString(blockstring).Trim('\0'); index += 64; Array.Copy(contentBytes, index, blockstring, 0, 64); var goodsName = Encoding.UTF8.GetString(blockstring).Trim('\0'); index += 64; Array.Copy(contentBytes, index, block4b, 0, 4); var exchangeCode = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(block4b, 0)); index += 4; var qouteGoods = new QuoteGoods(exchangeCode.ToString(), goodsCode, goodsCode, QuoteCategoryType.Futures); qouteGoods.Name = goodsName; Array.Copy(contentBytes, index, block8b, 0, 8); var goodsGroupId = IPAddress.NetworkToHostOrder(BitConverter.ToInt64(block8b, 0)); index += 8; Array.Copy(contentBytes, index, blockstring, 0, 64); var goodsGroupName = Encoding.UTF8.GetString(blockstring).Trim('\0'); ; index += 64; Array.Copy(contentBytes, index, block4b, 0, 4); var tradeMode = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(block4b, 0)); index += 4; qouteGoods.TradeMode = (eTradeMode)tradeMode; dicGoodsGroups[goodsGroupId] = new GoodsGroup() { GoodsGroupid = goodsGroupId, GoodsGroupName = goodsGroupName, TradeMode = (eTradeMode)tradeMode }; Array.Copy(contentBytes, index, block8b, 0, 8); var agreeUint = BitConverter.ToDouble(block8b, 0); index += 8; ////价格小数位 Array.Copy(contentBytes, index, block4b, 0, 4); var decimalPlace = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(block4b, 0)); index += 4; qouteGoods.DecimalPlaces = decimalPlace; ////市场类型ID Array.Copy(contentBytes, index, block4b, 0, 4); var marketypeID = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(block4b, 0)); index += 4; ////商品id Array.Copy(contentBytes, index, block4b, 0, 4); var goodsId = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(block4b, 0)); index += 4; qouteGoods.GoodsId = (uint)goodsId; qouteGoods.GoodsParameters = new GoodsParameters() { GoodsId = (uint)goodsId, AgreeUnit = Convert.ToDecimal(agreeUint), HqExchFigures = decimalPlace, SortId = goodsGroupId, MarketTypeID = marketypeID }; dicGoodsGroups[goodsGroupId].MarketTypeID = marketypeID; results.Add(qouteGoods); } goodsGroups = dicGoodsGroups.Values.ToList(); return results; } /// /// 从行情获取发售商品参数 /// /// 数据内容 /// 商品组信息 /// 商品信息 public List ConvertSaleGoodsParam(byte[] contentBytes, int count) { var results = new List(); if (contentBytes.Length != c_SaleGoodsLength * count) { throw new Exception("商品数据长度错误Length:" + contentBytes.Length); } long index = 0; // var powDecimal = Math.Pow(10, decimalPlace); byte[] block4b = new byte[4]; byte[] block8b = new byte[8]; byte[] blockstring = new byte[32]; for (int i = 0; i < count; i++) { var saleGoods = new SaleGoods(); ////商品ID Array.Copy(contentBytes, index, block4b, 0, 4); var goodsId = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(block4b, 0)); index += 4; saleGoods.GoodsId = (uint)goodsId; ////合约单位 Array.Copy(contentBytes, index, blockstring, 0, 32); var agreeUnitString = Encoding.UTF8.GetString(blockstring).Trim('\0'); ; index += 32; saleGoods.AgreeUnitString = agreeUnitString; ////发售开始时间 Array.Copy(contentBytes, index, block4b, 0, 4); saleGoods.ApplyStartTime = baseDateTime.AddSeconds(IPAddress.NetworkToHostOrder(BitConverter.ToInt32(block4b, 0))); index += 4; ////发售结束时间 Array.Copy(contentBytes, index, block4b, 0, 4); saleGoods.ApplyEndTime = baseDateTime.AddSeconds(IPAddress.NetworkToHostOrder(BitConverter.ToInt32(block4b, 0))); index += 4; ////发售阶段 Array.Copy(contentBytes, index, block4b, 0, 4); saleGoods.RunSteps = (eRunStep)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(block4b, 0)); index += 4; ////发售价格 Array.Copy(contentBytes, index, block8b, 0, 8); saleGoods.SalePrice = Convert.ToDecimal(BitConverter.ToDouble(block8b, 0)); index += 8; results.Add(saleGoods); } return results; } /// /// 解析行情交易运行时间段 /// /// 数据内容 /// public QuoteTradePlan ConvertTradePlans(byte[] contentBytes) { if (contentBytes.Length < c_planheadLength) { throw new Exception("查询结算计划数据长度过小Length:" + contentBytes.Length); } var quoteTrade = new QuoteTradePlan(); uint index = 0; byte[] block4b = new byte[4]; Array.Copy(contentBytes, index, block4b, 0, 4); var marketTypeid = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(block4b, 0)); index += 4; quoteTrade.MarketTypeID = marketTypeid; Array.Copy(contentBytes, index, block4b, 0, 4); var count = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(block4b, 0)); ////数量 index += 4; var subBlocks = new byte[contentBytes.Length - c_planheadLength]; Array.Copy(contentBytes, index, subBlocks, 0, subBlocks.Length); if (subBlocks.Length != c_planRunSteps * count) { throw new Exception("结算计划时间段数据长度错误Length:" + subBlocks.Length); } index = 0; quoteTrade.OpenCloseDates = new List(); for (int i = 0; i < count; i++) { var runSteps = new OpenCloseDate(); Array.Copy(subBlocks, index, block4b, 0, 4); runSteps.TradeDay = baseDateTime.AddSeconds(IPAddress.NetworkToHostOrder(BitConverter.ToInt32(block4b, 0))); index += 4; Array.Copy(subBlocks, index, block4b, 0, 4); runSteps.RunStep = (eRunStep)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(block4b, 0)); index += 4; Array.Copy(subBlocks, index, block4b, 0, 4); runSteps.OpenDate = baseDateTime.AddSeconds(IPAddress.NetworkToHostOrder(BitConverter.ToInt32(block4b, 0))); index += 4; Array.Copy(subBlocks, index, block4b, 0, 4); runSteps.CloseDate = baseDateTime.AddSeconds(IPAddress.NetworkToHostOrder(BitConverter.ToInt32(block4b, 0))); index += 4; quoteTrade.OpenCloseDates.Add(runSteps); } return quoteTrade; } /// /// 使用json解析开收市计划 /// /// Json数据 /// 数据提示 /// public List ConvertFromJson(byte[] contentBytes, ref ErrorEntity error) { var quoteTradeList = new List(); try { var dataContractJson = new DataContractJsonSerializer(typeof(TimeSection[])); using (MemoryStream ms = new MemoryStream(contentBytes)) { var runsteps = dataContractJson.ReadObject(ms) as TimeSection[]; if (runsteps == null || !runsteps.Any()) { error.ReturnDesc = "无结算计划数据!"; error.ReturnCode = -1; return quoteTradeList; } var planDic = new Dictionary(); for (int i = 0; i < runsteps.Count(); i++) { if (!planDic.ContainsKey(runsteps[i].GoodsId)) { planDic[runsteps[i].GoodsId] = new QuoteTradePlan() { GoodsId = runsteps[i].GoodsId, MarketTypeID = runsteps[i].id, TradeDay = baseDateTime.AddSeconds(runsteps[i].TradeDay) }; planDic[runsteps[i].GoodsId].OpenCloseDates = new List(); } var planSection = new OpenCloseDate(); planSection.OpenDate = baseDateTime.AddSeconds(runsteps[i].BeginTime); planSection.CloseDate = baseDateTime.AddSeconds(runsteps[i].EndTime); planSection.RunStep = (eRunStep)runsteps[i].RunStep; planDic[runsteps[i].GoodsId].OpenCloseDates.Add(planSection); } quoteTradeList = planDic.Values.ToList(); } } catch (Exception ex) { error.ReturnDesc = ex.Message; error.ReturnCode = -1; } return quoteTradeList; } /// /// 使用json解析开收市计划 /// /// Json数据 /// 数据提示 /// public List ConvertFromMarketStatusJson(byte[] contentBytes, ref ErrorEntity error) { var quoteStatus = new List(); try { var dataContractJson = new DataContractJsonSerializer(typeof(MarketTypeStatus[])); using (MemoryStream ms = new MemoryStream(contentBytes)) { var runsteps = dataContractJson.ReadObject(ms) as MarketTypeStatus[]; if (runsteps == null || !runsteps.Any()) { error.ReturnDesc = "无开收市计划数据!"; error.ReturnCode = -1; return quoteStatus; } quoteStatus.AddRange(runsteps); return quoteStatus; } } catch (Exception ex) { error.ReturnDesc = ex.Message; error.ReturnCode = -1; } return quoteStatus; } /// /// 行情报文组装 /// /// 账号Id /// 令牌字串 /// public byte[] QuoteCheckToken(uint accountid, string token) { using (MemoryStream ms = new MemoryStream()) { byte[] block = new byte[] { }; block = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(accountid)); ms.Write(block, 0, block.Length); block = Encoding.UTF8.GetBytes(token.PadRight(64, '\0')); ms.Write(block, 0, block.Length); return ms.ToArray(); } } } }