private int close(string pInstrument, DirectionType pPosiDire, int pCloseLots, MarketData pTick, bool pForce, double pPrice, int pCustom) { PositionField pf; if (!DicPositionField.TryGetValue($"{pInstrument}_{pPosiDire}", out pf)) { return(pCloseLots); } var dire = pPosiDire == DirectionType.Buy ? DirectionType.Sell : DirectionType.Buy; var price = !double.IsNaN(pPrice) ? pPrice : (dire == DirectionType.Buy ? (pForce ? pTick.UpperLimitPrice : pTick.AskPrice) : (pForce ? pTick.LowerLimitPrice : pTick.BidPrice)); //板价发单 var volClose = Math.Min(pCloseLots, pf.Position); //可平量 var rtn = pCloseLots - volClose; if (DicInstrumentField[pInstrument].ExchangeID == Exchange.SHFE && pf.TdPosition > 0) { var tdClose = Math.Min(pf.TdPosition, volClose); ReqOrderInsert(pInstrument, dire, OffsetType.CloseToday, price, tdClose, pCustom: pCustom); volClose -= tdClose; } if (volClose > 0) { ReqOrderInsert(pInstrument, dire, OffsetType.Close, price, volClose, pCustom: pCustom); } return(rtn); }
private void CTPOnRtnTrade(ref CThostFtdcTradeField pTrade) { if (!IsLogin) { _rtnOrderTime = DateTime.Now; } string id; OrderField of = null; if (!(_dicSysidSfrId.TryGetValue(pTrade.OrderSysID, out id) && DicOrderField.TryGetValue(id, out of))) { CThostFtdcTradeField fReTrade = pTrade; var list = _sysidTrade.GetOrAdd(pTrade.OrderSysID, new List <CThostFtdcTradeField>()); list.Add(fReTrade); return; } TradeField f = new TradeField { Hedge = pTrade.HedgeFlag == TThostFtdcHedgeFlagType.THOST_FTDC_HF_Speculation ? HedgeType.Speculation : pTrade.HedgeFlag == TThostFtdcHedgeFlagType.THOST_FTDC_HF_Arbitrage ? HedgeType.Arbitrage : HedgeType.Hedge, Direction = pTrade.Direction == TThostFtdcDirectionType.THOST_FTDC_D_Buy ? DirectionType.Buy : DirectionType.Sell, //ExchangeID = pTrade.ExchangeID, InstrumentID = pTrade.InstrumentID, Offset = pTrade.OffsetFlag == TThostFtdcOffsetFlagType.THOST_FTDC_OF_Open ? OffsetType.Open : pTrade.OffsetFlag == TThostFtdcOffsetFlagType.THOST_FTDC_OF_CloseToday ? OffsetType.CloseToday : OffsetType.Close, Price = pTrade.Price, TradeID = pTrade.TradeID + (char)pTrade.Direction, TradeTime = pTrade.TradeTime, TradingDay = pTrade.TradingDay, Volume = pTrade.Volume, SysID = pTrade.OrderSysID, }; Exchange exc; if (Enum.TryParse(pTrade.ExchangeID, out exc)) { f.ExchangeID = exc; } if (DicTradeField.TryAdd(f.TradeID, f)) // string.Format("{0}_{1}", f.TradeID, f.Direction), f)) { f.OrderID = id; //更新成交对应的委托ID of.TradeTime = pTrade.TradeTime; of.AvgPrice = (of.AvgPrice * (of.Volume - of.VolumeLeft) + pTrade.Price * pTrade.Volume) / (of.Volume - of.VolumeLeft + pTrade.Volume); of.TradeVolume = pTrade.Volume; of.VolumeLeft -= of.TradeVolume; if (of.VolumeLeft == 0) { of.Status = OrderStatus.Filled; of.StatusMsg = "全部成交"; } else { of.Status = OrderStatus.Partial; of.StatusMsg = "部分成交"; } if (IsLogin) { #region 更新持仓 PositionField pf; //处理持仓 if (f.Offset == OffsetType.Open) { pf = DicPositionField.GetOrAdd(f.InstrumentID + "_" + f.Direction, new PositionField()); pf.InstrumentID = f.InstrumentID; pf.Direction = f.Direction; pf.Hedge = f.Hedge; pf.Price = (pf.Price * pf.Position + f.Price * f.Volume) / (pf.Position + f.Volume); pf.TdPosition += f.Volume; pf.Position += f.Volume; } else { pf = this.DicPositionField.GetOrAdd(f.InstrumentID + "_" + (f.Direction == DirectionType.Buy ? "Sell" : "Buy"), new PositionField()); if (f.Offset == OffsetType.CloseToday) { pf.TdPosition -= f.Volume; } else { int tdClose = Math.Min(pf.TdPosition, f.Volume); if (pf.TdPosition > 0) { pf.TdPosition -= tdClose; } pf.YdPosition -= Math.Max(0, f.Volume - tdClose); } pf.Position -= f.Volume; } #endregion //委托响应 _OnRtnOrder?.Invoke(this, new OrderArgs { Value = of }); //成交响应 _OnRtnTrade?.Invoke(this, new TradeArgs { Value = f }); } } }
private void CTPOnRspQryInvestorPosition(ref CThostFtdcInvestorPositionField pInvestorPosition, ref CThostFtdcRspInfoField pRspInfo, int nRequestID, bool bIsLast) { if (!string.IsNullOrEmpty(pInvestorPosition.InstrumentID)) { var f = pInvestorPosition; _listPosi.Add(f); } if (bIsLast) { foreach (var g in _listPosi.GroupBy(p => p.InstrumentID + "_" + p.PosiDirection)) { var id = g.First(); //整理持仓数据 HedgeType hedge = HedgeType.Speculation; switch (id.HedgeFlag) { case TThostFtdcHedgeFlagType.THOST_FTDC_HF_Speculation: hedge = HedgeType.Speculation; break; case TThostFtdcHedgeFlagType.THOST_FTDC_HF_Arbitrage: hedge = HedgeType.Arbitrage; break; case TThostFtdcHedgeFlagType.THOST_FTDC_HF_Hedge: hedge = HedgeType.Hedge; break; } DirectionType dire = DirectionType.Buy; if (g.First().PosiDirection == TThostFtdcPosiDirectionType.THOST_FTDC_PD_Short) { dire = DirectionType.Sell; } var key = id.InstrumentID + "_" + dire; var pf = DicPositionField.GetOrAdd(key, new PositionField { InstrumentID = id.InstrumentID, Direction = dire, Hedge = hedge, }); //if (pInvestorPosition.PositionDate == TThostFtdcPositionDateType.THOST_FTDC_PSD_Today) //{ // pf.TdPosition = pInvestorPosition.Position; // pf.TdCost = pf.TdPosition == 0 ? 0 : (pInvestorPosition.PositionCost /*pInvestorPosition.TodayPosition * pf.TdPosition*/); //} //if (pInvestorPosition.PositionDate == TThostFtdcPositionDateType.THOST_FTDC_PSD_History) //{ // pf.YdPosition = pInvestorPosition.Position; // pf.YdCost = pInvestorPosition.PreSettlementPrice * pf.YdPosition * DicInstrumentField[pf.InstrumentID].VolumeMultiple; // //pf.YdCost = pInvestorPosition.PositionCost / pInvestorPosition.YdPosition * pf.YdPosition; //} pf.Position = g.Sum(n => n.Position); // pf.TdPosition + pf.YdPosition; pf.TdPosition = g.Sum(n => n.TodayPosition); pf.YdPosition = pf.Position - pf.TdPosition; // g.Sum(n => n.YdPosition); pf.Price = pf.Position <= 0 ? 0 : (g.Sum(n => n.PositionCost) / DicInstrumentField[pf.InstrumentID].VolumeMultiple / pf.Position); pf.CloseProfit = g.Sum(n => n.CloseProfit); pf.PositionProfit = g.Sum(n => n.PositionProfit); pf.Commission = g.Sum(n => n.Commission); pf.Margin = g.Sum(n => n.UseMargin); } TradingAccount.CloseProfit = _listPosi.Sum(n => n.CloseProfit); TradingAccount.PositionProfit = _listPosi.Sum(n => n.PositionProfit); TradingAccount.Commission = _listPosi.Sum(n => n.Commission); TradingAccount.Fund = TradingAccount.PreBalance + TradingAccount.CloseProfit + TradingAccount.PositionProfit - TradingAccount.Commission; TradingAccount.FrozenCash = _listPosi.Sum(n => n.FrozenCash); //由查帐户资金函数处理,原因:保证金有单边收的情况无法用持仓统计 //TradingAccount.CurrMargin = _listPosi.Sum(n => n.UseMargin); //TradingAccount.Available = TradingAccount.Fund - TradingAccount.CurrMargin - TradingAccount.FrozenCash; //TradingAccount.Risk = TradingAccount.CurrMargin / TradingAccount.Fund; _listPosi.Clear();//清除,以便得到结果是重新添加 } }