/// <summary> /// 批量导入日K线数据。 /// 1. klines只能包含1支股票的日K线数据; /// 2. klines中的数据必须按照交易日期升序排序; /// </summary> /// <param name="db"></param> /// <param name="kdatas"></param> /// <returns></returns> public static int BatchImport(Database db, List<KJapaneseData> kdatas) { if(kdatas==null || kdatas.Count<=0) return 0; try{ int stockId = kdatas[0].StockId; //if(stockId!=998) return 0; //TODO DateTime start = DateTime.Now; //因为要计算250日均线,所以向前加载K线数据 List<KJapaneseData> latest = FindLatest(db, stockId, 251)as List<KJapaneseData>; #region 导入K线数据前的初始化处理 //1.数据库中已经存在K线数据时,将数据库中最新交易日的K线数据删除,这是为了防止在开盘时间导出的K线数据, // 导致当天的K线数据与收盘时不一致,删除重新导入; if(latest.Count>0){ latest[latest.Count-1].Remove(db); latest.RemoveAt(latest.Count-1); } //2.如果数据库中已经存在K线数据,则这些数据不再重新导入; while(kdatas.Count>0 && latest.Count>0 && kdatas[0].TxDate<=latest[latest.Count-1].TxDate){ kdatas.RemoveAt(0); } //3.如果latest中不足250条数据,则用最早的k线数据补全 KJapaneseData cloneTarget = null; int persistedStart = 0; if(latest.Count>0) cloneTarget = latest[0]; else cloneTarget = kdatas[0]; while(latest.Count<250){ latest.Insert(0, cloneTarget.Clone(-1)); persistedStart++; } //4.把本次要导入的数据添加到latest中 int impStart = latest.Count, impEnd = impStart + kdatas.Count - 1; //将需要导入的日K线数据kdatas追加到latest后面,计算过程中改变latest中实体的MA均线价格,这些修改 //同时也会反应到kdatas中的实体上。 //最后将kdatas插入数据库,即完成数据导入 latest.AddRange(kdatas); //5.在latest最后追加16条最新k线数据的拷贝,用于计算定制化的均价、均量 cloneTarget = kdatas[kdatas.Count-1]; long latestEffectiveVol = cloneTarget.Volume; for(int i=kdatas.Count-1; i>=0; i--){ if(!kdatas[i].IsAllDayOnFusingPrice()){ latestEffectiveVol = kdatas[i].Volume; break; } } for(int i=0; i<16; i++){ KJapaneseData cloned = cloneTarget.Clone(1); //1子板涨跌停期间对均量线影响较大,为排除这种影响,克隆对象取最后一个非涨跌停板的成交量 cloned.Volume = latestEffectiveVol; latest.Add(cloned); } #endregion #region 计算标准化MA均线价格 //初始化各均线价格 decimal ma5=0, ma10=0, ma20=0, ma60=0, ma120=0, ma250=0; for(int i=0; i<impStart; i++){ ma250 += latest[i].ClosePrice; if(impStart-i<=120) ma120 += latest[i].ClosePrice; if(impStart-i<=60) ma60 += latest[i].ClosePrice; if(impStart-i<=20) ma20 += latest[i].ClosePrice; if(impStart-i<=10) ma10 += latest[i].ClosePrice; if(impStart-i<=5) ma5 += latest[i].ClosePrice; } for(int i=impStart; i<=impEnd; i++){ //设置上一交易日日期及价格 if(!latest[i-1].IsCloned()){ latest[i].PrevDate = latest[i-1].TxDate; latest[i].PrevPrice = latest[i-1].ClosePrice; } //5日均线价格 ma5 = ma5 + latest[i].ClosePrice - latest[i-5].ClosePrice; latest[i].MA5 = ma5 / 5; //10日均线价格 ma10 = ma10 + latest[i].ClosePrice - latest[i-10].ClosePrice; latest[i].MA10 = ma10 / 10; //20日均线价格 ma20 = ma20 + latest[i].ClosePrice - latest[i-20].ClosePrice; latest[i].MA20 = ma20 / 20; //60日均线价格 ma60 = ma60 + latest[i].ClosePrice - latest[i-60].ClosePrice; latest[i].MA60 = ma60 / 60; //120日均线价格 ma120 = ma120 + latest[i].ClosePrice - latest[i-120].ClosePrice; latest[i].MA120 = ma120 / 120; //250日均线价格 ma250 = ma250 + latest[i].ClosePrice - latest[i-250].ClosePrice; latest[i].MA250 = ma250 / 250; } #endregion CalculateMA(latest, impStart, impEnd, MAType.MAShort); CalculateMA(latest, impStart, impEnd, MAType.MALong); CalculateMA(latest, impStart, impEnd, MAType.VMAShort); CalculateMA(latest, impStart, impEnd, MAType.VMALong); DateTime afterCalc = DateTime.Now; #region 批量导入、更新 db.BeginTransaction(); //批量插入 try{ BulkInserter<KJapaneseData> bi = new KJapaneseDataBulkInserter<KJapaneseData>(db, 200); //初步验证,一批次插入200条性能最好 for(int i=impStart; i<=impEnd; i++) bi.Push(latest[i]); bi.Flush(); //更新受影响的双重9日均线价格 int startIndex = impStart - 8; if(startIndex<0) startIndex = 0; if(startIndex<persistedStart) startIndex = persistedStart; for(int i=startIndex; i<impStart; i++) latest[i].UpdateMA(db); db.CommitTransaction(); }catch(Exception exInner){ db.RollbackTransaction(); log.Error("导入日K线数据错误", exInner); } #endregion return kdatas.Count; }catch(Exception ex){ log.Error("导入日K线错误", ex); return 0; } }
/// <summary> /// 创建股东数数据。前提条件:<br /> /// 1. 每次调用,<paramref name="entities"/>只能包含同一只股票的股东数数据;<br /> /// 2. 调用时,必须确保StockId, PublishDate, HolderCount, AverageStockNumber, Source属性值有效; /// </summary> /// <param name="db"></param> /// <param name="entities"></param> public static int Create(Database db, IList<ShareholdersNumEntity> entities) { if(entities==null || entities.Count<=0) return 0; DateTime minDate = DateTime.MaxValue, effectiveDate = new DateTime(1990, 1, 1); int stockId = 0, exists=0, insertedRows = 0; try{ db.BeginTransaction(); //添加数据 foreach(ShareholdersNumEntity entity in entities){ //数据校验 if(entity.StockId<=0 || entity.ReportDate<=effectiveDate // || entity.HolderCount<=0 || entity.AverageStockNumber<=0 || (entity.Source==null || entity.Source.Trim().Length<=0)) throw new EntityException("[holder-num] [create] 属性无效,无法更新数据库,[id:" + entity.StockId + ", date:" + entity.ReportDate.ToString("yyyyMMdd")); if(stockId==0) stockId = entity.StockId; if(stockId!=entity.StockId) throw new EntityException("[holder-num] [create] entities中包含了多只股票的股东数数据"); entity.CreateTime = DateTime.Now; entity.VarNum = 0; //插入数据 exists = Convert.ToInt32(db.ExecScalar( "select count(*) from sto_holder_num where sto_id=?id and report_date=?date", new string[] {"id", "date"}, new object[] { entity.StockId, entity.ReportDate} )); if(exists<=0){ insertedRows += db.ExecNonQuery(INSERT_SQL, new string[]{"id", "date", "holdersNum", "varNum", "avgShares", "totalShares", "transShares", "time", "source"}, new object[]{entity.StockId, entity.ReportDate, entity.HoldersNum, entity.VarNum , entity.AvgShares, entity.TotalShares, entity.TransShares , entity.CreateTime, entity.Source}); if(minDate>entity.ReportDate) minDate = entity.ReportDate; } } //更新股东数增长量 int prevCount = 0; exists = Convert.ToInt32(db.ExecScalar( "select count(*) from sto_holder_num where sto_id=?id and report_date<?date", new string[] {"id", "date"}, new object[] { stockId, minDate} )); if(exists>0){ prevCount = Convert.ToInt32(db.ExecScalar( "select holders_num from sto_holder_num where sto_id=?id and report_date<?date order by report_date desc limit 1", new string[] {"id", "date"}, new object[] { stockId, minDate} )); } DataSet ds = db.ExecDataSet( "select * from sto_holder_num where sto_id=?id and report_date>=?date order by report_date asc", new string[] { "id", "date" }, new object[] { stockId, minDate } ); foreach(DataRow row in ds.Tables[0].Rows){ if(prevCount==0){ prevCount = Convert.ToInt32(row["holders_num"]); continue; } int curCount = Convert.ToInt32(row["holders_num"]); db.ExecNonQuery( "update sto_holder_num set var_num=?varNum where sto_id=?id and report_date=?date", new string[] { "id", "date", "varNum" }, new object[] { stockId, row["report_date"], curCount-prevCount} ); prevCount = curCount; } db.CommitTransaction(); }catch(Exception ex){ db.RollbackTransaction(); throw ex; } return insertedRows; }