Пример #1
0
        /// <summary>
        /// 克隆
        /// </summary>
        /// <returns></returns>
        public DateDetailRecord Clone()
        {
            DateDetailRecord r = new DateDetailRecord();

            r.buyBouts.AddRange(this.buyBouts);
            r.buyCount = this.buyCount;
            r.curFund  = this.curFund;
            r.date     = this.date;
            r.holdBouts.AddRange(this.holdBouts);
            r.marketValueMax = marketValueMax;
            r.marketValueMin = marketValueMin;
            r.retracement    = retracement;
            r.sellBouts.AddRange(this.sellBouts);
            r.SellCount    = SellCount;
            r.willBuyCount = willBuyCount;
            return(r);
        }
Пример #2
0
        /// <summary>
        /// 写详细记录
        /// </summary>
        /// <param name="recordFileName">每天的交易摘要文件</param>
        /// <param name="boutFileName">每天的交易明细文件</param>
        public void WriteRecord(String recordFileName, String boutFileName)
        {
            List <String> recordLines = new List <string>();
            List <String> boutLines   = new List <string>();

            recordLines.Add(DateDetailRecord.GetTitle());
            for (int i = 0; i < this.records.Count; i++)
            {
                recordLines.Add(records[i].ToString());
                boutLines.AddRange(records[i].ToDetailString());
            }
            if (recordLines.Count > 0 && recordFileName != null && recordFileName != "")
            {
                System.IO.File.WriteAllLines(recordFileName, recordLines.ToArray());
            }
            if (boutLines.Count > 0 && boutFileName != null && boutFileName != "")
            {
                System.IO.File.WriteAllLines(boutFileName, boutLines.ToArray());
            }
        }
