/// <summary> /// 获取前一天下跌的股票 /// </summary> public static List <String> getLastDayCodes(int type) { List <String> ret = new List <String>(); foreach (String code in m_historyDatas.Keys) { List <SecurityData> sds = m_historyDatas[code]; SecurityData sd = sds[sds.Count - 1]; if (type == 0) { if (sd.m_close < sd.m_open) { ret.Add(code); } } else if (type == 1) { if (sd.m_close > sd.m_open) { ret.Add(code); } } } return(ret); }
/// <summary> /// 计算指标 /// </summary> /// <param name="id">指标ID</param> /// <param name="code">代码</param> /// <param name="path">路径</param> /// <param name="type">类型</param> /// <param name="cycle">周期</param> /// <param name="subscription">复权方式</param> /// <param name="date">日期</param> /// <param name="open">开盘价</param> /// <param name="high">最高价</param> /// <param name="low">最低价</param> /// <param name="close">收盘价</param> /// <param name="volume">成交量</param> /// <param name="amount">成交额</param> /// <returns>返回数据</returns> public static double[] calculateIndicatorExtern(int id, String code, ref double result) { if (m_indicators.ContainsKey(id)) { FCScript indicator = m_indicators[id]; List <FCScript> indicators = new List <FCScript>(); indicators.Add(indicator); List <SecurityData> datas = new List <SecurityData>(); if (SecurityService.m_historyDatas.ContainsKey(code)) { datas = SecurityService.m_historyDatas[code]; SecurityLatestData latestData = null; if (SecurityService.m_latestDatas.ContainsKey(code)) { latestData = SecurityService.m_latestDatas[code]; } if (latestData != null) { SecurityData newData = new SecurityData(); getSecurityData(latestData, latestData.m_lastClose, 1440, 0, ref newData); if (datas.Count == 0) { datas.Add(newData); } else { if (newData.m_date > datas[datas.Count - 1].m_date) { datas.Add(newData); } else { datas[datas.Count - 1] = newData; } } } FCDataTable dataSource = indicator.DataSource; int[] fields = new int[] { KeyFields.CLOSE_INDEX, KeyFields.HIGH_INDEX, KeyFields.LOW_INDEX, KeyFields.OPEN_INDEX, KeyFields.VOL_INDEX, KeyFields.AMOUNT_INDEX }; SecurityDataHelper.bindHistoryDatas(m_chart, dataSource, indicators, fields, datas);; int rowsCount = dataSource.RowsCount; int variablesSize = indicator.MainVariables.Count; double[] list = new double[variablesSize]; if (rowsCount > 0) { int pos = 0; foreach (String name in indicator.MainVariables.Keys) { int field = indicator.MainVariables[name]; double value = dataSource.get2(rowsCount - 1, field); list[pos] = value; pos++; } } result = indicator.m_result; dataSource.clear(); return(list); } } return(null); }
/// <summary> /// 获取周线的历史数据 /// </summary> /// <param name="weekDatas">周线历史数据</param> /// <param name="dayDatas">日线历史数据</param> /// <returns>状态</returns> public static int getHistoryWeekDatas(List <SecurityData> weekDatas, List <SecurityData> dayDatas) { int weekDatasSize = dayDatas.Count; if (weekDatasSize > 0) { SecurityData weekData = new SecurityData(); weekData.copy(dayDatas[0]); int lDayOfWeek = 0, lDays = 0; for (int i = 0; i < weekDatasSize; i++) { SecurityData dayData = new SecurityData(); dayData.copy(dayDatas[i]); int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0, ms = 0, days = (int)dayData.m_date / (3600 * 24); FCStr.getDateByNum(dayData.m_date, ref year, ref month, ref day, ref hour, ref minute, ref second, ref ms); int dow = dayOfWeek(year, month, day); bool isNextWeek = true; bool add = false; if (days - lDays <= 5) { if (days != lDays) { isNextWeek = dow <= lDayOfWeek; } } if (isNextWeek || i == weekDatasSize - 1) { add = true; } if (!isNextWeek) { weekData.m_close = dayData.m_close; weekData.m_amount += dayData.m_amount; weekData.m_volume += dayData.m_volume; if (weekData.m_high < dayData.m_high) { weekData.m_high = dayData.m_high; } if (weekData.m_low > dayData.m_low) { weekData.m_low = dayData.m_low; } } if (add) { weekDatas.Add(weekData); weekData = dayData; } if (isNextWeek && i == weekDatasSize - 1) { weekData = dayData; weekDatas.Add(weekData); } lDayOfWeek = dow; lDays = days; } } return(1); }
/// <summary> /// 获取通达信的历史数据 /// </summary> /// <param name="str">数据字符串</param> /// <param name="datas">历史数据</param> /// <returns>状态</returns> public static int getHistoryDatasByTdxStr(String str, List <SecurityData> datas) { String[] strs = str.Split(new String[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); int strLen = strs.Length; for (int i = 2; i < strLen - 1; i++) { String[] strs2 = strs[i].Split(','); int strs2Size = strs2.Length; if (strs2Size >= 7) { String[] dateStrs = strs2[0].Split('-'); int year = 0, month = 0, day = 0, hour = 0, minute = 0; if (dateStrs.Length == 3) { year = FCStr.convertStrToInt(dateStrs[0]); month = FCStr.convertStrToInt(dateStrs[1]); day = FCStr.convertStrToInt(dateStrs[2]); } int si = 1; if (strs2Size == 8) { si = 2; hour = FCStr.convertStrToInt(strs2[1].Substring(0, 2)); minute = FCStr.convertStrToInt(strs2[1].Substring(2, 2)); } double open = FCStr.convertStrToDouble(strs2[si]); double high = FCStr.convertStrToDouble(strs2[si + 1]); double low = FCStr.convertStrToDouble(strs2[si + 2]); double close = FCStr.convertStrToDouble(strs2[si + 3]); double volume = FCStr.convertStrToDouble(strs2[si + 4]); double amount = FCStr.convertStrToDouble(strs2[si + 5]); if (volume == 0) { continue; } if (year != 0 && month != 0 && day != 0) { SecurityData securityData = new SecurityData(); if (hour != 0 || minute != 0) { securityData.m_date = FCStr.getDateNum(year, month, day, hour, minute, 0, 0) - 300; } else { securityData.m_date = FCStr.getDateNum(year, month, day, 0, 0, 0, 0); } securityData.m_open = open; securityData.m_high = high; securityData.m_low = low; securityData.m_close = close; securityData.m_volume = volume; securityData.m_amount = amount; datas.Add(securityData); } } } return(1); }
/// <summary> /// 复制数据 /// </summary> /// <param name="data">数据</param> public void copy(SecurityData data) { m_close = data.m_close; m_date = data.m_date; m_high = data.m_high; m_low = data.m_low; m_open = data.m_open; m_volume = data.m_volume; m_amount = data.m_amount; }
/// <summary> /// 获取月线的历史数据 /// </summary> /// <param name="weekDatas">月线历史数据</param> /// <param name="dayDatas">日线历史数据</param> /// <returns>状态</returns> public static int getHistoryMonthDatas(List <SecurityData> monthDatas, List <SecurityData> dayDatas) { int monthDatasSize = dayDatas.Count; if (monthDatasSize > 0) { SecurityData monthData = new SecurityData(); monthData.copy(dayDatas[0]); int lYear = 0, lMonth = 0, lDay = 0; for (int i = 0; i < monthDatasSize; i++) { SecurityData dayData = new SecurityData(); dayData.copy(dayDatas[i]); int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0, ms = 0; FCStr.getDateByNum(dayData.m_date, ref year, ref month, ref day, ref hour, ref minute, ref second, ref ms); bool isNextMonth = year * 12 + month > lYear * 12 + lMonth; bool add = false; if (i == monthDatasSize - 1 || (i > 0 && isNextMonth)) { add = true; } if (!isNextMonth) { monthData.m_close = dayData.m_close; monthData.m_amount += dayData.m_amount; monthData.m_volume += dayData.m_volume; if (monthData.m_high < dayData.m_high) { monthData.m_high = dayData.m_high; } if (monthData.m_low > dayData.m_low) { monthData.m_low = dayData.m_low; } } if (add) { monthDatas.Add(monthData); monthData = dayData; } if (isNextMonth && i == monthDatasSize - 1) { monthData = dayData; monthDatas.Add(monthData); } lYear = year; lMonth = month; lDay = day; } } return(1); }
/// <summary> /// 获取分时数据 /// </summary> public static void getMinuteDatas() { if (m_minuteDatas.Count > 0) { return; } String appPath = DataCenter.getAppPath(); foreach (String code in m_codedMap.Keys) { String fileName = m_newFileDir + FCStrEx.convertDBCodeToFileName(code); if (!FCFile.isFileExist(fileName)) { fileName = m_newFileDir + FCStrEx.convertDBCodeToSinaCode(code).ToUpper() + ".txt"; } if (FCFile.isFileExist(fileName)) { String text = ""; FCFile.read(fileName, ref text); List <SecurityData> datas = new List <SecurityData>(); StockService.getHistoryDatasByMinuteStr(text, datas); if (datas.Count > 0) { int rindex = 0; int dataSize = datas.Count; while (rindex < dataSize) { SecurityData d = datas[rindex]; if (rindex == 0) { d.m_avgPrice = d.m_close; } else { SecurityData ld = datas[rindex - 1]; d.m_avgPrice = (ld.m_avgPrice * rindex + d.m_close) / (rindex + 1); } rindex++; } m_minuteDatas[code] = datas; } } } }
/// <summary> /// 绑定历史数据 /// </summary> /// <param name="chart">股票控件</param> /// <param name="dataSource">数据源</param> /// <param name="indicators">指标</param> /// <param name="fields">字段</param> /// <param name="historyDatas">历史数据</param> public static void bindHistoryDatas(FCChart chart, FCDataTable dataSource, List <FCScript> indicators, int[] fields, List <SecurityData> historyDatas) { dataSource.clear(); int size = historyDatas.Count; dataSource.setRowsCapacity(size + 10); dataSource.setRowsGrowStep(100); int columnsCount = dataSource.ColumnsCount; for (int i = 0; i < size; i++) { SecurityData securityData = historyDatas[i]; if (dataSource == chart.DataSource) { insertData(chart, dataSource, fields, securityData); } else { double[] ary = new double[columnsCount]; ary[0] = securityData.m_close; ary[1] = securityData.m_high; ary[2] = securityData.m_low; ary[3] = securityData.m_open; ary[4] = securityData.m_volume; for (int j = 5; j < columnsCount; j++) { ary[j] = double.NaN; } dataSource.AddRow(securityData.m_date, ary, columnsCount); } } int indicatorsSize = indicators.Count; for (int i = 0; i < indicatorsSize; i++) { indicators[i].onCalculate(0); } }
/// <summary> /// 数据落地线程工作 /// </summary> public static void startWork3() { //复制数据 loadHistoryDatas(); //getMinuteDatas(); //新旧数据合并 foreach (String oCode in m_historyDatas.Keys) { if (!m_latestDatas.ContainsKey(oCode) || !m_historyDatas.ContainsKey(oCode)) { continue; } SecurityLatestData securityLatestData = m_latestDatas[oCode]; List <SecurityData> oldSecurityDatas = m_historyDatas[oCode]; SecurityData oldSecurityData = oldSecurityDatas[oldSecurityDatas.Count - 1]; int myear = 0, mmonth = 0, mday = 0, mhour = 0, mmin = 0, msec = 0, mmsec = 0; FCStr.getDateByNum(oldSecurityData.m_date, ref myear, ref mmonth, ref mday, ref mhour, ref mmin, ref msec, ref mmsec); int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0, msec2 = 0; FCStr.getDateByNum(securityLatestData.m_date, ref year, ref month, ref day, ref hour, ref min, ref sec, ref msec2); if (year >= myear && month >= mmonth && day >= mday) { SecurityData nSecurityData = new SecurityData(); nSecurityData.m_amount = securityLatestData.m_amount; nSecurityData.m_close = securityLatestData.m_close; nSecurityData.m_date = securityLatestData.m_date; nSecurityData.m_high = securityLatestData.m_high; nSecurityData.m_low = securityLatestData.m_low; nSecurityData.m_open = securityLatestData.m_open; nSecurityData.m_volume = securityLatestData.m_volume; if (day == mday) { m_historyDatas[oCode].RemoveAt(m_historyDatas[oCode].Count - 1); } m_historyDatas[oCode].Add(nSecurityData); } } String outputFileTemplate = DataCenter.getAppPath() + "\\day\\{0}.txt"; String fileInfo = "{0} {1} 日线 前复权\r\n"; String title = " 日期 开盘 最高 最低 收盘 成交量 成交额\r\n"; String lineTemp = "{0},{1},{2},{3},{4},{5},{6}\r\n"; String timeFormatStr = "yyyy-MM-dd"; //写入文件 foreach (String code in m_historyDatas.Keys) { List <SecurityData> temp3 = m_historyDatas[code]; StringBuilder strbuff = new StringBuilder(); strbuff.Append(String.Format(fileInfo, m_codedMap[code].m_code, m_codedMap[code].m_name)); strbuff.Append(title); foreach (SecurityData sdt in temp3) { strbuff.Append(String.Format(lineTemp, // FCStr.convertNumToDate(sdt.m_date).ToString(timeFormatStr), // sdt.m_open, // sdt.m_high, // sdt.m_low, // sdt.m_close, // sdt.m_volume, // sdt.m_amount)); } strbuff.Append("数据来源:通达信\r\n"); FCFile.write(String.Format(outputFileTemplate, code), strbuff.ToString()); } }
/// <summary> /// 检查是否开仓 /// </summary> /// <param name="latestData">最新数据</param> /// <param name="datas">数据</param> /// <param name="n">创新高参数</param> /// <param name="m">均线参数</param> /// <returns>是否开仓 1:买开 2:卖开 0:不开仓</returns> public static void checkOpen(SecurityLatestData latestData, List <SecurityData> datas, int n, int m) { int datasSize = datas.Count; //依次判断买和卖 direction = 0 买 direction = 1卖 for (int direction = 0; direction <= 1; direction++) { //极值 double extrem = 0; //判断是否产生极值 double lastClose = datas[datasSize - 1].m_close; //循环遍历除最新数据外的前n-1条数据 for (int i = datasSize - n; i < datasSize - 1; i++) { SecurityData data = datas[i]; if (direction == 0) { //获取阶段最高价 if (extrem == 0 || extrem < data.m_close) { extrem = data.m_close; } } else if (direction == 1) { //获取阶段最低价 if (extrem == 0 || extrem > data.m_close) { extrem = data.m_close; } } } //判断是否创新高 bool newExtrem = false; if (direction == 0) { //当前价高于前n-1的最高价 if (lastClose > extrem) { newExtrem = true; } } else if (direction == 1) { //当前价低于前n-1的最低价 if (lastClose < extrem) { newExtrem = true; } } //循环便利数据,计算60周期均线 for (int i = 0; i < datasSize; i++) { SecurityData data = datas[i]; int startIndex = i - (m - 1); int realM = m; if (startIndex <= 0) { startIndex = 0; realM = i + 1; } double sum = 0; for (int j = startIndex; j <= i; j++) { sum += datas[j].m_close; } data.m_ma = sum / realM; } //判断60周期均线是否上翘或下翘 bool newWards = false; if (direction == 0) { newWards = datas[datasSize - 1].m_ma > datas[datasSize - 2].m_ma; } else if (direction == 1) { newWards = datas[datasSize - 1].m_ma < datas[datasSize - 2].m_ma; } //判断是否买开仓 if (direction == 0) { if (newExtrem) { latestData.m_state1 = 1; //state1=1 代表是创新高 } if (newWards) { latestData.m_state2 = 1; //state2=1 代表是均线上翘 } } //判断是否卖开仓 else if (direction == 1) { if (newExtrem) { latestData.m_state3 = 1; //state3=1 代表是创新低 } if (newWards) { latestData.m_state4 = 1; //state4=1 代表是均线下翘 } } } }
/// <summary> /// 获取股票历史数据 /// </summary> /// <param name="latestData">最新数据</param> /// <param name="lastClose">上一期收盘价</param> /// <param name="cycle">周期</param> /// <param name="subscription">复权模式</param> /// <param name="securityData">历史数据</param> /// <returns>历史数据</returns> public static void getSecurityData(SecurityLatestData latestData, double lastClose, int cycle, int subscription, ref SecurityData securityData) { if (cycle <= 60) { securityData.m_date = getDivideDate(latestData.m_date, 60 * 60); } else { securityData.m_date = (long)latestData.m_date / (3600 * 24) * (3600 * 24); } //前复权计算 double factor = 1; if (lastClose > 0 && latestData.m_lastClose > 0 && subscription == 2) { factor = lastClose / latestData.m_lastClose; } securityData.m_close = latestData.m_close * factor; securityData.m_high = latestData.m_high * factor; securityData.m_low = latestData.m_low * factor; securityData.m_open = latestData.m_open * factor; securityData.m_volume = latestData.m_volume; securityData.m_amount = latestData.m_amount; }
/// <summary> /// 获取分时线的历史数据 /// </summary> /// <param name="str">数据字符串</param> /// <param name="datas">历史数据</param> /// <returns>状态</returns> public static int getHistoryDatasByMinuteStr(String str, List <SecurityData> datas) { String[] strs = str.Split(new String[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); int strLen = strs.Length; double lClose = 0, lHigh = 0, lLow = 0, lOpen = 0; double lVolume = 0, lAmount = 0, fVolume = 0, fAmount = 0, sum = 0; int lYear = 0, lMonth = 0, lDay = 0, lHour = 0, lMinute = 0; int startIndex = 0; for (int i = startIndex; i < strLen; i++) { String[] strs2 = strs[i].Split(','); if (strs2.Length == 4) { double date = FCStr.convertStrToDouble(strs2[0]); double close = FCStr.convertStrToDouble(strs2[1]); double volume = FCStr.convertStrToDouble(strs2[2]); double amount = FCStr.convertStrToDouble(strs2[3]); int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0, ms = 0; FCStr.getDateByNum(date, ref year, ref month, ref day, ref hour, ref minute, ref second, ref ms); if (hour * 60 + minute >= 899) { hour = 14; minute = 59; } if (i == startIndex) { lClose = close; lHigh = close; lLow = close; lOpen = close; lVolume = volume; lAmount = amount; lYear = year; lMonth = month; lDay = day; lHour = hour; lMinute = minute; } bool inSameTime = false; if (hour == lHour && minute == lMinute) { inSameTime = true; if (close > lHigh) { lHigh = close; } if (close < lLow) { lLow = close; } } if (!inSameTime || i == strLen - 1) { SecurityData data = new SecurityData(); data.m_date = FCStr.getDateNum(lYear, lMonth, lDay, lHour, lMinute, 0, 0); data.m_close = lClose; if (lHigh != 0) { data.m_high = lHigh; } else { data.m_high = lClose; } if (lLow != 0) { data.m_low = lLow; } else { data.m_low = lClose; } if (lOpen != 0) { data.m_open = lOpen; } else { data.m_open = lClose; } data.m_volume = lVolume - fVolume; data.m_amount = lAmount - fAmount; if (data.m_close != 0 && data.m_volume != 0) { sum += data.m_close; data.m_avgPrice = sum / (datas.Count + 1); datas.Add(data); } fVolume = lVolume; fAmount = lAmount; } if (!inSameTime) { lHigh = close; lLow = close; lOpen = close; lYear = year; lMonth = month; lDay = day; lHour = hour; lMinute = minute; } lClose = close; lVolume = volume; lAmount = amount; } } return(1); }
/// <summary> /// 插入最新数据 /// </summary> /// <param name="chart">股票控件</param> /// <param name="dataSource">数据源</param> /// <param name="indicators">指标</param> /// <param name="fields">字段</param> /// <param name="historyDatas">最近的历史数据</param> /// <param name="latestData">实时数据</param> /// <returns>索引</returns> public static int insertLatestData(FCChart chart, FCDataTable dataSource, List <FCScript> indicators, int[] fields, SecurityData latestData) { if (latestData.m_close > 0 && latestData.m_volume > 0) { int indicatorsSize = indicators.Count; int index = insertData(chart, dataSource, fields, latestData); for (int i = 0; i < indicatorsSize; i++) { indicators[i].onCalculate(index); } return(index); } else { return(-1); } }
/// <summary> /// 插入数据 /// </summary> /// <param name="chart">证券控件</param> /// <param name="dataSource">数据源</param> /// <param name="fields">字段</param> /// <param name="securityData">证券数据</param> /// <returns>索引</returns> public static int insertData(FCChart chart, FCDataTable dataSource, int[] fields, SecurityData securityData) { double close = securityData.m_close, high = securityData.m_high, low = securityData.m_low, open = securityData.m_open, avgPrice = securityData.m_avgPrice, volume = securityData.m_volume, amount = securityData.m_amount; if (volume > 0 || close > 0) { if (high == 0) { high = close; } if (low == 0) { low = close; } if (open == 0) { open = close; } if (avgPrice == 0) { avgPrice = double.NaN; } } else { close = double.NaN; high = double.NaN; low = double.NaN; open = double.NaN; volume = double.NaN; amount = double.NaN; avgPrice = double.NaN; } double date = securityData.m_date; dataSource.set(date, fields[4], volume); int index = dataSource.getRowIndex(date); dataSource.set2(index, fields[0], close); dataSource.set2(index, fields[1], high); dataSource.set2(index, fields[2], low); dataSource.set2(index, fields[3], open); dataSource.set2(index, fields[5], volume); dataSource.set2(index, fields[6], avgPrice); return(index); }