/// <summary> /// 转文本 /// </summary> /// <param name="item"></param> /// <param name="valueFormat"></param> /// <param name="fileFormat">参见ConvertUtils.TEXT_XXX</param> /// <param name="propertyNames"></param> /// <returns></returns> public static String ToText(this ITimeSeriesItem item, String valueFormat, String fileFormat, params String[] propertyNames) { if (item == null) { return(""); } Object value = item.GetDefaultValue <Object>(); if (fileFormat == null || fileFormat == "") { fileFormat = ConvertUtils.TEXT_FMT_CSV; } PropertyDescriptorCollection pds = item.GetPropertyDescriptorCollection(); if (pds == null) { String temp = fileFormat.Replace("{$P}", "date").Replace("{$V}", item.Date.ToString(FMT_TIME)); return(temp + "," + fileFormat.Replace("{$P}", "value").Replace("{$V}", ConvertUtils.objectToStr(value, valueFormat))); } StringBuilder str = new StringBuilder(); for (int i = 0; i < pds.Count; i++) { PropertyDescriptor pd = pds[i]; if (str.ToString() != "") { str.Append(","); } String temp = fileFormat.Replace("{$P}", pd.Name).Replace("{$V}", ConvertUtils.objectToStr(item.GetValue <Object>(pd.name), pd.Format)); str.Append(temp); } return(str.ToString()); }
/// <summary> /// 判断指定的代码是否大盘可以买 /// </summary> /// <param name="d"></param> /// <param name="code"></param> /// <returns></returns> public bool CanBuy(DateTime d, String code) { if (!Enable) { return(true); //大盘参数无效,总是认为可以买 } int drailType = getDrailType(code); if (drailType < 0) { return(true); //不认识是哪个盘的,让它买 } if (this.bspts[drailType] == null) { return(true); } KeyValuePair <int, ITimeSeriesItem> kv = this.bspts[drailType].GetNearest(d); if (kv.Key < 0) { return(true); //没有找到前一个买卖点 } ITimeSeriesItem <char> item = (ITimeSeriesItem <char>)kv.Value; if (item.Value == 'B') { return(true); } else if (item.Value == 'S') { return(false); } return(true); }
public static void EMA(this TimeSeries <ITimeSeriesItem <double> > output, TimeSeries <ITimeSeriesItem> input, String valueName, int num, DateTime begin, DateTime end) { if (input == null || output == null) { return; } int tBegin = input.IndexOf(begin); for (DateTime t = begin; t <= end; t = t.AddDays(1)) { ITimeSeriesItem item = input[t]; if (item == null) { continue; } int index = output.IndexOf(t); if (output[index - 1] == null) { continue; } double p1 = 0; if (tBegin == 0) { p1 = item.GetValue <double>(valueName); } else { p1 = output[index - 1].GetDefaultValue <double>(); } double value = 0; if (valueName == null || valueName == "") { value = item.GetDefaultValue <double>(); } else { value = item.GetValue <double>(valueName); } //Y=[2*X+(N-1)*Y’]/(N+1) double y = (2 * value + (num - 1) * p1) / (num + 1); TimeSeriesItem <double> obj = new TimeSeriesItem <double>() { Date = t, Value = y }; output[t] = obj; } }
/// <summary> /// MA(X,N)简单算术平均 /// 求X的N日移动平均值,不分轻重,平均算。算法是: /// (X1+X2+X3+…..+Xn)/N /// 例如:MA(C,20)表示20日的平均收盘价。C表示CLOSE。 /// </summary> /// <param name="ts"></param> /// <param name="num"></param> /// <returns></returns> public static TimeSeries <ITimeSeriesItem <double> > MA(this TimeSeries <ITimeSeriesItem <double> > ts, int num) { TimeSeries <ITimeSeriesItem <double> > results = new TimeSeries <ITimeSeriesItem <double> >(); for (int i = num - 1; i < ts.Count; i++) { ITimeSeriesItem t = ts[i]; TimeSeriesItem <double> item = new TimeSeriesItem <double>() { Date = t.Date, Value = ts[i - num + 1, i].Sum(x => x.Value) / num }; results.Add(item); } return(results); }
/// <summary> /// VAR0:=(2*CLOSE+HIGH+LOW)/4; /// B:=XMA((VAR0-LLV(LOW,30))/(HHV(HIGH,30)-LLV(LOW,30))*100,12); /// 主力做多资金:EMA(B,3),LINETHICK2,COLORWHITE; /// </summary> /// <param name="kline"></param> /// <param name="begin"></param> /// <param name="end"></param> /// <param name="param"></param> /// <returns></returns> public static TimeSeries <ITimeSeriesItem <List <double> > > executeIndicator(this KLine kline, int begin = 0, int end = 0, PropertyDescriptorCollection param = null) { TimeSeries <ITimeSeriesItem <double> > close = kline.Select <double>("CLOSE", begin, end); TimeSeries <ITimeSeriesItem <double> > open = kline.Select <double>("OPEN", begin, end); TimeSeries <ITimeSeriesItem <double> > high = kline.Select <double>("HIGH", begin, end); TimeSeries <ITimeSeriesItem <double> > low = kline.Select <double>("LOW", begin, end); TimeSeries <ITimeSeriesItem <double> > VAR0 = (close * 2.0 + high + low) / 4; TimeSeries <ITimeSeriesItem <double> > t1 = VAR0 - low.LLV(20); TimeSeries <ITimeSeriesItem <double> > t2 = high.HHV(20) - low.LLV(20); TimeSeries <ITimeSeriesItem <double> > t3 = (t1 / t2) * 100; //TimeSeries<ITimeSeriesItem<double>> B = t3.XMA(12); TimeSeries <ITimeSeriesItem <double> > B = t3.EMA(12); TimeSeries <ITimeSeriesItem <double> > mainforces = B.EMA(3); TimeSeries <ITimeSeriesItem <double> > retailInverstors = mainforces.EMA(30); TimeSeries <ITimeSeriesItem <List <double> > > results = new TimeSeries <ITimeSeriesItem <List <double> > >(); foreach (ITimeSeriesItem <double> mainforce in mainforces) { TimeSeriesItem <List <double> > r = new TimeSeriesItem <List <double> >(); r.Value = new List <double>(new double[2] { 0, 0 }); r.Date = mainforce.Date; r.Value[0] = mainforce.Value; ITimeSeriesItem <double> retailInverstor = retailInverstors[r.Date]; r.Value[1] = retailInverstor == null ? 0 : retailInverstor.Value; results.Add(r); } return(results); }
/// <summary> /// 判断大盘数据是否要求代码在d日必须卖 /// </summary> /// <param name="d"></param> /// <param name="code"></param> /// <returns></returns> public bool MustSell(DateTime d, String code) { if (!Enable) { return(false); } int drailType = getDrailType(code); if (drailType < 0) { return(false); //不认识是哪个盘的,不是必须卖 } if (this.bspts[drailType] == null) { return(false); } KeyValuePair <int, ITimeSeriesItem> kv = bspts[drailType].GetNearest(d); if (kv.Key < 0) { return(false); } ITimeSeriesItem <char> item = (ITimeSeriesItem <char>)kv.Value; if (item.Value == 'B') { return(false); } else if (item.Value == 'S') { return(true); } return(false); }
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); }
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 int CompareTo(ITimeSeriesItem other) { return((int)(this.Date.Ticks - other.Date.Ticks)); }
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> /// DIF:EMA(CLOSE,SHORT)-EMA(CLOSE,LONG); /// DEA:EMA(DIF, MID); /// MACD:(DIF-DEA)*2,COLORSTICK; /// 其中SHORT = 12,LONG = 26,MID = 9 /// </summary> /// <param name="kline"></param> /// <returns></returns> public static MACD Create(KLine kline) { if (kline == null) { return(null); } int p_short = 12, p_long = 26, p_mid = 9; TimeSeries <ITimeSeriesItem <double> > CLOSE = kline.Select <double>("close"); TimeSeries <ITimeSeriesItem <double> > DIF = CLOSE.EMA(p_short) - CLOSE.EMA(p_long); TimeSeries <ITimeSeriesItem <double> > DEA = DIF.EMA(p_mid); TimeSeries <ITimeSeriesItem <double> > MACD = (DIF - DEA) * 2; MACD macd = new MACD(kline.Code, kline.TimeUnit); double prevDif = 0, prevdea = 0; for (int i = 0; i < kline.Count; i++) { DateTime d = kline[i].Date; MACDItem item = new MACDItem(); item.Date = d; ITimeSeriesItem <double> difItem = DIF[d]; if (difItem == null) { continue; } item.DIF = difItem.Value; if (prevDif == 0) { prevDif = difItem.Value; } ITimeSeriesItem <double> deaItem = DEA[d]; if (deaItem == null) { continue; } item.DEA = deaItem.Value; if (prevdea == 0) { prevdea = deaItem.Value; } ITimeSeriesItem <double> macdItem = MACD[d]; if (macdItem == null) { continue; } item.MACD = macdItem.Value; if (prevDif < prevdea && difItem.Value > deaItem.Value) { item.CROSS = difItem.Value - deaItem.Value;//金叉点 } else if (prevDif > prevdea && difItem.Value < deaItem.Value) { item.CROSS = difItem.Value - deaItem.Value;//死叉点 } macd.Add(item); prevDif = difItem.Value; prevdea = deaItem.Value; } return(macd); }
/// <summary> /// 买线:EMA(CLOSE,3),COLORRED,LINETHICK1; /// 卖线:EMA(SLOPE(CLOSE,21)*20+CLOSE,42),COLORBLUE,LINETHICK2; /// </summary> /// <param name="kline"></param> /// <returns></returns> public static TradingLine indicator_trading_stereo1(this KLine kline, int begin = 0, int end = 0) { TimeSeries <ITimeSeriesItem <double> > close = kline.Select <double>("close", begin, end); TimeSeries <ITimeSeriesItem <double> > buyLine = close.EMA(3); TimeSeries <ITimeSeriesItem <double> > sellLine = (close.SLOPE(21) * 20 + close).EMA(42); TimeSeries <ITimeSeriesItem <char> > buysellPoints = new TimeSeries <ITimeSeriesItem <char> >(); int buy_gt_sell = 1, sell_gt_buy = 2; //买大于卖为1,卖大于买为2 int state = 0; //前一个状态 for (int i = 0; i < buyLine.Count; i++) { ITimeSeriesItem <double> buyItem = buyLine[i]; ITimeSeriesItem <double> sellItem = sellLine[buyItem.Date]; if (sellItem == null) { continue; } double t = buyItem.Value - sellItem.Value; if (t == 0) { continue; } if (state == 0) { state = t > 0 ? buy_gt_sell : sell_gt_buy; continue; } int cs = t > 0 ? buy_gt_sell : sell_gt_buy; if (cs == state) { continue; } if (state == buy_gt_sell) { TimeSeriesItem <char> v = new TimeSeriesItem <char>() { Date = buyItem.Date, Value = 'S' }; buysellPoints.Add(v); } else if (state == sell_gt_buy) { TimeSeriesItem <char> v = new TimeSeriesItem <char>() { Date = buyItem.Date, Value = 'B' }; buysellPoints.Add(v); } state = cs; } return(new TradingLine() { buyLine = buyLine, sellLine = sellLine, buysellPoints = buysellPoints }); }
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 static String ToText(this ITimeSeriesItem item, String valueFormat) { return(ToText(item, valueFormat, ConvertUtils.TEXT_FMT_CSV)); }
public static String ToText(this ITimeSeriesItem item, String valueFormat, params String[] propertyNames) { return(ToText(item, valueFormat, ConvertUtils.TEXT_FMT_CSV, propertyNames)); }
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 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); }
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 static String ToText(this ITimeSeriesItem item) { return(ToText(item, "", ConvertUtils.TEXT_FMT_CSV)); }
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); }