using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace AutoSellerNS { public class CybosHelper { public class STOCK_CUR_ITEM { public AutoSeller m_Listener = null; public CybosHelper m_CybosHelper = null; public string m_strCode; public string m_strCodeName; public DSCBO1Lib.StockCur m_StockCur = null; public DSCBO1Lib.StockJpbid m_Jpbid = null; public int[] m_aiBidPrice = new int[10]; public int[] m_aiBidCount = new int[10]; public int[] m_aiAskPrice = new int[10]; public int[] m_aiAskCount = new int[10]; public int m_iCurPrice = 0; public int m_iMaxPrice = 0; public int m_iCheckCount = 0; public int m_iTrailingCount = 0; // real time, price time, price public List> m_PriceList = new List>(); public double m_dCheckCountLimit = 5; int m_iPrevTime = 0; public void OnRecievedPrice() { bool bReal = (m_StockCur.GetHeaderValue(19) == '2'); m_iCurPrice = m_StockCur.GetHeaderValue(13); int iTime = m_StockCur.GetHeaderValue(18); int iConclusionCnt = m_StockCur.GetHeaderValue(17); int iTimeDiff = 0; if(m_iPrevTime > 0) iTimeDiff = ((iTime/10000)*60*60 + ((iTime%10000)/100)*60 + (iTime%100)) - ((m_iPrevTime/10000)*60*60 + ((m_iPrevTime%10000)/100)*60 + (m_iPrevTime%100)); if(bReal == true) { DateTime RealTime = DateTime.Now; int iRealTime = RealTime.Hour * 10000 + RealTime.Minute * 100 + RealTime.Second; m_PriceList.Add(new Tuple(iRealTime, iTime, m_iCurPrice)); double dAverage = (float)m_PriceList.Average(s => s.Item3); double sumOfSquaresOfDifferences = m_PriceList.Select(val => Math.Pow((val.Item3-dAverage)/m_CybosHelper.GetUnitValue(val.Item3), 2)).Sum(); double dStdDev = Math.Sqrt(sumOfSquaresOfDifferences / m_PriceList.Count); if(dStdDev >= Config.GetFastSD()) { if(m_iCurPrice >= dAverage) m_dCheckCountLimit += Config.GetFastUp(); else m_dCheckCountLimit -= Config.GetFastDown(); } else if(dStdDev <= Config.GetSlowSD()) { if(m_iCurPrice >= dAverage) m_dCheckCountLimit += Config.GetSlowUp(); else m_dCheckCountLimit -= Config.GetSlowDown(); } m_dCheckCountLimit -= iTimeDiff*Config.GetTimeDown(); if(m_iCurPrice > m_iMaxPrice) m_iTrailingCount = 0; m_iMaxPrice = Math.Max(m_iCurPrice, m_iMaxPrice); int iAskPrice = m_StockCur.GetHeaderValue(7); int iBidPrice = m_StockCur.GetHeaderValue(8); if(m_iCurPrice*iConclusionCnt > Config.GetIgnorePrice()) { if(m_iCurPrice <= iBidPrice) m_iCheckCount++; else m_iCheckCount = 0; } if(m_iCheckCount >= m_dCheckCountLimit && m_Listener.IsSelling() == true) { m_CybosHelper.SellItem(m_strCode, m_Listener.GetSellableCount(m_strCode), m_aiAskPrice[0]); Util.Log(Util.LOG_TYPE.SELL, string.Format("[조건 완료 매도] {0} ({1}회) (현재가 {2:n0}원, 최고가 {3:n0}원)", m_strCodeName, Config.GetBidCount(), m_iCurPrice, m_iMaxPrice)); } if(m_iCurPrice < (m_iMaxPrice*(100.0f-Config.GetTrailingRate())/100.0f)) m_iTrailingCount++; if(m_iTrailingCount >= Config.GetTrailingCnt() && m_Listener.IsSelling() == true) { m_CybosHelper.SellItem(m_strCode, m_Listener.GetSellableCount(m_strCode), m_aiAskPrice[0]); Util.Log(Util.LOG_TYPE.SELL, string.Format("[트레일링 매도] {0} ({1}% {2}회) (현재가 {3:n0}원, 최고가 {4:n0}원)", m_strCodeName, Config.GetTrailingRate(), Config.GetTrailingCnt(), m_iCurPrice, m_iMaxPrice)); } if(iTimeDiff >= Config.GetTimeLimit() && m_Listener.IsSelling() == true) { m_CybosHelper.SellItem(m_strCode, m_Listener.GetSellableCount(m_strCode), m_aiAskPrice[0]); Util.Log(Util.LOG_TYPE.SELL, string.Format("[시간제한 매도] {0} ({1}초) (현재가 {2:n0}원, 최고가 {3:n0}원)", m_strCodeName, iTimeDiff, m_iCurPrice, m_iMaxPrice)); } } m_Listener.OnReceivedCurPrice(m_strCode, m_iCurPrice, m_iMaxPrice, m_dCheckCountLimit, m_iCheckCount, bReal); m_iPrevTime = iTime; } public void OnReceivedCall() { for(int i=0; i<5; i++) { m_aiBidPrice[i] = m_Jpbid.GetHeaderValue(4 + 4*i); m_aiBidCount[i] = m_Jpbid.GetHeaderValue(6 + 4*i); m_aiAskPrice[i] = m_Jpbid.GetHeaderValue(3 + 4*i); m_aiAskCount[i] = m_Jpbid.GetHeaderValue(5 + 4*i); } for (int i = 0; i < 5; i++) { m_aiBidPrice[i+5] = m_Jpbid.GetHeaderValue(28 + 4*i); m_aiBidCount[i+5] = m_Jpbid.GetHeaderValue(30 + 4*i); m_aiAskPrice[i+5] = m_Jpbid.GetHeaderValue(27 + 4*i); m_aiAskCount[i+5] = m_Jpbid.GetHeaderValue(29 + 4*i); } m_Listener.OnReceivedCall(m_strCode, 0, m_aiBidPrice, m_aiBidCount, m_aiAskPrice, m_aiAskCount); } } AutoSeller m_Listener = null; CPUTILLib.CpCybos m_CPCybos = new CPUTILLib.CpCybos(); CPFORETRADELib.CpForeTdUtil m_CPUtil = new CPFORETRADELib.CpForeTdUtil(); DSCBO1Lib.CpConclusion m_CpConclusion = new DSCBO1Lib.CpConclusion(); CPTRADELib.CpTd6033 m_6033 = new CPTRADELib.CpTd6033(); Dictionary m_aStockCur = new Dictionary(); object m_NCItemLock = new object(); public CybosHelper(AutoSeller Listener) { m_Listener = Listener; } public void InitCybos() { short iResult = m_CPUtil.TradeInit(); switch (iResult) { case -1: Util.Log(Util.LOG_TYPE.ERROR, "[TradeInit] 오류"); break; case 0: Util.Log(Util.LOG_TYPE.VERVOSE, "[TradeInit] 로그인 되었습니다"); break; case 1: Util.Log(Util.LOG_TYPE.ERROR, "[TradeInit] 업무 키 입력 잘못됨"); break; case 2: Util.Log(Util.LOG_TYPE.ERROR, "[TradeInit] 계좌 비밀번호가 잘못되었습니다"); break; case 3: Util.Log(Util.LOG_TYPE.ERROR, "[TradeInit] 취소되었습니다"); break; } m_Listener.SetAccountList(m_CPUtil.AccountNumber); m_CpConclusion.Received += CpConclusion_Received; m_CpConclusion.Subscribe(); } public void SavePrice(STOCK_CUR_ITEM item) { if (Directory.Exists(Util.GetLogPath()) == false) Directory.CreateDirectory(Util.GetLogPath()); string strToday = DateTime.Now.ToString("yyyy-MM-dd"); string strFilePath = Util.GetLogPath() + "/price-" + strToday + item.m_strCodeName + ".txt"; string strMessage = ""; foreach (var pair in item.m_PriceList) { strMessage = string.Format("[{0}] {1} ({2})", pair.Item2, pair.Item3, pair.Item1); File.AppendAllText(strFilePath, strMessage + Environment.NewLine, new UTF8Encoding(true)); } } public List UpdateItems() { List aItems = new List(); if (Config.GetAccount() == "") return aItems; m_6033.SetInputValue(0, Config.GetAccount()); m_6033.SetInputValue(1, Config.GetSubAccount()); m_6033.BlockRequest2(1); string strCodeList = ""; bool bContinue = true; while(bContinue == true) { int iCount = m_6033.GetHeaderValue(7); for(int i = 0; i < iCount; i++) { AutoSeller.ITEM Item = new AutoSeller.ITEM(); Item.m_strCodeName = m_6033.GetDataValue(0, i); if(Item.m_strCodeName != "") { Item.m_strCode = m_6033.GetDataValue(12, i); Item.m_iItemCnt = m_6033.GetDataValue(7, i); Item.m_iAssessedValue = m_6033.GetDataValue(9, i); Item.m_iValuationGains = m_6033.GetDataValue(10, i); Item.m_dYield = m_6033.GetDataValue(11, i); Item.m_iAvailableQuantity = m_6033.GetDataValue(15, i); Item.m_dBookUnitPrice = m_6033.GetDataValue(17, i); Item.m_iProfitUnitPrice = m_6033.GetDataValue(18, i); if(strCodeList.Length > 0) strCodeList += ","; strCodeList += Item.m_strCode; aItems.Add(Item); } } bContinue = (m_6033.Continue != 0); if(bContinue == true) m_6033.BlockRequest2(1); } if (strCodeList.Length > 0) { DSCBO1Lib.StockMst2 StockMst = new DSCBO1Lib.StockMst2(); StockMst.SetInputValue(0, strCodeList); StockMst.BlockRequest2(1); int iCnt = StockMst.GetHeaderValue(0); for (int i = 0; i < iCnt; i++) { string strCode = StockMst.GetDataValue(0, i); int iPrice = StockMst.GetDataValue(3, i); AutoSeller.ITEM Item = aItems.FirstOrDefault(s => s.m_strCode == strCode); if (Item != default(AutoSeller.ITEM)) Item.m_iCurPrice = iPrice; } } // sync List aRemoveKeys = new List(); foreach(var Item in m_aStockCur) { if(aItems.Any(s => s.m_strCode == Item.Key) == false) aRemoveKeys.Add(Item.Key); } foreach(var Key in aRemoveKeys) { m_aStockCur[Key].m_StockCur.Unsubscribe(); m_aStockCur[Key].m_Jpbid.Unsubscribe(); SavePrice(m_aStockCur[Key]); m_aStockCur.Remove(Key); } return aItems; } static int iUpdateNCIdx = 1; public List UpdateNC() { int iIdx = iUpdateNCIdx++; Util.Log(Util.LOG_TYPE.DEBUG, string.Format("UpdateNC Start ({0}, {1}, {2}, {3})", iIdx, GetLimitRemainCountRQ(), GetLimitRemainCountSB(), GetLimitRemainCountTrade() )); while(GetLimitRemainCountTrade() < 1) Thread.Sleep(500); List NCItems = new List(); CPTRADELib.CpTd5339 CP5339 = new CPTRADELib.CpTd5339(); CP5339.SetInputValue(0, Config.GetAccount()); CP5339.SetInputValue(1, Config.GetSubAccount()); CP5339.BlockRequest2(1); bool bContinue = true; while(bContinue) { int iCnt = CP5339.GetHeaderValue(5); Console.WriteLine("icnt : {0}", iCnt); for(int i = 0; i s.Key == Item.m_strCode) == false) { STOCK_CUR_ITEM StockCur = new STOCK_CUR_ITEM(); StockCur.m_Listener = m_Listener; StockCur.m_CybosHelper = this; StockCur.m_strCode = Item.m_strCode; StockCur.m_strCodeName = Item.m_strCodeName; DSCBO1Lib.StockJpbid2 JpBid = new DSCBO1Lib.StockJpbid2(); JpBid.SetInputValue(0, Item.m_strCode); JpBid.BlockRequest2(1); for(int i=0; i<10; i++) { StockCur.m_aiAskPrice[i] = JpBid.GetDataValue(0, i); StockCur.m_aiAskCount[i] = JpBid.GetDataValue(2, i); StockCur.m_aiBidPrice[i] = JpBid.GetDataValue(1, i); StockCur.m_aiBidCount[i] = JpBid.GetDataValue(3, i); } StockCur.m_StockCur = new DSCBO1Lib.StockCur(); StockCur.m_StockCur.SetInputValue(0, Item.m_strCode); StockCur.m_StockCur.Received += StockCur.OnRecievedPrice; StockCur.m_StockCur.Subscribe(); StockCur.m_Jpbid = new DSCBO1Lib.StockJpbid(); StockCur.m_Jpbid.SetInputValue(0, Item.m_strCode); StockCur.m_Jpbid.Received += StockCur.OnReceivedCall; StockCur.m_Jpbid.SubscribeLatest(); StockCur.m_iCurPrice = Item.m_iCurPrice; StockCur.m_iMaxPrice = Item.m_iCurPrice; m_aStockCur.Add(Item.m_strCode, StockCur); } } public int GetUnitValue(int iValue) { int iUnit = 1; if(iValue < 1000) iUnit = 1; else if(iValue < 5000) iUnit = 5; else if(iValue < 10000) iUnit = 10; else if(iValue < 50000) iUnit = 50; else if(iValue < 100000) iUnit = 100; else if(iValue < 500000) iUnit = 500; else iUnit = 1000; return iUnit; } int GetCallUnitValue(int iValue) { int iUnit = GetUnitValue(iValue); return (iValue/iUnit)*iUnit; } static int iSellIdx = 1; public void SellItem(string strCode, int iCnt, int iAskPrice) { int iIdx = iSellIdx++; Util.Log(Util.LOG_TYPE.DEBUG, string.Format("SellItem Start ({0})", iIdx)); int iSellPrice = iAskPrice-GetUnitValue(iAskPrice); CPTRADELib.CpTd0311 Td0311 = new CPTRADELib.CpTd0311(); Td0311.SetInputValue(0, "1"); Td0311.SetInputValue(1, Config.GetAccount()); Td0311.SetInputValue(2, Config.GetSubAccount()); Td0311.SetInputValue(3, strCode); Td0311.SetInputValue(4, iCnt); Td0311.SetInputValue(5, iSellPrice); Td0311.SetInputValue(8, "01"); Td0311.BlockRequest2(1); Util.Log(Util.LOG_TYPE.DEBUG, string.Format("SellItem End ({0})", iIdx)); } static int iCancelIdx = 1; public void CancelItem(string strCode, int iOrgOrderNo) { int iIdx = iCancelIdx++; Util.Log(Util.LOG_TYPE.DEBUG, string.Format("CancelItem Start ({0})", iIdx)); CPTRADELib.CpTd0314 Td0314 = new CPTRADELib.CpTd0314(); Td0314.SetInputValue(1, iOrgOrderNo); Td0314.SetInputValue(2, Config.GetAccount()); Td0314.SetInputValue(3, Config.GetSubAccount()); Td0314.SetInputValue(4, strCode); Td0314.SetInputValue(5, 0); Td0314.BlockRequest2(1); Util.Log(Util.LOG_TYPE.DEBUG, string.Format("CancelItem End ({0})", iIdx)); } static int iCorrectIdx = 1; public void CorrectionItem(string strCode, int iOrgOrderNo, int iCnt, int iAskPrice) { int iIdx = iCorrectIdx++; Util.Log(Util.LOG_TYPE.DEBUG, string.Format("CorrectionItem Start ({0})", iIdx)); int iSellPrice = iAskPrice-GetUnitValue(iAskPrice); //CancelItem(strCode, iOrgOrderNo); //Thread.Sleep(1000); //SellItem(strCode, iCnt, iAskPrice); CPTRADELib.CpTd0313 Td0313 = new CPTRADELib.CpTd0313(); Td0313.SetInputValue(1, iOrgOrderNo); Td0313.SetInputValue(2, Config.GetAccount()); Td0313.SetInputValue(3, Config.GetSubAccount()); Td0313.SetInputValue(4, strCode); Td0313.SetInputValue(5, 0); Td0313.SetInputValue(6, iSellPrice); Td0313.BlockRequest2(1); Util.Log(Util.LOG_TYPE.DEBUG, string.Format("CorrectionItem End ({0})", iIdx)); } } }