using BitgetAPI; using BitgetAPI.Utils; using BitgetAPI.Data; using BitgetAPI.Utils; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.WebSockets; using System.Text; using System.Threading; using System.Threading.Tasks; using BitgetApi.Data; using Newtonsoft.Json.Linq; using DevExpress.Utils.Extensions; namespace BitgetAPI.WebService { public class WebConnection { public static object SendWebServer(CommonProperty.ExchangeWebReqType exchangeWebReqType, string url = "", string postData = "", string subUri = "") { object returnJsonData = null; CommonProperty commonProperty = CommonProperty.Instance; try { HttpWebRequest wReq = null; // Post 방식인 경우만 사용 var rgbyData = Encoding.ASCII.GetBytes(postData); // 웹 전송 타입 지정 var webConType = CommonProperty.WebConnectionType.GET; // 1. WebRequest 객체 형성 및 HttpWebRequest 로 형변환 // 2. 거래소에 따른 헤더 파일 처리(POST 일 경우만 지정함) if(string.IsNullOrEmpty(url)) { switch (exchangeWebReqType) { #region Upbit case CommonProperty.ExchangeWebReqType.UpbitMarket: wReq = (HttpWebRequest)WebRequest.Create(new Uri(CommonProperty.UpbitURL_MarketInfo)); break; #endregion #region Bitget case CommonProperty.ExchangeWebReqType.BitgetMarket_Spot: wReq = (HttpWebRequest)WebRequest.Create(new Uri(CommonProperty.BitgetURL_MarketInfo_COIN)); break; case CommonProperty.ExchangeWebReqType.BitgetMarket_Future: wReq = (HttpWebRequest)WebRequest.Create(new Uri(CommonProperty.BitgetURL_MarketInfo_FUTURE)); break; case CommonProperty.ExchangeWebReqType.BitgetCandleStick_Coin: wReq = (HttpWebRequest)WebRequest.Create(new Uri(CommonProperty.BitgetURL_MarketCandle_Coin)); break; case CommonProperty.ExchangeWebReqType.BitgetCandleStick_Future: wReq = (HttpWebRequest)WebRequest.Create(new Uri(CommonProperty.BitgetURL_MarketCandle_Future)); break; #endregion } } else wReq= (HttpWebRequest)WebRequest.Create(new Uri(url)); // GET, POST 구분 switch (webConType) { case CommonProperty.WebConnectionType.GET: break; case CommonProperty.WebConnectionType.POST: wReq.Method = "POST"; // 전송 방법 "GET" or "POST" using (var stream = wReq.GetRequestStream()) { stream.Write(rgbyData, 0, rgbyData.Length); } wReq.ContentType = "application/x-www-form-urlencoded"; wReq.ContentLength = rgbyData.Length; break; } using (var wRes = (HttpWebResponse)wReq.GetResponse()) { var respPostStream = wRes.GetResponseStream(); var readerPost = new StreamReader(respPostStream, Encoding.UTF8, true); var resResult = readerPost.ReadToEnd(); switch (exchangeWebReqType) { #region Bitget case CommonProperty.ExchangeWebReqType.BitgetMarket_Spot: { var datalist = JsonConvert.DeserializeObject>(resResult); var marketInfo = JsonConvert.DeserializeObject>>(datalist["data"]?.ToString()); var data = marketInfo.FindAll(x => x["coin"].ToString().Contains("USDT")); } break; case CommonProperty.ExchangeWebReqType.BitgetMarket_Future: { var datalist = JsonConvert.DeserializeObject>(resResult); var marketInfos = JsonConvert.DeserializeObject>>(datalist["data"]?.ToString()); commonProperty.marketInfoList = new List(); foreach (var item in marketInfos) { MarketInfo marketInfo = new MarketInfo(); marketInfo.MarketName = item["symbol"].ToString(); marketInfo.ExchangePlace = Enum.GetName(typeof(CommonProperty.ExchangePlace), commonProperty.selectedChangePlace); commonProperty.marketInfoList.Add(marketInfo); } return commonProperty.marketInfoList; } break; case CommonProperty.ExchangeWebReqType.BitgetCandleStick_Coin: { } break; case CommonProperty.ExchangeWebReqType.BitgetCandleStick_Future: { var datalist = JsonConvert.DeserializeObject>(resResult); var datas = JsonConvert.DeserializeObject>>(datalist["data"]?.ToString()); List candleDatas = new List(); foreach(var item in datas) { CandleData candleData = new CandleData(); candleData.Argument = Convertor.GetUnixtimeStampToDateTime(long.Parse(item[0].ToString())); candleData.Open = Convert.ToDouble(item[1]); candleData.High = Convert.ToDouble(item[2]); candleData.Low = Convert.ToDouble(item[3]); candleData.Close = Convert.ToDouble(item[4]); candleData.Vol_C = Convert.ToDouble(item[5]); candleData.Vol_USD = Convert.ToDouble(item[6]); candleDatas.Add(candleData); } return candleDatas; } break; #endregion } } } catch (WebException webEx) { using (var Response = (HttpWebResponse)webEx.Response) { var nCode = Response.StatusCode; using (var reader = new StreamReader(Response.GetResponseStream())) { var sRespBodyData = reader.ReadToEnd(); //return (JObject.Parse(sRespBodyData)); } } } return returnJsonData; } public async void webSocektStart() { string apiUrl = "https://api.upbit.com/v1/market/all?isDetails=true"; // IP당 100개 연결 // 시간당 240회 !!! // 타이머 30초 유지 > 30초 이내의 응답 메시지 수신 필요 > 아니면 오류 발생 !! > 재접속 필요 !! // 초당 10개 메시지 허용 // 단일 연결로 최대 1000개의 스트림 구독 // 단인 IP 최대의 100개 연결 // * /* timestamp : Unix Epoch 시간 * passphrase : APIKey 비밀번호 * timestamp : Unix Epoch 시간, 단위는 초(--restAPI의 서명 타임스탬프와 다름--) * secretKey : 사용자가 APIKey를 신청할 때 생성되는 보안 키입니다. 예: 22582BD0CFF14C41EDBF1AB98506286D */ ClientWebSocket webSocket = new ClientWebSocket(); string WebSocketUrl = "wss://ws.bitget.com/v2/ws/public"; string message = ""; var tempStrData = ""; CommonProperty commonProperty = CommonProperty.Instance; try { await webSocket.ConnectAsync(new Uri(WebSocketUrl), CancellationToken.None); // 연결이 성공적으로 이루어지면 처리할 코드 작성 Console.WriteLine("WebSocket 연결 성공"); // Json String 만들기 // 종목별 Ticker 구독하기 var dic = new Dictionary(); dic.Add("op", "subscribe"); var argsList = new List>(); foreach (var marketInfo in commonProperty.marketInfoList) { var args = new Dictionary(); args.Add("instType", "USDT-FUTURES"); args.Add("channel", "ticker"); //args.Add("channel", "candle1m"); args.Add("instId", marketInfo.MarketName); argsList.Add(args); } 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); await SendMessage(webSocket, jsonData); // 데이터 수신을 위한 반복문 시작 while (webSocket.State == WebSocketState.Open) { //Thread.Sleep(100); byte[] buffer = new byte[1024]; WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); message = ""; // 수신한 데이터 처리 message = System.Text.Encoding.UTF8.GetString(buffer, 0, result.Count); if (!ValidateJSON(message)) { tempStrData += message; if (!ValidateJSON(message)) { continue; } else { message = tempStrData; } } var datalist = JsonConvert.DeserializeObject>(message); if (datalist.ContainsKey("data")) { var candleInfo = JsonConvert.DeserializeObject>(datalist["data"]?.ToString()); var tickerList = candleInfo[0]; 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); else { commonProperty.webSocketCandles[searchIndex] = tickerList; } //var sendTime = dt.AddMilliseconds(Convert.ToDouble(datalist["ts"])).ToLocalTime(); // Candle 리스트에 데이터 쌓기 //var marketCandleList = commonProperty.candleDataLists.Find(i => i.ConGoodsData.MarketName == candleInfo[0]["instId"].ToString()); // 분 업데이트 (1,3,5,10,15,30) //if(recieveTime.Second == 0) { } // 시 업데이트 (1,4,6) //if(recieveTime.Minute == 0) { } //else { } } // 요청시간 // Candle 시간 } } catch (Exception ex) { Console.WriteLine("WebSocket 연결 중 오류 발생: " + ex.Message); } finally { if (webSocket.State == WebSocketState.Open) await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "WebSocket 연결 종료", CancellationToken.None); webSocket.Dispose(); } } private static async Task SendMessage(ClientWebSocket webSocket, string message) { byte[] buffer = Encoding.UTF8.GetBytes(message); await webSocket.SendAsync(new ArraySegment(buffer), WebSocketMessageType.Text, true, CancellationToken.None); Console.WriteLine("메시지 전송: " + message); } public static bool ValidateJSON(string s) { try { JToken.Parse(s); return true; } catch (JsonReaderException) { return false; } } } }