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();
}
}
}
}