Пример #3
0
        /// <summary>
        /// 执行回测
        /// </summary>
        /// <param name="props"></param>
        /// <returns></returns>
        public virtual TotalStat doTestByDate(List <TradeRecords> tradeRecoreds)
        {
            List <TradeBout> bouts = new List <TradeBout>();

            tradeRecoreds.ForEach(x => bouts.AddRange(x.Bouts));

            double   marketValueMin         = backtestParam.Initfunds; //日最低市值
            double   marketValueMax         = backtestParam.Initfunds; //日最高市值
            double   lastmarketValueMax     = backtestParam.Initfunds; //上一个日最高市值
            DateTime lastmarketValueMaxDate = backtestParam.BeginDate;
            double   curFund = backtestParam.Initfunds;                //当前资金

            TotalStat stat = new TotalStat();
            List <DateDetailRecord> records    = new List <DateDetailRecord>(); //日详细记录
            List <TradeBout>        holdTrades = new List <TradeBout>();        //日持仓回合
            List <int>    holdDays             = new List <int>();              //持仓日期
            List <String> codes     = new List <string>();                      //交易的股票代码
            List <int>    buyCounts = new List <int>();                         //每天买入的回合数

            IndicatorRepository repository = (IndicatorRepository)backtestParam.Get <Object>("repository");
            String reason = "";

            //遍历每一天
            for (DateTime d = backtestParam.BeginDate; d <= backtestParam.EndDate; d = d.AddDays(1))
            {
                //跳过非工作日
                //if (!CalendarUtils.IsWorkDay(d))
                //     continue;


                //生成空的当日记录
                DateDetailRecord record = new DateDetailRecord();
                record.date = d;
                //找到当日的买入回合、卖出回合
                bouts.ForEach(y =>
                {
                    if (y.BuyInfo.TradeDate.Date == d.Date)
                    {
                        record.buyBouts.Add(y);
                    }
                    else if (y.SellInfo.TradeDate.Date == d.Date)
                    {
                        record.sellBouts.Add(y);
                    }
                });

                //当日没有发生买卖操作,也没有持仓,跳过
                if (record.buyBouts.Count <= 0 && record.sellBouts.Count <= 0 && holdTrades.Count <= 0)
                {
                    continue;
                }



                //将buyTrades按照优先规则排序,待实现

                //计算当日买入的花销,如果超过了资金允许买入的量,则删除一部分
                record.willBuyCount = record.buyBouts.Count;
                for (int i = 0; i < record.buyBouts.Count; i++)
                {
                    if (record.buyBouts[i].BuyInfo.TradeCost > curFund)//资金不够
                    {
                        bouts.Remove(record.buyBouts[i]);
                        record.buyBouts.RemoveAt(i--);
                    }
                    else if (isForbidBuy(d, record.buyBouts[i].Code, out reason))//如果策略实现禁止买入
                    {
                        bouts.Remove(record.buyBouts[i]);
                        record.buyBouts.RemoveAt(i--);
                    }
                    else
                    {
                        curFund -= record.buyBouts[i].BuyInfo.TradeCost; //买入
                        holdTrades.Add(record.buyBouts[i]);              //买入后变成持仓
                    }
                }
                record.buyCount = record.buyBouts.Count;
                if (stat.MaxTradeCountPerDay < record.buyBouts.Count)
                {
                    stat.MaxTradeCountPerDay = record.buyBouts.Count;
                }
                buyCounts.Add(record.buyBouts.Count);

                //判断持仓中的股票是否被禁止持仓
                for (int i = 0; i < holdTrades.Count; i++)
                {
                    TradeBout info = holdTrades[i];
                    if (!isForbidHold(d, info.Code, out reason))
                    {
                        continue;
                    }
                    info.SellInfo.Reason = reason + "(" + info.SellInfo.Reason + ")";
                    record.sellBouts.Add(info);
                    holdTrades.RemoveAt(i--);
                }


                //卖出收入放回资金
                for (int i = 0; i < record.sellBouts.Count; i++)
                {
                    if (!codes.Contains(record.sellBouts[i].Code))//记录交易的股票
                    {
                        codes.Add(record.sellBouts[i].Code);
                    }
                    stat.BoutNum += 1;           //回合数加1
                    if (record.sellBouts[i].Win) //胜数加1
                    {
                        stat.WinNum += 1;
                    }
                    holdDays.Add(record.sellBouts[i].PositionDays);    //记录持仓日期

                    curFund += record.sellBouts[i].SellInfo.TradeCost; //回收资金
                    holdTrades.Remove(record.sellBouts[i]);            //从持仓中拿掉
                }
                record.SellCount = record.sellBouts.Count;

                //计算市值
                record.holdCount = holdTrades.Count;
                if (holdTrades.Count <= 0)//如果没有持仓,市值就是资金量
                {
                    marketValueMax = marketValueMin = curFund;
                    records.Add(record);
                }
                else//如果有持仓,则计算市值=资金量+持仓当日市值
                {
                    double min = 0, max = 0;
                    foreach (TradeBout info in holdTrades)
                    {
                        TimeSerialsDataSet ds = repository[info.Code];
                        KLine     kline       = ds.DayKLine;
                        KLineItem klineitem   = kline.GetNearest(d, true, -1);
                        if (klineitem == null)//有一个回合找不到当日K线数据,则当日市值不再计算
                        {
                            min = max = 0;
                            this.log.Warn("日期" + d.ToString("yyyyMMdd") + "中有回合缺少当日和历史K线:" + info.Code);
                            break;
                        }
                        min += info.BuyInfo.Amount * klineitem.LOW;
                        max += info.BuyInfo.Amount * klineitem.HIGH;
                        record.holdBouts.Add(info.Code + "," + info.BuyInfo.Amount + "," + info.BuyInfo.TradePrice.ToString("F2") + "," + klineitem.CLOSE);
                    }
                    if (min != 0)
                    {
                        marketValueMin = curFund + min;
                    }
                    if (max != 0)
                    {
                        marketValueMax = curFund + max;
                    }
                    if (min != 0 && max != 0)
                    {
                        records.Add(record);
                    }
                }
                //记录资金和市值数据
                record.curFund        = curFund;
                record.marketValueMin = marketValueMin;
                record.marketValueMax = marketValueMax;
                if (marketValueMin < backtestParam.Initfunds)
                {
                    record.retracement = (backtestParam.Initfunds - marketValueMin) / backtestParam.Initfunds;
                }
                if (stat.MaxInitRetracementRate < record.retracement)
                {
                    stat.MaxInitRetracementRate = record.retracement;
                    stat.MaxInitRetracementDate = d;
                }
                if (marketValueMax > lastmarketValueMax)
                {
                    lastmarketValueMax     = marketValueMax;
                    lastmarketValueMaxDate = d;
                    record.retracement     = 0;
                }
                else
                {
                    record.retracement      = (lastmarketValueMax - marketValueMax) / lastmarketValueMax;
                    stat.MaxRetracementRate = record.retracement;
                    stat.MaxRetracementDate = d;
                }
            }

            //清除没有卖出的回合
            for (int i = 0; i < holdTrades.Count; i++)
            {
                curFund += holdTrades[i].BuyInfo.TradeCost;
                bouts.Remove(holdTrades[i]);
            }
            holdTrades.Clear();
            marketValueMin = marketValueMax = curFund;
            if (records.Count > 0)
            {
                DateDetailRecord extends = new DateDetailRecord();
                extends.date           = records[records.Count - 1].date.AddDays(1);
                extends.curFund        = curFund;
                extends.marketValueMax = marketValueMax;
                extends.marketValueMin = marketValueMin;
                records.Add(extends);
            }

            //结果统计
            stat.Records = records;

            stat.AverageTradeCountPerDay = buyCounts.Count <= 0?0:buyCounts.Average();
            stat.AvgHoldDays             = holdDays.Count <= 0?0:(int)holdDays.Average();
            stat.Count        = codes.Count;
            stat.MaxHoldDays  = holdDays.Count <= 0 ? 0 : holdDays.Max();
            stat.TotalFund    = curFund;
            stat.TotalProfilt = (curFund - backtestParam.Initfunds) / backtestParam.Initfunds;
            stat.WinRate      = stat.WinNum * 1.0 / stat.BoutNum;

            return(stat);
        }