From bd08843af81820a91998c82a43cc4fdcb78bebd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Wed, 19 Jul 2017 09:54:07 +0800 Subject: [PATCH 01/41] =?UTF-8?q?=E5=85=BC=E5=AE=B9=E6=96=B0=E7=89=88?= =?UTF-8?q?=E7=9A=84SubSide?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../QuantBox.APIProvider.csproj | 13 ++- .../Single/SingleProvider.API.Order.cs | 81 +++++++++++++++++-- QuantBox.API.Provider/packages.config | 4 +- .../QuantBox.Extensions.csproj | 3 +- 4 files changed, 82 insertions(+), 19 deletions(-) diff --git a/QuantBox.API.Provider/QuantBox.APIProvider.csproj b/QuantBox.API.Provider/QuantBox.APIProvider.csproj index 998a013..9078bb6 100644 --- a/QuantBox.API.Provider/QuantBox.APIProvider.csproj +++ b/QuantBox.API.Provider/QuantBox.APIProvider.csproj @@ -31,18 +31,17 @@ 4 - - ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll + + ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll True - ..\packages\NLog.4.3.9\lib\net45\NLog.dll + ..\packages\NLog.4.4.11\lib\net45\NLog.dll True - + False C:\Program Files\SmartQuant Ltd\OpenQuant 2014\SmartQuant.dll - False @@ -119,9 +118,7 @@ - - Designer - + diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs b/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs index 64b5a64..ac30c5b 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs @@ -45,7 +45,7 @@ public partial class SingleProvider // && 0 == LowerLimitPrice) // { // //涨跌停无效 - + // } // else // { @@ -58,7 +58,7 @@ public partial class SingleProvider // return price; //} - public double FixPrice(MarketDataRecord record,double price, SmartQuant.OrderSide Side, double tickSize) + public double FixPrice(MarketDataRecord record, double price, SmartQuant.OrderSide Side, double tickSize) { double LowerLimitPrice = record.DepthMarket.LowerLimitPrice; double UpperLimitPrice = record.DepthMarket.UpperLimitPrice; @@ -89,7 +89,7 @@ public double FixPrice(MarketDataRecord record,double price, SmartQuant.OrderSid { //涨跌停无效 _TdApi.GetLog().Warn("Symbol:{0},Symbol_Dot_Exchange:{1},LowerLimitPrice && UpperLimitPrice 为0,没有进行价格修正", - record.Symbol,record.Symbol_Dot_Exchange); + record.Symbol, record.Symbol_Dot_Exchange); } else { @@ -198,7 +198,7 @@ private void CmdNewOrderSingle(ExecutionCommand command) MarketDataRecord record; if (marketDataRecords.TryGetValue(command.Instrument.Symbol, out record)) { - switch(command.OrdType) + switch (command.OrdType) { case SQ.OrderType.Market: case SQ.OrderType.MarketOnClose: @@ -215,7 +215,7 @@ private void CmdNewOrderSingle(ExecutionCommand command) } // 市价单使用限价单模拟 - if(SwitchMakertOrderToLimitOrder) + if (SwitchMakertOrderToLimitOrder) { fields[0].Type = XAPI.OrderType.Limit; } @@ -225,9 +225,9 @@ private void CmdNewOrderSingle(ExecutionCommand command) if (HasPriceLimit) { //price = FixPrice(price, command.Side, apiTickSize, record.DepthMarket.LowerLimitPrice, record.DepthMarket.UpperLimitPrice); - price = FixPrice(record,price, command.Side, apiTickSize); + price = FixPrice(record, price, command.Side, apiTickSize); } - + fields[0].Price = price; } @@ -259,6 +259,71 @@ private void CmdNewOrderList(ExecutionCommand command) orderMap.DoOrderSend(ref fields, orders); } + private void SubSide2OpenClose(ref OrderField field, Order order) + { + // 由于无法指定平今与平昨,所以废弃 + if (framework.Configuration.UseSubPositions) + { + switch (order.SubSide) + { + case SubSide.Undefined: + field.OpenClose = order.Side == SQ.OrderSide.Buy ? OpenCloseType.Open : OpenCloseType.Close; + break; + case SubSide.BuyCover: + field.OpenClose = OpenCloseType.Close; + break; + case SubSide.SellShort: + field.OpenClose = OpenCloseType.Open; + break; + } + } + else + { + // 前面已经处理过了 + // field.OpenClose = GetOpenClose(order); + } + } + + private void OpenClose2SubSide(ref OrderField field, Order order) + { + //多头 + //Buy 就是开 + //Sell 就是平 SubSide 是 Undefined + + //空头 + //Sell 加 SubSide = SellShort 是开仓 + //Buy 加 SubSide = BuyCover 是平仓 + + // 由于使用官方的办法无法指定平今与平昨,所以还是用以前的开平仓的写法 + // 区别只是官方维护了双向持仓 + if (order.Side == SQ.OrderSide.Buy) + { + switch (field.OpenClose) + { + case OpenCloseType.Open: + order.SubSide = SubSide.Undefined; + break; + case OpenCloseType.Close: + case OpenCloseType.CloseToday: + order.SubSide = SubSide.BuyCover; + break; + } + } + else + { + switch (field.OpenClose) + { + case OpenCloseType.Open: + order.SubSide = SubSide.SellShort; + break; + case OpenCloseType.Close: + case OpenCloseType.CloseToday: + order.SubSide = SubSide.Undefined; + break; + } + } + } + private void ToOrderStruct(ref OrderField field, Order order, string apiSymbol, string apiExchange) { field.InstrumentID = apiSymbol; @@ -278,6 +343,8 @@ private void ToOrderStruct(ref OrderField field, Order order, string apiSymbol, field.PortfolioID2 = GetPortfolioID2(order); field.PortfolioID3 = GetPortfolioID3(order); field.Business = GetBusiness(order); + + OpenClose2SubSide(ref field, order); } private void OnRtnOrder_callback(object sender, ref OrderField order) diff --git a/QuantBox.API.Provider/packages.config b/QuantBox.API.Provider/packages.config index 539b72e..e8a9e5a 100644 --- a/QuantBox.API.Provider/packages.config +++ b/QuantBox.API.Provider/packages.config @@ -1,5 +1,5 @@  - - + + \ No newline at end of file diff --git a/QuantBox.Extensions/QuantBox.Extensions.csproj b/QuantBox.Extensions/QuantBox.Extensions.csproj index bd56cfe..e1a4edd 100644 --- a/QuantBox.Extensions/QuantBox.Extensions.csproj +++ b/QuantBox.Extensions/QuantBox.Extensions.csproj @@ -34,10 +34,9 @@ - + False C:\Program Files\SmartQuant Ltd\OpenQuant 2014\SmartQuant.dll - False From c309a9a0d106f819318cc78dbaf7a57039da5ac9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Fri, 15 Sep 2017 13:38:23 +0800 Subject: [PATCH 02/41] =?UTF-8?q?=E8=A7=A3=E5=86=B3SubSide=E5=8F=91?= =?UTF-8?q?=E5=8D=95=E5=90=8E=E4=B8=8D=E8=83=BD=E4=BF=AE=E6=94=B9=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Single/SingleProvider.API.Order.cs | 124 +++++++++--------- .../SingleProvider.InstrumentProvider.cs | 18 +-- .../OrderExtensions_OpenCloseType.cs | 47 ++++++- 3 files changed, 117 insertions(+), 72 deletions(-) diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs b/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs index ac30c5b..5a30ab3 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs @@ -259,70 +259,70 @@ private void CmdNewOrderList(ExecutionCommand command) orderMap.DoOrderSend(ref fields, orders); } - private void SubSide2OpenClose(ref OrderField field, Order order) - { - // 由于无法指定平今与平昨,所以废弃 - if (framework.Configuration.UseSubPositions) - { - switch (order.SubSide) - { - case SubSide.Undefined: - field.OpenClose = order.Side == SQ.OrderSide.Buy ? OpenCloseType.Open : OpenCloseType.Close; - break; - case SubSide.BuyCover: - field.OpenClose = OpenCloseType.Close; - break; - case SubSide.SellShort: - field.OpenClose = OpenCloseType.Open; - break; - } - } - else - { - // 前面已经处理过了 - // field.OpenClose = GetOpenClose(order); - } - } + //private void SubSide2OpenClose(ref OrderField field, Order order) + //{ + // // 由于无法指定平今与平昨,所以废弃 + // if (framework.Configuration.UseSubPositions) + // { + // switch (order.SubSide) + // { + // case SubSide.Undefined: + // field.OpenClose = order.Side == SQ.OrderSide.Buy ? OpenCloseType.Open : OpenCloseType.Close; + // break; + // case SubSide.BuyCover: + // field.OpenClose = OpenCloseType.Close; + // break; + // case SubSide.SellShort: + // field.OpenClose = OpenCloseType.Open; + // break; + // } + // } + // else + // { + // // 前面已经处理过了 + // // field.OpenClose = GetOpenClose(order); + // } + //} - private void OpenClose2SubSide(ref OrderField field, Order order) - { - //多头 - //Buy 就是开 - //Sell 就是平 SubSide 是 Undefined + //private void OpenClose2SubSide(ref OrderField field, Order order) + //{ + // //多头 + // //Buy 就是开 + // //Sell 就是平 SubSide 是 Undefined - //空头 - //Sell 加 SubSide = SellShort 是开仓 - //Buy 加 SubSide = BuyCover 是平仓 + // //空头 + // //Sell 加 SubSide = SellShort 是开仓 + // //Buy 加 SubSide = BuyCover 是平仓 - // 由于使用官方的办法无法指定平今与平昨,所以还是用以前的开平仓的写法 - // 区别只是官方维护了双向持仓 - if (order.Side == SQ.OrderSide.Buy) - { - switch (field.OpenClose) - { - case OpenCloseType.Open: - order.SubSide = SubSide.Undefined; - break; - case OpenCloseType.Close: - case OpenCloseType.CloseToday: - order.SubSide = SubSide.BuyCover; - break; - } - } - else - { - switch (field.OpenClose) - { - case OpenCloseType.Open: - order.SubSide = SubSide.SellShort; - break; - case OpenCloseType.Close: - case OpenCloseType.CloseToday: - order.SubSide = SubSide.Undefined; - break; - } - } - } + // // 由于使用官方的办法无法指定平今与平昨,所以还是用以前的开平仓的写法 + // // 区别只是官方维护了双向持仓 + // if (order.Side == SQ.OrderSide.Buy) + // { + // switch (field.OpenClose) + // { + // case OpenCloseType.Open: + // order.SubSide = SubSide.Undefined; + // break; + // case OpenCloseType.Close: + // case OpenCloseType.CloseToday: + // order.SubSide = SubSide.BuyCover; + // break; + // } + // } + // else + // { + // switch (field.OpenClose) + // { + // case OpenCloseType.Open: + // order.SubSide = SubSide.SellShort; + // break; + // case OpenCloseType.Close: + // case OpenCloseType.CloseToday: + // order.SubSide = SubSide.Undefined; + // break; + // } + // } + //} private void ToOrderStruct(ref OrderField field, Order order, string apiSymbol, string apiExchange) { @@ -344,7 +344,7 @@ private void ToOrderStruct(ref OrderField field, Order order, string apiSymbol, field.PortfolioID3 = GetPortfolioID3(order); field.Business = GetBusiness(order); - OpenClose2SubSide(ref field, order); + //OpenClose2SubSide(ref field, order); } private void OnRtnOrder_callback(object sender, ref OrderField order) diff --git a/QuantBox.API.Provider/Single/SingleProvider.InstrumentProvider.cs b/QuantBox.API.Provider/Single/SingleProvider.InstrumentProvider.cs index 68dc26c..f6794c0 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.InstrumentProvider.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.InstrumentProvider.cs @@ -20,7 +20,7 @@ public override void Send(InstrumentDefinitionRequest request) private void ReturnInstrumentDefinition(InstrumentDefinitionRequest request) { - Dictionary> dict = new Dictionary>(); + Dictionary> dict = new Dictionary>(); List instruments = new List(); @@ -92,19 +92,19 @@ private void ReturnInstrumentDefinition(InstrumentDefinitionRequest request) description.Underlying = contract.UnderlyingInstrID; instrument.Description = JsonConvert.SerializeObject(description, description.GetType(), null); - - if(!string.IsNullOrWhiteSpace(contract.UnderlyingInstrID)) + + if (!string.IsNullOrWhiteSpace(contract.UnderlyingInstrID)) { // 要求先导入标的合约,再导入期权,如果在这里生成会丢失合约信息 Instrument UnderlyingInstrID = framework.InstrumentManager.Get(contract.UnderlyingInstrID); - if(UnderlyingInstrID == null) + if (UnderlyingInstrID == null) { //xlog.Warn("合约:{0},存在标的物字段,请先导入标的物合约{1},导入后放在Parent属性中", contract.Symbol, contract.UnderlyingInstrID); List list = null; - if(!dict.TryGetValue(contract.UnderlyingInstrID,out list)) + if (!dict.TryGetValue(contract.UnderlyingInstrID, out list)) { list = new List(); - dict.Add(contract.UnderlyingInstrID,list); + dict.Add(contract.UnderlyingInstrID, list); } list.Add(contract.Symbol); } @@ -120,6 +120,8 @@ private void ReturnInstrumentDefinition(InstrumentDefinitionRequest request) int yyyy = contract.ExpireDate / 10000; int MM = contract.ExpireDate % 10000 / 100; int dd = contract.ExpireDate % 100; + // 居然有期权传回来的到期时间没有日 + dd = Math.Max(dd, 1); instrument.Maturity = new DateTime(yyyy, MM, dd); } @@ -131,7 +133,7 @@ private void ReturnInstrumentDefinition(InstrumentDefinitionRequest request) instruments.Add(instrument); } - if(dict.Count>0) + if (dict.Count > 0) { xlog.Warn("标的物合约必须先导入,然后再Request,衍生品合约的Legs才会有一条记录指向标的物"); foreach (var kv in dict) @@ -141,7 +143,7 @@ private void ReturnInstrumentDefinition(InstrumentDefinitionRequest request) xlog.Warn("请将以上合约先导入"); xlog.Warn("如果在Request后列表中没有标的物合约,则需要手工添加"); } - + instruments.Sort(SortInstrument); diff --git a/QuantBox.Extensions/OrderExtensions_OpenCloseType.cs b/QuantBox.Extensions/OrderExtensions_OpenCloseType.cs index bcad954..b356826 100644 --- a/QuantBox.Extensions/OrderExtensions_OpenCloseType.cs +++ b/QuantBox.Extensions/OrderExtensions_OpenCloseType.cs @@ -32,6 +32,7 @@ public static Order CloseToday(this Order order) public static Order SetOpenClose(this Order order, OpenCloseType OpenClose) { + order.SubSide = order.OpenClose2SubSide(OpenClose); order.GetDictionary(index)[OrderTagType.PositionEffect] = (byte)OpenClose; return order; } @@ -39,11 +40,53 @@ public static Order SetOpenClose(this Order order, OpenCloseType OpenClose) public static OpenCloseType? GetOpenClose(this Order order) { object obj = order.GetDictionaryValue(OrderTagType.PositionEffect, index); - if(obj == null) + if (obj == null) { return (OpenCloseType?)obj; } return (OpenCloseType?)(byte)obj; } - } + + public static SubSide OpenClose2SubSide(this Order order, OpenCloseType OpenClose) + { + //多头 + //Buy 就是开 + //Sell 就是平 SubSide 是 Undefined + + //空头 + //Sell 加 SubSide = SellShort 是开仓 + //Buy 加 SubSide = BuyCover 是平仓 + + // 由于使用官方的办法无法指定平今与平昨,所以还是用以前的开平仓的写法 + // 区别只是官方维护了双向持仓 + if (order.Side == SmartQuant.OrderSide.Buy) + { + switch (OpenClose) + { + case OpenCloseType.Open: + order.SubSide = SubSide.Undefined; + break; + case OpenCloseType.Close: + case OpenCloseType.CloseToday: + order.SubSide = SubSide.BuyCover; + break; + } + } + else + { + switch (OpenClose) + { + case OpenCloseType.Open: + order.SubSide = SubSide.SellShort; + break; + case OpenCloseType.Close: + case OpenCloseType.CloseToday: + order.SubSide = SubSide.Undefined; + break; + } + } + + return order.SubSide; + } + } } From 57c4eaa24977a6d3c8e2c532c4f72649e1b86119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Wed, 8 Nov 2017 15:30:55 +0800 Subject: [PATCH 03/41] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=A4=E6=98=93?= =?UTF-8?q?=E6=89=80=E7=8A=B6=E6=80=81=E6=96=B0=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../QuantBox.APIProvider.csproj | 2 +- QuantBox.API.Provider/Single/BaseMap.cs | 18 ++--- QuantBox.API.Provider/Single/OrderMap.cs | 78 ++++++++++++------ .../Single/SingleProvider.API.Connection.cs | 3 +- .../Single/SingleProvider.API.Order.cs | 79 ++----------------- .../Single/SingleProvider.API.cs | 36 ++++++++- QuantBox.API.Provider/packages.config | 2 +- 7 files changed, 111 insertions(+), 107 deletions(-) diff --git a/QuantBox.API.Provider/QuantBox.APIProvider.csproj b/QuantBox.API.Provider/QuantBox.APIProvider.csproj index 9078bb6..62d2404 100644 --- a/QuantBox.API.Provider/QuantBox.APIProvider.csproj +++ b/QuantBox.API.Provider/QuantBox.APIProvider.csproj @@ -36,7 +36,7 @@ True - ..\packages\NLog.4.4.11\lib\net45\NLog.dll + ..\packages\NLog.4.4.12\lib\net45\NLog.dll True diff --git a/QuantBox.API.Provider/Single/BaseMap.cs b/QuantBox.API.Provider/Single/BaseMap.cs index fbd8ac0..7f045b5 100644 --- a/QuantBox.API.Provider/Single/BaseMap.cs +++ b/QuantBox.API.Provider/Single/BaseMap.cs @@ -27,20 +27,20 @@ public ExecutionReport CreateReport( SQ.ExecType? execType, SQ.OrderStatus? orderStatus) { - ExecutionReport report = new ExecutionReport(); + ExecutionReport report = new ExecutionReport(record.Order); report.DateTime = framework.Clock.DateTime; - report.Order = record.Order; - report.Instrument = record.Order.Instrument; + //report.Order = record.Order; + //report.Instrument = record.Order.Instrument; - report.Side = record.Order.Side; - report.OrdType = record.Order.Type; - report.TimeInForce = record.Order.TimeInForce; + //report.Side = record.Order.Side; + //report.OrdType = record.Order.Type; + //report.TimeInForce = record.Order.TimeInForce; - report.OrdQty = record.Order.Qty; - report.Price = record.Order.Price; - report.StopPx = record.Order.StopPx; + //report.OrdQty = record.Order.Qty; + //report.Price = record.Order.Price; + //report.StopPx = record.Order.StopPx; report.AvgPx = record.AvgPx; report.CumQty = record.CumQty; diff --git a/QuantBox.API.Provider/Single/OrderMap.cs b/QuantBox.API.Provider/Single/OrderMap.cs index 434d470..926e71f 100644 --- a/QuantBox.API.Provider/Single/OrderMap.cs +++ b/QuantBox.API.Provider/Single/OrderMap.cs @@ -25,8 +25,10 @@ class OrderMap : BaseMap private OrderRecord GetExternalOrder(ref TradeField field) { ExternalOrderRecord record; - if (externalOrders.TryGetValue(field.InstrumentID, out record)) { - if (field.OpenClose == OpenCloseType.Open) { + if (externalOrders.TryGetValue(field.InstrumentID, out record)) + { + if (field.OpenClose == OpenCloseType.Open) + { return field.Side == XAPI.OrderSide.Buy ? record.BuyOpen : record.SellOpen; } return field.Side == XAPI.OrderSide.Buy ? record.BuyClose : record.SellClose; @@ -38,21 +40,25 @@ private void SetExternalOrder(Order order, ref OrderField field) var orderRecord = new OrderRecord(order); ExternalOrderRecord record = new ExternalOrderRecord(); record = externalOrders.GetOrAdd(order.Instrument.Symbol, record); - if (field.OpenClose == OpenCloseType.Open) { + if (field.OpenClose == OpenCloseType.Open) + { if (field.Side == XAPI.OrderSide.Buy) { record.BuyOpen = orderRecord; } - else { + else + { record.SellOpen = orderRecord; } } - else { + else + { if (field.Side == XAPI.OrderSide.Buy) { record.BuyClose = orderRecord; } - else { + else + { record.SellClose = orderRecord; } } @@ -77,10 +83,12 @@ public void Clear() public void DoOrderSend(ref OrderField[] ordersArray, Order order) { - if (Convert.ToInt32(order.Qty) == int.MaxValue) { + if (Convert.ToInt32(order.Qty) == int.MaxValue) + { SetExternalOrder(order, ref ordersArray[0]); } - else { + else + { DoOrderSend(ref ordersArray, new List() { order }); } } @@ -101,6 +109,7 @@ public void DoOrderSend(ref OrderField[] ordersArray, List ordersList) } else { + //Console.WriteLine(orderId); this.pendingOrders.TryAdd(orderId, new OrderRecord(ordersList[i])); // 记下了本地ID,用于立即撤单时供API来定位 this.orderIDs.Add(ordersList[i].Id, orderId); @@ -120,13 +129,17 @@ public void DoOrderCancel(List ordersList) OrderRecord[] recordList = new OrderRecord[ordersList.Count]; string[] OrderIds = new string[ordersList.Count]; - for (int i = 0; i < ordersList.Count; ++i) { + for (int i = 0; i < ordersList.Count; ++i) + { // 如果需要下单的过程中撤单,这里有可能返回LocalID或ID - if (orderIDs.TryGetValue(ordersList[i].Id, out OrderIds[i])) { - if (this.workingOrders.TryGetValue(OrderIds[i], out recordList[i])) { + if (orderIDs.TryGetValue(ordersList[i].Id, out OrderIds[i])) + { + if (this.workingOrders.TryGetValue(OrderIds[i], out recordList[i])) + { pendingCancels[OrderIds[i]] = recordList[i]; } - }else if (ordersList[i].Fields[9] != null) + } + else if (ordersList[i].Fields[9] != null) { OrderIds[i] = (string)ordersList[i].Fields[9]; recordList[i] = new OrderRecord(ordersList[i]); @@ -142,14 +155,17 @@ public void DoOrderCancel(List ordersList) { if (!string.IsNullOrEmpty(e) && e != "0") { - EmitExecutionReport(recordList[i], SQ.ExecType.ExecCancelReject, recordList[i].Order.Status, "ErrorCode:" + e); + if(recordList[i] != null) + { + EmitExecutionReport(recordList[i], SQ.ExecType.ExecCancelReject, recordList[i].Order.Status, "ErrorCode:" + e); + } } ++i; } } } - public void Process(ref OrderField order) + public void Process(ref OrderField order, NLog.Logger log) { // 所有的成交信息都不处理,交给TradeField处理 if (order.ExecType == XAPI.ExecType.Trade) @@ -157,14 +173,20 @@ public void Process(ref OrderField order) OrderRecord record; - switch (order.ExecType) { + switch (order.ExecType) + { case XAPI.ExecType.New: - if (this.pendingOrders.TryRemove(order.LocalID, out record)) { + if (this.pendingOrders.TryRemove(order.LocalID, out record)) + { this.workingOrders.Add(order.ID, record); // 将LocalID更新为ID this.orderIDs[record.Order.Id] = order.ID; EmitExecutionReport(record, (SQ.ExecType)order.ExecType, (SQ.OrderStatus)order.Status); } + else + { + //log.Warn("New,找不到订单,pendingOrders.Count={0}", pendingOrders.Count); + } break; case XAPI.ExecType.Rejected: if (this.pendingOrders.TryRemove(order.LocalID, out record)) @@ -172,7 +194,8 @@ public void Process(ref OrderField order) orderIDs.Remove(record.Order.Id); EmitExecutionReport(record, (SQ.ExecType)order.ExecType, (SQ.OrderStatus)order.Status, order.Text()); } - else if (this.workingOrders.TryGetValue(order.ID, out record)) { + else if (this.workingOrders.TryGetValue(order.ID, out record)) + { // 比如说出现超出涨跌停时,先会到ProcessNew,所以得再多判断一次 workingOrders.Remove(order.ID); orderIDs.Remove(record.Order.Id); @@ -180,7 +203,8 @@ public void Process(ref OrderField order) } break; case XAPI.ExecType.Cancelled: - if (this.workingOrders.TryGetValue(order.ID, out record)) { + if (this.workingOrders.TryGetValue(order.ID, out record)) + { workingOrders.Remove(order.ID); orderIDs.Remove(record.Order.Id); EmitExecutionReport(record, SQ.ExecType.ExecCancelled, SQ.OrderStatus.Cancelled); @@ -192,25 +216,29 @@ public void Process(ref OrderField order) } break; case XAPI.ExecType.PendingCancel: - if (this.workingOrders.TryGetValue(order.ID, out record)) { + if (this.workingOrders.TryGetValue(order.ID, out record)) + { EmitExecutionReport(record, SQ.ExecType.ExecPendingCancel, SQ.OrderStatus.PendingCancel); } break; case XAPI.ExecType.CancelReject: - if (this.pendingCancels.TryRemove(order.ID, out record)) { + if (this.pendingCancels.TryRemove(order.ID, out record)) + { EmitExecutionReport(record, SQ.ExecType.ExecCancelReject, (SQ.OrderStatus)order.Status, order.Text()); } break; } } - public void Process(ref TradeField trade) + public void Process(ref TradeField trade, NLog.Logger log) { OrderRecord record; - if (!workingOrders.TryGetValue(trade.ID, out record)) { + if (!workingOrders.TryGetValue(trade.ID, out record)) + { record = GetExternalOrder(ref trade); } - if (record != null) { + if (record != null) + { record.AddFill(trade.Price, (int)trade.Qty); SQ.ExecType execType = SQ.ExecType.ExecTrade; SQ.OrderStatus orderStatus = (record.LeavesQty > 0) ? SQ.OrderStatus.PartiallyFilled : SQ.OrderStatus.Filled; @@ -219,6 +247,10 @@ record = GetExternalOrder(ref trade); report.LastQty = trade.Qty; provider.EmitExecutionReport(report); } + else + { + log.Warn("Trade,找不到订单,workingOrders.Count={0}", workingOrders.Count); + } } public void ProcessNew(ref QuoteField quote, QuoteRecord record) diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs b/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs index b3f066e..d630237 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs @@ -412,7 +412,8 @@ private XApi ConnectToApi(ApiItem item) api.OnRspQryHistoricalTicks = OnRspQryHistoricalTicks_callback; api.OnRspQryHistoricalBars = OnRspQryHistoricalBars_callback; - api.OnRspQrySettlementInfo = OnRspQrySettlementInfo; + api.OnRspQrySettlementInfo = OnRspQrySettlementInfo_callback; + api.OnRtnInstrumentStatus = OnRtnInstrumentStatus_callback; api.Connect(); diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs b/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs index 5a30ab3..84454fe 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs @@ -259,71 +259,6 @@ private void CmdNewOrderList(ExecutionCommand command) orderMap.DoOrderSend(ref fields, orders); } - //private void SubSide2OpenClose(ref OrderField field, Order order) - //{ - // // 由于无法指定平今与平昨,所以废弃 - // if (framework.Configuration.UseSubPositions) - // { - // switch (order.SubSide) - // { - // case SubSide.Undefined: - // field.OpenClose = order.Side == SQ.OrderSide.Buy ? OpenCloseType.Open : OpenCloseType.Close; - // break; - // case SubSide.BuyCover: - // field.OpenClose = OpenCloseType.Close; - // break; - // case SubSide.SellShort: - // field.OpenClose = OpenCloseType.Open; - // break; - // } - // } - // else - // { - // // 前面已经处理过了 - // // field.OpenClose = GetOpenClose(order); - // } - //} - - //private void OpenClose2SubSide(ref OrderField field, Order order) - //{ - // //多头 - // //Buy 就是开 - // //Sell 就是平 SubSide 是 Undefined - - // //空头 - // //Sell 加 SubSide = SellShort 是开仓 - // //Buy 加 SubSide = BuyCover 是平仓 - - // // 由于使用官方的办法无法指定平今与平昨,所以还是用以前的开平仓的写法 - // // 区别只是官方维护了双向持仓 - // if (order.Side == SQ.OrderSide.Buy) - // { - // switch (field.OpenClose) - // { - // case OpenCloseType.Open: - // order.SubSide = SubSide.Undefined; - // break; - // case OpenCloseType.Close: - // case OpenCloseType.CloseToday: - // order.SubSide = SubSide.BuyCover; - // break; - // } - // } - // else - // { - // switch (field.OpenClose) - // { - // case OpenCloseType.Open: - // order.SubSide = SubSide.SellShort; - // break; - // case OpenCloseType.Close: - // case OpenCloseType.CloseToday: - // order.SubSide = SubSide.Undefined; - // break; - // } - // } - //} - private void ToOrderStruct(ref OrderField field, Order order, string apiSymbol, string apiExchange) { field.InstrumentID = apiSymbol; @@ -349,27 +284,29 @@ private void ToOrderStruct(ref OrderField field, Order order, string apiSymbol, private void OnRtnOrder_callback(object sender, ref OrderField order) { - (sender as XApi).GetLog().Debug("OnRtnOrder:" + order.ToFormattedString()); + var log = (sender as XApi).GetLog(); + log.Debug("OnRtnOrder:" + order.ToFormattedString()); try { - orderMap.Process(ref order); + orderMap.Process(ref order, log); } catch (Exception ex) { - (sender as XApi).GetLog().Error(ex); + log.Error(ex); } } private void OnRtnTrade_callback(object sender, ref TradeField trade) { - (sender as XApi).GetLog().Debug("OnRtnTrade:" + trade.ToFormattedString()); + var log = (sender as XApi).GetLog(); + log.Debug("OnRtnTrade:" + trade.ToFormattedString()); try { - orderMap.Process(ref trade); + orderMap.Process(ref trade, log); } catch (Exception ex) { - (sender as XApi).GetLog().Error(ex); + log.Error(ex); } } } diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.cs b/QuantBox.API.Provider/Single/SingleProvider.API.cs index 97330b1..b42e76a 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.cs @@ -19,8 +19,13 @@ public partial class SingleProvider static SingleProvider() { NLog.LogManager.Configuration = new NLog.Config.XmlLoggingConfiguration(Path.Combine(PathHelper.RootPath.LocalPath, "NLog.config"), true); } + public DelegateOnRspQryInvestorPosition OnRspQryInvestorPosition { get; set; } + public DelegateOnRspQryTradingAccount OnRspQryTradingAccount { get; set; } + public DelegateOnRtnInstrumentStatus OnRtnInstrumentStatus { get; set; } + //记录合约列表,从实盘合约名到对象的映射 private readonly Dictionary _dictInstruments = new Dictionary(); + private readonly Dictionary _dictInstrumentsStatus = new Dictionary(); public static int GetDate(DateTime dt) { @@ -62,6 +67,10 @@ private void OnRspQryInstrument_callback(object sender, ref InstrumentField inst private void OnRspQryTradingAccount_callback(object sender, ref AccountField account, int size1, bool bIsLast) { + // 由策略来收回报 + if (OnRspQryTradingAccount != null) + OnRspQryTradingAccount(sender, ref account, size1, bIsLast); + if (size1 <= 0) { (sender as XApi).GetLog().Info("OnRspQryTradingAccount"); @@ -112,6 +121,10 @@ private void OnRspQryInvestor_callback(object sender, ref InvestorField investor private void OnRspQryInvestorPosition_callback(object sender, ref PositionField position, int size1, bool bIsLast) { + // 由策略来收回报 + if (OnRspQryInvestorPosition != null) + OnRspQryInvestorPosition(sender, ref position, size1, bIsLast); + if (size1 <= 0) { (sender as XApi).GetLog().Info("OnRspQryInvestorPosition"); @@ -153,7 +166,7 @@ private void OnRspQryInvestorPosition_callback(object sender, ref PositionField } } - private void OnRspQrySettlementInfo(object sender, ref SettlementInfoClass settlementInfo, int size1, bool bIsLast) + private void OnRspQrySettlementInfo_callback(object sender, ref SettlementInfoClass settlementInfo, int size1, bool bIsLast) { if (size1 <= 0) { @@ -200,5 +213,26 @@ private void OnRspQryOrder_callback(object sender, ref OrderField order, int siz (sender as XApi).GetLog().Info("OnRspQryOrder:" + order.ToFormattedString()); } + + private void OnRtnInstrumentStatus_callback(object sender, ref InstrumentStatusField instrumentStatus) + { + if (OnRtnInstrumentStatus != null) + OnRtnInstrumentStatus(sender, ref instrumentStatus); + + // 记录下来,后期可能要用到 + _dictInstrumentsStatus[instrumentStatus.Symbol] = instrumentStatus; + + (sender as XApi).GetLog().Info("OnRtnInstrumentStatus:" + instrumentStatus.ToFormattedString()); + } + + public InstrumentStatusField GetInstrumentStatus(string symbol) + { + InstrumentStatusField instrumentStatus; + if(_dictInstrumentsStatus.TryGetValue(symbol,out instrumentStatus)) + { + return instrumentStatus; + } + return instrumentStatus; + } } } diff --git a/QuantBox.API.Provider/packages.config b/QuantBox.API.Provider/packages.config index e8a9e5a..524b16d 100644 --- a/QuantBox.API.Provider/packages.config +++ b/QuantBox.API.Provider/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file From 68ca17ebcd2bb59505d38e0f1a4b936d5ae22e51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Wed, 8 Nov 2017 15:49:53 +0800 Subject: [PATCH 04/41] =?UTF-8?q?=E6=B3=A8=E9=87=8A=E5=A4=9A=E4=BD=99?= =?UTF-8?q?=E8=BE=93=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QuantBox.API.Provider/Single/OrderMap.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/QuantBox.API.Provider/Single/OrderMap.cs b/QuantBox.API.Provider/Single/OrderMap.cs index 926e71f..32a1c36 100644 --- a/QuantBox.API.Provider/Single/OrderMap.cs +++ b/QuantBox.API.Provider/Single/OrderMap.cs @@ -249,7 +249,7 @@ record = GetExternalOrder(ref trade); } else { - log.Warn("Trade,找不到订单,workingOrders.Count={0}", workingOrders.Count); + // log.Warn("Trade,找不到订单,workingOrders.Count={0}", workingOrders.Count); } } From 3c8140b917e0843375210441f7ed140985dd1c06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Mon, 27 Nov 2017 17:25:12 +0800 Subject: [PATCH 05/41] =?UTF-8?q?=E5=8A=A0=E5=85=A5OnLevel2Snapshot?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Properties/AssemblyInfo.cs | 4 +- .../QuantBox.APIProvider.csproj | 1 + .../Single/NoTypeConverterJsonConverter.cs | 44 ++++++++++++ .../Single/SessionTimeItem.cs | 28 ++++---- .../Single/SingleProvider.API.Connection.cs | 3 + .../SingleProvider.API.HistoricalData.cs | 4 +- .../Single/SingleProvider.API.MarketData.cs | 68 ++++++++++++++++++- .../Single/SingleProvider.Provider.cs | 7 +- .../Single/SingleProvider.Settings.cs | 10 ++- 9 files changed, 146 insertions(+), 23 deletions(-) create mode 100644 QuantBox.API.Provider/Single/NoTypeConverterJsonConverter.cs diff --git a/QuantBox.API.Provider/Properties/AssemblyInfo.cs b/QuantBox.API.Provider/Properties/AssemblyInfo.cs index 30febab..1f25849 100644 --- a/QuantBox.API.Provider/Properties/AssemblyInfo.cs +++ b/QuantBox.API.Provider/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.9.8.4")] -[assembly: AssemblyFileVersion("0.9.8.4")] \ No newline at end of file +[assembly: AssemblyVersion("0.9.8.5")] +[assembly: AssemblyFileVersion("0.9.8.5")] \ No newline at end of file diff --git a/QuantBox.API.Provider/QuantBox.APIProvider.csproj b/QuantBox.API.Provider/QuantBox.APIProvider.csproj index 62d2404..6c37973 100644 --- a/QuantBox.API.Provider/QuantBox.APIProvider.csproj +++ b/QuantBox.API.Provider/QuantBox.APIProvider.csproj @@ -77,6 +77,7 @@ + diff --git a/QuantBox.API.Provider/Single/NoTypeConverterJsonConverter.cs b/QuantBox.API.Provider/Single/NoTypeConverterJsonConverter.cs new file mode 100644 index 0000000..280c123 --- /dev/null +++ b/QuantBox.API.Provider/Single/NoTypeConverterJsonConverter.cs @@ -0,0 +1,44 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace QuantBox.APIProvider.Single +{ + public class NoTypeConverterJsonConverter : JsonConverter + { + static readonly IContractResolver resolver = new NoTypeConverterContractResolver(); + + class NoTypeConverterContractResolver : DefaultContractResolver + { + protected override JsonContract CreateContract(Type objectType) + { + if (typeof(T).IsAssignableFrom(objectType)) + { + var contract = this.CreateObjectContract(objectType); + contract.Converter = null; // Also null out the converter to prevent infinite recursion. + return contract; + } + return base.CreateContract(objectType); + } + } + + public override bool CanConvert(Type objectType) + { + return typeof(T).IsAssignableFrom(objectType); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + return JsonSerializer.CreateDefault(new JsonSerializerSettings { ContractResolver = resolver }).Deserialize(reader, objectType); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + JsonSerializer.CreateDefault(new JsonSerializerSettings { ContractResolver = resolver }).Serialize(writer, value); + } + } +} diff --git a/QuantBox.API.Provider/Single/SessionTimeItem.cs b/QuantBox.API.Provider/Single/SessionTimeItem.cs index 521a066..069f94c 100644 --- a/QuantBox.API.Provider/Single/SessionTimeItem.cs +++ b/QuantBox.API.Provider/Single/SessionTimeItem.cs @@ -1,4 +1,5 @@ -using OrderedPropertyGrid; +using Newtonsoft.Json; +using OrderedPropertyGrid; using System; using System.Collections.Generic; using System.ComponentModel; @@ -9,28 +10,29 @@ namespace QuantBox.APIProvider.Single { // 发现想让属性显示排序,但发现Json转换出问题了,所以还是决定不排序了 - //[TypeConverter(typeof(PropertySorter))] + [TypeConverter(typeof(PropertySorter))] + [JsonConverter(typeof(NoTypeConverterJsonConverter))] public class SessionTimeItem { [PropertyOrder(1)] public TimeSpan SessionStart { get; set; } [PropertyOrder(2)] public TimeSpan SessionEnd { get; set; } - //[PropertyOrder(3)] - //public bool Enable { get; set; } + [PropertyOrder(3)] + public bool Enable { get; set; } public override string ToString() { - return string.Format("Start={0};End={1}", this.SessionStart, this.SessionEnd); - //if (Enable) - //{ - // return string.Format("[+]Start={0};End={1}", this.SessionStart, this.SessionEnd); - //} - //else - //{ + //return string.Format("Start={0};End={1}", this.SessionStart, this.SessionEnd); + if (Enable) + { + return string.Format("+|Start={0};End={1}", this.SessionStart, this.SessionEnd); + } + else + { - // return string.Format("[-]Start={0};End={1}", this.SessionStart, this.SessionEnd); - //} + return string.Format("-|Start={0};End={1}", this.SessionStart, this.SessionEnd); + } } } } diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs b/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs index d630237..e1b6831 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs @@ -156,6 +156,9 @@ void _Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) // 如果当前时间在交易范围内,要开启重连 // 如果当前时间不在交易范围内,要主动断开 TimeSpan ts = e.SignalTime.TimeOfDay; + if (!st.Enable) + continue; + if (ts < st.SessionStart) { // 停 diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.HistoricalData.cs b/QuantBox.API.Provider/Single/SingleProvider.API.HistoricalData.cs index 998543a..987ed00 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.HistoricalData.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.HistoricalData.cs @@ -155,7 +155,7 @@ private void OnRspQryHistoricalTicks_callback(object sender, IntPtr pTicks, int volume = obj.Volume; } - if(EnableEmitHistoricalData) + if(EmitHistoricalData) { HistoricalData data = new HistoricalData { @@ -217,7 +217,7 @@ private void OnRspQryHistoricalBars_callback(object sender, IntPtr pBars, int si } } - if(EnableEmitHistoricalData) + if(EmitHistoricalData) { HistoricalData data = new HistoricalData { diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.MarketData.cs b/QuantBox.API.Provider/Single/SingleProvider.API.MarketData.cs index 901ca92..50d4d5b 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.MarketData.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.MarketData.cs @@ -68,6 +68,11 @@ private void OnRtnDepthMarketData_callback(object sender, ref DepthMarketDataNCl FireAsk(record.Instrument.Id, _dateTime, _exchangeDateTime, pDepthMarketData, depthMarket); } } + + if (_emitLevel2Snapshot) + { + FireLevel2Snapshot(record.Instrument.Id, _dateTime, _exchangeDateTime, pDepthMarketData, depthMarket); + } } catch (Exception ex) { @@ -75,7 +80,7 @@ private void OnRtnDepthMarketData_callback(object sender, ref DepthMarketDataNCl } } - private void FireTrade(int InstrumentId,DateTime _dateTime, DateTime _exchangeDateTime, DepthMarketDataNClass pDepthMarketData,DepthMarketDataNClass DepthMarket) + private void FireTrade(int InstrumentId, DateTime _dateTime, DateTime _exchangeDateTime, DepthMarketDataNClass pDepthMarketData, DepthMarketDataNClass DepthMarket) { //行情过来时是今天累计成交量,得转换成每个tick中成交量之差 double volume = pDepthMarketData.Volume - DepthMarket.Volume; @@ -98,13 +103,72 @@ private void FireTrade(int InstrumentId,DateTime _dateTime, DateTime _exchangeDa this.id, InstrumentId, pDepthMarketData.LastPrice, - (int) volume) {DepthMarketData = pDepthMarketData}; + (int)volume) + { DepthMarketData = pDepthMarketData }; // 启用底层数据上传 EmitData(trade); } + private void FireLevel2Snapshot(int InstrumentId, DateTime _dateTime, DateTime _exchangeDateTime, DepthMarketDataNClass pDepthMarketData, DepthMarketDataNClass DepthMarket) + { + //行情过来时是今天累计成交量,得转换成每个tick中成交量之差 + double volume = pDepthMarketData.Volume - DepthMarket.Volume; + // 以前第一条会导致集合竞价后的第一条没有成交量,这种方法就明确了上一笔是空数据 + if (0 == DepthMarket.TradingDay && 0 == DepthMarket.ActionDay) + { + //没有接收到最开始的一条,所以这计算每个Bar的数据时肯定超大,强行设置为0 + volume = 0; + } + else if (volume < 0) + { + //如果隔夜运行,会出现今早成交量0-昨收盘成交量,出现负数,所以当发现为负时要修改 + volume = pDepthMarketData.Volume; + } + + List bids = new List(); + if (pDepthMarketData.Bids != null) + { + foreach (var d in pDepthMarketData.Bids) + { + Bid bid = new Bid( + _dateTime, + _exchangeDateTime, + this.id, + InstrumentId, + d.Price, + d.Size); + bids.Add(bid); + } + } + + List asks = new List(); + if (pDepthMarketData.Asks != null) + { + foreach (var d in pDepthMarketData.Asks) + { + Ask ask = new Ask( + _dateTime, + _exchangeDateTime, + this.id, + InstrumentId, + d.Price, + d.Size); + asks.Add(ask); + } + } + + var l2s = new Level2Snapshot(_dateTime, _exchangeDateTime, this.id, InstrumentId, bids.ToArray(), asks.ToArray()) + { + + }; + + // 启用底层数据上传 + + EmitData(l2s); + } + private void FireBid(int InstrumentId, DateTime _dateTime, DateTime _exchangeDateTime, DepthMarketDataNClass pDepthMarketData, DepthMarketDataNClass DepthMarket) { do diff --git a/QuantBox.API.Provider/Single/SingleProvider.Provider.cs b/QuantBox.API.Provider/Single/SingleProvider.Provider.cs index 8b9694a..c38d7b9 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.Provider.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.Provider.cs @@ -64,8 +64,9 @@ public void Init(byte id, string name) // 以下初始化的值在,初始化后由软件读取文件中的参数据后又设置回来 LastPricePlusNTicks = 10; EmitBidAsk = true; + EmitLevel2Snapshot = false; //UpdateInstrument = true; - EnableEmitHistoricalData = true; + EmitHistoricalData = true; FilterDateTime = true; EnableEmitData = true; HasPriceLimit = true; @@ -188,7 +189,7 @@ private void Load() private int _QueryAccountCount = 0; private int _QueryPositionCount = 0; - public override void Connect() + protected override void OnConnect() { _QueryAccountCount = _QueryAccountInterval; _QueryPositionCount = _QueryPositionInterval; @@ -203,7 +204,7 @@ public override void Connect() xlog.Info("重连检测定时器开启,检测频率(毫秒):{0}", _Timer.Interval); _Connect(true); } - public override void Disconnect() + protected override void OnDisconnect() { // 关闭重连定时器 _Timer.Elapsed -= _Timer_Elapsed; diff --git a/QuantBox.API.Provider/Single/SingleProvider.Settings.cs b/QuantBox.API.Provider/Single/SingleProvider.Settings.cs index 21cb19e..70ff1b4 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.Settings.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.Settings.cs @@ -26,6 +26,7 @@ public partial class SingleProvider : Provider private bool _enableEmitData; private bool _emitBidAsk; private bool _emitBidAskFirst; + private bool _emitLevel2Snapshot; #region 行情配置 @@ -54,6 +55,13 @@ public bool EmitBidAskFirst get { return _emitBidAskFirst; } set { _emitBidAskFirst = value; } } + [Category(CATEGORY_MARKETDATA)] + [Description("【行情】触发OnLevel2Snapshot事件")] + public bool EmitLevel2Snapshot + { + get { return _emitLevel2Snapshot; } + set { _emitLevel2Snapshot = value; } + } #endregion @@ -173,7 +181,7 @@ public string ConfigPath [Category(CATEGORY_HISTORICAL_DATA)] [Description("【历史】是否触发EmitHistoricalData事件")] [DisplayName("EmitHistoricalData")] - public bool EnableEmitHistoricalData { get; set; } + public bool EmitHistoricalData { get; set; } [Category(CATEGORY_HISTORICAL_DATA)] [Description("【历史】是否过滤数据日期和时间")] From a2a846235701e822edc0c3a37b89f0b35211a9f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Mon, 27 Nov 2017 17:47:30 +0800 Subject: [PATCH 06/41] =?UTF-8?q?=E6=8E=92=E9=99=A4=E4=BC=9A=E8=AF=9D?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E5=88=97=E8=A1=A8=E9=83=BD=E4=B8=BA=E7=A9=BA?= =?UTF-8?q?=E7=9A=84=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Single/SingleProvider.API.Connection.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs b/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs index e1b6831..4dd9637 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs @@ -147,11 +147,15 @@ void _Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) if (SessionTimeList == null || SessionTimeList.Count == 0) break; + var stl = SessionTimeList.Where(x => x.Enable).ToList(); + if (stl.Count == 0) + break; + bool bTryConnect = true; SessionTimeItem st_current = null; SessionTimeItem st_next = null; - foreach (var st in SessionTimeList.ToList()) + foreach (var st in stl) { // 如果当前时间在交易范围内,要开启重连 // 如果当前时间不在交易范围内,要主动断开 From 9adf74c44a681a28dca8a81cdf6696fa5b3a9ed3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Tue, 28 Nov 2017 13:13:03 +0800 Subject: [PATCH 07/41] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E9=A1=BA=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Single/SingleProvider.API.cs | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.cs b/QuantBox.API.Provider/Single/SingleProvider.API.cs index b42e76a..486357c 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.cs @@ -67,17 +67,21 @@ private void OnRspQryInstrument_callback(object sender, ref InstrumentField inst private void OnRspQryTradingAccount_callback(object sender, ref AccountField account, int size1, bool bIsLast) { + if (size1 <= 0) + { + (sender as XApi).GetLog().Info("OnRspQryTradingAccount"); + } + else + { + (sender as XApi).GetLog().Info("OnRspQryTradingAccount:" + account.ToFormattedString()); + } + // 由策略来收回报 if (OnRspQryTradingAccount != null) OnRspQryTradingAccount(sender, ref account, size1, bIsLast); if (size1 <= 0) - { - (sender as XApi).GetLog().Info("OnRspQryTradingAccount"); return; - } - - (sender as XApi).GetLog().Info("OnRspQryTradingAccount:" + account.ToFormattedString()); if (!IsConnected) return; @@ -121,17 +125,21 @@ private void OnRspQryInvestor_callback(object sender, ref InvestorField investor private void OnRspQryInvestorPosition_callback(object sender, ref PositionField position, int size1, bool bIsLast) { + if (size1 <= 0) + { + (sender as XApi).GetLog().Info("OnRspQryInvestorPosition"); + } + else + { + (sender as XApi).GetLog().Info("OnRspQryInvestorPosition:" + position.ToFormattedString()); + } + // 由策略来收回报 if (OnRspQryInvestorPosition != null) OnRspQryInvestorPosition(sender, ref position, size1, bIsLast); if (size1 <= 0) - { - (sender as XApi).GetLog().Info("OnRspQryInvestorPosition"); return; - } - - (sender as XApi).GetLog().Info("OnRspQryInvestorPosition:" + position.ToFormattedString()); if (!IsConnected) return; From 10378441a13fcf3adabf2bfe2b89da64e927d581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Thu, 30 Nov 2017 10:45:50 +0800 Subject: [PATCH 08/41] =?UTF-8?q?=E5=8A=A0=E5=85=A5=E8=BE=93=E5=87=BA?= =?UTF-8?q?=E8=AE=A2=E5=8D=95=E4=BA=8B=E4=BB=B6=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Single/SingleProvider.API.Order.cs | 51 ++++--------------- .../Single/SingleProvider.API.cs | 35 +++++++++---- 2 files changed, 34 insertions(+), 52 deletions(-) diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs b/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs index 84454fe..232f469 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs @@ -18,46 +18,6 @@ namespace QuantBox.APIProvider.Single public partial class SingleProvider { #region 价格修正 - //public double FixPrice(double price, SmartQuant.OrderSide Side, double tickSize, double LowerLimitPrice, double UpperLimitPrice) - //{ - // //没有设置就直接用 - // if (tickSize > 0) - // { - // decimal remainder = ((decimal)price % (decimal)tickSize); - // if (remainder != 0) - // { - // if (Side == SmartQuant.OrderSide.Buy) - // { - // price = Math.Round(Math.Ceiling(price / tickSize) * tickSize, 6); - // } - // else - // { - // price = Math.Round(Math.Floor(price / tickSize) * tickSize, 6); - // } - // } - // else - // { - // //正好能整除,不操作 - // } - // } - - // if (0 == UpperLimitPrice - // && 0 == LowerLimitPrice) - // { - // //涨跌停无效 - - // } - // else - // { - // //防止价格超过涨跌停 - // if (price >= UpperLimitPrice) - // price = UpperLimitPrice; - // else if (price <= LowerLimitPrice) - // price = LowerLimitPrice; - // } - // return price; - //} - public double FixPrice(MarketDataRecord record, double price, SmartQuant.OrderSide Side, double tickSize) { double LowerLimitPrice = record.DepthMarket.LowerLimitPrice; @@ -224,7 +184,6 @@ private void CmdNewOrderSingle(ExecutionCommand command) } if (HasPriceLimit) { - //price = FixPrice(price, command.Side, apiTickSize, record.DepthMarket.LowerLimitPrice, record.DepthMarket.UpperLimitPrice); price = FixPrice(record, price, command.Side, apiTickSize); } @@ -286,6 +245,11 @@ private void OnRtnOrder_callback(object sender, ref OrderField order) { var log = (sender as XApi).GetLog(); log.Debug("OnRtnOrder:" + order.ToFormattedString()); + + // 由策略来收回报 + if (OnRtnOrder != null) + OnRtnOrder(sender, ref order); + try { orderMap.Process(ref order, log); @@ -300,6 +264,11 @@ private void OnRtnTrade_callback(object sender, ref TradeField trade) { var log = (sender as XApi).GetLog(); log.Debug("OnRtnTrade:" + trade.ToFormattedString()); + + // 由策略来收回报 + if (OnRtnTrade != null) + OnRtnTrade(sender, ref trade); + try { orderMap.Process(ref trade, log); diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.cs b/QuantBox.API.Provider/Single/SingleProvider.API.cs index 486357c..d57360e 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.cs @@ -16,12 +16,18 @@ namespace QuantBox.APIProvider.Single { public partial class SingleProvider { - static SingleProvider() { + static SingleProvider() + { NLog.LogManager.Configuration = new NLog.Config.XmlLoggingConfiguration(Path.Combine(PathHelper.RootPath.LocalPath, "NLog.config"), true); } public DelegateOnRspQryInvestorPosition OnRspQryInvestorPosition { get; set; } public DelegateOnRspQryTradingAccount OnRspQryTradingAccount { get; set; } public DelegateOnRtnInstrumentStatus OnRtnInstrumentStatus { get; set; } + public DelegateOnRtnOrder OnRtnOrder { get; set; } + public DelegateOnRtnTrade OnRtnTrade { get; set; } + + public DelegateOnRspQryOrder OnRspQryOrder { get; set; } + public DelegateOnRspQryTrade OnRspQryTrade { get; set; } //记录合约列表,从实盘合约名到对象的映射 private readonly Dictionary _dictInstruments = new Dictionary(); @@ -58,8 +64,8 @@ private void OnRspQryInstrument_callback(object sender, ref InstrumentField inst } _dictInstruments[instrument.Symbol] = instrument; - - if(bIsLast) + + if (bIsLast) { (sender as XApi).GetLog().Info("合约列表已经接收完成,共 {0} 条", _dictInstruments.Count); } @@ -156,7 +162,7 @@ private void OnRspQryInvestorPosition_callback(object sender, ref PositionField position.AccountID, this.id, this.id); ad.Fields.Add(AccountDataField.SYMBOL, item.Symbol); - ad.Fields.Add(AccountDataField.EXCHANGE,item.Exchange); + ad.Fields.Add(AccountDataField.EXCHANGE, item.Exchange); ad.Fields.Add(AccountDataField.QTY, item.Qty); ad.Fields.Add(AccountDataField.LONG_QTY, item.LongQty); ad.Fields.Add(AccountDataField.SHORT_QTY, item.ShortQty); @@ -205,10 +211,14 @@ private void OnRspQryTrade_callback(object sender, ref TradeField trade, int siz if (size1 <= 0) { (sender as XApi).GetLog().Info("OnRspQryTrade"); - return; - } - (sender as XApi).GetLog().Info("OnRspQryTrade:" + trade.ToFormattedString()); + } + else + { + (sender as XApi).GetLog().Info("OnRspQryTrade:" + trade.ToFormattedString()); + } + if (OnRspQryTrade != null) + OnRspQryTrade(this, ref trade, size1, bIsLast); } private void OnRspQryOrder_callback(object sender, ref OrderField order, int size1, bool bIsLast) @@ -216,10 +226,13 @@ private void OnRspQryOrder_callback(object sender, ref OrderField order, int siz if (size1 <= 0) { (sender as XApi).GetLog().Info("OnRspQryOrder"); - return; } - - (sender as XApi).GetLog().Info("OnRspQryOrder:" + order.ToFormattedString()); + else + { + (sender as XApi).GetLog().Info("OnRspQryOrder:" + order.ToFormattedString()); + } + if (OnRspQryOrder != null) + OnRspQryOrder(this, ref order, size1, bIsLast); } private void OnRtnInstrumentStatus_callback(object sender, ref InstrumentStatusField instrumentStatus) @@ -236,7 +249,7 @@ private void OnRtnInstrumentStatus_callback(object sender, ref InstrumentStatusF public InstrumentStatusField GetInstrumentStatus(string symbol) { InstrumentStatusField instrumentStatus; - if(_dictInstrumentsStatus.TryGetValue(symbol,out instrumentStatus)) + if (_dictInstrumentsStatus.TryGetValue(symbol, out instrumentStatus)) { return instrumentStatus; } From 5318c3166f8ebd72ff9bfd863267e1056d6a2df7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Thu, 18 Jan 2018 09:41:56 +0800 Subject: [PATCH 09/41] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=8A=A0=E8=BD=BDC#?= =?UTF-8?q?=E5=B0=81=E8=A3=85=E7=9A=84XAPI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QuantBox.API.Provider/Single/ApiItem.cs | 117 +++++++++--------- QuantBox.API.Provider/Single/Extensions.cs | 4 +- QuantBox.API.Provider/Single/OrderMap.cs | 2 +- QuantBox.API.Provider/Single/ServerItem.cs | 2 +- .../Single/SingleProvider.API.Connection.cs | 69 +++++------ .../Single/SingleProvider.API.Order.cs | 2 + .../Single/SingleProvider.Provider.cs | 2 +- QuantBox.API.Provider/Single/UserItem.cs | 2 +- QuantBox.API.Provider/UI/ApiControlForm.cs | 16 +-- .../UI/ApiTypeSelectorEditor.cs | 2 +- 10 files changed, 102 insertions(+), 116 deletions(-) diff --git a/QuantBox.API.Provider/Single/ApiItem.cs b/QuantBox.API.Provider/Single/ApiItem.cs index 5e75528..0130c56 100644 --- a/QuantBox.API.Provider/Single/ApiItem.cs +++ b/QuantBox.API.Provider/Single/ApiItem.cs @@ -1,6 +1,5 @@ using Newtonsoft.Json; using QuantBox.APIProvider.UI; -using XAPI.Callback; using System; using System.Collections.Generic; using System.ComponentModel; @@ -21,74 +20,70 @@ namespace QuantBox.APIProvider.Single public class ApiItem : ICloneable { public const string CATEGORY_INFO = "Information"; - public const string CATEGORY_Type = "Type"; + public const string CATEGORY_TYPE = "Type"; internal BindingList LinkedUserList; internal BindingList LinkedServerList; private string _dllPath; + private string _typeName; + + private IXApi CheckApi(string typeName,string dllPath) + { + if(string.IsNullOrEmpty(typeName)) + { + TypeName = "XAPI.Callback.XApi, XAPI_CSharp"; + return null; + } + var api = XApiHelper.CreateInstance(typeName, dllPath); + try + { + Type = api.GetApiTypes; + Name = api.GetApiName; + Version = api.GetApiVersion; + + // 取公共部分 + UseType = UseType & Type; + } + catch (Exception ex) + { + api = null; + Type = ApiType.None; + Name = ex.Message; + Version = "请使用depends检查一下是否缺少依赖"; + UseType = ApiType.None; + } + return api; + } [Editor(typeof(System.Windows.Forms.Design.FileNameEditor), typeof(System.Drawing.Design.UITypeEditor))] public string DllPath { - get { - if (ProviderHost.autoMakeRelativePath) - { - return PathHelper.MakeRelativePath(_dllPath); - } - else - { - return PathHelper.MakeAbsolutePath(_dllPath); - } + get + { + return _dllPath; } set { - string tmp_dllPath; - if (ProviderHost.autoMakeRelativePath) - { - tmp_dllPath = PathHelper.MakeRelativePath(value); - } - else - { - tmp_dllPath = PathHelper.MakeAbsolutePath(value); - } - - // 不一样 - bool diff = _dllPath != tmp_dllPath; - _dllPath = tmp_dllPath; - - - // 这个地方导致Json无法还原,所以先判断是否需要进行调用 - if (LinkedUserList != null) { - if (Api == null || diff) - { - Api = new XApi(_dllPath); - } - if (Api != null) { - try - { - Type = Api.GetApiTypes; - Name = Api.GetApiName; - Version = Api.GetApiVersion; - - // 取公共部分 - UseType = UseType & Type; - } - catch(Exception ex) - { - Api = null; - Type = ApiType.Nono; - Name = ex.Message; - Version = "请使用depends检查一下是否缺少依赖"; - UseType = ApiType.Nono; - } - } - } + _dllPath = value; + Api = CheckApi(_typeName, _dllPath); + } + } + + public string TypeName + { + get + { + return _typeName; + } + set { + _typeName = value; + Api = CheckApi(_typeName, _dllPath); } } [Browsable(false)] - internal XApi Api { get; set; } + internal IXApi Api { get; set; } [Category(CATEGORY_INFO)] [ReadOnly(true)] @@ -103,20 +98,20 @@ public string DllPath [TypeConverter(typeof(ServerItemConverter))] public int Server { get; set; } - private BindingList userList = new BindingList(); - public BindingList UserList - { - get { return userList; } - set { userList = value; } - } + //private BindingList userList = new BindingList(); + //public BindingList UserList + //{ + // get { return userList; } + // set { userList = value; } + //} public string LogPrefix { get; set; } - [Category(CATEGORY_Type)] + [Category(CATEGORY_TYPE)] [ReadOnly(true)] public ApiType Type { get; set; } - [Category(CATEGORY_Type)] + [Category(CATEGORY_TYPE)] [Editor(typeof(ApiTypeSelectorEditor), typeof(UITypeEditor))] public ApiType UseType { get; set; } diff --git a/QuantBox.API.Provider/Single/Extensions.cs b/QuantBox.API.Provider/Single/Extensions.cs index b64743d..ef16f50 100644 --- a/QuantBox.API.Provider/Single/Extensions.cs +++ b/QuantBox.API.Provider/Single/Extensions.cs @@ -3,7 +3,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -using XAPI.Callback; +using XAPI; using NLog; @@ -11,7 +11,7 @@ namespace QuantBox.APIProvider.Single { public static class XAPI_Extensions { - public static Logger GetLog(this XApi api) + public static Logger GetLog(this IXApi api) { return (api.Log as Logger); } diff --git a/QuantBox.API.Provider/Single/OrderMap.cs b/QuantBox.API.Provider/Single/OrderMap.cs index 32a1c36..9411f44 100644 --- a/QuantBox.API.Provider/Single/OrderMap.cs +++ b/QuantBox.API.Provider/Single/OrderMap.cs @@ -96,7 +96,7 @@ public void DoOrderSend(ref OrderField[] ordersArray, Order order) public void DoOrderSend(ref OrderField[] ordersArray, List ordersList) { // 这里其实返回的是LocalID - string outstr = provider._TdApi.SendOrder(ref ordersArray); + string outstr = provider._TdApi.SendOrder(ordersArray); string[] OrderIds = outstr.Split(';'); int i = 0; diff --git a/QuantBox.API.Provider/Single/ServerItem.cs b/QuantBox.API.Provider/Single/ServerItem.cs index ddc9a6d..46dd4c2 100644 --- a/QuantBox.API.Provider/Single/ServerItem.cs +++ b/QuantBox.API.Provider/Single/ServerItem.cs @@ -89,7 +89,7 @@ public ServerItem() public ServerInfoField ToStruct() { - ServerInfoField field; + ServerInfoField field = new ServerInfoField(); field.IsUsingUdp = this.IsUsingUdp; field.IsMulticast = this.IsMulticast; field.TopicId = this.TopicId; diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs b/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs index 4dd9637..061869f 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using System.Windows.Forms; -using XAPI.Callback; using XAPI; using NLog; using QuantBox.Extensions; @@ -35,13 +34,13 @@ namespace QuantBox.APIProvider.Single public partial class SingleProvider { // 实际的连接,由这个来 - internal XApi _TdApi; - internal XApi _MdApi; - internal XApi _L2Api; - internal XApi _QuoteRequestApi; - internal XApi _HdApi; - internal XApi _ItApi; - internal XApi _QueryApi; + internal IXApi _TdApi; + internal IXApi _MdApi; + internal IXApi _L2Api; + internal IXApi _QuoteRequestApi; + internal IXApi _HdApi; + internal IXApi _ItApi; + internal IXApi _QueryApi; private void _Connect(bool bFromUI) { @@ -80,7 +79,7 @@ private void _Connect(bool bFromUI) { if (item.UseType > 0) { - XApi api = ConnectToApi(item); + IXApi api = ConnectToApi(item); assign(item, api); } else @@ -232,16 +231,16 @@ private void OnConnectionStatus_callback(object sender, ConnectionStatus status, { if (userLogin.RawErrorID != 0) { - (sender as XApi).GetLog().Info("{0}:{1}", status, userLogin.ToFormattedStringShort()); + (sender as IXApi).GetLog().Info("{0}:{1}", status, userLogin.ToFormattedStringShort()); } else { - (sender as XApi).GetLog().Info("{0}:{1}", status, userLogin.ToFormattedStringLong()); + (sender as IXApi).GetLog().Info("{0}:{1}", status, userLogin.ToFormattedStringLong()); } } else { - (sender as XApi).GetLog().Info("{0}", status); + (sender as IXApi).GetLog().Info("{0}", status); } switch (status) @@ -309,7 +308,7 @@ private void OnConnectionStatus_Disconnected(object sender, ConnectionStatus sta #region XApi小功能 - private void assign(ApiItem item, XApi api) + private void assign(ApiItem item, IXApi api) { if ((item.UseType & ApiType.MarketData) == ApiType.MarketData) { @@ -341,7 +340,7 @@ private void assign(ApiItem item, XApi api) } } - public XApi GetXApi(ApiType type) + public IXApi GetXApi(ApiType type) { switch (type) { @@ -362,32 +361,22 @@ public XApi GetXApi(ApiType type) } } - private XApi ConnectToApi(ApiItem item) + private IXApi ConnectToApi(ApiItem item) { //lock (this) { DisconnectToApi(item); - XApi api = item.Api; + IXApi api = item.Api; if (api == null) { - api = new XApi(PathHelper.MakeAbsolutePath(item.DllPath)); + api = XApiHelper.CreateInstance(item.TypeName, item.DllPath); item.Api = api; } api.Server = ServerList[item.Server].ToStruct(); - if (item.UserList.Count > 0) - { - foreach (var it in item.UserList) - { - api.UserList.Add(it.ToStruct()); - } - } - else - { - api.User = UserList[item.User].ToStruct(); - } + api.User = UserList[item.User].ToStruct(); // 更新Log名字,这样在日志中可以进行识别 api.Log = LogManager.GetLogger(string.Format("{0}.{1}.{2}", Name, item.LogPrefix, api.User.UserID)); @@ -445,7 +434,7 @@ private void DisconnectToApi(ApiItem item) } } - private void _DisconnectToApi(XApi api) + private void _DisconnectToApi(IXApi api) { try { @@ -468,7 +457,7 @@ private void _DisconnectToApi(XApi api) } } - private bool IsApiConnected(XApi api) + private bool IsApiConnected(IXApi api) { return (api != null && api.IsConnected); } @@ -500,17 +489,17 @@ private void SetApiReconnectInterval(int reconnectInterval) #region 其它非关键功能 private void OnRtnError_callback(object sender, ref ErrorField error) { - (sender as XApi).GetLog().Error("OnRtnError:" + error.ToFormattedString()); + (sender as IXApi).GetLog().Error("OnRtnError:" + error.ToFormattedString()); } private void OnLog_callback(object sender, ref LogField log) { - (sender as XApi).GetLog().Info("OnLog:" + log.ToFormattedString()); + (sender as IXApi).GetLog().Info("OnLog:" + log.ToFormattedString()); } private void OnRtnQuoteRequest_callback(object sender, ref QuoteRequestField quoteRequest) { - (sender as XApi).GetLog().Info("OnRtnQuoteRequest:" + quoteRequest.ToFormattedString()); + (sender as IXApi).GetLog().Info("OnRtnQuoteRequest:" + quoteRequest.ToFormattedString()); MarketDataRecord record; if (!marketDataRecords.TryGetValue(quoteRequest.Symbol, out record)) @@ -526,7 +515,7 @@ private void OnRtnQuoteRequest_callback(object sender, ref QuoteRequestField quo private void QueryAccountPositionInstrument_Logined() { - ReqQueryField query = default(ReqQueryField); + ReqQueryField query = new ReqQueryField(); query.PortfolioID1 = DefaultPortfolioID1; query.PortfolioID2 = DefaultPortfolioID2; query.PortfolioID3 = DefaultPortfolioID3; @@ -535,14 +524,14 @@ private void QueryAccountPositionInstrument_Logined() // 查持仓,查资金 if (IsApiConnected(_QueryApi)) { - _QueryApi.ReqQuery(QueryType.ReqQryTradingAccount, ref query); - _QueryApi.ReqQuery(QueryType.ReqQryInvestorPosition, ref query); + _QueryApi.ReqQuery(QueryType.ReqQryTradingAccount, query); + _QueryApi.ReqQuery(QueryType.ReqQryInvestorPosition, query); } // 查合约 if (IsApiConnected(_ItApi)) { - _ItApi.ReqQuery(QueryType.ReqQryInstrument, ref query); + _ItApi.ReqQuery(QueryType.ReqQryInstrument, query); } } @@ -551,7 +540,7 @@ private void QueryAccountPosition_OnTimer() if (!IsApiConnected(_QueryApi)) return; - ReqQueryField query = default(ReqQueryField); + ReqQueryField query = new ReqQueryField(); query.PortfolioID1 = DefaultPortfolioID1; query.PortfolioID2 = DefaultPortfolioID2; query.PortfolioID3 = DefaultPortfolioID3; @@ -560,14 +549,14 @@ private void QueryAccountPosition_OnTimer() _QueryAccountCount -= (int)_Timer.Interval / 1000; if (_QueryAccountCount <= 0) { - _QueryApi.ReqQuery(QueryType.ReqQryTradingAccount, ref query); + _QueryApi.ReqQuery(QueryType.ReqQryTradingAccount, query); _QueryAccountCount = _QueryAccountInterval; } _QueryPositionCount -= (int)_Timer.Interval / 1000; if (_QueryPositionCount <= 0) { - _QueryApi.ReqQuery(QueryType.ReqQryInvestorPosition, ref query); + _QueryApi.ReqQuery(QueryType.ReqQryInvestorPosition, query); _QueryPositionCount = _QueryPositionInterval; } } diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs b/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs index 232f469..1308c4b 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs @@ -220,6 +220,8 @@ private void CmdNewOrderList(ExecutionCommand command) private void ToOrderStruct(ref OrderField field, Order order, string apiSymbol, string apiExchange) { + field = new OrderField(); + field.InstrumentID = apiSymbol; field.ExchangeID = apiExchange; field.Price = order.Price; diff --git a/QuantBox.API.Provider/Single/SingleProvider.Provider.cs b/QuantBox.API.Provider/Single/SingleProvider.Provider.cs index c38d7b9..fa95d9a 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.Provider.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.Provider.cs @@ -197,7 +197,7 @@ protected override void OnConnect() // 启动重连定时器 _Timer.Elapsed -= _Timer_Elapsed; // 改小用来测试连接销毁,用完要改回去 - _Timer.Interval = 20 * 1000; + _Timer.Interval = 30 * 1000; _Timer.Enabled = true; _Timer.Elapsed += _Timer_Elapsed; diff --git a/QuantBox.API.Provider/Single/UserItem.cs b/QuantBox.API.Provider/Single/UserItem.cs index 1ea388b..5a40954 100644 --- a/QuantBox.API.Provider/Single/UserItem.cs +++ b/QuantBox.API.Provider/Single/UserItem.cs @@ -37,7 +37,7 @@ public string Label public UserInfoField ToStruct() { - UserInfoField field; + UserInfoField field = new UserInfoField(); field.UserID = this.UserID; field.Password = this.Password; diff --git a/QuantBox.API.Provider/UI/ApiControlForm.cs b/QuantBox.API.Provider/UI/ApiControlForm.cs index 28b6118..4b09b61 100644 --- a/QuantBox.API.Provider/UI/ApiControlForm.cs +++ b/QuantBox.API.Provider/UI/ApiControlForm.cs @@ -27,46 +27,46 @@ public void Init(SingleProvider provider) private void button_QueryOrder_Click(object sender, EventArgs e) { - ReqQueryField query = default(ReqQueryField); + ReqQueryField query = new ReqQueryField(); query.PortfolioID1 = textBox_PortfolioID1.Text; query.PortfolioID2 = textBox_PortfolioID2.Text; query.PortfolioID3 = textBox_PortfolioID3.Text; query.Business = (BusinessType)Enum.Parse(typeof(BusinessType),comboBox_BusinessType.Text); - provider._QueryApi.ReqQuery(QueryType.ReqQryOrder,ref query); + provider._QueryApi.ReqQuery(QueryType.ReqQryOrder, query); } private void button_QueryTrade_Click(object sender, EventArgs e) { - ReqQueryField query = default(ReqQueryField); + ReqQueryField query = new ReqQueryField(); query.PortfolioID1 = textBox_PortfolioID1.Text; query.PortfolioID2 = textBox_PortfolioID2.Text; query.PortfolioID3 = textBox_PortfolioID3.Text; query.Business = (BusinessType)Enum.Parse(typeof(BusinessType), comboBox_BusinessType.Text); - provider._QueryApi.ReqQuery(QueryType.ReqQryTrade, ref query); + provider._QueryApi.ReqQuery(QueryType.ReqQryTrade, query); } private void button_QueryAccount_Click(object sender, EventArgs e) { - ReqQueryField query = default(ReqQueryField); + ReqQueryField query = new ReqQueryField(); query.PortfolioID1 = textBox_PortfolioID1.Text; query.PortfolioID2 = textBox_PortfolioID2.Text; query.PortfolioID3 = textBox_PortfolioID3.Text; query.Business = (BusinessType)Enum.Parse(typeof(BusinessType), comboBox_BusinessType.Text); - provider._QueryApi.ReqQuery(QueryType.ReqQryTradingAccount, ref query); + provider._QueryApi.ReqQuery(QueryType.ReqQryTradingAccount, query); } private void button_QueryPosition_Click(object sender, EventArgs e) { - ReqQueryField query = default(ReqQueryField); + ReqQueryField query = new ReqQueryField(); query.PortfolioID1 = textBox_PortfolioID1.Text; query.PortfolioID2 = textBox_PortfolioID2.Text; query.PortfolioID3 = textBox_PortfolioID3.Text; query.Business = (BusinessType)Enum.Parse(typeof(BusinessType), comboBox_BusinessType.Text); - provider._QueryApi.ReqQuery(QueryType.ReqQryInvestorPosition, ref query); + provider._QueryApi.ReqQuery(QueryType.ReqQryInvestorPosition, query); } private void ApiControlForm_Load(object sender, EventArgs e) diff --git a/QuantBox.API.Provider/UI/ApiTypeSelectorEditor.cs b/QuantBox.API.Provider/UI/ApiTypeSelectorEditor.cs index 024f5c8..b42b388 100644 --- a/QuantBox.API.Provider/UI/ApiTypeSelectorEditor.cs +++ b/QuantBox.API.Provider/UI/ApiTypeSelectorEditor.cs @@ -42,7 +42,7 @@ protected override void FillTreeWithData(ObjectSelectorEditor.Selector selector, selector.Clear(); foreach (ApiType category in Enum.GetValues(typeof(ApiType))) { - if (category != ApiType.Nono) + if (category != ApiType.None) { if((instance.Type & category) == category) { From caf4a36786dfe417e10a21923a11d627bcc96c81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Sat, 3 Feb 2018 10:17:17 +0800 Subject: [PATCH 10/41] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=A4=9A=E4=B8=AA?= =?UTF-8?q?=E5=90=88=E7=BA=A6=E5=90=8C=E4=B8=80AltID=E9=83=BD=E8=83=BD?= =?UTF-8?q?=E8=A7=A6=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Single/MarketDataRecord.cs | 10 +- .../Single/SingleProvider.API.Connection.cs | 56 +++---- .../Single/SingleProvider.API.MarketData.cs | 139 ++++++++++-------- .../Single/SingleProvider.DataProvider.cs | 57 ++++--- 4 files changed, 145 insertions(+), 117 deletions(-) diff --git a/QuantBox.API.Provider/Single/MarketDataRecord.cs b/QuantBox.API.Provider/Single/MarketDataRecord.cs index e54420b..34c2584 100644 --- a/QuantBox.API.Provider/Single/MarketDataRecord.cs +++ b/QuantBox.API.Provider/Single/MarketDataRecord.cs @@ -16,7 +16,7 @@ public class MarketDataRecord public string Symbol_Dot; public string Symbol_Dot_Exchange; - public Instrument Instrument; + public string Instrument; public bool TradeRequested; public bool QuoteRequested; @@ -24,10 +24,12 @@ public class MarketDataRecord // 记录上次行情 public DepthMarketDataNClass DepthMarket; - public MarketDataRecord(Instrument instrument) + public SortedSet Ids; + + public MarketDataRecord() { - this.Instrument = instrument; - this.DepthMarket = new DepthMarketDataNClass(); + DepthMarket = new DepthMarketDataNClass(); + Ids = new SortedSet(); } } } diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs b/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs index 061869f..ccefa43 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs @@ -12,24 +12,24 @@ namespace QuantBox.APIProvider.Single { -/* - 插件状态分解 + /* + 插件状态分解 - 人为: - 用户主动连接,1.连接成功,2连接失败,3,连接成功登录失败,4.登录成功,但初始化失败 - 用户主动断开, - 定时: - 定时连接 - 定时断开 - 其它: - 网络连上 - 网络断开 + 人为: + 用户主动连接,1.连接成功,2连接失败,3,连接成功登录失败,4.登录成功,但初始化失败 + 用户主动断开, + 定时: + 定时连接 + 定时断开 + 其它: + 网络连上 + 网络断开 - */ -/* - * OQ里正在断开连接不能轻易用,因为会导致右键时不能连接也不能断开 -*/ + */ + /* + * OQ里正在断开连接不能轻易用,因为会导致右键时不能连接也不能断开 + */ public partial class SingleProvider { @@ -136,7 +136,7 @@ private void _Disconnect(bool bFromUI) private int nDisconnectCount = 0; void _Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { - lock(this) + lock (this) { _Timer.Enabled = false; @@ -202,7 +202,7 @@ void _Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) // 关闭查询间隔 SetApiReconnectInterval(0); // 由于定时器设置的是20秒,所以这里正好是5分钟显示一次 - if (nDisconnectCount % (3*5) == 0) + if (nDisconnectCount % (3 * 5) == 0) { xlog.Info("当前[{0}]在非交易时段,主动断开连接,下次要连接的时段为[{1}]", e.SignalTime.TimeOfDay, st_next); @@ -265,7 +265,7 @@ private void OnConnectionStatus_Done(object sender, ConnectionStatus status) { if (item.UseType > 0) { - if(!IsApiConnected(item.Api)) + if (!IsApiConnected(item.Api)) { bCheckOk = false; break; @@ -274,7 +274,7 @@ private void OnConnectionStatus_Done(object sender, ConnectionStatus status) } // 每个连接都检查是否连上,如果连上,开始进行一些基本的查询 - if(bCheckOk) + if (bCheckOk) { base.Status = ProviderStatus.Connected; @@ -290,7 +290,7 @@ private void OnConnectionStatus_Disconnected(object sender, ConnectionStatus sta 3.主动断开连接 4.被动断开,需要重连 */ - switch(base.Status) + switch (base.Status) { case ProviderStatus.Connected: // 以前连接成功了,现在需要试着重连 @@ -420,11 +420,11 @@ private IXApi ConnectToApi(ApiItem item) private void DisconnectToApi(ApiItem item) { - if(item.Api != null) + if (item.Api != null) { // 直接销毁 _DisconnectToApi(item.Api); - + //// 在线程中销毁 //Task task = Task.Factory.StartNew( // ()=> { _DisconnectToApi(item.Api); } @@ -507,10 +507,14 @@ private void OnRtnQuoteRequest_callback(object sender, ref QuoteRequestField quo return; } - NewsEx news = new NewsEx(DateTime.Now, this.id, record.Instrument.Id, NewsUrgency.Flash, "", "", quoteRequest.ToFormattedString()); - news.ResponseType = XAPI.ResponseType.OnRtnQuoteRequest; - news.UserData = quoteRequest; - EmitData(news); + foreach (var _id in record.Ids) + { + NewsEx news = new NewsEx(DateTime.Now, this.id, _id, NewsUrgency.Flash, "", "", quoteRequest.ToFormattedString()); + + news.ResponseType = XAPI.ResponseType.OnRtnQuoteRequest; + news.UserData = quoteRequest; + EmitData(news); + } } private void QueryAccountPositionInstrument_Logined() diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.MarketData.cs b/QuantBox.API.Provider/Single/SingleProvider.API.MarketData.cs index 50d4d5b..2d96b14 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.MarketData.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.MarketData.cs @@ -7,7 +7,6 @@ using XAPI.Callback; using XAPI; -//using System.Threading.Tasks.Dataflow; using QuantBox.Extensions; namespace QuantBox.APIProvider.Single @@ -54,24 +53,24 @@ private void OnRtnDepthMarketData_callback(object sender, ref DepthMarketDataNCl { if (_emitBidAsk) { - FireBid(record.Instrument.Id, _dateTime, _exchangeDateTime, pDepthMarketData, depthMarket); - FireAsk(record.Instrument.Id, _dateTime, _exchangeDateTime, pDepthMarketData, depthMarket); + FireBid(record.Ids, _dateTime, _exchangeDateTime, pDepthMarketData, depthMarket); + FireAsk(record.Ids, _dateTime, _exchangeDateTime, pDepthMarketData, depthMarket); } - FireTrade(record.Instrument.Id, _dateTime, _exchangeDateTime, pDepthMarketData, depthMarket); + FireTrade(record.Ids, _dateTime, _exchangeDateTime, pDepthMarketData, depthMarket); } else { - FireTrade(record.Instrument.Id, _dateTime, _exchangeDateTime, pDepthMarketData, depthMarket); + FireTrade(record.Ids, _dateTime, _exchangeDateTime, pDepthMarketData, depthMarket); if (_emitBidAsk) { - FireBid(record.Instrument.Id, _dateTime, _exchangeDateTime, pDepthMarketData, depthMarket); - FireAsk(record.Instrument.Id, _dateTime, _exchangeDateTime, pDepthMarketData, depthMarket); + FireBid(record.Ids, _dateTime, _exchangeDateTime, pDepthMarketData, depthMarket); + FireAsk(record.Ids, _dateTime, _exchangeDateTime, pDepthMarketData, depthMarket); } } if (_emitLevel2Snapshot) { - FireLevel2Snapshot(record.Instrument.Id, _dateTime, _exchangeDateTime, pDepthMarketData, depthMarket); + FireLevel2Snapshot(record.Ids, _dateTime, _exchangeDateTime, pDepthMarketData, depthMarket); } } catch (Exception ex) @@ -80,7 +79,7 @@ private void OnRtnDepthMarketData_callback(object sender, ref DepthMarketDataNCl } } - private void FireTrade(int InstrumentId, DateTime _dateTime, DateTime _exchangeDateTime, DepthMarketDataNClass pDepthMarketData, DepthMarketDataNClass DepthMarket) + private void FireTrade(SortedSet Ids, DateTime _dateTime, DateTime _exchangeDateTime, DepthMarketDataNClass pDepthMarketData, DepthMarketDataNClass DepthMarket) { //行情过来时是今天累计成交量,得转换成每个tick中成交量之差 double volume = pDepthMarketData.Volume - DepthMarket.Volume; @@ -96,22 +95,26 @@ private void FireTrade(int InstrumentId, DateTime _dateTime, DateTime _exchangeD volume = pDepthMarketData.Volume; } - // 使用新的类,保存更多信息 - var trade = new TradeEx( - _dateTime, - _exchangeDateTime, - this.id, - InstrumentId, - pDepthMarketData.LastPrice, - (int)volume) - { DepthMarketData = pDepthMarketData }; - - // 启用底层数据上传 + foreach (var _id in Ids) + { + // 使用新的类,保存更多信息 + var trade = new TradeEx( + _dateTime, + _exchangeDateTime, + id, + _id, + pDepthMarketData.LastPrice, + (int)volume) + { + DepthMarketData = pDepthMarketData + }; - EmitData(trade); + // 启用底层数据上传 + EmitData(trade); + } } - private void FireLevel2Snapshot(int InstrumentId, DateTime _dateTime, DateTime _exchangeDateTime, DepthMarketDataNClass pDepthMarketData, DepthMarketDataNClass DepthMarket) + private void FireLevel2Snapshot(SortedSet Ids, DateTime _dateTime, DateTime _exchangeDateTime, DepthMarketDataNClass pDepthMarketData, DepthMarketDataNClass DepthMarket) { //行情过来时是今天累计成交量,得转换成每个tick中成交量之差 double volume = pDepthMarketData.Volume - DepthMarket.Volume; @@ -127,49 +130,51 @@ private void FireLevel2Snapshot(int InstrumentId, DateTime _dateTime, DateTime _ volume = pDepthMarketData.Volume; } - List bids = new List(); - if (pDepthMarketData.Bids != null) + foreach (var _id in Ids) { - foreach (var d in pDepthMarketData.Bids) + List bids = new List(); + if (pDepthMarketData.Bids != null) { - Bid bid = new Bid( - _dateTime, - _exchangeDateTime, - this.id, - InstrumentId, - d.Price, - d.Size); - bids.Add(bid); + foreach (var d in pDepthMarketData.Bids) + { + Bid bid = new Bid( + _dateTime, + _exchangeDateTime, + id, + _id, + d.Price, + d.Size); + bids.Add(bid); + } } - } - List asks = new List(); - if (pDepthMarketData.Asks != null) - { - foreach (var d in pDepthMarketData.Asks) + List asks = new List(); + if (pDepthMarketData.Asks != null) { - Ask ask = new Ask( - _dateTime, - _exchangeDateTime, - this.id, - InstrumentId, - d.Price, - d.Size); - asks.Add(ask); + foreach (var d in pDepthMarketData.Asks) + { + Ask ask = new Ask( + _dateTime, + _exchangeDateTime, + id, + _id, + d.Price, + d.Size); + asks.Add(ask); + } } - } - - var l2s = new Level2Snapshot(_dateTime, _exchangeDateTime, this.id, InstrumentId, bids.ToArray(), asks.ToArray()) - { - }; + var l2s = new Level2Snapshot(_dateTime, _exchangeDateTime, id, _id, bids.ToArray(), asks.ToArray()) + { - // 启用底层数据上传 + }; - EmitData(l2s); + // 启用底层数据上传 + EmitData(l2s); + } } - private void FireBid(int InstrumentId, DateTime _dateTime, DateTime _exchangeDateTime, DepthMarketDataNClass pDepthMarketData, DepthMarketDataNClass DepthMarket) + private void FireBid(SortedSet Ids, DateTime _dateTime, DateTime _exchangeDateTime, DepthMarketDataNClass pDepthMarketData, DepthMarketDataNClass DepthMarket) { do { @@ -186,20 +191,22 @@ private void FireBid(int InstrumentId, DateTime _dateTime, DateTime _exchangeDat } } - Bid bid = new Bid( + foreach (var _id in Ids) + { + Bid bid = new Bid( _dateTime, _exchangeDateTime, - this.id, - InstrumentId, + id, + _id, pDepthMarketData.Bids[0].Price, pDepthMarketData.Bids[0].Size); - EmitData(bid); - + EmitData(bid); + } } while (false); } - private void FireAsk(int InstrumentId, DateTime _dateTime, DateTime _exchangeDateTime, DepthMarketDataNClass pDepthMarketData, DepthMarketDataNClass DepthMarket) + private void FireAsk(SortedSet Ids, DateTime _dateTime, DateTime _exchangeDateTime, DepthMarketDataNClass pDepthMarketData, DepthMarketDataNClass DepthMarket) { do { @@ -217,16 +224,18 @@ private void FireAsk(int InstrumentId, DateTime _dateTime, DateTime _exchangeDat } - Ask ask = new Ask( + foreach (var _id in Ids) + { + Ask ask = new Ask( _dateTime, _exchangeDateTime, - this.id, - InstrumentId, + id, + _id, pDepthMarketData.Asks[0].Price, pDepthMarketData.Asks[0].Size); - EmitData(ask); - + EmitData(ask); + } } while (false); } } diff --git a/QuantBox.API.Provider/Single/SingleProvider.DataProvider.cs b/QuantBox.API.Provider/Single/SingleProvider.DataProvider.cs index 6d93f1b..4b581d1 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.DataProvider.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.DataProvider.cs @@ -16,7 +16,7 @@ private void SubscribeForTest(Instrument instrument) { Bid bid = new Bid(DateTime.Now, this.id, instrument.Id, 100, 5); EmitData(bid); - + Ask ask = new Ask(DateTime.Now, this.id, instrument.Id, 101, 5); EmitData(ask); } @@ -51,10 +51,16 @@ public override void Subscribe(Instrument instrument) string Symbol = apiSymbol; MarketDataRecord record; + if (!marketDataRecords.TryGetValue(Symbol_Dot_Exchange, out record)) { - record = new MarketDataRecord(instrument); - record.Symbol = Symbol; + record = new MarketDataRecord(); + + record.TradeRequested = true; + record.QuoteRequested = true; + record.MarketDepthRequested = true; + + record.Symbol = apiSymbol; record.Exchange = apiExchange; record.Symbol_Dot = Symbol_Dot; record.Symbol_Dot_Exchange = Symbol_Dot_Exchange; @@ -63,13 +69,15 @@ public override void Subscribe(Instrument instrument) marketDataRecords[Symbol_Dot_Exchange] = record; marketDataRecords[Symbol_Dot] = record; marketDataRecords[Symbol] = record; - } - - record.TradeRequested = true; - record.QuoteRequested = true; - record.MarketDepthRequested = true; - Subscribe(record); + record.Instrument = instrument.Symbol; + record.Ids.Add(instrument.Id); + Subscribe(record); + } + else + { + record.Ids.Add(instrument.Id); + } } public override void Unsubscribe(Instrument instrument) @@ -93,25 +101,30 @@ public override void Unsubscribe(Instrument instrument) MarketDataRecord record; if (marketDataRecords.TryGetValue(Symbol_Dot_Exchange, out record)) { - Unsubscribe(record); - - // 多次订阅也无所谓 - record.TradeRequested = false; - record.QuoteRequested = false; - record.MarketDepthRequested = false; + record.Ids.Remove(instrument.Id); + + if (record.Ids.Count == 0) + { + Unsubscribe(record); + + // 多次订阅也无所谓 + record.TradeRequested = false; + record.QuoteRequested = false; + record.MarketDepthRequested = false; + + // 移除 + marketDataRecords.Remove(Symbol_Dot_Exchange); + marketDataRecords.Remove(Symbol_Dot); + marketDataRecords.Remove(Symbol); + } } - - // 移除 - marketDataRecords.Remove(Symbol_Dot_Exchange); - marketDataRecords.Remove(Symbol_Dot); - marketDataRecords.Remove(Symbol); } private void Subscribe(MarketDataRecord record) { if (IsApiConnected(_MdApi)) { - _MdApi.GetLog().Info("订阅合约 {0} {1} {2}", record.Instrument.Symbol, record.Symbol, record.Exchange); + _MdApi.GetLog().Info("订阅合约 {0} {1} {2}", record.Instrument, record.Symbol, record.Exchange); _MdApi.Subscribe(record.Symbol, record.Exchange); } else @@ -130,7 +143,7 @@ private void Unsubscribe(MarketDataRecord record) { if (_MdApi != null) { - _MdApi.GetLog().Info("退订合约 {0} {1} {2}", record.Instrument.Symbol, record.Symbol, record.Exchange); + _MdApi.GetLog().Info("退订合约 {0} {1} {2}", record.Instrument, record.Symbol, record.Exchange); _MdApi.Unsubscribe(record.Symbol, record.Exchange); } From 07664a8924dafaaa2a6e3be5aab0a591b69869d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Mon, 5 Feb 2018 16:53:42 +0800 Subject: [PATCH 11/41] =?UTF-8?q?=E5=8A=A0=E5=85=A5=E6=9C=BA=E5=88=B6?= =?UTF-8?q?=EF=BC=8C=E9=98=B2=E6=AD=A2Fields=E4=B8=AD=E7=9A=84ID=E5=86=B2?= =?UTF-8?q?=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QuantBox.Extensions/OrderTagType.cs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/QuantBox.Extensions/OrderTagType.cs b/QuantBox.Extensions/OrderTagType.cs index e7948eb..a6d852d 100644 --- a/QuantBox.Extensions/OrderTagType.cs +++ b/QuantBox.Extensions/OrderTagType.cs @@ -16,7 +16,7 @@ public class OrderTagType // 在本地就可以处理好的数据类型,没有必要在网络中传输,并且有可能无法序列化 public const int Local = 1; // 留给用户自定义的数据类型,让用户自己发挥的类型,可做临时变量等等 - public const int Custom = 2; + public static int Index_MAX = 2; // ===== 需要跨网络传输的Tag @@ -30,6 +30,7 @@ public class OrderTagType public const int PortfolioID3 = 6; public const int Business = 7; public const int QuoteReqID = 8; // 这个名字可能有错,需要确认 + public static int Network_MAX = 9; // ===== 不需要网络传输的类型,并且有可能无法序列化 @@ -37,5 +38,23 @@ public class OrderTagType public const int SameTimeOrder = 1; // 特殊的用于记录关联的Order,但没有先后循序,如Quote报单 public const int CancelCount = 2; // 定时撤单次数,用来区分是否跟单功能撤单 public const int SendCount = 3;//记录跟单时重发次数 + public static int Local_MAX = 4; } } + +// 使用static 定义,主要是想在不同的模块下,ID不冲突 +// 目前这个写法还没有在不同模块下测试过 + +//public class MyOrderTagType +//{ +// // TODO: 这种方法是否有坑 +// public static int TargetAmount = OrderTagType.Local_MAX + 1; +// public static int MaxQtyPerLot = TargetAmount + 1; +// public static int TimesTicks = MaxQtyPerLot + 1; +// public static int MaxCancelCnt = TimesTicks + 1; + +// static MyOrderTagType() +// { +// OrderTagType.Local_MAX = MaxCancelCnt + 1; +// } +//} From 9f3b046f8d23e347522f65ba555d7581e21a5c24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Mon, 12 Feb 2018 13:56:19 +0800 Subject: [PATCH 12/41] =?UTF-8?q?=E6=B5=8B=E8=AF=95CTP=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E4=B9=B1=E6=8C=87=E5=AE=9A=E4=BA=A4=E6=98=93=E6=89=80=E5=85=BC?= =?UTF-8?q?=E5=AE=B9=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Single/SingleProvider.API.Order.cs | 4 ++-- .../Single/SingleProvider.API.Quote.cs | 8 ++++--- .../Single/SingleProvider.DataProvider.cs | 9 ++++---- .../SingleProvider.HistoricalDataProvider.cs | 10 ++++----- .../Single/SingleProvider.Other.cs | 21 ++++++++++++------- 5 files changed, 30 insertions(+), 22 deletions(-) diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs b/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs index 1308c4b..52f4cbf 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs @@ -144,7 +144,7 @@ private void CmdNewOrderSingle(ExecutionCommand command) string apiExchange; double apiTickSize; - GetApi_Symbol_Exchange_TickSize(command.Instrument, + GetApi_Symbol_Exchange_TickSize(command.Instrument, this.id, out altSymbol, out altExchange, out apiSymbol, out apiExchange, out apiTickSize); @@ -207,7 +207,7 @@ private void CmdNewOrderList(ExecutionCommand command) string apiExchange; double apiTickSize; - GetApi_Symbol_Exchange_TickSize(orders[i].Instrument, + GetApi_Symbol_Exchange_TickSize(orders[i].Instrument, this.id, out altSymbol, out altExchange, out apiSymbol, out apiExchange, out apiTickSize); diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.Quote.cs b/QuantBox.API.Provider/Single/SingleProvider.API.Quote.cs index 7ce52ad..febe93f 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.Quote.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.Quote.cs @@ -48,7 +48,7 @@ private void CmdNewQuote(ExecutionCommand command) string apiExchange; double apiTickSize; - GetApi_Symbol_Exchange_TickSize(command.Instrument, + GetApi_Symbol_Exchange_TickSize(command.Instrument, this.id, out altSymbol, out altExchange, out apiSymbol, out apiExchange, out apiTickSize); @@ -69,10 +69,12 @@ private void CmdCancelQuote(ExecutionCommand command) private void OnRtnQuote_callback(object sender, ref QuoteField quote) { (sender as XApi).GetLog().Debug("OnRtnQuote:" + quote.ToFormattedString()); - try { + try + { quoteMap.Process(ref quote); } - catch (Exception ex) { + catch (Exception ex) + { (sender as XApi).GetLog().Error(ex); } } diff --git a/QuantBox.API.Provider/Single/SingleProvider.DataProvider.cs b/QuantBox.API.Provider/Single/SingleProvider.DataProvider.cs index 4b581d1..eb552d6 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.DataProvider.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.DataProvider.cs @@ -41,11 +41,12 @@ public override void Subscribe(Instrument instrument) string apiExchange; double apiTickSize; - GetApi_Symbol_Exchange_TickSize(instrument, + GetApi_Symbol_Exchange_TickSize(instrument, this.id, out altSymbol, out altExchange, out apiSymbol, out apiExchange, out apiTickSize); + // 如果是对CTP接口,使用UFX的参数进行订阅是否有问题?IF1802.7,目前猜没有问题 string Symbol_Dot_Exchange = string.Format("{0}.{1}", apiSymbol, apiExchange); string Symbol_Dot = string.Format("{0}.", apiSymbol); string Symbol = apiSymbol; @@ -88,7 +89,7 @@ public override void Unsubscribe(Instrument instrument) string apiExchange; double apiTickSize; - GetApi_Symbol_Exchange_TickSize(instrument, + GetApi_Symbol_Exchange_TickSize(instrument, this.id, out altSymbol, out altExchange, out apiSymbol, out apiExchange, out apiTickSize); @@ -124,7 +125,7 @@ private void Subscribe(MarketDataRecord record) { if (IsApiConnected(_MdApi)) { - _MdApi.GetLog().Info("订阅合约 {0} {1} {2}", record.Instrument, record.Symbol, record.Exchange); + _MdApi.GetLog().Info("订阅合约:Symbol:{0};InstrumentID:{1};ExchangeID:{2}", record.Instrument, record.Symbol, record.Exchange); _MdApi.Subscribe(record.Symbol, record.Exchange); } else @@ -143,7 +144,7 @@ private void Unsubscribe(MarketDataRecord record) { if (_MdApi != null) { - _MdApi.GetLog().Info("退订合约 {0} {1} {2}", record.Instrument, record.Symbol, record.Exchange); + _MdApi.GetLog().Info("退订合约:Symbol:{0};InstrumentID:{1};ExchangeID:{2}", record.Instrument, record.Symbol, record.Exchange); _MdApi.Unsubscribe(record.Symbol, record.Exchange); } diff --git a/QuantBox.API.Provider/Single/SingleProvider.HistoricalDataProvider.cs b/QuantBox.API.Provider/Single/SingleProvider.HistoricalDataProvider.cs index e111a04..f874b84 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.HistoricalDataProvider.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.HistoricalDataProvider.cs @@ -20,7 +20,7 @@ private HistoricalDataRequestField ToStruct(HistoricalDataRequest request) string apiExchange; double apiTickSize; - GetApi_Symbol_Exchange_TickSize(request.Instrument, + GetApi_Symbol_Exchange_TickSize(request.Instrument, this.id, out altSymbol, out altExchange, out apiSymbol, out apiExchange, out apiTickSize); @@ -34,9 +34,9 @@ private HistoricalDataRequestField ToStruct(HistoricalDataRequest request) field.Time1 = GetTime(request.DateTime1); field.Time2 = GetTime(request.DateTime2); field.DataType = (XAPI.DataObjetType)request.DataType; - if(request.BarType.HasValue) + if (request.BarType.HasValue) field.BarType = (XAPI.BarType)request.BarType.Value; - if(request.BarSize.HasValue) + if (request.BarSize.HasValue) field.BarSize = (int)request.BarSize.Value; //field.RequestId; //field.Count; @@ -52,7 +52,7 @@ void IHistoricalDataProvider.Cancel(string requestId) } public override void Send(HistoricalDataRequest request) { - if(!IsApiConnected(_HdApi)) + if (!IsApiConnected(_HdApi)) { EmitHistoricalDataEnd(request.RequestId, RequestResult.Error, "Provider is not connected."); xlog.Error("历史行情服务器没有连接"); @@ -60,7 +60,7 @@ public override void Send(HistoricalDataRequest request) } int iRet = 1; - switch(request.DataType) + switch (request.DataType) { case DataObjectType.Bid: case DataObjectType.Ask: diff --git a/QuantBox.API.Provider/Single/SingleProvider.Other.cs b/QuantBox.API.Provider/Single/SingleProvider.Other.cs index 8603ffc..50e387d 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.Other.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.Other.cs @@ -11,26 +11,31 @@ namespace QuantBox.APIProvider.Single public partial class SingleProvider { // 得到API中的合约名与交易所 - private void GetApi_Symbol_Exchange_TickSize(Instrument instrument, + private void GetApi_Symbol_Exchange_TickSize(Instrument instrument, byte id, out string altSymbol, out string altExchange, out string apiSymbol, out string apiExchange, out double apiTickSize) { // 取合约别名 - altSymbol = instrument.GetSymbol(this.id); - altExchange = instrument.GetExchange(this.id); + altSymbol = instrument.GetSymbol(id); + altExchange = instrument.GetExchange(id); apiTickSize = instrument.TickSize; // 取合约在API中的名字 apiSymbol = altSymbol; apiExchange = altExchange; - InstrumentField _Instrument; - if (_dictInstruments.TryGetValue(altSymbol, out _Instrument)) + // 对于UFX,没有实现查询合约的功能,所以这里其实使用的是AltID中的信息 + // 屏蔽这个功能,订阅的合约就根据设置来了 + if(true) { - apiSymbol = _Instrument.InstrumentID; - apiExchange = _Instrument.ExchangeID; - apiTickSize = _Instrument.PriceTick; + InstrumentField _Instrument; + if (_dictInstruments.TryGetValue(altSymbol, out _Instrument)) + { + apiSymbol = _Instrument.InstrumentID; + apiExchange = _Instrument.ExchangeID; + apiTickSize = _Instrument.PriceTick; + } } } } From 0d339b3dc9907e87b8ea8f9222fbc0ec7f2a3bde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Thu, 22 Feb 2018 16:24:16 +0800 Subject: [PATCH 13/41] =?UTF-8?q?UFX=E4=B8=8B=E5=8D=95=E6=B2=A1=E6=9C=89?= =?UTF-8?q?=E5=9B=9E=E5=88=B0=E5=9B=9E=E6=8A=A5=E6=97=B6=E5=B0=B1=E6=83=B3?= =?UTF-8?q?=E6=92=A4=E5=8D=95=E6=83=85=E5=86=B5=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QuantBox.API.Provider/Single/OrderMap.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/QuantBox.API.Provider/Single/OrderMap.cs b/QuantBox.API.Provider/Single/OrderMap.cs index 9411f44..a7ab579 100644 --- a/QuantBox.API.Provider/Single/OrderMap.cs +++ b/QuantBox.API.Provider/Single/OrderMap.cs @@ -105,7 +105,7 @@ public void DoOrderSend(ref OrderField[] ordersArray, List ordersList) if (string.IsNullOrEmpty(orderId)) { // 直接将单子拒绝 - EmitExecutionReport(new OrderRecord(ordersList[i]), SQ.ExecType.ExecRejected, SQ.OrderStatus.Rejected, "ErrorCode:" + orderId); + EmitExecutionReport(new OrderRecord(ordersList[i]), SQ.ExecType.ExecRejected, SQ.OrderStatus.Rejected, "Provider ErrorCode:" + orderId); } else { @@ -136,6 +136,12 @@ public void DoOrderCancel(List ordersList) { if (this.workingOrders.TryGetValue(OrderIds[i], out recordList[i])) { + // 订单已经下到柜台上了 + pendingCancels[OrderIds[i]] = recordList[i]; + } + else if (this.pendingOrders.TryGetValue(OrderIds[i], out recordList[i])) + { + // 订单还没有下到柜台,需要撤单 pendingCancels[OrderIds[i]] = recordList[i]; } } @@ -157,7 +163,7 @@ public void DoOrderCancel(List ordersList) { if(recordList[i] != null) { - EmitExecutionReport(recordList[i], SQ.ExecType.ExecCancelReject, recordList[i].Order.Status, "ErrorCode:" + e); + EmitExecutionReport(recordList[i], SQ.ExecType.ExecCancelReject, recordList[i].Order.Status, "Provider ErrorCode:" + e); } } ++i; @@ -226,6 +232,10 @@ public void Process(ref OrderField order, NLog.Logger log) { EmitExecutionReport(record, SQ.ExecType.ExecCancelReject, (SQ.OrderStatus)order.Status, order.Text()); } + else if (this.pendingCancels.TryRemove(order.LocalID, out record)) + { + EmitExecutionReport(record, SQ.ExecType.ExecCancelReject, (SQ.OrderStatus)order.Status, order.Text()); + } break; } } From 8c3015338da21058e644641fdbfade37e899e91a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Thu, 22 Feb 2018 22:37:30 +0800 Subject: [PATCH 14/41] =?UTF-8?q?=E6=B6=88=E6=81=AF=E5=A4=AA=E5=A4=9A?= =?UTF-8?q?=EF=BC=8C=E5=B1=8F=E8=94=BD=E6=8E=89OnRtnInstrumentStatus?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QuantBox.API.Provider/Single/SingleProvider.API.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.cs b/QuantBox.API.Provider/Single/SingleProvider.API.cs index d57360e..8c8481a 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.cs @@ -243,7 +243,7 @@ private void OnRtnInstrumentStatus_callback(object sender, ref InstrumentStatusF // 记录下来,后期可能要用到 _dictInstrumentsStatus[instrumentStatus.Symbol] = instrumentStatus; - (sender as XApi).GetLog().Info("OnRtnInstrumentStatus:" + instrumentStatus.ToFormattedString()); + //(sender as XApi).GetLog().Info("OnRtnInstrumentStatus:" + instrumentStatus.ToFormattedString()); } public InstrumentStatusField GetInstrumentStatus(string symbol) From 6eb679bccd107f7e29c5195e658f529354274182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Sat, 24 Feb 2018 01:39:49 +0800 Subject: [PATCH 15/41] =?UTF-8?q?=E5=87=8F=E5=B0=91=E5=B9=B2=E6=89=B0?= =?UTF-8?q?=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QuantBox.API.Provider/Single/OrderMap.cs | 2 +- QuantBox.API.Provider/Single/SingleProvider.API.cs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/QuantBox.API.Provider/Single/OrderMap.cs b/QuantBox.API.Provider/Single/OrderMap.cs index a7ab579..2d20c6d 100644 --- a/QuantBox.API.Provider/Single/OrderMap.cs +++ b/QuantBox.API.Provider/Single/OrderMap.cs @@ -187,7 +187,7 @@ public void Process(ref OrderField order, NLog.Logger log) this.workingOrders.Add(order.ID, record); // 将LocalID更新为ID this.orderIDs[record.Order.Id] = order.ID; - EmitExecutionReport(record, (SQ.ExecType)order.ExecType, (SQ.OrderStatus)order.Status); + EmitExecutionReport(record, (SQ.ExecType)order.ExecType, (SQ.OrderStatus)order.Status, order.Text()); } else { diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.cs b/QuantBox.API.Provider/Single/SingleProvider.API.cs index 8c8481a..90e525e 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.cs @@ -135,8 +135,9 @@ private void OnRspQryInvestorPosition_callback(object sender, ref PositionField { (sender as XApi).GetLog().Info("OnRspQryInvestorPosition"); } - else + else if (position.Position != 0) { + // UFX中已经过期的持仓也会推送,所以这里过滤一下不显示 (sender as XApi).GetLog().Info("OnRspQryInvestorPosition:" + position.ToFormattedString()); } @@ -243,6 +244,7 @@ private void OnRtnInstrumentStatus_callback(object sender, ref InstrumentStatusF // 记录下来,后期可能要用到 _dictInstrumentsStatus[instrumentStatus.Symbol] = instrumentStatus; + // 合约状态信息太多了,也不关心,这里屏蔽显示 //(sender as XApi).GetLog().Info("OnRtnInstrumentStatus:" + instrumentStatus.ToFormattedString()); } From f3b78864f7decd573d35d6e218a25ef9f93e012f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Thu, 1 Mar 2018 20:52:00 +0800 Subject: [PATCH 16/41] =?UTF-8?q?=E5=8F=AA=E6=9C=89=E5=B7=B2=E7=BB=8F?= =?UTF-8?q?=E8=BF=9E=E6=8E=A5=E6=88=90=E5=8A=9F=E7=9A=84=E8=BF=9E=E6=8E=A5?= =?UTF-8?q?=E6=89=8D=E5=AF=B9=E9=80=80=E8=AE=A2=E5=90=88=E7=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QuantBox.API.Provider/Single/ApiItem.cs | 7 ------- QuantBox.API.Provider/Single/SingleProvider.API.cs | 9 ++++++--- .../Single/SingleProvider.DataProvider.cs | 7 ++++--- .../Single/SingleProvider.Provider.cs | 3 --- .../Single/SingleProvider.Settings.cs | 13 ++++++++++++- 5 files changed, 22 insertions(+), 17 deletions(-) diff --git a/QuantBox.API.Provider/Single/ApiItem.cs b/QuantBox.API.Provider/Single/ApiItem.cs index 0130c56..37b7545 100644 --- a/QuantBox.API.Provider/Single/ApiItem.cs +++ b/QuantBox.API.Provider/Single/ApiItem.cs @@ -98,13 +98,6 @@ public string TypeName [TypeConverter(typeof(ServerItemConverter))] public int Server { get; set; } - //private BindingList userList = new BindingList(); - //public BindingList UserList - //{ - // get { return userList; } - // set { userList = value; } - //} - public string LogPrefix { get; set; } diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.cs b/QuantBox.API.Provider/Single/SingleProvider.API.cs index 90e525e..7547be8 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.cs @@ -79,7 +79,8 @@ private void OnRspQryTradingAccount_callback(object sender, ref AccountField acc } else { - (sender as XApi).GetLog().Info("OnRspQryTradingAccount:" + account.ToFormattedString()); + if (IsLogOnRspQryTradingAccount) + (sender as XApi).GetLog().Info("OnRspQryTradingAccount:" + account.ToFormattedString()); } // 由策略来收回报 @@ -138,7 +139,8 @@ private void OnRspQryInvestorPosition_callback(object sender, ref PositionField else if (position.Position != 0) { // UFX中已经过期的持仓也会推送,所以这里过滤一下不显示 - (sender as XApi).GetLog().Info("OnRspQryInvestorPosition:" + position.ToFormattedString()); + if (IsLogOnRspQryInvestorPosition) + (sender as XApi).GetLog().Info("OnRspQryInvestorPosition:" + position.ToFormattedString()); } // 由策略来收回报 @@ -245,7 +247,8 @@ private void OnRtnInstrumentStatus_callback(object sender, ref InstrumentStatusF _dictInstrumentsStatus[instrumentStatus.Symbol] = instrumentStatus; // 合约状态信息太多了,也不关心,这里屏蔽显示 - //(sender as XApi).GetLog().Info("OnRtnInstrumentStatus:" + instrumentStatus.ToFormattedString()); + if (IsLogOnRtnInstrumentStatus) + (sender as XApi).GetLog().Info("OnRtnInstrumentStatus:" + instrumentStatus.ToFormattedString()); } public InstrumentStatusField GetInstrumentStatus(string symbol) diff --git a/QuantBox.API.Provider/Single/SingleProvider.DataProvider.cs b/QuantBox.API.Provider/Single/SingleProvider.DataProvider.cs index eb552d6..45a2957 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.DataProvider.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.DataProvider.cs @@ -142,15 +142,16 @@ private void Subscribe(MarketDataRecord record) private void Unsubscribe(MarketDataRecord record) { - if (_MdApi != null) + if (IsApiConnected(_MdApi)) { _MdApi.GetLog().Info("退订合约:Symbol:{0};InstrumentID:{1};ExchangeID:{2}", record.Instrument, record.Symbol, record.Exchange); _MdApi.Unsubscribe(record.Symbol, record.Exchange); } - if (_QuoteRequestApi != null && SubscribeQuote) + if (SubscribeQuote) { - _QuoteRequestApi.UnsubscribeQuote(record.Symbol, record.Exchange); + if (IsApiConnected(_QuoteRequestApi)) + _QuoteRequestApi.UnsubscribeQuote(record.Symbol, record.Exchange); } } } diff --git a/QuantBox.API.Provider/Single/SingleProvider.Provider.cs b/QuantBox.API.Provider/Single/SingleProvider.Provider.cs index fa95d9a..632a037 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.Provider.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.Provider.cs @@ -11,9 +11,6 @@ using XAPI; using XAPI.Callback; -//using System.Threading.Tasks.Dataflow; - - namespace QuantBox.APIProvider.Single { public partial class SingleProvider:Provider diff --git a/QuantBox.API.Provider/Single/SingleProvider.Settings.cs b/QuantBox.API.Provider/Single/SingleProvider.Settings.cs index 70ff1b4..91743c8 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.Settings.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.Settings.cs @@ -22,7 +22,8 @@ public partial class SingleProvider : Provider private const string CATEGORY_QUOTE_REQUEST = "Settings - QuoteRequest"; private const string CATEGORY_INSTRUMENT = "Settings - Instrument"; private const string CATEGORY_HISTORICAL_DATA = "Settings - HistoricalData"; - + private const string CATEGORY_LOG_INFO = "Settings - Log Info"; + private bool _enableEmitData; private bool _emitBidAsk; private bool _emitBidAskFirst; @@ -187,5 +188,15 @@ public string ConfigPath [Description("【历史】是否过滤数据日期和时间")] public bool FilterDateTime { get; set; } #endregion + + [Category(CATEGORY_LOG_INFO)] + [Description("【日志】是否显示OnRspQryInvestorPosition记录")] + public bool IsLogOnRspQryInvestorPosition { get; set; } + [Category(CATEGORY_LOG_INFO)] + [Description("【日志】是否显示OnRspQryTradingAccount记录")] + public bool IsLogOnRspQryTradingAccount { get; set; } + [Category(CATEGORY_LOG_INFO)] + [Description("【日志】是否显示OnRtnInstrumentStatus记录")] + public bool IsLogOnRtnInstrumentStatus { get; set; } } } From 26f7f40585010ac696e1b7ee7203a95046616646 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Tue, 13 Mar 2018 20:20:20 +0800 Subject: [PATCH 17/41] =?UTF-8?q?=E4=BF=AE=E6=AD=A3OQ=E5=A4=9A=E5=BC=80?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E6=94=B9=E6=8F=92=E4=BB=B6=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E4=BC=9A=E8=A2=AB=E5=8F=A6=E4=B8=80oq?= =?UTF-8?q?=E5=90=8C=E6=8F=92=E4=BB=B6=E5=85=B3=E9=97=AD=E6=97=B6=E8=A6=86?= =?UTF-8?q?=E5=86=99=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QuantBox.API.Provider/Single/OrderMap.cs | 274 ++++++++++-------- .../Single/SingleProvider.API.Order.cs | 54 ++-- .../Single/SingleProvider.Provider.cs | 13 +- .../Single/SingleProvider.Settings.cs | 11 +- .../UI/ApiManagerForm.Designer.cs | 92 +++--- QuantBox.API.Provider/UI/ApiManagerForm.cs | 6 + 6 files changed, 253 insertions(+), 197 deletions(-) diff --git a/QuantBox.API.Provider/Single/OrderMap.cs b/QuantBox.API.Provider/Single/OrderMap.cs index 2d20c6d..d67001c 100644 --- a/QuantBox.API.Provider/Single/OrderMap.cs +++ b/QuantBox.API.Provider/Single/OrderMap.cs @@ -95,27 +95,31 @@ public void DoOrderSend(ref OrderField[] ordersArray, Order order) public void DoOrderSend(ref OrderField[] ordersArray, List ordersList) { - // 这里其实返回的是LocalID - string outstr = provider._TdApi.SendOrder(ordersArray); - string[] OrderIds = outstr.Split(';'); - - int i = 0; - foreach (var orderId in OrderIds) + lock (this) { - if (string.IsNullOrEmpty(orderId)) - { - // 直接将单子拒绝 - EmitExecutionReport(new OrderRecord(ordersList[i]), SQ.ExecType.ExecRejected, SQ.OrderStatus.Rejected, "Provider ErrorCode:" + orderId); - } - else + // 这里其实返回的是LocalID + string outstr = provider._TdApi.SendOrder(ordersArray); + string[] OrderIds = outstr.Split(';'); + + int i = 0; + foreach (var orderId in OrderIds) { - //Console.WriteLine(orderId); - this.pendingOrders.TryAdd(orderId, new OrderRecord(ordersList[i])); - // 记下了本地ID,用于立即撤单时供API来定位 - this.orderIDs.Add(ordersList[i].Id, orderId); - ordersList[i].Fields[9] = orderId; + if (string.IsNullOrEmpty(orderId)) + { + // 直接将单子拒绝 + EmitExecutionReport(new OrderRecord(ordersList[i]), SQ.ExecType.ExecRejected, SQ.OrderStatus.Rejected, "Provider ErrorCode:" + orderId); + } + else + { + // 记下了本地ID,用于立即撤单时供API来定位 + this.orderIDs[ordersList[i].Id] = orderId; + //Console.WriteLine(orderId); + this.pendingOrders[orderId] = new OrderRecord(ordersList[i]); + + ordersList[i].Fields[9] = orderId; + } + ++i; } - ++i; } } @@ -126,47 +130,50 @@ public void DoOrderCancel(Order order) public void DoOrderCancel(List ordersList) { - OrderRecord[] recordList = new OrderRecord[ordersList.Count]; - string[] OrderIds = new string[ordersList.Count]; - - for (int i = 0; i < ordersList.Count; ++i) + lock (this) { - // 如果需要下单的过程中撤单,这里有可能返回LocalID或ID - if (orderIDs.TryGetValue(ordersList[i].Id, out OrderIds[i])) + OrderRecord[] recordList = new OrderRecord[ordersList.Count]; + string[] OrderIds = new string[ordersList.Count]; + + for (int i = 0; i < ordersList.Count; ++i) { - if (this.workingOrders.TryGetValue(OrderIds[i], out recordList[i])) + // 如果需要下单的过程中撤单,这里有可能返回LocalID或ID + if (orderIDs.TryGetValue(ordersList[i].Id, out OrderIds[i])) { - // 订单已经下到柜台上了 - pendingCancels[OrderIds[i]] = recordList[i]; + if (this.workingOrders.TryGetValue(OrderIds[i], out recordList[i])) + { + // 订单已经下到柜台上了 + pendingCancels[OrderIds[i]] = recordList[i]; + } + else if (this.pendingOrders.TryGetValue(OrderIds[i], out recordList[i])) + { + // 订单还没有下到柜台,需要撤单 + pendingCancels[OrderIds[i]] = recordList[i]; + } } - else if (this.pendingOrders.TryGetValue(OrderIds[i], out recordList[i])) + else if (ordersList[i].Fields[9] != null) { - // 订单还没有下到柜台,需要撤单 - pendingCancels[OrderIds[i]] = recordList[i]; + OrderIds[i] = (string)ordersList[i].Fields[9]; + recordList[i] = new OrderRecord(ordersList[i]); } } - else if (ordersList[i].Fields[9] != null) - { - OrderIds[i] = (string)ordersList[i].Fields[9]; - recordList[i] = new OrderRecord(ordersList[i]); - } - } - string outstr = provider._TdApi.CancelOrder(OrderIds); - string[] errs = outstr.Split(';'); + string outstr = provider._TdApi.CancelOrder(OrderIds); + string[] errs = outstr.Split(';'); - { - int i = 0; - foreach (var e in errs) { - if (!string.IsNullOrEmpty(e) && e != "0") + int i = 0; + foreach (var e in errs) { - if(recordList[i] != null) + if (!string.IsNullOrEmpty(e) && e != "0") { - EmitExecutionReport(recordList[i], SQ.ExecType.ExecCancelReject, recordList[i].Order.Status, "Provider ErrorCode:" + e); + if (recordList[i] != null) + { + EmitExecutionReport(recordList[i], SQ.ExecType.ExecCancelReject, recordList[i].Order.Status, "Provider ErrorCode:" + e); + } } + ++i; } - ++i; } } } @@ -177,102 +184,119 @@ public void Process(ref OrderField order, NLog.Logger log) if (order.ExecType == XAPI.ExecType.Trade) return; - OrderRecord record; - - switch (order.ExecType) + lock (this) { - case XAPI.ExecType.New: - if (this.pendingOrders.TryRemove(order.LocalID, out record)) - { - this.workingOrders.Add(order.ID, record); - // 将LocalID更新为ID - this.orderIDs[record.Order.Id] = order.ID; - EmitExecutionReport(record, (SQ.ExecType)order.ExecType, (SQ.OrderStatus)order.Status, order.Text()); - } - else - { - //log.Warn("New,找不到订单,pendingOrders.Count={0}", pendingOrders.Count); - } - break; - case XAPI.ExecType.Rejected: - if (this.pendingOrders.TryRemove(order.LocalID, out record)) - { - orderIDs.Remove(record.Order.Id); - EmitExecutionReport(record, (SQ.ExecType)order.ExecType, (SQ.OrderStatus)order.Status, order.Text()); - } - else if (this.workingOrders.TryGetValue(order.ID, out record)) - { - // 比如说出现超出涨跌停时,先会到ProcessNew,所以得再多判断一次 - workingOrders.Remove(order.ID); - orderIDs.Remove(record.Order.Id); - EmitExecutionReport(record, (SQ.ExecType)order.ExecType, (SQ.OrderStatus)order.Status, order.Text()); - } - break; - case XAPI.ExecType.Cancelled: - if (this.workingOrders.TryGetValue(order.ID, out record)) - { - workingOrders.Remove(order.ID); - orderIDs.Remove(record.Order.Id); - EmitExecutionReport(record, SQ.ExecType.ExecCancelled, SQ.OrderStatus.Cancelled); - } - else if (this.pendingOrders.TryRemove(order.LocalID, out record)) - { - orderIDs.Remove(record.Order.Id); - EmitExecutionReport(record, (SQ.ExecType)order.ExecType, (SQ.OrderStatus)order.Status, order.Text()); - } - break; - case XAPI.ExecType.PendingCancel: - if (this.workingOrders.TryGetValue(order.ID, out record)) - { - EmitExecutionReport(record, SQ.ExecType.ExecPendingCancel, SQ.OrderStatus.PendingCancel); - } - break; - case XAPI.ExecType.CancelReject: - if (this.pendingCancels.TryRemove(order.ID, out record)) - { - EmitExecutionReport(record, SQ.ExecType.ExecCancelReject, (SQ.OrderStatus)order.Status, order.Text()); - } - else if (this.pendingCancels.TryRemove(order.LocalID, out record)) - { - EmitExecutionReport(record, SQ.ExecType.ExecCancelReject, (SQ.OrderStatus)order.Status, order.Text()); - } - break; + OrderRecord record; + + switch (order.ExecType) + { + case XAPI.ExecType.New: + if (this.pendingOrders.TryRemove(order.LocalID, out record)) + { + this.workingOrders[order.ID] = record; + // 将LocalID更新为ID + this.orderIDs[record.Order.Id] = order.ID; + EmitExecutionReport(record, (SQ.ExecType)order.ExecType, (SQ.OrderStatus)order.Status, order.Text()); + } + else + { + //log.Warn("New,找不到订单,pendingOrders.Count={0}", pendingOrders.Count); + } + break; + case XAPI.ExecType.Rejected: + if (this.pendingOrders.TryRemove(order.LocalID, out record)) + { + orderIDs.Remove(record.Order.Id); + EmitExecutionReport(record, (SQ.ExecType)order.ExecType, (SQ.OrderStatus)order.Status, order.Text()); + } + else if (this.workingOrders.TryGetValue(order.ID, out record)) + { + // 比如说出现超出涨跌停时,先会到ProcessNew,所以得再多判断一次 + workingOrders.Remove(order.ID); + orderIDs.Remove(record.Order.Id); + EmitExecutionReport(record, (SQ.ExecType)order.ExecType, (SQ.OrderStatus)order.Status, order.Text()); + } + break; + case XAPI.ExecType.Cancelled: + if (this.workingOrders.TryGetValue(order.ID, out record)) + { + workingOrders.Remove(order.ID); + orderIDs.Remove(record.Order.Id); + EmitExecutionReport(record, SQ.ExecType.ExecCancelled, SQ.OrderStatus.Cancelled); + } + else if (this.pendingOrders.TryRemove(order.LocalID, out record)) + { + orderIDs.Remove(record.Order.Id); + EmitExecutionReport(record, (SQ.ExecType)order.ExecType, (SQ.OrderStatus)order.Status, order.Text()); + } + break; + case XAPI.ExecType.PendingCancel: + if (this.workingOrders.TryGetValue(order.ID, out record)) + { + EmitExecutionReport(record, SQ.ExecType.ExecPendingCancel, SQ.OrderStatus.PendingCancel); + } + else if (this.pendingOrders.TryGetValue(order.LocalID, out record)) + { + EmitExecutionReport(record, SQ.ExecType.ExecPendingCancel, SQ.OrderStatus.PendingCancel); + } + break; + case XAPI.ExecType.CancelReject: + if (this.pendingCancels.TryRemove(order.ID, out record)) + { + // 已经收到第一回报的情况下 + EmitExecutionReport(record, SQ.ExecType.ExecCancelReject, (SQ.OrderStatus)order.Status, order.Text()); + } + else if (this.pendingCancels.TryRemove(order.LocalID, out record)) + { + // 没有收到第一条回报的情况下 + EmitExecutionReport(record, SQ.ExecType.ExecCancelReject, (SQ.OrderStatus)order.Status, order.Text()); + } + //else if (this.workingOrders.TryGetValue(order.ID, out record)) + //{ + // // 撤单回报延时的情况下 + // EmitExecutionReport(record, SQ.ExecType.ExecCancelReject, (SQ.OrderStatus)order.Status, order.Text()); + //} + break; + } } } public void Process(ref TradeField trade, NLog.Logger log) { - OrderRecord record; - if (!workingOrders.TryGetValue(trade.ID, out record)) - { - record = GetExternalOrder(ref trade); - } - if (record != null) + lock(this) { - record.AddFill(trade.Price, (int)trade.Qty); - SQ.ExecType execType = SQ.ExecType.ExecTrade; - SQ.OrderStatus orderStatus = (record.LeavesQty > 0) ? SQ.OrderStatus.PartiallyFilled : SQ.OrderStatus.Filled; - ExecutionReport report = CreateReport(record, execType, orderStatus); - report.LastPx = trade.Price; - report.LastQty = trade.Qty; - provider.EmitExecutionReport(report); - } - else - { - // log.Warn("Trade,找不到订单,workingOrders.Count={0}", workingOrders.Count); + OrderRecord record; + if (!workingOrders.TryGetValue(trade.ID, out record)) + { + record = GetExternalOrder(ref trade); + } + if (record != null) + { + record.AddFill(trade.Price, (int)trade.Qty); + SQ.ExecType execType = SQ.ExecType.ExecTrade; + SQ.OrderStatus orderStatus = (record.LeavesQty > 0) ? SQ.OrderStatus.PartiallyFilled : SQ.OrderStatus.Filled; + ExecutionReport report = CreateReport(record, execType, orderStatus); + report.LastPx = trade.Price; + report.LastQty = trade.Qty; + provider.EmitExecutionReport(report); + } + else + { + // log.Warn("Trade,找不到订单,workingOrders.Count={0}", workingOrders.Count); + } } } public void ProcessNew(ref QuoteField quote, QuoteRecord record) { OrderRecord askRecord = new OrderRecord(record.AskOrder); - this.workingOrders.Add(quote.AskID, askRecord); - this.orderIDs.Add(askRecord.Order.Id, quote.AskID); + this.workingOrders[quote.AskID] = askRecord; + this.orderIDs[askRecord.Order.Id] = quote.AskID; EmitExecutionReport(askRecord, (SQ.ExecType)quote.ExecType, (SQ.OrderStatus)quote.Status); OrderRecord bidRecord = new OrderRecord(record.BidOrder); - this.workingOrders.Add(quote.BidID, bidRecord); - this.orderIDs.Add(bidRecord.Order.Id, quote.BidID); + this.workingOrders[quote.BidID] = bidRecord; + this.orderIDs[bidRecord.Order.Id] = quote.BidID; EmitExecutionReport(bidRecord, (SQ.ExecType)quote.ExecType, (SQ.OrderStatus)quote.Status); } } diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs b/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs index 52f4cbf..875f36a 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs @@ -245,39 +245,45 @@ private void ToOrderStruct(ref OrderField field, Order order, string apiSymbol, private void OnRtnOrder_callback(object sender, ref OrderField order) { - var log = (sender as XApi).GetLog(); - log.Debug("OnRtnOrder:" + order.ToFormattedString()); + lock (this) + { + var log = (sender as XApi).GetLog(); + log.Debug("OnRtnOrder:" + order.ToFormattedString()); - // 由策略来收回报 - if (OnRtnOrder != null) - OnRtnOrder(sender, ref order); + // 由策略来收回报 + if (OnRtnOrder != null) + OnRtnOrder(sender, ref order); - try - { - orderMap.Process(ref order, log); - } - catch (Exception ex) - { - log.Error(ex); + try + { + orderMap.Process(ref order, log); + } + catch (Exception ex) + { + log.Error(ex); + } } } private void OnRtnTrade_callback(object sender, ref TradeField trade) { - var log = (sender as XApi).GetLog(); - log.Debug("OnRtnTrade:" + trade.ToFormattedString()); + lock(this) + { + var log = (sender as XApi).GetLog(); + log.Debug("OnRtnTrade:" + trade.ToFormattedString()); - // 由策略来收回报 - if (OnRtnTrade != null) - OnRtnTrade(sender, ref trade); + // 由策略来收回报 + if (OnRtnTrade != null) + OnRtnTrade(sender, ref trade); - try - { - orderMap.Process(ref trade, log); - } - catch (Exception ex) - { - log.Error(ex); + try + { + orderMap.Process(ref trade, log); + } + catch (Exception ex) + { + log.Error(ex); + } } } } diff --git a/QuantBox.API.Provider/Single/SingleProvider.Provider.cs b/QuantBox.API.Provider/Single/SingleProvider.Provider.cs index 632a037..b727da0 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.Provider.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.Provider.cs @@ -35,7 +35,8 @@ public SingleProvider(Framework framework) ~SingleProvider() { - Save(); + // OQ多开时,其中一个改了,另一个关闭会导致保存丢失 + // Save(); } private static JsonSerializerSettings jSetting = new JsonSerializerSettings() @@ -86,7 +87,7 @@ public void Init(byte id, string name) historicalDataIds = new Dictionary(); // ConfigPath在做Setting时已经做了 - Load(); + //Load(); } void SessionTimeList_ListChanged(object sender, ListChangedEventArgs e) @@ -137,7 +138,7 @@ private void Save(string path,string file,object obj) } } - internal void Save() + public void Save() { Save(ConfigPath, "SessionTimeList.json", SessionTimeList); Save(ConfigPath, "ServerList.json", ServerList); @@ -145,7 +146,7 @@ internal void Save() Save(ConfigPath, "ApiList.json", ApiList); } - private void Load() + public void Load() { SessionTimeList = new BindingList(); UserList = new BindingList(); @@ -188,6 +189,8 @@ private void Load() protected override void OnConnect() { + Load(); + _QueryAccountCount = _QueryAccountInterval; _QueryPositionCount = _QueryPositionInterval; @@ -210,6 +213,8 @@ protected override void OnDisconnect() xlog.Info("重连检测定时器关闭"); _Disconnect(true); + + Save(); } public override void Clear() diff --git a/QuantBox.API.Provider/Single/SingleProvider.Settings.cs b/QuantBox.API.Provider/Single/SingleProvider.Settings.cs index 91743c8..302eee1 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.Settings.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.Settings.cs @@ -133,16 +133,7 @@ public int QueryPositionInterval [Category(CATEGORY_COMMON)] [Description("配置文件路径")] [Editor(typeof(System.Windows.Forms.Design.FolderNameEditor), typeof(UITypeEditor))] - public string ConfigPath - { - get { return _configPath; } - set - { - _configPath = value; - Load(); - } - } - private string _configPath; + public string ConfigPath { get; set; } [Category(CATEGORY_COMMON)] [Description("交易时段列表,当前时间在这些列表中将启用重连机制,不在此列表中将主动断开,列表为空将不处理")] diff --git a/QuantBox.API.Provider/UI/ApiManagerForm.Designer.cs b/QuantBox.API.Provider/UI/ApiManagerForm.Designer.cs index 69267ed..7c5d0f2 100644 --- a/QuantBox.API.Provider/UI/ApiManagerForm.Designer.cs +++ b/QuantBox.API.Provider/UI/ApiManagerForm.Designer.cs @@ -61,9 +61,11 @@ private void InitializeComponent() this.listBox_UserList.DataSource = this.userItemBindingSource; this.listBox_UserList.FormattingEnabled = true; this.listBox_UserList.HorizontalScrollbar = true; - this.listBox_UserList.Location = new System.Drawing.Point(14, 19); + this.listBox_UserList.ItemHeight = 15; + this.listBox_UserList.Location = new System.Drawing.Point(19, 22); + this.listBox_UserList.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.listBox_UserList.Name = "listBox_UserList"; - this.listBox_UserList.Size = new System.Drawing.Size(313, 108); + this.listBox_UserList.Size = new System.Drawing.Size(416, 124); this.listBox_UserList.TabIndex = 0; this.listBox_UserList.SelectedIndexChanged += new System.EventHandler(this.listBox_UserList_SelectedIndexChanged); // @@ -76,9 +78,10 @@ private void InitializeComponent() this.propertyGrid.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.propertyGrid.Location = new System.Drawing.Point(439, -1); + this.propertyGrid.Location = new System.Drawing.Point(585, -1); + this.propertyGrid.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.propertyGrid.Name = "propertyGrid"; - this.propertyGrid.Size = new System.Drawing.Size(435, 468); + this.propertyGrid.Size = new System.Drawing.Size(580, 540); this.propertyGrid.TabIndex = 1; this.propertyGrid.PropertyValueChanged += new System.Windows.Forms.PropertyValueChangedEventHandler(this.propertyGrid_PropertyValueChanged); // @@ -88,18 +91,21 @@ private void InitializeComponent() this.groupBox1.Controls.Add(this.button_RemoveUser); this.groupBox1.Controls.Add(this.button_AddUser); this.groupBox1.Controls.Add(this.listBox_UserList); - this.groupBox1.Location = new System.Drawing.Point(12, 12); + this.groupBox1.Location = new System.Drawing.Point(16, 14); + this.groupBox1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(421, 142); + this.groupBox1.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3); + this.groupBox1.Size = new System.Drawing.Size(561, 164); this.groupBox1.TabIndex = 2; this.groupBox1.TabStop = false; this.groupBox1.Text = "UserList"; // // button_CopyUser // - this.button_CopyUser.Location = new System.Drawing.Point(333, 77); + this.button_CopyUser.Location = new System.Drawing.Point(444, 89); + this.button_CopyUser.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.button_CopyUser.Name = "button_CopyUser"; - this.button_CopyUser.Size = new System.Drawing.Size(75, 23); + this.button_CopyUser.Size = new System.Drawing.Size(100, 27); this.button_CopyUser.TabIndex = 1; this.button_CopyUser.Text = "Copy"; this.button_CopyUser.UseVisualStyleBackColor = true; @@ -107,9 +113,10 @@ private void InitializeComponent() // // button_RemoveUser // - this.button_RemoveUser.Location = new System.Drawing.Point(333, 48); + this.button_RemoveUser.Location = new System.Drawing.Point(444, 55); + this.button_RemoveUser.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.button_RemoveUser.Name = "button_RemoveUser"; - this.button_RemoveUser.Size = new System.Drawing.Size(75, 23); + this.button_RemoveUser.Size = new System.Drawing.Size(100, 27); this.button_RemoveUser.TabIndex = 1; this.button_RemoveUser.Text = "Remove"; this.button_RemoveUser.UseVisualStyleBackColor = true; @@ -117,9 +124,10 @@ private void InitializeComponent() // // button_AddUser // - this.button_AddUser.Location = new System.Drawing.Point(333, 19); + this.button_AddUser.Location = new System.Drawing.Point(444, 22); + this.button_AddUser.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.button_AddUser.Name = "button_AddUser"; - this.button_AddUser.Size = new System.Drawing.Size(75, 23); + this.button_AddUser.Size = new System.Drawing.Size(100, 27); this.button_AddUser.TabIndex = 1; this.button_AddUser.Text = "Add"; this.button_AddUser.UseVisualStyleBackColor = true; @@ -131,18 +139,21 @@ private void InitializeComponent() this.groupBox2.Controls.Add(this.button_RemoveServer); this.groupBox2.Controls.Add(this.listBox_ServerList); this.groupBox2.Controls.Add(this.button_AddServer); - this.groupBox2.Location = new System.Drawing.Point(12, 160); + this.groupBox2.Location = new System.Drawing.Point(16, 185); + this.groupBox2.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.groupBox2.Name = "groupBox2"; - this.groupBox2.Size = new System.Drawing.Size(421, 142); + this.groupBox2.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3); + this.groupBox2.Size = new System.Drawing.Size(561, 164); this.groupBox2.TabIndex = 2; this.groupBox2.TabStop = false; this.groupBox2.Text = "ServerList"; // // button_CopyServer // - this.button_CopyServer.Location = new System.Drawing.Point(333, 80); + this.button_CopyServer.Location = new System.Drawing.Point(444, 92); + this.button_CopyServer.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.button_CopyServer.Name = "button_CopyServer"; - this.button_CopyServer.Size = new System.Drawing.Size(75, 23); + this.button_CopyServer.Size = new System.Drawing.Size(100, 27); this.button_CopyServer.TabIndex = 1; this.button_CopyServer.Text = "Copy"; this.button_CopyServer.UseVisualStyleBackColor = true; @@ -150,9 +161,10 @@ private void InitializeComponent() // // button_RemoveServer // - this.button_RemoveServer.Location = new System.Drawing.Point(333, 51); + this.button_RemoveServer.Location = new System.Drawing.Point(444, 59); + this.button_RemoveServer.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.button_RemoveServer.Name = "button_RemoveServer"; - this.button_RemoveServer.Size = new System.Drawing.Size(75, 23); + this.button_RemoveServer.Size = new System.Drawing.Size(100, 27); this.button_RemoveServer.TabIndex = 1; this.button_RemoveServer.Text = "Remove"; this.button_RemoveServer.UseVisualStyleBackColor = true; @@ -163,17 +175,20 @@ private void InitializeComponent() this.listBox_ServerList.DataSource = this.serverItemBindingSource; this.listBox_ServerList.FormattingEnabled = true; this.listBox_ServerList.HorizontalScrollbar = true; - this.listBox_ServerList.Location = new System.Drawing.Point(14, 19); + this.listBox_ServerList.ItemHeight = 15; + this.listBox_ServerList.Location = new System.Drawing.Point(19, 22); + this.listBox_ServerList.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.listBox_ServerList.Name = "listBox_ServerList"; - this.listBox_ServerList.Size = new System.Drawing.Size(313, 108); + this.listBox_ServerList.Size = new System.Drawing.Size(416, 124); this.listBox_ServerList.TabIndex = 0; this.listBox_ServerList.SelectedIndexChanged += new System.EventHandler(this.listBox_ServerList_SelectedIndexChanged); // // button_AddServer // - this.button_AddServer.Location = new System.Drawing.Point(333, 22); + this.button_AddServer.Location = new System.Drawing.Point(444, 25); + this.button_AddServer.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.button_AddServer.Name = "button_AddServer"; - this.button_AddServer.Size = new System.Drawing.Size(75, 23); + this.button_AddServer.Size = new System.Drawing.Size(100, 27); this.button_AddServer.TabIndex = 1; this.button_AddServer.Text = "Add"; this.button_AddServer.UseVisualStyleBackColor = true; @@ -187,18 +202,21 @@ private void InitializeComponent() this.groupBox3.Controls.Add(this.button_RemoveApi); this.groupBox3.Controls.Add(this.listBox_ApiList); this.groupBox3.Controls.Add(this.button_AddApi); - this.groupBox3.Location = new System.Drawing.Point(12, 314); + this.groupBox3.Location = new System.Drawing.Point(16, 362); + this.groupBox3.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.groupBox3.Name = "groupBox3"; - this.groupBox3.Size = new System.Drawing.Size(421, 142); + this.groupBox3.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3); + this.groupBox3.Size = new System.Drawing.Size(561, 164); this.groupBox3.TabIndex = 2; this.groupBox3.TabStop = false; this.groupBox3.Text = "ApiList"; // // button_CopyApi // - this.button_CopyApi.Location = new System.Drawing.Point(333, 76); + this.button_CopyApi.Location = new System.Drawing.Point(444, 88); + this.button_CopyApi.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.button_CopyApi.Name = "button_CopyApi"; - this.button_CopyApi.Size = new System.Drawing.Size(75, 23); + this.button_CopyApi.Size = new System.Drawing.Size(100, 27); this.button_CopyApi.TabIndex = 1; this.button_CopyApi.Text = "Copy"; this.button_CopyApi.UseVisualStyleBackColor = true; @@ -206,9 +224,10 @@ private void InitializeComponent() // // button_RemoveApi // - this.button_RemoveApi.Location = new System.Drawing.Point(333, 47); + this.button_RemoveApi.Location = new System.Drawing.Point(444, 54); + this.button_RemoveApi.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.button_RemoveApi.Name = "button_RemoveApi"; - this.button_RemoveApi.Size = new System.Drawing.Size(75, 23); + this.button_RemoveApi.Size = new System.Drawing.Size(100, 27); this.button_RemoveApi.TabIndex = 1; this.button_RemoveApi.Text = "Remove"; this.button_RemoveApi.UseVisualStyleBackColor = true; @@ -222,9 +241,11 @@ private void InitializeComponent() this.listBox_ApiList.DataSource = this.apiItemBindingSource; this.listBox_ApiList.FormattingEnabled = true; this.listBox_ApiList.HorizontalScrollbar = true; - this.listBox_ApiList.Location = new System.Drawing.Point(14, 19); + this.listBox_ApiList.ItemHeight = 15; + this.listBox_ApiList.Location = new System.Drawing.Point(19, 22); + this.listBox_ApiList.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.listBox_ApiList.Name = "listBox_ApiList"; - this.listBox_ApiList.Size = new System.Drawing.Size(313, 108); + this.listBox_ApiList.Size = new System.Drawing.Size(416, 124); this.listBox_ApiList.TabIndex = 0; this.listBox_ApiList.SelectedIndexChanged += new System.EventHandler(this.listBox_ApiList_SelectedIndexChanged); // @@ -234,9 +255,10 @@ private void InitializeComponent() // // button_AddApi // - this.button_AddApi.Location = new System.Drawing.Point(333, 18); + this.button_AddApi.Location = new System.Drawing.Point(444, 21); + this.button_AddApi.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.button_AddApi.Name = "button_AddApi"; - this.button_AddApi.Size = new System.Drawing.Size(75, 23); + this.button_AddApi.Size = new System.Drawing.Size(100, 27); this.button_AddApi.TabIndex = 1; this.button_AddApi.Text = "Add"; this.button_AddApi.UseVisualStyleBackColor = true; @@ -244,15 +266,17 @@ private void InitializeComponent() // // ApiManagerForm // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(873, 468); + this.ClientSize = new System.Drawing.Size(1164, 540); this.Controls.Add(this.groupBox3); this.Controls.Add(this.groupBox2); this.Controls.Add(this.groupBox1); this.Controls.Add(this.propertyGrid); + this.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.Name = "ApiManagerForm"; this.Text = "ApiManagerForm"; + this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.ApiManagerForm_FormClosed); this.Load += new System.EventHandler(this.ApiManagerForm_Load); ((System.ComponentModel.ISupportInitialize)(this.userItemBindingSource)).EndInit(); this.groupBox1.ResumeLayout(false); diff --git a/QuantBox.API.Provider/UI/ApiManagerForm.cs b/QuantBox.API.Provider/UI/ApiManagerForm.cs index 14dd317..1bee632 100644 --- a/QuantBox.API.Provider/UI/ApiManagerForm.cs +++ b/QuantBox.API.Provider/UI/ApiManagerForm.cs @@ -154,6 +154,7 @@ private void listBox_ApiList_SelectedIndexChanged(object sender, EventArgs e) public void Init(SingleProvider provider) { this.provider = provider; + provider.Load(); } private void ApiManagerForm_Load(object sender, EventArgs e) @@ -162,5 +163,10 @@ private void ApiManagerForm_Load(object sender, EventArgs e) serverItemBindingSource.DataSource = provider.ServerList; apiItemBindingSource.DataSource = provider.ApiList; } + + private void ApiManagerForm_FormClosed(object sender, FormClosedEventArgs e) + { + provider.Save(); + } } } From a3eecd0ac5e3efb42def8883580bf13a8aa81c45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Mon, 2 Apr 2018 09:29:04 +0800 Subject: [PATCH 18/41] =?UTF-8?q?=E4=BF=AE=E6=AD=A3LeavesQty?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QuantBox.API.Provider/Single/OrderMap.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/QuantBox.API.Provider/Single/OrderMap.cs b/QuantBox.API.Provider/Single/OrderMap.cs index d67001c..76b9690 100644 --- a/QuantBox.API.Provider/Single/OrderMap.cs +++ b/QuantBox.API.Provider/Single/OrderMap.cs @@ -207,6 +207,7 @@ public void Process(ref OrderField order, NLog.Logger log) if (this.pendingOrders.TryRemove(order.LocalID, out record)) { orderIDs.Remove(record.Order.Id); + record.LeavesQty = 0; EmitExecutionReport(record, (SQ.ExecType)order.ExecType, (SQ.OrderStatus)order.Status, order.Text()); } else if (this.workingOrders.TryGetValue(order.ID, out record)) @@ -214,6 +215,7 @@ public void Process(ref OrderField order, NLog.Logger log) // 比如说出现超出涨跌停时,先会到ProcessNew,所以得再多判断一次 workingOrders.Remove(order.ID); orderIDs.Remove(record.Order.Id); + record.LeavesQty = 0; EmitExecutionReport(record, (SQ.ExecType)order.ExecType, (SQ.OrderStatus)order.Status, order.Text()); } break; @@ -222,11 +224,13 @@ public void Process(ref OrderField order, NLog.Logger log) { workingOrders.Remove(order.ID); orderIDs.Remove(record.Order.Id); + record.LeavesQty = 0; EmitExecutionReport(record, SQ.ExecType.ExecCancelled, SQ.OrderStatus.Cancelled); } else if (this.pendingOrders.TryRemove(order.LocalID, out record)) { orderIDs.Remove(record.Order.Id); + record.LeavesQty = 0; EmitExecutionReport(record, (SQ.ExecType)order.ExecType, (SQ.OrderStatus)order.Status, order.Text()); } break; From 730d32f86ce73cdca15d20596b17d73b3f036f5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Thu, 26 Apr 2018 09:22:58 +0800 Subject: [PATCH 19/41] =?UTF-8?q?=E5=A4=84=E7=90=86CTP=E5=8F=AF=E8=83=BD?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E5=8F=91=E9=80=81=E6=88=90=E4=BA=A4=E5=9B=9E?= =?UTF-8?q?=E6=8A=A5=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QuantBox.API.Provider/Single/OrderMap.cs | 29 +++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/QuantBox.API.Provider/Single/OrderMap.cs b/QuantBox.API.Provider/Single/OrderMap.cs index 76b9690..8e8f7b5 100644 --- a/QuantBox.API.Provider/Single/OrderMap.cs +++ b/QuantBox.API.Provider/Single/OrderMap.cs @@ -22,6 +22,7 @@ class OrderMap : BaseMap // Order.ID与LocalID或ID的映射,没有收到回报时是LocalID,收到后要更新为ID private Dictionary orderIDs; // 撤单时映射 private ConcurrentDictionary pendingCancels; // 撤单拒绝时使用 + private ConcurrentDictionary tradesDict; // 防止重复收到成交回报 private OrderRecord GetExternalOrder(ref TradeField field) { ExternalOrderRecord record; @@ -71,6 +72,7 @@ public OrderMap(Framework framework, SingleProvider provider) workingOrders = new Dictionary(); orderIDs = new Dictionary(); pendingCancels = new ConcurrentDictionary(); + tradesDict = new ConcurrentDictionary(); } public void Clear() @@ -79,6 +81,7 @@ public void Clear() workingOrders.Clear(); orderIDs.Clear(); pendingCancels.Clear(); + tradesDict.Clear(); } public void DoOrderSend(ref OrderField[] ordersArray, Order order) @@ -267,7 +270,7 @@ public void Process(ref OrderField order, NLog.Logger log) public void Process(ref TradeField trade, NLog.Logger log) { - lock(this) + lock (this) { OrderRecord record; if (!workingOrders.TryGetValue(trade.ID, out record)) @@ -276,6 +279,30 @@ record = GetExternalOrder(ref trade); } if (record != null) { + // CTP出现过重复发送委托与成交的情况,需要过滤。并提示 + // 同一交易ID同一方向不会同时出现,出现表示系统重复提示 + // 不向方向表示自成交了 + TradeField field = null; + if (tradesDict.TryGetValue(trade.TradeID, out field)) + { + // 有取出,可能是自成交,也可能是重复发单 + if (trade.Side == field.Side) + { + log.Error("重复收到成交回报!"); + // 后面不再处理 + return; + } + else + { + log.Warn("出现自成交!"); + // 自成交也得处理 + } + } + else + { + tradesDict[trade.TradeID] = trade; + } + record.AddFill(trade.Price, (int)trade.Qty); SQ.ExecType execType = SQ.ExecType.ExecTrade; SQ.OrderStatus orderStatus = (record.LeavesQty > 0) ? SQ.OrderStatus.PartiallyFilled : SQ.OrderStatus.Filled; From b8e4a9a7a6f1dd073a001cbcafc696273c9ce8ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Wed, 13 Jun 2018 14:49:15 +0800 Subject: [PATCH 20/41] =?UTF-8?q?=E5=8E=BB=E9=99=A4dll=E7=89=88=E6=9C=AC?= =?UTF-8?q?=EF=BC=8C=E6=96=B9=E4=BE=BF=E7=BC=96=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QuantBox.API.Provider/QuantBox.APIProvider.csproj | 10 +++++----- QuantBox.Extensions/QuantBox.Extensions.csproj | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/QuantBox.API.Provider/QuantBox.APIProvider.csproj b/QuantBox.API.Provider/QuantBox.APIProvider.csproj index 6c37973..c2fe041 100644 --- a/QuantBox.API.Provider/QuantBox.APIProvider.csproj +++ b/QuantBox.API.Provider/QuantBox.APIProvider.csproj @@ -9,7 +9,7 @@ Properties QuantBox.APIProvider QuantBox.APIProvider - v4.5.1 + v4.6.1 512 @@ -31,15 +31,15 @@ 4 - + ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll True - + ..\packages\NLog.4.4.12\lib\net45\NLog.dll True - + False C:\Program Files\SmartQuant Ltd\OpenQuant 2014\SmartQuant.dll @@ -58,7 +58,7 @@ - + False C:\Program Files\SmartQuant Ltd\OpenQuant 2014\XAPI_CSharp.exe diff --git a/QuantBox.Extensions/QuantBox.Extensions.csproj b/QuantBox.Extensions/QuantBox.Extensions.csproj index e1a4edd..7c011a7 100644 --- a/QuantBox.Extensions/QuantBox.Extensions.csproj +++ b/QuantBox.Extensions/QuantBox.Extensions.csproj @@ -9,7 +9,7 @@ Properties QuantBox.Extensions QuantBox.Extensions - v4.5.1 + v4.6.1 512 @@ -34,7 +34,7 @@ - + False C:\Program Files\SmartQuant Ltd\OpenQuant 2014\SmartQuant.dll @@ -43,7 +43,7 @@ - + False C:\Program Files\SmartQuant Ltd\OpenQuant 2014\XAPI_CSharp.exe From bf4b3e316e15b2aa01a1cf52a971e279fc249cc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Wed, 11 Jul 2018 10:18:07 +0800 Subject: [PATCH 21/41] =?UTF-8?q?=E6=B6=A8=E8=B7=8C=E5=81=9C=E6=97=B6?= =?UTF-8?q?=E8=BE=93=E5=87=BA=E6=8C=82=E5=8D=95=E9=87=8F=E4=B8=BA0?= =?UTF-8?q?=E7=9A=84=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../QuantBox.APIProvider.csproj | 6 +- .../Single/SingleProvider.API.MarketData.cs | 87 +++++++++++-------- QuantBox.API.Provider/packages.config | 4 +- 3 files changed, 54 insertions(+), 43 deletions(-) diff --git a/QuantBox.API.Provider/QuantBox.APIProvider.csproj b/QuantBox.API.Provider/QuantBox.APIProvider.csproj index c2fe041..9ca24b4 100644 --- a/QuantBox.API.Provider/QuantBox.APIProvider.csproj +++ b/QuantBox.API.Provider/QuantBox.APIProvider.csproj @@ -32,12 +32,10 @@ - ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll - True + ..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll - ..\packages\NLog.4.4.12\lib\net45\NLog.dll - True + ..\packages\NLog.4.5.6\lib\net45\NLog.dll False diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.MarketData.cs b/QuantBox.API.Provider/Single/SingleProvider.API.MarketData.cs index 2d96b14..28ba4ce 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.MarketData.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.MarketData.cs @@ -176,67 +176,80 @@ private void FireLevel2Snapshot(SortedSet Ids, DateTime _dateTime, DateTime private void FireBid(SortedSet Ids, DateTime _dateTime, DateTime _exchangeDateTime, DepthMarketDataNClass pDepthMarketData, DepthMarketDataNClass DepthMarket) { - do - { - if (pDepthMarketData.Bids == null || pDepthMarketData.Bids.Length == 0) - break; + double price = 0.0; + int size = 0; + // 当出现涨跌停时,有可能是一开始就是涨跌停,也有可能慢慢变成涨跌停 + if(pDepthMarketData.Bids == null || pDepthMarketData.Bids.Length == 0) + { + } + else + { if (DepthMarket.Bids != null && DepthMarket.Bids.Length > 0) { if (DepthMarket.Bids[0].Size == pDepthMarketData.Bids[0].Size && DepthMarket.Bids[0].Price == pDepthMarketData.Bids[0].Price) { // 由于与上次一样,不能动 - break; + return; } } - foreach (var _id in Ids) - { - Bid bid = new Bid( - _dateTime, - _exchangeDateTime, - id, - _id, - pDepthMarketData.Bids[0].Price, - pDepthMarketData.Bids[0].Size); - - EmitData(bid); - } - } while (false); + price = pDepthMarketData.Bids[0].Price; + size = pDepthMarketData.Bids[0].Size; + } + + foreach (var _id in Ids) + { + Bid bid = new Bid( + _dateTime, + _exchangeDateTime, + id, + _id, + price, + size); + + EmitData(bid); + } } private void FireAsk(SortedSet Ids, DateTime _dateTime, DateTime _exchangeDateTime, DepthMarketDataNClass pDepthMarketData, DepthMarketDataNClass DepthMarket) { - do - { - if (pDepthMarketData.Asks == null || pDepthMarketData.Asks.Length == 0) - break; + double price = 0.0; + int size = 0; + // 当出现涨跌停时,有可能是一开始就是涨跌停,也有可能慢慢变成涨跌停 + if (pDepthMarketData.Asks == null || pDepthMarketData.Asks.Length == 0) + { + } + else + { if (DepthMarket.Asks != null && DepthMarket.Asks.Length > 0) { if (DepthMarket.Asks[0].Size == pDepthMarketData.Asks[0].Size && DepthMarket.Asks[0].Price == pDepthMarketData.Asks[0].Price) { // 由于与上次一样,不能动 - break; + return; } - } - foreach (var _id in Ids) - { - Ask ask = new Ask( - _dateTime, - _exchangeDateTime, - id, - _id, - pDepthMarketData.Asks[0].Price, - pDepthMarketData.Asks[0].Size); - - EmitData(ask); - } - } while (false); + price = pDepthMarketData.Asks[0].Price; + size = pDepthMarketData.Asks[0].Size; + } + + foreach (var _id in Ids) + { + Ask ask = new Ask( + _dateTime, + _exchangeDateTime, + id, + _id, + price, + size); + + EmitData(ask); + } } } } diff --git a/QuantBox.API.Provider/packages.config b/QuantBox.API.Provider/packages.config index 524b16d..5656d2a 100644 --- a/QuantBox.API.Provider/packages.config +++ b/QuantBox.API.Provider/packages.config @@ -1,5 +1,5 @@  - - + + \ No newline at end of file From deec3214ac98ec67dad8525f7e8729f5397ecce3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Thu, 18 Apr 2019 10:41:11 +0800 Subject: [PATCH 22/41] =?UTF-8?q?=E7=A9=BF=E9=80=8F=E5=BC=8F=E7=9B=91?= =?UTF-8?q?=E7=AE=A1=E5=8D=87=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QuantBox.API.Provider/Single/ServerItem.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/QuantBox.API.Provider/Single/ServerItem.cs b/QuantBox.API.Provider/Single/ServerItem.cs index 46dd4c2..34d4f8e 100644 --- a/QuantBox.API.Provider/Single/ServerItem.cs +++ b/QuantBox.API.Provider/Single/ServerItem.cs @@ -45,14 +45,19 @@ public string Label /// /// 用户端产品信息 /// - [Category("客户端认证 - CTP/LTS")] + [Category("客户端认证")] public string UserProductInfo { get; set; } /// /// 认证码 /// - [Category("客户端认证 - CTP/LTS")] + [Category("客户端认证")] public string AuthCode { get; set; } /// + /// App认证码 + /// + [Category("客户端认证")] + public string AppID { get; set; } + /// /// 地址 /// [Category("服务端信息")] @@ -101,6 +106,7 @@ public ServerInfoField ToStruct() field.BrokerID = this.BrokerID; field.UserProductInfo = this.UserProductInfo; field.AuthCode = this.AuthCode; + field.AppID = this.AppID; field.Address = this.Address; field.ConfigPath = this.ConfigPath; field.ExtInfoChar128 = this.ExtInfoChar128; From 7975c010ec22489d7d455134a98da14fb9e89399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Tue, 21 May 2019 23:31:44 +0800 Subject: [PATCH 23/41] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QuantBox.API.Provider/QuantBox.APIProvider.csproj | 6 +++--- .../Single/SingleProvider.API.HistoricalData.cs | 4 ++-- QuantBox.API.Provider/Single/SingleProvider.Provider.cs | 2 +- QuantBox.API.Provider/Single/SingleProvider.Settings.cs | 2 +- QuantBox.API.Provider/packages.config | 4 ++-- QuantBox.Extensions/QuantBox.Extensions.csproj | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/QuantBox.API.Provider/QuantBox.APIProvider.csproj b/QuantBox.API.Provider/QuantBox.APIProvider.csproj index 9ca24b4..b0251d8 100644 --- a/QuantBox.API.Provider/QuantBox.APIProvider.csproj +++ b/QuantBox.API.Provider/QuantBox.APIProvider.csproj @@ -9,7 +9,7 @@ Properties QuantBox.APIProvider QuantBox.APIProvider - v4.6.1 + v4.8 512 @@ -32,10 +32,10 @@ - ..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll + ..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll - ..\packages\NLog.4.5.6\lib\net45\NLog.dll + ..\packages\NLog.4.6.3\lib\net45\NLog.dll False diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.HistoricalData.cs b/QuantBox.API.Provider/Single/SingleProvider.API.HistoricalData.cs index 987ed00..076118b 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.HistoricalData.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.HistoricalData.cs @@ -155,7 +155,7 @@ private void OnRspQryHistoricalTicks_callback(object sender, IntPtr pTicks, int volume = obj.Volume; } - if(EmitHistoricalData) + if(EnablEmitHistoricalData) { HistoricalData data = new HistoricalData { @@ -217,7 +217,7 @@ private void OnRspQryHistoricalBars_callback(object sender, IntPtr pBars, int si } } - if(EmitHistoricalData) + if(EnablEmitHistoricalData) { HistoricalData data = new HistoricalData { diff --git a/QuantBox.API.Provider/Single/SingleProvider.Provider.cs b/QuantBox.API.Provider/Single/SingleProvider.Provider.cs index b727da0..9d0939d 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.Provider.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.Provider.cs @@ -64,7 +64,7 @@ public void Init(byte id, string name) EmitBidAsk = true; EmitLevel2Snapshot = false; //UpdateInstrument = true; - EmitHistoricalData = true; + EnablEmitHistoricalData = true; FilterDateTime = true; EnableEmitData = true; HasPriceLimit = true; diff --git a/QuantBox.API.Provider/Single/SingleProvider.Settings.cs b/QuantBox.API.Provider/Single/SingleProvider.Settings.cs index 302eee1..e0a1bb9 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.Settings.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.Settings.cs @@ -173,7 +173,7 @@ public int QueryPositionInterval [Category(CATEGORY_HISTORICAL_DATA)] [Description("【历史】是否触发EmitHistoricalData事件")] [DisplayName("EmitHistoricalData")] - public bool EmitHistoricalData { get; set; } + public bool EnablEmitHistoricalData { get; set; } [Category(CATEGORY_HISTORICAL_DATA)] [Description("【历史】是否过滤数据日期和时间")] diff --git a/QuantBox.API.Provider/packages.config b/QuantBox.API.Provider/packages.config index 5656d2a..58c5b1b 100644 --- a/QuantBox.API.Provider/packages.config +++ b/QuantBox.API.Provider/packages.config @@ -1,5 +1,5 @@  - - + + \ No newline at end of file diff --git a/QuantBox.Extensions/QuantBox.Extensions.csproj b/QuantBox.Extensions/QuantBox.Extensions.csproj index 7c011a7..0ebed29 100644 --- a/QuantBox.Extensions/QuantBox.Extensions.csproj +++ b/QuantBox.Extensions/QuantBox.Extensions.csproj @@ -9,7 +9,7 @@ Properties QuantBox.Extensions QuantBox.Extensions - v4.6.1 + v4.8 512 From 1df0ac30620d55d51c658c5a49736ded06957e1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Mon, 3 Jun 2019 13:14:06 +0800 Subject: [PATCH 24/41] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E6=97=B6=E6=9F=A5=E8=AF=A2=E8=BF=87=E5=BF=AB=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E7=9A=84CTP=E6=9F=A5=E8=AF=A2=E6=9C=AA=E5=87=86=E5=A4=87?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Single/SingleProvider.API.Connection.cs | 164 ++++++++++-------- 1 file changed, 95 insertions(+), 69 deletions(-) diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs b/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs index ccefa43..342901e 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs @@ -9,6 +9,7 @@ using XAPI; using NLog; using QuantBox.Extensions; +using System.Threading; namespace QuantBox.APIProvider.Single { @@ -133,85 +134,91 @@ private void _Disconnect(bool bFromUI) } - private int nDisconnectCount = 0; - void _Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + private void CheckConnection(System.Timers.ElapsedEventArgs e) { - lock (this) + do { - _Timer.Enabled = false; + // 列表为空,表示不处理。这时没有自动重连 + if (SessionTimeList == null || SessionTimeList.Count == 0) + break; - do - { - // 列表为空,表示不处理。这时没有自动重连 - if (SessionTimeList == null || SessionTimeList.Count == 0) - break; + var stl = SessionTimeList.Where(x => x.Enable).ToList(); + if (stl.Count == 0) + break; - var stl = SessionTimeList.Where(x => x.Enable).ToList(); - if (stl.Count == 0) - break; + bool bTryConnect = true; - bool bTryConnect = true; + SessionTimeItem st_current = null; + SessionTimeItem st_next = null; + foreach (var st in stl) + { + // 如果当前时间在交易范围内,要开启重连 + // 如果当前时间不在交易范围内,要主动断开 + TimeSpan ts = e.SignalTime.TimeOfDay; + if (!st.Enable) + continue; - SessionTimeItem st_current = null; - SessionTimeItem st_next = null; - foreach (var st in stl) + if (ts < st.SessionStart) { - // 如果当前时间在交易范围内,要开启重连 - // 如果当前时间不在交易范围内,要主动断开 - TimeSpan ts = e.SignalTime.TimeOfDay; - if (!st.Enable) - continue; - - if (ts < st.SessionStart) - { - // 停 - bTryConnect = false; - st_next = st; - } - else if (ts <= st.SessionEnd) - { - // 启动 - bTryConnect = true; - st_current = st; - break; - } - else - { - // 停 - bTryConnect = false; - st_next = st; - } + // 停 + bTryConnect = false; + st_next = st; } + else if (ts <= st.SessionEnd) + { + // 启动 + bTryConnect = true; + st_current = st; + break; + } + else + { + // 停 + bTryConnect = false; + st_next = st; + } + } - if (bTryConnect) + if (bTryConnect) + { + // 没有连接要连上,有连接要设置时间 + if (!IsConnected) { - // 没有连接要连上,有连接要设置时间 - if (!IsConnected) - { - xlog.Info("当前[{0}]在交易时段[{1}],主动连接", e.SignalTime.TimeOfDay, st_current); - _Connect(false); - } + xlog.Info("当前[{0}]在交易时段[{1}],主动连接", e.SignalTime.TimeOfDay, st_current); + _Connect(false); + } - // 初始化查询间隔 - SetApiReconnectInterval(_ReconnectInterval); + // 初始化查询间隔 + SetApiReconnectInterval(_ReconnectInterval); - nDisconnectCount = 0; - } - else + nDisconnectCount = 0; + } + else + { + // 关闭查询间隔 + SetApiReconnectInterval(0); + // 由于定时器设置的是20秒,所以这里正好是5分钟显示一次 + if (nDisconnectCount % (3 * 5) == 0) { - // 关闭查询间隔 - SetApiReconnectInterval(0); - // 由于定时器设置的是20秒,所以这里正好是5分钟显示一次 - if (nDisconnectCount % (3 * 5) == 0) - { - xlog.Info("当前[{0}]在非交易时段,主动断开连接,下次要连接的时段为[{1}]", e.SignalTime.TimeOfDay, st_next); - - // 要断开连接 - _Disconnect(false); - } - ++nDisconnectCount; + xlog.Info("当前[{0}]在非交易时段,主动断开连接,下次要连接的时段为[{1}]", e.SignalTime.TimeOfDay, st_next); + + // 要断开连接 + _Disconnect(false); } - } while (false); + ++nDisconnectCount; + } + } while (false); + } + + + private int nDisconnectCount = 0; + void _Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + lock (this) + { + _Timer.Enabled = false; + + CheckConnection(e); // 查询持仓和资金 QueryAccountPosition_OnTimer(); @@ -278,6 +285,7 @@ private void OnConnectionStatus_Done(object sender, ConnectionStatus status) { base.Status = ProviderStatus.Connected; + // 这个查询不能太快,否则CTP报错 QueryAccountPositionInstrument_Logined(); } } @@ -519,26 +527,44 @@ private void OnRtnQuoteRequest_callback(object sender, ref QuoteRequestField quo private void QueryAccountPositionInstrument_Logined() { + // OnRtnError:[XErrorID = 0; RawErrorID = 90; Text = CTP:查询未就绪,请稍后重试; Source = OnRspError] + Thread thread2 = new Thread(QueryAccountPositionInstrument_Thread); + thread2.Start(); + } + + private void QueryAccountPositionInstrument_Thread() + { + + ReqQueryField query = new ReqQueryField(); query.PortfolioID1 = DefaultPortfolioID1; query.PortfolioID2 = DefaultPortfolioID2; query.PortfolioID3 = DefaultPortfolioID3; query.Business = DefaultBusiness; + // 查合约 + if (IsApiConnected(_ItApi)) + { + Thread.Sleep(3000); + _ItApi.ReqQuery(QueryType.ReqQryInstrument, query); + } + // 查持仓,查资金 if (IsApiConnected(_QueryApi)) { + Thread.Sleep(3000); _QueryApi.ReqQuery(QueryType.ReqQryTradingAccount, query); - _QueryApi.ReqQuery(QueryType.ReqQryInvestorPosition, query); } - // 查合约 - if (IsApiConnected(_ItApi)) + if (IsApiConnected(_QueryApi)) { - _ItApi.ReqQuery(QueryType.ReqQryInstrument, query); + Thread.Sleep(3000); + _QueryApi.ReqQuery(QueryType.ReqQryInvestorPosition, query); } } + + private void QueryAccountPosition_OnTimer() { if (!IsApiConnected(_QueryApi)) From c9e133208ad5f3d849a3bea7d21a4a9f84530ff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Wed, 18 Sep 2019 22:01:15 +0800 Subject: [PATCH 25/41] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E6=88=90=E5=8A=9F=E5=90=8E=E7=AB=8B=E5=8D=B3=E6=96=AD=E5=BC=80?= =?UTF-8?q?=E8=BF=9E=E6=8E=A5=E5=B4=A9=E6=BA=83=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../QuantBox.APIProvider.csproj | 6 ++++-- .../Single/SingleProvider.API.Connection.cs | 17 ++++++++--------- QuantBox.API.Provider/packages.config | 2 +- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/QuantBox.API.Provider/QuantBox.APIProvider.csproj b/QuantBox.API.Provider/QuantBox.APIProvider.csproj index b0251d8..cf4a6a2 100644 --- a/QuantBox.API.Provider/QuantBox.APIProvider.csproj +++ b/QuantBox.API.Provider/QuantBox.APIProvider.csproj @@ -35,7 +35,7 @@ ..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll - ..\packages\NLog.4.6.3\lib\net45\NLog.dll + ..\packages\NLog.4.6.7\lib\net45\NLog.dll False @@ -117,7 +117,9 @@ - + + Designer + diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs b/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs index 342901e..2449c41 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs @@ -433,10 +433,8 @@ private void DisconnectToApi(ApiItem item) // 直接销毁 _DisconnectToApi(item.Api); - //// 在线程中销毁 - //Task task = Task.Factory.StartNew( - // ()=> { _DisconnectToApi(item.Api); } - // ); + // 立即断开连接后,登录时自动查资金与持仓的功能在线程中还在运行,会报错 + assign(item, null); item.Api = null; } @@ -534,8 +532,6 @@ private void QueryAccountPositionInstrument_Logined() private void QueryAccountPositionInstrument_Thread() { - - ReqQueryField query = new ReqQueryField(); query.PortfolioID1 = DefaultPortfolioID1; query.PortfolioID2 = DefaultPortfolioID2; @@ -546,20 +542,23 @@ private void QueryAccountPositionInstrument_Thread() if (IsApiConnected(_ItApi)) { Thread.Sleep(3000); - _ItApi.ReqQuery(QueryType.ReqQryInstrument, query); + if (IsApiConnected(_ItApi)) + _ItApi.ReqQuery(QueryType.ReqQryInstrument, query); } // 查持仓,查资金 if (IsApiConnected(_QueryApi)) { Thread.Sleep(3000); - _QueryApi.ReqQuery(QueryType.ReqQryTradingAccount, query); + if (IsApiConnected(_QueryApi)) + _QueryApi.ReqQuery(QueryType.ReqQryTradingAccount, query); } if (IsApiConnected(_QueryApi)) { Thread.Sleep(3000); - _QueryApi.ReqQuery(QueryType.ReqQryInvestorPosition, query); + if (IsApiConnected(_QueryApi)) + _QueryApi.ReqQuery(QueryType.ReqQryInvestorPosition, query); } } diff --git a/QuantBox.API.Provider/packages.config b/QuantBox.API.Provider/packages.config index 58c5b1b..cac1bc5 100644 --- a/QuantBox.API.Provider/packages.config +++ b/QuantBox.API.Provider/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file From 965a48d9c259bcad9e8171dd6b026b48ba0b9f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Mon, 23 Sep 2019 09:53:23 +0800 Subject: [PATCH 26/41] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=B8=8B=E6=AC=A1?= =?UTF-8?q?=E9=87=8D=E8=BF=9E=E6=8F=90=E7=A4=BA=E4=BF=A1=E6=81=AF=E9=94=99?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Single/SingleProvider.API.Connection.cs | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs b/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs index 2449c41..b7a732b 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs @@ -163,6 +163,7 @@ private void CheckConnection(System.Timers.ElapsedEventArgs e) // 停 bTryConnect = false; st_next = st; + break; } else if (ts <= st.SessionEnd) { @@ -539,27 +540,18 @@ private void QueryAccountPositionInstrument_Thread() query.Business = DefaultBusiness; // 查合约 + Thread.Sleep(3000); if (IsApiConnected(_ItApi)) - { - Thread.Sleep(3000); - if (IsApiConnected(_ItApi)) - _ItApi.ReqQuery(QueryType.ReqQryInstrument, query); - } + _ItApi.ReqQuery(QueryType.ReqQryInstrument, query); // 查持仓,查资金 + Thread.Sleep(3000); if (IsApiConnected(_QueryApi)) - { - Thread.Sleep(3000); - if (IsApiConnected(_QueryApi)) - _QueryApi.ReqQuery(QueryType.ReqQryTradingAccount, query); - } + _QueryApi.ReqQuery(QueryType.ReqQryTradingAccount, query); + Thread.Sleep(3000); if (IsApiConnected(_QueryApi)) - { - Thread.Sleep(3000); - if (IsApiConnected(_QueryApi)) - _QueryApi.ReqQuery(QueryType.ReqQryInvestorPosition, query); - } + _QueryApi.ReqQuery(QueryType.ReqQryInvestorPosition, query); } From 08862605a9529682f6e426db13a22aaefb584178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Fri, 27 Sep 2019 15:13:26 +0800 Subject: [PATCH 27/41] =?UTF-8?q?=E7=99=BB=E5=BD=95=E6=88=90=E5=8A=9F?= =?UTF-8?q?=E7=9A=84=E9=80=9A=E7=9F=A5=E5=BB=B6=E5=90=8E=E4=B8=80=E4=B8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Single/SingleProvider.API.Connection.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs b/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs index b7a732b..f4cd0f3 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs +++ b/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs @@ -284,7 +284,8 @@ private void OnConnectionStatus_Done(object sender, ConnectionStatus status) // 每个连接都检查是否连上,如果连上,开始进行一些基本的查询 if (bCheckOk) { - base.Status = ProviderStatus.Connected; + // 晚一点通知上层,这个更稳定一些 + // base.Status = ProviderStatus.Connected; // 这个查询不能太快,否则CTP报错 QueryAccountPositionInstrument_Logined(); @@ -539,16 +540,20 @@ private void QueryAccountPositionInstrument_Thread() query.PortfolioID3 = DefaultPortfolioID3; query.Business = DefaultBusiness; - // 查合约 + Thread.Sleep(3000); + // 查合约 if (IsApiConnected(_ItApi)) _ItApi.ReqQuery(QueryType.ReqQryInstrument, query); - - // 查持仓,查资金 + Thread.Sleep(3000); + // 查持仓,查资金 if (IsApiConnected(_QueryApi)) _QueryApi.ReqQuery(QueryType.ReqQryTradingAccount, query); + // 晚一点通知上层会不会更稳定一些? + base.Status = ProviderStatus.Connected; + Thread.Sleep(3000); if (IsApiConnected(_QueryApi)) _QueryApi.ReqQuery(QueryType.ReqQryInvestorPosition, query); From 0c26b242456b5c1ed72fe5ac5859ab54723b2622 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Sat, 28 Sep 2019 03:46:54 +0800 Subject: [PATCH 28/41] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=80=9A=E8=BF=87?= =?UTF-8?q?=E5=91=BD=E4=BB=A4=E8=A1=8C=E5=8A=A0=E8=BD=BD=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E5=B9=B6=E7=AB=8B=E5=8D=B3=E5=90=AF=E5=8A=A8=E7=9A=84=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QuantBox.API.Provider/Host/ProviderHost.cs | 136 ++++++++++++------ .../QuantBox.APIProvider.csproj | 3 + QuantBox.API.Provider/packages.config | 1 + autorun_oq.bat | 3 + 4 files changed, 100 insertions(+), 43 deletions(-) create mode 100644 autorun_oq.bat diff --git a/QuantBox.API.Provider/Host/ProviderHost.cs b/QuantBox.API.Provider/Host/ProviderHost.cs index c29d2cc..66025be 100644 --- a/QuantBox.API.Provider/Host/ProviderHost.cs +++ b/QuantBox.API.Provider/Host/ProviderHost.cs @@ -11,6 +11,7 @@ using QuantBox.APIProvider.Single; using System.Reflection; using System.Windows.Forms; +using CommandLine; namespace QuantBox.APIProvider { @@ -48,7 +49,48 @@ public string Version get { return Assembly.GetExecutingAssembly().GetName().Version.ToString(); } } - + class Options + { + [Value(0, MetaName = "filename", Required = true, HelpText = "项目路径")] + public string filename { get; set; } + + [Option('r', "run", Required = false, Default = false, HelpText = "运行策略.")] + public bool run { get; set; } + } + + void RunOptions(Options opts) + { + if (!(new FileInfo(opts.filename).Exists)) + return; + + System.Threading.ThreadPool.QueueUserWorkItem(delegate + { + // 检查界面是否正常启动 + while (Application.OpenForms.Count == 0 || Application.OpenForms[0].Name != "MainForm") + { + System.Threading.Thread.Sleep(1000); + } + var mainForm = Application.OpenForms[0]; + + var sm = GetSolutionManager(); + mainForm.SafeInvoke(() => + { + LoadSolution(sm, opts.filename); + }); + if(opts.run) + { + mainForm.SafeInvoke(() => + { + Solution_Start(mainForm); + }); + } + }); + } + + void HandleParseError(IEnumerable errs) + { + + } public ProviderHost(Framework framework) : base(framework) @@ -67,6 +109,16 @@ public ProviderHost(Framework framework) Create(ProviderList); ProviderList.ListChanged += ProviderList_ListChanged; + + // 通过命令行启动策略 + //cd "C:\Program Files\SmartQuant Ltd\OpenQuant 2014" + //C: + //start OpenQuant.exe "D:\Users\Kan\Documents\OpenQuant 2014\Solutions\SMACrossover\SMACrossover.sln" --run + var args = System.Environment.GetCommandLineArgs().ToList(); + args.RemoveAt(0); + CommandLine.Parser.Default.ParseArguments(args) + .WithParsed(opts => RunOptions(opts)) + .WithNotParsed((errs) => HandleParseError(errs)); } ~ProviderHost() @@ -79,53 +131,19 @@ void ProviderList_ListChanged(object sender, ListChangedEventArgs e) Save(ConfigPath); } - //private static bool _bMenuAdded; - public void Init(byte id, string name) { base.id = id; base.name = name; base.description = "QuantBox API Provider Host"; base.url = "www.quantbox.cn"; - - //if (!_bMenuAdded) - //{ - // try - // { - // // DOS窗口时没有问题,非DOS下异常,所以可以利用一下 - // Console.Clear(); - // } - // catch - // { - // Console.WriteLine("要创建自己的菜单"); - // // 只有DOS窗口时要注意 - // System.Threading.ThreadPool.QueueUserWorkItem(delegate - // { - // while (Application.OpenForms.Count == 0 || Application.OpenForms[0].Name != "MainForm") - // { - // System.Threading.Thread.Sleep(1000); - // } - // Form mainForm = Application.OpenForms[0]; - - // try - // { - // mainForm.SafeInvoke(() => { AddToolStripMenuItem(mainForm); }); - // } - // catch (Exception e) - // { - // // 奇怪,调试的时候总是会出错 - // Console.WriteLine(e); - // } - // }); - // } - // _bMenuAdded = true; - //} } /// /// 指定保存格式 /// - private static readonly JsonSerializerSettings JSetting = new JsonSerializerSettings() { + private static readonly JsonSerializerSettings JSetting = new JsonSerializerSettings() + { //NullValueHandling = NullValueHandling.Ignore, //DefaultValueHandling = DefaultValueHandling.Ignore, Formatting = Formatting.Indented, @@ -134,9 +152,11 @@ public void Init(byte id, string name) // 读取信息 public void Load(string path) { - try { + try + { object ret; - using (TextReader reader = new StreamReader(path)) { + using (TextReader reader = new StreamReader(path)) + { ret = JsonConvert.DeserializeObject(reader.ReadToEnd(), ProviderList.GetType()); reader.Close(); } @@ -153,7 +173,8 @@ public void Save(string path) if (ProviderList == null) return; - using (TextWriter writer = new StreamWriter(path)) { + using (TextWriter writer = new StreamWriter(path)) + { writer.Write("{0}", JsonConvert.SerializeObject(ProviderList, ProviderList.GetType(), JSetting)); writer.Close(); } @@ -174,9 +195,11 @@ public override void Disconnect() public void Create(IList list) { - foreach (var l in list) { + foreach (var l in list) + { IProvider pvd = framework.ProviderManager.GetProvider(l.Id); - if (pvd == null) { + if (pvd == null) + { SingleProvider provider = new SingleProvider(framework); provider.Init(l.Id, l.Name); framework.ProviderManager.AddProvider(provider); @@ -202,7 +225,7 @@ public IExecutionProvider ExecutionProvider } public override void Send(ExecutionCommand command) { - if(command.RouteId == id) + if (command.RouteId == id) return; IExecutionProvider provider; @@ -247,6 +270,33 @@ public override void Unsubscribe(InstrumentList instrument) { DataProvider.Unsubscribe(instrument); } + #endregion + + #region auto start + private object GetSolutionManager() + { + // OpenQuant.Global.SolutionManager是静态属性,可以通过Get方式获得 + var g = Assembly.GetEntryAssembly().GetType("OpenQuant.Global"); + var sm = g.GetProperty("SolutionManager"); + return sm.GetGetMethod().Invoke(null, null); + } + + private void LoadSolution(object solutionManager, string filename) + { + var type = solutionManager.GetType(); + var m = type.GetMethod("LoadSolution", BindingFlags.NonPublic | BindingFlags.Instance); + m.Invoke(solutionManager, new object[] { new FileInfo(filename) }); + } + + private void Solution_Start(Form from) + { + Type type = from.GetType(); + var m = type.GetMethod("menuSolution_Start_Click", BindingFlags.NonPublic | BindingFlags.Instance); + m.Invoke(from, new object[] { null, null }); + } + + + #endregion } } diff --git a/QuantBox.API.Provider/QuantBox.APIProvider.csproj b/QuantBox.API.Provider/QuantBox.APIProvider.csproj index cf4a6a2..928239c 100644 --- a/QuantBox.API.Provider/QuantBox.APIProvider.csproj +++ b/QuantBox.API.Provider/QuantBox.APIProvider.csproj @@ -31,6 +31,9 @@ 4 + + ..\packages\CommandLineParser.2.6.0\lib\net461\CommandLine.dll + ..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll diff --git a/QuantBox.API.Provider/packages.config b/QuantBox.API.Provider/packages.config index cac1bc5..5144414 100644 --- a/QuantBox.API.Provider/packages.config +++ b/QuantBox.API.Provider/packages.config @@ -1,5 +1,6 @@  + \ No newline at end of file diff --git a/autorun_oq.bat b/autorun_oq.bat new file mode 100644 index 0000000..5273edd --- /dev/null +++ b/autorun_oq.bat @@ -0,0 +1,3 @@ +cd "C:\Program Files\SmartQuant Ltd\OpenQuant 2014" +C: +start OpenQuant.exe "D:\Users\Kan\Documents\OpenQuant 2014\Solutions\SMACrossover\SMACrossover.sln" --run \ No newline at end of file From a3c4775ec40ca8c88d2d0888ef327e26078e941f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Sun, 29 Sep 2019 21:18:16 +0800 Subject: [PATCH 29/41] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=E8=A1=8C=E5=81=9C=E6=AD=A2=E9=80=80=E5=87=BA=E7=AD=96=E7=95=A5?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QuantBox.API.Provider/CmdLine.cs | 91 +++++++++++ QuantBox.API.Provider/Host/ProviderHost.cs | 145 ++++++++++++------ .../QuantBox.APIProvider.csproj | 4 + QuantBox.API.Provider/packages.config | 1 + README.md | 28 +++- autorun_oq.bat | 2 +- exit_oq.bat | 1 + 7 files changed, 225 insertions(+), 47 deletions(-) create mode 100644 QuantBox.API.Provider/CmdLine.cs create mode 100644 exit_oq.bat diff --git a/QuantBox.API.Provider/CmdLine.cs b/QuantBox.API.Provider/CmdLine.cs new file mode 100644 index 0000000..bf2de33 --- /dev/null +++ b/QuantBox.API.Provider/CmdLine.cs @@ -0,0 +1,91 @@ +using CommandLine; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace QuantBox.APIProvider +{ + public class Options + { + [Option('f', "file", Required = false, HelpText = "策略项目文件")] + public string file { get; set; } + + [Option('i', "id", Required = false, HelpText = "实例数字ID,用于收到剪贴板事件时过滤使用")] + public int id { get; set; } + + [Option('r', "run", Required = false, Default = false, HelpText = "运行策略")] + public bool run { get; set; } + + [Option('s', "stop", Required = false, Default = false, HelpText = "停止策略")] + public bool stop { get; set; } + + [Option('e', "exit", Required = false, Default = false, HelpText = "退出程序")] + public bool exit { get; set; } + } + + public class CmdLine + { + private int id; + + public void ParseForStart(ProviderHost host) + { + // 通过命令行启动策略 + //cd "C:\Program Files\SmartQuant Ltd\OpenQuant 2014" + //C: + //start OpenQuant.exe --file="D:\Users\Kan\Documents\OpenQuant 2014\Solutions\SMACrossover\SMACrossover.sln" --id=100 --run + + var args = System.Environment.GetCommandLineArgs(); + var text = System.Environment.CommandLine; + Console.WriteLine($"命令行: {text}"); + CommandLine.Parser.Default.ParseArguments(args) + .WithParsed(opts => RunOptions(opts, host)) + .WithNotParsed((errs) => HandleParseError(errs)); + } + + public void ParseForStop(ProviderHost host) + { + //echo --id=100 --stop --exit | clip + IDataObject ido = Clipboard.GetDataObject(); + + if (!ido.GetDataPresent(DataFormats.Text)) + return; + + var text = ido.GetData(DataFormats.Text) as string; + Console.WriteLine($"剪贴板: {text}"); + CommandLine.Parser.Default.ParseArguments(text.Split(' ')) + .WithParsed(opts => ExitOptions(opts, host)) + .WithNotParsed((errs) => HandleParseError(errs)); + } + + void RunOptions(Options opts, ProviderHost host) + { + // 记下ID,退出时使用 + id = opts.id; + + if (string.IsNullOrEmpty(opts.file)) + return; + + if (!(new FileInfo(opts.file).Exists)) + return; + + host.Solution_Start_Thread(opts); + } + + void ExitOptions(Options opts, ProviderHost host) + { + if (id != opts.id) + return; + + host.Solution_Stop_Thread(opts); + } + + void HandleParseError(IEnumerable errs) + { + // Application.Exit(); + } + } +} diff --git a/QuantBox.API.Provider/Host/ProviderHost.cs b/QuantBox.API.Provider/Host/ProviderHost.cs index 66025be..63e6f9e 100644 --- a/QuantBox.API.Provider/Host/ProviderHost.cs +++ b/QuantBox.API.Provider/Host/ProviderHost.cs @@ -12,6 +12,8 @@ using System.Reflection; using System.Windows.Forms; using CommandLine; +using ClipboardMonitor; +using System.Threading; namespace QuantBox.APIProvider { @@ -49,36 +51,78 @@ public string Version get { return Assembly.GetExecutingAssembly().GetName().Version.ToString(); } } - class Options + private CmdLine cmdLine = null; + + public ProviderHost(Framework framework) + : base(framework) { - [Value(0, MetaName = "filename", Required = true, HelpText = "项目路径")] - public string filename { get; set; } + Init(100, "API Host"); + + ConfigPath = Path.Combine(Installation.ConfigDir.FullName, "API_Host.json"); + ProviderList = new BindingList(); + + Load(ConfigPath); + if (ProviderList == null) + ProviderList = new BindingList(); + + string applicationDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + + Create(ProviderList); + + ProviderList.ListChanged += ProviderList_ListChanged; + + cmdLine = new CmdLine(); + + cmdLine.ParseForStart(this); - [Option('r', "run", Required = false, Default = false, HelpText = "运行策略.")] - public bool run { get; set; } + new ClipboardNotifications(); + ClipboardNotifications.ClipboardUpdate += ClipboardNotifications_ClipboardUpdate; } - void RunOptions(Options opts) + private void ClipboardNotifications_ClipboardUpdate(object sender, EventArgs e) + { + cmdLine.ParseForStop(this); + } + + private Form GetMainForm() + { + foreach (Form f in Application.OpenForms) + { + if (f.Name == "MainForm") + return f; + } + return null; + } + + public void Solution_Start_Thread(Options opts) { - if (!(new FileInfo(opts.filename).Exists)) - return; - System.Threading.ThreadPool.QueueUserWorkItem(delegate { + DateTime dt = DateTime.Now; // 检查界面是否正常启动 - while (Application.OpenForms.Count == 0 || Application.OpenForms[0].Name != "MainForm") + var mainForm = GetMainForm(); + while (mainForm == null) { - System.Threading.Thread.Sleep(1000); + Thread.Sleep(1000); + mainForm = GetMainForm(); + + // 如果1分钟找不到就退出循环 + var ts = DateTime.Now - dt; + if (ts.TotalSeconds > 60) + { + return; + } } - var mainForm = Application.OpenForms[0]; var sm = GetSolutionManager(); + Thread.Sleep(1000); mainForm.SafeInvoke(() => { - LoadSolution(sm, opts.filename); + LoadSolution(sm, opts.file); }); - if(opts.run) + if (opts.run) { + Thread.Sleep(3000); mainForm.SafeInvoke(() => { Solution_Start(mainForm); @@ -87,38 +131,37 @@ void RunOptions(Options opts) }); } - void HandleParseError(IEnumerable errs) + public void Solution_Stop_Thread(Options opts) { - - } - - public ProviderHost(Framework framework) - : base(framework) - { - Init(100, "API Host"); - - ConfigPath = Path.Combine(Installation.ConfigDir.FullName, "API_Host.json"); - ProviderList = new BindingList(); - - Load(ConfigPath); - if (ProviderList == null) - ProviderList = new BindingList(); - - string applicationDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - - Create(ProviderList); - - ProviderList.ListChanged += ProviderList_ListChanged; - - // 通过命令行启动策略 - //cd "C:\Program Files\SmartQuant Ltd\OpenQuant 2014" - //C: - //start OpenQuant.exe "D:\Users\Kan\Documents\OpenQuant 2014\Solutions\SMACrossover\SMACrossover.sln" --run - var args = System.Environment.GetCommandLineArgs().ToList(); - args.RemoveAt(0); - CommandLine.Parser.Default.ParseArguments(args) - .WithParsed(opts => RunOptions(opts)) - .WithNotParsed((errs) => HandleParseError(errs)); + System.Threading.ThreadPool.QueueUserWorkItem(delegate + { + var mainForm = GetMainForm(); + if(mainForm == null) + { + return; + } + var sm = GetSolutionManager(); + if (opts.stop) + { + // 没有停止的需要停止才能退出 + if (framework.StrategyManager.Status != StrategyStatus.Stopped) + { + Thread.Sleep(1000); + mainForm.SafeInvoke(() => + { + Solution_Stop(mainForm); + }); + } + } + if (opts.exit) + { + Thread.Sleep(3000); + mainForm.SafeInvoke(() => + { + File_Exit(mainForm); + }); + } + }); } ~ProviderHost() @@ -295,7 +338,19 @@ private void Solution_Start(Form from) m.Invoke(from, new object[] { null, null }); } + private void Solution_Stop(Form from) + { + Type type = from.GetType(); + var m = type.GetMethod("menuSolution_Stop_Click", BindingFlags.NonPublic | BindingFlags.Instance); + m.Invoke(from, new object[] { null, null }); + } + private void File_Exit(Form from) + { + Type type = from.GetType(); + var m = type.GetMethod("menuFile_Exit_Click", BindingFlags.NonPublic | BindingFlags.Instance); + m.Invoke(from, new object[] { null, null }); + } #endregion } diff --git a/QuantBox.API.Provider/QuantBox.APIProvider.csproj b/QuantBox.API.Provider/QuantBox.APIProvider.csproj index 928239c..ec05c74 100644 --- a/QuantBox.API.Provider/QuantBox.APIProvider.csproj +++ b/QuantBox.API.Provider/QuantBox.APIProvider.csproj @@ -31,6 +31,9 @@ 4 + + ..\packages\ClipboardMonitor.0.3\lib\net40\ClipboardMonitor.dll + ..\packages\CommandLineParser.2.6.0\lib\net461\CommandLine.dll @@ -65,6 +68,7 @@ + diff --git a/QuantBox.API.Provider/packages.config b/QuantBox.API.Provider/packages.config index 5144414..c934824 100644 --- a/QuantBox.API.Provider/packages.config +++ b/QuantBox.API.Provider/packages.config @@ -1,5 +1,6 @@  + diff --git a/README.md b/README.md index fe735b2..1711038 100644 --- a/README.md +++ b/README.md @@ -1 +1,27 @@ -#QuantBox.APIProvider +# QuantBox.APIProvider +OpenQuant2014的行情交易插件,使用XAPI统一接口 + +## 特殊功能 +命令启停OQ功能 + +1. 启动OQ,并打开指定策略,并运行 +通过**命令行**传入参数 +- --file: 策略绝对路径。如果空格必须用引号 +- --run: 运行策略。否则只打开策略 +- --id: 识别码。用于监控剪贴板时过滤命令 + +``` +cd "C:\Program Files\SmartQuant Ltd\OpenQuant 2014" +C: +start OpenQuant.exe --file="D:\Users\Kan\Documents\OpenQuant 2014\Solutions\SMACrossover\SMACrossover.sln" --id=100 --run +``` + +2. 停止策略,并退出程序 +通过**剪贴板**传入参数。 +- --id: 识别码。用于监控剪贴板时过滤命令 +- --stop: 停止策略。必须先停止才能退出 +- --exit: 退出程序。 +``` +echo --id=100 --stop --exit | clip +``` +只要向剪贴板复制`--id=100 --stop --exit`即可,这个复制可以手工实现,也可以灵活使用管道符|将echo的回显重定向到剪贴板clip \ No newline at end of file diff --git a/autorun_oq.bat b/autorun_oq.bat index 5273edd..9ffa4d2 100644 --- a/autorun_oq.bat +++ b/autorun_oq.bat @@ -1,3 +1,3 @@ cd "C:\Program Files\SmartQuant Ltd\OpenQuant 2014" C: -start OpenQuant.exe "D:\Users\Kan\Documents\OpenQuant 2014\Solutions\SMACrossover\SMACrossover.sln" --run \ No newline at end of file +start OpenQuant.exe --file="D:\Users\Kan\Documents\OpenQuant 2014\Solutions\SMACrossover\SMACrossover.sln" --id=100 --run \ No newline at end of file diff --git a/exit_oq.bat b/exit_oq.bat new file mode 100644 index 0000000..4ea8643 --- /dev/null +++ b/exit_oq.bat @@ -0,0 +1 @@ +echo --id=100 --stop --exit | clip \ No newline at end of file From a8ca6dae8ed401ce5f3f8dcf73e705ab529b69ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Tue, 22 Oct 2019 09:55:23 +0800 Subject: [PATCH 30/41] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=88=90net=20standard?= =?UTF-8?q?=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../QuantBox.APIProvider.csproj | 156 ------------------ .../QuantBox.APIProvider.csproj.user | 7 - .../QuantBox.APIProvider_Linux.csproj | 95 ----------- QuantBox.API.Provider/app.config | 3 - QuantBox.API.Provider/packages.config | 7 - QuantBox.APIProvider.sln | 34 ++++ .../CmdLine.cs | 17 +- .../ControlExtention.cs | 6 +- .../Host/ProviderHost.cs | 140 +--------------- QuantBox.APIProvider/Host/ProviderHost_UI.cs | 154 +++++++++++++++++ .../Host/ProviderItem.cs | 0 .../PathHelper.cs | 0 .../Properties/AssemblyInfo.cs | 0 ...tBox.APIProvider.Single.ApiItem.datasource | 0 ...x.APIProvider.Single.ServerItem.datasource | 0 ...Box.APIProvider.Single.UserItem.datasource | 0 .../PropertySorter.cs | 0 .../QuantBox.APIProvider.csproj | 32 ++++ .../QuantBox.APIProvider.csproj.user | 4 + .../Single/ApiItem.cs | 28 ++-- .../Single/BaseMap.cs | 0 .../Single/Extensions.cs | 0 .../Single/ExternalOrderRecord.cs | 0 .../Single/HistoricalDataRecord.cs | 0 .../Single/InstrumentJson.cs | 0 .../Single/MarketDataRecord.cs | 0 .../Single/NoTypeConverterJsonConverter.cs | 0 .../Single/OrderMap.cs | 0 .../Single/OrderRecord.cs | 0 .../Single/QuoteMap.cs | 0 .../Single/QuoteRecord.cs | 0 .../Single/ServerItem.cs | 0 .../Single/SessionTimeItem.cs | 0 .../Single/SingleProvider.API.Connection.cs | 4 - .../SingleProvider.API.HistoricalData.cs | 0 .../Single/SingleProvider.API.MarketData.cs | 0 .../Single/SingleProvider.API.Order.cs | 5 - .../Single/SingleProvider.API.Quote.cs | 9 +- .../Single/SingleProvider.API.cs | 0 .../Single/SingleProvider.DataProvider.cs | 0 .../SingleProvider.ExecutionProvider.cs | 0 .../SingleProvider.HistoricalDataProvider.cs | 0 .../SingleProvider.InstrumentProvider.cs | 0 .../Single/SingleProvider.Other.cs | 0 .../Single/SingleProvider.Provider.cs | 0 .../Single/SingleProvider.Settings.cs | 34 ++-- .../Single/UserItem.cs | 0 .../UI/ApiControlForm.Designer.cs | 6 +- .../UI/ApiControlForm.cs | 12 +- .../UI/ApiControlForm.resx | 0 .../UI/ApiControlTypeEditor.cs | 16 +- .../UI/ApiManagerForm.Designer.cs | 6 +- .../UI/ApiManagerForm.cs | 5 +- .../UI/ApiManagerForm.resx | 0 .../UI/ApiManagerTypeEditor.cs | 16 +- .../UI/ApiTypeSelectorEditor.cs | 13 +- .../UI/ComboBoxItemTypeConvert.cs | 0 .../UI/JTypeDescriptor.cs | 0 .../UI/ServerItemConverter.cs | 0 .../UI/UserItemConverter.cs | 8 +- QuantBox.APIProvider_Windows.sln | 31 ---- .../QuantBox.Extensions.csproj | 78 +-------- .../QuantBox.Extensions_Linux.csproj | 67 -------- 63 files changed, 328 insertions(+), 665 deletions(-) delete mode 100644 QuantBox.API.Provider/QuantBox.APIProvider.csproj delete mode 100644 QuantBox.API.Provider/QuantBox.APIProvider.csproj.user delete mode 100644 QuantBox.API.Provider/QuantBox.APIProvider_Linux.csproj delete mode 100644 QuantBox.API.Provider/app.config delete mode 100644 QuantBox.API.Provider/packages.config create mode 100644 QuantBox.APIProvider.sln rename {QuantBox.API.Provider => QuantBox.APIProvider}/CmdLine.cs (92%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/ControlExtention.cs (91%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Host/ProviderHost.cs (59%) create mode 100644 QuantBox.APIProvider/Host/ProviderHost_UI.cs rename {QuantBox.API.Provider => QuantBox.APIProvider}/Host/ProviderItem.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/PathHelper.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Properties/AssemblyInfo.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Properties/DataSources/QuantBox.APIProvider.Single.ApiItem.datasource (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Properties/DataSources/QuantBox.APIProvider.Single.ServerItem.datasource (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Properties/DataSources/QuantBox.APIProvider.Single.UserItem.datasource (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/PropertySorter.cs (100%) create mode 100644 QuantBox.APIProvider/QuantBox.APIProvider.csproj create mode 100644 QuantBox.APIProvider/QuantBox.APIProvider.csproj.user rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/ApiItem.cs (88%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/BaseMap.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/Extensions.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/ExternalOrderRecord.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/HistoricalDataRecord.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/InstrumentJson.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/MarketDataRecord.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/NoTypeConverterJsonConverter.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/OrderMap.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/OrderRecord.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/QuoteMap.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/QuoteRecord.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/ServerItem.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/SessionTimeItem.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/SingleProvider.API.Connection.cs (99%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/SingleProvider.API.HistoricalData.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/SingleProvider.API.MarketData.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/SingleProvider.API.Order.cs (98%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/SingleProvider.API.Quote.cs (92%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/SingleProvider.API.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/SingleProvider.DataProvider.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/SingleProvider.ExecutionProvider.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/SingleProvider.HistoricalDataProvider.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/SingleProvider.InstrumentProvider.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/SingleProvider.Other.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/SingleProvider.Provider.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/SingleProvider.Settings.cs (94%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/Single/UserItem.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/UI/ApiControlForm.Designer.cs (99%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/UI/ApiControlForm.cs (92%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/UI/ApiControlForm.resx (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/UI/ApiControlTypeEditor.cs (85%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/UI/ApiManagerForm.Designer.cs (99%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/UI/ApiManagerForm.cs (99%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/UI/ApiManagerForm.resx (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/UI/ApiManagerTypeEditor.cs (85%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/UI/ApiTypeSelectorEditor.cs (91%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/UI/ComboBoxItemTypeConvert.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/UI/JTypeDescriptor.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/UI/ServerItemConverter.cs (100%) rename {QuantBox.API.Provider => QuantBox.APIProvider}/UI/UserItemConverter.cs (81%) delete mode 100644 QuantBox.APIProvider_Windows.sln delete mode 100644 QuantBox.Extensions/QuantBox.Extensions_Linux.csproj diff --git a/QuantBox.API.Provider/QuantBox.APIProvider.csproj b/QuantBox.API.Provider/QuantBox.APIProvider.csproj deleted file mode 100644 index ec05c74..0000000 --- a/QuantBox.API.Provider/QuantBox.APIProvider.csproj +++ /dev/null @@ -1,156 +0,0 @@ - - - - - Debug - AnyCPU - {E86E1057-B344-4805-A836-43606154677E} - Library - Properties - QuantBox.APIProvider - QuantBox.APIProvider - v4.8 - 512 - - - - true - full - false - C:\Program Files\SmartQuant Ltd\OpenQuant 2014\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\packages\ClipboardMonitor.0.3\lib\net40\ClipboardMonitor.dll - - - ..\packages\CommandLineParser.2.6.0\lib\net461\CommandLine.dll - - - ..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll - - - ..\packages\NLog.4.6.7\lib\net45\NLog.dll - - - False - C:\Program Files\SmartQuant Ltd\OpenQuant 2014\SmartQuant.dll - - - - - - - - - - - - - - - - - - False - C:\Program Files\SmartQuant Ltd\OpenQuant 2014\XAPI_CSharp.exe - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Form - - - ApiControlForm.cs - - - Form - - - ApiManagerForm.cs - - - - - - - - - - - - Designer - - - - - - - - ApiControlForm.cs - - - ApiManagerForm.cs - - - - - {d8d82e27-47f5-4579-92ad-416da86ad601} - QuantBox.Extensions - - - - - \ No newline at end of file diff --git a/QuantBox.API.Provider/QuantBox.APIProvider.csproj.user b/QuantBox.API.Provider/QuantBox.APIProvider.csproj.user deleted file mode 100644 index ee82c1f..0000000 --- a/QuantBox.API.Provider/QuantBox.APIProvider.csproj.user +++ /dev/null @@ -1,7 +0,0 @@ - - - - Program - C:\Program Files\SmartQuant Ltd\OpenQuant 2014\OpenQuant.x86.exe - - \ No newline at end of file diff --git a/QuantBox.API.Provider/QuantBox.APIProvider_Linux.csproj b/QuantBox.API.Provider/QuantBox.APIProvider_Linux.csproj deleted file mode 100644 index 58a1aa7..0000000 --- a/QuantBox.API.Provider/QuantBox.APIProvider_Linux.csproj +++ /dev/null @@ -1,95 +0,0 @@ - - - - - Debug - AnyCPU - {E86E1057-B344-4805-A836-43606154677E} - Library - Properties - QuantBox.APIProvider - QuantBox.APIProvider - v4.5.1 - 512 - - - - true - full - false - C:\Program Files\SmartQuant Ltd\OpenQuant 2014\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - ..\packages\Newtonsoft.Json.6.0.5\lib\net45\Newtonsoft.Json.dll - - - ..\packages\NLog.3.1.0.0\lib\net45\NLog.dll - - - ..\..\bin\SmartQuant.dll - - - ..\..\bin\QuantBox.XAPI.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {D8D82E27-47F5-4579-92AD-416DA86AD601} - QuantBox.Extensions_Linux - - - \ No newline at end of file diff --git a/QuantBox.API.Provider/app.config b/QuantBox.API.Provider/app.config deleted file mode 100644 index 99ddf3e..0000000 --- a/QuantBox.API.Provider/app.config +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/QuantBox.API.Provider/packages.config b/QuantBox.API.Provider/packages.config deleted file mode 100644 index c934824..0000000 --- a/QuantBox.API.Provider/packages.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/QuantBox.APIProvider.sln b/QuantBox.APIProvider.sln new file mode 100644 index 0000000..ecede0b --- /dev/null +++ b/QuantBox.APIProvider.sln @@ -0,0 +1,34 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29411.108 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuantBox.Extensions", "QuantBox.Extensions\QuantBox.Extensions.csproj", "{1A772F95-B670-40AC-8D29-2B82A4B95E12}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuantBox.APIProvider", "QuantBox.APIProvider\QuantBox.APIProvider.csproj", "{DD59FAE6-8CA6-4389-B934-06F26A08D289}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1A772F95-B670-40AC-8D29-2B82A4B95E12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1A772F95-B670-40AC-8D29-2B82A4B95E12}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1A772F95-B670-40AC-8D29-2B82A4B95E12}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1A772F95-B670-40AC-8D29-2B82A4B95E12}.Release|Any CPU.Build.0 = Release|Any CPU + {DD59FAE6-8CA6-4389-B934-06F26A08D289}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DD59FAE6-8CA6-4389-B934-06F26A08D289}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DD59FAE6-8CA6-4389-B934-06F26A08D289}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DD59FAE6-8CA6-4389-B934-06F26A08D289}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DE721877-AECD-4501-976D-2AA3C52F9CE0} + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + StartupItem = SMACrossover\Realtime\Realtime.csproj + EndGlobalSection +EndGlobal diff --git a/QuantBox.API.Provider/CmdLine.cs b/QuantBox.APIProvider/CmdLine.cs similarity index 92% rename from QuantBox.API.Provider/CmdLine.cs rename to QuantBox.APIProvider/CmdLine.cs index bf2de33..f1aee41 100644 --- a/QuantBox.API.Provider/CmdLine.cs +++ b/QuantBox.APIProvider/CmdLine.cs @@ -1,11 +1,12 @@ -using CommandLine; -using System; +using System; using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; + +using CommandLine; + +#if NET48 using System.Windows.Forms; +#endif namespace QuantBox.APIProvider { @@ -38,8 +39,8 @@ public void ParseForStart(ProviderHost host) //C: //start OpenQuant.exe --file="D:\Users\Kan\Documents\OpenQuant 2014\Solutions\SMACrossover\SMACrossover.sln" --id=100 --run - var args = System.Environment.GetCommandLineArgs(); - var text = System.Environment.CommandLine; + var args = Environment.GetCommandLineArgs(); + var text = Environment.CommandLine; Console.WriteLine($"命令行: {text}"); CommandLine.Parser.Default.ParseArguments(args) .WithParsed(opts => RunOptions(opts, host)) @@ -48,6 +49,7 @@ public void ParseForStart(ProviderHost host) public void ParseForStop(ProviderHost host) { +#if NET48 //echo --id=100 --stop --exit | clip IDataObject ido = Clipboard.GetDataObject(); @@ -59,6 +61,7 @@ public void ParseForStop(ProviderHost host) CommandLine.Parser.Default.ParseArguments(text.Split(' ')) .WithParsed(opts => ExitOptions(opts, host)) .WithNotParsed((errs) => HandleParseError(errs)); +#endif } void RunOptions(Options opts, ProviderHost host) diff --git a/QuantBox.API.Provider/ControlExtention.cs b/QuantBox.APIProvider/ControlExtention.cs similarity index 91% rename from QuantBox.API.Provider/ControlExtention.cs rename to QuantBox.APIProvider/ControlExtention.cs index abf4943..696e84e 100644 --- a/QuantBox.API.Provider/ControlExtention.cs +++ b/QuantBox.APIProvider/ControlExtention.cs @@ -3,10 +3,13 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Windows.Forms; + namespace QuantBox.APIProvider { +#if NET48 + using System.Windows.Forms; + public static class ControlExtention { public delegate void InvokeHandler(); @@ -23,4 +26,5 @@ public static void SafeInvoke(this Control control, InvokeHandler handler) } } } +#endif } diff --git a/QuantBox.API.Provider/Host/ProviderHost.cs b/QuantBox.APIProvider/Host/ProviderHost.cs similarity index 59% rename from QuantBox.API.Provider/Host/ProviderHost.cs rename to QuantBox.APIProvider/Host/ProviderHost.cs index 63e6f9e..95abcea 100644 --- a/QuantBox.API.Provider/Host/ProviderHost.cs +++ b/QuantBox.APIProvider/Host/ProviderHost.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; + using SmartQuant; using System.IO; @@ -10,18 +8,18 @@ using System.ComponentModel; using QuantBox.APIProvider.Single; using System.Reflection; -using System.Windows.Forms; using CommandLine; using ClipboardMonitor; using System.Threading; + namespace QuantBox.APIProvider { /// /// Provder宿主 /// 由它进行其它Provder的初始创建,以及订单的路由 /// - public class ProviderHost : Provider, IExecutionProvider, IDataProvider + public partial class ProviderHost : Provider, IExecutionProvider, IDataProvider { #region Provider [Description("创建Provder的记录文件路径")] @@ -51,8 +49,6 @@ public string Version get { return Assembly.GetExecutingAssembly().GetName().Version.ToString(); } } - private CmdLine cmdLine = null; - public ProviderHost(Framework framework) : base(framework) { @@ -71,97 +67,14 @@ public ProviderHost(Framework framework) ProviderList.ListChanged += ProviderList_ListChanged; +#if NET48 cmdLine = new CmdLine(); cmdLine.ParseForStart(this); new ClipboardNotifications(); ClipboardNotifications.ClipboardUpdate += ClipboardNotifications_ClipboardUpdate; - } - - private void ClipboardNotifications_ClipboardUpdate(object sender, EventArgs e) - { - cmdLine.ParseForStop(this); - } - - private Form GetMainForm() - { - foreach (Form f in Application.OpenForms) - { - if (f.Name == "MainForm") - return f; - } - return null; - } - - public void Solution_Start_Thread(Options opts) - { - System.Threading.ThreadPool.QueueUserWorkItem(delegate - { - DateTime dt = DateTime.Now; - // 检查界面是否正常启动 - var mainForm = GetMainForm(); - while (mainForm == null) - { - Thread.Sleep(1000); - mainForm = GetMainForm(); - - // 如果1分钟找不到就退出循环 - var ts = DateTime.Now - dt; - if (ts.TotalSeconds > 60) - { - return; - } - } - - var sm = GetSolutionManager(); - Thread.Sleep(1000); - mainForm.SafeInvoke(() => - { - LoadSolution(sm, opts.file); - }); - if (opts.run) - { - Thread.Sleep(3000); - mainForm.SafeInvoke(() => - { - Solution_Start(mainForm); - }); - } - }); - } - - public void Solution_Stop_Thread(Options opts) - { - System.Threading.ThreadPool.QueueUserWorkItem(delegate - { - var mainForm = GetMainForm(); - if(mainForm == null) - { - return; - } - var sm = GetSolutionManager(); - if (opts.stop) - { - // 没有停止的需要停止才能退出 - if (framework.StrategyManager.Status != StrategyStatus.Stopped) - { - Thread.Sleep(1000); - mainForm.SafeInvoke(() => - { - Solution_Stop(mainForm); - }); - } - } - if (opts.exit) - { - Thread.Sleep(3000); - mainForm.SafeInvoke(() => - { - File_Exit(mainForm); - }); - } - }); +#endif } ~ProviderHost() @@ -205,9 +118,9 @@ public void Load(string path) } ProviderList = ret as BindingList; } - catch + catch(Exception ex) { - // ignored + Console.WriteLine(ex); } } @@ -314,44 +227,5 @@ public override void Unsubscribe(InstrumentList instrument) DataProvider.Unsubscribe(instrument); } #endregion - - #region auto start - private object GetSolutionManager() - { - // OpenQuant.Global.SolutionManager是静态属性,可以通过Get方式获得 - var g = Assembly.GetEntryAssembly().GetType("OpenQuant.Global"); - var sm = g.GetProperty("SolutionManager"); - return sm.GetGetMethod().Invoke(null, null); - } - - private void LoadSolution(object solutionManager, string filename) - { - var type = solutionManager.GetType(); - var m = type.GetMethod("LoadSolution", BindingFlags.NonPublic | BindingFlags.Instance); - m.Invoke(solutionManager, new object[] { new FileInfo(filename) }); - } - - private void Solution_Start(Form from) - { - Type type = from.GetType(); - var m = type.GetMethod("menuSolution_Start_Click", BindingFlags.NonPublic | BindingFlags.Instance); - m.Invoke(from, new object[] { null, null }); - } - - private void Solution_Stop(Form from) - { - Type type = from.GetType(); - var m = type.GetMethod("menuSolution_Stop_Click", BindingFlags.NonPublic | BindingFlags.Instance); - m.Invoke(from, new object[] { null, null }); - } - - private void File_Exit(Form from) - { - Type type = from.GetType(); - var m = type.GetMethod("menuFile_Exit_Click", BindingFlags.NonPublic | BindingFlags.Instance); - m.Invoke(from, new object[] { null, null }); - } - - #endregion } } diff --git a/QuantBox.APIProvider/Host/ProviderHost_UI.cs b/QuantBox.APIProvider/Host/ProviderHost_UI.cs new file mode 100644 index 0000000..8a569c4 --- /dev/null +++ b/QuantBox.APIProvider/Host/ProviderHost_UI.cs @@ -0,0 +1,154 @@ +using System; + +using SmartQuant; +using System.IO; +using System.Reflection; + +using CommandLine; + +using System.Threading; + +#if NET48 +using ClipboardMonitor; +using System.Windows.Forms; +#endif + +namespace QuantBox.APIProvider +{ + /// + /// Provder宿主 + /// 由它进行其它Provder的初始创建,以及订单的路由 + /// + public partial class ProviderHost + { + private CmdLine cmdLine = null; + + private void ClipboardNotifications_ClipboardUpdate(object sender, EventArgs e) + { + cmdLine.ParseForStop(this); + } + + private object GetSolutionManager() + { + // OpenQuant.Global.SolutionManager是静态属性,可以通过Get方式获得 + var g = Assembly.GetEntryAssembly().GetType("OpenQuant.Global"); + var sm = g.GetProperty("SolutionManager"); + return sm.GetGetMethod().Invoke(null, null); + } + + private void LoadSolution(object solutionManager, string filename) + { + var type = solutionManager.GetType(); + var m = type.GetMethod("LoadSolution", BindingFlags.NonPublic | BindingFlags.Instance); + m.Invoke(solutionManager, new object[] { new FileInfo(filename) }); + } + + public void Solution_Start_Thread(Options opts) + { +#if NET48 + System.Threading.ThreadPool.QueueUserWorkItem(delegate + { + DateTime dt = DateTime.Now; + // 检查界面是否正常启动 + var mainForm = GetMainForm(); + while (mainForm == null) + { + Thread.Sleep(1000); + mainForm = GetMainForm(); + + // 如果1分钟找不到就退出循环 + var ts = DateTime.Now - dt; + if (ts.TotalSeconds > 60) + { + return; + } + } + + var sm = GetSolutionManager(); + Thread.Sleep(1000); + mainForm.SafeInvoke(() => + { + LoadSolution(sm, opts.file); + }); + if (opts.run) + { + Thread.Sleep(3000); + mainForm.SafeInvoke(() => + { + Solution_Start(mainForm); + }); + } + }); +#endif + } + + public void Solution_Stop_Thread(Options opts) + { +#if NET48 + System.Threading.ThreadPool.QueueUserWorkItem(delegate + { + var mainForm = GetMainForm(); + if (mainForm == null) + { + return; + } + var sm = GetSolutionManager(); + if (opts.stop) + { + // 没有停止的需要停止才能退出 + if (framework.StrategyManager.Status != StrategyStatus.Stopped) + { + Thread.Sleep(1000); + mainForm.SafeInvoke(() => + { + Solution_Stop(mainForm); + }); + } + } + if (opts.exit) + { + Thread.Sleep(3000); + mainForm.SafeInvoke(() => + { + File_Exit(mainForm); + }); + } + }); +#endif + } + + +#if NET48 + + private Form GetMainForm() + { + foreach (Form f in Application.OpenForms) + { + if (f.Name == "MainForm") + return f; + } + return null; + } + private void Solution_Start(Form from) + { + Type type = from.GetType(); + var m = type.GetMethod("menuSolution_Start_Click", BindingFlags.NonPublic | BindingFlags.Instance); + m.Invoke(from, new object[] { null, null }); + } + + private void Solution_Stop(Form from) + { + Type type = from.GetType(); + var m = type.GetMethod("menuSolution_Stop_Click", BindingFlags.NonPublic | BindingFlags.Instance); + m.Invoke(from, new object[] { null, null }); + } + + private void File_Exit(Form from) + { + Type type = from.GetType(); + var m = type.GetMethod("menuFile_Exit_Click", BindingFlags.NonPublic | BindingFlags.Instance); + m.Invoke(from, new object[] { null, null }); + } +#endif + } +} diff --git a/QuantBox.API.Provider/Host/ProviderItem.cs b/QuantBox.APIProvider/Host/ProviderItem.cs similarity index 100% rename from QuantBox.API.Provider/Host/ProviderItem.cs rename to QuantBox.APIProvider/Host/ProviderItem.cs diff --git a/QuantBox.API.Provider/PathHelper.cs b/QuantBox.APIProvider/PathHelper.cs similarity index 100% rename from QuantBox.API.Provider/PathHelper.cs rename to QuantBox.APIProvider/PathHelper.cs diff --git a/QuantBox.API.Provider/Properties/AssemblyInfo.cs b/QuantBox.APIProvider/Properties/AssemblyInfo.cs similarity index 100% rename from QuantBox.API.Provider/Properties/AssemblyInfo.cs rename to QuantBox.APIProvider/Properties/AssemblyInfo.cs diff --git a/QuantBox.API.Provider/Properties/DataSources/QuantBox.APIProvider.Single.ApiItem.datasource b/QuantBox.APIProvider/Properties/DataSources/QuantBox.APIProvider.Single.ApiItem.datasource similarity index 100% rename from QuantBox.API.Provider/Properties/DataSources/QuantBox.APIProvider.Single.ApiItem.datasource rename to QuantBox.APIProvider/Properties/DataSources/QuantBox.APIProvider.Single.ApiItem.datasource diff --git a/QuantBox.API.Provider/Properties/DataSources/QuantBox.APIProvider.Single.ServerItem.datasource b/QuantBox.APIProvider/Properties/DataSources/QuantBox.APIProvider.Single.ServerItem.datasource similarity index 100% rename from QuantBox.API.Provider/Properties/DataSources/QuantBox.APIProvider.Single.ServerItem.datasource rename to QuantBox.APIProvider/Properties/DataSources/QuantBox.APIProvider.Single.ServerItem.datasource diff --git a/QuantBox.API.Provider/Properties/DataSources/QuantBox.APIProvider.Single.UserItem.datasource b/QuantBox.APIProvider/Properties/DataSources/QuantBox.APIProvider.Single.UserItem.datasource similarity index 100% rename from QuantBox.API.Provider/Properties/DataSources/QuantBox.APIProvider.Single.UserItem.datasource rename to QuantBox.APIProvider/Properties/DataSources/QuantBox.APIProvider.Single.UserItem.datasource diff --git a/QuantBox.API.Provider/PropertySorter.cs b/QuantBox.APIProvider/PropertySorter.cs similarity index 100% rename from QuantBox.API.Provider/PropertySorter.cs rename to QuantBox.APIProvider/PropertySorter.cs diff --git a/QuantBox.APIProvider/QuantBox.APIProvider.csproj b/QuantBox.APIProvider/QuantBox.APIProvider.csproj new file mode 100644 index 0000000..ce6d2ed --- /dev/null +++ b/QuantBox.APIProvider/QuantBox.APIProvider.csproj @@ -0,0 +1,32 @@ + + + + netstandard2.0 + false + QuantBox.APIProvider + QuantBox.APIProvider + + + + + + + + + + + + + + + + C:\Program Files\SmartQuant Ltd\OpenQuant 2014\SmartQuant.dll + + + + + C:\Program Files\SmartQuant Ltd\OpenQuant 2014\XAPI_CSharp.dll + + + + diff --git a/QuantBox.APIProvider/QuantBox.APIProvider.csproj.user b/QuantBox.APIProvider/QuantBox.APIProvider.csproj.user new file mode 100644 index 0000000..88a5509 --- /dev/null +++ b/QuantBox.APIProvider/QuantBox.APIProvider.csproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/QuantBox.API.Provider/Single/ApiItem.cs b/QuantBox.APIProvider/Single/ApiItem.cs similarity index 88% rename from QuantBox.API.Provider/Single/ApiItem.cs rename to QuantBox.APIProvider/Single/ApiItem.cs index 37b7545..043f509 100644 --- a/QuantBox.API.Provider/Single/ApiItem.cs +++ b/QuantBox.APIProvider/Single/ApiItem.cs @@ -1,18 +1,13 @@ -using Newtonsoft.Json; -using QuantBox.APIProvider.UI; +using QuantBox.APIProvider.UI; using System; -using System.Collections.Generic; using System.ComponentModel; -using System.ComponentModel.Design; -using System.Drawing.Design; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; using XAPI; namespace QuantBox.APIProvider.Single { +#if NET48 + using System.Drawing.Design; +#endif /// /// 由用户选择Dll,然后加载,得到 /// @@ -28,9 +23,9 @@ public class ApiItem : ICloneable private string _dllPath; private string _typeName; - private IXApi CheckApi(string typeName,string dllPath) + private IXApi CheckApi(string typeName, string dllPath) { - if(string.IsNullOrEmpty(typeName)) + if (string.IsNullOrEmpty(typeName)) { TypeName = "XAPI.Callback.XApi, XAPI_CSharp"; return null; @@ -55,8 +50,9 @@ private IXApi CheckApi(string typeName,string dllPath) } return api; } - +#if NET48 [Editor(typeof(System.Windows.Forms.Design.FileNameEditor), typeof(System.Drawing.Design.UITypeEditor))] +#endif public string DllPath { get @@ -76,7 +72,8 @@ public string TypeName { return _typeName; } - set { + set + { _typeName = value; Api = CheckApi(_typeName, _dllPath); } @@ -100,12 +97,13 @@ public string TypeName public string LogPrefix { get; set; } - +#if NET48 + [Editor(typeof(ApiTypeSelectorEditor), typeof(UITypeEditor))] +#endif [Category(CATEGORY_TYPE)] [ReadOnly(true)] public ApiType Type { get; set; } [Category(CATEGORY_TYPE)] - [Editor(typeof(ApiTypeSelectorEditor), typeof(UITypeEditor))] public ApiType UseType { get; set; } diff --git a/QuantBox.API.Provider/Single/BaseMap.cs b/QuantBox.APIProvider/Single/BaseMap.cs similarity index 100% rename from QuantBox.API.Provider/Single/BaseMap.cs rename to QuantBox.APIProvider/Single/BaseMap.cs diff --git a/QuantBox.API.Provider/Single/Extensions.cs b/QuantBox.APIProvider/Single/Extensions.cs similarity index 100% rename from QuantBox.API.Provider/Single/Extensions.cs rename to QuantBox.APIProvider/Single/Extensions.cs diff --git a/QuantBox.API.Provider/Single/ExternalOrderRecord.cs b/QuantBox.APIProvider/Single/ExternalOrderRecord.cs similarity index 100% rename from QuantBox.API.Provider/Single/ExternalOrderRecord.cs rename to QuantBox.APIProvider/Single/ExternalOrderRecord.cs diff --git a/QuantBox.API.Provider/Single/HistoricalDataRecord.cs b/QuantBox.APIProvider/Single/HistoricalDataRecord.cs similarity index 100% rename from QuantBox.API.Provider/Single/HistoricalDataRecord.cs rename to QuantBox.APIProvider/Single/HistoricalDataRecord.cs diff --git a/QuantBox.API.Provider/Single/InstrumentJson.cs b/QuantBox.APIProvider/Single/InstrumentJson.cs similarity index 100% rename from QuantBox.API.Provider/Single/InstrumentJson.cs rename to QuantBox.APIProvider/Single/InstrumentJson.cs diff --git a/QuantBox.API.Provider/Single/MarketDataRecord.cs b/QuantBox.APIProvider/Single/MarketDataRecord.cs similarity index 100% rename from QuantBox.API.Provider/Single/MarketDataRecord.cs rename to QuantBox.APIProvider/Single/MarketDataRecord.cs diff --git a/QuantBox.API.Provider/Single/NoTypeConverterJsonConverter.cs b/QuantBox.APIProvider/Single/NoTypeConverterJsonConverter.cs similarity index 100% rename from QuantBox.API.Provider/Single/NoTypeConverterJsonConverter.cs rename to QuantBox.APIProvider/Single/NoTypeConverterJsonConverter.cs diff --git a/QuantBox.API.Provider/Single/OrderMap.cs b/QuantBox.APIProvider/Single/OrderMap.cs similarity index 100% rename from QuantBox.API.Provider/Single/OrderMap.cs rename to QuantBox.APIProvider/Single/OrderMap.cs diff --git a/QuantBox.API.Provider/Single/OrderRecord.cs b/QuantBox.APIProvider/Single/OrderRecord.cs similarity index 100% rename from QuantBox.API.Provider/Single/OrderRecord.cs rename to QuantBox.APIProvider/Single/OrderRecord.cs diff --git a/QuantBox.API.Provider/Single/QuoteMap.cs b/QuantBox.APIProvider/Single/QuoteMap.cs similarity index 100% rename from QuantBox.API.Provider/Single/QuoteMap.cs rename to QuantBox.APIProvider/Single/QuoteMap.cs diff --git a/QuantBox.API.Provider/Single/QuoteRecord.cs b/QuantBox.APIProvider/Single/QuoteRecord.cs similarity index 100% rename from QuantBox.API.Provider/Single/QuoteRecord.cs rename to QuantBox.APIProvider/Single/QuoteRecord.cs diff --git a/QuantBox.API.Provider/Single/ServerItem.cs b/QuantBox.APIProvider/Single/ServerItem.cs similarity index 100% rename from QuantBox.API.Provider/Single/ServerItem.cs rename to QuantBox.APIProvider/Single/ServerItem.cs diff --git a/QuantBox.API.Provider/Single/SessionTimeItem.cs b/QuantBox.APIProvider/Single/SessionTimeItem.cs similarity index 100% rename from QuantBox.API.Provider/Single/SessionTimeItem.cs rename to QuantBox.APIProvider/Single/SessionTimeItem.cs diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs b/QuantBox.APIProvider/Single/SingleProvider.API.Connection.cs similarity index 99% rename from QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs rename to QuantBox.APIProvider/Single/SingleProvider.API.Connection.cs index f4cd0f3..579ffc8 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.Connection.cs +++ b/QuantBox.APIProvider/Single/SingleProvider.API.Connection.cs @@ -1,10 +1,6 @@ using SmartQuant; using System; -using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; using XAPI; using NLog; diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.HistoricalData.cs b/QuantBox.APIProvider/Single/SingleProvider.API.HistoricalData.cs similarity index 100% rename from QuantBox.API.Provider/Single/SingleProvider.API.HistoricalData.cs rename to QuantBox.APIProvider/Single/SingleProvider.API.HistoricalData.cs diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.MarketData.cs b/QuantBox.APIProvider/Single/SingleProvider.API.MarketData.cs similarity index 100% rename from QuantBox.API.Provider/Single/SingleProvider.API.MarketData.cs rename to QuantBox.APIProvider/Single/SingleProvider.API.MarketData.cs diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs b/QuantBox.APIProvider/Single/SingleProvider.API.Order.cs similarity index 98% rename from QuantBox.API.Provider/Single/SingleProvider.API.Order.cs rename to QuantBox.APIProvider/Single/SingleProvider.API.Order.cs index 875f36a..02de6ae 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.Order.cs +++ b/QuantBox.APIProvider/Single/SingleProvider.API.Order.cs @@ -1,15 +1,10 @@ using SmartQuant; using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; using QuantBox.Extensions; using XAPI.Callback; using XAPI; -using Newtonsoft.Json; using SQ = SmartQuant; diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.Quote.cs b/QuantBox.APIProvider/Single/SingleProvider.API.Quote.cs similarity index 92% rename from QuantBox.API.Provider/Single/SingleProvider.API.Quote.cs rename to QuantBox.APIProvider/Single/SingleProvider.API.Quote.cs index febe93f..1803ea2 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.API.Quote.cs +++ b/QuantBox.APIProvider/Single/SingleProvider.API.Quote.cs @@ -1,13 +1,6 @@ -using Newtonsoft.Json; -using NLog; -using QuantBox.Extensions; +using QuantBox.Extensions; using SmartQuant; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; using XAPI; using XAPI.Callback; diff --git a/QuantBox.API.Provider/Single/SingleProvider.API.cs b/QuantBox.APIProvider/Single/SingleProvider.API.cs similarity index 100% rename from QuantBox.API.Provider/Single/SingleProvider.API.cs rename to QuantBox.APIProvider/Single/SingleProvider.API.cs diff --git a/QuantBox.API.Provider/Single/SingleProvider.DataProvider.cs b/QuantBox.APIProvider/Single/SingleProvider.DataProvider.cs similarity index 100% rename from QuantBox.API.Provider/Single/SingleProvider.DataProvider.cs rename to QuantBox.APIProvider/Single/SingleProvider.DataProvider.cs diff --git a/QuantBox.API.Provider/Single/SingleProvider.ExecutionProvider.cs b/QuantBox.APIProvider/Single/SingleProvider.ExecutionProvider.cs similarity index 100% rename from QuantBox.API.Provider/Single/SingleProvider.ExecutionProvider.cs rename to QuantBox.APIProvider/Single/SingleProvider.ExecutionProvider.cs diff --git a/QuantBox.API.Provider/Single/SingleProvider.HistoricalDataProvider.cs b/QuantBox.APIProvider/Single/SingleProvider.HistoricalDataProvider.cs similarity index 100% rename from QuantBox.API.Provider/Single/SingleProvider.HistoricalDataProvider.cs rename to QuantBox.APIProvider/Single/SingleProvider.HistoricalDataProvider.cs diff --git a/QuantBox.API.Provider/Single/SingleProvider.InstrumentProvider.cs b/QuantBox.APIProvider/Single/SingleProvider.InstrumentProvider.cs similarity index 100% rename from QuantBox.API.Provider/Single/SingleProvider.InstrumentProvider.cs rename to QuantBox.APIProvider/Single/SingleProvider.InstrumentProvider.cs diff --git a/QuantBox.API.Provider/Single/SingleProvider.Other.cs b/QuantBox.APIProvider/Single/SingleProvider.Other.cs similarity index 100% rename from QuantBox.API.Provider/Single/SingleProvider.Other.cs rename to QuantBox.APIProvider/Single/SingleProvider.Other.cs diff --git a/QuantBox.API.Provider/Single/SingleProvider.Provider.cs b/QuantBox.APIProvider/Single/SingleProvider.Provider.cs similarity index 100% rename from QuantBox.API.Provider/Single/SingleProvider.Provider.cs rename to QuantBox.APIProvider/Single/SingleProvider.Provider.cs diff --git a/QuantBox.API.Provider/Single/SingleProvider.Settings.cs b/QuantBox.APIProvider/Single/SingleProvider.Settings.cs similarity index 94% rename from QuantBox.API.Provider/Single/SingleProvider.Settings.cs rename to QuantBox.APIProvider/Single/SingleProvider.Settings.cs index e0a1bb9..54e51f3 100644 --- a/QuantBox.API.Provider/Single/SingleProvider.Settings.cs +++ b/QuantBox.APIProvider/Single/SingleProvider.Settings.cs @@ -1,17 +1,14 @@ -using NLog; -using QuantBox.APIProvider.UI; -using XAPI; +using XAPI; using SmartQuant; -using System; -using System.Collections.Generic; using System.ComponentModel; -using System.Drawing.Design; -using System.Linq; -using System.Text; -using System.Threading.Tasks; + +using QuantBox.APIProvider.UI; namespace QuantBox.APIProvider.Single { +#if NET48 + using System.Drawing.Design; +#endif public partial class SingleProvider : Provider { private const string CATEGORY_SETTINGS = "Settings"; @@ -130,9 +127,12 @@ public int QueryPositionInterval #region 通用 + +#if NET48 + [Editor(typeof(System.Windows.Forms.Design.FolderNameEditor), typeof(UITypeEditor))] +#endif [Category(CATEGORY_COMMON)] [Description("配置文件路径")] - [Editor(typeof(System.Windows.Forms.Design.FolderNameEditor), typeof(UITypeEditor))] public string ConfigPath { get; set; } [Category(CATEGORY_COMMON)] @@ -140,12 +140,18 @@ public int QueryPositionInterval public BindingList SessionTimeList { get; set; } #endregion - [Category(CATEGORY_SETTINGS), Editor(typeof(ApiManagerTypeEditor), typeof(UITypeEditor)), - Description("综合设置")] +#if NET48 + [Editor(typeof(ApiManagerTypeEditor), typeof(UITypeEditor))] +#endif + [Category(CATEGORY_SETTINGS)] + [Description("综合设置")] public string AllConfig { get; set; } - [Category(CATEGORY_SETTINGS), Editor(typeof(ApiControlTypeEditor), typeof(UITypeEditor)), - Description("综合控制")] +#if NET48 + [Editor(typeof(ApiManagerTypeEditor), typeof(UITypeEditor))] +#endif + [Category(CATEGORY_SETTINGS)] + [Description("综合控制")] public string AllControl { get; set; } [Browsable(false)] diff --git a/QuantBox.API.Provider/Single/UserItem.cs b/QuantBox.APIProvider/Single/UserItem.cs similarity index 100% rename from QuantBox.API.Provider/Single/UserItem.cs rename to QuantBox.APIProvider/Single/UserItem.cs diff --git a/QuantBox.API.Provider/UI/ApiControlForm.Designer.cs b/QuantBox.APIProvider/UI/ApiControlForm.Designer.cs similarity index 99% rename from QuantBox.API.Provider/UI/ApiControlForm.Designer.cs rename to QuantBox.APIProvider/UI/ApiControlForm.Designer.cs index 881b246..3a43a92 100644 --- a/QuantBox.API.Provider/UI/ApiControlForm.Designer.cs +++ b/QuantBox.APIProvider/UI/ApiControlForm.Designer.cs @@ -1,5 +1,6 @@ namespace QuantBox.APIProvider.UI { +#if NET48 partial class ApiControlForm { /// @@ -20,7 +21,7 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } - #region Windows Form Designer generated code + #region Windows Form Designer generated code /// /// Required method for Designer support - do not modify @@ -188,7 +189,7 @@ private void InitializeComponent() } - #endregion + #endregion private System.Windows.Forms.GroupBox groupBox1; private System.Windows.Forms.Label label1; @@ -204,4 +205,5 @@ private void InitializeComponent() private System.Windows.Forms.TextBox textBox_PortfolioID2; private System.Windows.Forms.TextBox textBox_PortfolioID1; } +#endif } \ No newline at end of file diff --git a/QuantBox.API.Provider/UI/ApiControlForm.cs b/QuantBox.APIProvider/UI/ApiControlForm.cs similarity index 92% rename from QuantBox.API.Provider/UI/ApiControlForm.cs rename to QuantBox.APIProvider/UI/ApiControlForm.cs index 4b09b61..87463c6 100644 --- a/QuantBox.API.Provider/UI/ApiControlForm.cs +++ b/QuantBox.APIProvider/UI/ApiControlForm.cs @@ -1,17 +1,12 @@ using QuantBox.APIProvider.Single; using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; + using XAPI; namespace QuantBox.APIProvider.UI { +#if NET48 + using System.Windows.Forms; public partial class ApiControlForm : Form { public ApiControlForm() @@ -74,4 +69,5 @@ private void ApiControlForm_Load(object sender, EventArgs e) comboBox_BusinessType.DataSource = Enum.GetValues(typeof(BusinessType)); } } +#endif } diff --git a/QuantBox.API.Provider/UI/ApiControlForm.resx b/QuantBox.APIProvider/UI/ApiControlForm.resx similarity index 100% rename from QuantBox.API.Provider/UI/ApiControlForm.resx rename to QuantBox.APIProvider/UI/ApiControlForm.resx diff --git a/QuantBox.API.Provider/UI/ApiControlTypeEditor.cs b/QuantBox.APIProvider/UI/ApiControlTypeEditor.cs similarity index 85% rename from QuantBox.API.Provider/UI/ApiControlTypeEditor.cs rename to QuantBox.APIProvider/UI/ApiControlTypeEditor.cs index 6b33d85..365ff2d 100644 --- a/QuantBox.API.Provider/UI/ApiControlTypeEditor.cs +++ b/QuantBox.APIProvider/UI/ApiControlTypeEditor.cs @@ -1,15 +1,14 @@ -using QuantBox.APIProvider.Single; -using System; -using System.Collections.Generic; +using System; using System.ComponentModel; -using System.Drawing.Design; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms.Design; + +using QuantBox.APIProvider.Single; namespace QuantBox.APIProvider.UI { +#if NET48 + using System.Drawing.Design; + using System.Windows.Forms.Design; + class ApiControlTypeEditor : UITypeEditor { // Methods @@ -41,4 +40,5 @@ public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext contex return base.GetEditStyle(context); } } +#endif } diff --git a/QuantBox.API.Provider/UI/ApiManagerForm.Designer.cs b/QuantBox.APIProvider/UI/ApiManagerForm.Designer.cs similarity index 99% rename from QuantBox.API.Provider/UI/ApiManagerForm.Designer.cs rename to QuantBox.APIProvider/UI/ApiManagerForm.Designer.cs index 7c5d0f2..cb5030b 100644 --- a/QuantBox.API.Provider/UI/ApiManagerForm.Designer.cs +++ b/QuantBox.APIProvider/UI/ApiManagerForm.Designer.cs @@ -1,5 +1,6 @@ namespace QuantBox.APIProvider.UI { +#if NET48 partial class ApiManagerForm { /// @@ -20,7 +21,7 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } - #region Windows Form Designer generated code +#region Windows Form Designer generated code /// /// Required method for Designer support - do not modify @@ -288,7 +289,7 @@ private void InitializeComponent() } - #endregion +#endregion private System.Windows.Forms.ListBox listBox_UserList; private System.Windows.Forms.PropertyGrid propertyGrid; @@ -310,4 +311,5 @@ private void InitializeComponent() private System.Windows.Forms.BindingSource serverItemBindingSource; private System.Windows.Forms.BindingSource apiItemBindingSource; } +#endif } \ No newline at end of file diff --git a/QuantBox.API.Provider/UI/ApiManagerForm.cs b/QuantBox.APIProvider/UI/ApiManagerForm.cs similarity index 99% rename from QuantBox.API.Provider/UI/ApiManagerForm.cs rename to QuantBox.APIProvider/UI/ApiManagerForm.cs index 1bee632..e493594 100644 --- a/QuantBox.API.Provider/UI/ApiManagerForm.cs +++ b/QuantBox.APIProvider/UI/ApiManagerForm.cs @@ -7,10 +7,12 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Windows.Forms; + namespace QuantBox.APIProvider.UI { +#if NET48 + using System.Windows.Forms; public partial class ApiManagerForm : Form { public ApiManagerForm() @@ -169,4 +171,5 @@ private void ApiManagerForm_FormClosed(object sender, FormClosedEventArgs e) provider.Save(); } } +#endif } diff --git a/QuantBox.API.Provider/UI/ApiManagerForm.resx b/QuantBox.APIProvider/UI/ApiManagerForm.resx similarity index 100% rename from QuantBox.API.Provider/UI/ApiManagerForm.resx rename to QuantBox.APIProvider/UI/ApiManagerForm.resx diff --git a/QuantBox.API.Provider/UI/ApiManagerTypeEditor.cs b/QuantBox.APIProvider/UI/ApiManagerTypeEditor.cs similarity index 85% rename from QuantBox.API.Provider/UI/ApiManagerTypeEditor.cs rename to QuantBox.APIProvider/UI/ApiManagerTypeEditor.cs index f6273e4..fb58f6c 100644 --- a/QuantBox.API.Provider/UI/ApiManagerTypeEditor.cs +++ b/QuantBox.APIProvider/UI/ApiManagerTypeEditor.cs @@ -1,15 +1,14 @@ -using QuantBox.APIProvider.Single; -using System; -using System.Collections.Generic; +using System; using System.ComponentModel; -using System.Drawing.Design; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms.Design; + +using QuantBox.APIProvider.Single; namespace QuantBox.APIProvider.UI { +#if NET48 + using System.Drawing.Design; + using System.Windows.Forms.Design; + class ApiManagerTypeEditor : UITypeEditor { // Methods @@ -40,4 +39,5 @@ public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext contex return base.GetEditStyle(context); } } +#endif } diff --git a/QuantBox.API.Provider/UI/ApiTypeSelectorEditor.cs b/QuantBox.APIProvider/UI/ApiTypeSelectorEditor.cs similarity index 91% rename from QuantBox.API.Provider/UI/ApiTypeSelectorEditor.cs rename to QuantBox.APIProvider/UI/ApiTypeSelectorEditor.cs index b42b388..e639961 100644 --- a/QuantBox.API.Provider/UI/ApiTypeSelectorEditor.cs +++ b/QuantBox.APIProvider/UI/ApiTypeSelectorEditor.cs @@ -1,17 +1,16 @@ using QuantBox.APIProvider.Single; using System; -using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.Design; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; + using XAPI; namespace QuantBox.APIProvider.UI { +#if NET48 + using System.Windows.Forms; + class ApiTypeSelectorEditor : ObjectSelectorEditor { private ObjectSelectorEditor.Selector selector; @@ -44,7 +43,7 @@ protected override void FillTreeWithData(ObjectSelectorEditor.Selector selector, { if (category != ApiType.None) { - if((instance.Type & category) == category) + if ((instance.Type & category) == category) { selector.AddNode(category.ToString(), (int)category, null).Checked = (instance.UseType & category) == category; } @@ -63,5 +62,5 @@ private void method_0(object sender, TreeViewCancelEventArgs e) e.Cancel = true; } } - +#endif } diff --git a/QuantBox.API.Provider/UI/ComboBoxItemTypeConvert.cs b/QuantBox.APIProvider/UI/ComboBoxItemTypeConvert.cs similarity index 100% rename from QuantBox.API.Provider/UI/ComboBoxItemTypeConvert.cs rename to QuantBox.APIProvider/UI/ComboBoxItemTypeConvert.cs diff --git a/QuantBox.API.Provider/UI/JTypeDescriptor.cs b/QuantBox.APIProvider/UI/JTypeDescriptor.cs similarity index 100% rename from QuantBox.API.Provider/UI/JTypeDescriptor.cs rename to QuantBox.APIProvider/UI/JTypeDescriptor.cs diff --git a/QuantBox.API.Provider/UI/ServerItemConverter.cs b/QuantBox.APIProvider/UI/ServerItemConverter.cs similarity index 100% rename from QuantBox.API.Provider/UI/ServerItemConverter.cs rename to QuantBox.APIProvider/UI/ServerItemConverter.cs diff --git a/QuantBox.API.Provider/UI/UserItemConverter.cs b/QuantBox.APIProvider/UI/UserItemConverter.cs similarity index 81% rename from QuantBox.API.Provider/UI/UserItemConverter.cs rename to QuantBox.APIProvider/UI/UserItemConverter.cs index 2434f31..b45af1a 100644 --- a/QuantBox.API.Provider/UI/UserItemConverter.cs +++ b/QuantBox.APIProvider/UI/UserItemConverter.cs @@ -1,11 +1,7 @@ using QuantBox.APIProvider.Single; -using System; -using System.Collections; -using System.Collections.Generic; + using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; + namespace QuantBox.APIProvider.UI { diff --git a/QuantBox.APIProvider_Windows.sln b/QuantBox.APIProvider_Windows.sln deleted file mode 100644 index 6e9aac4..0000000 --- a/QuantBox.APIProvider_Windows.sln +++ /dev/null @@ -1,31 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.21005.1 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuantBox.APIProvider", "QuantBox.API.Provider\QuantBox.APIProvider.csproj", "{E86E1057-B344-4805-A836-43606154677E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuantBox.Extensions", "QuantBox.Extensions\QuantBox.Extensions.csproj", "{D8D82E27-47F5-4579-92AD-416DA86AD601}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E86E1057-B344-4805-A836-43606154677E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E86E1057-B344-4805-A836-43606154677E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E86E1057-B344-4805-A836-43606154677E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E86E1057-B344-4805-A836-43606154677E}.Release|Any CPU.Build.0 = Release|Any CPU - {D8D82E27-47F5-4579-92AD-416DA86AD601}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D8D82E27-47F5-4579-92AD-416DA86AD601}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D8D82E27-47F5-4579-92AD-416DA86AD601}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D8D82E27-47F5-4579-92AD-416DA86AD601}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(MonoDevelopProperties) = preSolution - StartupItem = SMACrossover\Realtime\Realtime.csproj - EndGlobalSection -EndGlobal diff --git a/QuantBox.Extensions/QuantBox.Extensions.csproj b/QuantBox.Extensions/QuantBox.Extensions.csproj index 0ebed29..1283ef8 100644 --- a/QuantBox.Extensions/QuantBox.Extensions.csproj +++ b/QuantBox.Extensions/QuantBox.Extensions.csproj @@ -1,79 +1,17 @@ - - - + + - Debug - AnyCPU - {D8D82E27-47F5-4579-92AD-416DA86AD601} - Library - Properties - QuantBox.Extensions - QuantBox.Extensions - v4.8 - 512 - - - - true - full - false - C:\Program Files\SmartQuant Ltd\OpenQuant 2014\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - C:\Program Files\SmartQuant Ltd\OpenQuant 2014\ - TRACE - prompt - 4 - - - + netstandard2.0 + false + - False C:\Program Files\SmartQuant Ltd\OpenQuant 2014\SmartQuant.dll - - - - - - False - C:\Program Files\SmartQuant Ltd\OpenQuant 2014\XAPI_CSharp.exe + C:\Program Files\SmartQuant Ltd\OpenQuant 2014\XAPI_CSharp.dll - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + diff --git a/QuantBox.Extensions/QuantBox.Extensions_Linux.csproj b/QuantBox.Extensions/QuantBox.Extensions_Linux.csproj deleted file mode 100644 index ac1f5d4..0000000 --- a/QuantBox.Extensions/QuantBox.Extensions_Linux.csproj +++ /dev/null @@ -1,67 +0,0 @@ - - - - - Debug - AnyCPU - {D8D82E27-47F5-4579-92AD-416DA86AD601} - Library - Properties - QuantBox.Extensions - QuantBox.Extensions - v4.5.1 - 512 - - - - true - full - false - C:\Program Files\SmartQuant Ltd\OpenQuant 2014\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - ..\..\bin\SmartQuant.dll - - - ..\..\bin\QuantBox.XAPI.dll - - - - - - - - - - - - - - - - \ No newline at end of file From 1535bf77c2137c0b0b46f0f05fdbd09f0bed1276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Fri, 22 Nov 2019 11:25:04 +0800 Subject: [PATCH 31/41] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AE=9A=E6=97=B6?= =?UTF-8?q?=E8=B4=A6=E5=8F=B7=E9=80=9A=E7=9F=A5=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QuantBox.APIProvider/Host/ProviderHost.cs | 9 +- QuantBox.APIProvider/Host/ProviderHost_UI.cs | 9 +- .../QuantBox.APIProvider.csproj | 6 +- .../Single/SingleProvider.API.cs | 88 +++++++++++++++++++ .../Single/SingleProvider.Provider.cs | 2 + 5 files changed, 109 insertions(+), 5 deletions(-) diff --git a/QuantBox.APIProvider/Host/ProviderHost.cs b/QuantBox.APIProvider/Host/ProviderHost.cs index 95abcea..836ab8d 100644 --- a/QuantBox.APIProvider/Host/ProviderHost.cs +++ b/QuantBox.APIProvider/Host/ProviderHost.cs @@ -69,8 +69,15 @@ public ProviderHost(Framework framework) #if NET48 cmdLine = new CmdLine(); + try + { + cmdLine.ParseForStart(this); + } + catch + { - cmdLine.ParseForStart(this); + } + new ClipboardNotifications(); ClipboardNotifications.ClipboardUpdate += ClipboardNotifications_ClipboardUpdate; diff --git a/QuantBox.APIProvider/Host/ProviderHost_UI.cs b/QuantBox.APIProvider/Host/ProviderHost_UI.cs index 8a569c4..b715a89 100644 --- a/QuantBox.APIProvider/Host/ProviderHost_UI.cs +++ b/QuantBox.APIProvider/Host/ProviderHost_UI.cs @@ -25,7 +25,14 @@ public partial class ProviderHost private void ClipboardNotifications_ClipboardUpdate(object sender, EventArgs e) { - cmdLine.ParseForStop(this); + try + { + cmdLine.ParseForStop(this); + } + catch + { + + } } private object GetSolutionManager() diff --git a/QuantBox.APIProvider/QuantBox.APIProvider.csproj b/QuantBox.APIProvider/QuantBox.APIProvider.csproj index ce6d2ed..e0cf4a5 100644 --- a/QuantBox.APIProvider/QuantBox.APIProvider.csproj +++ b/QuantBox.APIProvider/QuantBox.APIProvider.csproj @@ -1,7 +1,7 @@  - netstandard2.0 + net48;netstandard2.0 false QuantBox.APIProvider QuantBox.APIProvider @@ -10,8 +10,8 @@ - - + + diff --git a/QuantBox.APIProvider/Single/SingleProvider.API.cs b/QuantBox.APIProvider/Single/SingleProvider.API.cs index 7547be8..689329e 100644 --- a/QuantBox.APIProvider/Single/SingleProvider.API.cs +++ b/QuantBox.APIProvider/Single/SingleProvider.API.cs @@ -32,6 +32,8 @@ static SingleProvider() //记录合约列表,从实盘合约名到对象的映射 private readonly Dictionary _dictInstruments = new Dictionary(); private readonly Dictionary _dictInstrumentsStatus = new Dictionary(); + private SortedDictionary _dictAccounts_current = new SortedDictionary(); + private SortedDictionary _dictAccounts_last = new SortedDictionary(); public static int GetDate(DateTime dt) { @@ -90,6 +92,21 @@ private void OnRspQryTradingAccount_callback(object sender, ref AccountField acc if (size1 <= 0) return; + _dictAccounts_current[account.AccountID] = account; + if (bIsLast) + { + if(_dictAccounts_last.Count == 0) + { + _dictAccounts_last = _dictAccounts_current; + } + + ProcessAccounts(_dictAccounts_current, _dictAccounts_last); + + _dictAccounts_last = _dictAccounts_current; + // 使用新容器 + _dictAccounts_current = new SortedDictionary(); + } + if (!IsConnected) return; @@ -119,6 +136,30 @@ private void OnRspQryTradingAccount_callback(object sender, ref AccountField acc } } + private void ProcessAccounts(SortedDictionary dict_curr, SortedDictionary dict_last) + { + // 开始比较 + var list_curr = _dictAccounts_current.Values.ToList(); + var list_last = _dictAccounts_last.Values.ToList(); + var len = Math.Min(list_curr.Count, list_last.Count); + string str = ""; + for (int i = 0; i < len; ++i) + { + var curr = list_curr[i]; + var last = list_last[i]; + + if (true) + { + str = AccountMsg_Long(curr, last); + } + else + { + str = AccountMsg_Short(curr, last); + } + } + alog.Info(str); + } + private void OnRspQryInvestor_callback(object sender, ref InvestorField investor, int size1, bool bIsLast) { if (size1 <= 0) @@ -260,5 +301,52 @@ public InstrumentStatusField GetInstrumentStatus(string symbol) } return instrumentStatus; } + + private string AccountMsg_Long(AccountField current, AccountField last) + { + double risk = current.CurrMargin * 100.0 / current.Balance; + double balance_1 = (current.Balance - current.Deposit + current.Withdraw) - current.PreBalance; + double balance_2 = current.Balance - last.Balance; + + string str = ""; + + str += string.Format("{0:F2}%/{1:F0}/{2:F0}/{3:F0}", risk, current.PositionProfit, balance_1, balance_2); + str += string.Format("\n{0:F0}/{1:F0}/{2:F0}", current.CloseProfit, current.Commission, current.Available); + str += string.Format("\n风险度/持仓盈亏/日间权益差/区间权益差"); + str += string.Format("\n平仓盈亏/手续费/可用资金\n"); + + str += string.Format("\n{0:F0}/{1:F0}", current.Withdraw, current.Deposit); + str += string.Format("\n出/入金\n"); + + str += string.Format("\n{0:F0}-*+*-{1:F0}=*", current.Balance, current.PreBalance); + str += string.Format("\n(动态权益-入金+出金)-昨结权益=日间权益差"); + str += string.Format("\n动态权益-上期动态权益=区间权益差\n"); + + str += string.Format("\n{0:F0}/*=*", current.CurrMargin); + str += string.Format("\n占用保证金/动态权益=风险度\n"); + + str += string.Format("\n>>AccountID:{0}<<", current.AccountID); + + return str; + } + + private string AccountMsg_Short(AccountField current, AccountField last) + { + double risk = current.CurrMargin * 100.0 / current.Balance; + double balance_1 = (current.Balance - current.Deposit + current.Withdraw) - current.PreBalance; + double balance_2 = current.Balance - last.Balance; + + string str = ""; + + str += string.Format("{0:F2}%/{1:F0}/{2:F0}/{3:F0}", risk, current.PositionProfit, balance_1, balance_2); + str += string.Format("\n{0:F0}/{1:F0}/{2:F0}", current.CloseProfit, current.Commission, current.Available); + str += string.Format("\n{0:F0}", current.Balance); + str += string.Format("\n风险度/持仓盈亏/日间权益差/区间权益差"); + str += string.Format("\n平仓盈亏/手续费/可用资金"); + str += string.Format("\n动态权益"); + str += string.Format("\n>>AccountID:{0}<<", current.AccountID); + + return str; + } } } diff --git a/QuantBox.APIProvider/Single/SingleProvider.Provider.cs b/QuantBox.APIProvider/Single/SingleProvider.Provider.cs index 9d0939d..c7e68c0 100644 --- a/QuantBox.APIProvider/Single/SingleProvider.Provider.cs +++ b/QuantBox.APIProvider/Single/SingleProvider.Provider.cs @@ -16,6 +16,7 @@ namespace QuantBox.APIProvider.Single public partial class SingleProvider:Provider { private Logger xlog; + private Logger alog; private Logger barLog; private Logger tickLog; @@ -56,6 +57,7 @@ public void Init(byte id, string name) // 只是简单设置,等登录时将把账号设置上,X日志由于一些信息没法 xlog = LogManager.GetLogger(Name + ".X"); + alog = LogManager.GetLogger(Name + ".A"); barLog = LogManager.GetLogger("Bar"); tickLog = LogManager.GetLogger("Tick"); From 35009e67f22a6b8d5e3fb82727746b48d3d8cf84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Mon, 16 Dec 2019 17:20:35 +0800 Subject: [PATCH 32/41] =?UTF-8?q?=E6=94=B6=E7=9B=98=E5=90=8E=EF=BC=8C?= =?UTF-8?q?=E5=B0=86=E6=8C=82=E5=8D=95=E6=A0=87=E8=AE=B0=E6=88=90=E8=BF=87?= =?UTF-8?q?=E6=9C=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 373 ++++++++++++++++-- .../QuantBox.APIProvider.csproj | 4 + QuantBox.APIProvider/Single/BaseMap.cs | 35 +- QuantBox.APIProvider/Single/OrderMap.cs | 40 ++ .../Single/SingleProvider.API.Order.cs | 32 +- .../Single/SingleProvider.API.Quote.cs | 4 +- .../Single/SingleProvider.API.cs | 3 + .../Single/SingleProvider.DataProvider.cs | 8 +- .../SingleProvider.HistoricalDataProvider.cs | 4 +- .../Single/SingleProvider.Other.cs | 7 +- 10 files changed, 455 insertions(+), 55 deletions(-) diff --git a/.gitignore b/.gitignore index 96374c4..dfcfd56 100644 --- a/.gitignore +++ b/.gitignore @@ -1,43 +1,350 @@ -# Windows image file caches -Thumbs.db -ehthumbs.db +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore -# Folder config file -Desktop.ini +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates -# Recycle Bin used on file shares -$RECYCLE.BIN/ +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs -# Windows Installer files -*.cab -*.msi -*.msm -*.msp +# Mono auto generated files +mono_crash.* -# Windows shortcuts -*.lnk +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ -# ========================= -# Operating System Files -# ========================= +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ -# OSX -# ========================= +# Visual Studio 2017 auto generated files +Generated\ Files/ -.DS_Store -.AppleDouble -.LSOverride +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* -# Thumbnails -._* +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml -# Files that might appear on external disk -.Spotlight-V100 -.Trashes +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ diff --git a/QuantBox.APIProvider/QuantBox.APIProvider.csproj b/QuantBox.APIProvider/QuantBox.APIProvider.csproj index e0cf4a5..dadef3a 100644 --- a/QuantBox.APIProvider/QuantBox.APIProvider.csproj +++ b/QuantBox.APIProvider/QuantBox.APIProvider.csproj @@ -29,4 +29,8 @@ + + + + diff --git a/QuantBox.APIProvider/Single/BaseMap.cs b/QuantBox.APIProvider/Single/BaseMap.cs index 7f045b5..4c54317 100644 --- a/QuantBox.APIProvider/Single/BaseMap.cs +++ b/QuantBox.APIProvider/Single/BaseMap.cs @@ -12,7 +12,7 @@ namespace QuantBox.APIProvider.Single { class BaseMap { - private Framework framework; + protected Framework framework; protected SingleProvider provider; public BaseMap(Framework framework, SingleProvider provider) @@ -31,17 +31,6 @@ public ExecutionReport CreateReport( report.DateTime = framework.Clock.DateTime; - //report.Order = record.Order; - //report.Instrument = record.Order.Instrument; - - //report.Side = record.Order.Side; - //report.OrdType = record.Order.Type; - //report.TimeInForce = record.Order.TimeInForce; - - //report.OrdQty = record.Order.Qty; - //report.Price = record.Order.Price; - //report.StopPx = record.Order.StopPx; - report.AvgPx = record.AvgPx; report.CumQty = record.CumQty; report.LeavesQty = record.LeavesQty; @@ -55,6 +44,28 @@ public ExecutionReport CreateReport( return report; } + public ExecutionReport CreateReport( + Order order, + SQ.ExecType? execType, + SQ.OrderStatus? orderStatus) + { + ExecutionReport report = new ExecutionReport(order); + + report.DateTime = framework.Clock.DateTime; + + report.AvgPx = order.AvgPx; + report.CumQty = order.CumQty; + report.LeavesQty = order.LeavesQty; + + if (execType != null) + report.ExecType = execType.Value; + + if (orderStatus != null) + report.OrdStatus = orderStatus.Value; + + return report; + } + public void EmitExecutionReport(OrderRecord record, SQ.ExecType execType, SQ.OrderStatus orderStatus) { ExecutionReport report = CreateReport(record, execType, orderStatus); diff --git a/QuantBox.APIProvider/Single/OrderMap.cs b/QuantBox.APIProvider/Single/OrderMap.cs index 8e8f7b5..9aec76b 100644 --- a/QuantBox.APIProvider/Single/OrderMap.cs +++ b/QuantBox.APIProvider/Single/OrderMap.cs @@ -318,6 +318,46 @@ record = GetExternalOrder(ref trade); } } + public void ProcessExpired(ref InstrumentStatusField instrumentStatus, NLog.Logger log) + { + // 根据当前挂单来统计 + //if (workingOrders.Count == 0) + // return; + + if (instrumentStatus.InstrumentStatus != TradingPhaseType.Closed) + return; + + foreach (var order in framework.OrderManager.Orders) + { + // 量有点多,需要判断一下 + if (order.IsDone) + continue; + + var inst = order.Instrument; + + string altSymbol; + string altExchange; + string apiSymbol; + string apiExchange; + double apiTickSize; + string apiProductID; + + this.provider.GetApi_Symbol_Exchange_TickSize(inst, this.provider.Id, + out altSymbol, out altExchange, + out apiSymbol, out apiExchange, + out apiTickSize, + out apiProductID); + + if (apiProductID != instrumentStatus.InstrumentID) + continue; + + ExecutionReport report = CreateReport(order, SQ.ExecType.ExecExpired, SQ.OrderStatus.Expired); + report.LeavesQty = 0; + report.Text = "收盘,插件标记定单过期"; + provider.EmitExecutionReport(report); + } + } + public void ProcessNew(ref QuoteField quote, QuoteRecord record) { OrderRecord askRecord = new OrderRecord(record.AskOrder); diff --git a/QuantBox.APIProvider/Single/SingleProvider.API.Order.cs b/QuantBox.APIProvider/Single/SingleProvider.API.Order.cs index 02de6ae..81f111d 100644 --- a/QuantBox.APIProvider/Single/SingleProvider.API.Order.cs +++ b/QuantBox.APIProvider/Single/SingleProvider.API.Order.cs @@ -138,11 +138,13 @@ private void CmdNewOrderSingle(ExecutionCommand command) string apiSymbol; string apiExchange; double apiTickSize; + string apiProductID; GetApi_Symbol_Exchange_TickSize(command.Instrument, this.id, out altSymbol, out altExchange, out apiSymbol, out apiExchange, - out apiTickSize); + out apiTickSize, + out apiProductID); OrderField[] fields = new OrderField[1]; @@ -201,11 +203,13 @@ private void CmdNewOrderList(ExecutionCommand command) string apiSymbol; string apiExchange; double apiTickSize; + string apiProductID; - GetApi_Symbol_Exchange_TickSize(orders[i].Instrument, this.id, + GetApi_Symbol_Exchange_TickSize(command.Instrument, this.id, out altSymbol, out altExchange, out apiSymbol, out apiExchange, - out apiTickSize); + out apiTickSize, + out apiProductID); ToOrderStruct(ref fields[i], orders[i], apiSymbol, apiExchange); } @@ -262,7 +266,7 @@ private void OnRtnOrder_callback(object sender, ref OrderField order) private void OnRtnTrade_callback(object sender, ref TradeField trade) { - lock(this) + lock (this) { var log = (sender as XApi).GetLog(); log.Debug("OnRtnTrade:" + trade.ToFormattedString()); @@ -281,5 +285,25 @@ private void OnRtnTrade_callback(object sender, ref TradeField trade) } } } + + private void OnRtnOrder_Expired(ref InstrumentStatusField instrumentStatus) + { + if (_TdApi == null) + return; + + lock (this) + { + var log = _TdApi.GetLog(); + + try + { + orderMap.ProcessExpired(ref instrumentStatus, log); + } + catch (Exception ex) + { + log.Error(ex); + } + } + } } } diff --git a/QuantBox.APIProvider/Single/SingleProvider.API.Quote.cs b/QuantBox.APIProvider/Single/SingleProvider.API.Quote.cs index 1803ea2..542d95e 100644 --- a/QuantBox.APIProvider/Single/SingleProvider.API.Quote.cs +++ b/QuantBox.APIProvider/Single/SingleProvider.API.Quote.cs @@ -40,11 +40,13 @@ private void CmdNewQuote(ExecutionCommand command) string apiSymbol; string apiExchange; double apiTickSize; + string apiProductID; GetApi_Symbol_Exchange_TickSize(command.Instrument, this.id, out altSymbol, out altExchange, out apiSymbol, out apiExchange, - out apiTickSize); + out apiTickSize, + out apiProductID); Order bidOrder; Order askOrder; diff --git a/QuantBox.APIProvider/Single/SingleProvider.API.cs b/QuantBox.APIProvider/Single/SingleProvider.API.cs index 689329e..621ea1c 100644 --- a/QuantBox.APIProvider/Single/SingleProvider.API.cs +++ b/QuantBox.APIProvider/Single/SingleProvider.API.cs @@ -287,6 +287,9 @@ private void OnRtnInstrumentStatus_callback(object sender, ref InstrumentStatusF // 记录下来,后期可能要用到 _dictInstrumentsStatus[instrumentStatus.Symbol] = instrumentStatus; + // 考虑收盘后,主动为一些合约标记成过期 + OnRtnOrder_Expired(ref instrumentStatus); + // 合约状态信息太多了,也不关心,这里屏蔽显示 if (IsLogOnRtnInstrumentStatus) (sender as XApi).GetLog().Info("OnRtnInstrumentStatus:" + instrumentStatus.ToFormattedString()); diff --git a/QuantBox.APIProvider/Single/SingleProvider.DataProvider.cs b/QuantBox.APIProvider/Single/SingleProvider.DataProvider.cs index 45a2957..caa93bf 100644 --- a/QuantBox.APIProvider/Single/SingleProvider.DataProvider.cs +++ b/QuantBox.APIProvider/Single/SingleProvider.DataProvider.cs @@ -40,11 +40,13 @@ public override void Subscribe(Instrument instrument) string apiSymbol; string apiExchange; double apiTickSize; + string apiProductID; GetApi_Symbol_Exchange_TickSize(instrument, this.id, out altSymbol, out altExchange, out apiSymbol, out apiExchange, - out apiTickSize); + out apiTickSize, + out apiProductID); // 如果是对CTP接口,使用UFX的参数进行订阅是否有问题?IF1802.7,目前猜没有问题 string Symbol_Dot_Exchange = string.Format("{0}.{1}", apiSymbol, apiExchange); @@ -88,11 +90,13 @@ public override void Unsubscribe(Instrument instrument) string apiSymbol; string apiExchange; double apiTickSize; + string apiProductID; GetApi_Symbol_Exchange_TickSize(instrument, this.id, out altSymbol, out altExchange, out apiSymbol, out apiExchange, - out apiTickSize); + out apiTickSize, + out apiProductID); string Symbol_Dot_Exchange = string.Format("{0}.{1}", apiSymbol, apiExchange); string Symbol_Dot = string.Format("{0}.", apiSymbol); diff --git a/QuantBox.APIProvider/Single/SingleProvider.HistoricalDataProvider.cs b/QuantBox.APIProvider/Single/SingleProvider.HistoricalDataProvider.cs index f874b84..031ce5c 100644 --- a/QuantBox.APIProvider/Single/SingleProvider.HistoricalDataProvider.cs +++ b/QuantBox.APIProvider/Single/SingleProvider.HistoricalDataProvider.cs @@ -19,11 +19,13 @@ private HistoricalDataRequestField ToStruct(HistoricalDataRequest request) string apiSymbol; string apiExchange; double apiTickSize; + string apiProductID; GetApi_Symbol_Exchange_TickSize(request.Instrument, this.id, out altSymbol, out altExchange, out apiSymbol, out apiExchange, - out apiTickSize); + out apiTickSize, + out apiProductID); HistoricalDataRequestField field = new HistoricalDataRequestField(); field.Symbol = request.Instrument.Symbol; diff --git a/QuantBox.APIProvider/Single/SingleProvider.Other.cs b/QuantBox.APIProvider/Single/SingleProvider.Other.cs index 50e387d..137b9fc 100644 --- a/QuantBox.APIProvider/Single/SingleProvider.Other.cs +++ b/QuantBox.APIProvider/Single/SingleProvider.Other.cs @@ -11,10 +11,11 @@ namespace QuantBox.APIProvider.Single public partial class SingleProvider { // 得到API中的合约名与交易所 - private void GetApi_Symbol_Exchange_TickSize(Instrument instrument, byte id, + public void GetApi_Symbol_Exchange_TickSize(Instrument instrument, byte id, out string altSymbol, out string altExchange, out string apiSymbol, out string apiExchange, - out double apiTickSize) + out double apiTickSize, + out string apiProductID) { // 取合约别名 altSymbol = instrument.GetSymbol(id); @@ -24,6 +25,7 @@ private void GetApi_Symbol_Exchange_TickSize(Instrument instrument, byte id, // 取合约在API中的名字 apiSymbol = altSymbol; apiExchange = altExchange; + apiProductID = ""; // 对于UFX,没有实现查询合约的功能,所以这里其实使用的是AltID中的信息 // 屏蔽这个功能,订阅的合约就根据设置来了 @@ -35,6 +37,7 @@ private void GetApi_Symbol_Exchange_TickSize(Instrument instrument, byte id, apiSymbol = _Instrument.InstrumentID; apiExchange = _Instrument.ExchangeID; apiTickSize = _Instrument.PriceTick; + apiProductID = _Instrument.ProductID; } } } From 4224bdfcba4947bd96bd96c8f8502617490a00e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Wed, 18 Dec 2019 19:45:14 +0800 Subject: [PATCH 33/41] =?UTF-8?q?=E5=A4=84=E7=90=86=E5=B9=B3=E4=BB=93?= =?UTF-8?q?=E6=88=900=E5=90=8E=EF=BC=8CAccount=E7=95=8C=E9=9D=A2=E6=8C=81?= =?UTF-8?q?=E4=BB=93=E4=B8=8D=E6=9B=B4=E6=96=B0=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Single/SingleProvider.API.Connection.cs | 9 + .../Single/SingleProvider.API.cs | 190 +++++++++++------- 2 files changed, 130 insertions(+), 69 deletions(-) diff --git a/QuantBox.APIProvider/Single/SingleProvider.API.Connection.cs b/QuantBox.APIProvider/Single/SingleProvider.API.Connection.cs index 579ffc8..fdcd7dd 100644 --- a/QuantBox.APIProvider/Single/SingleProvider.API.Connection.cs +++ b/QuantBox.APIProvider/Single/SingleProvider.API.Connection.cs @@ -545,14 +545,21 @@ private void QueryAccountPositionInstrument_Thread() Thread.Sleep(3000); // 查持仓,查资金 if (IsApiConnected(_QueryApi)) + { + _dictAccounts_current.Clear(); _QueryApi.ReqQuery(QueryType.ReqQryTradingAccount, query); + } + // 晚一点通知上层会不会更稳定一些? base.Status = ProviderStatus.Connected; Thread.Sleep(3000); if (IsApiConnected(_QueryApi)) + { + _dictPositions_current.Clear(); _QueryApi.ReqQuery(QueryType.ReqQryInvestorPosition, query); + } } @@ -571,6 +578,7 @@ private void QueryAccountPosition_OnTimer() _QueryAccountCount -= (int)_Timer.Interval / 1000; if (_QueryAccountCount <= 0) { + _dictAccounts_current.Clear(); _QueryApi.ReqQuery(QueryType.ReqQryTradingAccount, query); _QueryAccountCount = _QueryAccountInterval; } @@ -578,6 +586,7 @@ private void QueryAccountPosition_OnTimer() _QueryPositionCount -= (int)_Timer.Interval / 1000; if (_QueryPositionCount <= 0) { + _dictPositions_current.Clear(); _QueryApi.ReqQuery(QueryType.ReqQryInvestorPosition, query); _QueryPositionCount = _QueryPositionInterval; } diff --git a/QuantBox.APIProvider/Single/SingleProvider.API.cs b/QuantBox.APIProvider/Single/SingleProvider.API.cs index 621ea1c..016d39a 100644 --- a/QuantBox.APIProvider/Single/SingleProvider.API.cs +++ b/QuantBox.APIProvider/Single/SingleProvider.API.cs @@ -31,10 +31,17 @@ static SingleProvider() //记录合约列表,从实盘合约名到对象的映射 private readonly Dictionary _dictInstruments = new Dictionary(); + // 品种交易状态 private readonly Dictionary _dictInstrumentsStatus = new Dictionary(); + + // 账号信息 private SortedDictionary _dictAccounts_current = new SortedDictionary(); private SortedDictionary _dictAccounts_last = new SortedDictionary(); + // 持仓信息 + private SortedDictionary _dictPositions_current = new SortedDictionary(); + private SortedDictionary _dictPositions_last = new SortedDictionary(); + public static int GetDate(DateTime dt) { return dt.Year * 10000 + dt.Month * 100 + dt.Day; @@ -89,75 +96,79 @@ private void OnRspQryTradingAccount_callback(object sender, ref AccountField acc if (OnRspQryTradingAccount != null) OnRspQryTradingAccount(sender, ref account, size1, bIsLast); - if (size1 <= 0) - return; - - _dictAccounts_current[account.AccountID] = account; - if (bIsLast) + if (size1 > 0) { - if(_dictAccounts_last.Count == 0) - { - _dictAccounts_last = _dictAccounts_current; - } - - ProcessAccounts(_dictAccounts_current, _dictAccounts_last); - - _dictAccounts_last = _dictAccounts_current; - // 使用新容器 - _dictAccounts_current = new SortedDictionary(); + _dictAccounts_current[account.AccountID] = account; } - if (!IsConnected) + if (!bIsLast) return; - string currency = "CNY"; + var list = MergeAccounts(_dictAccounts_current, _dictAccounts_last); + alog.Info(string.Join("\n", list)); - AccountData ad = new AccountData(DateTime.Now, AccountDataType.AccountValue, - account.AccountID, this.id, this.id); + _dictAccounts_last = _dictAccounts_current; + _dictAccounts_current = new SortedDictionary(); + + if (!IsConnected) + return; - Type type = typeof(AccountField); - FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance); - foreach (FieldInfo field in fields) + foreach (var acc in _dictAccounts_last.Values) { - ad.Fields.Add(field.Name, currency, field.GetValue(account)); - } - // 将对像完全设置进去,等着取出 - ad.Fields.Add(AccountDataFieldEx.USER_DATA, currency, account); - ad.Fields.Add(AccountDataFieldEx.DATE, currency, GetDate(DateTime.Today)); + string currency = "CNY"; + AccountData ad = new AccountData(DateTime.Now, AccountDataType.AccountValue, + acc.AccountID, this.id, this.id); - try - { - EmitAccountData(ad); - } - catch (Exception ex) - { - (sender as XApi).GetLog().Error(ex); + Type type = typeof(AccountField); + FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance); + foreach (FieldInfo field in fields) + { + ad.Fields.Add(field.Name, currency, field.GetValue(acc)); + } + // 将对像完全设置进去,等着取出 + ad.Fields.Add(AccountDataFieldEx.USER_DATA, currency, acc); + ad.Fields.Add(AccountDataFieldEx.DATE, currency, GetDate(DateTime.Today)); + + try + { + EmitAccountData(ad); + } + catch (Exception ex) + { + (sender as XApi).GetLog().Error(ex); + } } } - private void ProcessAccounts(SortedDictionary dict_curr, SortedDictionary dict_last) + private List MergeAccounts(SortedDictionary dict_curr, SortedDictionary dict_last) { - // 开始比较 - var list_curr = _dictAccounts_current.Values.ToList(); - var list_last = _dictAccounts_last.Values.ToList(); - var len = Math.Min(list_curr.Count, list_last.Count); - string str = ""; - for (int i = 0; i < len; ++i) + var list = new List(); + // 交集 { - var curr = list_curr[i]; - var last = list_last[i]; - - if (true) + var keys = dict_curr.Keys.Intersect(dict_last.Keys); + foreach (var key in keys) { - str = AccountMsg_Long(curr, last); + var curr = dict_curr[key]; + var last = dict_last[key]; + + list.Add(AccountMsg_Long(curr, last)); } - else + } + + // 差集,表示新增 + { + var keys = dict_curr.Keys.Except(dict_last.Keys); + foreach (var key in keys) { - str = AccountMsg_Short(curr, last); + var curr = dict_curr[key]; + var last = new AccountField(); + + list.Add(AccountMsg_Long(curr, last)); } } - alog.Info(str); + return list; + } private void OnRspQryInvestor_callback(object sender, ref InvestorField investor, int size1, bool bIsLast) @@ -188,40 +199,81 @@ private void OnRspQryInvestorPosition_callback(object sender, ref PositionField if (OnRspQryInvestorPosition != null) OnRspQryInvestorPosition(sender, ref position, size1, bIsLast); - if (size1 <= 0) + // 需要保证从上一个查询到现在,列表中的数据是本次查询的所有数据 + if (size1 > 0) + { + _dictPositions_current[position.ID] = position; + } + + if (!bIsLast) return; + // 比较两次容器的区别 + var list = MergePositions(_dictPositions_current, _dictPositions_last); + _dictPositions_last = _dictPositions_current; + _dictPositions_current = new SortedDictionary(); + if (!IsConnected) return; - PositionFieldEx item; - if (!positions.TryGetValue(position.Symbol, out item)) + // 没有持仓通知的合约,也通知为0 + foreach (var pos in list) { - item = new PositionFieldEx(); - positions[position.Symbol] = item; - } - item.AddPosition(position); + PositionFieldEx item; + if (!positions.TryGetValue(pos.Symbol, out item)) + { + item = new PositionFieldEx(); + positions[pos.Symbol] = item; + } + item.AddPosition(pos); - AccountData ad = new AccountData(DateTime.Now, AccountDataType.Position, - position.AccountID, this.id, this.id); + AccountData ad = new AccountData(DateTime.Now, AccountDataType.Position, + pos.AccountID, this.id, this.id); - ad.Fields.Add(AccountDataField.SYMBOL, item.Symbol); - ad.Fields.Add(AccountDataField.EXCHANGE, item.Exchange); - ad.Fields.Add(AccountDataField.QTY, item.Qty); - ad.Fields.Add(AccountDataField.LONG_QTY, item.LongQty); - ad.Fields.Add(AccountDataField.SHORT_QTY, item.ShortQty); + ad.Fields.Add(AccountDataField.SYMBOL, item.Symbol); + ad.Fields.Add(AccountDataField.EXCHANGE, item.Exchange); + ad.Fields.Add(AccountDataField.QTY, item.Qty); + ad.Fields.Add(AccountDataField.LONG_QTY, item.LongQty); + ad.Fields.Add(AccountDataField.SHORT_QTY, item.ShortQty); - ad.Fields.Add(AccountDataFieldEx.USER_DATA, item); - ad.Fields.Add(AccountDataFieldEx.DATE, GetDate(DateTime.Today)); + ad.Fields.Add(AccountDataFieldEx.USER_DATA, item); + ad.Fields.Add(AccountDataFieldEx.DATE, GetDate(DateTime.Today)); - try + try + { + EmitAccountData(ad); + } + catch (Exception ex) + { + (sender as XApi).GetLog().Error(ex); + } + } + } + + private List MergePositions(SortedDictionary dict_curr, SortedDictionary dict_last) + { + // 由于可能收不到接口推送的持仓已经清空的消息,所以只能使用两次进行比较 + var list = new List(); + + // 新的全部添加 + foreach (var v in dict_curr.Values) { - EmitAccountData(ad); + list.Add(v); } - catch (Exception ex) + + // 老的需要更改数据为0 { - (sender as XApi).GetLog().Error(ex); + var keys = dict_last.Keys.Except(dict_curr.Keys); + foreach (var key in keys) + { + var last = dict_last[key]; + // 修改时间 + last.Position = 0; + list.Add(last); + } } + + return list; } private void OnRspQrySettlementInfo_callback(object sender, ref SettlementInfoClass settlementInfo, int size1, bool bIsLast) From c00cd8912f37ccd2c1935284c52feb0645b2a8e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Sun, 22 Dec 2019 22:44:11 +0800 Subject: [PATCH 34/41] =?UTF-8?q?=E9=87=8D=E8=BF=9E=E6=96=AD=E7=BA=BF?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E6=B7=BB=E5=8A=A0=E6=98=9F=E6=9C=9F=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=8C=E9=98=B2=E6=AD=A2=E5=91=A8=E6=9C=AB=E6=94=B6?= =?UTF-8?q?=E5=88=B0=E8=84=8F=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Single/SessionTimeItem.cs | 81 +++++++++++++++++-- .../Single/SingleProvider.API.Connection.cs | 19 +++-- .../Single/SingleProvider.Provider.cs | 4 +- 3 files changed, 86 insertions(+), 18 deletions(-) diff --git a/QuantBox.APIProvider/Single/SessionTimeItem.cs b/QuantBox.APIProvider/Single/SessionTimeItem.cs index 069f94c..ff5bbeb 100644 --- a/QuantBox.APIProvider/Single/SessionTimeItem.cs +++ b/QuantBox.APIProvider/Single/SessionTimeItem.cs @@ -14,25 +14,92 @@ namespace QuantBox.APIProvider.Single [JsonConverter(typeof(NoTypeConverterJsonConverter))] public class SessionTimeItem { + public const string CATEGORY_DAY_OF_WEEK = "DayOfWeek"; + + private static string[] DayOfWeekChinese = new string[] { "日", "一", "二", "三", "四", "五", "六" }; + + private List DayOfWeekList = null; + [PropertyOrder(1)] public TimeSpan SessionStart { get; set; } [PropertyOrder(2)] public TimeSpan SessionEnd { get; set; } + + [Category(CATEGORY_DAY_OF_WEEK)] + [PropertyOrder(1)] + public bool Sunday { get; set; } + [Category(CATEGORY_DAY_OF_WEEK)] + [PropertyOrder(2)] + public bool Monday { get; set; } + [Category(CATEGORY_DAY_OF_WEEK)] [PropertyOrder(3)] - public bool Enable { get; set; } + public bool Tuesday { get; set; } + [Category(CATEGORY_DAY_OF_WEEK)] + [PropertyOrder(4)] + public bool Wednesday { get; set; } + [Category(CATEGORY_DAY_OF_WEEK)] + [PropertyOrder(5)] + public bool Thursday { get; set; } + [Category(CATEGORY_DAY_OF_WEEK)] + [PropertyOrder(6)] + public bool Friday { get; set; } + [Category(CATEGORY_DAY_OF_WEEK)] + [PropertyOrder(7)] + public bool Saturday { get; set; } - public override string ToString() + public bool Contains(DayOfWeek dayOfWeek) + { + if (DayOfWeekList == null) + DayOfWeekList = GetDayOfWeekList(); + + return DayOfWeekList.Contains(dayOfWeek); + } + + public List GetDayOfWeekList() { - //return string.Format("Start={0};End={1}", this.SessionStart, this.SessionEnd); - if (Enable) + var list = new List(); + if (Sunday) list.Add(DayOfWeek.Sunday); + if (Monday) list.Add(DayOfWeek.Monday); + if (Tuesday) list.Add(DayOfWeek.Tuesday); + if (Wednesday) list.Add(DayOfWeek.Wednesday); + if (Thursday) list.Add(DayOfWeek.Thursday); + if (Friday) list.Add(DayOfWeek.Friday); + if (Saturday) list.Add(DayOfWeek.Saturday); + + DayOfWeekList = list; + + return list; + } + + public string GetDayOfWeekString() + { + var strs = new List(); + var list = GetDayOfWeekList(); + foreach (var l in list) { - return string.Format("+|Start={0};End={1}", this.SessionStart, this.SessionEnd); + strs.Add(DayOfWeekChinese[Convert.ToInt16(l)]); } - else + return string.Join("", strs); + } + + + public override string ToString() + { + var list = new List() { SessionStart, SessionEnd }; + var strs = new List(); + foreach (var ts in list) { + if (ts.TotalDays >= 1.0) + { + strs.Add(ts.ToString(@"d\:mm")); + } + else + { + strs.Add(ts.ToString(@"hh\:mm")); + } - return string.Format("-|Start={0};End={1}", this.SessionStart, this.SessionEnd); } + return $"[{string.Join(",", strs)}] {{{GetDayOfWeekString()}}}"; } } } diff --git a/QuantBox.APIProvider/Single/SingleProvider.API.Connection.cs b/QuantBox.APIProvider/Single/SingleProvider.API.Connection.cs index fdcd7dd..958ebb6 100644 --- a/QuantBox.APIProvider/Single/SingleProvider.API.Connection.cs +++ b/QuantBox.APIProvider/Single/SingleProvider.API.Connection.cs @@ -138,21 +138,20 @@ private void CheckConnection(System.Timers.ElapsedEventArgs e) if (SessionTimeList == null || SessionTimeList.Count == 0) break; - var stl = SessionTimeList.Where(x => x.Enable).ToList(); + var stl = SessionTimeList.Where(x => x.Contains(e.SignalTime.DayOfWeek)).ToList(); if (stl.Count == 0) + { break; + } bool bTryConnect = true; - + TimeSpan ts = e.SignalTime.TimeOfDay; SessionTimeItem st_current = null; SessionTimeItem st_next = null; foreach (var st in stl) { // 如果当前时间在交易范围内,要开启重连 // 如果当前时间不在交易范围内,要主动断开 - TimeSpan ts = e.SignalTime.TimeOfDay; - if (!st.Enable) - continue; if (ts < st.SessionStart) { @@ -181,7 +180,7 @@ private void CheckConnection(System.Timers.ElapsedEventArgs e) // 没有连接要连上,有连接要设置时间 if (!IsConnected) { - xlog.Info("当前[{0}]在交易时段[{1}],主动连接", e.SignalTime.TimeOfDay, st_current); + xlog.Info($"当前[{e.SignalTime.TimeOfDay}]在交易时段[{st_current}],主动连接"); _Connect(false); } @@ -197,7 +196,7 @@ private void CheckConnection(System.Timers.ElapsedEventArgs e) // 由于定时器设置的是20秒,所以这里正好是5分钟显示一次 if (nDisconnectCount % (3 * 5) == 0) { - xlog.Info("当前[{0}]在非交易时段,主动断开连接,下次要连接的时段为[{1}]", e.SignalTime.TimeOfDay, st_next); + xlog.Info($"当前[{e.SignalTime.TimeOfDay}]在非交易时段,主动断开连接,下次要连接的时段为[{st_next}](仅限当日)"); // 要断开连接 _Disconnect(false); @@ -536,12 +535,12 @@ private void QueryAccountPositionInstrument_Thread() query.PortfolioID3 = DefaultPortfolioID3; query.Business = DefaultBusiness; - + Thread.Sleep(3000); // 查合约 if (IsApiConnected(_ItApi)) _ItApi.ReqQuery(QueryType.ReqQryInstrument, query); - + Thread.Sleep(3000); // 查持仓,查资金 if (IsApiConnected(_QueryApi)) @@ -549,7 +548,7 @@ private void QueryAccountPositionInstrument_Thread() _dictAccounts_current.Clear(); _QueryApi.ReqQuery(QueryType.ReqQryTradingAccount, query); } - + // 晚一点通知上层会不会更稳定一些? base.Status = ProviderStatus.Connected; diff --git a/QuantBox.APIProvider/Single/SingleProvider.Provider.cs b/QuantBox.APIProvider/Single/SingleProvider.Provider.cs index c7e68c0..9ef770a 100644 --- a/QuantBox.APIProvider/Single/SingleProvider.Provider.cs +++ b/QuantBox.APIProvider/Single/SingleProvider.Provider.cs @@ -17,6 +17,7 @@ public partial class SingleProvider:Provider { private Logger xlog; private Logger alog; + private Logger plog; private Logger barLog; private Logger tickLog; @@ -58,6 +59,7 @@ public void Init(byte id, string name) // 只是简单设置,等登录时将把账号设置上,X日志由于一些信息没法 xlog = LogManager.GetLogger(Name + ".X"); alog = LogManager.GetLogger(Name + ".A"); + plog = LogManager.GetLogger(Name + ".P"); barLog = LogManager.GetLogger("Bar"); tickLog = LogManager.GetLogger("Tick"); @@ -89,7 +91,7 @@ public void Init(byte id, string name) historicalDataIds = new Dictionary(); // ConfigPath在做Setting时已经做了 - //Load(); + Load(); } void SessionTimeList_ListChanged(object sender, ListChangedEventArgs e) From 2dda4ddc59fbce8cf24743fc0a47c39cf75784f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Tue, 24 Dec 2019 16:20:05 +0800 Subject: [PATCH 35/41] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=8C=81=E4=BB=93?= =?UTF-8?q?=E9=80=9A=E7=9F=A5=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Single/SingleProvider.API.cs | 3 +++ README.md | 20 ++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/QuantBox.APIProvider/Single/SingleProvider.API.cs b/QuantBox.APIProvider/Single/SingleProvider.API.cs index 016d39a..a6b09c9 100644 --- a/QuantBox.APIProvider/Single/SingleProvider.API.cs +++ b/QuantBox.APIProvider/Single/SingleProvider.API.cs @@ -193,6 +193,9 @@ private void OnRspQryInvestorPosition_callback(object sender, ref PositionField // UFX中已经过期的持仓也会推送,所以这里过滤一下不显示 if (IsLogOnRspQryInvestorPosition) (sender as XApi).GetLog().Info("OnRspQryInvestorPosition:" + position.ToFormattedString()); + + if (position.Position > 0) + plog.Info($"{position.Symbol},{position.Side},今+昨=总:{position.TodayPosition}+{position.HistoryPosition}={position.Position}"); } // 由策略来收回报 diff --git a/README.md b/README.md index 1711038..0291a5a 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # QuantBox.APIProvider + OpenQuant2014的行情交易插件,使用XAPI统一接口 -## 特殊功能 -命令启停OQ功能 +## 命令启停OQ功能 1. 启动OQ,并打开指定策略,并运行 通过**命令行**传入参数 @@ -24,4 +24,18 @@ start OpenQuant.exe --file="D:\Users\Kan\Documents\OpenQuant 2014\Solutions\SMAC ``` echo --id=100 --stop --exit | clip ``` -只要向剪贴板复制`--id=100 --stop --exit`即可,这个复制可以手工实现,也可以灵活使用管道符|将echo的回显重定向到剪贴板clip \ No newline at end of file +只要向剪贴板复制`--id=100 --stop --exit`即可,这个复制可以手工实现,也可以灵活使用管道符|将echo的回显重定向到剪贴板clip + +## 开盘前自动连接并通知 + +此插件在登录成功时会自动查询资金,可以将其转发到钉钉,这样用户就可以知道连接已经成功。 +1. 设置SessionTimeList,需要每个星期都有,包括周日。 +2. 设置NLog.config,如当前插件名为A99CTP,那么NLog中资金的logger是A99CTP.A +3. 将A99CTP.A转发到WebService,如钉钉 + + +## 定时通知资金与持仓功能 + +通过设置参数QueryAccountInterval(资金查询间隔,秒)和QueryPositionInterval(持仓查询间隔,秒),可以自动查询,并输出日志。 +1. 资金logger:A99CTP.A +2. 持仓logger:A99CTP.P \ No newline at end of file From fe2e2c10ba667553ab8599f083365c7ef083c2d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Wed, 25 Dec 2019 09:56:44 +0800 Subject: [PATCH 36/41] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=8C=81=E4=BB=93?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Single/SingleProvider.API.Connection.cs | 31 +++++----- .../Single/SingleProvider.API.cs | 57 ++++++++++++------- 2 files changed, 51 insertions(+), 37 deletions(-) diff --git a/QuantBox.APIProvider/Single/SingleProvider.API.Connection.cs b/QuantBox.APIProvider/Single/SingleProvider.API.Connection.cs index 958ebb6..596ae6f 100644 --- a/QuantBox.APIProvider/Single/SingleProvider.API.Connection.cs +++ b/QuantBox.APIProvider/Single/SingleProvider.API.Connection.cs @@ -539,30 +539,29 @@ private void QueryAccountPositionInstrument_Thread() Thread.Sleep(3000); // 查合约 if (IsApiConnected(_ItApi)) + { _ItApi.ReqQuery(QueryType.ReqQryInstrument, query); + } - Thread.Sleep(3000); // 查持仓,查资金 + Thread.Sleep(3000); if (IsApiConnected(_QueryApi)) { - _dictAccounts_current.Clear(); - _QueryApi.ReqQuery(QueryType.ReqQryTradingAccount, query); + _dictPositions_current.Clear(); + _QueryApi.ReqQuery(QueryType.ReqQryInvestorPosition, query); } - // 晚一点通知上层会不会更稳定一些? base.Status = ProviderStatus.Connected; Thread.Sleep(3000); if (IsApiConnected(_QueryApi)) { - _dictPositions_current.Clear(); - _QueryApi.ReqQuery(QueryType.ReqQryInvestorPosition, query); + _dictAccounts_current.Clear(); + _QueryApi.ReqQuery(QueryType.ReqQryTradingAccount, query); } } - - private void QueryAccountPosition_OnTimer() { if (!IsApiConnected(_QueryApi)) @@ -574,14 +573,6 @@ private void QueryAccountPosition_OnTimer() query.PortfolioID3 = DefaultPortfolioID3; query.Business = DefaultBusiness; - _QueryAccountCount -= (int)_Timer.Interval / 1000; - if (_QueryAccountCount <= 0) - { - _dictAccounts_current.Clear(); - _QueryApi.ReqQuery(QueryType.ReqQryTradingAccount, query); - _QueryAccountCount = _QueryAccountInterval; - } - _QueryPositionCount -= (int)_Timer.Interval / 1000; if (_QueryPositionCount <= 0) { @@ -589,6 +580,14 @@ private void QueryAccountPosition_OnTimer() _QueryApi.ReqQuery(QueryType.ReqQryInvestorPosition, query); _QueryPositionCount = _QueryPositionInterval; } + + _QueryAccountCount -= (int)_Timer.Interval / 1000; + if (_QueryAccountCount <= 0) + { + _dictAccounts_current.Clear(); + _QueryApi.ReqQuery(QueryType.ReqQryTradingAccount, query); + _QueryAccountCount = _QueryAccountInterval; + } } #endregion diff --git a/QuantBox.APIProvider/Single/SingleProvider.API.cs b/QuantBox.APIProvider/Single/SingleProvider.API.cs index a6b09c9..995029b 100644 --- a/QuantBox.APIProvider/Single/SingleProvider.API.cs +++ b/QuantBox.APIProvider/Single/SingleProvider.API.cs @@ -193,9 +193,6 @@ private void OnRspQryInvestorPosition_callback(object sender, ref PositionField // UFX中已经过期的持仓也会推送,所以这里过滤一下不显示 if (IsLogOnRspQryInvestorPosition) (sender as XApi).GetLog().Info("OnRspQryInvestorPosition:" + position.ToFormattedString()); - - if (position.Position > 0) - plog.Info($"{position.Symbol},{position.Side},今+昨=总:{position.TodayPosition}+{position.HistoryPosition}={position.Position}"); } // 由策略来收回报 @@ -211,6 +208,8 @@ private void OnRspQryInvestorPosition_callback(object sender, ref PositionField if (!bIsLast) return; + PositionsMsg_Long(_dictPositions_current); + // 比较两次容器的区别 var list = MergePositions(_dictPositions_current, _dictPositions_last); _dictPositions_last = _dictPositions_current; @@ -366,24 +365,22 @@ private string AccountMsg_Long(AccountField current, AccountField last) double balance_1 = (current.Balance - current.Deposit + current.Withdraw) - current.PreBalance; double balance_2 = current.Balance - last.Balance; - string str = ""; - - str += string.Format("{0:F2}%/{1:F0}/{2:F0}/{3:F0}", risk, current.PositionProfit, balance_1, balance_2); - str += string.Format("\n{0:F0}/{1:F0}/{2:F0}", current.CloseProfit, current.Commission, current.Available); - str += string.Format("\n风险度/持仓盈亏/日间权益差/区间权益差"); - str += string.Format("\n平仓盈亏/手续费/可用资金\n"); - - str += string.Format("\n{0:F0}/{1:F0}", current.Withdraw, current.Deposit); - str += string.Format("\n出/入金\n"); - - str += string.Format("\n{0:F0}-*+*-{1:F0}=*", current.Balance, current.PreBalance); - str += string.Format("\n(动态权益-入金+出金)-昨结权益=日间权益差"); - str += string.Format("\n动态权益-上期动态权益=区间权益差\n"); - - str += string.Format("\n{0:F0}/*=*", current.CurrMargin); - str += string.Format("\n占用保证金/动态权益=风险度\n"); - - str += string.Format("\n>>AccountID:{0}<<", current.AccountID); + string str = $"{risk:F2}%/{current.PositionProfit:F0}/{balance_1:F0}/{balance_2:F0}" + + $"\n{current.CloseProfit:F0}/{current.Commission:F0}/{current.Available:F0}" + + $"\n风险度/持仓盈亏/日间权益差/区间权益差" + + $"\n平仓盈亏/手续费/可用资金\n" + + $"\n{current.Withdraw:F0}/{current.Deposit:F0}" + + $"\n出/入金" + + $"\n" + + $"\n{current.Balance:F0}-*+*-{current.PreBalance:F0}=*" + + $"\n(动态权益-入金+出金)-昨结权益=日间权益差" + + $"\n动态权益-上期动态权益=区间权益差" + + $"\n" + + $"\n{current.CurrMargin:F0}/*=*" + + $"\n占用保证金/动态权益=风险度" + + $"\n" + + $"\n>>AccountID:{current.AccountID}<<" + + $"\n>>{DateTime.Now.ToLongTimeString()}<<"; return str; } @@ -406,5 +403,23 @@ private string AccountMsg_Short(AccountField current, AccountField last) return str; } + + private string PositionsMsg_Long(SortedDictionary positions) + { + if (positions.Count == 0) + return null; + + string str = ""; + foreach (var p in positions.Values) + { + str += $"{p.Symbol},{p.Side.ToString()},{p.HistoryPosition}+{p.TodayPosition}={p.Position}\n"; + + } + str += $"\n合约,多空,昨+今=总"; + str += $"\n>>{DateTime.Now.ToLongTimeString()}<<"; + plog.Info(str); + + return str; + } } } From ee713824f3628521dd429f7f351a3a56520be9a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Tue, 2 Mar 2021 00:14:46 +0800 Subject: [PATCH 37/41] =?UTF-8?q?=E5=B0=86=E6=9C=8D=E5=8A=A1=E5=99=A8?= =?UTF-8?q?=E4=B8=8E=E8=B4=A6=E5=8F=B7=E7=9A=84=E9=85=8D=E7=BD=AE=E6=94=BE?= =?UTF-8?q?=E5=88=B0json?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../QuantBox.APIProvider.csproj | 6 +- .../QuantBox.APIProvider.csproj.user | 8 ++ QuantBox.APIProvider/Single/ApiItem.cs | 7 +- QuantBox.APIProvider/Single/ServerItem.cs | 111 ++---------------- .../Single/SingleProvider.API.Connection.cs | 10 +- QuantBox.APIProvider/Single/UserItem.cs | 39 ++---- 6 files changed, 40 insertions(+), 141 deletions(-) diff --git a/QuantBox.APIProvider/QuantBox.APIProvider.csproj b/QuantBox.APIProvider/QuantBox.APIProvider.csproj index dadef3a..bfa0720 100644 --- a/QuantBox.APIProvider/QuantBox.APIProvider.csproj +++ b/QuantBox.APIProvider/QuantBox.APIProvider.csproj @@ -1,7 +1,7 @@  - net48;netstandard2.0 + netstandard2.0;net48 false QuantBox.APIProvider QuantBox.APIProvider @@ -9,9 +9,9 @@ - + - + diff --git a/QuantBox.APIProvider/QuantBox.APIProvider.csproj.user b/QuantBox.APIProvider/QuantBox.APIProvider.csproj.user index 88a5509..34a18ad 100644 --- a/QuantBox.APIProvider/QuantBox.APIProvider.csproj.user +++ b/QuantBox.APIProvider/QuantBox.APIProvider.csproj.user @@ -1,4 +1,12 @@  + + + Form + + + Form + + \ No newline at end of file diff --git a/QuantBox.APIProvider/Single/ApiItem.cs b/QuantBox.APIProvider/Single/ApiItem.cs index 043f509..10c5cca 100644 --- a/QuantBox.APIProvider/Single/ApiItem.cs +++ b/QuantBox.APIProvider/Single/ApiItem.cs @@ -97,12 +97,13 @@ public string TypeName public string LogPrefix { get; set; } -#if NET48 - [Editor(typeof(ApiTypeSelectorEditor), typeof(UITypeEditor))] -#endif + [Category(CATEGORY_TYPE)] [ReadOnly(true)] public ApiType Type { get; set; } +#if NET48 + [Editor(typeof(ApiTypeSelectorEditor), typeof(UITypeEditor))] +#endif [Category(CATEGORY_TYPE)] public ApiType UseType { get; set; } diff --git a/QuantBox.APIProvider/Single/ServerItem.cs b/QuantBox.APIProvider/Single/ServerItem.cs index 34d4f8e..c14abbc 100644 --- a/QuantBox.APIProvider/Single/ServerItem.cs +++ b/QuantBox.APIProvider/Single/ServerItem.cs @@ -5,6 +5,9 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +#if NET48 +using System.Drawing.Design; +#endif namespace QuantBox.APIProvider.Single @@ -12,111 +15,17 @@ namespace QuantBox.APIProvider.Single [DefaultProperty("Label")] public class ServerItem : ICloneable { - private const string OPEN_QUANT = "OpenQuant"; [Category("标签")] - public string Label - { - get; - set; - } - /// - /// 订阅主题 - /// - [Category("行情 - Femas")] - [Description("Femas")] - public int TopicId { get; set; } - - /// - /// 流恢复 - /// - [Category("流重传方式")] - public ResumeType MarketDataTopicResumeType { get; set; } - [Category("流重传方式")] - public ResumeType PrivateTopicResumeType { get; set; } - [Category("流重传方式")] - public ResumeType PublicTopicResumeType { get; set; } - [Category("流重传方式")] - public ResumeType UserTopicResumeType { get; set; } - /// - /// 经纪公司代码 - /// - [Category("服务端信息")] - public string BrokerID { get; set; } - /// - /// 用户端产品信息 - /// - [Category("客户端认证")] - public string UserProductInfo { get; set; } - /// - /// 认证码 - /// - [Category("客户端认证")] - public string AuthCode { get; set; } - /// - /// App认证码 - /// - [Category("客户端认证")] - public string AppID { get; set; } - /// - /// 地址 - /// - [Category("服务端信息")] - public string Address { get; set; } - /// - /// 地址 - /// - [Category("扩展信息")] - public string ExtInfoChar128 { get; set; } - [Category("扩展信息")] - public string ConfigPath { get; set; } - /// - /// 端口号 - /// - [Category("服务端信息")] - public int Port { get; set; } - /// - /// UDP行情 - /// - [Category("行情")] - [Description("CTP/DFITC_Level2")] - public bool IsUsingUdp { get; set; } - /// - /// 多播行情 - /// - [Category("行情")] - [Description("CTP")] - public bool IsMulticast { get; set; } - - public ServerItem() - { - UserProductInfo = OPEN_QUANT; - } - - public ServerInfoField ToStruct() - { - ServerInfoField field = new ServerInfoField(); - field.IsUsingUdp = this.IsUsingUdp; - field.IsMulticast = this.IsMulticast; - field.TopicId = this.TopicId; - field.Port = this.Port; - field.MarketDataTopicResumeType = this.MarketDataTopicResumeType; - field.PrivateTopicResumeType = this.PrivateTopicResumeType; - field.PublicTopicResumeType = this.PublicTopicResumeType; - field.UserTopicResumeType = this.UserTopicResumeType; - field.BrokerID = this.BrokerID; - field.UserProductInfo = this.UserProductInfo; - field.AuthCode = this.AuthCode; - field.AppID = this.AppID; - field.Address = this.Address; - field.ConfigPath = this.ConfigPath; - field.ExtInfoChar128 = this.ExtInfoChar128; - - return field; - } + public string Label { get; set; } +#if NET48 + [Editor(typeof(System.Windows.Forms.Design.FolderNameEditor), typeof(UITypeEditor))] +#endif + public string Path { get; set; } + public override string ToString() { - return string.Format("Label={0};BrokerID={1};Address={2}", this.Label, this.BrokerID, this.Address); + return string.Format("Label={0}", this.Label); } public object Clone() diff --git a/QuantBox.APIProvider/Single/SingleProvider.API.Connection.cs b/QuantBox.APIProvider/Single/SingleProvider.API.Connection.cs index 596ae6f..11dbf5d 100644 --- a/QuantBox.APIProvider/Single/SingleProvider.API.Connection.cs +++ b/QuantBox.APIProvider/Single/SingleProvider.API.Connection.cs @@ -6,6 +6,7 @@ using NLog; using QuantBox.Extensions; using System.Threading; +using System.IO; namespace QuantBox.APIProvider.Single { @@ -380,11 +381,12 @@ private IXApi ConnectToApi(ApiItem item) item.Api = api; } - api.Server = ServerList[item.Server].ToStruct(); - api.User = UserList[item.User].ToStruct(); + string szServerPath = ServerList[item.Server].Path; + string szUserPath = UserList[item.User].Path; + string szUserLabel = UserList[item.User].Label; // 更新Log名字,这样在日志中可以进行识别 - api.Log = LogManager.GetLogger(string.Format("{0}.{1}.{2}", Name, item.LogPrefix, api.User.UserID)); + api.Log = LogManager.GetLogger(string.Format("{0}.{1}.{2}", Name, item.LogPrefix, szUserLabel)); if (api.IsConnected) return api; @@ -416,7 +418,7 @@ private IXApi ConnectToApi(ApiItem item) api.OnRspQrySettlementInfo = OnRspQrySettlementInfo_callback; api.OnRtnInstrumentStatus = OnRtnInstrumentStatus_callback; - api.Connect(); + api.Connect(szServerPath, szUserPath, Path.GetTempPath()); return api; } diff --git a/QuantBox.APIProvider/Single/UserItem.cs b/QuantBox.APIProvider/Single/UserItem.cs index 5a40954..e08085c 100644 --- a/QuantBox.APIProvider/Single/UserItem.cs +++ b/QuantBox.APIProvider/Single/UserItem.cs @@ -6,6 +6,10 @@ using System.Threading.Tasks; using XAPI; +#if NET48 +using System.Drawing.Design; +#endif + namespace QuantBox.APIProvider.Single { [DefaultProperty("Label")] @@ -17,39 +21,14 @@ public string Label get; set; } - /// - /// 用户代码 - /// - [Category("账号")] - public string UserID { get; set; } - /// - /// 密码 - /// - [Category("账号")] - public string Password { get; set; } - /// - /// 扩展信息 - /// - [Category("账号")] - public string ExtInfoChar64 { get; set; } - [Category("账号")] - public int ExtInfoInt32 { get; set; } - - public UserInfoField ToStruct() - { - UserInfoField field = new UserInfoField(); - - field.UserID = this.UserID; - field.Password = this.Password; - field.ExtInfoChar64 = this.ExtInfoChar64; - field.ExtInfoInt32 = this.ExtInfoInt32; - - return field; - } +#if NET48 + [Editor(typeof(System.Windows.Forms.Design.FolderNameEditor), typeof(UITypeEditor))] +#endif + public string Path { get; set; } public override string ToString() { - return string.Format("Label={0};UserID={1}", this.Label,this.UserID); + return string.Format("Label={0}", this.Label); } public object Clone() From de393ac719a3de4d0b2d036083bd42318314283c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Tue, 2 Mar 2021 16:43:48 +0800 Subject: [PATCH 38/41] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=92=89=E9=92=89?= =?UTF-8?q?=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- autorun_oq.bat | 3 - config/NLog.config | 29 ++++++++ config/backup_proj.bat | 6 ++ config/run_proj.bat | 9 +++ config/stop_proj.bat | 6 ++ exit_oq.bat | 1 - python/BatchDelayQueue.py | 57 +++++++++++++++ python/DtalkRobot.py | 146 ++++++++++++++++++++++++++++++++++++++ python/dtlogger.py | 112 +++++++++++++++++++++++++++++ python/run_dt.bat | 2 + 10 files changed, 367 insertions(+), 4 deletions(-) delete mode 100644 autorun_oq.bat create mode 100644 config/NLog.config create mode 100644 config/backup_proj.bat create mode 100644 config/run_proj.bat create mode 100644 config/stop_proj.bat delete mode 100644 exit_oq.bat create mode 100644 python/BatchDelayQueue.py create mode 100644 python/DtalkRobot.py create mode 100644 python/dtlogger.py create mode 100644 python/run_dt.bat diff --git a/autorun_oq.bat b/autorun_oq.bat deleted file mode 100644 index 9ffa4d2..0000000 --- a/autorun_oq.bat +++ /dev/null @@ -1,3 +0,0 @@ -cd "C:\Program Files\SmartQuant Ltd\OpenQuant 2014" -C: -start OpenQuant.exe --file="D:\Users\Kan\Documents\OpenQuant 2014\Solutions\SMACrossover\SMACrossover.sln" --id=100 --run \ No newline at end of file diff --git a/config/NLog.config b/config/NLog.config new file mode 100644 index 0000000..4fb04bd --- /dev/null +++ b/config/NLog.config @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/backup_proj.bat b/config/backup_proj.bat new file mode 100644 index 0000000..fd652b4 --- /dev/null +++ b/config/backup_proj.bat @@ -0,0 +1,6 @@ +cd D:\ +D: +set DATA_YMD=%date:~0,4%%date:~5,2%%date:~8,2% +xcopy S1 S1_ά\%DATA_YMD%\ +xcopy S2 S2_ά\%DATA_YMD%\ +pause \ No newline at end of file diff --git a/config/run_proj.bat b/config/run_proj.bat new file mode 100644 index 0000000..fdc7374 --- /dev/null +++ b/config/run_proj.bat @@ -0,0 +1,9 @@ +cd "C:\Program Files\SmartQuant Ltd\OpenQuant 2014" +C: + +start OpenQuant.exe --file="D:\GitHub\S1\S1.sln" --id=100 --run +ping 127.0.0.1 -n 20 +start OpenQuant.exe --file="D:\GitHub\S2\S2.sln" --id=200 --run +ping 127.0.0.1 -n 20 + +pause diff --git a/config/stop_proj.bat b/config/stop_proj.bat new file mode 100644 index 0000000..a952368 --- /dev/null +++ b/config/stop_proj.bat @@ -0,0 +1,6 @@ +echo --id=100 --stop --exit | clip +ping 127.0.0.1 -n 10 +echo --id=200 --stop --exit | clip +ping 127.0.0.1 -n 10 + +pause \ No newline at end of file diff --git a/exit_oq.bat b/exit_oq.bat deleted file mode 100644 index 4ea8643..0000000 --- a/exit_oq.bat +++ /dev/null @@ -1 +0,0 @@ -echo --id=100 --stop --exit | clip \ No newline at end of file diff --git a/python/BatchDelayQueue.py b/python/BatchDelayQueue.py new file mode 100644 index 0000000..4244561 --- /dev/null +++ b/python/BatchDelayQueue.py @@ -0,0 +1,57 @@ +""" +延迟队列 +""" +import threading +import time + + +class BatchQueue: + def __init__(self): + self.buf = [] + + def add_one(self, obj): + self.buf.append(obj) + + def get_all(self): + _buf = self.buf.copy() + self.buf = [] + return _buf + + +class DelayQueue: + + def __init__(self, interval, process_func): + self.queue = BatchQueue() + self.interval = interval + self.process_func = process_func + # 启动定时器 + threading.Timer(self.interval, self.process).start() + + def add(self, obj): + self.queue.add_one(obj) + + def process(self): + buf = self.queue.get_all() + if len(buf) > 0: + self.process_func(buf) + # 定时器需要再激活才可使用 + threading.Timer(self.interval, self.process).start() + + +if __name__ == '__main__': + + def process(buf): + print(buf) + + + def thread_fun(dq): + for i in range(1000): + dq.add(i) + time.sleep(0.01) + + + dq = DelayQueue(5, process) + threading.Thread(target=thread_fun, args=(dq,)).start() + threading.Thread(target=thread_fun, args=(dq,)).start() + threading.Thread(target=thread_fun, args=(dq,)).start() + input() diff --git a/python/DtalkRobot.py b/python/DtalkRobot.py new file mode 100644 index 0000000..e4f8c69 --- /dev/null +++ b/python/DtalkRobot.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +钉钉群自定义机器人 +author:疯狂的技术宅 +github:https://github.com/magician000 + +学习python时做的练习,纯粹为了娱乐 +如果存在bug请自行修改,不提供任何支持 + +官方文档 +https://open-doc.dingtalk.com/docs/doc.htm?spm=a219a.7629140.0.0.z5MWoh&treeId=257&articleId=105735&docType=1 + +这个接口的消息格式命名风格不统一,坑爹呢? +所以不要迷信大公司就怎样规范。 +""" + +import urllib.parse +import urllib.request +import json +import time + +# 代理,一般不使用 +if False: + proxy_support = urllib.request.ProxyHandler({'http': '192.168.1.60:808', 'https': '192.168.1.60:808'}) + # proxy_support = urllib.request.ProxyHandler({'sock5': '192.168.1.60:1080'}) + opener = urllib.request.build_opener(proxy_support) + urllib.request.install_opener(opener) + + +# 自定义机器人的封装类 +class DtalkRobot(object): + def __init__(self, webhook): + super(DtalkRobot, self).__init__() + self.webhook = webhook + + # text类型 + def sendText_webhook(self, webhook, msg, isAtAll=False, atMobiles=[]): + data = {"msgtype": "text", "text": {"content": msg}, "at": {"atMobiles": atMobiles, "isAtAll": isAtAll}} + return self.post_webhook(webhook, data) + + # markdown类型 + def sendMarkdown_webhook(self, webhook, title, text): + data = {"msgtype": "markdown", "markdown": {"title": title, "text": text}} + return self.post_webhook(webhook, data) + + # link类型 + def sendLink(self, title, text, messageUrl, picUrl=""): + data = {"msgtype": "link", + "link": {"text": text, "title": title, "picUrl": picUrl, "messageUrl": messageUrl}} + return self.post(data) + + # ActionCard类型 + def sendActionCard(self, actionCard): + data = actionCard.getData() + return self.post(data) + + # FeedCard类型 + def sendFeedCard(self, links): + data = {"feedCard": {"links": links}, "msgtype": "feedCard"} + return self.post(data) + + def post(self, data): + post_data = json.JSONEncoder().encode(data).encode(encoding='UTF8') + + req = urllib.request.Request(self.webhook, post_data) + req.add_header('Content-Type', 'application/json') + content = urllib.request.urlopen(req).read().decode('UTF-8') + return content + + def post_webhook(self, webhook, data): + post_data = json.JSONEncoder().encode(data).encode(encoding='UTF8') + + req = urllib.request.Request(webhook, post_data) + req.add_header('Content-Type', 'application/json') + content = urllib.request.urlopen(req).read().decode('UTF-8') + # print(content) + return content + + +# ActionCard类型消息结构 +class ActionCard(object): + """docstring for ActionCard""" + title = "" + text = "" + singleTitle = "" + singleURL = "" + btnOrientation = 0 + hideAvatar = 0 + btns = [] + + def __init__(self, arg=""): + super(ActionCard, self).__init__() + self.arg = arg + + def putBtn(self, title, actionURL): + self.btns.append({"title": title, "actionURL": actionURL}) + + def getData(self): + data = {"actionCard": {"title": self.title, "text": self.text, "hideAvatar": self.hideAvatar, + "btnOrientation": self.btnOrientation, "singleTitle": self.singleTitle, + "singleURL": self.singleURL, "btns": self.btns}, "msgtype": "actionCard"} + return data + + +# FeedCard类型消息格式 +class FeedLink(object): + """docstring for FeedLink""" + title = "" + picUrl = "" + messageUrl = "" + + def __init__(self, arg=""): + super(FeedLink, self).__init__() + self.arg = arg + + def getData(self): + data = {"title": self.title, "picURL": self.picUrl, "messageURL": self.messageUrl} + return data + + +if __name__ == "__main__": + webhook = "https://oapi.dingtalk.com/robot/send?access_token=72f6252257f43f402f743b7d698fc21d21939717783a20689e1c1292c20d1903" + robot = DtalkRobot(webhook) + + # print(robot.sendText("xxxx:[" + time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) + "]", False, + # ["13912345678 "])) + + print(robot.sendMarkdown('报单回报', """# LAST_HEDGE (OI805) +1. 21:00:00.224/6298/0|-2/ +1. 21:00:01.412/6296/0 +## LAST_HEDGE (TA805) +1. 21:00:00.224/5692/0|-6/ +1. 21:00:01.427/5690/0 +### LAST_HEDGE (TA805) +- 21:00:00.224/5692/0|-6/ +- 21:00:01.427/5690/0 +#### LAST_HEDGE (TA805) +- 21:00:00.224/5692/0|-6/ +- 21:00:01.427/5690/0 +##### LAST_HEDGE (TA805) +- 21:00:00.224/5692/0|-6/ +- 21:00:01.427/5690/0 +###### LAST_HEDGE (i1805) +- 21:00:00.427/514.5/0|1/ +- 21:00:01.412/514/0""")) diff --git a/python/dtlogger.py b/python/dtlogger.py new file mode 100644 index 0000000..136b0ee --- /dev/null +++ b/python/dtlogger.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +pip install spyne + + + + + + + + + + + + + + +protected NLog.Logger log_wx = NLog.LogManager.GetLogger("wx"); + +log_wx.Warn("策略启动。"); + +""" +from spyne import Application, rpc, ServiceBase, String +from spyne.protocol.http import HttpRpc +from spyne.protocol.json import JsonDocument +from spyne.server.wsgi import WsgiApplication + +from DtalkRobot import * +from BatchDelayQueue import DelayQueue + +# 99simnow +webhook_a99ctp = "https://oapi.dingtalk.com/robot/send?access_token=11111" +# 98实 +webhook_a98ctp = "https://oapi.dingtalk.com/robot/send?access_token=11111" +# S01策略 +webhook_s01 = "https://oapi.dingtalk.com/robot/send?access_token=11111" + +# 不明的消息都发到模拟平台上 +webhook = webhook_a99ctp + +ip = '0.0.0.0' +port = 8000 + + +def send_msgs(logger, level, title, message): + # 利用logger,可以将消息发向不同的机器人 + if logger == 'ALL': + _webhook = webhook + elif logger == 'A98CTP.A': + _webhook = webhook_a98ctp + elif logger == 'A98CTP.P': + _webhook = webhook_a98ctp + elif logger == 'S01': + _webhook = webhook_s01 + else: + _webhook = webhook + + if title is None or len(title) == 0: + robot.sendText_webhook(_webhook, message) + else: + msg = f"##### {title}\n{message}" + robot.sendMarkdown_webhook(_webhook, title, msg) + + +def process_log_msg(tuples): + msgs = {} + for tp in tuples: + logger, level, title, message = tp + key = (logger, level, title) + lst = msgs.get(key, []) + lst.append(message) + msgs[key] = lst + print("定时处理", len(msgs)) + for k, v in msgs.items(): + # 这里不能太长,否则会被截断 + send_msgs(k[0], k[1], k[2], '\n'.join(v)) + + +class LogService(ServiceBase): + @rpc(String, String, String, String, _returns=String) + def logme(ctx, logger, level, title, message): + delayQueue.add((logger, level, title, message)) + return 'OK' + + +delayQueue = DelayQueue(10, process_log_msg) + +application = Application([LogService], + tns='kan.logger.wechat', + in_protocol=HttpRpc(validator='soft'), + out_protocol=JsonDocument() + ) + +if __name__ == '__main__': + # You can use any Wsgi server. Here, we chose + # Python's built-in wsgi server but you're not + # supposed to use it in production. + from wsgiref.simple_server import make_server + + wsgi_app = WsgiApplication(application) + server = make_server(ip, port, wsgi_app) + + robot = DtalkRobot(webhook) + robot.sendText_webhook(webhook, "启动钉钉日志服务成功") + + # 不退出 + server.serve_forever() diff --git a/python/run_dt.bat b/python/run_dt.bat new file mode 100644 index 0000000..0db0556 --- /dev/null +++ b/python/run_dt.bat @@ -0,0 +1,2 @@ +python dtlogger.py +pause \ No newline at end of file From 48d687f89e9905ee75e08879cc32a6ef7ac4a5d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Tue, 2 Mar 2021 18:11:31 +0800 Subject: [PATCH 39/41] =?UTF-8?q?=E6=B7=BB=E5=8A=A05=E5=88=86=E9=92=9F?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E6=97=B6=E9=97=B4=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/Clock.reg | Bin 0 -> 334 bytes config/NTP.reg | Bin 0 -> 616 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 config/Clock.reg create mode 100644 config/NTP.reg diff --git a/config/Clock.reg b/config/Clock.reg new file mode 100644 index 0000000000000000000000000000000000000000..081b4af5637ff4153baee875ecc892834ef5ee97 GIT binary patch literal 334 zcmY+9QA+|*5QV?z!2clr0MUnDf*wKwMe1Q!i)bUnz1EWM#;&#b=dJIq5Xj{+b7sz* zne%&mq@X0HqNSlvLg39>!=9Rhm0P=os1o;iuwUCP#HIL>AtPUpi|#)&W$w%quS{5~ zmx%6Jh?k`137N5Cqh`xWwP58=#kF~*_NkX~ep{yAmyF0Sojt!KQ~8HawoXSzt>%rF zf4iYnIhen67Y^M1E~_;LJJCn()|oNYadaNoxh-m~`C!1cjJ8wGx$68z&!;#3_x=a? C^gD(C literal 0 HcmV?d00001 diff --git a/config/NTP.reg b/config/NTP.reg new file mode 100644 index 0000000000000000000000000000000000000000..c90b456f1c7b1adf4bbbe019795b5cfff28c9088 GIT binary patch literal 616 zcmd6j!AiqG6h+Tk@E=M)K&&E&;6j3+XlpTI5tSlsEP Date: Sat, 6 Mar 2021 01:17:51 +0800 Subject: [PATCH 40/41] =?UTF-8?q?=E6=92=A4=E5=8D=95=E6=8A=A5=E5=91=8A?= =?UTF-8?q?=E4=B8=AD=E6=B7=BB=E5=8A=A0=E6=96=87=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QuantBox.APIProvider/Single/OrderMap.cs | 2 +- QuantBox.APIProvider/Single/SingleProvider.API.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/QuantBox.APIProvider/Single/OrderMap.cs b/QuantBox.APIProvider/Single/OrderMap.cs index 9aec76b..58d3e83 100644 --- a/QuantBox.APIProvider/Single/OrderMap.cs +++ b/QuantBox.APIProvider/Single/OrderMap.cs @@ -228,7 +228,7 @@ public void Process(ref OrderField order, NLog.Logger log) workingOrders.Remove(order.ID); orderIDs.Remove(record.Order.Id); record.LeavesQty = 0; - EmitExecutionReport(record, SQ.ExecType.ExecCancelled, SQ.OrderStatus.Cancelled); + EmitExecutionReport(record, SQ.ExecType.ExecCancelled, SQ.OrderStatus.Cancelled, order.Text()); } else if (this.pendingOrders.TryRemove(order.LocalID, out record)) { diff --git a/QuantBox.APIProvider/Single/SingleProvider.API.cs b/QuantBox.APIProvider/Single/SingleProvider.API.cs index 995029b..06a3e48 100644 --- a/QuantBox.APIProvider/Single/SingleProvider.API.cs +++ b/QuantBox.APIProvider/Single/SingleProvider.API.cs @@ -18,7 +18,7 @@ public partial class SingleProvider { static SingleProvider() { - NLog.LogManager.Configuration = new NLog.Config.XmlLoggingConfiguration(Path.Combine(PathHelper.RootPath.LocalPath, "NLog.config"), true); + NLog.LogManager.LoadConfiguration(Path.Combine(PathHelper.RootPath.LocalPath, "NLog.config")); } public DelegateOnRspQryInvestorPosition OnRspQryInvestorPosition { get; set; } public DelegateOnRspQryTradingAccount OnRspQryTradingAccount { get; set; } From 1bb483284163175d36cf80e8079a752d58910d87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=8D=E4=BE=83?= Date: Mon, 29 Mar 2021 09:48:13 +0800 Subject: [PATCH 41/41] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=B8=A4=E5=A4=84?= =?UTF-8?q?=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QuantBox.APIProvider/Single/ServerItem.cs | 2 +- QuantBox.APIProvider/Single/UserItem.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/QuantBox.APIProvider/Single/ServerItem.cs b/QuantBox.APIProvider/Single/ServerItem.cs index c14abbc..2ba7078 100644 --- a/QuantBox.APIProvider/Single/ServerItem.cs +++ b/QuantBox.APIProvider/Single/ServerItem.cs @@ -19,7 +19,7 @@ public class ServerItem : ICloneable public string Label { get; set; } #if NET48 - [Editor(typeof(System.Windows.Forms.Design.FolderNameEditor), typeof(UITypeEditor))] + [Editor(typeof(System.Windows.Forms.Design.FileNameEditor), typeof(UITypeEditor))] #endif public string Path { get; set; } diff --git a/QuantBox.APIProvider/Single/UserItem.cs b/QuantBox.APIProvider/Single/UserItem.cs index e08085c..5b97973 100644 --- a/QuantBox.APIProvider/Single/UserItem.cs +++ b/QuantBox.APIProvider/Single/UserItem.cs @@ -22,7 +22,7 @@ public string Label set; } #if NET48 - [Editor(typeof(System.Windows.Forms.Design.FolderNameEditor), typeof(UITypeEditor))] + [Editor(typeof(System.Windows.Forms.Design.FileNameEditor), typeof(UITypeEditor))] #endif public string Path { get; set; }