using Newtonsoft.Json.Linq; using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Globalization; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Net.NetworkInformation; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace NewsCrawler { public partial class NewsForm : Form { class NEWS_ITEM { public NEWS_ITEM(int iID, string strTitle, string strCode, CodeList.CODE_VALUE Code, DateTime NewsTime, DateTime ResTime, string strRef, string strURL, float fElapseT) { m_iID = iID; m_strCode = strCode; m_Code = Code; m_NewsTime = NewsTime; m_ResTime = ResTime; m_strRef = strRef; m_strTitle = strTitle; m_strURL = strURL; m_fElapseT = fElapseT; } public int m_iID; public string m_strCode; public CodeList.CODE_VALUE m_Code = null; public DateTime m_NewsTime; public DateTime m_ResTime; public string m_strRef; public string m_strTitle; public string m_strURL; public float m_fElapseT; } class PRICE_CHECK_DATA { public int m_iID; public CodeList.CODE_VALUE m_Code; public int m_iPriceStart = 0; public int m_iPriceLow = 0; public int m_iPriceHigh = 0; public DateTime m_StartTime; public int m_iTryCnt = 0; public bool m_bLog = false; public NEWS_ITEM m_NewsItem; } CybosHelper m_CybosHelper = null; CodeList m_CodeList = null; TextCondition m_Condition = null; ConfigForm m_ConfigForm = null; DateTime m_StartTime; DateTime m_EndTime; System.Timers.Timer m_CrawlTimer = new System.Timers.Timer(); int m_iCrawlInterval = 500; bool m_bBuy = false; ConcurrentQueue m_NewItems = new ConcurrentQueue(); ConcurrentBag m_URLs = new ConcurrentBag(); System.Timers.Timer m_SystemTimer = new System.Timers.Timer(); ConcurrentQueue m_PriceCheckList = new ConcurrentQueue(); System.Timers.Timer m_PriceCheckTimer = new System.Timers.Timer(); Crawler m_Crawler = null; ExcelHandler m_Excel = null; public NewsForm() { InitializeComponent(); m_StartTime = DateTime.ParseExact("09:00", "HH:mm", CultureInfo.CurrentCulture); m_EndTime = DateTime.ParseExact("15:30", "HH:mm", CultureInfo.CurrentCulture); Config.Init(); Util.SetLogView(tbLog); m_CodeList = new CodeList(); m_Condition = new TextCondition(); m_CybosHelper = new CybosHelper(this); m_Crawler = new Crawler(this); Util.Log(Util.LOG_TYPE.VERVOSE, "========== NewsCrawler 실행 =========="); //MessageBox.Show("Keywords : \n\n" + m_Condition.GetKeywordsCnt()); m_Crawler.ReadKIND(true); m_Crawler.ReadDart(true); m_Crawler.ReadEtoday(true); //m_Crawler.ReadEtoday2(true); m_Crawler.ReadAsiaE(true); m_Crawler.ReadEdaily(true); m_Crawler.ReadMoneyToday(true); m_Crawler.ReadFinancialNews(true); lvList.Columns[chTime.Index].TextAlign = HorizontalAlignment.Right; lvList.Columns[chResponseT.Index].TextAlign = HorizontalAlignment.Right; lvList.Columns[chResT.Index].TextAlign = HorizontalAlignment.Right; lvList.Columns[chId.Index].TextAlign = HorizontalAlignment.Right; lvList.Columns[chPriceS.Index].TextAlign = HorizontalAlignment.Right; lvList.Columns[chPriceLow.Index].TextAlign = HorizontalAlignment.Right; lvList.Columns[chPriceLowP.Index].TextAlign = HorizontalAlignment.Right; lvList.Columns[chPriceHigh.Index].TextAlign = HorizontalAlignment.Right; lvList.Columns[chPriceHighP.Index].TextAlign = HorizontalAlignment.Right; lvList.ListViewItemSorter = new ListViewItemComparer(chId.Index, SortOrder.Ascending); lvList.Sorting = SortOrder.Ascending; lvList.Sort(); if(lvList.Items.Count > 0) { lvList.Items[lvList.Items.Count - 1].Selected = true; lvList.Select(); if(lvList.SelectedItems.Count > 0) lvList.SelectedItems[0].EnsureVisible(); } //foreach(ColumnHeader col in lvList.Columns) //{ // if(!(col == chPriceS || col == chPriceLow || col == chPriceHigh)) // col.Width = -2; //} m_Excel = new ExcelHandler(Util.GetLogPath()+"/PriceCheck-"+DateTime.Now.ToString("yyyy-MM-dd")+".xlsx"); m_CrawlTimer.Elapsed+=CrawlTimer_Tick; m_CrawlTimer.Interval = m_iCrawlInterval; m_CrawlTimer.Start(); m_SystemTimer.Elapsed+=SystemTimer_Elapsed; m_SystemTimer.Interval=1000; m_SystemTimer.Start(); m_PriceCheckTimer.Interval = 5000; m_PriceCheckTimer.Elapsed += PriceCheckTimer_Elapsed; m_PriceCheckTimer.Start(); m_bBuy = chBuy.Checked; Test(); } void Test() { if(Util.IsDebugging() == false) return; InsertItem("[test] 신한, 덕산네오룩스 66만여주 취득14:38", "", "", new DateTime(2016, 11, 30, 00, 00, 00), DateTime.Now, "http://www.etoday.co.kr/news/sokbo/sokbo_view.htm?idxno=2016112914055964082", "이투데이", 0, false); InsertItem("[test] 덕산하이메탈, 덕산네오룩스 66만여주 취득14:38", "", "", new DateTime(2016, 11, 30, 00, 00, 00), DateTime.Now, "http://www.asiae.co.kr/news/sokbo/sokbo_view.htm?idxno=2016112914371817318", "asiae", 0, false); InsertItem("[test] 자연과환경, 12월15일~22일 주주명부폐쇄14:19", "", "", new DateTime(2016, 11, 30, 00, 00, 00), DateTime.Now, "http://www.asiae.co.kr/news/sokbo/sokbo_view.htm?idxno=2016112914193170301", "asiae", 0, false); InsertItem("[test] 이엠코리아, 한국항공우주산업과 3억원 규모 공급계약14:06", "", "", new DateTime(2016, 11, 30, 00, 00, 00), DateTime.Now, "http://www.asiae.co.kr/news/sokbo/sokbo_view.htm?idxno=2016112914055964082", "asiae", 0, false); InsertItem("[test] [특징주] 진원생명과학, 국외 AI 인체감염증...", "", "", new DateTime(2016, 11, 30, 00, 00, 00), DateTime.Now, "http://www.etoday.co.kr/news/sokbo/sokbo_view.htm?idxno=2016112914055964082", "이투데이", 0, false); } private void BuyItem(CodeList.CODE_VALUE Code) { if(m_bBuy == false) return; if((Code.m_enType & CodeList.CODE_TYPE.DENIAL) == CodeList.CODE_TYPE.DENIAL) { Util.Log(Util.LOG_TYPE.DENIAL, string.Format("거부종목 ({0})", Code)); return; } if((Code.m_enType & CodeList.CODE_TYPE.DUPLICATED) == CodeList.CODE_TYPE.DUPLICATED) { Util.Log(Util.LOG_TYPE.DUPLICATED, string.Format("중복종목 ({0})", Code)); return; } m_CybosHelper.Buy(Code, Config.GetBuyPrice()); m_CodeList.AddDuplicatedList(Code.m_strCode, Code.m_strName); } public void OnManualItemBuy(CodeList.CODE_VALUE Code) { BuyItem(Code); } void CheckPrice(NEWS_ITEM NewsItem) { if(DateTime.Now < m_StartTime || DateTime.Now >= m_EndTime) return; PRICE_CHECK_DATA CheckData = new PRICE_CHECK_DATA(); CheckData.m_iID = NewsItem.m_iID; CheckData.m_Code = NewsItem.m_Code; CheckData.m_StartTime = DateTime.Now; CheckData.m_NewsItem = NewsItem; m_PriceCheckList.Enqueue(CheckData); } public TextCondition.RESULT CheckMatch(string strTitle) { return m_Condition.Match(strTitle); } void ProcessSearchAndBuy(NEWS_ITEM NewsItem) { TextCondition.RESULT MatchResult = CheckMatch(NewsItem.m_strTitle); switch(MatchResult.m_enType) { case TextCondition.TYPE.NEGATIVE: Util.Log(Util.LOG_TYPE.NEGATIVE, string.Format("[{0}] {1} (keyword:{2}, code:{3})", NewsItem.m_strRef, NewsItem.m_strTitle, MatchResult.m_strKeyword, NewsItem.m_Code.ToString())); break; case TextCondition.TYPE.POSITIVE_FORCE: if ((NewsItem.m_Code.m_enType & CodeList.CODE_TYPE.DUPLICATED) == CodeList.CODE_TYPE.DUPLICATED) { Util.Log(Util.LOG_TYPE.DUPLICATED, string.Format("[{0}] {1} (keyword:{2}, code:{3})", NewsItem.m_strRef, NewsItem.m_strTitle, MatchResult.m_strKeyword, NewsItem.m_Code.ToString())); } else { BuyItem(NewsItem.m_Code); Util.Log(Util.LOG_TYPE.POSITIVE_FORCE, string.Format("[{0}] {1} (keyword:{2}, code:{3})", NewsItem.m_strRef, NewsItem.m_strTitle, MatchResult.m_strKeyword, NewsItem.m_Code.ToString())); } m_CodeList.AddDuplicatedList(NewsItem.m_Code.m_strCode, NewsItem.m_Code.m_strName); break; case TextCondition.TYPE.POSITIVE: if((NewsItem.m_Code.m_enType&CodeList.CODE_TYPE.DENIAL) == CodeList.CODE_TYPE.DENIAL) Util.Log(Util.LOG_TYPE.DENIAL, string.Format("[{0}] {1} (keyword:{2}, code:{3})", NewsItem.m_strRef, NewsItem.m_strTitle, MatchResult.m_strKeyword, NewsItem.m_Code.ToString())); else if((NewsItem.m_Code.m_enType&CodeList.CODE_TYPE.DUPLICATED) == CodeList.CODE_TYPE.DUPLICATED) Util.Log(Util.LOG_TYPE.DUPLICATED, string.Format("[{0}] {1} (keyword:{2}, code:{3})", NewsItem.m_strRef, NewsItem.m_strTitle, MatchResult.m_strKeyword, NewsItem.m_Code.ToString())); else if((NewsItem.m_Code.m_enType&CodeList.CODE_TYPE.MANUAL) == CodeList.CODE_TYPE.MANUAL) { Util.Log(Util.LOG_TYPE.MANUAL_CODE, string.Format("[{0}] {1} (keyword:{2}, code:{3})", NewsItem.m_strRef, NewsItem.m_strTitle, MatchResult.m_strKeyword, NewsItem.m_Code.ToString())); if(m_bBuy == true) { ModelessPopup ManualPopup = new ModelessPopup(this); ManualPopup.SetMessage(string.Format("{0}\n[{1}] {2}\n(keyword:{3}, code:{4})\n\n매수하시겠습니까?", DateTime.Now.ToString("[hh:mm:ss]"), NewsItem.m_strRef, NewsItem.m_strTitle, MatchResult.m_strKeyword, NewsItem.m_Code), NewsItem.m_Code); ManualPopup.TopMost = true; ManualPopup.Show(); } } else { BuyItem(NewsItem.m_Code); Util.Log(Util.LOG_TYPE.POSITIVE, string.Format("[{0}] {1} (keyword:{2}, code:{3})", NewsItem.m_strRef, NewsItem.m_strTitle, MatchResult.m_strKeyword, NewsItem.m_Code.ToString())); } m_CodeList.AddDuplicatedList(NewsItem.m_Code.m_strCode, NewsItem.m_Code.m_strName); break; case TextCondition.TYPE.MANUAL: Util.Log(Util.LOG_TYPE.MANUAL_KEYWORD, string.Format("[{0}] {1} (keyword:{2}, code:{3})", NewsItem.m_strRef, NewsItem.m_strTitle, MatchResult.m_strKeyword, NewsItem.m_Code.ToString())); if(m_bBuy == true) { ModelessPopup ManualPopup = new ModelessPopup(this); ManualPopup.SetMessage(string.Format("{0}\n[{1}] {2}\n(keyword:{3}, code:{4})\n\n매수하시겠습니까?", DateTime.Now.ToString("[hh:mm:ss]"), NewsItem.m_strRef, NewsItem.m_strTitle, MatchResult.m_strKeyword, NewsItem.m_Code), NewsItem.m_Code); ManualPopup.TopMost = true; ManualPopup.Show(); } m_CodeList.AddDuplicatedList(NewsItem.m_Code.m_strCode, NewsItem.m_Code.m_strName); break; case TextCondition.TYPE.NOT_MATCHED: Util.Log(Util.LOG_TYPE.DEBUG, string.Format("[NOT_MATCHED] [{0}] {1}({2})", NewsItem.m_strRef, NewsItem.m_strTitle, NewsItem.m_Code.ToString())); break; } if (m_Condition.IsDuplicatedKeyword(NewsItem.m_strTitle) == true) { m_CodeList.AddDuplicatedList(NewsItem.m_Code.m_strCode, NewsItem.m_Code.m_strName); Util.Log(Util.LOG_TYPE.DEBUG, string.Format("[DUPLICATED_KEYWORD] [{0}] {1}({2})", NewsItem.m_strRef, NewsItem.m_strTitle, NewsItem.m_Code.ToString())); } CheckPrice(NewsItem); } public void OnReceivedSupplyContract(string strCodeName, float fRate) { CodeList.CODE_VALUE Code = m_CodeList.GetCodeByName(strCodeName); if(Code == null) { Util.Log(Util.LOG_TYPE.VERVOSE, string.Format("[DartAPI][공급계약체결] 종목을 찾을 수 없음({0}, {1}%", strCodeName, fRate)); return; } if(fRate < Config.GetSupplyContractRate()) { Util.Log(Util.LOG_TYPE.VERVOSE, string.Format("[DartAPI][공급계약체결] 매출액 대비율 낮음({0}, {1}% / {2}%)", strCodeName, fRate, Config.GetSupplyContractRate())); return; } string strRef = "DartAPI"; string strTitle = string.Format("공급계약체결 - {0} {1:n2}%", strCodeName, fRate); if((Code.m_enType&CodeList.CODE_TYPE.DENIAL) == CodeList.CODE_TYPE.DENIAL) Util.Log(Util.LOG_TYPE.DENIAL, string.Format("[{0}] {1}", strRef, strTitle)); else if((Code.m_enType&CodeList.CODE_TYPE.DUPLICATED) == CodeList.CODE_TYPE.DUPLICATED) Util.Log(Util.LOG_TYPE.DUPLICATED, string.Format("[{0}] {1}", strRef, strTitle)); else if((Code.m_enType&CodeList.CODE_TYPE.MANUAL) == CodeList.CODE_TYPE.MANUAL) { Util.Log(Util.LOG_TYPE.MANUAL_CODE, string.Format("[{0}] {1}", strRef, strTitle)); if(m_bBuy == true) { ModelessPopup ManualPopup = new ModelessPopup(this); ManualPopup.SetMessage(string.Format("{0}\n[{1}] {2}\n\n매수하시겠습니까?", DateTime.Now.ToString("[hh:mm:ss]"), strRef, strTitle), Code); ManualPopup.TopMost = true; ManualPopup.Show(); } } else { BuyItem(Code); Util.Log(Util.LOG_TYPE.POSITIVE, string.Format("[{0}] {1}", strRef, strTitle)); } m_CodeList.AddDuplicatedList(Code.m_strCode, Code.m_strName); } public void OnReceivedRevenue(string strCodeName, float fRate) { CodeList.CODE_VALUE Code = m_CodeList.GetCodeByName(strCodeName); if (Code == null) { Util.Log(Util.LOG_TYPE.VERVOSE, string.Format("[DartAPI][영업실적] 종목을 찾을 수 없음({0}, {1}%", strCodeName, fRate)); return; } if (fRate < Config.GetRevenueRate()) { Util.Log(Util.LOG_TYPE.VERVOSE, string.Format("[DartAPI][영업실적] 당기순이익률 낮음({0}, {1}% / {2}%)", strCodeName, fRate, Config.GetRevenueRate())); return; } string strRef = "DartAPI"; string strTitle = string.Format("영업실적 - {0} {1:n2}%", strCodeName, fRate); if ((Code.m_enType & CodeList.CODE_TYPE.DENIAL) == CodeList.CODE_TYPE.DENIAL) Util.Log(Util.LOG_TYPE.DENIAL, string.Format("[{0}] {1}", strRef, strTitle)); else if ((Code.m_enType & CodeList.CODE_TYPE.DUPLICATED) == CodeList.CODE_TYPE.DUPLICATED) Util.Log(Util.LOG_TYPE.DUPLICATED, string.Format("[{0}] {1}", strRef, strTitle)); else if ((Code.m_enType & CodeList.CODE_TYPE.MANUAL) == CodeList.CODE_TYPE.MANUAL) { Util.Log(Util.LOG_TYPE.MANUAL_CODE, string.Format("[{0}] {1}", strRef, strTitle)); if (m_bBuy == true) { ModelessPopup ManualPopup = new ModelessPopup(this); ManualPopup.SetMessage(string.Format("{0}\n[{1}] {2}\n\n매수하시겠습니까?", DateTime.Now.ToString("[hh:mm:ss]"), strRef, strTitle), Code); ManualPopup.TopMost = true; ManualPopup.Show(); } } else { BuyItem(Code); Util.Log(Util.LOG_TYPE.POSITIVE, string.Format("[{0}] {1}", strRef, strTitle)); } m_CodeList.AddDuplicatedList(Code.m_strCode, Code.m_strName); } public void OnReceivedRightsIssue(string strCodeName) { CodeList.CODE_VALUE Code = m_CodeList.GetCodeByName(strCodeName); if (Code == null) { Util.Log(Util.LOG_TYPE.VERVOSE, string.Format("[DartAPI][제3자배정증자] 종목을 찾을 수 없음({0})", strCodeName)); return; } string strRef = "DartAPI"; string strTitle = string.Format("제3자배정증자 - {0}", strCodeName); if ((Code.m_enType & CodeList.CODE_TYPE.DENIAL) == CodeList.CODE_TYPE.DENIAL) Util.Log(Util.LOG_TYPE.DENIAL, string.Format("[{0}] {1}", strRef, strTitle)); else if ((Code.m_enType & CodeList.CODE_TYPE.DUPLICATED) == CodeList.CODE_TYPE.DUPLICATED) Util.Log(Util.LOG_TYPE.DUPLICATED, string.Format("[{0}] {1}", strRef, strTitle)); else if ((Code.m_enType & CodeList.CODE_TYPE.MANUAL) == CodeList.CODE_TYPE.MANUAL) { Util.Log(Util.LOG_TYPE.MANUAL_CODE, string.Format("[{0}] {1}", strRef, strTitle)); if (m_bBuy == true) { ModelessPopup ManualPopup = new ModelessPopup(this); ManualPopup.SetMessage(string.Format("{0}\n[{1}] {2}\n\n매수하시겠습니까?", DateTime.Now.ToString("[hh:mm:ss]"), strRef, strTitle), Code); ManualPopup.TopMost = true; ManualPopup.Show(); } } else { BuyItem(Code); Util.Log(Util.LOG_TYPE.POSITIVE, string.Format("[{0}] {1}", strRef, strTitle)); } m_CodeList.AddDuplicatedList(Code.m_strCode, Code.m_strName); } public void OnReceivedPatent(string strCodeName) { CodeList.CODE_VALUE Code = m_CodeList.GetCodeByName(strCodeName); if(Code == null) { Util.Log(Util.LOG_TYPE.VERVOSE, string.Format("[DartAPI][특허권취득] 종목을 찾을 수 없음({0})", strCodeName)); return; } string strRef = "DartAPI"; string strTitle = string.Format("특허권취득 - {0}", strCodeName); if((Code.m_enType & CodeList.CODE_TYPE.DENIAL) == CodeList.CODE_TYPE.DENIAL) Util.Log(Util.LOG_TYPE.DENIAL, string.Format("[{0}] {1}", strRef, strTitle)); else if((Code.m_enType & CodeList.CODE_TYPE.DUPLICATED) == CodeList.CODE_TYPE.DUPLICATED) Util.Log(Util.LOG_TYPE.DUPLICATED, string.Format("[{0}] {1}", strRef, strTitle)); else if((Code.m_enType & CodeList.CODE_TYPE.MANUAL) == CodeList.CODE_TYPE.MANUAL) { Util.Log(Util.LOG_TYPE.MANUAL_CODE, string.Format("[{0}] {1}", strRef, strTitle)); if(m_bBuy == true) { ModelessPopup ManualPopup = new ModelessPopup(this); ManualPopup.SetMessage(string.Format("{0}\n[{1}] {2}\n\n매수하시겠습니까?", DateTime.Now.ToString("[hh:mm:ss]"), strRef, strTitle), Code); ManualPopup.TopMost = true; ManualPopup.Show(); } } else { BuyItem(Code); Util.Log(Util.LOG_TYPE.POSITIVE, string.Format("[{0}] {1}", strRef, strTitle)); } m_CodeList.AddDuplicatedList(Code.m_strCode, Code.m_strName); } public void OnReceivedProfitChange(string strCodeName, bool bBlackCheckers, float fProfit) { string strKeyword = string.Format("손익구조 변동({0})", bBlackCheckers?"흑자전환":fProfit+"%"); CodeList.CODE_VALUE Code = m_CodeList.GetCodeByName(strCodeName); if(Code == null) { Util.Log(Util.LOG_TYPE.VERVOSE, string.Format("[DartAPI][{0}] 종목을 찾을 수 없음({1})", strKeyword, strCodeName)); return; } if(bBlackCheckers == false && fProfit < Config.GetProfitChangeRate()) { Util.Log(Util.LOG_TYPE.VERVOSE, string.Format("[DartAPI][{0}] 영업이익률 낮음({1}, {2}% / {3}%)", strKeyword, strCodeName, fProfit, Config.GetProfitChangeRate())); return; } string strRef = "DartAPI"; string strTitle = string.Format("{0} - {1}", strKeyword, strCodeName); if((Code.m_enType & CodeList.CODE_TYPE.DENIAL) == CodeList.CODE_TYPE.DENIAL) Util.Log(Util.LOG_TYPE.DENIAL, string.Format("[{0}] {1}", strRef, strTitle)); else if((Code.m_enType & CodeList.CODE_TYPE.DUPLICATED) == CodeList.CODE_TYPE.DUPLICATED) Util.Log(Util.LOG_TYPE.DUPLICATED, string.Format("[{0}] {1}", strRef, strTitle)); else if((Code.m_enType & CodeList.CODE_TYPE.MANUAL) == CodeList.CODE_TYPE.MANUAL) { Util.Log(Util.LOG_TYPE.MANUAL_CODE, string.Format("[{0}] {1}", strRef, strTitle)); if(m_bBuy == true) { ModelessPopup ManualPopup = new ModelessPopup(this); ManualPopup.SetMessage(string.Format("{0}\n[{1}] {2}\n\n매수하시겠습니까?", DateTime.Now.ToString("[hh:mm:ss]"), strRef, strTitle), Code); ManualPopup.TopMost = true; ManualPopup.Show(); } } else { BuyItem(Code); Util.Log(Util.LOG_TYPE.POSITIVE, string.Format("[{0}] {1}", strRef, strTitle)); } m_CodeList.AddDuplicatedList(Code.m_strCode, Code.m_strName); } public bool IsDuplicatedURL(string strURL) { if(strURL == "") return false; return m_URLs.Any(s => s == strURL); } public void InsertItem(string strTitle, string strName, string strCode, DateTime time, DateTime ResTime, string strURL, string strRef, double dElapseT, bool bInitial) { if (IsDuplicatedURL(strURL) == true) return; int iID = lvList.Items.Count + 1; CodeList.CODE_VALUE Code = m_CodeList.SearchCode(strTitle); if (bInitial == false && Code != null) ProcessSearchAndBuy(new NEWS_ITEM(iID, strTitle, strCode, Code, time, ResTime, strRef, strURL, (float)dElapseT)); var newItem = new ListViewItem(new string[] { iID.ToString(), time.ToString("HH:mm:ss"), ResTime.ToString("HH:mm:ss:fff"), string.Format("{0:n3} ms", dElapseT), strRef, strTitle, (Code != null) ? Code.m_strName : strName, "", "", "", "", "", strURL }); newItem.UseItemStyleForSubItems = false; if (Code == null && strCode != "") newItem.SubItems[chCodeName.Index].BackColor = Color.Gray; m_NewItems.Enqueue(newItem); m_URLs.Add(strURL); Action insert = delegate { if (m_NewItems.IsEmpty == false) { List itemList = new List(); ListViewItem item; while (m_NewItems.TryDequeue(out item)) itemList.Add(item); lvList.BeginUpdate(); lvList.Items.AddRange(itemList.ToArray()); if (lvList.Items.Count < 2) { foreach (ColumnHeader col in lvList.Columns) col.Width = -2; } if (bInitial == false) lvList.Sort(); lvList.EndUpdate(); } }; if (lvList.InvokeRequired) lvList.Invoke(insert); else insert(); } private void SystemTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { if(statusBar.InvokeRequired) { statusBar.BeginInvoke((MethodInvoker)delegate () { statusBar.Items[3].Text = DateTime.Now.ToString("HH:mm:ss"); statusBar.Items[2].Text = m_CybosHelper.GetLimitRemainCountRQ().ToString(); statusBar.Items[0].Text = m_CybosHelper.IsConnected() ? "연결됨" : "연결끊김"; }); } else { statusBar.Items[3].Text = DateTime.Now.ToString("HH:mm:ss"); statusBar.Items[2].Text = m_CybosHelper.GetLimitRemainCountRQ().ToString(); statusBar.Items[0].Text = m_CybosHelper.IsConnected() ? "연결됨" : "연결끊김"; } } private void CrawlTimer_Tick(object sender, EventArgs e) { m_CrawlTimer.Stop(); if(chAutoReload.Checked == true) { m_Crawler.ReadKIND(); m_Crawler.ReadDart(); if(Config.CheckDartAPI()) m_Crawler.ReadDartAPI(); m_Crawler.ReadEtoday(); //m_Crawler.ReadEtoday2(); m_Crawler.ReadAsiaE(); m_Crawler.ReadEdaily(); m_Crawler.ReadMoneyToday(); m_Crawler.ReadFinancialNews(); } m_CrawlTimer.Interval = m_iCrawlInterval; m_CrawlTimer.Start(); } private void UpdateStartPrice(int iID, int iPrice) { if (iID < 0) return; if(lvList.InvokeRequired) { lvList.BeginInvoke((MethodInvoker)delegate () { ListViewItem item = lvList.Items.Cast().FirstOrDefault(s => s.SubItems[chId.Index].Text == iID.ToString()); item.SubItems[chPriceS.Index].Text = iPrice.ToString("n0"); lvList.Columns[chPriceS.Index].Width = -1; }); } else { ListViewItem item = lvList.Items.Cast().FirstOrDefault(s => s.SubItems[chId.Index].Text == iID.ToString()); item.SubItems[chPriceS.Index].Text = iPrice.ToString("n0"); lvList.Columns[chPriceS.Index].Width = -1; } } private void UpdateLowHighPrice(PRICE_CHECK_DATA Data) { if(lvList.InvokeRequired) { lvList.BeginInvoke((MethodInvoker)delegate () { ListViewItem item = lvList.Items.Cast().FirstOrDefault(s => s.SubItems[chId.Index].Text == Data.m_iID.ToString()); item.SubItems[chPriceLow.Index].Text = string.Format("{0:n0}", Data.m_iPriceLow); float fLowRate = (Data.m_iPriceLow-Data.m_iPriceStart)*100/(float)Data.m_iPriceStart; item.SubItems[chPriceLowP.Index].Text = string.Format("{0:n}", fLowRate); if(fLowRate > 0) item.SubItems[chPriceLowP.Index].ForeColor = Color.Red; else if(fLowRate < 0) item.SubItems[chPriceLowP.Index].ForeColor = Color.Blue; item.SubItems[chPriceHigh.Index].Text = string.Format("{0:n0}", Data.m_iPriceHigh); float fLowHigh = (Data.m_iPriceHigh-Data.m_iPriceStart)*100/(float)Data.m_iPriceStart; item.SubItems[chPriceHighP.Index].Text = string.Format("{0:n}", fLowHigh); if(fLowHigh > 0) item.SubItems[chPriceHighP.Index].ForeColor = Color.Red; else if(fLowHigh < 0) item.SubItems[chPriceHighP.Index].ForeColor = Color.Blue; lvList.Columns[chPriceHighP.Index].Width = -1; lvList.Columns[chPriceLowP.Index].Width = -1; }); } else { ListViewItem item = lvList.Items.Cast().FirstOrDefault(s => s.SubItems[chId.Index].Text == Data.m_iID.ToString()); item.SubItems[chPriceLow.Index].Text = string.Format("{0:n0}", Data.m_iPriceLow); float fLowRate = (Data.m_iPriceLow-Data.m_iPriceStart)*100/(float)Data.m_iPriceStart; item.SubItems[chPriceLowP.Index].Text = string.Format("{0:n}", fLowRate); if(fLowRate > 0) item.SubItems[chPriceLowP.Index].ForeColor = Color.Red; else if(fLowRate < 0) item.SubItems[chPriceLowP.Index].ForeColor = Color.Blue; item.SubItems[chPriceHigh.Index].Text = string.Format("{0:n0}", Data.m_iPriceHigh); float fLowHigh = (Data.m_iPriceHigh-Data.m_iPriceStart)*100/(float)Data.m_iPriceStart; item.SubItems[chPriceHighP.Index].Text = string.Format("{0:n}", fLowHigh); if(fLowHigh > 0) item.SubItems[chPriceHighP.Index].ForeColor = Color.Red; else if(fLowHigh < 0) item.SubItems[chPriceHighP.Index].ForeColor = Color.Blue; lvList.Columns[chPriceHighP.Index].Width = -1; lvList.Columns[chPriceLowP.Index].Width = -1; } } private void PriceCheckTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { if(cbPriceCheck.Checked == false) return; m_PriceCheckTimer.Enabled = false; DateTime CurTime = DateTime.Now; foreach(PRICE_CHECK_DATA data in m_PriceCheckList) { if(data.m_iPriceStart == 0) { data.m_iPriceStart = m_CybosHelper.GetCurPrice(data.m_Code); UpdateStartPrice(data.m_iID, data.m_iPriceStart); } else if(data.m_iPriceHigh == 0 && (CurTime - data.m_StartTime).Minutes >= 5) { m_CybosHelper.GetLowHighPrice(data.m_Code, data.m_StartTime, 5, out data.m_iPriceLow, out data.m_iPriceHigh); data.m_iTryCnt++; if(data.m_iPriceHigh > 0) UpdateLowHighPrice(data); } } while(m_PriceCheckList.Count > 0) { PRICE_CHECK_DATA Data; if(m_PriceCheckList.TryPeek(out Data) == false) break; if(Data.m_iTryCnt < 3 && Data.m_iPriceHigh == 0) break; if(Data.m_bLog == false) { Data.m_bLog = m_Excel.AddRow(Data.m_NewsItem.m_NewsTime.ToString("HH:mm:ss:fff"), Data.m_NewsItem.m_ResTime.ToString("HH:mm:ss:fff"), Data.m_NewsItem.m_fElapseT, Data.m_NewsItem.m_strRef, Data.m_NewsItem.m_strTitle, Data.m_NewsItem.m_Code.m_strName, Data.m_iPriceStart, Data.m_iPriceLow, (Data.m_iPriceLow-Data.m_iPriceStart)*100/(float)Data.m_iPriceStart, Data.m_iPriceHigh, (Data.m_iPriceHigh-Data.m_iPriceStart)*100/(float)Data.m_iPriceStart, Data.m_NewsItem.m_strURL); } if(Data.m_bLog == false) break; m_PriceCheckList.TryDequeue(out Data); } m_PriceCheckTimer.Enabled = true; } private void tbInterval_KeyPress(object sender, KeyPressEventArgs e) { if(e.KeyChar == Convert.ToChar(Keys.Enter)) { m_iCrawlInterval = (int)(float.Parse(Regex.Replace(tbInterval.Text, @"\D\.", "")) * 1000); if(m_iCrawlInterval < 1) m_iCrawlInterval = 500; tbInterval.Text = (m_iCrawlInterval / (float)1000).ToString("##0.0") + "초"; } } private void lvList_ColumnClick(object sender, ColumnClickEventArgs e) { SortOrder Order = (lvList.Sorting == SortOrder.Descending || lvList.Sorting == SortOrder.None) ? SortOrder.Ascending : SortOrder.Descending; lvList.BeginUpdate(); lvList.ListViewItemSorter = new ListViewItemComparer(e.Column, Order); lvList.Sorting = Order; lvList.Sort(); lvList.EndUpdate(); } private void lvList_DoubleClick(object sender, EventArgs e) { if(lvList.SelectedItems.Count < 1) return; string strLink = lvList.SelectedItems[0].SubItems[chLink.Index].Text; try { System.Diagnostics.Process.Start(strLink); } catch { } } private void btnConfig_Click(object sender, EventArgs e) { if(m_ConfigForm == null) m_ConfigForm = new ConfigForm(this); FormCollection OpenForms = Application.OpenForms; bool bOpen = false; foreach(Form form in OpenForms) { if(form == m_ConfigForm) { bOpen = true; break; } } if(bOpen == false) { m_ConfigForm.Show(); } else { m_ConfigForm.BringToFront(); } } private void btnManualBuy_Click(object sender, EventArgs e) { if (lvList.SelectedItems.Count <= 0) return; string strCodeName = lvList.SelectedItems[0].SubItems[chCodeName.Index].Text; string strTitle = lvList.SelectedItems[0].SubItems[chTitle.Index].Text; CodeList.CODE_VALUE Code = m_CodeList.GetCodeByName(strCodeName); if (Code == null) Code = m_CodeList.SearchCode(strTitle); if (Code != null) ProcessSearchAndBuy(new NEWS_ITEM(-1, strTitle, Code.m_strCode, Code, DateTime.Now, DateTime.Now, "", "", 0)); } public void OnConfigFormClosing() { m_ConfigForm = null; } public void OnManualCodeClick(int iPrice) { m_CodeList.MakeManualList(iPrice); } public void ApplyDenialCode() { m_CodeList.LoadDenialList(); } public void ApplyDuplicatedCode() { m_CodeList.LoadDuplicatedList(); } public void ApplyPositive() { m_Condition.LoadPositive(); } public void ApplyManual() { m_Condition.LoadManual(); } public void ApplyNegative() { m_Condition.LoadNegative(); } public void ApplySynonym() { m_CodeList.LoadSynonym(); } public void ApplyDuplicatedKeyword() { m_Condition.LoadDuplicatedKeyword(); } private void NewsForm_FormClosing(object sender, FormClosingEventArgs e) { Util.Clear(); } public class HttpResult { public HttpStatusCode StatusCode; public string strData; }; async Task Request(string url, HttpMethod method, string data = null, Dictionary headers = null) { HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url); req.Method = method.ToString(); req.ContentType = "application/json"; if(headers != null) { foreach (var kv in headers) req.Headers[kv.Key] = kv.Value; } if (data != null) { Stream writeStream = req.GetRequestStream(); byte[] buffer = Encoding.UTF8.GetBytes(data); await writeStream.WriteAsync(buffer, 0, buffer.Length); } HttpWebResponse resp = null; HttpResult result = null; try { resp = await req.GetResponseAsync() as HttpWebResponse; } catch (WebException ex) { if (ex.Status == WebExceptionStatus.ProtocolError) resp = ex.Response as HttpWebResponse; } finally { Stream readStream = resp.GetResponseStream(); StreamReader sr = new StreamReader(readStream); result = new HttpResult() { StatusCode = resp.StatusCode, strData = await sr.ReadToEndAsync() }; } return result; } async void SendConfiguration() { var oData = new { Mac = NetworkInterface.GetAllNetworkInterfaces()[0].GetPhysicalAddress().ToString(), Date = DateTime.Now.ToString("yyyy-MM-dd"), Config = Config.GetAllConfig(), Keywords = new { Positive = m_Condition.GetAllPositive(), PositiveForce = m_Condition.GetAllPositiveForce(), Negative = m_Condition.GetAllNegative(), Manual = m_Condition.GetAllManual(), Duplicated = m_Condition.GetAllDuplicated(), }, Codes = new { Deny = m_CodeList.GetAllDeny(), Duplicated = m_CodeList.GetAllDuplicated(), Manual = m_CodeList.GetAllManual(), }, Synonym = m_CodeList.GetAllSynonym(), }; string serverURL = "http://mjjo53.us.to:9200"; string index = "trading-news"; string doc = "default"; string id = $"{oData.Mac}-{oData.Date}"; JObject data = JObject.FromObject(oData); string json = data.ToString(Newtonsoft.Json.Formatting.Indented); Dictionary headers = new Dictionary(); headers["Authorization"] = "Basic dHJhZGVyOnNidG1hb2Fv"; var result = await Request($"{serverURL}/{index}/{doc}/{id}?pretty", HttpMethod.Post, json, headers); } private void chBuy_CheckedChanged(object sender, EventArgs e) { m_bBuy = chBuy.Checked; if(m_bBuy == true && Config.GetAccount() == "") { chBuy.Checked = false; MessageBox.Show("계좌를 선택해주시기 바랍니다"); return; } if (m_bBuy == true) { //FileTransfer ft = new FileTransfer(); //string today = DateTime.Now.ToString("yyyy-MM-dd"); //string macAddr = NetworkInterface.GetAllNetworkInterfaces()[0].GetPhysicalAddress().ToString(); //ft.SendDir("/configure", macAddr + "/NewsCrawler/" + today); SendConfiguration(); Util.Log(Util.LOG_TYPE.VERVOSE, "매수 시작"); } else { Util.Log(Util.LOG_TYPE.VERVOSE, "매수 취소"); } } public string[] GetAccounts() { return m_CybosHelper.GetAccounts(); } public void ApplyAccount(string strAccount, string strAccountSub) { Config.SetAccount(strAccount, strAccountSub); } private void btClearDuplicate_Click(object sender, EventArgs e) { DialogResult dialogResult = MessageBox.Show("중복 종목을 삭제합니다", "확인", MessageBoxButtons.YesNo); if(dialogResult == DialogResult.Yes) m_CodeList.ClearDuplicatedList(); } } class ListViewItemComparer : IComparer { int m_iColumn = 0; SortOrder m_Order = SortOrder.Ascending; public ListViewItemComparer(int column, SortOrder Order) { m_iColumn = column; m_Order = Order; } public int Compare(object x, object y) { ListViewItem item1 = (ListViewItem)x; ListViewItem item2 = (ListViewItem)y; double num1; double num2; if(double.TryParse(item1.SubItems[m_iColumn].Text, out num1) && double.TryParse(item2.SubItems[m_iColumn].Text, out num2)) { if (m_Order == SortOrder.Ascending) return (num1 > num2) ? 1 : -1; else return (num1 > num2) ? -1 : 1; } else { if(m_Order == SortOrder.Ascending) return string.Compare(item1.SubItems[m_iColumn].Text, item2.SubItems[m_iColumn].Text); else return string.Compare(item2.SubItems[m_iColumn].Text, item1.SubItems[m_iColumn].Text); } } } }