//重载OnRecvDataMsg方法,接收行情数据 // 请注意: // 1. 不要在这个函数里做耗时操作 // 2. 只在这个函数里做数据获取工作 -- 将数据复制到其它数据缓存区,由其它线程做业务逻辑处理 public override void OnRecvDataMsg(TDFMSG msg) { try { if (msg.MsgID == TDFMSGID.MSG_DATA_MARKET) { //行情消息 TDFMarketData[] marketDataArr = msg.Data as TDFMarketData[]; foreach (TDFMarketData data in marketDataArr) { //if (data.Code.Contains("10000015")) // continue; lock (this.dataDict) { if (dataDict.Keys.Contains(data.Code)) { SingleStockData sd = dataDict[data.Code]; //数据获取部分 if (data.Match != 0) { sd.LastPrice = (double)data.Match / 10000; //最新成交价 } sd.PrevClose = (double)data.PreClose / 10000; sd.AskPrices[0] = (double)data.AskPrice[0] / 10000; sd.BidPrices[0] = (double)data.BidPrice[0] / 10000; for (int i = 0; i < 10; i++) { sd.BidPrices[i] = (double)data.BidPrice[i] / 10000; sd.AskPrices[i] = (double)data.AskPrice[i] / 10000; sd.BidVol[i] = data.BidVol[i]; sd.AskVol[i] = data.AskVol[i]; } if ((sd.ShortPriceListed != sd.AskPrices[0]) && (sd.StatusTrending == StrategyStatus.ShortListedOnly)) //最新卖一已变动,需改价重挂 { sd.bAskPriceChanged = true; //测试,按卖五挂单 } # region Fishing Strategies //业务逻辑部分,只有对FishingStrategy这样时效要求极高的放在此处,其余均放入EngineClass if (sd.StatusCBFishing != StrategyStatus.None) //此ticker需要跑CBFishing Strategy { if (sd.StatusCBFishing == StrategyStatus.New) //首次挂买单,或上一轮结束后重新挂单 { //sd.LongPriceListed = sd.BidPrices[0] - sd.CBBuyPriceOffset; //挂在卖五,后续可以参数化 sd.LongPriceListed = sd.BidPrices[4]; //挂在卖五,后续可以参数化 sd.StatusCBFishing = StrategyStatus.LongListedOnly; //下一步考虑在EngineClass或TradeClass中生成Order,只需有strategy和ticker,即可在dataDict中取到生成order所需数据 FIXApi.OrderBookEntry entry = new OrderBookEntry(); entry.strategies = TradingStrategies.CBFishing; entry.action = OrderAction.Buy; entry.type = FIXApi.OrderType.CreditBuy; entry.ticker = data.Code; entry.quantityListed = sd.Quantity; entry.priceListed = sd.LongPriceListed; sd.StatusCBFishing = StrategyStatus.Pending; //获得成交回报后再改变状态,避免重复执行 Thread orderThread = new Thread(new ParameterizedThreadStart(tc.OrderSender_CBFishing)); orderThread.IsBackground = true; orderThread.Start(entry); } else if (sd.StatusCBFishing == StrategyStatus.LongListedOnly) //买单已挂,根据最新价格检查是否需要撤单重挂 { if ((sd.LongPriceListed >= sd.BidPrices[3]) || (sd.LongPriceListed <= sd.BidPrices[5])) //大于卖三或小于卖七时重挂 { sd.LongPriceListed = sd.BidPrices[0] - sd.CBBuyPriceOffset; FIXApi.OrderBookEntry entry = new OrderBookEntry(); entry.strategies = TradingStrategies.CBFishing; entry.action = OrderAction.CancelAndBuy; entry.type = FIXApi.OrderType.CreditBuy; entry.ticker = data.Code; entry.quantityListed = sd.Quantity; entry.priceListed = sd.LongPriceListed; sd.StatusCBFishing = StrategyStatus.Pending; //获得成交回报后再改变状态,避免重复执行 Thread orderThread = new Thread(new ParameterizedThreadStart(tc.OrderSender_CBFishing)); orderThread.IsBackground = true; orderThread.Start(entry); } //if ((sd.ShortPriceListed<data.AskPrice[4]) || (sd.ShortPriceListed>data.AskPrice[6]) ) //低于卖五或者高于卖七时撤单重挂,避免撤单过于频繁 // sd.ShortPriceListed = sd.AskPrices[4]; ////cancel and resend } else if (sd.StatusCBFishing == StrategyStatus.ShortListedOnly) //卖单已挂,根据最新价格检查是否需要撤单重挂 { if (sd.ShortPriceListed > sd.AskPrices[0]) { sd.ShortPriceListed = sd.AskPrices[0] - sd.CBSellPriceOffset; //一直挂在比卖一低0.01的位置 FIXApi.OrderBookEntry entry = new OrderBookEntry(); entry.strategies = TradingStrategies.CBFishing; entry.action = OrderAction.CancelAndSell_CF; entry.type = FIXApi.OrderType.CreditSell; entry.ticker = data.Code; entry.quantityListed = sd.Quantity; entry.priceListed = sd.ShortPriceListed; entry.strategies = TradingStrategies.CBFishing; sd.StatusCBFishing = StrategyStatus.Pending; //获得成交回报后再改变状态,避免重复执行 Thread orderThread = new Thread(new ParameterizedThreadStart(tc.OrderSender_CBFishing)); orderThread.IsBackground = true; orderThread.Start(entry); } //if ((sd.ShortPriceListed<data.AskPrice[4]) || (sd.ShortPriceListed>data.AskPrice[6]) ) //低于卖五或者高于卖七时撤单重挂,避免撤单过于频繁 // sd.ShortPriceListed = sd.AskPrices[4]; ////cancel and resend } else if (sd.StatusStockFishing != StrategyStatus.None) //此ticker需要跑StockFishing Strategy { } } # endregion } } } //极其耗时,轻易不要打开 //RecvDataReport(this, null); } else if (msg.MsgID == TDFMSGID.MSG_DATA_FUTURE) { //期货行情消息 TDFFutureData[] futureDataArr = msg.Data as TDFFutureData[]; foreach (TDFFutureData data in futureDataArr) { ; } return; } else if (msg.MsgID == TDFMSGID.MSG_DATA_INDEX) { //指数消息 TDFIndexData[] indexDataArr = msg.Data as TDFIndexData[]; foreach (TDFIndexData data in indexDataArr) { return; } } else if (msg.MsgID == TDFMSGID.MSG_DATA_TRANSACTION) { //逐笔成交 TDFTransaction[] transactionDataArr = msg.Data as TDFTransaction[]; foreach (TDFTransaction data in transactionDataArr) { //每一data变量包含最底层的一笔逐笔成交数据 lock (this.dataDict) { if (dataDict.Keys.Contains(data.Code)) { //数据获取部分 int timeStamp = Convert.ToInt32((double)data.Time / 1000 - 0.5); //去掉毫秒部分; if (timeStamp == 93524) { timeStamp = 93524; } int direction = 0; if (data.BSFlag == 66) { direction = 1; } else if (data.BSFlag == 83) { direction = -1; } int volume = data.Volume; double price = (double)data.Price / 10000; if (dataDict[data.Code].zbDataList.Count == 0) //第一次添加 { ZBTickData zbdata = new ZBTickData(); zbdata.timeStamp = timeStamp; if (direction == 1) { zbdata.volumeB = volume; zbdata.priceTotalB = price; zbdata.countB = 1; zbdata.priceB = zbdata.priceTotalB / (double)zbdata.countB;//计算该秒、买方向的平均价格 } else if (direction == -1) { zbdata.volumeS = volume; zbdata.priceTotalS = price; zbdata.countS = 1; zbdata.priceS = zbdata.priceTotalS / (double)zbdata.countS;//计算该秒、买方向的平均价格 } if ((zbdata.priceB > 0) && (zbdata.priceS > 0)) { zbdata.price = (zbdata.priceB + zbdata.priceS) / 2; } else { zbdata.price = (zbdata.priceB + zbdata.priceS); } zbdata.volume = zbdata.volumeB + zbdata.volumeS; if ((zbdata.volume == 0) || (zbdata.price == 0)) { continue; //空记录 } dataDict[data.Code].zbDataList.Add(zbdata); dataDict[data.Code].ZBFirstIndex = 0; dataDict[data.Code].ZBLastIndex = 0; } else { int currLastIndex = dataDict[data.Code].ZBLastIndex; if (dataDict[data.Code].zbDataList[currLastIndex].timeStamp == timeStamp) //同一时间戳存在,只需更新价格与成交量,不需插入新纪录 { ZBTickData zbdata = dataDict[data.Code].zbDataList[currLastIndex]; //取出字典中的元素并进行修改,由于是引用,对zbdata的修改会自动在字典中更新 if (direction == 1) { zbdata.priceTotalB = zbdata.priceTotalB + price; zbdata.countB = zbdata.countB + 1; zbdata.priceB = zbdata.priceTotalB / (double)zbdata.countB;//计算该秒、该方向的平均价格 zbdata.volumeB = zbdata.volumeB + volume; } else if (direction == -1) { zbdata.priceTotalS = zbdata.priceTotalS + price; zbdata.countS = zbdata.countS + 1; zbdata.priceS = zbdata.priceTotalS / (double)zbdata.countS;//计算该秒、该方向的平均价格 zbdata.volumeS = zbdata.volumeS + volume; } if ((zbdata.priceB > 0) && (zbdata.priceS > 0)) { zbdata.price = (zbdata.priceB + zbdata.priceS) / 2; } else { zbdata.price = (zbdata.priceB + zbdata.priceS); } zbdata.volume = zbdata.volumeB + zbdata.volumeS; dataDict[data.Code].zbDataList.RemoveAt(currLastIndex); dataDict[data.Code].zbDataList.Add(zbdata); } else //不存在此时间戳,需添加新纪录 { ZBTickData zbdata = new ZBTickData(); zbdata.timeStamp = timeStamp; if (direction == 1) { zbdata.volumeB = volume; zbdata.priceTotalB = price; zbdata.countB = 1; zbdata.priceB = zbdata.priceTotalB / (double)zbdata.countB;//计算该秒、买方向的平均价格 } else if (direction == -1) { zbdata.volumeS = volume; zbdata.priceTotalS = price; zbdata.countS = 1; zbdata.priceS = zbdata.priceTotalS / (double)zbdata.countS;//计算该秒、买方向的平均价格 } if ((zbdata.priceB > 0) && (zbdata.priceS > 0)) { zbdata.price = (zbdata.priceB + zbdata.priceS) / 2; } else { zbdata.price = (zbdata.priceB + zbdata.priceS); } zbdata.volume = zbdata.volumeB + zbdata.volumeS; //dataDict[data.Code].totalVolTillNow += zbdata.volume; if ((zbdata.volume == 0) || (zbdata.price == 0)) { continue; //空记录 } dataDict[data.Code].zbDataList.Add(zbdata); dataDict[data.Code].ZBLastIndex = dataDict[data.Code].ZBLastIndex + 1; } } /* * //数据获取部分 * ZBTickData zbdata = new ZBTickData(); * zbdata.timeStamp = Convert.ToInt32((double)data.Time / 1000); //去掉毫秒部分 * * //if (zbdata.timeStamp > 93850) { int i = 0; i++; } * * zbdata.price = (double)data.Price / 10000; * if (data.BSFlag == 66) * zbdata.direction = 1; * else if (data.BSFlag == 83) * zbdata.direction = -1; * else * zbdata.direction = 0; * zbdata.volume = data.Volume; * dataDict[data.Code].totalVolTillNow += zbdata.volume; * * dataDict[data.Code].zbDataList.Add(zbdata); * * if (dataDict[data.Code].zbDataList.Count == 1) //第一次添加 * { * dataDict[data.Code].ZBFirstIndex = 0; * dataDict[data.Code].ZBLastIndex = 0; * } * else * { * dataDict[data.Code].ZBLastIndex = dataDict[data.Code].ZBLastIndex + 1; * } */ } } //极其耗时,轻易不要打开 //RecvDataReport(this, null); } } else if (msg.MsgID == TDFMSGID.MSG_DATA_ORDER) { //逐笔委托 TDFOrder[] orderDataArr = msg.Data as TDFOrder[]; foreach (TDFOrder data in orderDataArr) { return; } } else if (msg.MsgID == TDFMSGID.MSG_DATA_ORDERQUEUE) { //委托队列 TDFOrderQueue[] orderQueueArr = msg.Data as TDFOrderQueue[]; foreach (TDFOrderQueue data in orderQueueArr) { return; } } }
public void ComputeOneTick(string ticker, int firstIndex, int lastIndex) { int test; double pctChgThreshold = 0.003, //涨幅指标 volThreshold = 3, //放量指标 bsThreshold = 0.66, //内外盘指标 priceVolThreshold = 0.01; bool cPriceVol = true, cWithDraw = true, cSingleHugeOrder = true; bool cPriceLevel = false, cVolume = false, cBuySellRatio = false, cPriceTrend = true; bool cNoSuddenUp = true;//暂不加涨速过快指标,先用内外盘指标控制 //CuScore常数 int MALength = 60; //过去一分钟均价 SingleStockData sd = dataDict[ticker]; int midIndex = firstIndex; ////统计预观察期交易量和价格 //double p0 = sd.zbDataList[firstIndex].price, p2 = sd.zbDataList[midIndex].price; //for (int i = firstIndex; i < midIndex; i++) //遍历过去10分钟逐笔数据,计算相应指标 //{ // ZBTickData zbData = sd.zbDataList[i]; // double t1 = Convert.ToDouble(ComputeIntTimeDiff(sd.zbDataList[firstIndex].timeStamp, sd.zbDataList[i].timeStamp)); // double p1 = (p2 - p0) / t0 * t1 + p0; // if (Math.Abs(zbData.price / p1 - 1) > priceVolThreshold) // { // cPriceVol = false; //一旦预观察期价格波动幅度过大,则不符合要求 // return; //直接退出,该段不符合要求 // } // totalPreVolume += zbData.volume; //} if (sd.zbDataList[lastIndex].timeStamp > 94600) { cPriceLevel = false; } double zbMinPrice = sd.zbDataList[midIndex].price; double zbMaxPrice = sd.zbDataList[midIndex].price; int zbMinIndex = midIndex, zbMaxIndex = midIndex; int totalBuyVolume = 0, totalSellVolume = 0, totalBuyCount = 0, totalSellCount = 0; int totalObsVolume = 0; int maxSingleVolume = 0; double timeToLast = 0; double maPriceSum = 0, maCountSum = 0, maPrice = 0; for (int i = lastIndex; i > midIndex; i--) //遍历过去观察期内逐笔数据,计算相应指标 { ZBTickData zbData = sd.zbDataList[i]; if (sd.bComputeCuscore) { maPriceSum = maPriceSum + zbData.price; maCountSum = maCountSum + 1; } if (sd.StatusTrending == StrategyStatus.LongExecuted) { if (zbData.price > sd.MaxPriceAfterBuy) { sd.MaxPriceAfterBuy = zbData.price; } } //if (zbData.direction != 1) continue; //必须是买盘成交 totalObsVolume += zbData.volume; if (zbData.volume > maxSingleVolume) { maxSingleVolume = zbData.volume; } //if (zbData.price < zbMinPrice) //寻找最小值 //{ // zbMinPrice = zbData.price; //寻找2分钟内的最低价格 // zbMinIndex = i; //寻找2分钟内最低价格的索 // if (sd.StatusTrending == StrategyStatus.New) //以免影响卖出逻辑 // { // totalObsVolume = 0; // totalBuyVolume = 0; totalSellVolume = 0; totalBuyCount = 0; totalSellCount = 0; //清零,只计算从最低点开始的成交量 // } //} //if (zbData.price > zbMaxPrice) //寻找最大值 //{ // zbMaxPrice = zbData.price; //寻找2分钟内的最低价格 // zbMaxIndex = i; //寻找2分钟内最低价格的索引 //} //unable to compute huge order for now //if (zbData.price * zbData.volume > 100000) //只统计大单 //{ // if (zbData.direction == 1) // { // totalBuyCount = totalBuyCount + 1; // totalBuyVolume = totalBuyVolume + zbData.volume; // } // else if (zbData.direction == -1) // { // totalSellCount = totalSellCount + 1; // totalSellVolume = totalSellVolume + zbData.volume; // } //} totalBuyCount = totalBuyCount + zbData.countB; totalBuyVolume = totalBuyVolume + zbData.volumeB; totalSellCount = totalSellCount + zbData.countS; totalSellVolume = totalSellVolume + zbData.volumeS; double pctChg = (sd.zbDataList[lastIndex].price - zbData.price) / zbData.price; if (zbData.price > 5) { if (pctChg > pctChgThreshold) { cPriceLevel = true; } } else { if (pctChg > pctChgThreshold * 2) { cPriceLevel = true; } } if (cPriceLevel) //涨幅条件满足,检测其它条件 { double timeToLast1 = 0; zbMinIndex = i; timeToLast1 = Convert.ToDouble(ComputeIntTimeDiff(sd.zbDataList[zbMinIndex].timeStamp, sd.zbDataList[lastIndex].timeStamp)); //时间,以秒计 if (timeToLast1 < 10) { continue; //跳涨,不符合要求,继续往前搜索,看是否上涨趋势 } break; } //if (i > midIndex) //{ // double oneTickPctChg = (zbData.price - sd.zbDataList[i - 1].price) / sd.zbDataList[i - 1].price; // ////条件1: 要求2分钟内没有某一笔拉升很大涨幅,即5块钱以下的不能有一笔的涨幅不超过0.5%,5块钱以上的不能有一笔超过0.25% // if (zbMinPrice > 5) // { // if (oneTickPctChg > pctChgThreshold*0.5) cNoSuddenUp = false; // } // else // { if (oneTickPctChg > 2*pctChgThreshold*0.5) cNoSuddenUp = false; } // //最大回撤不超过涨幅的一半 // double pctWithDraw = (zbData.price - zbMaxPrice) / zbMaxPrice; // if (pctWithDraw < - 0.5 * pctChgThreshold) cWithDraw = false; //} } //观察期遍历结束 //计算CuScore if ((sd.zbDataList[lastIndex].timeStamp > 112955) && (ticker == "601628")) { //if (sd.zbDataList[lastIndex].timeStamp > 112930) test = 0; } if (sd.bComputeCuscore) { if (maCountSum == 0) { throw new Exception("maSum=0"); } double cuT = ComputeIntTimeDiff(sd.BuyTime, sd.zbDataList[lastIndex].timeStamp); double cuScoreNew = 0; maPrice = maPriceSum / maCountSum; if (sd.zbDataList[lastIndex].timeStamp > sd.cuScoreLastTimeStamp) { if ((sd.zbDataList[lastIndex].timeStamp > 93541) && (ticker == "600015")) { test = 0; } if (sd.cuScoreLastIndex == -1) //首次计算 { cuScoreNew = (sd.zbDataList[lastIndex].price - maPrice) * cuT; } else { cuScoreNew = sd.CuScoreList[sd.cuScoreLastIndex] + (sd.zbDataList[lastIndex].price - maPrice) * cuT; } sd.CuScoreList.Add(cuScoreNew); sd.cuScoreLastIndex = sd.cuScoreLastIndex + 1; sd.cuScoreLastTimeStamp = sd.zbDataList[lastIndex].timeStamp; } sd.bCuScoreSell = false; if (sd.cuScoreLastIndex > 60) { double minScore = sd.CuScoreList[sd.cuScoreLastIndex - 1]; for (int iCu = sd.cuScoreLastIndex - 1; iCu > (sd.cuScoreLastIndex - 60); iCu--) { if (sd.CuScoreList[iCu] < minScore) { minScore = sd.CuScoreList[iCu]; } } if (sd.CuScoreList[sd.cuScoreLastIndex] < minScore) { sd.bCuScoreSell = true; //if (ticker == "600015") // sd.bCuScoreSell = true; } } } //检查单笔大单 //if (((double)maxSingleVolume / (double)totalObsVolume) > 0.5) cSingleHugeOrder = false; ; // 一笔大单占交易量一半以上 //检查趋势 //for (int k = zbMinIndex; k < lastIndex - 1; k++) //{ // if ((sd.zbDataList[k + 1].price / sd.zbDataList[k].price - 1) < -0.002) cPriceTrend = false; // if ((!cPriceTrend)&&(sd.zbDataList[lastIndex].timeStamp > 94550)) Thread.Sleep(1); //} //2 - Volume:2分钟成交量均超过过去一周平均水平的3倍。后续再加上成交笔数要求 //if (Convert.ToDouble((lastIndex - zbMinIndex)) / (double)t < 0.3) return; //数据点过少,平均超过2秒才有一次成交 double avgVolume1 = (double)sd.PrevVolume / (4 * 3600); //每秒平均成交量 //double avgVolume1 = sd.avgVolTillNow; //每秒平均成交量 timeToLast = Convert.ToDouble(ComputeIntTimeDiff(sd.zbDataList[firstIndex].timeStamp, sd.zbDataList[lastIndex].timeStamp)); //时间,以秒计 if (totalObsVolume > volThreshold * avgVolume1 * timeToLast) { cVolume = true; } if ((totalBuyCount + totalSellCount) == 0) { return; //盘前数据,无交易量 } //3 - 内外盘:2分钟内内外盘指标,买盘的交易量和交易笔数占比都要超过75% //if ((totalBuyVolume > bsThreshold * (totalBuyVolume + totalSellVolume)) && (totalBuyCount > bsThreshold * (totalBuyCount + totalSellCount))) if (totalBuyVolume > bsThreshold * (totalBuyVolume + totalSellVolume)) { cBuySellRatio = true; } ////条件3为要求前10分钟振幅不能太高,不超过2.5% //double range=(priceArray.Max() - priceArray.Min())/priceArray.Min(); //if (range<0.025) c3=true; ////条件5要求当时涨幅不能超过0.05,且必须是上涨的 //此处为固定区间涨幅,并非区间振幅 //double pctChgFromStart = (dd.tickData[obsEndIndex].LastPrice - startingPrice) / startingPrice; //if ((pctChgFromStart > 0) && (pctChgFromStart < 0.05)) c5 = true; if ((sd.zbDataList[lastIndex].timeStamp > 93739) && (ticker == "600015")) { test = 0; } //if (sd.zbDataList[lastIndex].direction != 1) return; //必须是买盘成交 /*涨停撤单逻辑,暂停使用 * if (sd.zbDataList[lastIndex].price > sd.PrevClose*1.08) * { * FIXApi.OrderBookEntry entry = new OrderBookEntry(); * entry.strategies = TradingStrategies.StockTrending; * entry.action = OrderAction.CancelLock; * entry.ticker = ticker; * entry.quantityListed = 0;//没有必要输入Quantity * entry.priceListed = 0; * entry.orderTime = sd.BuyTime; * entry.orderDate = sd.DateStamp; * * sd.StatusTrending = StrategyStatus.Pending; //获得成交回报后再改变状态,避免重复执行 * Thread orderThread = new Thread(new ParameterizedThreadStart(tc.OrderSender_StockTrending)); * orderThread.IsBackground = true; * orderThread.Start(entry); * } */ if (sd.StatusTrending == StrategyStatus.New) //尚未下过单 { //判断是否需要下买单 if ((cPriceLevel && cVolume && cBuySellRatio && cNoSuddenUp && cWithDraw && cPriceVol && cPriceTrend && cSingleHugeOrder) || bTestEngine) { //到达此处即条件符合,下买单 sd.BuyTime = sd.zbDataList[lastIndex].timeStamp; //用逐笔时间,此处修改Dictionary,如发生线程冲突可能出现问题,后续把所有涉及修改zbDataList的逻辑全部去掉,engine中只读 sd.bComputeCuscore = true; //开始计算CuScore; sd.CuScoreList = new List <double>(); sd.cuScoreLastIndex = -1; sd.cuScoreLastTimeStamp = sd.BuyTime; if ((tc.mode == TradeMode.Backtest) || (tc.mode == TradeMode.Debug)) { sd.StatusTrending = StrategyStatus.LongExecuted; if (sd.BuyTime > 144500) { return; //14:45分后不再下单 } FIXApi.OrderBookEntry entry = new OrderBookEntry(); entry.strategies = TradingStrategies.StockTrending; entry.action = OrderAction.Buy; entry.type = FIXApi.OrderType.CashBuy; entry.ticker = ticker; entry.quantityListed = sd.Quantity; entry.priceListed = sd.zbDataList[lastIndex].price; entry.lockPrice = Math.Round(sd.PrevClose * 1.09, 2); entry.orderTime = sd.BuyTime; entry.orderDate = sd.DateStamp; tc.OrderSender_StockTrending(entry); } else if (tc.mode == TradeMode.Production) { if (sd.BuyTime > 144500) { return; //14:45分后不再下单 } FIXApi.OrderBookEntry entry = new OrderBookEntry(); entry.strategies = TradingStrategies.StockTrending; entry.action = OrderAction.Buy; //entry.type = FIXApi.OrderType.CreditMarginBuy; //融资买入 entry.type = FIXApi.OrderType.CashBuy; //信用账户现金买入 entry.ticker = ticker; //double maxAmount = 20000; //int quantityListed = 100; //if (sd.PrevClose > 0) //{ // quantityListed = Math.Min(sd.MaxQuantity, Convert.ToInt32(maxAmount / sd.PrevClose / 100) * 100); //} //entry.quantityListed = quantityListed; entry.quantityListed = sd.Quantity; //DEBUG if (bTestEngine) { entry.priceListed = sd.AskPrices[4];//测试用,挂买五 DEBUG } else { entry.priceListed = sd.AskPrices[4];//直接按卖五下限价买单,以保证成交 } entry.lockPrice = Math.Round(sd.PrevClose * 1.098, 2); entry.orderTime = sd.BuyTime; entry.orderDate = sd.DateStamp; sd.StatusTrending = StrategyStatus.Pending; //获得成交回报后再改变状态,避免重复执行 OrderRouter(entry); } } } else if (sd.StatusTrending == StrategyStatus.LongExecuted) //买单已下,下卖单 { //判断是否需要下卖单 int s = ComputeIntTimeDiff(sd.BuyTime, sd.zbDataList[lastIndex].timeStamp); int sellTime = 120;//最多5分钟后卖出 if (s < sellTime) { return; //5分钟内无论如何不卖 } if (!sd.bCuScoreSell) { return; } //if (bTestEngine) sellTime = 10; //测试下单用,10秒后即卖出 DEBUG //if ((s < sellTime) && (!sd.bCuScoreSell)) //{ // //double bsSellThreshold = 0.5; // //根据内外盘指标决定卖出时间, // //if ((totalBuyVolume > bsSellThreshold * (totalBuyVolume + totalSellVolume)) && (totalBuyCount > bsSellThreshold * (totalBuyCount + totalSellCount))) //只要买盘足够大就继续持有 // //if (totalBuyVolume > bsSellThreshold * (totalBuyVolume + totalSellVolume)) // return; //} //条件通过,下卖单 if ((tc.mode == TradeMode.Backtest) || (tc.mode == TradeMode.Debug)) { FIXApi.OrderBookEntry entry = new OrderBookEntry(); entry.strategies = TradingStrategies.StockTrending; entry.action = OrderAction.Sell; entry.type = FIXApi.OrderType.CashSell; entry.ticker = ticker; entry.quantityListed = sd.Quantity; entry.priceListed = sd.zbDataList[lastIndex].price; entry.orderTime = sd.zbDataList[lastIndex].timeStamp; entry.orderDate = sd.DateStamp; sd.StatusTrending = StrategyStatus.None; //不重复执行 //sd.StatusTrending = StrategyStatus.New; //重复执行 tc.OrderSender_StockTrending(entry); tc.CalcPnL(); } else if (tc.mode == TradeMode.Production) { FIXApi.OrderBookEntry entry = new OrderBookEntry(); entry.strategies = TradingStrategies.StockTrending; //entry.action = OrderAction.ShortSell; //entry.type = FIXApi.OrderType.CreditMarginSell; entry.action = OrderAction.Sell; entry.type = FIXApi.OrderType.CashSell; entry.ticker = ticker; entry.quantityListed = sd.Quantity; //entry.quantityListed = 0;//没有必要输入Quantity, 完全依赖锁券和预先锁券 //if (bTestEngine) // entry.priceListed = sd.AskPrices[5];//测试,按卖五挂单 //else // entry.priceListed = sd.AskPrices[0];//按卖一挂单 entry.priceListed = sd.BidPrices[4]; //按卖五挂单,等同市价 entry.orderTime = sd.zbDataList[lastIndex].timeStamp; //SellTime entry.orderDate = sd.DateStamp; sd.StatusTrending = StrategyStatus.Pending; //获得成交回报后再改变状态,避免重复执行 OrderRouter(entry); } } }