/// <summary> /// 根据个股S点卖出 /// </summary> /// <param name="bouts"></param> /// <param name="ds"></param> /// <param name="strategyParam"></param> /// <param name="backtestParam"></param> public void DoSell1(TradeRecords tradeRecords, TimeSerialsDataSet ds, Properties strategyParam, BacktestParameter backtestParam) { TimeSeries <ITimeSeriesItem <char> > dayTradePt = ds.CubePtCreateOrLoad(); if (dayTradePt == null) { return; } if (tradeRecords == null || tradeRecords.Bouts == null || tradeRecords.Bouts.Count <= 0) { return; } KLine dayLine = ds.DayKLine; if (dayLine == null) { return; } foreach (TradeBout bout in tradeRecords.Bouts) { DateTime buyDate = bout.BuyInfo.TradeDate; KeyValuePair <int, ITimeSeriesItem> dayTradePtItem = dayTradePt.GetNearest(buyDate, false); if (dayTradePtItem.Key < 0) { continue; } if (dayTradePtItem.Value == null) { continue; } int index = dayTradePt.IndexOf(dayTradePtItem.Value.Date); for (int k = index; k < dayTradePt.Count; k++) { if (dayTradePt[k].Value == 'S') { KLineItem dayLineItem = dayLine[dayTradePt[k].Date]; if (dayLineItem == null) { break; } bout.RecordTrade(2, dayLineItem.Date, TradeDirection.Sell, dayLineItem.CLOSE, bout.BuyInfo.Amount, 0, 0, "发S点"); break; } } } }
/// <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, ""); } }
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()); } }
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); } TimeSeries <ITimeSeriesItem <char> > btpoints = ds.DayTradeLine.buysellPoints; if (btpoints == null || btpoints.Count <= 0) { return(false); } ITimeSeriesItem <char> item = btpoints[d]; if (item == null || item.Value == 'B') { return(false); } KLineItem klineItemDay = kline[d]; if (klineItemDay == null) { return(false); } double price = klineItemDay.CLOSE; //if (price < bout.BuyInfo.TradePrice) // return true; int amount = bout.BuyInfo.Amount; bout.RecordTrade(2, klineItemDay.Date, TradeDirection.Sell, price, amount, backtestParam.Volumecommission, backtestParam.Stampduty, "日线出S点"); 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); } //取得策略参数 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); } MACD macd = (MACD)ds.Create("macd", TimeUnit.day, false); if (macd == null) { return(null); } //买入条件判定 for (int i = 0; i < macd.Count; i++) { MACDItem macdItem = macd[i]; if (macdItem.Date < backtestParam.BeginDate || macdItem.Date >= backtestParam.EndDate) { continue; } if (macdItem.CROSS <= 0) { continue; } if (macdItem.DIF > buy_mainlow) { continue; } DateTime d = macdItem.Date; KLineItem klineItem = kline[d]; if (klineItem == null) { continue; } TradeBout bout = new TradeBout(code); bout.RecordTrade(1, d, TradeDirection.Buy, klineItem.CLOSE, (int)(p_getinMode.Value / klineItem.CLOSE), backtestParam.Volumecommission, backtestParam.Stampduty, "低位金叉" + macdItem.DIF.ToString("F2")); tr.Bouts.Add(bout); } return(tr); }
public override List <TradeInfo> DoBuy(Properties strategyParam, DateTime d, StrategyContext context) { //取得行情库 IndicatorRepository repository = (IndicatorRepository)context.Get <Object>("repository"); if (repository == null) { return(null); } //读取代码 List <String> codes = LoadCodes(strategyParam, context); if (codes == null || codes.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")); GrailParameter p_grail = GrailParameter.Parse(strategyParam.Get <String>("grail")); double stampduty = context.Get <double>("stampduty"); double volumecommission = context.Get <double>("volumecommission"); List <TradeInfo> results = new List <TradeInfo>(); //遍历 foreach (String code in codes) { TimeSerialsDataSet ds = repository[code]; if (ds == null) { continue; } KLine klineDay = ds.DayKLine; if (klineDay == null) { continue; } KLineItem klineItemDay = klineDay[d]; if (klineItemDay == null) { continue; } TimeSeries <ITimeSeriesItem <List <double> > > fundDay = ds.DayFundTrend; if (fundDay == null) { continue; } ITimeSeriesItem <List <double> > fundItemDay = fundDay[d]; if (fundItemDay == null) { continue; } int index = fundDay.IndexOf(fundItemDay); if (index <= 0) { continue; } ITimeSeriesItem <List <double> > prevfundItemDay = fundDay[index - 1]; if (!p_grail.CanBuy(d, code)) //大盘禁止买入的跳过 { continue; } if (p_mainforcelow > 0)//判断主力线上穿p_mainforcelow { if (fundItemDay.Value[0] < p_mainforcelow) { continue; } if (prevfundItemDay.Value[0] > p_mainforcelow) { continue; } } if (p_mainforceslope > 0) //判断主力线上升速度超过p_mainforceslope { if (fundItemDay.Value[0] - prevfundItemDay.Value[0] < p_mainforceslope) { continue; } } TradeInfo tradeInfo = new TradeInfo() { Direction = TradeDirection.Buy, Code = code, Amount = (int)(p_fundpergetin.Value / klineItemDay.CLOSE), EntrustPrice = klineItemDay.CLOSE, EntrustDate = d, TradeDate = d, TradePrice = klineItemDay.CLOSE, Stamps = stampduty, Fee = volumecommission, TradeMethod = TradeInfo.TM_AUTO, Reason = (p_mainforcelow <= 0 ? "" : "[主力线低位" + p_mainforcelow.ToString("F2") + "]") + (p_mainforceslope <= 0 ? "" : "[主力线上升速度超过" + p_mainforceslope.ToString("F2") + "]") }; results.Add(tradeInfo); } return(results); }
/// <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); }
/// <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 override TradeRecords DoBuy(TimeSerialsDataSet ds, Properties strategyParam, BacktestParameter backtestParam) { TimeSeries <ITimeSeriesItem <List <double> > > dayFunds = ds.FundTrendCreateOrLoad(TimeUnit.day); TimeSeries <ITimeSeriesItem <List <double> > > weekFunds = ds.FundTrendCreateOrLoad(TimeUnit.week); TimeSeries <ITimeSeriesItem <double> > dayCross = ds.FundTrendCrossCreateOrLoad(TimeUnit.day); TimeSeries <ITimeSeriesItem <double> > weekCross = ds.FundTrendCrossCreateOrLoad(TimeUnit.day); if (dayFunds == null || dayFunds.Count <= 0 || weekFunds == null || weekFunds.Count <= 0 || dayCross == null || dayCross.Count <= 0 || weekCross == null || weekCross.Count <= 0) { return(null); } TradeRecords tr = new TradeRecords(ds.Code); DateTime begin = backtestParam.BeginDate; DateTime end = backtestParam.EndDate; double p_day_low = strategyParam.Get <double>("day_low"); double p_day_bias = strategyParam.Get <double>("day_bias"); double p_week_low = strategyParam.Get <double>("week_low"); double p_week_bias = strategyParam.Get <double>("week_bias"); GetInMode p_getinMode = (GetInMode)strategyParam.Get <Object>("getinMode"); for (int i = 0; i < dayFunds.Count; i++) { ITimeSeriesItem <List <double> > dayFundItem = dayFunds[i]; if (dayFundItem == null) { continue; } if (dayFundItem.Date < begin || dayFundItem.Date >= end) { continue; } if ((dayFundItem.Value[0] - dayFundItem.Value[1]) < p_day_bias) { continue; } DateTime td = CalendarUtils.GetWeek(dayFundItem.Date, DayOfWeek.Friday); ITimeSeriesItem <List <double> > weekFundItem = weekFunds[td]; if (weekFundItem == null) { continue; } if ((weekFundItem.Value[0] - weekFundItem.Value[1]) < p_week_bias) { continue; } KLine dayLine = ds.DayKLine; if (dayLine == null) { continue; } KLineItem dayLineItem = dayLine[dayFundItem.Date]; if (dayLineItem == null) { continue; } TradeBout bout = new TradeBout(ds.Code); bout.RecordTrade(1, dayFundItem.Date, TradeDirection.Buy, dayLineItem.CLOSE, (int)(p_getinMode.Value / dayLineItem.CLOSE), 0, 0, Name); tr.Bouts.Add(bout); } return(tr); }
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); }
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); } TimeSeries <ITimeSeriesItem <char> > ts = ds.DayTradeLine.buysellPoints; if (ts == null) { return(null); } TimeSeries <ITimeSeriesItem <List <double> > > fundTrends = ds.DayFundTrend; KLine kline = ds.DayKLine; TradeRecords tr = new TradeRecords(code); GetInMode getin = GetInMode.Parse(strategyParam.Get <String>("getinMode")); int diffdays = strategyParam.Get <int>("diffdays"); for (int i = 0; i < ts.Count; i++) { if (ts[i].Date.Date < backtestParam.BeginDate) { continue; } if (ts[i].Date.Date >= backtestParam.EndDate) { continue; } if (ts[i].Value == 'S') { continue; } TradeBout bout = new TradeBout(code); //主力线大于散户线,且连续diffdays天与散户线拉大距离 if (diffdays > 0 && fundTrends != null) { int fi = fundTrends.IndexOf(ts[i].Date); if (fi < 0 || fi < diffdays - 1) { continue; } ITimeSeriesItem <List <double> > ftItem = fundTrends[fi]; if (ftItem.Value[0] >= 30) { continue; } double diff = ftItem.Value[0] - ftItem.Value[1]; if (diff <= 0) { continue; } bool continuekuoda = true; for (int t = 1; t < diffdays; t++) { ftItem = fundTrends[fi - i]; double tDiff = ftItem.Value[0] - ftItem.Value[1]; if (diff < tDiff) { continuekuoda = false; break; } diff = tDiff; } if (!continuekuoda) { continue; } } KLineItem item = kline[ts[i].Date]; bout.RecordTrade(1, ts[i].Date, TradeDirection.Buy, item.CLOSE, (int)(getin.Value / item.CLOSE), backtestParam.Volumecommission, backtestParam.Stampduty, "B"); tr.Bouts.Add(bout); } return(tr); }
/// <summary> /// 导入数据 /// </summary> public bool doMergeToRepository() { showBeginMessage("开始合并数据..."); if (repository == null) { repository = new IndicatorRepository(FileUtils.GetDirectory(props.Get <String>("repository"))); repository.Initilization(); } String datapath = FileUtils.GetDirectory(props.Get <String>("datapath")); DirectoryInfo dInfo = new DirectoryInfo(datapath); FileInfo[] fInfos = dInfo.GetFiles("*.scv"); if (fInfos == null || fInfos.Length <= 0) { showResultMessage("没有需要导入的新文件", 1); return(false); } try { foreach (FileInfo fInfo in fInfos) { String code = fInfo.Name.Substring(3, 6); TimeSerialsDataSet ds = repository[code]; KLine kline = ds.DayKLine; if (ds == null) { continue; } showProgressMessage(code); CSVFile csvFile = new CSVFile(); csvFile.Load(fInfo.FullName, Encoding.UTF8, false, ","); List <String> lines = csvFile.Lines; for (int i = lines.Count - 1; i >= 0; i--) { if (lines[i] == null || lines[i].Trim() == "") { continue; } String[] ss = lines[i].Split(','); if (ss == null || ss.Length < 7) { continue; } DateTime d = DateUtils.Parse(ss[0]); KLineItem item = kline[d]; if (item != null) { break; } double[] v = new double[6]; for (int j = 0; j < v.Length; j++) { v[j] = double.Parse(ss[j + 1]); } item = new KLineItem(); item.Date = d; item.SetValue <double>("OPEN", v[0]); item.SetValue <double>("HIGH", v[1]); item.SetValue <double>("LOW", v[2]); item.SetValue <double>("CLOSE", v[3]); item.SetValue <double>("VOLUME", v[4]); item.SetValue <double>("TURNOVER", v[5]); kline.Add(item); } ds.Save("kline", TimeUnit.day); } showResultMessage(""); return(true); } catch (Exception e) { showResultMessage("导入失败", -1, e.Message); 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); }
/// <summary> /// 执行方法 /// </summary> /// <param name="context"></param> public override void Execute(CommandContext context) { logger.Debug("执行命令:" + this.ToString()); //取得参数 everydayLinePath = (String)context.GetExternalValue(everydayLinePath); dayLineReposorityPath = (String)context.GetExternalValue(dayLineReposorityPath); mergeDateString = (String)context.GetExternalValue(mergeDateString); mergeDate = DateUtils.Parse(mergeDateString); logger.Debug("取得参数:源路径=" + everydayLinePath + ",合并路径=" + dayLineReposorityPath + ",日期=" + mergeDateString); if (!everydayLinePath.EndsWith("\\")) { everydayLinePath += "\\"; } if (!dayLineReposorityPath.EndsWith("\\")) { dayLineReposorityPath += "\\"; } IndicatorRepository repository = (IndicatorRepository)context.GetExternalValue("{$repository}"); //检查路径 DirectoryInfo dFromInfo = new DirectoryInfo(everydayLinePath); if (!dFromInfo.Exists) { throw new Exception("单日日线存储路径不存在:" + everydayLinePath); } DirectoryInfo dToInfo = new DirectoryInfo(dayLineReposorityPath); if (!dToInfo.Exists) { throw new Exception("日线存储仓库路径不存在:" + dayLineReposorityPath); } FileInfo[] finfos = dFromInfo.GetFiles("*.txt"); logger.Debug("共有" + (finfos == null ? "0" : finfos.Length.ToString()) + "个单日K线数据待合并..."); foreach (FileInfo fInfo in finfos) { logger.Debug("处理" + fInfo.Name + "..."); String market = fInfo.Name.Substring(0, fInfo.Name.IndexOf("#")); String code = fInfo.Name.substring(0, "#", "."); String[] lines = File.ReadAllLines(fInfo.FullName); for (int i = 0; i < lines.Length; i++) { if (lines[i] == null || lines[i] == "") { continue; } if (!lines[i].Contains(",")) { continue; } String[] ss = lines[i].Trim().Split(','); if (ss == null || ss.Length != 7) { continue; } if (ss[0] == null) { continue; } DateTime d = DateUtils.InitDate; if (!DateUtils.TryParse(ss[0].Trim(), out d)) { continue; } if (d.Date != this.mergeDate.Date) { continue; } KLineItem item = new KLineItem(); item.SetValue <String>(KLineItem.PD_CODE.Name, code); item.SetValue <DateTime>(KLineItem.PD_TIME.Name, d); item.SetValue <double>(KLineItem.PD_OPEN.Name, ConvertUtils.ConvertTo <double>(ss[1].Trim())); item.SetValue <double>(KLineItem.PD_HIGH.Name, ConvertUtils.ConvertTo <double>(ss[2].Trim())); item.SetValue <double>(KLineItem.PD_LOW.Name, ConvertUtils.ConvertTo <double>(ss[3].Trim())); item.SetValue <double>(KLineItem.PD_CLOSE.Name, ConvertUtils.ConvertTo <double>(ss[4].Trim())); item.SetValue <double>(KLineItem.PD_VOLUMN.Name, ConvertUtils.ConvertTo <double>(ss[5].Trim())); item.SetValue <double>(KLineItem.PD_TURNOVER.Name, ConvertUtils.ConvertTo <double>(ss[6].Trim())); TimeSerialsDataSet ds = repository[code]; if (ds == null) { continue; } ds.DayKLine[d.Date] = item; ds.Save("kline", TimeUnit.day); logger.Debug("合并到" + market.ToUpper() + code + ".csv"); } } }
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); }
/// <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 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); }
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); }
private void button12_Click(object sender, EventArgs e) { String code = textBox4.Text; DateTime begin = dateTimePicker3.Value; DateTime end = dateTimePicker4.Value; int days = int.Parse(textBox5.Text); if (repository == null) { repository = new IndicatorRepository(textBox2.Text); repository.Initilization(); } TimeSerialsDataSet ds = repository[code]; if (ds == null || ds.DayKLine == null) { MessageBox.Show("代码" + code + "缺少K线数据"); } KLine klineDay = ds.DayKLine; KLineItem item = null; List <double[]> datas = new List <double[]>(); for (int i = 0; i < klineDay.Count; i++) { item = klineDay[i]; if (item.Date < begin) { continue; } if (item.Date > end) { break; } double maxprofilt = -100; for (int j = i + 1; j <= i + 1 + days; j++) { if (j >= klineDay.Count) { break; } double p = (klineDay[j].CLOSE - item.CLOSE) / item.CLOSE; if (maxprofilt < p) { maxprofilt = p; } } if (maxprofilt == -100) { continue; } double[] values = new double[2]; values[0] = item.CLOSE; values[1] = maxprofilt; datas.Add(values); } if (datas.Count <= 0) { MessageBox.Show("没有有效数据"); return; } String[] lines = datas.ConvertAll(x => x[0].ToString("F2") + "," + x[1].ToString("F3")).ToArray(); File.WriteAllLines("d:\\" + code + ".csv", lines); }