using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace AutoSellerNS { public class PriceNode { public int m_iTime; public int m_iPrice; public int m_iAskPrice; public int m_iBidPrice; public int m_iAccDealCnt; public int m_iDealCnt; public double m_dAvg; public double m_dSD; public double m_dSellLimit; public int m_iSellCnt; public override string ToString() { return $"{m_iPrice}({m_dAvg})"; } } 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_iOpenigPrice = 0; 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 = Config.GetBidCount(); int m_iPrevTime = 0; public async void OnRecievedPrice() { bool bOpeningHour = (m_StockCur.GetHeaderValue(19) == '2'); m_iCurPrice = m_StockCur.GetHeaderValue(13); if (m_iOpenigPrice == 0) m_iOpenigPrice = m_iCurPrice; int iTime = m_StockCur.GetHeaderValue(18); int iConclusionCnt = m_StockCur.GetHeaderValue(17); int iAccDealCnt = m_StockCur.GetHeaderValue(9); int iDealCnt = 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 (bOpeningHour == true) { DateTime RealTime = DateTime.Now; int iRealTime = RealTime.Hour * 10000 + RealTime.Minute * 100 + RealTime.Second; List lastNPrice = null; lock (m_PriceList) { if (Config.GetListSize() == 0) lastNPrice = m_PriceList.Select(s => s.m_iPrice).ToList(); else lastNPrice = m_PriceList.Skip(Math.Max(0, m_PriceList.Count - (Config.GetListSize() - 1))).Select(s => s.m_iPrice).ToList(); lastNPrice.Add(m_iCurPrice); } double dAverage = lastNPrice.Average(); double sumOfSquaresOfDifferences = lastNPrice.Select(val => Math.Pow((val - dAverage) / m_CybosHelper.GetUnitValue(val), 2)).Sum(); double dStdDev = Math.Sqrt(sumOfSquaresOfDifferences / lastNPrice.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) { await m_CybosHelper.SellItem(m_strCode, m_Listener.GetSellableCount(m_strCode), m_aiAskPrice[0]-m_CybosHelper.GetUnitValue(m_iCurPrice)); 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) { await m_CybosHelper.SellItem(m_strCode, m_Listener.GetSellableCount(m_strCode), m_aiAskPrice[0]-m_CybosHelper.GetUnitValue(m_iCurPrice)); 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) { await m_CybosHelper.SellItem(m_strCode, m_Listener.GetSellableCount(m_strCode), m_aiAskPrice[0]-m_CybosHelper.GetUnitValue(m_iCurPrice)); Util.Log(Util.LOG_TYPE.SELL, string.Format("[시간제한 매도] {0} ({1}초) (현재가 {2:n0}원, 최고가 {3:n0}원)", m_strCodeName, iTimeDiff, m_iCurPrice, m_iMaxPrice)); } lock (m_PriceList) { m_PriceList.Add(new PriceNode { m_iTime = iTime, m_iPrice = m_iCurPrice, m_iAskPrice = iAskPrice, m_iBidPrice = iBidPrice, m_iAccDealCnt = iAccDealCnt, m_iDealCnt = iDealCnt, m_dAvg = dAverage, m_dSD = dStdDev, m_dSellLimit = m_dCheckCountLimit, m_iSellCnt = m_iCheckCount, }); } } m_Listener.OnReceivedCurPrice(m_strCode, m_iCurPrice, m_iMaxPrice, m_dCheckCountLimit, m_iCheckCount, bOpeningHour); 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); } public override string ToString() { return $"[{m_strCodeName}:{m_strCode}] {m_iCurPrice}"; } } }