public void ShortSellTest() { //OrderList = new Dictionary<string, int>(); //OrderList.Add("000768", 1000); //OrderList.Add("600893", 600); //OrderList.Add("300070", 1200); //OrderList.Add("300024", 1000); //OrderList.Add("300124", 700); //OrderList.Add("300058", 800); //OrderList.Add("300002", 1000); //OrderList.Add("300003", 800); if (OrderList == null) { return; } foreach (KeyValuePair <string, int> kvp in OrderList) { try { SingleStockData sd = dataDict[kvp.Key]; FIXApi.OrderBookEntry entry = new OrderBookEntry(); entry.strategies = TradingStrategies.StockTrending; entry.action = OrderAction.ShortSell; entry.type = FIXApi.OrderType.CreditMarginSell; entry.ticker = kvp.Key; entry.quantityListed = kvp.Value; int tCount = 0; while (sd.AskPrices[0] == 0) { tCount++; Thread.Sleep(100); if (tCount > 100) { break; } } if (sd.AskPrices[0] == 0) { continue; } entry.priceListed = sd.AskPrices[0]; Thread orderThread = new Thread(new ParameterizedThreadStart(tc.OrderSender_StockTrending)); orderThread.IsBackground = true; orderThread.Start(entry); } catch (Exception ex) { strListLog.Add(ex.Message); } } }
public void PrevLockAll() { foreach (string ticker in dc.TickerList) { SingleStockData sd = dataDict[ticker]; FIXApi.OrderBookEntry entry = new OrderBookEntry(); entry.strategies = TradingStrategies.StockTrending; entry.action = OrderAction.PrevLock; entry.type = FIXApi.OrderType.CreditMarginSell; entry.ticker = ticker; entry.quantityListed = sd.Quantity; entry.priceListed = Math.Round(sd.PrevClose * 1.098, 2); //entry.orderTime = sd.BuyTime; //entry.orderDate = sd.DateStamp; Thread orderThread = new Thread(new ParameterizedThreadStart(tc.OrderSender_StockTrending)); orderThread.IsBackground = true; orderThread.Start(entry); Thread.Sleep(1000); //避免堵塞 } }
//重载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 string LoadDataDict() * { * string ticker = "", tickerWithMarket = "", tickerListStr = ""; * * SqlConnection conn = new SqlConnection(connStr); * * //string sql = "select Ticker, ShortQuantity, prevClose, Volume from v_Ticker_Trending where prevClose>0 and volume>0 and shortquantity*prevClose>20000 Order by ticker"; * //string sql = "select Ticker, ShortQuantity, prevClose, Volume from v_Ticker_Trending where prevClose>0 and volume>0 and shortquantity*prevClose>2000 Order by ticker";//DEBUG * //string sql = "select Ticker, QuantityHolding, prevClose, PrevVolume from v_Ticker_Trending where ticker='600316' Order by ticker"; //测试用 * string sql = "select Ticker, Quantity, prevClose, PrevVolume from TickerList_HighFreq Order by ticker"; * * conn.Open(); * SqlCommand cmd = new SqlCommand(sql, conn); * SqlDataReader sqldr = cmd.ExecuteReader(); * * int count = 0; * while (sqldr.Read()) * { * ticker = sqldr.GetString(0); * ticker = ticker.Trim(); * * if (ticker.StartsWith("60") || ticker.StartsWith("51")) * { * tickerWithMarket = ticker + ".sh"; // 上海 * } * else if (ticker.StartsWith("00") || ticker.StartsWith("30") || ticker.StartsWith("15")) * { * tickerWithMarket = ticker + ".sz"; // 深圳 * } * * * TickerList.Add(ticker); * tickerListStr = tickerListStr + ";" + tickerWithMarket; * * SingleStockData sd = new SingleStockData(ticker); * * sd.MaxQuantity = Convert.ToInt32(sqldr.GetInt32(1)); * * sd.PrevClose = Convert.ToDouble(sqldr.GetDouble(2)); * sd.PrevVolume = Convert.ToInt64(sqldr.GetInt64(3)); * * sd.Quantity = 100; //DEBUG * * sd.StatusTrending = StrategyStatus.New; * * dataDict.Add(ticker, sd); * } * * return tickerListStr; * } */ //此版本为分级基金套利使用 public string LoadDataDict() { string ticker = "", tickerWithMarket = "", tickerListStr = ""; connStr = "server=192.168.0.169,1433;database=HedgeHogDB;User ID=wg;Password=Pass@word;Connection Timeout=30"; SqlConnection conn = new SqlConnection(connStr); if (intDate == 0) { intDate = Convert.ToInt32(DateTime.Today.ToString("yyyyMMdd")); } string sql = "select Ticker, Quantity, prevClose, PrevVolume from v_HFT_PrevCloseData where NowDate =" + intDate.ToString() + " and prevvolume>0 Order by ticker";//融券卖空用 // string sql = "select top 100 Ticker, Quantity, prevClose, PrevVolume from v_HFT_PrevCloseData where NowDate =" + intDate.ToString() + " and ticker='000933' and prevvolume>0 Order by ticker";//融券卖空用 conn.Open(); SqlCommand cmd = new SqlCommand(sql, conn); SqlDataReader sqldr = cmd.ExecuteReader(); while (sqldr.Read()) { ticker = sqldr.GetString(0); ticker = ticker.Trim(); if (ticker.StartsWith("60") || ticker.StartsWith("51")) { tickerWithMarket = ticker + ".sh"; // 上海 } else if (ticker.StartsWith("00") || ticker.StartsWith("30") || ticker.StartsWith("15")) { tickerWithMarket = ticker + ".sz"; // 深圳 } if (!TickerList.Contains(ticker)) { TickerList.Add(ticker); tickerListStr = tickerListStr + ";" + tickerWithMarket; } SingleStockData sd = new SingleStockData(ticker); sd.MaxQuantity = Convert.ToInt32(sqldr.GetInt32(1)); sd.PrevClose = Convert.ToDouble(sqldr.GetDouble(2)); sd.PrevVolume = Convert.ToInt64(sqldr.GetInt64(3)); sd.Quantity = sd.MaxQuantity; //sd.Quantity = 100; sd.StatusTrending = StrategyStatus.New; sd.StatusReverse = StrategyStatus.New; sd.DateStamp = intDate; if (!dataDict.ContainsKey(ticker)) { dataDict.Add(ticker, sd); } } return(tickerListStr); }
private void comboBoxIfArb_SelectedIndexChanged(object sender, EventArgs e) { string account = ""; //单一账户对应的position,也可以写成将多个账户汇总 if (checkBoxGuosenHedge1.Checked) { account = "dj1"; } else if (checkBoxCiccSeed1.Checked) { account = "zj1"; } else if (checkBoxCiccSeed2.Checked) { account = "zj2"; } else if (checkBoxHY.Checked) { account = "hy1"; } else { //MessageBox.Show("请选择账户!"); return; } dtPosition = new DataTable(); if ((!radioButtonSell.Checked) && (!radioButtonBuy.Checked)) { //MessageBox.Show("请选择买或者卖"); return; } string Strategy = Convert.ToString(comboBoxIfArb.Text); if (string.IsNullOrEmpty(Strategy)) { //MessageBox.Show("Please Select Index!"); return; } //买时从basketlist读取 if (radioButtonBuy.Checked) { string sql = "select * from v_arbitrage where Strategy='" + Strategy + "'"; SqlDataAdapter SDA = new SqlDataAdapter("select * from v_arbitrage where Strategy='" + Strategy + "'", MF.conn); SDA.Fill(dtPosition); //dtPosition中会包含数量为0的股票,下单注意剔除 //第一列为Strategy,第二列为Ticker,第三列为Position, dtPosition.Columns.Add("Account"); for (int i = 0; i < dtPosition.Rows.Count; i++) { dtPosition.Rows[i]["Account"] = account; } double capital = 0; string[] strvalue = Strategy.Split('_'); string sql1 = "select SUM(Position*Price_Close) from (select A.Ticker,Position,TotalAHist.Price_Close from (select * from BasketList where SubStrategy1='" + strvalue[1] + "' and SubStrategy2='" + strvalue[2] + "') A " + "left join TotalAHist on A.Ticker=TotalAHist.Ticker and A.HistDate=TotalAHist.HistDate) C"; SqlCommand cmd = new SqlCommand(sql1, MF.conn); SqlDataReader sdr = cmd.ExecuteReader(); while (sdr.Read()) { if (sdr.IsDBNull(0)) { capital = 0; } else { capital = sdr.GetDouble(0); } } sdr.Close(); textBoxCiccLog2.Text = "篮子总市值为:" + capital; } //卖时从Inventory读取 else { //每次卖时需要根据当日成交回报更新Inventory, //tc.OrderBookUpdate(conn); //PositionUpdate(); int weight = GetWeight(MF.conn, account, Strategy); //每篮子对应个股持仓数 string sql = "select Strategy + '_' + SubStrategy1 + '_' + SubStrategy2 as Strategy,Ticker,(PrePosition+TodayBuy-TodaySell) as Position,Account from Inventory where Strategy + '_' + SubStrategy1 + '_' + SubStrategy2='" + Strategy + "' and account='" + account + "'"; SqlDataAdapter SDA = new SqlDataAdapter(sql, MF.conn); SDA.Fill(dtPosition); for (int i = 0; i < dtPosition.Rows.Count; i++) { DataRow dr = dtPosition.Rows[i]; if (weight > 0) { dr["Position"] = Math.Round(Convert.ToDouble(dr["Position"]) / weight / 100) * 100; } } //计算篮子市值 double capital = 0; string[] strvalue = Strategy.Split('_'); string subsql = ""; if (weight == 0) { subsql = "select SUM(Position*Price_Close)"; } else { subsql = "select SUM(floor(Position/(" + weight + "*100))*100*Price_Close)"; } string sql1 = subsql + " from (select A.Position,B.Price_Close from (select Ticker,PrePosition as Position,Account from Inventory where Strategy + '_' + SubStrategy1 + '_' + SubStrategy2='" + Strategy + "' and account='" + account + "') A " + " left join" + "(select * from TotalAHist where HistDate= (select MAX(HistDate) from TotalAHist)) B on A.Ticker=B.Ticker) C"; SqlCommand cmd = new SqlCommand(sql1, MF.conn); SqlDataReader sdr = cmd.ExecuteReader(); while (sdr.Read()) { if (sdr.IsDBNull(0)) { capital = 0; } else { capital = sdr.GetDouble(0); } } sdr.Close(); textBoxCiccLog2.Text = "篮子总市值为:" + capital; } //订阅行情 string TickerList = ""; string ticker = "", tickerWithMarket = "", tickerListStr = ""; for (int i = 0; i < dtPosition.Rows.Count; i++) { DataRow dr = dtPosition.Rows[i]; ticker = Convert.ToString(dr["Ticker"]); ticker = ticker.Trim(); if (ticker.StartsWith("60") || ticker.StartsWith("51")) { tickerWithMarket = ticker + ".sh"; // 上海 } else if (ticker.StartsWith("00") || ticker.StartsWith("30") || ticker.StartsWith("15")) { tickerWithMarket = ticker + ".sz"; // 深圳 } if (!TickerList.Contains(ticker)) { tickerListStr = tickerListStr + ";" + tickerWithMarket; } SingleStockData sd = new SingleStockData(ticker); sd.StatusTrending = StrategyStatus.New; sd.StatusReverse = StrategyStatus.New; if (!dataDict.ContainsKey(ticker)) { dataDict.Add(ticker, sd); } } dc.SetSubscription(tickerListStr, SubscriptionType.SUBSCRIPTION_ADD); //将行情输入dtPosition dtPosition.Columns.Add("OrderPrice"); //刷新datagridview System.Timers.Timer t = new System.Timers.Timer(5000); //实例化Timer类,设置间隔时间为5000毫秒; t.Elapsed += new System.Timers.ElapsedEventHandler(theout); //到达时间的时候执行事件; t.AutoReset = true; //设置是执行一次(false)还是一直执行(true); t.Enabled = true; G_position.DataSource = dtPosition; }
public void RunReverseStrategy() { //实时是第一层每秒重新计算一次,第二层对每只股票代码循环,每只股票此时只需计算一次 //PrevLockAll(); bRunning = true; while (bRunning) { foreach (string ticker in dc.TickerList) //注意不能直接对dict用foreach,否则任何修改都会抛出异常 { lock (this.dataDict) { if (!dataDict.Keys.Contains(ticker)) { continue; } SingleStockData sd = dataDict[ticker]; if (sd.StatusReverse == StrategyStatus.None) { continue; //该股票已交易过,当日只交易一次 } if (((sd.ZBFirstIndex) < 0) || ((sd.ZBLastIndex) < 0)) { continue; } if (sd.zbDataList[sd.ZBLastIndex].timeStamp < 93000) { continue; } if (sd.zbDataList[sd.ZBLastIndex].timeStamp > 145900) { bRunning = false; break; } int tDiff = ComputeIntTimeDiff(sd.zbDataList[sd.ZBFirstIndex].timeStamp, sd.zbDataList[sd.ZBLastIndex].timeStamp); int obsTime = bTestEngine?2:600; if ((sd.ZBFirstIndex == 0) && tDiff < obsTime) { continue; //已读取数据长度不满2分钟 DEBUG } while (ComputeIntTimeDiff(sd.zbDataList[sd.ZBFirstIndex].timeStamp, sd.zbDataList[sd.ZBLastIndex].timeStamp) > 120) //保持内存中时间序列长度在2分钟左右 { sd.zbDataList.RemoveAt(sd.ZBFirstIndex); sd.ZBLastIndex = sd.ZBLastIndex - 1; //sd.ZBFirstIndex++; } ComputeOneTick(ticker, sd.ZBFirstIndex, sd.ZBLastIndex); } } if (tc.mode == TradeMode.Debug) { Thread.Sleep(10); //每秒计算一次 } else if (tc.mode == TradeMode.Production) { Thread.Sleep(1000); //每秒计算一次 } } }
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); } } }
public void Run() { bTestEngine = false; int tLength = 60; //只使用过去一分钟数据 if (tc.mode == TradeMode.Backtest) //回测模式包括TDF和数据库两种回测 { //回测时是第一层对每只股票代码循环,第二层对每只股票的日期做循环,第三层对每只股票的时间序列循环 foreach (string ticker in dc.TickerList) { if (!dataDict.Keys.Contains(ticker)) { continue; } SingleStockData sd = dataDict[ticker]; //if (sd.zbDataList.Count < 2000) continue; int iStart = 0, iEnd; for (iEnd = 1; iEnd < sd.zbDataList.Count; iEnd++) { sd.totalVolTillNow += sd.zbDataList[iEnd].volume; int timeTillNow = ComputeIntTimeDiff(sd.zbDataList[0].timeStamp, sd.zbDataList[iEnd].timeStamp); sd.avgVolTillNow = (double)sd.totalVolTillNow / (double)timeTillNow; if (sd.zbDataList[iEnd].timeStamp < 94500) { continue; } if (timeTillNow < tLength) { continue; } while (ComputeIntTimeDiff(sd.zbDataList[iStart].timeStamp, sd.zbDataList[iEnd].timeStamp) > tLength) //保持内存中时间序列长度固定 { iStart++; } if (sd.StatusTrending == StrategyStatus.None) { continue; //该股票已交易过,当日只交易一次 } ComputeOneTick(ticker, iStart, iEnd); } } } else { //实时时是第一层每秒重新计算一次,第二层对每只股票代码循环,每只股票此时只需计算一次 //PrevLockAll(); bRunning = true; while (bRunning) { int timeStamp = 0; foreach (string ticker in dc.TickerList) //注意不能直接对dict用foreach,否则任何修改都会抛出异常 { lock (this.dataDict) { if (!dataDict.Keys.Contains(ticker)) { continue; } SingleStockData sd = dataDict[ticker]; if (sd.StatusTrending == StrategyStatus.None) { continue; //该股票已交易过,当日只交易一次 } if (((sd.ZBFirstIndex) < 0) || ((sd.ZBLastIndex) < 0)) { continue; } timeStamp = sd.zbDataList[sd.ZBLastIndex].timeStamp; if (timeStamp > sd.prevTimeStamp) { sd.prevTimeStamp = timeStamp; } else { continue; //时间尚未更新,无需后续计算 } if (timeStamp < 93130) { continue; //盘前30秒的数据暂不使用 } int tDiff = ComputeIntTimeDiff(sd.zbDataList[sd.ZBFirstIndex].timeStamp, sd.zbDataList[sd.ZBLastIndex].timeStamp); int timeTillNow = ComputeIntTimeDiff(93000, sd.zbDataList[sd.ZBLastIndex].timeStamp); sd.avgVolTillNow = (double)sd.totalVolTillNow / (double)timeTillNow; if (bTestEngine) { if ((sd.ZBFirstIndex == 0) && tDiff < 2) { continue; } } //已读取数据长度不满2分钟 else { if ((sd.ZBFirstIndex == 0) && tDiff < tLength) { continue; } } //已读取数据长度不满2分钟 DEBUG if (sd.zbDataList[sd.ZBLastIndex].timeStamp < 93500) { continue; } while (ComputeIntTimeDiff(sd.zbDataList[sd.ZBFirstIndex].timeStamp, sd.zbDataList[sd.ZBLastIndex].timeStamp) > tLength) //保持内存中时间序列长度固定 { if (sd.zbDataList.Count < 30) { break; //交易不活跃,距离太短,保留至少30个tick } if ((sd.zbDataList[sd.ZBFirstIndex].timeStamp > 93500) && ((sd.ZBLastIndex - sd.ZBFirstIndex) > tLength)) { ComputeOneTick(ticker, sd.ZBFirstIndex, sd.ZBFirstIndex + tLength - 1); //以秒为tick单位,以后需修改 } sd.zbDataList.RemoveAt(sd.ZBFirstIndex); sd.ZBLastIndex = sd.ZBLastIndex - 1; //sd.ZBFirstIndex++; } ComputeOneTick(ticker, sd.ZBFirstIndex, sd.ZBLastIndex); } } if (tc.mode == TradeMode.Debug) { Thread.Sleep(10); //每秒计算一次 } else if (tc.mode == TradeMode.Production) { Thread.Sleep(500); //每秒计算一次 } if (timeStamp > 145900) { break; } } } dc.WriteToDatabase(tc.dt_PnL); WriteLog(this, null); }