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 01/20] =?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 02/20] =?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 03/20] =?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 04/20] =?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 05/20] =?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 06/20] =?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 07/20] =?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 08/20] =?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 09/20] =?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 10/20] =?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 11/20] =?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 12/20] =?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 13/20] =?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 14/20] =?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 15/20] =?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 16/20] =?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 17/20] =?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 18/20] =?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 19/20] =?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 20/20] =?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; }