예제 #1
0
        /// <summary>
        /// 执行卖出操作
        /// </summary>
        /// <param name="tradeRecord"></param>
        /// <param name="strategyParam"></param>
        /// <param name="backtestParam"></param>
        public virtual void Execute(TradeRecords tradeRecord, Properties strategyParam, BacktestParameter backtestParam)
        {
            #region 1初始化行情库
            if (tradeRecord == null)
            {
                return;
            }

            IndicatorRepository repository = (IndicatorRepository)backtestParam.Get <Object>("repository");
            if (repository == null)
            {
                return;
            }

            #endregion

            #region 2 取得策略参数

            int    p_maxbuynum      = strategyParam.Get <int>("maxbuynum", 0);
            double p_maxprofilt     = strategyParam.Get <double>("maxprofilt");
            int    p_maxholddays    = strategyParam.Get <int>("maxholddays");
            double p_stoploss       = strategyParam.Get <double>("stoploss");
            int    p_choosedays     = strategyParam.Get <int>("choosedays");
            double p_chooseprofilt  = strategyParam.Get <double>("chooseprofilt");
            double p_addholdprofilt = strategyParam.Get <double>("addholdprofilt");
            double p_addholdamount  = strategyParam.Get <double>("addholdamount");
            #endregion


            String           code  = tradeRecord.Code;
            List <TradeBout> bouts = tradeRecord.Bouts;

            #region 3 遍历每一个买入回合
            for (int i = 0; i < bouts.Count; i++)
            {
                #region 3.1 取得该回合的行情数据
                TradeBout          bout = bouts[i];
                TimeSerialsDataSet ds   = repository[bout.Code];
                if (ds == null)
                {
                    continue;
                }

                if (bout.Completed)
                {
                    continue;                //跳过已完成的
                }
                KLine kline = ds.DayKLine;
                if (kline == null)
                {
                    continue;
                }

                bool chooseToSell = false;//择机卖出状态,是指持仓价值较低

                int bIndex = kline.IndexOf(bout.BuyInfo.TradeDate);
                if (bIndex < 0)
                {
                    continue;
                }
                KLineItem klineItemDay = kline[bIndex];
                DateTime  d            = klineItemDay.Date;


                #endregion

                #region 3.2 如果超过了最大持仓数限制,该回合跳过
                if (p_maxbuynum > 0)
                {
                    //计算当前回合的买入日期这天有多少持仓
                    int count = 0;
                    bouts.ForEach(x => { if (x.Completed && bout.BuyInfo.TradeDate.Date >= x.BuyInfo.TradeDate.Date && bout.BuyInfo.TradeDate.Date < x.SellInfo.TradeDate.Date)
                                         {
                                             count++;
                                         }
                                  });

                    if (count > p_maxbuynum)
                    {
                        continue;
                    }
                }
                #endregion


                #region 3.3 寻找卖点
                String reason = "";
                for (int index = bIndex + 1; index < kline.Count; index++)
                {
                    klineItemDay = kline[index];
                    d            = klineItemDay.Date;


                    #region A 计算以当日最高价和收盘价卖出的盈利
                    double diff        = klineItemDay.HIGH - bout.BuyInfo.TradePrice;
                    double percentHigh = diff / bout.BuyInfo.TradePrice;
                    diff = klineItemDay.CLOSE - bout.BuyInfo.TradePrice;
                    double percentClose = diff / bout.BuyInfo.TradePrice;
                    #endregion

                    #region B 盈利超过预定
                    if (p_maxprofilt > 0 && percentHigh >= p_maxprofilt) //盈利超过预定
                    {
                        double price  = bout.BuyInfo.TradePrice * (1 + p_maxprofilt);
                        int    amount = bout.BuyInfo.Amount;
                        bout.RecordTrade(2, klineItemDay.Date, TradeDirection.Sell, price, amount, backtestParam.Volumecommission, backtestParam.Stampduty, "盈利>=" + p_maxprofilt.ToString("F2"));
                        break;
                    }
                    #endregion

                    #region C 择机卖出状态
                    if (chooseToSell)
                    {
                        for (int t = 0; t < p_choosedays; t++)
                        {
                            index += t;
                            if (index >= kline.Count)
                            {
                                break;
                            }
                            double percent = (kline[index].HIGH - bout.BuyInfo.TradePrice) / bout.BuyInfo.TradePrice;
                            if (percent >= p_chooseprofilt)
                            {
                                double price  = bout.BuyInfo.TradePrice * (1 + p_chooseprofilt);
                                int    amount = bout.BuyInfo.Amount;
                                bout.RecordTrade(2, kline[index].Date, TradeDirection.Sell, price, amount, backtestParam.Volumecommission, backtestParam.Stampduty, (reason == "" ? "" : reason + ",并") + "在第" + (t + 1).ToString() + "天择机卖出");
                                break;
                            }
                        }
                        if (!bout.Completed)
                        {
                            if (index >= kline.Count)
                            {
                                return;
                            }
                            double price  = kline[index].CLOSE;
                            int    amount = bout.BuyInfo.Amount;
                            bout.RecordTrade(2, kline[index].Date, TradeDirection.Sell, price, amount, backtestParam.Volumecommission, backtestParam.Stampduty, (reason == "" ? "" : reason + ",并") + "择机强制卖出");
                        }
                        break;
                    }
                    #endregion

                    #region D 持仓超过n天进入到择机卖出状态
                    if (p_maxholddays != 0 && CalendarUtils.WorkDayCount(bout.BuyInfo.TradeDate, klineItemDay.Date) >= p_maxholddays)
                    {
                        reason       = "持仓超过" + p_maxholddays.ToString() + "天";
                        chooseToSell = true;
                        continue;
                    }
                    #endregion


                    #region E 达到止损线,进入到择机卖出状态
                    double loss = (klineItemDay.LOW - bout.BuyInfo.TradePrice) / bout.BuyInfo.TradePrice;
                    if (p_stoploss > 0 && loss < 0 && loss < -1 * p_stoploss)
                    {
                        reason = "达到止损" + p_stoploss.ToString("F2");
                        bout.RecordTrade(2, d, TradeDirection.Sell, bout.BuyInfo.TradePrice * (1 - p_stoploss), bout.BuyInfo.Amount, backtestParam.Volumecommission, backtestParam.Stampduty, reason);
                        break;
                    }
                    #endregion

                    #region F调用子类的算法来寻找卖点
                    if (!bout.Completed)
                    {
                        chooseToSell = DoSell(code, bout, d, strategyParam, backtestParam, out reason);
                    }
                    if (bout.Completed)
                    {
                        break;
                    }
                    #endregion

                    #region 判断是否加仓或者减仓
                    if (p_addholdprofilt > 0 && p_addholdamount > 0)
                    {
                        if (percentClose > p_addholdprofilt)
                        {
                            int       addamount = (int)(bout.BuyInfo.Amount * p_addholdamount);
                            TradeInfo tradeInfo = new TradeInfo();
                            tradeInfo.Code       = bout.Code;
                            tradeInfo.Amount     = addamount;
                            tradeInfo.Direction  = TradeDirection.Buy;
                            tradeInfo.Reason     = "加仓";
                            tradeInfo.Fee        = backtestParam.Volumecommission;
                            tradeInfo.Stamps     = backtestParam.Stampduty;
                            tradeInfo.TradeDate  = klineItemDay.Date;
                            tradeInfo.TradePrice = klineItemDay.CLOSE;

                            bout.BuyInfo.TradePrice = (bout.BuyInfo.Amount * bout.BuyInfo.TradePrice + addamount * klineItemDay.CLOSE) / (bout.BuyInfo.Amount + addamount);
                            bout.BuyInfo.Amount    += addamount;
                        }
                    }
                    #endregion
                }

                #endregion //寻找卖点结束
            }

            #endregion //遍历每一个买入回合结束
        }
