using BitgetApi.Data; using BitgetAPI.Data; using BitgetAPI.IndicatorConditionSetup; using BitgetAPI.WebService; using DevExpress.Utils.Extensions; using DevExpress.Utils.MVVM; using DevExpress.XtraEditors; using DevExpress.XtraGrid.Views.BandedGrid.Handler; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Net.WebSockets; using System.Reflection; using System.Security; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using static BitgetAPI.CommonProperty; using static DevExpress.Utils.Html.ViewInfo.DxHtmlOrderedListInfoCore; using static System.Windows.Forms.VisualStyles.VisualStyleElement; using static System.Windows.Forms.VisualStyles.VisualStyleElement.TextBox; namespace BitgetAPI { public partial class MainForm : Form { CommonProperty commonProperty = CommonProperty.Instance; #region 폼 내 사용되는 스레드 // 트리 현황판 업데이트 스레드 (단순 폼 업데이트) Thread th_treeListMarketInfoListUpdateTimer = null; // 신호검색 스레드 Thread th_SignalInfo = null; // 현황판 웹서비스 Ticker 스레드 (한번에 전체 종목 종가 받음) Thread th_MarketInfoList_WebService = null; // 웹소켓 스레드 Thread th_ticker_Websocket = null; Thread dataCalculateThread = null; WebConnection webConnection = new WebConnection(); // 스레드 종료 플래그 bool Is_th_th_MarketInfoList_WebService = false; bool Is_th_treeListUpdate = false; // 신호검색 리스트 작성 // 신호 Long 상승 (구매) List signals_LU = null; // 신호 Short 하락 (구매) List signals_SD = null; // 검색현황 Long 하락 (판매) List signals_LD = null; // 검색현황 Short 상승 (판매) List signals_SU = null; IndicatorProcess indicatorProcess = null; // 종목별 캔들 데이터 : 캔들 개수 const int candleCount = 200; #endregion public MainForm() { InitializeComponent(); init(); } // 폼 초기화 작업 public void init() { commonProperty.mainform = this; // 거래소 항목 추가 및 설정하기 comboBoxEdit_ExchangePlace.Properties.Items.AddRange(Enum.GetNames(typeof(CommonProperty.ExchangePlace))); comboBoxEdit_ExchangePlace.SelectedIndex = (int)CommonProperty.ExchangePlace.Bitget; commonProperty.selectedChangePlace = CommonProperty.ExchangePlace.Bitget; // 현황판 정렬 treeList_MarketInfo.BeginSort(); treeList_MarketInfo.Columns["quoteVolume"].SortOrder = SortOrder.Descending; treeList_MarketInfo.EndSort(); commonProperty.webSocketCandles = new List(); // 신호 Long 상승 (구매) signals_LU = new List(); // 신호 Short 하락 (구매) signals_SD = new List(); // 검색현황 Long 하락 (판매) signals_LD = new List(); // 검색현황 Short 상승 (판매) signals_SU = new List(); // 신호검색 트리리스트 설정 treeList_LongUp.DataSource = signals_LU; treeList_ShortDown.DataSource = signals_SD; // API Key 가져오기 및 등록 } // 웹서비스를 통해 현황판 및 마켓 Ticker 업데이트 private void getMarketInfoList_WebService(ExchangeWebReqType exchangeWebReqType) { Is_th_th_MarketInfoList_WebService = true; while (true) { Thread.Sleep(300); if (!Is_th_th_MarketInfoList_WebService) break; // 마켓 모든 종목 캔들 정보 Web Service로 가져오기 commonProperty.marketInfoList = (List)BitgetAPI.WebService.WebConnection.SendWebServer(exchangeWebReqType); try { // 현황판에 최신 정보 업데이트 하기 Invoke(new MethodInvoker(delegate () { var scrollPoint = treeList_MarketInfo.TopVisibleNodeIndex; treeList_MarketInfo.DataSource = commonProperty.marketInfoList; treeList_MarketInfo.RefreshDataSource(); treeList_MarketInfo.TopVisibleNodeIndex = scrollPoint; })); }catch (Exception ex) { } } } // 마켓 현황판 업데이트 (1) => Thread // 지표 생성 및 신호 검색 (2) private void TreeListMarketInfoListUpdate( ) { Is_th_treeListUpdate = true; // 마켓 현황판 업데이트 while (true) { if (!Is_th_treeListUpdate) break; Thread.Sleep(300); try { Invoke(new MethodInvoker(delegate () { var scrollPoint = treeList_MarketInfo.TopVisibleNodeIndex; var scrollPoint_LU = treeList_LongUp.TopVisibleNodeIndex; var scrollPoint_SD = treeList_ShortDown.TopVisibleNodeIndex; treeList_MarketInfo.RefreshDataSource(); treeList_LongUp.RefreshDataSource(); treeList_ShortDown.RefreshDataSource(); treeList_MarketInfo.TopVisibleNodeIndex = scrollPoint; treeList_LongUp.TopVisibleNodeIndex = scrollPoint_LU; treeList_ShortDown.TopVisibleNodeIndex = scrollPoint_SD; })); }catch(Exception ex) { } } } /// /// Data 처리 관련 Thread /// /// private void DataCalculateThread(BitgetWebSocketType type) { var flag = true; while (webConnection.Is_th_webSocketThread) { webConnection.CalculateDataList(type); if (flag) { th_SignalInfo = new Thread(new ThreadStart(Signalnfo)); th_SignalInfo.Start(); } flag = false; } } // 신호검색 Thread 함수 private void Signalnfo() { /* * 전환선 : (과거 n일간의 최고가 + 과거 n일간의 최저가) / 2 기준선 : (과거 m일간의 최고가 + 과거 m일간의 최저가) / 2 후행스팬 : 금일 종가를 ℓ일 전에 기입 선행스팬1 : (금일 전환선 + 금일 기준선) / 2한 값을 ℓ일 후에 기입 선행스팬2 : (과거 k일간의 최고가 + 과거 k일간의 최저가) /2한 값을 ℓ일 후에 기입 */ var checkedMarkets = checkedComboBoxEdit_MarketInfoList.Properties.Items.GetCheckedValues(); var intervalList = checkedComboBoxEdit_TimeInterval.Properties.Items.GetCheckedValues(); indicatorProcess = new IndicatorProcess(); indicatorProcess.Is_th_SignalInfo = true; indicatorProcess.checkedMarkets = checkedMarkets; indicatorProcess.intervalList = intervalList; indicatorProcess.signals_LU = signals_LU; indicatorProcess.signals_SD = signals_SD; indicatorProcess.signals_LD = signals_LD; indicatorProcess.signals_SU = signals_SU; indicatorProcess.sesstionTime = timeSpanEdit_SesstionTime.TimeSpan; if(checkEdit_ichmoku_Long.Checked) indicatorProcess.checked구름떼상향돌파 = true; if(checkEdit_Ichmoku_Short.Checked) indicatorProcess.checked구름떼하향돌파= true; if(checkEdit_yhk_Long.Checked) indicatorProcess.영호조건식_상향돌파 = true; if(checkEdit_yhk_Short.Checked) indicatorProcess.영호조건식_하향돌파= true; indicatorProcess.calProcess(); } // 종목별 캔들데이터 가져오기 (초기 설정) => Thread private void getMarketCandleData_WebService(ExchangeWebReqType exchangeWebReqType, List marketList) { // 프로그레스 바 Invoke(new MethodInvoker(delegate () { progressBarControl_data.Properties.Minimum = 0; progressBarControl_data.Properties.Maximum = marketList.Count; progressBarControl_data.Properties.Step = 1; progressBarControl_data.EditValue = 0; })); var progressCnt = 0; // WebServicee 초기 캔들 데이터 가져오기 : 종목, 개수 foreach (var marketName in marketList) { var marketCandleDataList = commonProperty.candleDataLists.Find(i => i.ConGoodsData.MarketName.Equals(marketName)); if (marketCandleDataList == null) continue; // 캔들 데이터 가져오기 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); } // 프로그레스 바 progressCnt++; Invoke(new MethodInvoker(delegate () { progressBarControl_data.EditValue = progressCnt; progressBarControl_data.PerformStep(); progressBarControl_data.Update(); })); } dataCalculateThread = new Thread(() => DataCalculateThread(BitgetWebSocketType.현황정보_전체종목)); dataCalculateThread.Start(); } // 거래소 콤보박스 클릭 시 이벤트 처리 private void comboBox_ExchangePlace_SelectedIndexChanged(object sender, EventArgs e) { var combobox = (ComboBoxEdit)sender; // 거래소에 따라서 코인 타입 생성하기 switch (combobox.SelectedIndex) { case (int)CommonProperty.ExchangePlace.Bitget: // 코인 타입 설정하기 comboBoxEdit_ConinType.Properties.Items.AddRange(Enum.GetNames(typeof(CommonProperty.BitgetProductType))); comboBoxEdit_ConinType.SelectedIndex = (int)CommonProperty.BitgetProductType.FUTURE; commonProperty.selectedBitgetProductType = CommonProperty.BitgetProductType.FUTURE; break; } } // 코인 타입 콤보박스 클릭 시 이벤트 처리 private void comboBox_CoinType_SelectedIndexChanged(object sender, EventArgs e) { var combobox = (ComboBoxEdit)sender; // 선택된 타입에 따라서 종목 정보 가져오기 ExchangeWebReqType exchangeWebReqType = ExchangeWebReqType.BitgetMarket_Future; switch (combobox.SelectedIndex) { case (int)CommonProperty.BitgetProductType.COIN: commonProperty.selectedBitgetProductType = CommonProperty.BitgetProductType.COIN; exchangeWebReqType = ExchangeWebReqType.BitgetMarket_Spot; break; case (int)CommonProperty.BitgetProductType.FUTURE: commonProperty.selectedBitgetProductType = CommonProperty.BitgetProductType.FUTURE; exchangeWebReqType = ExchangeWebReqType.BitgetMarket_Future; break; case (int)CommonProperty.BitgetProductType.MARGIN_보류: commonProperty.selectedBitgetProductType = CommonProperty.BitgetProductType.MARGIN_보류; break; } // 마켓 정보 가져오기 var marketInfos = commonProperty.marketInfoList = (List)BitgetAPI.WebService.WebConnection.SendWebServer(exchangeWebReqType); commonProperty.marketInfoList = marketInfos; labelControl_MarketCount.Text = marketInfos.Count().ToString(); treeList_MarketInfo.DataSource = marketInfos; treeList_MarketInfo.RefreshDataSource(); List candleDataLists = new List(); commonProperty.candleDataLists = candleDataLists; // 캔들 리스트 생성하기 foreach (var item in marketInfos) { MarketCandleDataList candleDataList = new MarketCandleDataList(); candleDataList.ConGoodsData = item; foreach (var interval in Enum.GetValues(typeof(CommonProperty.MCandleTimeType))) { candleDataList.candleDataList.Add((MCandleTimeType)interval, new List()); } candleDataLists.Add(candleDataList); } // 조건 설정 : 체크콤보박스 마켓 정보 추가하기 foreach (var item in marketInfos.OrderByDescending(i => i.quoteVolume)) checkedComboBoxEdit_MarketInfoList.Properties.Items.Add(item.MarketName); // 조건 설정 : 체크콤보박스 시간별 정보 추가하기 // 캔들 데이터 가져오기 foreach (var interval in Enum.GetValues(typeof(CommonProperty.MCandleTimeType))) { var description = Utils.Convertor.GetEnumDescription((Enum)interval); checkedComboBoxEdit_TimeInterval.Properties.Items.Add(description); } // 마켓정보(WebService Ticker) => 0.5초당 1번으로 업데이트 하기 (현황판) th_MarketInfoList_WebService = new Thread(() => getMarketInfoList_WebService(exchangeWebReqType)); th_MarketInfoList_WebService.Start(); #region 캔들 웹소켓 : 종목 50, 캔들 1 개만 해도 뒤지려고 함 !! (일딴 패스) /* // 시간별 분봉 웹소켓 foreach (var interval in Enum.GetValues(typeof(CommonProperty.MCandleTimeType))) { var description = Utils.Convertor.GetEnumDescription((Enum)interval); var th_CandleStatus = new Thread(() => ThreadEventAsync(BitgetWebSocketType.캔들정보, "candle" + description)); th_CandleStatus.Start(); break; }*/ #endregion } private void ticker_WebSocket(List marketList, int count) { } // 폼 닫기 시 처리 이벤트 private void MainForm_FormClosing(object sender, FormClosingEventArgs e) { if (th_SignalInfo != null) { indicatorProcess.Is_th_SignalInfo = false; th_SignalInfo.Join(); th_SignalInfo = null; } if (commonProperty.webConnection != null) { commonProperty.webConnection.Is_th_webSocketThread = false; commonProperty.webConnection.closeWebSocket(); } if (th_MarketInfoList_WebService != null) { Is_th_th_MarketInfoList_WebService = false; if (th_MarketInfoList_WebService.ThreadState == ThreadState.Running) { th_MarketInfoList_WebService.Join(); th_MarketInfoList_WebService = null; } } if (th_treeListMarketInfoListUpdateTimer != null) { Is_th_treeListUpdate = false; if (th_treeListMarketInfoListUpdateTimer.ThreadState == ThreadState.Running) { th_treeListMarketInfoListUpdateTimer.Join(); th_treeListMarketInfoListUpdateTimer = null; } } } // 검색기 > 종목 재 정렬 private void simpleButton_MarketOrderRefresh_Click(object sender, EventArgs e) { checkedComboBoxEdit_MarketInfoList.Properties.Items.Clear(); // 조건 설정 : 체크콤보박스 마켓 정보 추가하기 foreach (var item in commonProperty.marketInfoList.OrderByDescending(i=>i.quoteVolume)) checkedComboBoxEdit_MarketInfoList.Properties.Items.Add(item.MarketName); } // 신호 검색 시작 private void simpleButton_SignalStart_Click(object sender, EventArgs e) { if(th_SignalInfo != null) { indicatorProcess.Is_th_SignalInfo = false; if (th_SignalInfo.ThreadState == ThreadState.Running) th_SignalInfo.Join(); th_SignalInfo = null; } if (commonProperty.webConnection != null) { commonProperty.webConnection.Is_th_webSocketThread = false; commonProperty.webConnection.closeWebSocket(); } if(th_treeListMarketInfoListUpdateTimer != null) { Is_th_treeListUpdate = false; if (th_treeListMarketInfoListUpdateTimer.ThreadState == ThreadState.Running) { th_treeListMarketInfoListUpdateTimer.Join(); th_treeListMarketInfoListUpdateTimer = null; } } foreach (var candleList in commonProperty.candleDataLists) { foreach (var interval in candleList.candleDataList) interval.Value.Clear(); } var count = 0; var marketList = checkedComboBoxEdit_MarketInfoList.Properties.Items.GetCheckedValues(); if (marketList.Count <=0 ) return; if (marketList.Count > 50) { for(var i = 50; i < marketList.Count; i++) { checkedComboBoxEdit_MarketInfoList.Properties.Items[i].CheckState = CheckState.Unchecked; } marketList = checkedComboBoxEdit_MarketInfoList.Properties.Items.GetCheckedValues(); } var dic = new Dictionary(); dic.Add("op", "subscribe"); var argsList = new List>(); // Json String 만들기 // 종목별 Ticker 구독하기 // WebSocket으로 데이터 가져오기 foreach (var marketName in marketList) { var args = new Dictionary(); args.Add("instType", "USDT-FUTURES"); args.Add("channel", "ticker"); args.Add("instId", marketName); argsList.Add(args); count++; } dic.Add("args", argsList); // 웹소켓으로 캔들 쌓기 // WebSocket 생성 commonProperty.webConnection = webConnection; webConnection.Is_th_webSocketThread = true; webConnection.BitGetWebSocektStart(BitgetWebSocketType.현황정보_전체종목, dic); //th_webSocketThread = new Thread(() => TheadWebSocketRecieve(BitgetWebSocketType.현황정보_전체종목, dic)); //th_webSocketThread.Start(); // WebServicee 초기 캔들 데이터 가져오기 : 종목, 개수 // 종목별 캔들 데이터 가져오기 (WebService) // 선택된 타입에 따라서 종목 정보 가져오기 var exchangeWebReqType = ExchangeWebReqType.BitgetMarket_Future; th_MarketInfoList_WebService = new Thread(() => getMarketCandleData_WebService(exchangeWebReqType, marketList)); th_MarketInfoList_WebService.Start(); // 트리 현황판 업데이트 th_treeListMarketInfoListUpdateTimer = new Thread(new ThreadStart(TreeListMarketInfoListUpdate)); th_treeListMarketInfoListUpdateTimer.Start(); } } }