/// <summary> /// 根据个股主力线高位卖出 /// </summary> /// <param name="bouts"></param> /// <param name="ds"></param> /// <param name="strategyParam"></param> /// <param name="backtestParam"></param> public void DoSell2(TradeRecords tradeRecords, TimeSerialsDataSet ds, Properties strategyParam, BacktestParameter backtestParam) { if (tradeRecords == null || tradeRecords.Bouts == null || tradeRecords.Bouts.Count <= 0) { return; } TimeSeries <ITimeSeriesItem <List <double> > > dayFunds = ds.DayFundTrend; KLine dayLine = ds.DayKLine; if (dayLine == null) { return; } foreach (TradeBout bout in tradeRecords.Bouts) { DateTime buyDate = bout.BuyInfo.TradeDate; //找20个工作日的收盘价最高值 KLineItem klineItem = dayLine.GetNearest(buyDate, false); if (klineItem == null) { continue; } int index = dayLine.IndexOf(klineItem); DateTime sellDate = buyDate; double sellPrice = 0; for (int i = index + 1; i < Math.Min(index + 41, dayLine.Count); i++) { if (dayLine[i].CLOSE > sellPrice) { sellPrice = dayLine[i].CLOSE; sellDate = dayLine[i].Date; } } bout.RecordTrade(2, sellDate, TradeDirection.Sell, sellPrice, bout.BuyInfo.Amount, 0, 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 //遍历每一个买入回合结束 }
public void Execute() { List <String> codes = new List <string>(); System.IO.File.ReadAllLines(FileUtils.GetDirectory() + "test.csv") .ToList().ForEach(x => codes.Add(x.Split(',')[1])); IndicatorRepository repository = new IndicatorRepository("d:\\repository\\"); repository.Initilization(); foreach (String code in codes) { //生成数据 TimeSerialsDataSet ds = repository[code]; KLine dayLine = ds.DayKLine; KLine weekLine = dayLine.CreateWeek(); ds.WeekKLine = weekLine; TimeSeries <ITimeSeriesItem <double> > dayClose = dayLine.Select <double>("close", 0, 0); TimeSeries <ITimeSeriesItem <double> > weekClose = weekLine.Select <double>("close", 0, 0); TradingLine dayTradeLine = ds.CubeCreateOrLoad(TimeUnit.day); TradingLine weekTradeLine = ds.CubeCreateOrLoad(TimeUnit.week); TimeSeries <ITimeSeriesItem <List <double> > > dayFunds = ds.FundTrendCreate(TimeUnit.day); TimeSeries <ITimeSeriesItem <List <double> > > weekFunds = ds.FundTrendCreate(TimeUnit.week); TimeSeries <ITimeSeriesItem <double> > dayCross = ds.FundTrendCrossCreateOrLoad(TimeUnit.day); TimeSeries <ITimeSeriesItem <double> > weedCross = ds.FundTrendCrossCreateOrLoad(TimeUnit.week); //测试买入 List <TradeBout> bouts = new List <TradeBout>(); TimeSeries <ITimeSeriesItem <char> > dayTradePt = dayTradeLine.buysellPoints; for (int i = 0; i < dayTradePt.Count; i++) { ITimeSeriesItem <char> item = dayTradePt[i]; if (item.Value == 'S') { continue; } if (item.Date < begin || item.Date > end) { continue; } DateTime buyPtDate = item.Date; int index = dayFunds.IndexOf(buyPtDate); while (index <= dayFunds.Count) { ITimeSeriesItem <List <double> > fundItem = dayFunds[index]; if (fundItem == null) { index += 1; continue; } if (fundItem.Value[0] <= fundItem.Value[1]) { index += 1; continue; } TradeBout bout = new TradeBout(code); KLineItem klineItem = dayLine.GetNearest(fundItem.Date, false); if (klineItem == null) { index += 1; continue; } bout.RecordTrade(1, klineItem.Date, TradeDirection.Buy, klineItem.CLOSE, (int)(funds / klineItem.CLOSE), 0, 0, "发出B点且主力=" + fundItem.Value[0].ToString("F3") + "大于散户" + fundItem.Value[1].ToString("F3") + ",日期=" + fundItem.Date.ToString("yyyyMMdd")); bouts.Add(bout); break; } } //测试卖出 for (int i = 0; i < bouts.Count; i++) { DateTime buyDate = bouts[i].BuyInfo.TradeDate; int buyIndex = dayLine.IndexOf(buyDate); int index = buyIndex + 1; while (index <= dayLine.Count - 1) { KLineItem item = dayLine[index]; if (index - buyIndex >= maxdays) { bouts[i].RecordTrade(2, item.Date, TradeDirection.Sell, item.CLOSE, bouts[i].BuyInfo.Amount, 0, 0, "大于" + maxdays.ToString() + "天卖出"); break; } else { double profile = (item.HIGH - bouts[i].BuyInfo.TradePrice) / bouts[i].BuyInfo.TradePrice; if (profile >= maxProfilt) { bouts[i].RecordTrade(2, item.Date, TradeDirection.Sell, (bouts[i].BuyInfo.TradePrice * (1 + maxProfilt)), bouts[i].BuyInfo.Amount, 0, 0, "利润大于" + maxdays.ToString() + "天卖出"); break; } } index += 1; } } //去掉未完成的 for (int i = 0; i < bouts.Count; i++) { if (!bouts[i].Completed) { bouts.RemoveAt(i--); } } TradeRecords tradeRecords = new TradeRecords(); tradeRecords.Bouts.AddRange(bouts); //打印结果 for (int i = 0; i < bouts.Count; i++) { Console.WriteLine(bouts[i].ToString()); } Console.WriteLine(tradeRecords.ToString()); } }
/// <summary> /// 执行卖出操作 /// </summary> /// <param name="tradeRecord"></param> /// <param name="strategyParam"></param> /// <param name="backtestParam"></param> public override void Execute(TradeRecords tradeRecord, Properties strategyParam, BacktestParameter backtestParam) { //初始化行情库 if (tradeRecord == null) { return; } IndicatorRepository repository = (IndicatorRepository)backtestParam.Get <Object>("repository"); if (repository == null) { return; } //取得策略参数 int p_maxday = strategyParam.Get <int>("maxholddays"); //遍历每一个买入回合 String code = tradeRecord.Code; List <TradeBout> bouts = tradeRecord.Bouts; for (int i = 0; i < bouts.Count; i++) { 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; } int bIndex = kline.IndexOf(bout.BuyInfo.TradeDate); //寻找p_maxday天内最大收益那天 KLineItem maxProfileItem = null; for (int index = bIndex + 1; index <= bIndex + 1 + p_maxday; index++) { if (index >= kline.Count) { break; } KLineItem item = kline[index]; if (item.CLOSE > (maxProfileItem == null?0: maxProfileItem.CLOSE)) { maxProfileItem = item; } } if (maxProfileItem == null) { continue; } bout.RecordTrade(2, maxProfileItem.Date, TradeDirection.Sell, maxProfileItem.CLOSE, bout.BuyInfo.Amount, backtestParam.Volumecommission, backtestParam.Stampduty, ""); } }
public override TradeRecords Execute(string code, Properties strategyParam, BacktestParameter backtestParam, ISeller seller = null) { IndicatorRepository repository = (IndicatorRepository)backtestParam.Get <Object>("repository"); //取得策略参数 double buy_mainlow = strategyParam.Get <double>("buy_mainlow"); //主力线低位买入 int buy_cross = strategyParam.Get <int>("buy_cross"); GetInMode p_getinMode = (GetInMode)strategyParam.Get <GetInMode>("getinMode"); TradeRecords tr = new TradeRecords(code); TimeSerialsDataSet ds = repository[code]; if (ds == null) { return(null); } KLine kline = ds.DayKLine; if (kline == null) { return(null); } TimeSeries <ITimeSeriesItem <List <double> > > dayFunds = ds.DayFundTrend; TimeSeries <ITimeSeriesItem <double> > dayFundsCross = ds.DayFundTrendCross; if (buy_cross == 0 && dayFunds == null) { return(null); } else if (buy_cross == 1 && (dayFundsCross == null || dayFunds == null)) { return(null); } #region 判断主力线低位决定买入点 if (buy_cross == 0) { for (int i = 0; i < dayFunds.Count; i++) { if (dayFunds[i].Date.Date <backtestParam.BeginDate || dayFunds[i].Date.Date> backtestParam.EndDate) { continue; } if (double.IsNaN(dayFunds[i].Value[0])) { continue; } if (dayFunds[i].Value[0] > buy_mainlow) { continue; } //主力线开始低于buy_mainlow... i += 1; while (i < dayFunds.Count) { if (dayFunds[i].Value[0] <= buy_mainlow) { i += 1; continue; } //主力线出了buy_mainlow KLineItem klineItem = kline[dayFunds[i].Date]; if (klineItem == null) { break; } int tIndex = kline.IndexOf(klineItem); if (tIndex >= kline.Count - 1) { break; } KLineItem klineItemNext = kline[tIndex + 1]; TradeBout bout = new TradeBout(code); double price = klineItem.CLOSE; if (price > klineItemNext.HIGH || price < klineItemNext.LOW) { break; } bout.RecordTrade(1, dayFunds[i].Date.Date, TradeDirection.Buy, price, (int)(p_getinMode.Value / price), backtestParam.Volumecommission, backtestParam.Stampduty, "主力线低于" + buy_mainlow.ToString("F2")); tr.Bouts.Add(bout); break; } } } #endregion #region 判断金叉决定买入点 else if (buy_cross == 1) { for (int i = 0; i < dayFundsCross.Count; i++) { if (dayFundsCross[i].Date.Date <backtestParam.BeginDate || dayFundsCross[i].Date.Date> backtestParam.EndDate) { continue; } if (dayFundsCross[i].Value <= 0) { continue; } ITimeSeriesItem <List <double> > dayFundItem = dayFunds[dayFundsCross[i].Date]; if (dayFundItem == null) { continue; } if (buy_mainlow != 0 && dayFundItem.Value[0] >= buy_mainlow) { continue; } KLineItem klineItem = kline[dayFundItem.Date]; if (klineItem == null) { continue; } int tIndex = kline.IndexOf(klineItem); if (tIndex >= kline.Count - 1) { continue; } KLineItem klineItemNext = kline[tIndex + 1]; TradeBout bout = new TradeBout(code); double price = klineItem.CLOSE; if (price > klineItemNext.HIGH || price < klineItemNext.LOW) { continue; } bout.RecordTrade(1, dayFunds[i].Date.Date, TradeDirection.Buy, price, (int)(p_getinMode.Value / price), backtestParam.Volumecommission, backtestParam.Stampduty, "主力线低于" + buy_mainlow.ToString("F2")); tr.Bouts.Add(bout); } } #endregion return(tr); }
public override bool DoSell(String code, TradeBout bout, DateTime d, Properties strategyParam, BacktestParameter backtestParam, out String reason) { reason = ""; if (bout == null) { return(false); } IndicatorRepository repository = (IndicatorRepository)backtestParam.Get <Object>("repository"); if (repository == null) { return(false); } TimeSerialsDataSet ds = repository[bout.Code]; if (ds == null) { return(false); } KLine kline = ds.DayKLine; if (kline == null) { return(false); } //跳过已完成的 if (bout.Completed) { return(false); } //取得策略参数 int p_spoints = strategyParam.Get <int>("spoints"); int p_totaldropcount = strategyParam.Get <int>("totaldropcount"); int p_continuedropcount = strategyParam.Get <int>("continuedropcount"); #region 判断发出S点卖出:p_spoints=1表示日线出S点,p_spoints=2表示60分钟线出S点 if (p_spoints > 0 && ds.DayTradeLine != null && ds.DayTradeLine.buysellPoints != null && ds.DayTradeLine.buysellPoints.Count > 0) { ITimeSeriesItem <char> bsptItemDay = ds.DayTradeLine.buysellPoints[d]; if (bsptItemDay != null && bsptItemDay.Value == 'S') { KLineItem klineItemDay = kline[d]; if (klineItemDay != null) { double price = klineItemDay.CLOSE; int amount = bout.BuyInfo.Amount; bout.RecordTrade(2, klineItemDay.Date, TradeDirection.Sell, price, amount, backtestParam.Volumecommission, backtestParam.Stampduty, "日线出S点"); return(false); } } } #endregion #region 根据价格下降情况判断是否卖出 if (p_continuedropcount > 0 || p_totaldropcount > 0) { int bIndex = kline.IndexOf(bout.BuyInfo.TradeDate); int index = bIndex + 1; if (index >= kline.Count) { return(false); } KLineItem item = kline[index]; DateTime td = item.Date; int totaldropcount = 0, continuedropcount = 0; double prevPrice = bout.BuyInfo.TradePrice; bool prevDrop = item.Average < prevPrice; while (td <= d && index < kline.Count - 1) { double price = item.Average; if (price < prevPrice) { totaldropcount += 1; if (prevDrop) { continuedropcount += 1; } prevDrop = true; } else { prevDrop = false; } index += 1; item = kline[index]; td = item.Date; } //进入到伺机卖出状态 if (p_continuedropcount != 0 && continuedropcount >= p_continuedropcount) { return(true); } //进入到伺机卖出情况 if (p_totaldropcount != 0 && totaldropcount >= p_totaldropcount) { return(true); } } #endregion return(false); }
public override TradeRecords Execute(string code, Properties strategyParam, BacktestParameter backtestParam, ISeller seller = null) { //获取行情数据 IndicatorRepository repository = (IndicatorRepository)backtestParam.Get <Object>("repository"); if (repository == null) { return(null); } TimeSerialsDataSet ds = repository[code]; if (ds == null) { return(null); } KLine kline = ds.DayKLine; if (kline == null) { return(null); } DateTime beginDate = backtestParam.BeginDate; DateTime endDate = backtestParam.EndDate; int bIndex = kline.IndexOf(beginDate, false); if (bIndex < 0) { return(null); } //获取参数 int maxholddays = strategyParam.Get <int>("maxholddays"); double maxprofilt = strategyParam.Get <double>("maxprofilt"); //遍历K线 List <Object[]> listEarn = new List <object[]>(); List <Object[]> listLoss = new List <object[]>(); TradeRecords tr = new TradeRecords(); for (int index = bIndex; index < kline.Count; index++) { KLineItem item = kline[index]; if (item.Date >= endDate) { break; } double buyPrice = item.CLOSE; double maxProfiltEffenicePerStock = double.MinValue + 1; double maxLossEffenicePerStock = double.MaxValue - 1; int maxProfiltHoldDays = 0; int maxLossHoldDays = 0; KLineItem sellEarnItem = null; KLineItem sellLossItem = null; for (int i = 1; i < maxholddays; i++) { if (index + i >= kline.Count) { break; } KLineItem item2 = kline[index + i]; if ((item2.Date - item.Date).TotalDays > maxholddays) { break; } double eraningRates = (item2.CLOSE - buyPrice) / buyPrice; if (eraningRates > 0 && eraningRates >= maxprofilt && maxProfiltEffenicePerStock < eraningRates) { maxProfiltEffenicePerStock = eraningRates / i; maxProfiltHoldDays = i; sellEarnItem = item2; } if (eraningRates < 0 && maxLossEffenicePerStock > eraningRates) { maxLossEffenicePerStock = eraningRates; maxLossHoldDays = i; sellLossItem = item2; } } if (maxProfiltHoldDays > 0) { Object[] objs = new Object[] { item, sellEarnItem, maxProfiltEffenicePerStock, (sellEarnItem.CLOSE - buyPrice) / buyPrice }; listEarn.Add(objs); index = kline.IndexOf(sellEarnItem); } if (maxLossHoldDays > 0) { Object[] objs = new Object[] { item, sellLossItem, maxLossEffenicePerStock, (sellLossItem.CLOSE - buyPrice) / buyPrice }; listLoss.Add(objs); } } if (listEarn.Count <= 0) { return(null); } Comparison <Object[]> comparsionEran = (x, y) => { return((int)((double)y[2] - (double)x[2])); }; listEarn.Sort(comparsionEran); List <String> strs = new List <string>(); foreach (Object[] objs in listEarn) { KLineItem buyItem = (KLineItem)objs[0]; KLineItem sellItem = (KLineItem)objs[1]; String str = code + "," + ((double)objs[2]).ToString("F3") + "," + ((double)objs[3]).ToString("F3") + "," + (sellItem.Date - buyItem.Date).TotalDays.ToString() + "," + buyItem.Date.ToString("yyyyMMdd") + "," + sellItem.Date.ToString("yyyyMMdd") + "," + buyItem.CLOSE.ToString("F2") + "," + sellItem.CLOSE.ToString("F2"); strs.Add(str); logger.Info(str); } System.IO.File.AppendAllLines(backtestParam.Resultpath + "temp.csv", strs.ToArray(), Encoding.UTF8); return(null); }
public override bool DoSell(string code, TradeBout bout, DateTime d, Properties strategyParam, BacktestParameter backtestParam, out string reason) { reason = ""; if (bout == null) { return(false); } if (bout.Completed) { return(false); } //取得策略参数 int sell_maxholddays = strategyParam.Get <int>("maxholddays"); //最大持仓天数 int sell_notrun_num = strategyParam.Get <int>("sell_notrun_num"); //主力线与价格趋势不符允许出现的最大次数 int sell_selectnum = strategyParam.Get <int>("sell_selectnum"); //可以尝试的最大卖出次数 double sell_mainvalve = strategyParam.Get <double>("sell_mainvalve"); //主力线高位阈值 double sell_mainvalve_diff = strategyParam.Get <double>("sell_mainvalve_diff"); //主力线高位增幅 double sell_slopediff = strategyParam.Get <double>("sell_slopediff"); //主力线和收盘价的斜率差阈值 sell_slopediff = (sell_slopediff / 180) * Math.PI; double sell_slopepoint = strategyParam.Get <double>("sell_slopepoint"); //线性回归斜率的卖点 sell_slopepoint = (sell_slopepoint / 180) * Math.PI; GetInMode p_getinMode = (GetInMode)strategyParam.Get <GetInMode>("getinMode"); //取得行情数据 IndicatorRepository repository = (IndicatorRepository)backtestParam.Get <Object>("repository"); if (repository == null) { return(false); } TimeSerialsDataSet ds = repository[bout.Code]; if (ds == null) { return(false); } KLine kline = ds.DayKLine; TimeSeries <ITimeSeriesItem <List <double> > > dayFunds = ds.DayFundTrend; TimeSeries <ITimeSeriesItem <double> > dayFundsCross = ds.DayFundTrendCross; DateTime curDate = d; DateTime buyDate = bout.BuyInfo.TradeDate;//买入日期 d = buyDate.AddDays(1); int days = 1; //买入后的第几天 double prevMainFundValue = 0; //前一日的主力值 double mainFunddiff = 0; //主力线当日与前一日的差值 int is_slope_run = 0; //主力线和收盘价走势是否一致,0未知;1一致;-1,-2不一致 int sellnum = 0; //择机卖出次数 int state = 0; //当日状态;0未知;1 择机卖出(在连续sell_selectnum内只要不亏损就卖) String stateReason = ""; //卖出原因 while (d <= curDate) { //查找d日的资金线,找不到则跳过这天 int dayFundIndex = dayFunds.IndexOf(d); if (dayFundIndex < 0) { d = d.AddDays(1); continue; } ITimeSeriesItem <List <double> > dayFundsItem = dayFunds[dayFundIndex]; //查找当日K线,找不到则跳过这天 int dayKLineIndex = kline.IndexOf(d); if (dayKLineIndex < 0) { d = d.AddDays(1); continue; } KLineItem dayLineItem = kline[dayKLineIndex]; //对买入后的每一天 //1.计算以d日收盘价卖出的盈利情况 bout.RecordTrade(2, d, TradeDirection.Sell, kline[dayKLineIndex].CLOSE, bout.BuyInfo.Amount, backtestParam.Volumecommission, backtestParam.Stampduty); double earnRate = bout.EarningsRate; bout.TradeInfos[1] = null; //如果是择机卖出状态 if (state == 1) { if (sellnum > sell_selectnum || earnRate > 0) { bout.RecordTrade(2, d, TradeDirection.Sell, kline[dayKLineIndex].CLOSE, bout.BuyInfo.Amount, backtestParam.Volumecommission, backtestParam.Stampduty, stateReason + ",延迟天数=" + sellnum.ToString()); break; } sellnum += 1; d = d.AddDays(1); days += 1; continue; } //如果超过最大持仓天数,则进入到择机卖出 if (days >= sell_maxholddays) { state = 1; continue; } //趋势不一致出现sell_notrun_num次,择机卖出 if (is_slope_run <= -1 * sell_notrun_num) { stateReason = "主力线趋势不符" + is_slope_run.ToString() + "次数"; state = 1; d = d.AddDays(1); days += 1; continue; } //主力线超出预定值 if (sell_mainvalve != 0 && dayFunds[dayFundIndex].Value[0] >= sell_mainvalve) { if (prevMainFundValue == 0) { prevMainFundValue = dayFunds[dayFundIndex].Value[0]; d = d.AddDays(1); days += 1; continue; } else if ((dayFunds[dayFundIndex].Value[0] - prevMainFundValue) > sell_mainvalve_diff) { d = d.AddDays(1); days += 1; continue; } mainFunddiff = (dayFunds[dayFundIndex].Value[0] - prevMainFundValue); //如果盈利率小于0,延迟数天卖出 if (earnRate <= 0) { state = 1; stateReason = "主力线突破高位且增幅减缓" + mainFunddiff.ToString("F3"); d = d.AddDays(1); days += 1; continue; } //卖出操作 bout.RecordTrade(2, d, TradeDirection.Sell, dayLineItem.CLOSE, bout.BuyInfo.Amount, backtestParam.Volumecommission, backtestParam.Stampduty, "主力线突破高位且增幅减缓" + mainFunddiff.ToString("F3")); break; } //计算线性回归斜率 int begin = dayFunds.IndexOf(buyDate); int end = dayFundIndex; List <double> list1 = new List <double>(); for (int k = begin; k <= end; k++) { list1.Add(dayFunds[k].Value[0]); } double fundT = list1.Normalization().SLOPE(); begin = kline.IndexOf(buyDate); end = dayKLineIndex; List <double> list2 = new List <double>(); for (int k = begin; k <= end; k++) { list2.Add(kline[k].CLOSE); } double closeT = list2.Normalization().SLOPE(); //log.Info("斜率=" + fundT.ToString("F3") + "-" + closeT.ToString("F3") + "=" + Math.Abs(fundT - closeT).ToString("F3")); //两个线性回归斜率不一致 if (Math.Abs(fundT - closeT) >= sell_slopediff) { is_slope_run -= 1; } else //两个线性回归斜率一致 { if (fundT <= sell_slopepoint) { KLineItem prevKlineItem = kline[dayKLineIndex - 1]; if (prevKlineItem.CLOSE > dayLineItem.CLOSE)//价格下降了 { if (earnRate > 0) { bout.RecordTrade(2, d, TradeDirection.Sell, dayLineItem.CLOSE, bout.BuyInfo.Amount, backtestParam.Volumecommission, backtestParam.Stampduty, "斜率一致且增幅小于阈值(" + fundT.ToString("F2") + "<" + sell_slopepoint.ToString("F2")); break; } } /*if(earnRate>0) * { * bout.RecordTrade(2, d, TradeDirection.Sell, dayLineItem.CLOSE, bout.BuyInfo.Amount, backtestParam.volumecommission, backtestParam.stampduty, "斜率一致且增幅小于阈值("+ fundT.ToString("F2")+"<"+ sell_slopepoint.ToString("F2")); * break; * }*/ } } //进入下一天 d = d.AddDays(1); days += 1; continue; } return(false); }
public override TradeRecords Execute(string code, Properties strategyParam, BacktestParameter backtestParam, ISeller seller = null) { IndicatorRepository repository = (IndicatorRepository)backtestParam.Get <Object>("repository"); if (repository == null) { return(null); } //创建数据集 TimeSerialsDataSet ds = repository[code]; if (ds == null) { return(null); } KLine klineDay = ds.DayKLine; if (klineDay == null || klineDay.Count < 0) { return(null); } TimeSeries <ITimeSeriesItem <List <double> > > fundDay = ds.DayFundTrend; if (fundDay == null || fundDay.Count <= 0) { return(null); } double p_mainforcelow = strategyParam.Get <double>("mainforcelow"); int p_monthbutpt = strategyParam.Get <int>("monthbutpt", 0); //double p_mainforceclimb = strategyParam.Get<double>("mainforceclimb"); double p_mainforceslope = strategyParam.Get <double>("mainforceslope"); int p_mainforcerough = strategyParam.Get <int>("mainforcerough"); int p_buypointdays = strategyParam.Get <int>("buypointdays"); int p_maxbuynum = strategyParam.Get <int>("maxbuynum"); GetInMode p_fundpergetin = GetInMode.Parse(strategyParam.Get <String>("getinMode")); TradeRecords tradeRecords = new TradeRecords(code); //遍历回测中的每一天 DateTime d = backtestParam.BeginDate; int beginIndex = klineDay.IndexOf(d, true); if (beginIndex < 0) { return(tradeRecords); } for (int index = beginIndex; index < klineDay.Count; index++) { KLineItem klineItemDay = klineDay[index]; if (klineItemDay == null) { continue; } d = klineItemDay.Date; ITimeSeriesItem <List <double> > fundItemDay = fundDay[d]; if (fundItemDay == null) { continue; } int fIndex = fundDay.IndexOf(fundItemDay); //是否进入到主力线低位 if (p_mainforcelow != 0 && fundItemDay.Value[0] >= p_mainforcelow) { continue; } //是否主力线爬升离开低位 if (p_mainforcelow != 0) { for (fIndex = fIndex + 1; fIndex < fundDay.Count; fIndex++) { fundItemDay = fundDay[fIndex]; if (fundItemDay == null) { continue; } if (fundItemDay.Value[0] <= p_mainforcelow) { continue; } if (fundItemDay.Date < backtestParam.BeginDate || fundItemDay.Date > backtestParam.EndDate)//数据错误 { return(tradeRecords); } d = fundItemDay.Date; index = klineDay.IndexOf(d); klineItemDay = klineDay[index]; break; } if (fIndex >= fundDay.Count) { return(tradeRecords); } } //看主力线爬升速度 if (p_mainforceslope != 0 && fIndex > 0) { //爬升速度不够快 if ((fundItemDay.Value[0] - fundDay[fIndex - 1].Value[0]) < p_mainforceslope) { continue; } } //看主力线是否持续爬升 if (p_mainforcerough > 0) { bool cont = true; for (int temp = 0; temp < p_mainforcerough; temp++) { fIndex += temp; if (fIndex >= fundDay.Count) { cont = false; break; } fundItemDay = fundDay[fIndex]; if (fundItemDay.Value[0] < fundDay[fIndex - 1].Value[0]) { cont = false; break; } } if (!cont) { continue; } d = fundItemDay.Date; index = klineDay.IndexOf(d); klineItemDay = klineDay[index]; } //看是否在买点附近 TradingLine tradingLine = ds.DayTradeLine; if (p_buypointdays >= 0 && tradingLine != null && tradingLine.buysellPoints != null && tradingLine.buysellPoints.Count > 0) { int bsptIndex = tradingLine.buysellPoints.IndexOf(d, true); ITimeSeriesItem <char> bsptItemDay = bsptIndex < 0 ? null : tradingLine.buysellPoints[bsptIndex]; if (bsptItemDay != null && bsptItemDay.Value == 'S') { bsptItemDay = bsptIndex >= tradingLine.buysellPoints.Count - 1 ? null : tradingLine.buysellPoints[bsptIndex + 1]; } if (bsptItemDay == null || (bsptItemDay.Date.Date - d).TotalDays > p_buypointdays) { continue; } } //月线买点才能买入 TimeSeries <ITimeSeriesItem <char> > ptMonths = ds.CubePtCreateOrLoad(TimeUnit.month); if (p_monthbutpt == 1 && ptMonths != null && ptMonths.Count > 0) { int t1 = 0; for (; t1 < ptMonths.Count - 1; t1++) { if (d.Date >= ptMonths[t1].Date.Date && d.Date <= ptMonths[t1 + 1].Date.Date) { break; } } if (t1 < ptMonths.Count - 1) { if (ptMonths[t1].Value != 'B') { continue; } } } //准备执行买入 String reason = ""; double price = klineItemDay.CLOSE; double fund = p_fundpergetin.Value;// price * p_maxholdnum; int amount = (int)(fund / price); TradeBout newBout = new TradeBout(ds.Code); newBout.RecordTrade(1, d, TradeDirection.Buy, price, amount, backtestParam.Volumecommission, 0, reason); tradeRecords.Bouts.Add(newBout); } return(tradeRecords); }
private void createTrainTestData() { if (repository == null) { repository = new IndicatorRepository(textBox2.Text); repository.Initilization(); } String filename = textBox7.Text; FileInfo fInfo = new FileInfo(filename); String[] lines = File.ReadAllLines(filename); for (int i = 0; i < lines.Length; i++) { if (lines[i] == null || lines[i].Trim() == "") { continue; } int index = lines[i].IndexOf("\""); if (index < 0) { continue; } index = lines[i].IndexOf("\"", index + 1); if (index < 0) { continue; } index = lines[i].IndexOf("\"", index + 1); if (index < 0) { continue; } String label = lines[i].substring(index - 1, "\"", "\""); //"[-6.4500000000000002, '2007-05-17', 6]" String[] ss = label.Split(','); if (ss == null || ss.Length < 3) { continue; } String sDate = ss[1].Trim().Substring(1, 10); String code = ss[2].Substring(0, ss[2].Length - 2).Trim(); int len = code.Length; for (int j = 0; j < 6 - len; j++) { code = "0" + code; } DateTime d = DateTime.ParseExact(sDate, "yyyy-MM-dd", null); TimeSerialsDataSet ds = repository[code]; if (ds == null) { lines[i] = lines[i].Substring(0, index) + "\"[0.0,'" + sDate + "'," + code + "]\""; continue; } KLine kline = ds.DayKLine; KLineItem item = kline[d]; if (item == null) { lines[i] = lines[i].Substring(0, index) + "\"[0.0,'" + sDate + "'," + code + "]\""; continue; } double maxprofilt = -100; int itemIndex = kline.IndexOf(item); for (int k = itemIndex + 1; k < itemIndex + 5; k++) { if (k >= kline.Count) { break; } double p = (kline[k].CLOSE - item.CLOSE) / item.CLOSE; if (maxprofilt < p) { maxprofilt = p; } } if (maxprofilt == -100) { lines[i] = lines[i].Substring(0, index) + "\"[0.0,'" + sDate + "'," + code + "]\""; continue; } lines[i] = lines[i].Substring(0, index) + "\"[" + maxprofilt.ToString("F3") + ",'" + sDate + "'," + code + "]\""; } File.WriteAllLines(filename + "2", lines); }