diff --git a/BitgetApi/MainForm.Designer.cs b/BitgetApi/MainForm.Designer.cs index 6973027..b8eb5e0 100644 --- a/BitgetApi/MainForm.Designer.cs +++ b/BitgetApi/MainForm.Designer.cs @@ -49,8 +49,9 @@ this.xtraTabControl_Main = new DevExpress.XtraTab.XtraTabControl(); this.xtraTabPage_Status = new DevExpress.XtraTab.XtraTabPage(); this.xtraTabPage_Searcher = new DevExpress.XtraTab.XtraTabPage(); - this.groupControl_SearcherCondition = new DevExpress.XtraEditors.GroupControl(); this.groupControl_SignalSeacher = new DevExpress.XtraEditors.GroupControl(); + this.groupControl_SearcherCondition = new DevExpress.XtraEditors.GroupControl(); + this.checkedComboBoxEdit_MarketInfoList = new DevExpress.XtraEditors.CheckedComboBoxEdit(); ((System.ComponentModel.ISupportInitialize)(this.groupControl_Setting)).BeginInit(); this.groupControl_Setting.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.comboBoxEdit_ConinType.Properties)).BeginInit(); @@ -62,8 +63,10 @@ this.xtraTabControl_Main.SuspendLayout(); this.xtraTabPage_Status.SuspendLayout(); this.xtraTabPage_Searcher.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.groupControl_SearcherCondition)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.groupControl_SignalSeacher)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.groupControl_SearcherCondition)).BeginInit(); + this.groupControl_SearcherCondition.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.checkedComboBoxEdit_MarketInfoList.Properties)).BeginInit(); this.SuspendLayout(); // // groupControl_Setting @@ -76,7 +79,7 @@ this.groupControl_Setting.Controls.Add(this.labelControl1); this.groupControl_Setting.Location = new System.Drawing.Point(3, 2); this.groupControl_Setting.Name = "groupControl_Setting"; - this.groupControl_Setting.Size = new System.Drawing.Size(912, 75); + this.groupControl_Setting.Size = new System.Drawing.Size(907, 75); this.groupControl_Setting.TabIndex = 0; this.groupControl_Setting.Text = "초기 설정"; // @@ -86,6 +89,7 @@ this.comboBoxEdit_ConinType.Name = "comboBoxEdit_ConinType"; this.comboBoxEdit_ConinType.Properties.Buttons.AddRange(new DevExpress.XtraEditors.Controls.EditorButton[] { new DevExpress.XtraEditors.Controls.EditorButton(DevExpress.XtraEditors.Controls.ButtonPredefines.Combo)}); + this.comboBoxEdit_ConinType.Properties.ReadOnly = true; this.comboBoxEdit_ConinType.Size = new System.Drawing.Size(100, 20); this.comboBoxEdit_ConinType.TabIndex = 1; this.comboBoxEdit_ConinType.SelectedIndexChanged += new System.EventHandler(this.comboBox_CoinType_SelectedIndexChanged); @@ -96,6 +100,7 @@ this.comboBoxEdit_ExchangePlace.Name = "comboBoxEdit_ExchangePlace"; this.comboBoxEdit_ExchangePlace.Properties.Buttons.AddRange(new DevExpress.XtraEditors.Controls.EditorButton[] { new DevExpress.XtraEditors.Controls.EditorButton(DevExpress.XtraEditors.Controls.ButtonPredefines.Combo)}); + this.comboBoxEdit_ExchangePlace.Properties.ReadOnly = true; this.comboBoxEdit_ExchangePlace.Size = new System.Drawing.Size(100, 20); this.comboBoxEdit_ExchangePlace.TabIndex = 1; this.comboBoxEdit_ExchangePlace.SelectedIndexChanged += new System.EventHandler(this.comboBox_ExchangePlace_SelectedIndexChanged); @@ -124,13 +129,14 @@ this.groupControl_MarketInfo.Dock = System.Windows.Forms.DockStyle.Fill; this.groupControl_MarketInfo.Location = new System.Drawing.Point(0, 0); this.groupControl_MarketInfo.Name = "groupControl_MarketInfo"; - this.groupControl_MarketInfo.Size = new System.Drawing.Size(910, 428); + this.groupControl_MarketInfo.Size = new System.Drawing.Size(905, 430); this.groupControl_MarketInfo.TabIndex = 1; this.groupControl_MarketInfo.Text = "종목 현황"; // // labelControl_MarketCount // - this.labelControl_MarketCount.Location = new System.Drawing.Point(856, 36); + this.labelControl_MarketCount.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.labelControl_MarketCount.Location = new System.Drawing.Point(851, 36); this.labelControl_MarketCount.Name = "labelControl_MarketCount"; this.labelControl_MarketCount.Size = new System.Drawing.Size(21, 14); this.labelControl_MarketCount.TabIndex = 2; @@ -138,7 +144,8 @@ // // labelControl3 // - this.labelControl3.Location = new System.Drawing.Point(804, 36); + this.labelControl3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.labelControl3.Location = new System.Drawing.Point(799, 36); this.labelControl3.Name = "labelControl3"; this.labelControl3.Size = new System.Drawing.Size(46, 14); this.labelControl3.TabIndex = 1; @@ -161,7 +168,7 @@ this.treeListColumn_quoteVolume}); this.treeList_MarketInfo.Location = new System.Drawing.Point(2, 56); this.treeList_MarketInfo.Name = "treeList_MarketInfo"; - this.treeList_MarketInfo.Size = new System.Drawing.Size(906, 370); + this.treeList_MarketInfo.Size = new System.Drawing.Size(901, 372); this.treeList_MarketInfo.TabIndex = 0; // // treeListColumn_ExchangePlace @@ -244,7 +251,7 @@ this.xtraTabControl_Main.Location = new System.Drawing.Point(3, 83); this.xtraTabControl_Main.Name = "xtraTabControl_Main"; this.xtraTabControl_Main.SelectedTabPage = this.xtraTabPage_Status; - this.xtraTabControl_Main.Size = new System.Drawing.Size(912, 454); + this.xtraTabControl_Main.Size = new System.Drawing.Size(907, 456); this.xtraTabControl_Main.TabIndex = 2; this.xtraTabControl_Main.TabPages.AddRange(new DevExpress.XtraTab.XtraTabPage[] { this.xtraTabPage_Status, @@ -254,7 +261,7 @@ // this.xtraTabPage_Status.Controls.Add(this.groupControl_MarketInfo); this.xtraTabPage_Status.Name = "xtraTabPage_Status"; - this.xtraTabPage_Status.Size = new System.Drawing.Size(910, 428); + this.xtraTabPage_Status.Size = new System.Drawing.Size(905, 430); this.xtraTabPage_Status.Text = "현황판"; // // xtraTabPage_Searcher @@ -265,15 +272,6 @@ this.xtraTabPage_Searcher.Size = new System.Drawing.Size(910, 428); this.xtraTabPage_Searcher.Text = "검색기"; // - // groupControl_SearcherCondition - // - this.groupControl_SearcherCondition.Dock = System.Windows.Forms.DockStyle.Top; - this.groupControl_SearcherCondition.Location = new System.Drawing.Point(0, 0); - this.groupControl_SearcherCondition.Name = "groupControl_SearcherCondition"; - this.groupControl_SearcherCondition.Size = new System.Drawing.Size(910, 100); - this.groupControl_SearcherCondition.TabIndex = 0; - this.groupControl_SearcherCondition.Text = "조건 설정"; - // // groupControl_SignalSeacher // this.groupControl_SignalSeacher.Dock = System.Windows.Forms.DockStyle.Fill; @@ -283,15 +281,36 @@ this.groupControl_SignalSeacher.TabIndex = 1; this.groupControl_SignalSeacher.Text = "신호 검색"; // + // groupControl_SearcherCondition + // + this.groupControl_SearcherCondition.Controls.Add(this.checkedComboBoxEdit_MarketInfoList); + this.groupControl_SearcherCondition.Dock = System.Windows.Forms.DockStyle.Top; + this.groupControl_SearcherCondition.Location = new System.Drawing.Point(0, 0); + this.groupControl_SearcherCondition.Name = "groupControl_SearcherCondition"; + this.groupControl_SearcherCondition.Size = new System.Drawing.Size(910, 100); + this.groupControl_SearcherCondition.TabIndex = 0; + this.groupControl_SearcherCondition.Text = "조건 설정"; + // + // checkedComboBoxEdit_MarketInfoList + // + this.checkedComboBoxEdit_MarketInfoList.Location = new System.Drawing.Point(17, 52); + this.checkedComboBoxEdit_MarketInfoList.Name = "checkedComboBoxEdit_MarketInfoList"; + this.checkedComboBoxEdit_MarketInfoList.Properties.Buttons.AddRange(new DevExpress.XtraEditors.Controls.EditorButton[] { + new DevExpress.XtraEditors.Controls.EditorButton(DevExpress.XtraEditors.Controls.ButtonPredefines.Combo)}); + this.checkedComboBoxEdit_MarketInfoList.Properties.IncrementalSearch = true; + this.checkedComboBoxEdit_MarketInfoList.Size = new System.Drawing.Size(129, 20); + this.checkedComboBoxEdit_MarketInfoList.TabIndex = 0; + // // MainForm // this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(916, 542); + this.ClientSize = new System.Drawing.Size(911, 544); this.Controls.Add(this.xtraTabControl_Main); this.Controls.Add(this.groupControl_Setting); this.Name = "MainForm"; this.Text = "Searcher"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing); ((System.ComponentModel.ISupportInitialize)(this.groupControl_Setting)).EndInit(); this.groupControl_Setting.ResumeLayout(false); this.groupControl_Setting.PerformLayout(); @@ -305,8 +324,10 @@ this.xtraTabControl_Main.ResumeLayout(false); this.xtraTabPage_Status.ResumeLayout(false); this.xtraTabPage_Searcher.ResumeLayout(false); - ((System.ComponentModel.ISupportInitialize)(this.groupControl_SearcherCondition)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.groupControl_SignalSeacher)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.groupControl_SearcherCondition)).EndInit(); + this.groupControl_SearcherCondition.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.checkedComboBoxEdit_MarketInfoList.Properties)).EndInit(); this.ResumeLayout(false); } @@ -336,6 +357,7 @@ private DevExpress.XtraTab.XtraTabPage xtraTabPage_Searcher; private DevExpress.XtraEditors.GroupControl groupControl_SignalSeacher; private DevExpress.XtraEditors.GroupControl groupControl_SearcherCondition; + private DevExpress.XtraEditors.CheckedComboBoxEdit checkedComboBoxEdit_MarketInfoList; } } diff --git a/BitgetApi/MainForm.cs b/BitgetApi/MainForm.cs index 668abaa..e7f51f5 100644 --- a/BitgetApi/MainForm.cs +++ b/BitgetApi/MainForm.cs @@ -15,6 +15,7 @@ using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using static BitgetAPI.CommonProperty; +using static DevExpress.Utils.Html.ViewInfo.DxHtmlOrderedListInfoCore; namespace BitgetAPI { @@ -22,6 +23,18 @@ namespace BitgetAPI { CommonProperty commonProperty = CommonProperty.Instance; + #region 폼 내 사용되는 스레드 + // 트리 현황판 업데이트 스레드 + Thread treeListMarketInfoListUpdateTimer = null; + // 현황판 웹소켓 스레드 + Thread th_MarketStatus = null; + // 종목별 캔들 데이터 스레드 + Thread th_MarketCandeData = null; + + // 종목별 캔들 데이터 : 캔들 개수 + const int candleCount = 200; + #endregion + public MainForm() { InitializeComponent(); @@ -45,6 +58,15 @@ namespace BitgetAPI treeList_MarketInfo.BeginSort(); treeList_MarketInfo.Columns["quoteVolume"].SortOrder = SortOrder.Descending; treeList_MarketInfo.EndSort(); + + // 현황판 웹소켓 + th_MarketStatus = new Thread(() => ThreadEventAsync(BitgetWebSocketType.현황정보_전체종목, "ticker")); + th_MarketStatus.Start(); + + // 트리 현황판 업데이트 + treeListMarketInfoListUpdateTimer = new Thread(new ThreadStart(TreeListMarketInfoListUpdate)); + treeListMarketInfoListUpdateTimer.Start(); + // API Key 가져오기 및 등록 // BITGET Raster 소켓 테스트 @@ -55,24 +77,20 @@ namespace BitgetAPI // 구름떼, 볼린저 생성 - // 트리 현황판 업데이트 - var treeListMarketInfoListUpdateTimer = new Thread(new ThreadStart(TreeListMarketInfoListUpdate)); - treeListMarketInfoListUpdateTimer.Start(); - } - // 마켓정보 가져오기 !! - private void MarketInfoListUpdate() + private async void ThreadEventAsync(BitgetWebSocketType bitgetWebSocketType, string channel) { - // 마켓 정보 가져오기 - var marketInfos = (List)BitgetAPI.WebService.WebConnection.SendWebServer(ExchangeWebReqType.BitgetMarket_Future); + // WebSocket 생성 + var webConnection = new WebConnection(); + webConnection.BitGetWebSocektStart(bitgetWebSocketType, channel); } - private void TreeListMarketInfoListUpdate() + private void TreeListMarketInfoListUpdate( ) { while(true) { - Thread.Sleep(500); + Thread.Sleep(300); Invoke(new MethodInvoker(delegate () { @@ -82,6 +100,62 @@ namespace BitgetAPI } } + // 종목별 캔들데이터 가져오기 (초기 설정) + private void getMarketCandleData_WebService(ExchangeWebReqType exchangeWebReqType) + { + // WebServicee 초기 캔들 데이터 가져오기 : 종목, 개수 + foreach (var marketCandleDataList in commonProperty.candleDataLists) + { + var marketName = marketCandleDataList.ConGoodsData.MarketName; + + // 캔들 데이터 가져오기 + foreach (var interval in Enum.GetValues(typeof(CommonProperty.MCandleTimeType))) + { + // Description + var description = Utils.Convertor.GetEnumDescription((Enum)interval); + // 1M, 3M Names.... + var intervalName = Enum.GetName(typeof(CommonProperty.MCandleTimeType), interval); + + var url = ""; + + switch (commonProperty.selectedChangePlace) + { + case ExchangePlace.Upbit: + break; + case ExchangePlace.Bitget: + switch (commonProperty.selectedBitgetProductType) + { + case BitgetProductType.COIN: + exchangeWebReqType = ExchangeWebReqType.BitgetCandleStick_Coin; + var defaultDateTime = DateTime.Now; + + var startDateTime = DateTime.FromFileTimeUtc(defaultDateTime.Ticks); + + // count + 50 개 캔들 추가 가져오기 + var endDateTime = DateTime.FromFileTimeUtc(defaultDateTime.AddSeconds((int)interval * -1).Ticks); + + // 종목, 인터벌시간, 시작시간(UTC), 종료시간(UTC), 제한 개수 (default:100, Max:1000) + url = string.Format(BitgetURL_MarketCandle_Coin, + marketName, description, startDateTime.ToString(), endDateTime.ToString(), candleCount.ToString()); + break; + case BitgetProductType.FUTURE: + exchangeWebReqType = ExchangeWebReqType.BitgetCandleStick_Future; + + url = string.Format(CommonProperty.BitgetURL_MarketCandle_Future, + marketName, description, candleCount.ToString(), "USDT-FUTURES"); + break; + } + break; + } + + // 초당 20회 제한 !!!! + // Thread.Sleep(50); + var candleList = BitgetAPI.WebService.WebConnection.SendWebServer(exchangeWebReqType, url, marketCandleDataList, (CommonProperty.MCandleTimeType) interval); + } + break; + } + } + // 거래소 콤보박스 클릭 시 이벤트 처리 private void comboBox_ExchangePlace_SelectedIndexChanged(object sender, EventArgs e) { @@ -133,8 +207,6 @@ namespace BitgetAPI commonProperty.candleDataLists = candleDataLists; - var candleCount = 200; - // 캔들 리스트 생성하기 foreach (var item in marketInfos) { @@ -144,16 +216,18 @@ namespace BitgetAPI { candleDataList.candleDataList.Add((MCandleTimeType)interval, new List()); } - candleDataLists.Add(candleDataList); } + // 조건 설정 : 체크콤보박스 마켓 정보 추가하기 + foreach (var item in commonProperty.candleDataLists) + checkedComboBoxEdit_MarketInfoList.Properties.Items.Add(item.ConGoodsData.MarketName); + + commonProperty.webSocketCandles = new List(); - // 현황판 웹소켓 - //var th_MarketStatus = new Thread(() => ThreadEventAsync(BitgetWebSocketType.현황정보_전체종목, "ticker")); - //th_MarketStatus.Start(); - + #region 캔들 웹소켓 : 종목 50, 캔들 1 개만 해도 뒤지려고 함 !! (일딴 패스) + /* // 시간별 분봉 웹소켓 foreach (var interval in Enum.GetValues(typeof(CommonProperty.MCandleTimeType))) { @@ -161,70 +235,29 @@ namespace BitgetAPI var th_CandleStatus = new Thread(() => ThreadEventAsync(BitgetWebSocketType.캔들정보, "candle" + description)); th_CandleStatus.Start(); break; - } + }*/ + #endregion - // 캔들 데이터 가져오기 : 종목, 개수, - foreach (var item in marketInfos) - { - MarketCandleDataList candleDataList = new MarketCandleDataList(); - candleDataList.ConGoodsData = item; - - // 캔들 데이터 가져오기 - foreach(var interval in Enum.GetValues(typeof(CommonProperty.MCandleTimeType))) - { - // Description - var description = Utils.Convertor.GetEnumDescription((Enum)interval); - // 1M, 3M Names.... - var intervalName = Enum.GetName(typeof(CommonProperty.MCandleTimeType), interval); - - var url = ""; - - switch(commonProperty.selectedChangePlace) - { - case ExchangePlace.Upbit: - break; - case ExchangePlace.Bitget: - switch(commonProperty.selectedBitgetProductType) - { - case BitgetProductType.COIN: - exchangeWebReqType = ExchangeWebReqType.BitgetCandleStick_Coin; - var defaultDateTime = DateTime.Now; - - var startDateTime = DateTime.FromFileTimeUtc(defaultDateTime.Ticks); - - // count + 50 개 캔들 추가 가져오기 - var endDateTime = DateTime.FromFileTimeUtc(defaultDateTime.AddSeconds((int)interval * -1).Ticks); - - // 종목, 인터벌시간, 시작시간(UTC), 종료시간(UTC), 제한 개수 (default:100, Max:1000) - url = string.Format(BitgetURL_MarketCandle_Coin, - item.MarketName, description, startDateTime.ToString(), endDateTime.ToString(), candleCount.ToString()); - break; - case BitgetProductType.FUTURE: - exchangeWebReqType = ExchangeWebReqType.BitgetCandleStick_Future; - - url = string.Format(CommonProperty.BitgetURL_MarketCandle_Future, - item.MarketName, description, candleCount.ToString(), "USDT-FUTURES"); - break; - } - break; - } - - List candleList = null; - //var candleList = BitgetAPI.WebService.WebConnection.SendWebServer(exchangeWebReqType, url); - // 초당 20회 제한 !!!! - // Thread.Sleep(50); - //candleDataList.candleDataList.Add((MCandleTimeType)interval,(List)candleList); - - } - } + // WebServicee 초기 캔들 데이터 가져오기 : 종목, 개수 + // 종목별 캔들 데이터 가져오기 (WebService) + th_MarketCandeData = new Thread(() => getMarketCandleData_WebService(exchangeWebReqType)); + th_MarketCandeData.Start(); } - - private async void ThreadEventAsync(BitgetWebSocketType bitgetWebSocketType, string channel ) + // 폼 닫기 시 처리 이벤트 + private void MainForm_FormClosing(object sender, FormClosingEventArgs e) { - // WebSocket 생성 - var webConnection = new WebConnection(); - webConnection.BitGetWebSocektStart(bitgetWebSocketType, channel); + if (th_MarketStatus != null) + { + th_MarketStatus.Abort(); + th_MarketStatus = null; + } + + if (treeListMarketInfoListUpdateTimer != null) + { + treeListMarketInfoListUpdateTimer.Abort(); + treeListMarketInfoListUpdateTimer = null; + } } } } diff --git a/BitgetApi/Properties/licenses.licx b/BitgetApi/Properties/licenses.licx index cedaf96..2a77515 100644 --- a/BitgetApi/Properties/licenses.licx +++ b/BitgetApi/Properties/licenses.licx @@ -1,4 +1,5 @@ -DevExpress.XtraTreeList.TreeList, DevExpress.XtraTreeList.v23.2, Version=23.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a -DevExpress.XtraEditors.TreeListLookUpEdit, DevExpress.XtraTreeList.v23.2, Version=23.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a DevExpress.XtraBars.Docking.DockManager, DevExpress.XtraBars.v23.2, Version=23.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a +DevExpress.XtraEditors.CheckEdit, DevExpress.XtraEditors.v23.2, Version=23.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a +DevExpress.XtraTreeList.TreeList, DevExpress.XtraTreeList.v23.2, Version=23.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a DevExpress.XtraEditors.ComboBoxEdit, DevExpress.XtraEditors.v23.2, Version=23.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a +DevExpress.XtraEditors.TreeListLookUpEdit, DevExpress.XtraTreeList.v23.2, Version=23.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a diff --git a/BitgetApi/WebService/WebConnection.cs b/BitgetApi/WebService/WebConnection.cs index 1a3f752..600d813 100644 --- a/BitgetApi/WebService/WebConnection.cs +++ b/BitgetApi/WebService/WebConnection.cs @@ -15,12 +15,15 @@ using System.Threading.Tasks; using BitgetApi.Data; using Newtonsoft.Json.Linq; using DevExpress.Utils.Extensions; +using static BitgetAPI.CommonProperty; namespace BitgetAPI.WebService { public class WebConnection { - public static object SendWebServer(CommonProperty.ExchangeWebReqType exchangeWebReqType, string url = "", string postData = "", string subUri = "") + public static object SendWebServer(CommonProperty.ExchangeWebReqType exchangeWebReqType, string url = "", + MarketCandleDataList marketCandleDataList = null, CommonProperty.MCandleTimeType interval = MCandleTimeType.M1, + string postData = "", string subUri = "") { object returnJsonData = null; @@ -39,7 +42,6 @@ namespace BitgetAPI.WebService // 1. WebRequest 객체 형성 및 HttpWebRequest 로 형변환 // 2. 거래소에 따른 헤더 파일 처리(POST 일 경우만 지정함) - if(string.IsNullOrEmpty(url)) { switch (exchangeWebReqType) @@ -129,7 +131,9 @@ namespace BitgetAPI.WebService var datalist = JsonConvert.DeserializeObject>(resResult); var datas = JsonConvert.DeserializeObject>>(datalist["data"]?.ToString()); - List candleDatas = new List(); + if (marketCandleDataList == null) return null; + + var candleDataList = marketCandleDataList.candleDataList[interval]; foreach(var item in datas) { @@ -142,7 +146,19 @@ namespace BitgetAPI.WebService candleData.Vol_C = Convert.ToDouble(item[5]); candleData.Vol_USD = Convert.ToDouble(item[6]); - candleDatas.Add(candleData); + // 같은 시간이 존재하면 업데이트 : 1개밖에 없음 + var sameCandleData = candleDataList.Find(i => i.Argument.Minute == candleData.Argument.Minute && + i.Argument.Hour == candleData.Argument.Hour); + + if (sameCandleData != null) + { + // 종가 => 웹소켓 데이터 사용 (웹 서비스 호출 데이터 중 마지막 데이터는 캔들이 완성되지 않음) + // 시가 => 웹 서비스 데이터 사용 + sameCandleData.Open = candleData.Open; + // 저가, 고가 => 비교해서 사용 + sameCandleData.Low = Math.Min(sameCandleData.Low, candleData.Low); + sameCandleData.High = Math.Max(sameCandleData.High, candleData.High); + } } return candleDatas; @@ -195,9 +211,9 @@ namespace BitgetAPI.WebService string WebSocketUrl = "wss://ws.bitget.com/v2/ws/public"; string message = ""; var tempStrData = ""; - try { + await webSocket.ConnectAsync(new Uri(WebSocketUrl), CancellationToken.None); // 연결이 성공적으로 이루어지면 처리할 코드 작성 Console.WriteLine("WebSocket 연결 성공"); @@ -214,13 +230,12 @@ namespace BitgetAPI.WebService var args = new Dictionary(); args.Add("instType", "USDT-FUTURES"); args.Add("channel", chnnelType); - //args.Add("channel", "candle1m"); args.Add("instId", marketInfo.MarketName); argsList.Add(args); - break; } - dic.Add("args", argsList); + dic.Add("args", argsList) + ; //var jsonDataText = "{\"op\":\"subscribe\",\"args\":[{\"instType\":\"SPOT\",\"channel\":\"ticker\",\"instId\":\"ETHUSDT\"}, {\"instType\":\"SPOT\",\"channel\":\"ticker\",\"instId\":\"BTCUSDT\"}]}"; var jsonData = JsonConvert.SerializeObject(dic); @@ -271,6 +286,7 @@ namespace BitgetAPI.WebService DateTime dt = new DateTime(1970, 01, 01); tickerList.reciveTime = dt.AddMilliseconds(Convert.ToDouble(tickerList.ts)).ToLocalTime(); + // 웹소켓 티커 리스트에 추가 var searchIndex = commonProperty.webSocketCandles.IndexOf(i => i.instId == tickerList.instId); if (searchIndex < 0) commonProperty.webSocketCandles.Add(tickerList); @@ -278,9 +294,108 @@ namespace BitgetAPI.WebService { commonProperty.webSocketCandles[searchIndex] = tickerList; } + + // 캔들 리스트에서 해당 데이터 찾기 + var searchIndex_c = commonProperty.candleDataLists.IndexOf(i => i.ConGoodsData.MarketName == tickerList.instId); + + // 캔들 리스트에 업데이트 (전체 시간별) + foreach (CommonProperty.MCandleTimeType interval in Enum.GetValues(typeof(CommonProperty.MCandleTimeType))) + { + var candleDataList = commonProperty.candleDataLists[searchIndex_c].candleDataList[interval]; + + // 캔들 리스트에 추가 + var candleData = new CandleData(); + candleData.Argument = tickerList.reciveTime; + candleData.Close = tickerList.lastPr; + + // 캔들 리스트가 없으면 추가 + if (candleDataList.Count == 0) + candleDataList.Add(candleData); + else + { + // 마지막 시간 데이터 가져오기 + var lastCandleData = candleDataList.Find(j=>j.Argument == candleDataList.Max(i => i.Argument)); + + // 업데이트 or 추가 + bool updateFlag = true; + + switch (interval) + { + case CommonProperty.MCandleTimeType.M1: + // 같은 분이면 무조건 업데이트 + if (lastCandleData.Argument.Minute != candleData.Argument.Minute) + updateFlag = false; + break; + case CommonProperty.MCandleTimeType.M3: + // 같은 분이면 무조건 업데이트 + if (lastCandleData.Argument.Minute != candleData.Argument.Minute && + candleData.Argument.Minute % 3 == 1) updateFlag = false; + break; + case CommonProperty.MCandleTimeType.M5: + if (lastCandleData.Argument.Minute != candleData.Argument.Minute && + candleData.Argument.Minute % 5 == 1) updateFlag = false; + break; + case CommonProperty.MCandleTimeType.M15: + if (lastCandleData.Argument.Minute != candleData.Argument.Minute && + candleData.Argument.Minute % 15 == 1) updateFlag = false; + break; + case CommonProperty.MCandleTimeType.M30: + if (lastCandleData.Argument.Minute != candleData.Argument.Minute && + candleData.Argument.Minute % 30 == 1) updateFlag = false; + break; + case CommonProperty.MCandleTimeType.H1: + if (lastCandleData.Argument.Hour != candleData.Argument.Hour) + updateFlag = false; + break; + case CommonProperty.MCandleTimeType.H4: + if (lastCandleData.Argument.Hour != candleData.Argument.Hour && + candleData.Argument.Hour % 4 == 1) updateFlag = false; + break; + case CommonProperty.MCandleTimeType.H6: + if (lastCandleData.Argument.Hour != candleData.Argument.Hour && + candleData.Argument.Hour % 6 == 1) updateFlag = false; + break; + case CommonProperty.MCandleTimeType.H12: + if (lastCandleData.Argument.Hour != candleData.Argument.Hour && + candleData.Argument.Hour % 12 == 1) updateFlag = false; + break; + } + + // 이미 등록된 시간 캔들이 있는 경우 변경 + if (updateFlag) + { + // 시간 업데이트 + lastCandleData.Argument = candleData.Argument; + // 종가 수정 + lastCandleData.Close = candleData.Close; + // 저가 등록 + if(lastCandleData.Low == 0 || lastCandleData.Low > candleData.Close) lastCandleData.Low = candleData.Close; + // 고가 등록 + if (lastCandleData.High == 0 || lastCandleData.High < candleData.Close) lastCandleData.High = candleData.Close; + } + // 없는 경우 추가 + else + { + // 새 데이터 등록 + candleDataList.Add(candleData); + + // 시가 등록 + candleData.Open = candleData.Close; + + // 기존 데이터 삭제 + if (candleDataList.Count > 250) + { + // 가장 오래된 데이터 삭제 + candleDataList.Remove(j => j.Argument == candleDataList.Min(i => i.Argument)); + } + } + } + + } } break; case CommonProperty.BitgetWebSocketType.캔들정보: + #region 캔들 웹소켓 : 종목 50, 캔들 1 개만 해도 뒤지려고 함 !! (일딴 패스) { var argList = JsonConvert.DeserializeObject>(datalist["arg"]?.ToString()); @@ -381,6 +496,7 @@ namespace BitgetAPI.WebService } } } + #endregion break; } @@ -412,6 +528,7 @@ namespace BitgetAPI.WebService // Candle 시간 } + } catch (Exception ex) @@ -458,3 +575,4 @@ namespace BitgetAPI.WebService } } } + diff --git a/BitgetApi/bin/Debug/BitgetApi.exe b/BitgetApi/bin/Debug/BitgetApi.exe index 3e6bfc4..7ee4491 100644 Binary files a/BitgetApi/bin/Debug/BitgetApi.exe and b/BitgetApi/bin/Debug/BitgetApi.exe differ diff --git a/BitgetApi/bin/Debug/BitgetApi.pdb b/BitgetApi/bin/Debug/BitgetApi.pdb index 1ac448c..65c4c5e 100644 Binary files a/BitgetApi/bin/Debug/BitgetApi.pdb and b/BitgetApi/bin/Debug/BitgetApi.pdb differ diff --git a/BitgetApi/bin/bitgetAPI.zip b/BitgetApi/bin/bitgetAPI.zip new file mode 100644 index 0000000..b9498bd Binary files /dev/null and b/BitgetApi/bin/bitgetAPI.zip differ diff --git a/BitgetApi/obj/Debug/BitgetApi.csproj.GenerateResource.cache b/BitgetApi/obj/Debug/BitgetApi.csproj.GenerateResource.cache index ae5e544..3e80abd 100644 Binary files a/BitgetApi/obj/Debug/BitgetApi.csproj.GenerateResource.cache and b/BitgetApi/obj/Debug/BitgetApi.csproj.GenerateResource.cache differ diff --git a/BitgetApi/obj/Debug/BitgetApi.exe b/BitgetApi/obj/Debug/BitgetApi.exe index 3e6bfc4..7ee4491 100644 Binary files a/BitgetApi/obj/Debug/BitgetApi.exe and b/BitgetApi/obj/Debug/BitgetApi.exe differ diff --git a/BitgetApi/obj/Debug/BitgetApi.pdb b/BitgetApi/obj/Debug/BitgetApi.pdb index 1ac448c..65c4c5e 100644 Binary files a/BitgetApi/obj/Debug/BitgetApi.pdb and b/BitgetApi/obj/Debug/BitgetApi.pdb differ diff --git a/BitgetApi/obj/Debug/DesignTimeResolveAssemblyReferences.cache b/BitgetApi/obj/Debug/DesignTimeResolveAssemblyReferences.cache index c85cb85..212ca5a 100644 Binary files a/BitgetApi/obj/Debug/DesignTimeResolveAssemblyReferences.cache and b/BitgetApi/obj/Debug/DesignTimeResolveAssemblyReferences.cache differ diff --git a/BitgetApi/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache b/BitgetApi/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache index fe857ef..fd118f5 100644 Binary files a/BitgetApi/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache and b/BitgetApi/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache differ diff --git a/BitgetApi/obj/Debug/bitgetapi.exe.licenses b/BitgetApi/obj/Debug/bitgetapi.exe.licenses index 99b1e47..bac4b2e 100644 Binary files a/BitgetApi/obj/Debug/bitgetapi.exe.licenses and b/BitgetApi/obj/Debug/bitgetapi.exe.licenses differ