private void Send(NewOrderSingle order) { if (!_bTdConnected) { EmitError(-1, -1, "交易服务器没有连接,无法报单"); tdlog.Error("交易服务器没有连接,无法报单"); return; } Instrument inst = InstrumentManager.Instruments[order.Symbol]; string altSymbol = inst.GetSymbol(Name); string altExchange = inst.GetSecurityExchange(Name); double tickSize = inst.TickSize; CThostFtdcInstrumentField _Instrument; if (_dictInstruments.TryGetValue(altSymbol, out _Instrument)) { //从合约列表中取交易所名与tickSize,不再依赖用户手工设置的参数了 tickSize = _Instrument.PriceTick; altExchange = _Instrument.ExchangeID; } //最小变动价格修正 double price = order.Price; //市价修正,如果不连接行情,此修正不执行,得策略层处理 CThostFtdcDepthMarketDataField DepthMarket; //如果取出来了,并且为有效的,涨跌停价将不为0 _dictDepthMarketData.TryGetValue(altSymbol, out DepthMarket); //市价单模拟 if (OrdType.Market == order.OrdType) { //按买卖调整价格 if (order.Side == Side.Buy) { price = DepthMarket.LastPrice + LastPricePlusNTicks * tickSize; } else { price = DepthMarket.LastPrice - LastPricePlusNTicks * tickSize; } } //没有设置就直接用 if (tickSize > 0) { decimal remainder = ((decimal)price % (decimal)tickSize); if (remainder != 0) { if (order.Side == Side.Buy) { price = Math.Ceiling(price / tickSize) * tickSize; } else { price = Math.Floor(price / tickSize) * tickSize; } } else { //正好能整除,不操作 } } if (0 == DepthMarket.UpperLimitPrice && 0 == DepthMarket.LowerLimitPrice) { //涨跌停无效 } else { //防止价格超过涨跌停 if (price >= DepthMarket.UpperLimitPrice) { price = DepthMarket.UpperLimitPrice; } else if (price <= DepthMarket.LowerLimitPrice) { price = DepthMarket.LowerLimitPrice; } } int YdPosition = 0; int TodayPosition = 0; string szCombOffsetFlag; if (order.Side == Side.Buy) { //买,先看有没有空单,有就平空单,没有空单,直接买开多单 _dbInMemInvestorPosition.GetPositions(altSymbol, TThostFtdcPosiDirectionType.Short, HedgeFlagType, out YdPosition, out TodayPosition);//TThostFtdcHedgeFlagType.Speculation } else//是否要区分Side.Sell与Side.SellShort呢? { //卖,先看有没有多单,有就平多单,没有多单,直接买开空单 _dbInMemInvestorPosition.GetPositions(altSymbol, TThostFtdcPosiDirectionType.Long, HedgeFlagType, out YdPosition, out TodayPosition); } List <SOrderSplitItem> OrderSplitList = new List <SOrderSplitItem>(); SOrderSplitItem orderSplitItem; //根据 梦翔 与 马不停蹄 的提示,新加在Text域中指定开平标志的功能 int nOpenCloseFlag = 0; if (order.Text.StartsWith(OpenPrefix)) { nOpenCloseFlag = 1; } else if (order.Text.StartsWith(ClosePrefix)) { nOpenCloseFlag = -1; } else if (order.Text.StartsWith(CloseTodayPrefix)) { nOpenCloseFlag = -2; } else if (order.Text.StartsWith(CloseYesterdayPrefix)) { nOpenCloseFlag = -3; } int leave = (int)order.OrderQty; //是否上海?上海先平今,然后平昨,最后开仓 //使用do主要是想利用break功能 //平仓部分 do { //指定开仓,直接跳过 if (nOpenCloseFlag > 0) { break; } //表示指定平今与平昨 if (nOpenCloseFlag < -1) { if (-2 == nOpenCloseFlag) { byte[] bytes = { (byte)TThostFtdcOffsetFlagType.CloseToday, (byte)TThostFtdcOffsetFlagType.CloseToday }; szCombOffsetFlag = System.Text.Encoding.Default.GetString(bytes, 0, bytes.Length); } else { //肯定是-3了 byte[] bytes = { (byte)TThostFtdcOffsetFlagType.CloseYesterday, (byte)TThostFtdcOffsetFlagType.CloseYesterday }; szCombOffsetFlag = System.Text.Encoding.Default.GetString(bytes, 0, bytes.Length); } orderSplitItem.qty = leave; orderSplitItem.szCombOffsetFlag = szCombOffsetFlag; OrderSplitList.Add(orderSplitItem); leave = 0; break; } if (SupportCloseToday.Contains(altExchange)) { //先看平今 if (leave > 0 && TodayPosition > 0) { int min = Math.Min(TodayPosition, leave); leave -= min; byte[] bytes = { (byte)TThostFtdcOffsetFlagType.CloseToday, (byte)TThostFtdcOffsetFlagType.CloseToday }; szCombOffsetFlag = System.Text.Encoding.Default.GetString(bytes, 0, bytes.Length); orderSplitItem.qty = min; orderSplitItem.szCombOffsetFlag = szCombOffsetFlag; OrderSplitList.Add(orderSplitItem); } if (leave > 0 && YdPosition > 0) { int min = Math.Min(YdPosition, leave); leave -= min; byte[] bytes = { (byte)TThostFtdcOffsetFlagType.CloseYesterday, (byte)TThostFtdcOffsetFlagType.CloseYesterday }; szCombOffsetFlag = System.Text.Encoding.Default.GetString(bytes, 0, bytes.Length); orderSplitItem.qty = min; orderSplitItem.szCombOffsetFlag = szCombOffsetFlag; OrderSplitList.Add(orderSplitItem); } } else { //平仓 int position = TodayPosition + YdPosition; if (leave > 0 && position > 0) { int min = Math.Min(position, leave); leave -= min; byte[] bytes = { (byte)TThostFtdcOffsetFlagType.Close, (byte)TThostFtdcOffsetFlagType.Close }; szCombOffsetFlag = System.Text.Encoding.Default.GetString(bytes, 0, bytes.Length); orderSplitItem.qty = min; orderSplitItem.szCombOffsetFlag = szCombOffsetFlag; OrderSplitList.Add(orderSplitItem); } } } while (false); do { //指定平仓,直接跳过 if (nOpenCloseFlag < 0) { break; } if (leave > 0) { byte[] bytes = { (byte)TThostFtdcOffsetFlagType.Open, (byte)TThostFtdcOffsetFlagType.Open }; szCombOffsetFlag = System.Text.Encoding.Default.GetString(bytes, 0, bytes.Length); orderSplitItem.qty = leave; orderSplitItem.szCombOffsetFlag = szCombOffsetFlag; OrderSplitList.Add(orderSplitItem); leave = 0; } } while (false); if (leave > 0) { tdlog.Info("CTP:还剩余{0}手,你应当是强制指定平仓了,但持仓数小于要平手数", leave); } //将第二腿也设置成一样,这样在使用组合时这地方不用再调整 byte[] bytes2 = { (byte)HedgeFlagType, (byte)HedgeFlagType }; string szCombHedgeFlag = System.Text.Encoding.Default.GetString(bytes2, 0, bytes2.Length); bool bSupportMarketOrder = SupportMarketOrder.Contains(altExchange); tdlog.Info("Side:{0},Price:{1},LastPrice:{2},Qty:{3},Text:{4},YdPosition:{5},TodayPosition:{6}", order.Side, order.Price, DepthMarket.LastPrice, order.OrderQty, order.Text, YdPosition, TodayPosition); TThostFtdcDirectionType Direction = order.Side == Side.Buy ? TThostFtdcDirectionType.Buy : TThostFtdcDirectionType.Sell; TThostFtdcOrderPriceTypeType OrderPriceType = TThostFtdcOrderPriceTypeType.LimitPrice; TThostFtdcTimeConditionType TimeCondition = TThostFtdcTimeConditionType.GFD; TThostFtdcContingentConditionType ContingentCondition = TThostFtdcContingentConditionType.Immediately; TThostFtdcVolumeConditionType VolumeCondition = TThostFtdcVolumeConditionType.AV; switch (order.TimeInForce) { case TimeInForce.IOC: TimeCondition = TThostFtdcTimeConditionType.IOC; VolumeCondition = TThostFtdcVolumeConditionType.AV; break; case TimeInForce.FOK: TimeCondition = TThostFtdcTimeConditionType.IOC; VolumeCondition = TThostFtdcVolumeConditionType.CV; break; default: break; } foreach (SOrderSplitItem it in OrderSplitList) { int nRet = 0; switch (order.OrdType) { case OrdType.Limit: break; case OrdType.Market: if (SwitchMakertOrderToLimitOrder || !bSupportMarketOrder) { } else { price = 0; OrderPriceType = TThostFtdcOrderPriceTypeType.AnyPrice; //TimeCondition = TThostFtdcTimeConditionType.IOC; } break; default: tdlog.Warn("没有实现{0}", order.OrdType); return; } nRet = TraderApi.TD_SendOrder(m_pTdApi, altSymbol, Direction, it.szCombOffsetFlag, szCombHedgeFlag, it.qty, price, OrderPriceType, TimeCondition, ContingentCondition, order.StopPx, VolumeCondition); if (nRet > 0) { _OrderRef2Order.Add(string.Format("{0}:{1}:{2}", _RspUserLogin.FrontID, _RspUserLogin.SessionID, nRet), order as SingleOrder); } } }
private void Send(NewOrderSingle order) { if (!_bTdConnected) { EmitError(-1, -1, "交易服务器没有连接,无法报单"); return; } Instrument inst = InstrumentManager.Instruments[order.Symbol]; string altSymbol = inst.GetSymbol(this.Name); string altExchange = inst.GetSecurityExchange(this.Name); double price; CThostFtdcDepthMarketDataField DepthMarket; if (_dictDepthMarketData.TryGetValue(altSymbol, out DepthMarket)) { //没有设置就直接用 if (inst.TickSize > 0) { //将价格调整为最小价格的整数倍,此处是否有问题?到底应当是向上调还是向下调呢?此处先这样 double num = 0; if (order.Side == Side.Buy) { num = Math.Round(order.Price / inst.TickSize, 0, MidpointRounding.AwayFromZero); } else { num = Math.Round(order.Price / inst.TickSize, 0, MidpointRounding.AwayFromZero); } price = inst.TickSize * num; string PF = string.Format("{{0:{0}}}", inst.PriceDisplay); price = Convert.ToDouble(string.Format(PF, price)); } else { price = order.Price; } //市价修正 if (price >= DepthMarket.UpperLimitPrice) { price = DepthMarket.UpperLimitPrice; } else if (price <= DepthMarket.LowerLimitPrice) { price = DepthMarket.LowerLimitPrice; } int YdPosition = 0; int TodayPosition = 0; string szCombOffsetFlag; if (order.Side == Side.Buy) { //买,先看有没有空单,有就平空单,没有空单,直接买开多单 _dbInMemInvestorPosition.GetPositions(altSymbol, TThostFtdcPosiDirectionType.Short, TThostFtdcHedgeFlagType.Speculation, out YdPosition, out TodayPosition); } else//是否要区分Side.Sell与Side.SellShort呢? { //卖,先看有没有多单,有就平多单,没有多单,直接买开空单 _dbInMemInvestorPosition.GetPositions(altSymbol, TThostFtdcPosiDirectionType.Long, TThostFtdcHedgeFlagType.Speculation, out YdPosition, out TodayPosition); } List <SOrderSplitItem> OrderSplitList = new List <SOrderSplitItem>(); SOrderSplitItem orderSplitItem; //根据 梦翔 与 马不停蹄 的提示,新加在Text域中指定开平标志的功能 int nOpenCloseFlag = 0; if (order.Text.StartsWith(OpenPrefix)) { nOpenCloseFlag = 1; } else if (order.Text.StartsWith(ClosePrefix)) { nOpenCloseFlag = -1; } int leave = (int)order.OrderQty; //是否上海?上海先平今,然后平昨,最后开仓 //使用do主要是想利用break功能 //平仓部分 do { //指定开仓,直接跳过 if (1 == nOpenCloseFlag) { break; } if (SupportCloseToday.Contains(altExchange)) { //先看平今 if (leave > 0 && TodayPosition > 0) { int min = Math.Min(TodayPosition, leave); leave -= min; byte[] bytes = { (byte)TThostFtdcOffsetFlagType.CloseToday, (byte)TThostFtdcOffsetFlagType.CloseToday }; szCombOffsetFlag = System.Text.Encoding.Default.GetString(bytes, 0, bytes.Length); orderSplitItem.qty = min; orderSplitItem.szCombOffsetFlag = szCombOffsetFlag; OrderSplitList.Add(orderSplitItem); } if (leave > 0 && YdPosition > 0) { int min = Math.Min(YdPosition, leave); leave -= min; byte[] bytes = { (byte)TThostFtdcOffsetFlagType.CloseYesterday, (byte)TThostFtdcOffsetFlagType.CloseYesterday }; szCombOffsetFlag = System.Text.Encoding.Default.GetString(bytes, 0, bytes.Length); orderSplitItem.qty = min; orderSplitItem.szCombOffsetFlag = szCombOffsetFlag; OrderSplitList.Add(orderSplitItem); } } else { //平仓 int position = TodayPosition + YdPosition; if (leave > 0 && position > 0) { int min = Math.Min(position, leave); leave -= min; byte[] bytes = { (byte)TThostFtdcOffsetFlagType.Close, (byte)TThostFtdcOffsetFlagType.Close }; szCombOffsetFlag = System.Text.Encoding.Default.GetString(bytes, 0, bytes.Length); orderSplitItem.qty = min; orderSplitItem.szCombOffsetFlag = szCombOffsetFlag; OrderSplitList.Add(orderSplitItem); } } } while (false); do { //指定平仓,直接跳过 if (-1 == nOpenCloseFlag) { break; } if (leave > 0) { leave = 0; byte[] bytes = { (byte)TThostFtdcOffsetFlagType.Open, (byte)TThostFtdcOffsetFlagType.Open }; szCombOffsetFlag = System.Text.Encoding.Default.GetString(bytes, 0, bytes.Length); orderSplitItem.qty = leave; orderSplitItem.szCombOffsetFlag = szCombOffsetFlag; OrderSplitList.Add(orderSplitItem); } } while (false); if (leave > 0) { string strErr = string.Format("CTP:还剩余{0}手,你应当是强制指定平仓了,但持仓数小于要平手数", leave); Console.WriteLine(strErr); EmitError(-1, -1, strErr); } //目前默认只支持投机,并且将第二腿也设置成投机,这样在使用组合时这地方不用再调整 //byte[] bytes = { (byte)TThostFtdcHedgeFlagType.Speculation, (byte)TThostFtdcHedgeFlagType.Speculation }; //string szCombHedgeFlag = System.Text.Encoding.Default.GetString(bytes, 0, bytes.Length); string szCombHedgeFlag = "11";//这样好直接啊!两个投机 foreach (SOrderSplitItem it in OrderSplitList) { int nRet = 0; switch (order.OrdType) { case OrdType.Limit: nRet = TraderApi.TD_SendOrder(m_pTdApi, altSymbol, order.Side == Side.Buy ? TThostFtdcDirectionType.Buy : TThostFtdcDirectionType.Sell, it.szCombOffsetFlag, szCombHedgeFlag, it.qty, price, TThostFtdcOrderPriceTypeType.LimitPrice, TThostFtdcTimeConditionType.GFD, TThostFtdcContingentConditionType.Immediately, order.StopPx); break; case OrdType.Market: nRet = TraderApi.TD_SendOrder(m_pTdApi, altSymbol, order.Side == Side.Buy ? TThostFtdcDirectionType.Buy : TThostFtdcDirectionType.Sell, it.szCombOffsetFlag, szCombHedgeFlag, it.qty, order.Side == Side.Buy ? DepthMarket.UpperLimitPrice : DepthMarket.LowerLimitPrice, TThostFtdcOrderPriceTypeType.LimitPrice, TThostFtdcTimeConditionType.GFD, TThostFtdcContingentConditionType.Immediately, order.StopPx); break; default: EmitError(-1, -1, string.Format("没有实现{0}", order.OrdType)); break; } if (nRet > 0) { _OrderRef2Order.Add(string.Format("{0}:{1}:{2}", _RspUserLogin.FrontID, _RspUserLogin.SessionID, nRet), order as SingleOrder); } } } }