예제 #2
0
        public override TradeInfo DoSell(HoldRecord holdRecord, DateTime d, Properties strategyParam, StrategyContext context)
        {
            if (holdRecord == null)
            {
                return(null);
            }

            //取得行情库
            IndicatorRepository repository = (IndicatorRepository)context.Get <Object>("repository");

            if (repository == null)
            {
                return(null);
            }
            TimeSerialsDataSet ds = repository[holdRecord.code];

            if (ds == null)
            {
                return(null);
            }
            KLine     klineDay     = ds.DayKLine;
            KLineItem klineItemDay = klineDay[d];

            if (klineItemDay == null)
            {
                return(null);
            }

            //取得策略参数
            double         p_maxprofilt     = strategyParam.Get <double>("maxprofilt");
            int            p_maxholddays    = strategyParam.Get <int>("maxholddays");
            double         p_stoploss       = strategyParam.Get <double>("stoploss");
            int            p_choosedays     = strategyParam.Get <int>("choosedays");
            double         p_chooseprofilt  = strategyParam.Get <double>("chooseprofilt");
            GrailParameter p_grail          = GrailParameter.Parse(strategyParam.Get <String>("grail"));
            double         stampduty        = context.Get <double>("stampduty");
            double         volumecommission = context.Get <double>("volumecommission");

            //大盘要求必须卖
            if (p_grail.MustSell(d, holdRecord.code))
            {
                TradeInfo tradeInfo = new TradeInfo()
                {
                    Direction    = TradeDirection.Sell,
                    Code         = holdRecord.code,
                    Amount       = holdRecord.amount,
                    EntrustPrice = klineItemDay.CLOSE,
                    EntrustDate  = d,
                    TradeDate    = d,
                    TradePrice   = klineItemDay.CLOSE,
                    Stamps       = stampduty,
                    Fee          = volumecommission,
                    TradeMethod  = TradeInfo.TM_AUTO,
                    Reason       = "大盘指数要求卖出"
                };
                return(tradeInfo);
            }

            double profilt = (klineItemDay.CLOSE - holdRecord.buyPrice) / holdRecord.buyPrice;

            //判断是否到达最大收益
            if (p_maxprofilt > 0)
            {
                if (profilt >= p_maxprofilt)
                {
                    TradeInfo tradeInfo = new TradeInfo()
                    {
                        Direction    = TradeDirection.Sell,
                        Code         = holdRecord.code,
                        Amount       = holdRecord.amount,
                        EntrustPrice = klineItemDay.CLOSE,
                        EntrustDate  = d,
                        TradeDate    = d,
                        TradePrice   = klineItemDay.CLOSE,
                        Stamps       = stampduty,
                        Fee          = volumecommission,
                        TradeMethod  = TradeInfo.TM_AUTO,
                        Reason       = "盈利达到" + p_maxprofilt.ToString("F2")
                    };
                    return(tradeInfo);
                }
            }

            //盈利超过个股预期
            if (holdRecord.expect > 0)
            {
                if (profilt >= p_maxprofilt)
                {
                    TradeInfo tradeInfo = new TradeInfo()
                    {
                        Direction    = TradeDirection.Sell,
                        Code         = holdRecord.code,
                        Amount       = holdRecord.amount,
                        EntrustPrice = klineItemDay.CLOSE,
                        EntrustDate  = d,
                        TradeDate    = d,
                        TradePrice   = klineItemDay.CLOSE,
                        Stamps       = stampduty,
                        Fee          = volumecommission,
                        TradeMethod  = TradeInfo.TM_AUTO,
                        Reason       = "盈利达到个股预期" + holdRecord.expect.ToString("F2")
                    };
                    return(tradeInfo);
                }
            }

            //预期要求立即卖出
            if (holdRecord.expect == -1)
            {
                TradeInfo tradeInfo = new TradeInfo()
                {
                    Direction    = TradeDirection.Sell,
                    Code         = holdRecord.code,
                    Amount       = holdRecord.amount,
                    EntrustPrice = klineItemDay.CLOSE,
                    EntrustDate  = d,
                    TradeDate    = d,
                    TradePrice   = klineItemDay.CLOSE,
                    Stamps       = stampduty,
                    Fee          = volumecommission,
                    TradeMethod  = TradeInfo.TM_AUTO,
                    Reason       = "个股预期极低"
                };
                return(tradeInfo);
            }

            //个股观望天数超过预期
            int holdDays = CalendarUtils.WorkDayCount(holdRecord.buyDate, d);

            if (holdRecord.expect < 0)
            {
                if (holdDays >= holdRecord.expect * -1)
                {
                    TradeInfo tradeInfo = new TradeInfo()
                    {
                        Direction    = TradeDirection.Sell,
                        Code         = holdRecord.code,
                        Amount       = holdRecord.amount,
                        EntrustPrice = klineItemDay.CLOSE,
                        EntrustDate  = d,
                        TradeDate    = d,
                        TradePrice   = klineItemDay.CLOSE,
                        Stamps       = stampduty,
                        Fee          = volumecommission,
                        TradeMethod  = TradeInfo.TM_AUTO,
                        Reason       = "个股预期观望超过" + (-1 * holdRecord.expect).ToString() + "天"
                    };
                    return(tradeInfo);
                }
            }

            //达到止损线
            if (p_stoploss > 0)
            {
                if (-1 * profilt > p_stoploss)
                {
                    TradeInfo tradeInfo = new TradeInfo()
                    {
                        Direction    = TradeDirection.Sell,
                        Code         = holdRecord.code,
                        Amount       = holdRecord.amount,
                        EntrustPrice = klineItemDay.CLOSE,
                        EntrustDate  = d,
                        TradeDate    = d,
                        TradePrice   = klineItemDay.CLOSE,
                        Stamps       = stampduty,
                        Fee          = volumecommission,
                        TradeMethod  = TradeInfo.TM_AUTO,
                        Reason       = "到达止损线" + p_stoploss.ToString("F2")
                    };
                    return(tradeInfo);
                }
            }

            //达到最大持仓天数
            if (p_maxholddays > 0)
            {
                if (holdDays > p_maxholddays)
                {
                    TradeInfo tradeInfo = new TradeInfo()
                    {
                        Direction    = TradeDirection.Sell,
                        Code         = holdRecord.code,
                        Amount       = holdRecord.amount,
                        EntrustPrice = klineItemDay.CLOSE,
                        EntrustDate  = d,
                        TradeDate    = d,
                        TradePrice   = klineItemDay.CLOSE,
                        Stamps       = stampduty,
                        Fee          = volumecommission,
                        TradeMethod  = TradeInfo.TM_AUTO,
                        Reason       = "到达最大持仓天数" + p_maxholddays.ToString()
                    };
                    return(tradeInfo);
                }
            }
            return(null);
        }