2024-05-23 16:32:30 +09:00
|
|
|
|
using BitgetAPI;
|
|
|
|
|
|
using BitgetAPI.Utils;
|
2024-05-22 16:56:51 +09:00
|
|
|
|
using BitgetAPI.Data;
|
|
|
|
|
|
using BitgetAPI.Utils;
|
|
|
|
|
|
using Newtonsoft.Json;
|
|
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.IO;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Net;
|
2024-05-23 16:32:30 +09:00
|
|
|
|
using System.Net.WebSockets;
|
2024-05-22 16:56:51 +09:00
|
|
|
|
using System.Text;
|
2024-05-23 16:32:30 +09:00
|
|
|
|
using System.Threading;
|
2024-05-22 16:56:51 +09:00
|
|
|
|
using System.Threading.Tasks;
|
2024-05-23 16:32:30 +09:00
|
|
|
|
using BitgetApi.Data;
|
|
|
|
|
|
using Newtonsoft.Json.Linq;
|
|
|
|
|
|
using DevExpress.Utils.Extensions;
|
2024-05-28 16:56:19 +09:00
|
|
|
|
using static BitgetAPI.CommonProperty;
|
2024-06-10 23:22:01 +09:00
|
|
|
|
using DateTime = System.DateTime;
|
2024-07-10 11:46:59 +09:00
|
|
|
|
using DevExpress.Xpo.Logger;
|
2024-07-11 14:16:48 +09:00
|
|
|
|
using DevExpress.XtraTreeList.Filtering.Provider;
|
2024-07-12 12:57:46 +09:00
|
|
|
|
using System.Runtime.InteropServices;
|
2024-07-15 12:49:00 +09:00
|
|
|
|
using DevExpress.XtraEditors.Filtering;
|
|
|
|
|
|
using DevExpress.XtraExport.Xls;
|
|
|
|
|
|
using DevExpress.Utils.Filtering.Internal;
|
2024-08-29 11:02:17 +09:00
|
|
|
|
using System.Collections.Specialized;
|
2024-10-31 10:46:24 +09:00
|
|
|
|
using Serilog;
|
2024-12-04 12:08:34 +09:00
|
|
|
|
using BitgetAPI.IndicatorConditionSetup;
|
2024-05-22 16:56:51 +09:00
|
|
|
|
|
|
|
|
|
|
namespace BitgetAPI.WebService
|
|
|
|
|
|
{
|
|
|
|
|
|
public class WebConnection
|
|
|
|
|
|
{
|
2024-07-10 11:46:59 +09:00
|
|
|
|
public Thread th_PingTimer { get; set; } = null;
|
2024-06-14 16:49:57 +09:00
|
|
|
|
|
|
|
|
|
|
// 웹소켓 스레드 시작/종료 플래그
|
2024-06-14 14:47:51 +09:00
|
|
|
|
public bool Is_th_webSocketThread { get; set; } = false;
|
|
|
|
|
|
public ClientWebSocket webSocket { get; set; } = null;
|
2024-07-10 11:46:59 +09:00
|
|
|
|
private object obj = new object();
|
|
|
|
|
|
public List<Dictionary<string, object>> webSocketDataList = new List<Dictionary<string, object>>();
|
2024-05-29 17:37:10 +09:00
|
|
|
|
|
2024-07-10 11:46:59 +09:00
|
|
|
|
CommonProperty commonProperty = CommonProperty.Instance;
|
|
|
|
|
|
|
|
|
|
|
|
public static object SendWebServer(CommonProperty.ExchangeWebReqType exchangeWebReqType, string url = "",
|
2024-05-28 16:56:19 +09:00
|
|
|
|
MarketCandleDataList marketCandleDataList = null, CommonProperty.MCandleTimeType interval = MCandleTimeType.M1,
|
2024-08-29 11:02:17 +09:00
|
|
|
|
string postData = "", string subUri = "", NameValueCollection headers = null)
|
2024-05-22 16:56:51 +09:00
|
|
|
|
{
|
|
|
|
|
|
object returnJsonData = null;
|
|
|
|
|
|
|
|
|
|
|
|
CommonProperty commonProperty = CommonProperty.Instance;
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
HttpWebRequest wReq = null;
|
|
|
|
|
|
|
|
|
|
|
|
// Post 방식인 경우만 사용
|
|
|
|
|
|
var rgbyData = Encoding.ASCII.GetBytes(postData);
|
|
|
|
|
|
|
|
|
|
|
|
// 웹 전송 타입 지정
|
|
|
|
|
|
var webConType = CommonProperty.WebConnectionType.GET;
|
|
|
|
|
|
|
2025-07-07 10:55:01 +09:00
|
|
|
|
if(postData.Length > 0) webConType = CommonProperty.WebConnectionType.POST;
|
2024-08-29 11:02:17 +09:00
|
|
|
|
|
2024-05-22 16:56:51 +09:00
|
|
|
|
// 1. WebRequest 객체 형성 및 HttpWebRequest 로 형변환
|
|
|
|
|
|
// 2. 거래소에 따른 헤더 파일 처리(POST 일 경우만 지정함)
|
|
|
|
|
|
|
2025-07-07 10:55:01 +09:00
|
|
|
|
if (string.IsNullOrEmpty(url))
|
2024-05-22 16:56:51 +09:00
|
|
|
|
{
|
2025-07-07 10:55:01 +09:00
|
|
|
|
switch (exchangeWebReqType)
|
|
|
|
|
|
{
|
|
|
|
|
|
#region Upbit
|
|
|
|
|
|
case CommonProperty.ExchangeWebReqType.UpbitMarket:
|
|
|
|
|
|
wReq = (HttpWebRequest)WebRequest.Create(new Uri(CommonProperty.UpbitURL_MarketInfo));
|
|
|
|
|
|
break;
|
|
|
|
|
|
#endregion
|
2024-05-22 16:56:51 +09:00
|
|
|
|
|
2025-07-07 10:55:01 +09:00
|
|
|
|
#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;
|
2024-05-22 16:56:51 +09:00
|
|
|
|
|
2025-07-07 10:55:01 +09:00
|
|
|
|
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;
|
2024-08-29 11:02:17 +09:00
|
|
|
|
#endregion
|
2025-07-07 10:55:01 +09:00
|
|
|
|
}
|
2024-05-22 16:56:51 +09:00
|
|
|
|
}
|
2025-07-07 10:55:01 +09:00
|
|
|
|
|
|
|
|
|
|
else wReq = (HttpWebRequest)WebRequest.Create(new Uri(url));
|
|
|
|
|
|
|
2024-05-22 16:56:51 +09:00
|
|
|
|
// 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";
|
2024-09-04 14:25:35 +09:00
|
|
|
|
//wReq.ContentLength = rgbyData.Length;
|
2024-05-22 16:56:51 +09:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-08-29 11:02:17 +09:00
|
|
|
|
if (headers != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
wReq.Headers.Add(headers);
|
|
|
|
|
|
wReq.ContentType = "application/json";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-05-22 16:56:51 +09:00
|
|
|
|
using (var wRes = (HttpWebResponse)wReq.GetResponse())
|
|
|
|
|
|
{
|
2025-07-07 10:55:01 +09:00
|
|
|
|
try
|
2024-05-22 16:56:51 +09:00
|
|
|
|
{
|
2025-07-07 10:55:01 +09:00
|
|
|
|
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<Dictionary<string, object>>(resResult);
|
|
|
|
|
|
var marketInfo = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(datalist["data"]?.ToString());
|
|
|
|
|
|
var data = marketInfo.FindAll(x => x["coin"].ToString().Contains("USDT"));
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case CommonProperty.ExchangeWebReqType.BitgetMarket_Future:
|
|
|
|
|
|
{
|
|
|
|
|
|
var datalist = JsonConvert.DeserializeObject<Dictionary<string, object>>(resResult);
|
|
|
|
|
|
var marketInfos = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(datalist["data"]?.ToString());
|
|
|
|
|
|
|
|
|
|
|
|
commonProperty.marketInfoList = new List<MarketInfo>();
|
2024-05-22 16:56:51 +09:00
|
|
|
|
|
2025-07-07 10:55:01 +09:00
|
|
|
|
foreach (var item in marketInfos)
|
|
|
|
|
|
{
|
|
|
|
|
|
MarketInfo marketInfo = new MarketInfo();
|
|
|
|
|
|
marketInfo.MarketName = item["symbol"].ToString();
|
|
|
|
|
|
marketInfo.ExchangePlace = Enum.GetName(typeof(CommonProperty.ExchangePlace), commonProperty.selectedChangePlace);
|
|
|
|
|
|
marketInfo.lastPr = Convert.ToDouble(item["lastPr"]);
|
|
|
|
|
|
marketInfo.change24h = Convert.ToDouble(item["change24h"]);
|
|
|
|
|
|
marketInfo.baseVolume = Convert.ToDouble(item["baseVolume"]);
|
|
|
|
|
|
marketInfo.quoteVolume = Convert.ToDouble(item["quoteVolume"]);
|
|
|
|
|
|
marketInfo.high24h = Convert.ToDouble(item["high24h"]);
|
|
|
|
|
|
marketInfo.low24h = Convert.ToDouble(item["low24h"]);
|
|
|
|
|
|
marketInfo.open24h = Convert.ToDouble(item["open24h"]);
|
|
|
|
|
|
commonProperty.marketInfoList.Add(marketInfo);
|
|
|
|
|
|
}
|
2024-05-22 16:56:51 +09:00
|
|
|
|
|
2025-07-07 10:55:01 +09:00
|
|
|
|
return commonProperty.marketInfoList;
|
|
|
|
|
|
}
|
|
|
|
|
|
case CommonProperty.ExchangeWebReqType.BitgetCandleStick_Coin:
|
2024-05-22 16:56:51 +09:00
|
|
|
|
{
|
2025-07-07 10:55:01 +09:00
|
|
|
|
|
2024-05-22 16:56:51 +09:00
|
|
|
|
}
|
2025-07-07 10:55:01 +09:00
|
|
|
|
break;
|
|
|
|
|
|
case CommonProperty.ExchangeWebReqType.BitgetCandleStick_Future:
|
|
|
|
|
|
{
|
|
|
|
|
|
var datalist = JsonConvert.DeserializeObject<Dictionary<string, object>>(resResult);
|
|
|
|
|
|
var datas = JsonConvert.DeserializeObject<List<List<object>>>(datalist["data"]?.ToString());
|
2024-05-22 16:56:51 +09:00
|
|
|
|
|
2025-07-07 10:55:01 +09:00
|
|
|
|
if (marketCandleDataList == null) return null;
|
2024-05-22 16:56:51 +09:00
|
|
|
|
|
2025-07-07 10:55:01 +09:00
|
|
|
|
var candleDataList = marketCandleDataList.candleDataList[interval];
|
2024-05-22 16:56:51 +09:00
|
|
|
|
|
2025-07-07 10:55:01 +09:00
|
|
|
|
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]);
|
|
|
|
|
|
|
|
|
|
|
|
// 같은 시간이 존재하면 업데이트 : 1개밖에 없음
|
|
|
|
|
|
// 마지막 시간 데이터는 불완전 > 웹소켓 데이터와 합체
|
|
|
|
|
|
if (item == datas.Last())
|
|
|
|
|
|
{
|
|
|
|
|
|
var timespan_add = new System.TimeSpan(0, 0, 0);
|
2024-05-28 16:56:19 +09:00
|
|
|
|
|
2025-07-07 10:55:01 +09:00
|
|
|
|
switch (interval)
|
|
|
|
|
|
{
|
|
|
|
|
|
case CommonProperty.MCandleTimeType.M1:
|
|
|
|
|
|
// 같은 분이면 무조건 업데이트
|
|
|
|
|
|
timespan_add = new System.TimeSpan(0, 1, 0);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case CommonProperty.MCandleTimeType.M3:
|
|
|
|
|
|
// 같은 분이면 무조건 업데이트
|
|
|
|
|
|
timespan_add = new System.TimeSpan(0, 3, 0);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case CommonProperty.MCandleTimeType.M5:
|
|
|
|
|
|
timespan_add = new System.TimeSpan(0, 5, 0);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case CommonProperty.MCandleTimeType.M15:
|
|
|
|
|
|
timespan_add = new System.TimeSpan(0, 15, 0);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case CommonProperty.MCandleTimeType.M30:
|
|
|
|
|
|
timespan_add = new System.TimeSpan(0, 30, 0);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case CommonProperty.MCandleTimeType.H1:
|
|
|
|
|
|
timespan_add = new System.TimeSpan(1, 0, 0);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case CommonProperty.MCandleTimeType.H2:
|
|
|
|
|
|
timespan_add = new System.TimeSpan(2, 0, 0);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case CommonProperty.MCandleTimeType.H3:
|
|
|
|
|
|
timespan_add = new System.TimeSpan(3, 0, 0);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case CommonProperty.MCandleTimeType.H4:
|
|
|
|
|
|
timespan_add = new System.TimeSpan(4, 0, 0);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case CommonProperty.MCandleTimeType.H6:
|
|
|
|
|
|
timespan_add = new System.TimeSpan(6, 0, 0);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case CommonProperty.MCandleTimeType.H12:
|
|
|
|
|
|
timespan_add = new System.TimeSpan(12, 0, 0);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2024-05-22 16:56:51 +09:00
|
|
|
|
|
2025-07-07 10:55:01 +09:00
|
|
|
|
var sameCandleData_WebService = candleDataList.Find(i => candleData.Argument <= i.Argument &&
|
|
|
|
|
|
i.Argument < (candleData.Argument + timespan_add) && i.WebSocketUpdate == true);
|
|
|
|
|
|
|
|
|
|
|
|
if (sameCandleData_WebService != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 종가 => 웹소켓 데이터 사용 (웹 서비스 호출 데이터 중 마지막 데이터는 캔들이 완성되지 않음)
|
|
|
|
|
|
// 시가 => 웹 서비스 데이터 사용
|
|
|
|
|
|
sameCandleData_WebService.Open = candleData.Open;
|
|
|
|
|
|
// 저가, 고가 => 비교해서 사용
|
|
|
|
|
|
sameCandleData_WebService.Low = Math.Min(sameCandleData_WebService.Low, candleData.Low);
|
|
|
|
|
|
sameCandleData_WebService.High = Math.Max(sameCandleData_WebService.High, candleData.High);
|
|
|
|
|
|
|
|
|
|
|
|
sameCandleData_WebService.WebServiceUpdate = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
candleDataList.Add(candleData);
|
|
|
|
|
|
candleData.WebServiceUpdate = true;
|
|
|
|
|
|
}
|
2024-06-10 23:22:01 +09:00
|
|
|
|
|
|
|
|
|
|
}
|
2025-07-07 10:55:01 +09:00
|
|
|
|
/*
|
|
|
|
|
|
//var sameCandleData_WebService = candleDataList.Find(i => i.Argument.Minute == candleData.Argument.Minute &&
|
|
|
|
|
|
//i.Argument.Hour == candleData.Argument.Hour && i.WebSocketUpdate == true);
|
2024-06-10 23:22:01 +09:00
|
|
|
|
|
|
|
|
|
|
|
2025-07-07 10:55:01 +09:00
|
|
|
|
// 기존 웹소켓으로 부터 받은 데이터에 수정 등록
|
2024-07-10 11:46:59 +09:00
|
|
|
|
if (sameCandleData_WebService != null)
|
2024-06-10 23:22:01 +09:00
|
|
|
|
{
|
2025-07-07 10:55:01 +09:00
|
|
|
|
|
|
|
|
|
|
}*/
|
|
|
|
|
|
// 웹 서비스로 받은 데이터를 새로 추가
|
2024-06-10 23:22:01 +09:00
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
candleDataList.Add(candleData);
|
|
|
|
|
|
candleData.WebServiceUpdate = true;
|
|
|
|
|
|
}
|
2024-07-10 11:46:59 +09:00
|
|
|
|
|
2024-06-10 23:22:01 +09:00
|
|
|
|
}
|
2024-05-29 17:37:10 +09:00
|
|
|
|
}
|
2025-07-07 10:55:01 +09:00
|
|
|
|
break;
|
|
|
|
|
|
case ExchangeWebReqType.BitgetAccountList_Future:
|
|
|
|
|
|
{
|
|
|
|
|
|
var datalist = JsonConvert.DeserializeObject<Dictionary<string, object>>(resResult);
|
|
|
|
|
|
return JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(datalist["data"]?.ToString());
|
|
|
|
|
|
}
|
|
|
|
|
|
case ExchangeWebReqType.BitgetOrder_Future:
|
|
|
|
|
|
{
|
|
|
|
|
|
return JsonConvert.DeserializeObject<Dictionary<string, object>>(resResult);
|
|
|
|
|
|
}
|
|
|
|
|
|
case ExchangeWebReqType.BitgetCancelOrder_Future:
|
|
|
|
|
|
{
|
|
|
|
|
|
return JsonConvert.DeserializeObject<Dictionary<string, object>>(resResult);
|
|
|
|
|
|
}
|
|
|
|
|
|
case ExchangeWebReqType.BitgetChangeLeverage_Future:
|
|
|
|
|
|
{
|
|
|
|
|
|
return JsonConvert.DeserializeObject<Dictionary<string, object>>(resResult);
|
|
|
|
|
|
}
|
|
|
|
|
|
case ExchangeWebReqType.BitgetChangeMarginMode_Future:
|
|
|
|
|
|
{
|
|
|
|
|
|
return JsonConvert.DeserializeObject<Dictionary<string, object>>(resResult);
|
|
|
|
|
|
}
|
|
|
|
|
|
case ExchangeWebReqType.BitgetChangePositionMode_Future:
|
|
|
|
|
|
{
|
|
|
|
|
|
return JsonConvert.DeserializeObject<Dictionary<string, object>>(resResult);
|
|
|
|
|
|
}
|
|
|
|
|
|
case ExchangeWebReqType.BitgetOrderDetail_Future:
|
|
|
|
|
|
{
|
|
|
|
|
|
return JsonConvert.DeserializeObject<Dictionary<string, object>>(resResult);
|
|
|
|
|
|
}
|
|
|
|
|
|
case ExchangeWebReqType.BitgetGetTimeStamp:
|
|
|
|
|
|
{
|
|
|
|
|
|
return JsonConvert.DeserializeObject<Dictionary<string, object>>(resResult);
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
}
|
|
|
|
|
|
}catch(Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
return returnJsonData;
|
2024-05-22 16:56:51 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (WebException webEx)
|
|
|
|
|
|
{
|
|
|
|
|
|
using (var Response = (HttpWebResponse)webEx.Response)
|
|
|
|
|
|
{
|
2024-07-25 12:26:45 +09:00
|
|
|
|
if (Response != null)
|
2024-05-22 16:56:51 +09:00
|
|
|
|
{
|
|
|
|
|
|
|
2024-07-25 12:26:45 +09:00
|
|
|
|
var nCode = Response.StatusCode;
|
|
|
|
|
|
|
|
|
|
|
|
using (var reader = new StreamReader(Response.GetResponseStream()))
|
|
|
|
|
|
{
|
|
|
|
|
|
var sRespBodyData = reader.ReadToEnd();
|
2024-10-31 10:46:24 +09:00
|
|
|
|
Log.Error(webEx, sRespBodyData);
|
2024-07-25 12:26:45 +09:00
|
|
|
|
//return (JObject.Parse(sRespBodyData));
|
|
|
|
|
|
}
|
2024-05-22 16:56:51 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return returnJsonData;
|
|
|
|
|
|
}
|
2024-05-23 16:32:30 +09:00
|
|
|
|
|
2024-06-08 14:45:14 +09:00
|
|
|
|
public async void BitGetWebSocektStart(CommonProperty.BitgetWebSocketType bitgetWebSocketType, Dictionary<string, object> dic)
|
2024-05-23 16:32:30 +09:00
|
|
|
|
{
|
|
|
|
|
|
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
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
2024-07-10 11:46:59 +09:00
|
|
|
|
|
2024-05-27 18:51:56 +09:00
|
|
|
|
|
2024-06-14 14:47:51 +09:00
|
|
|
|
webSocket = new ClientWebSocket();
|
2024-05-23 16:32:30 +09:00
|
|
|
|
|
|
|
|
|
|
string WebSocketUrl = "wss://ws.bitget.com/v2/ws/public";
|
|
|
|
|
|
string message = "";
|
|
|
|
|
|
var tempStrData = "";
|
2024-05-29 17:37:10 +09:00
|
|
|
|
|
2024-05-23 16:32:30 +09:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
await webSocket.ConnectAsync(new Uri(WebSocketUrl), CancellationToken.None);
|
|
|
|
|
|
// 연결이 성공적으로 이루어지면 처리할 코드 작성
|
|
|
|
|
|
Console.WriteLine("WebSocket 연결 성공");
|
|
|
|
|
|
|
|
|
|
|
|
//var jsonDataText = "{\"op\":\"subscribe\",\"args\":[{\"instType\":\"SPOT\",\"channel\":\"ticker\",\"instId\":\"ETHUSDT\"}, {\"instType\":\"SPOT\",\"channel\":\"ticker\",\"instId\":\"BTCUSDT\"}]}";
|
|
|
|
|
|
|
|
|
|
|
|
var jsonData = JsonConvert.SerializeObject(dic);
|
|
|
|
|
|
|
2024-05-27 18:51:56 +09:00
|
|
|
|
// Ping 유지용 (25초)
|
2024-05-29 17:37:10 +09:00
|
|
|
|
th_PingTimer = new Thread(() => ContinuePing(webSocket));
|
|
|
|
|
|
th_PingTimer.Start();
|
2024-05-27 18:51:56 +09:00
|
|
|
|
|
|
|
|
|
|
await SendMessage(webSocket, jsonData);
|
2024-05-23 16:32:30 +09:00
|
|
|
|
|
|
|
|
|
|
// 데이터 수신을 위한 반복문 시작
|
|
|
|
|
|
while (webSocket.State == WebSocketState.Open)
|
|
|
|
|
|
{
|
2024-06-14 14:47:51 +09:00
|
|
|
|
|
2024-05-23 16:32:30 +09:00
|
|
|
|
//Thread.Sleep(100);
|
|
|
|
|
|
|
2024-07-11 14:36:08 +09:00
|
|
|
|
byte[] buffer = new byte[1024];
|
2024-05-23 16:32:30 +09:00
|
|
|
|
WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
|
|
|
|
|
message = "";
|
|
|
|
|
|
// 수신한 데이터 처리
|
|
|
|
|
|
message = System.Text.Encoding.UTF8.GetString(buffer, 0, result.Count);
|
|
|
|
|
|
|
2024-07-11 14:36:08 +09:00
|
|
|
|
if (message.Contains("pong"))
|
|
|
|
|
|
{
|
|
|
|
|
|
string[] splitStr = { "pong" };
|
|
|
|
|
|
var temp = message.Split(splitStr, StringSplitOptions.RemoveEmptyEntries);
|
|
|
|
|
|
message = "";
|
|
|
|
|
|
foreach (var item in temp)
|
|
|
|
|
|
{
|
|
|
|
|
|
message += item;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-07-15 12:49:00 +09:00
|
|
|
|
if (tempStrData == "")
|
|
|
|
|
|
{
|
2024-07-11 14:16:48 +09:00
|
|
|
|
if (!ValidateJSON(message))
|
|
|
|
|
|
{
|
|
|
|
|
|
tempStrData = message;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
2024-05-23 16:32:30 +09:00
|
|
|
|
{
|
|
|
|
|
|
tempStrData += message;
|
2024-07-11 14:16:48 +09:00
|
|
|
|
if (!ValidateJSON(tempStrData))
|
2024-05-23 16:32:30 +09:00
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
message = tempStrData;
|
2024-07-11 14:36:08 +09:00
|
|
|
|
tempStrData = "";
|
2024-05-23 16:32:30 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-07-11 14:16:48 +09:00
|
|
|
|
|
|
|
|
|
|
if (message.Contains("{\"action"))
|
2024-07-10 11:46:59 +09:00
|
|
|
|
{
|
2024-07-11 14:16:48 +09:00
|
|
|
|
string[] separatingStrings = { "{\"action" };
|
|
|
|
|
|
|
|
|
|
|
|
var splitData = message.Split(separatingStrings, System.StringSplitOptions.RemoveEmptyEntries);
|
2024-07-15 12:49:00 +09:00
|
|
|
|
|
2024-07-11 14:16:48 +09:00
|
|
|
|
foreach (var item in splitData)
|
|
|
|
|
|
{
|
|
|
|
|
|
var temp = "{\"action" + item;
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var datalist = JsonConvert.DeserializeObject<Dictionary<string, object>>(temp);
|
2024-07-15 12:49:00 +09:00
|
|
|
|
if (datalist["action"].ToString() == "update")
|
2024-07-11 14:16:48 +09:00
|
|
|
|
{
|
2024-07-15 12:49:00 +09:00
|
|
|
|
lock (obj)
|
|
|
|
|
|
{
|
|
|
|
|
|
webSocketDataList.Add(datalist);
|
|
|
|
|
|
}
|
2024-07-11 14:16:48 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (JsonReaderException)
|
|
|
|
|
|
{
|
2024-07-15 12:49:00 +09:00
|
|
|
|
|
2024-07-11 14:16:48 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-07-15 12:49:00 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-07-10 11:46:59 +09:00
|
|
|
|
|
|
|
|
|
|
#region 접어 둘거
|
|
|
|
|
|
//if (datalist.ContainsKey("data"))
|
|
|
|
|
|
//{
|
|
|
|
|
|
// switch (bitgetWebSocketType)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// case CommonProperty.BitgetWebSocketType.현황정보_전체종목:
|
|
|
|
|
|
// {
|
|
|
|
|
|
// var candleInfo = JsonConvert.DeserializeObject<List<WebSocketTickerInfo>>(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 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_Edit = candleDataList.ToList();
|
|
|
|
|
|
|
|
|
|
|
|
// // 마지막 시간 데이터 가져오기
|
|
|
|
|
|
// var lastCandleData = lastCandleData_Edit.Find(j => j.Argument == lastCandleData_Edit.Max(i => i.Argument));
|
|
|
|
|
|
// if (lastCandleData == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
// // 업데이트 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;
|
|
|
|
|
|
|
|
|
|
|
|
// lastCandleData.WebSocketUpdate = true;
|
|
|
|
|
|
// }
|
|
|
|
|
|
// // 없는 경우 추가
|
|
|
|
|
|
// else
|
|
|
|
|
|
// {
|
|
|
|
|
|
// if (candleData.Open == 0) { }
|
|
|
|
|
|
// // 1분 이상 Ticker가 없는 겨우는 Open 가만 가격이 등록됨
|
|
|
|
|
|
// candleData.Open = candleData.Close;
|
|
|
|
|
|
|
|
|
|
|
|
// candleData.WebSocketUpdate = true;
|
|
|
|
|
|
|
|
|
|
|
|
// // 새 데이터 등록
|
|
|
|
|
|
// candleDataList.Add(candleData);
|
|
|
|
|
|
|
|
|
|
|
|
// // 기존 데이터 삭제
|
|
|
|
|
|
// 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<Dictionary<string, object>>(datalist["arg"]?.ToString());
|
|
|
|
|
|
|
|
|
|
|
|
// var candleInfos = JsonConvert.DeserializeObject<List<List<object>>>(datalist["data"]?.ToString());
|
|
|
|
|
|
// var candleInfo = candleInfos[0];
|
|
|
|
|
|
|
|
|
|
|
|
// DateTime dt = new DateTime(1970, 01, 01);
|
|
|
|
|
|
// var candleData = new CandleData(
|
|
|
|
|
|
// dt.AddMilliseconds(Convert.ToDouble(candleInfo[0])).ToLocalTime(),
|
|
|
|
|
|
// Convert.ToDouble(candleInfo[1]),
|
|
|
|
|
|
// Convert.ToDouble(candleInfo[2]),
|
|
|
|
|
|
// Convert.ToDouble(candleInfo[3]),
|
|
|
|
|
|
// Convert.ToDouble(candleInfo[4]),
|
|
|
|
|
|
// Convert.ToDouble(candleInfo[5]),
|
|
|
|
|
|
// Convert.ToDouble(candleInfo[6]),
|
|
|
|
|
|
// Convert.ToDouble(candleInfo[7])
|
|
|
|
|
|
// );
|
|
|
|
|
|
|
|
|
|
|
|
// // Websocket 캔들 정보 구분 하기 (1분, 1시간 등)
|
|
|
|
|
|
// CommonProperty.MCandleTimeType mCandleTimeType = CommonProperty.MCandleTimeType.H1;
|
|
|
|
|
|
// foreach (var interval in Enum.GetValues(typeof(CommonProperty.MCandleTimeType)))
|
|
|
|
|
|
// {
|
|
|
|
|
|
// // Description
|
|
|
|
|
|
// var description = Utils.Convertor.GetEnumDescription((Enum)interval);
|
|
|
|
|
|
// if (argList["channel"].ToString().Contains(description))
|
|
|
|
|
|
// mCandleTimeType = (CommonProperty.MCandleTimeType)interval;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// // 캔들 리스트에서 해당 데이터 찾기
|
|
|
|
|
|
// var searchIndex = commonProperty.candleDataLists.IndexOf(i => i.ConGoodsData.MarketName == argList["instId"].ToString());
|
|
|
|
|
|
|
|
|
|
|
|
// var candleDataList = commonProperty.candleDataLists[searchIndex].candleDataList[mCandleTimeType];
|
|
|
|
|
|
|
|
|
|
|
|
// // 마지막 데이터 (최신데이터) 가져오기
|
|
|
|
|
|
// CandleData lastCandleData = null;
|
|
|
|
|
|
|
|
|
|
|
|
// if (candleDataList.Count == 0)
|
|
|
|
|
|
// candleDataList.Add(candleData);
|
|
|
|
|
|
// else
|
|
|
|
|
|
// {
|
|
|
|
|
|
// lastCandleData = commonProperty.candleDataLists[searchIndex].candleDataList[mCandleTimeType].Last();
|
|
|
|
|
|
|
|
|
|
|
|
// // 최신데이터와 비교하여 교체/등록하기
|
|
|
|
|
|
|
|
|
|
|
|
// // 업데이트 or 추가
|
|
|
|
|
|
// bool updateFlag = false;
|
|
|
|
|
|
|
|
|
|
|
|
// switch (mCandleTimeType)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.M1:
|
|
|
|
|
|
// if (lastCandleData.Argument.Minute == candleData.Argument.Minute)
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.M3:
|
|
|
|
|
|
// if (candleData.Argument.Minute % 3 != 0 || (candleData.Argument.Minute % 3 == 0 && candleData.Argument.Minute == lastCandleData.Argument.Minute))
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.M5:
|
|
|
|
|
|
// if (candleData.Argument.Minute % 5 != 0 || (candleData.Argument.Minute % 5 == 0 && candleData.Argument.Minute == lastCandleData.Argument.Minute))
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.M15:
|
|
|
|
|
|
// if (candleData.Argument.Minute % 15 != 0 || (candleData.Argument.Minute % 15 == 0 && candleData.Argument.Minute == lastCandleData.Argument.Minute))
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.M30:
|
|
|
|
|
|
// if (candleData.Argument.Minute % 30 != 0 || (candleData.Argument.Minute % 30 == 0 && candleData.Argument.Minute == lastCandleData.Argument.Minute))
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.H1:
|
|
|
|
|
|
// if (candleData.Argument.Hour == candleData.Argument.Hour)
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.H4:
|
|
|
|
|
|
// if (candleData.Argument.Hour % 4 != 0 || (candleData.Argument.Hour % 4 == 0 && candleData.Argument.Hour == lastCandleData.Argument.Hour))
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.H6:
|
|
|
|
|
|
// if (candleData.Argument.Hour % 6 != 0 || (candleData.Argument.Hour % 6 == 0 && candleData.Argument.Hour == lastCandleData.Argument.Hour))
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.H12:
|
|
|
|
|
|
// if (candleData.Argument.Hour % 12 != 0 || (candleData.Argument.Hour % 12 == 0 && candleData.Argument.Hour == lastCandleData.Argument.Hour))
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// // 이미 등록된 시간 캔들이 있는 경우 변경
|
|
|
|
|
|
// if (updateFlag)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// lastCandleData = candleData;
|
|
|
|
|
|
// }
|
|
|
|
|
|
// // 없는 경우 추가
|
|
|
|
|
|
// else
|
|
|
|
|
|
// {
|
|
|
|
|
|
// lastCandleData.Close = candleData.Open;
|
|
|
|
|
|
// // 새 데이터 등록
|
|
|
|
|
|
// candleDataList.Add(candleData);
|
|
|
|
|
|
// // 기존 데이터 삭제
|
|
|
|
|
|
// if (candleDataList.Count > 250)
|
|
|
|
|
|
// {
|
|
|
|
|
|
|
|
|
|
|
|
// var minData = candleDataList.Min(t => t.Argument);
|
|
|
|
|
|
// var minCandle = candleDataList.FirstOrDefault(t => t.Argument == minData);
|
|
|
|
|
|
// if (minCandle != null)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// candleDataList.Remove(minCandle);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// #endregion
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
//}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine("WebSocket 연결 중 오류 발생: " + ex.Message);
|
|
|
|
|
|
}
|
|
|
|
|
|
finally
|
|
|
|
|
|
{
|
|
|
|
|
|
closeWebSocket();
|
|
|
|
|
|
|
|
|
|
|
|
// 웹소켓 재귀
|
|
|
|
|
|
if (Is_th_webSocketThread)
|
|
|
|
|
|
{
|
|
|
|
|
|
BitGetWebSocektStart(bitgetWebSocketType, dic);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 웹소켓 종료
|
|
|
|
|
|
public async void closeWebSocket()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (webSocket != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (webSocket.State == WebSocketState.Open)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (th_PingTimer != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
th_PingTimer.Abort();
|
|
|
|
|
|
th_PingTimer = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
await webSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "WebSocket 연결 종료", CancellationToken.None);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
webSocket.Dispose();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Ping 테스트 (25초), 30초에 한번 응답 확인 필요
|
|
|
|
|
|
public static async void ContinuePing(ClientWebSocket webSocket)
|
|
|
|
|
|
{
|
|
|
|
|
|
while (true)
|
|
|
|
|
|
{
|
|
|
|
|
|
Thread.Sleep(25000);
|
|
|
|
|
|
await SendMessage(webSocket, "ping");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static async Task SendMessage(ClientWebSocket webSocket, string message)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
byte[] buffer = Encoding.UTF8.GetBytes(message);
|
|
|
|
|
|
await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
|
|
|
|
|
|
Console.WriteLine("메시지 전송: " + message);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine(ex.Message);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static bool ValidateJSON(string s)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2024-07-11 14:16:48 +09:00
|
|
|
|
if (s.Contains("{\"action"))
|
|
|
|
|
|
{
|
|
|
|
|
|
string[] separatingStrings = { "{\"action" };
|
|
|
|
|
|
|
|
|
|
|
|
var splitData = s.Split(separatingStrings, System.StringSplitOptions.RemoveEmptyEntries);
|
|
|
|
|
|
|
|
|
|
|
|
bool flag = true;
|
|
|
|
|
|
foreach (var item in splitData)
|
|
|
|
|
|
{
|
|
|
|
|
|
var temp = "{\"action" + item;
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
JToken.Parse(temp);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (JsonReaderException)
|
|
|
|
|
|
{
|
|
|
|
|
|
flag = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return flag;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
JToken.Parse(s);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-07-15 12:49:00 +09:00
|
|
|
|
|
2024-07-10 11:46:59 +09:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (JsonReaderException)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-07-12 12:57:46 +09:00
|
|
|
|
public void CalculateDataList(BitgetWebSocketType bitgetWebSocketType, List<object> intervalList)
|
2024-07-10 11:46:59 +09:00
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var cloneList = new List<Dictionary<string, object>>();
|
|
|
|
|
|
lock (obj)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
2025-07-07 10:55:01 +09:00
|
|
|
|
{
|
2024-07-10 11:46:59 +09:00
|
|
|
|
foreach (var item in webSocketDataList)
|
|
|
|
|
|
{
|
|
|
|
|
|
var dic = new Dictionary<string, object>();
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var key in item.Keys)
|
|
|
|
|
|
{
|
|
|
|
|
|
dic[key] = item[key];
|
|
|
|
|
|
}
|
2024-05-23 16:32:30 +09:00
|
|
|
|
|
2024-07-10 11:46:59 +09:00
|
|
|
|
cloneList.Add(dic);
|
|
|
|
|
|
}
|
|
|
|
|
|
webSocketDataList.Clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-05-28 16:56:19 +09:00
|
|
|
|
|
2024-07-11 11:27:14 +09:00
|
|
|
|
switch (bitgetWebSocketType)
|
|
|
|
|
|
{
|
|
|
|
|
|
case CommonProperty.BitgetWebSocketType.현황정보_전체종목:
|
|
|
|
|
|
{
|
2024-07-15 12:49:00 +09:00
|
|
|
|
var dataList = cloneList.Where(t => t.ContainsKey("data")).Select(t => t["data"]);
|
|
|
|
|
|
var list = JsonConvert.DeserializeObject<List<List<WebSocketTickerInfo>>>(JsonConvert.SerializeObject(dataList));
|
|
|
|
|
|
|
|
|
|
|
|
var calList = new List<WebSocketTickerInfo>();
|
|
|
|
|
|
foreach (var item in list)
|
|
|
|
|
|
{
|
|
|
|
|
|
calList.Add(item[0]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var stringList = list.Select(t => t[0].instId).Distinct().ToList();
|
|
|
|
|
|
list = list.OrderBy(t => t[0].ts).ToList();
|
|
|
|
|
|
|
2024-07-12 12:57:46 +09:00
|
|
|
|
var minList = new Dictionary<string, List<CandleData>>();
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var item in stringList)
|
2024-07-11 11:27:14 +09:00
|
|
|
|
{
|
2024-07-12 17:25:58 +09:00
|
|
|
|
var temp = calList.Where(t => item == t.instId);
|
2024-07-12 12:57:46 +09:00
|
|
|
|
if (temp.Count() > 0)
|
2024-05-27 18:51:56 +09:00
|
|
|
|
{
|
2024-07-12 12:57:46 +09:00
|
|
|
|
minList.Add(item, new List<CandleData>());
|
|
|
|
|
|
foreach (var t in temp)
|
|
|
|
|
|
{
|
2024-07-12 17:25:58 +09:00
|
|
|
|
var tickerList = t;
|
2024-07-12 12:57:46 +09:00
|
|
|
|
DateTime dt = new DateTime(1970, 01, 01);
|
|
|
|
|
|
tickerList.reciveTime = dt.AddMilliseconds(Convert.ToDouble(tickerList.ts)).ToLocalTime();
|
|
|
|
|
|
}
|
2024-05-27 18:51:56 +09:00
|
|
|
|
|
2024-07-15 12:49:00 +09:00
|
|
|
|
var timeList = temp.Select(t => t.reciveTime.Minute).OrderBy(t => t).ToList();
|
2024-07-12 17:25:58 +09:00
|
|
|
|
|
2024-07-12 12:57:46 +09:00
|
|
|
|
foreach (var min in timeList)
|
|
|
|
|
|
{
|
2024-07-15 12:49:00 +09:00
|
|
|
|
var minDataList = temp.Where(t => t.reciveTime.Minute == min).OrderBy(t => t.reciveTime).ToList();
|
2024-07-12 17:25:58 +09:00
|
|
|
|
|
2024-07-12 12:57:46 +09:00
|
|
|
|
var candleData = new CandleData();
|
2024-07-15 12:49:00 +09:00
|
|
|
|
var dt = minDataList[minDataList.Count - 1].reciveTime;
|
2024-07-10 11:46:59 +09:00
|
|
|
|
|
2024-07-12 17:25:58 +09:00
|
|
|
|
candleData.Argument = dt;
|
|
|
|
|
|
candleData.Close = minDataList.Last().lastPr;
|
|
|
|
|
|
candleData.Open = minDataList.First().lastPr;
|
|
|
|
|
|
candleData.Low = minDataList.Min(t => t.lastPr);
|
|
|
|
|
|
candleData.High = minDataList.Max(t => t.lastPr);
|
2024-05-27 18:51:56 +09:00
|
|
|
|
|
2024-07-12 12:57:46 +09:00
|
|
|
|
minList[item].Add(candleData);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-05-27 18:51:56 +09:00
|
|
|
|
|
2024-07-12 12:57:46 +09:00
|
|
|
|
//minList = new Dictionary<string, List<CandleData>>();
|
|
|
|
|
|
|
|
|
|
|
|
//List<WebSocketTickerInfo> tempList = new List<WebSocketTickerInfo>();
|
|
|
|
|
|
//foreach (var datalist in list)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// var tickerList = datalist[0];
|
|
|
|
|
|
// DateTime dt = new DateTime(1970, 01, 01);
|
|
|
|
|
|
// tickerList.reciveTime = dt.AddMilliseconds(Convert.ToDouble(tickerList.ts)).ToLocalTime();
|
|
|
|
|
|
// tempList.Add(tickerList);
|
|
|
|
|
|
|
|
|
|
|
|
// if (minList.ContainsKey(tickerList.instId))
|
|
|
|
|
|
// {
|
|
|
|
|
|
// if (!minList[tickerList.instId].Any(m => m.Argument.Minute == tickerList.reciveTime.Minute))
|
|
|
|
|
|
// {
|
|
|
|
|
|
// var candleData = new CandleData();
|
|
|
|
|
|
// candleData.Argument = tickerList.reciveTime;
|
|
|
|
|
|
// candleData.Close = tickerList.lastPr;
|
|
|
|
|
|
// candleData.Open = tickerList.lastPr;
|
|
|
|
|
|
// candleData.Low = tickerList.lastPr;
|
|
|
|
|
|
// candleData.High = tickerList.lastPr;
|
|
|
|
|
|
|
|
|
|
|
|
// minList[tickerList.instId].Add(candleData);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// else
|
|
|
|
|
|
// {
|
|
|
|
|
|
// var tempItem = minList[tickerList.instId].First(t => t.Argument.Minute == tickerList.reciveTime.Minute);
|
|
|
|
|
|
// tempItem.Argument = tickerList.reciveTime;
|
|
|
|
|
|
// tempItem.Close = tickerList.lastPr;
|
|
|
|
|
|
// tempItem.Low = tempItem.Low > tickerList.lastPr ? tickerList.lastPr : tempItem.Low;
|
|
|
|
|
|
// tempItem.High = tempItem.High < tickerList.lastPr ? tickerList.lastPr : tempItem.High;
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
// else
|
|
|
|
|
|
// {
|
|
|
|
|
|
// minList.Add(tickerList.instId, new List<CandleData>());
|
|
|
|
|
|
// var candleData = new CandleData();
|
|
|
|
|
|
// candleData.Argument = tickerList.reciveTime;
|
|
|
|
|
|
// candleData.Close = tickerList.lastPr;
|
|
|
|
|
|
// candleData.Open = tickerList.lastPr;
|
|
|
|
|
|
// candleData.Low = tickerList.lastPr;
|
|
|
|
|
|
// candleData.High = tickerList.lastPr;
|
|
|
|
|
|
|
|
|
|
|
|
// minList[tickerList.instId].Add(candleData);
|
|
|
|
|
|
// }
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var item in minList.Keys)
|
|
|
|
|
|
{
|
|
|
|
|
|
var temp = minList[item];
|
2024-05-27 18:51:56 +09:00
|
|
|
|
|
2024-07-12 12:57:46 +09:00
|
|
|
|
foreach (var candleData in temp)
|
2024-07-15 12:49:00 +09:00
|
|
|
|
{
|
2024-05-27 18:51:56 +09:00
|
|
|
|
|
2024-07-12 12:57:46 +09:00
|
|
|
|
// 캔들 리스트에서 해당 데이터 찾기
|
|
|
|
|
|
var searchIndex_c = commonProperty.candleDataLists.IndexOf(i => i.ConGoodsData.MarketName == item);
|
2024-05-27 18:51:56 +09:00
|
|
|
|
|
2024-07-12 12:57:46 +09:00
|
|
|
|
// 캔들 리스트에 업데이트 (전체 시간별)
|
|
|
|
|
|
foreach (CommonProperty.MCandleTimeType interval in Enum.GetValues(typeof(CommonProperty.MCandleTimeType)))
|
|
|
|
|
|
{
|
|
|
|
|
|
var strInterval = Utils.Convertor.GetEnumDescription((Enum)interval);
|
|
|
|
|
|
if (!intervalList.Contains(strInterval)) continue;
|
2024-05-27 18:51:56 +09:00
|
|
|
|
|
2024-07-15 12:49:00 +09:00
|
|
|
|
var candleDataList = commonProperty.candleDataLists[searchIndex_c].candleDataList[interval];
|
2024-07-12 12:57:46 +09:00
|
|
|
|
|
|
|
|
|
|
// 캔들 리스트가 없으면 추가
|
|
|
|
|
|
if (candleDataList.Count == 0)
|
2024-07-15 12:49:00 +09:00
|
|
|
|
{
|
|
|
|
|
|
|
2024-07-12 12:57:46 +09:00
|
|
|
|
candleDataList.Add(candleData);
|
2024-07-15 12:49:00 +09:00
|
|
|
|
}
|
2024-05-27 18:51:56 +09:00
|
|
|
|
else
|
|
|
|
|
|
{
|
2024-07-12 17:25:58 +09:00
|
|
|
|
var lastCandleData_Edit = candleDataList;
|
2024-07-11 11:27:14 +09:00
|
|
|
|
|
2024-07-12 12:57:46 +09:00
|
|
|
|
// 마지막 시간 데이터 가져오기
|
|
|
|
|
|
var lastCandleData = lastCandleData_Edit.Find(j => j.Argument == lastCandleData_Edit.Max(i => i.Argument));
|
2024-07-12 17:25:58 +09:00
|
|
|
|
if (lastCandleData == null || lastCandleData.Argument > candleData.Argument)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (lastCandleData != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var beforeList = candleDataList.OrderByDescending(t => t.Argument).ToList();
|
|
|
|
|
|
var before = beforeList.FirstOrDefault(t => t.Argument < candleData.Argument);
|
|
|
|
|
|
if (before != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
lastCandleData = lastCandleData_Edit.Find(t => t.Argument == before.Argument);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2024-07-11 11:27:14 +09:00
|
|
|
|
|
2024-07-15 12:49:00 +09:00
|
|
|
|
if (lastCandleData.Argument.Second != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
var beforeList = lastCandleData_Edit.OrderByDescending(t => t.Argument).ToList();
|
|
|
|
|
|
var beforeArg = beforeList[1].Argument;
|
|
|
|
|
|
lastCandleData.Argument = beforeList[1].Argument.AddMinutes((int)interval);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-07-12 12:57:46 +09:00
|
|
|
|
// 업데이트 or 추가
|
|
|
|
|
|
bool updateFlag = false;
|
2024-07-11 11:27:14 +09:00
|
|
|
|
|
2024-07-15 12:49:00 +09:00
|
|
|
|
if (candleData.Argument > lastCandleData.Argument && candleData.Argument < lastCandleData.Argument.AddMinutes((int)interval))
|
|
|
|
|
|
updateFlag = true;
|
|
|
|
|
|
|
|
|
|
|
|
//switch (interval)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.M1:
|
|
|
|
|
|
// if (lastCandleData.Argument.Minute == candleData.Argument.Minute)
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.M3:
|
|
|
|
|
|
// if (candleData.Argument > lastCandleData.Argument && candleData.Argument < lastCandleData.Argument.AddMinutes((int)interval))
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// //if (candleData.Argument.Minute % 3 != 0 || (candleData.Argument.Minute % 3 == 0 && candleData.Argument.Minute == lastCandleData.Argument.Minute))
|
|
|
|
|
|
// // updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.M5:
|
|
|
|
|
|
// //if (candleData.Argument.Minute % 5 != 0 || (candleData.Argument.Minute % 5 == 0 && candleData.Argument.Minute == lastCandleData.Argument.Minute))
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.M15:
|
|
|
|
|
|
// if (candleData.Argument.Minute % 15 != 0 || (candleData.Argument.Minute % 15 == 0 && candleData.Argument.Minute == lastCandleData.Argument.Minute))
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.M30:
|
|
|
|
|
|
// if (candleData.Argument.Minute % 30 != 0 || (candleData.Argument.Minute % 30 == 0 && candleData.Argument.Minute == lastCandleData.Argument.Minute))
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.H1:
|
|
|
|
|
|
// if (candleData.Argument.Hour == candleData.Argument.Hour)
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.H4:
|
|
|
|
|
|
// if (candleData.Argument.Hour % 4 != 0 || (candleData.Argument.Hour % 4 == 0 && candleData.Argument.Hour == lastCandleData.Argument.Hour))
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.H6:
|
|
|
|
|
|
// if (candleData.Argument.Hour % 6 != 0 || (candleData.Argument.Hour % 6 == 0 && candleData.Argument.Hour == lastCandleData.Argument.Hour))
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.H12:
|
|
|
|
|
|
// if (candleData.Argument.Hour % 12 != 0 || (candleData.Argument.Hour % 12 == 0 && candleData.Argument.Hour == lastCandleData.Argument.Hour))
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
//}
|
2024-07-12 12:57:46 +09:00
|
|
|
|
|
|
|
|
|
|
// 이미 등록된 시간 캔들이 있는 경우 변경
|
|
|
|
|
|
if (updateFlag)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 시간 업데이트
|
2024-07-15 12:49:00 +09:00
|
|
|
|
//lastCandleData.Argument = candleData.Argument;
|
2024-07-12 12:57:46 +09:00
|
|
|
|
// 종가 수정
|
|
|
|
|
|
lastCandleData.Close = candleData.Close;
|
|
|
|
|
|
lastCandleData.Low = lastCandleData.Low > candleData.Low ? candleData.Low : lastCandleData.Low;
|
|
|
|
|
|
lastCandleData.High = lastCandleData.High < candleData.High ? candleData.High : lastCandleData.High;
|
|
|
|
|
|
|
|
|
|
|
|
lastCandleData.WebSocketUpdate = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
// 없는 경우 추가
|
|
|
|
|
|
else
|
2024-07-15 12:49:00 +09:00
|
|
|
|
{
|
2024-07-12 12:57:46 +09:00
|
|
|
|
candleData.WebSocketUpdate = true;
|
2024-07-15 12:49:00 +09:00
|
|
|
|
var dt = candleData.Argument;
|
|
|
|
|
|
dt = dt.AddSeconds(dt.Second * -1);
|
|
|
|
|
|
dt = dt.AddMilliseconds(dt.Millisecond * -1);
|
|
|
|
|
|
candleData.Open = lastCandleData.Close;
|
2024-07-12 12:57:46 +09:00
|
|
|
|
// 새 데이터 등록
|
|
|
|
|
|
candleDataList.Add(candleData);
|
|
|
|
|
|
|
|
|
|
|
|
// 기존 데이터 삭제
|
2024-12-13 14:29:21 +09:00
|
|
|
|
if (candleDataList.Count > 500)
|
2024-07-12 12:57:46 +09:00
|
|
|
|
{
|
|
|
|
|
|
// 가장 오래된 데이터 삭제
|
|
|
|
|
|
candleDataList.Remove(j => j.Argument == candleDataList.Min(i => i.Argument));
|
|
|
|
|
|
}
|
2024-07-11 11:27:14 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case CommonProperty.BitgetWebSocketType.캔들정보:
|
|
|
|
|
|
#region 캔들 웹소켓 : 종목 50, 캔들 1 개만 해도 뒤지려고 함 !! (일딴 패스)
|
|
|
|
|
|
{
|
2024-07-15 12:49:00 +09:00
|
|
|
|
var list = new List<ResponseCandleStick>();
|
|
|
|
|
|
cloneList = cloneList.Where(t => t["action"].ToString() == "update").ToList();
|
|
|
|
|
|
foreach (var item in cloneList)
|
2024-07-11 11:27:14 +09:00
|
|
|
|
{
|
2024-07-15 12:49:00 +09:00
|
|
|
|
var resCandleStick = new ResponseCandleStick();
|
|
|
|
|
|
resCandleStick.arg = new ResponseCandleStickArg();
|
|
|
|
|
|
|
|
|
|
|
|
double.TryParse(item["ts"].ToString(), out var ts);
|
|
|
|
|
|
|
|
|
|
|
|
var arg = (JObject)item["arg"];
|
|
|
|
|
|
resCandleStick.arg.instType = arg.GetValue("instType").ToString();
|
|
|
|
|
|
resCandleStick.arg.channel = arg.GetValue("channel").ToString();
|
|
|
|
|
|
resCandleStick.arg.instId = arg.GetValue("instId").ToString();
|
|
|
|
|
|
resCandleStick.action = item["action"]?.ToString();
|
|
|
|
|
|
resCandleStick.ts = ts;
|
|
|
|
|
|
var dataList = JsonConvert.DeserializeObject<List<List<string>>>(JsonConvert.SerializeObject(item["data"]));
|
|
|
|
|
|
resCandleStick.data = dataList[0];
|
|
|
|
|
|
list.Add(resCandleStick);
|
2025-07-07 10:55:01 +09:00
|
|
|
|
}
|
2024-07-11 11:27:14 +09:00
|
|
|
|
|
2024-07-15 12:49:00 +09:00
|
|
|
|
var minList = new Dictionary<string, List<CandleData>>();
|
2024-07-11 11:27:14 +09:00
|
|
|
|
|
2024-07-15 12:49:00 +09:00
|
|
|
|
var stringList = list.Select(t => t.arg.instId).ToList();
|
|
|
|
|
|
list = list.OrderBy(t => t.ts).ToList();
|
2024-07-10 11:46:59 +09:00
|
|
|
|
|
2024-07-15 12:49:00 +09:00
|
|
|
|
foreach (var item in stringList)
|
|
|
|
|
|
{
|
|
|
|
|
|
var temp = list.Where(t => item == t.arg.instId);
|
|
|
|
|
|
if (temp.Count() > 0)
|
2024-07-11 11:27:14 +09:00
|
|
|
|
{
|
2024-07-15 12:49:00 +09:00
|
|
|
|
minList.Add(item, new List<CandleData>());
|
|
|
|
|
|
foreach (var t in temp)
|
2024-07-11 11:27:14 +09:00
|
|
|
|
{
|
2024-07-15 12:49:00 +09:00
|
|
|
|
DateTime dt = new DateTime(1970, 01, 01);
|
|
|
|
|
|
t.reciveTime = dt.AddMilliseconds(Convert.ToDouble(t.data[0])).ToLocalTime();
|
2024-07-11 11:27:14 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-07-15 12:49:00 +09:00
|
|
|
|
var timeList = temp.Select(t => t.reciveTime.Minute).OrderBy(t => t).ToList();
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var min in timeList)
|
2024-07-11 11:27:14 +09:00
|
|
|
|
{
|
2024-07-15 12:49:00 +09:00
|
|
|
|
var minDataList = temp.Where(t => t.reciveTime.Minute == min).OrderBy(t => t.reciveTime).ToList();
|
2025-06-09 11:27:53 +09:00
|
|
|
|
|
2024-07-15 12:49:00 +09:00
|
|
|
|
var lastData = minDataList[minDataList.Count - 1];
|
|
|
|
|
|
var candleData = new CandleData();
|
|
|
|
|
|
|
|
|
|
|
|
double.TryParse(lastData.data[1].ToString(), out var openData);
|
|
|
|
|
|
double.TryParse(lastData.data[2].ToString(), out var highData);
|
|
|
|
|
|
double.TryParse(lastData.data[3].ToString(), out var lowData);
|
|
|
|
|
|
double.TryParse(lastData.data[4].ToString(), out var closeData);
|
|
|
|
|
|
|
|
|
|
|
|
candleData.Argument = lastData.reciveTime;
|
|
|
|
|
|
candleData.Close = closeData;
|
|
|
|
|
|
candleData.Open = openData;
|
|
|
|
|
|
candleData.Low = lowData;
|
|
|
|
|
|
candleData.High = highData;
|
|
|
|
|
|
|
|
|
|
|
|
minList[item].Add(candleData);
|
2024-07-11 11:27:14 +09:00
|
|
|
|
}
|
2024-07-15 12:49:00 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
foreach (var item in minList.Keys)
|
|
|
|
|
|
{
|
|
|
|
|
|
var temp = minList[item];
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var candleData in temp)
|
2025-07-07 10:55:01 +09:00
|
|
|
|
{
|
2024-07-15 12:49:00 +09:00
|
|
|
|
foreach (CommonProperty.MCandleTimeType mCandleTimeType in Enum.GetValues(typeof(CommonProperty.MCandleTimeType)))
|
2024-07-11 11:27:14 +09:00
|
|
|
|
{
|
2024-07-15 12:49:00 +09:00
|
|
|
|
var strInterval = Utils.Convertor.GetEnumDescription((Enum)mCandleTimeType);
|
|
|
|
|
|
if (!intervalList.Contains(strInterval)) continue;
|
|
|
|
|
|
|
|
|
|
|
|
// 캔들 리스트에서 해당 데이터 찾기
|
|
|
|
|
|
var searchIndex = commonProperty.candleDataLists.IndexOf(i => i.ConGoodsData.MarketName == item);
|
|
|
|
|
|
|
|
|
|
|
|
var candleDataList = commonProperty.candleDataLists[searchIndex].candleDataList[mCandleTimeType];
|
|
|
|
|
|
|
|
|
|
|
|
// 마지막 데이터 (최신데이터) 가져오기
|
|
|
|
|
|
CandleData lastCandleData = null;
|
|
|
|
|
|
|
|
|
|
|
|
if (candleDataList.Count == 0)
|
|
|
|
|
|
candleDataList.Add(candleData);
|
|
|
|
|
|
else
|
2024-07-11 11:27:14 +09:00
|
|
|
|
{
|
2024-07-15 12:49:00 +09:00
|
|
|
|
var max = candleDataList.Max(t => t.Argument);
|
|
|
|
|
|
lastCandleData = candleDataList.Find(t => t.Argument == max);
|
2025-06-09 11:27:53 +09:00
|
|
|
|
lastCandleData.Open = 0;
|
2024-07-25 12:26:45 +09:00
|
|
|
|
var flag = false;
|
|
|
|
|
|
if (((int)mCandleTimeType) < 60)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!(lastCandleData.Argument.Millisecond == 0 && lastCandleData.Argument.Second == 0 && lastCandleData.Argument.Minute % ((int)mCandleTimeType) == 0))
|
|
|
|
|
|
{
|
|
|
|
|
|
flag = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!(lastCandleData.Argument.Millisecond == 0 && lastCandleData.Argument.Second == 0 &&
|
|
|
|
|
|
lastCandleData.Argument.Minute == 0 && lastCandleData.Argument.Hour % (((int)mCandleTimeType) / 60) == 0))
|
|
|
|
|
|
{
|
|
|
|
|
|
flag = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (flag)
|
2024-07-15 12:49:00 +09:00
|
|
|
|
{
|
|
|
|
|
|
var beforeList = candleDataList.OrderByDescending(t => t.Argument).ToList();
|
|
|
|
|
|
var beforeArg = beforeList[1].Argument;
|
|
|
|
|
|
lastCandleData.Argument = beforeList[1].Argument.AddMinutes((int)mCandleTimeType);
|
|
|
|
|
|
}
|
2024-07-11 11:27:14 +09:00
|
|
|
|
|
2024-07-15 12:49:00 +09:00
|
|
|
|
// 업데이트 or 추가
|
|
|
|
|
|
bool updateFlag = false;
|
|
|
|
|
|
|
|
|
|
|
|
if (candleData.Argument >= lastCandleData.Argument && candleData.Argument < lastCandleData.Argument.AddMinutes((int)mCandleTimeType))
|
|
|
|
|
|
updateFlag = true;
|
|
|
|
|
|
#region 접어 두기
|
|
|
|
|
|
//switch (mCandleTimeType)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.M1:
|
|
|
|
|
|
// if (lastCandleData.Argument.Minute == candleData.Argument.Minute)
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.M3:
|
|
|
|
|
|
// if (candleData.Argument.Minute % 3 != 0 || (candleData.Argument.Minute % 3 == 0 && candleData.Argument.Minute == lastCandleData.Argument.Minute))
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.M5:
|
|
|
|
|
|
// if (candleData.Argument.Minute % 5 != 0 || (candleData.Argument.Minute % 5 == 0 && candleData.Argument.Minute == lastCandleData.Argument.Minute))
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.M15:
|
|
|
|
|
|
// if (candleData.Argument.Minute % 15 != 0 || (candleData.Argument.Minute % 15 == 0 && candleData.Argument.Minute == lastCandleData.Argument.Minute))
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.M30:
|
|
|
|
|
|
// if (candleData.Argument.Minute % 30 != 0 || (candleData.Argument.Minute % 30 == 0 && candleData.Argument.Minute == lastCandleData.Argument.Minute))
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.H1:
|
|
|
|
|
|
// if (candleData.Argument.Hour == candleData.Argument.Hour)
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.H4:
|
|
|
|
|
|
// if (candleData.Argument.Hour % 4 != 0 || (candleData.Argument.Hour % 4 == 0 && candleData.Argument.Hour == lastCandleData.Argument.Hour))
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.H6:
|
|
|
|
|
|
// if (candleData.Argument.Hour % 6 != 0 || (candleData.Argument.Hour % 6 == 0 && candleData.Argument.Hour == lastCandleData.Argument.Hour))
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// case CommonProperty.MCandleTimeType.H12:
|
|
|
|
|
|
// if (candleData.Argument.Hour % 12 != 0 || (candleData.Argument.Hour % 12 == 0 && candleData.Argument.Hour == lastCandleData.Argument.Hour))
|
|
|
|
|
|
// updateFlag = true;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
//}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
// 이미 등록된 시간 캔들이 있는 경우 변경
|
|
|
|
|
|
if (updateFlag)
|
2024-07-11 11:27:14 +09:00
|
|
|
|
{
|
2024-07-15 12:49:00 +09:00
|
|
|
|
// 시간 업데이트
|
|
|
|
|
|
//lastCandleData.Argument = candleData.Argument;
|
|
|
|
|
|
// 종가 수정
|
|
|
|
|
|
lastCandleData.Close = candleData.Close;
|
|
|
|
|
|
lastCandleData.Low = lastCandleData.Low > candleData.Low ? candleData.Low : lastCandleData.Low;
|
|
|
|
|
|
lastCandleData.High = lastCandleData.High < candleData.High ? candleData.High : lastCandleData.High;
|
|
|
|
|
|
|
|
|
|
|
|
lastCandleData.WebSocketUpdate = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
// 없는 경우 추가
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
candleData.WebSocketUpdate = true;
|
2024-07-15 16:06:18 +09:00
|
|
|
|
lastCandleData.Close = candleData.Open;
|
2025-07-07 10:55:01 +09:00
|
|
|
|
if(lastCandleData.High < lastCandleData.Close)
|
2024-07-15 16:08:37 +09:00
|
|
|
|
{
|
|
|
|
|
|
lastCandleData.High = lastCandleData.Close;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (lastCandleData.Low > lastCandleData.Close)
|
|
|
|
|
|
{
|
|
|
|
|
|
lastCandleData.Low = lastCandleData.Close;
|
|
|
|
|
|
}
|
2024-07-15 12:49:00 +09:00
|
|
|
|
var dt = candleData.Argument;
|
|
|
|
|
|
dt = dt.AddSeconds(dt.Second * -1);
|
2024-07-25 12:26:45 +09:00
|
|
|
|
dt = dt.AddMilliseconds(dt.Millisecond * -1);
|
2025-07-07 10:55:01 +09:00
|
|
|
|
|
|
|
|
|
|
if((int)mCandleTimeType > 60)
|
2024-07-25 12:26:45 +09:00
|
|
|
|
{
|
|
|
|
|
|
dt = dt.AddMinutes(dt.Minute * -1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-07-15 12:49:00 +09:00
|
|
|
|
// 새 데이터 등록
|
|
|
|
|
|
candleDataList.Add(candleData);
|
|
|
|
|
|
|
|
|
|
|
|
// 기존 데이터 삭제
|
2024-12-13 14:29:21 +09:00
|
|
|
|
if (candleDataList.Count > 500)
|
2024-07-15 12:49:00 +09:00
|
|
|
|
{
|
|
|
|
|
|
// 가장 오래된 데이터 삭제
|
|
|
|
|
|
candleDataList.Remove(j => j.Argument == candleDataList.Min(i => i.Argument));
|
|
|
|
|
|
}
|
2024-06-19 12:51:35 +09:00
|
|
|
|
}
|
2024-05-27 18:51:56 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-07-11 11:27:14 +09:00
|
|
|
|
}
|
2024-05-23 16:32:30 +09:00
|
|
|
|
}
|
2024-07-11 11:27:14 +09:00
|
|
|
|
#endregion
|
|
|
|
|
|
break;
|
2024-06-14 14:47:51 +09:00
|
|
|
|
}
|
2024-07-11 11:27:14 +09:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
2024-05-29 17:37:10 +09:00
|
|
|
|
{
|
2024-05-23 16:32:30 +09:00
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-05-22 16:56:51 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-05-28 16:56:19 +09:00
|
|
|
|
|