package order import ( "encoding/json" "fmt" "math" "mtp2_if/db" "mtp2_if/global/app" "mtp2_if/global/e" "mtp2_if/logger" "mtp2_if/models" "mtp2_if/mtpcache" "mtp2_if/utils" "net/http" "strconv" "strings" "time" "github.com/gin-gonic/gin" "github.com/shopspring/decimal" ) type QtyCovert struct { QTYDECIMALPLACE int32 } // CovertQty 根据数位 放大缩小 func (r *QtyCovert) CovertQty(v int64) float64 { return float64(v) / math.Pow10(int(r.QTYDECIMALPLACE)) } // 成交付款信息 type TradePayInfo struct { PAYAMOUNT float64 `json:"payamount" xorm:"PAYAMOUNT"` // 支付金额(付款金额) ADVANCERATIO float64 `json:"advanceratio" xorm:"ADVANCERATIO"` // 首付比率 TRADECHARGE float64 `json:"-" xorm:"TRADECHARGE"` // 成交手续费(买方) TOTALAMOUNT float64 `json:"totalamount"` // 订单总额 = 成交金额 + 手续费 RECVAMOUNT float64 `json:"recvamount"` // 到账金额 = 成交金额 - 手续费 } // QueryTradePositionReq 持仓汇总查询请求参数(合约市场) type QueryTradePositionReq struct { AccountID string `form:"accountID" binding:"required"` TradeMode string `form:"tradeMode"` } // QueryTradePositionRsp 持仓汇总查询返回模型(合约市场) type QueryTradePositionRsp struct { AccountID int64 `json:"accountid" xorm:"'ACCOUNTID'"` // 资金账户 BuyOrSell int64 `json:"buyorsell" xorm:"'BUYORSELL'" ` // 方向 - 0:买 1:卖 Goodsid int32 `json:"goodsid" xorm:"'GOODSID'" binding:"required"` // 商品Id GoodsCode string `json:"goodscode" xorm:"GOODSCODE"` // 商品代码 GoodsName string `json:"goodsname" xorm:"GOODSNAME"` // 商品名称 AgreeUnit float64 `json:"agreeunit" xorm:"'AGREEUNIT'"` // 合约单位 CurrencyID int64 `json:"currencyid" xorm:"'CURRENCYID'"` // 报价货币ID - goods TaCurrencyid int64 `json:"tacurrencyid" xorm:"'TACURRENCYID'"` // 报价货币ID - taaccount GoodUnitID int64 `json:"goodunitid" xorm:"'GOODUNITID'"` // 报价单位ID Goodunit string `json:"goodunit" xorm:"'GOODUNIT'"` // 报价单位 DecimalPlace int64 `json:"decimalplace" xorm:"'DECIMALPLACE'"` // 报价小数位 MarketID int64 `json:"marketid" xorm:"'MARKETID'"` // 所属市场ID TradeMode int32 `json:"trademode" xorm:"'TRADEMODE'"` // 交易模式 PositionQTY float64 `json:"positionqty" xorm:"'POSITIONQTY'"` // 期初持仓数量 HolderAmount float64 `json:"holderamount" xorm:"'HOLDERAMOUNT'"` // 期初持仓总金额[商品币种] CurPositionQTY float64 `json:"curpositionqty" xorm:"'CURPOSITIONQTY'"` // 当前持仓总数量 CurHolderAmount float64 `json:"curholderamount" xorm:"'CURHOLDERAMOUNT'"` // 当前持仓总金额[商品币种] FrozenQTY float64 `json:"frozenqty" xorm:"'FROZENQTY'"` // 持仓冻结数量 OtherFrozenQTY float64 `json:"otherfrozenqty" xorm:"'OTHERFROZENQTY'"` // 持仓其他冻结数量(交割冻结) OpenReqQTY float64 `json:"openreqqty" xorm:"'OPENREQQTY'"` // 开仓申请数量(用于比较最大持仓数量) OpenTotalQTY float64 `json:"opentotalqty" xorm:"'OPENTOTALQTY'"` // 开仓总数量 CloseTotalQTY float64 `json:"closetotalqty" xorm:"'CLOSETOTALQTY'"` // 平仓总数量 TNQTY float64 `json:"tnqty" xorm:"'TNQTY'"` // T+N冻结总量 TNUsedQTY float64 `json:"tnusedqty" xorm:"'TNUSEDQTY'"` // T+N使用量(可以使用T+N的冻结数量) CurTDPosition float64 `json:"curtdposition" xorm:"'CURTDPOSITION'"` // 期末今日头寸 FreTDPosition float64 `json:"fretdposition" xorm:"'FRETDPOSITION'"` // 冻结今日头寸 EnableQTY float64 `json:"enableqty" xorm:"'ENABLEQTY'"` // 可用量 AveragePrice float64 `json:"averageprice" xorm:"AVERAGEPRICE"` // 持仓均价 Usedmargin float64 `json:"usedmargin" xorm:"'USEDMARGIN'"` // 占用保证金[商品币种] QTYDECIMALPLACE int32 `json:"qtydecimalplace"` // 成交量小数位 PositionPL float64 `json:"positionpl"` // 持仓盈亏 买方向 = (最新价 - 持仓均价) * 买期末头寸 * 合约单位;卖方向 = (持仓均价 - 最新价) * 卖期末头寸 * 合约单位 PositionPLRate float64 `json:"positionplrate"` // 持仓盈亏比例【实时行情更新】 = 持仓盈亏 / 开仓成本 MarketAmount float64 `json:"marketamount"` // 市值 LastPrice float64 `json:"lastprice"` // 最新价 Tradeproperty int32 `json:"tradeproperty"` // 交易属性 REFGOODSID int32 `json:"refgoodsid" xorm:"'REFGOODSID'"` // 参考商品ID REFGOODSCODE string `json:"refgoodscode" xorm:"'REFGOODSCODE'"` // 参考商品代码 MatchName string `json:"matchname" xorm:"'MATCHNAME'"` // ProviderUserID 企业名称 Mindeliverylot int64 `json:"mindeliverylot" xorm:"MINDELIVERYLOT"` // 最小交收手数(50模式) PROVIDERUSERID int64 `json:"provideruserid" xorm:"PROVIDERUSERID"` // 发售方用户ID(49)\供货商(50) PROVIDERACCOUNTID int64 `json:"provideraccountid" xorm:"PROVIDERACCOUNTID"` // 发售方资金账户ID(49)\供货商资金账户ID(50) RISKCONTROLMODE int32 `json:"riskcontrolmode" xorm:"RISKCONTROLMODE"` // 风控方式(52模式) 1:按单风控 2:按账户风控 PKID string `json:"pkid" xorm:"-"` // 自定义主键 } // QueryTradePosition 持仓汇总查询(合约市场) // @Summary 持仓汇总查询(合约市场) // @Produce json // @Security ApiKeyAuth // @Param accountID query string true "资金账户 - 格式:1,2,3" // @Param tradeMode query string false "交易模式 - 格式:1,2,3" // @Success 200 {object} QueryTradePositionRsp // @Failure 500 {object} app.Response // @Router /Order/QueryTradePosition [get] // @Tags 通用单据 // 参考通用查询:SearchTradePositionDetail func QueryTradePosition(c *gin.Context) { appG := app.Gin{C: c} // 获取请求参数 var req QueryTradePositionReq if err := appG.C.ShouldBindQuery(&req); err != nil { logger.GetLogger().Errorf("QueryTradePosition failed: %s", err.Error()) appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil) return } rst, ret := GetTradePosition(req.AccountID, req.TradeMode) if ret { appG.Response(http.StatusOK, e.SUCCESS, rst) } else { appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil) } } // GetTradePosition 获取持仓汇总数据, 成功返回true, 失败返回false func GetTradePosition(accIds string, tradeModes string) (rst []QueryTradePositionRsp, ret bool) { rst = make([]QueryTradePositionRsp, 0) // 查询数据 type tradePosition struct { models.Tradeposition `xorm:"extends"` Goodscode string `json:"goodscode" xorm:"'GOODSCODE'"` // 商品代码(内部) Goodsname string `json:"goodsname" xorm:"'GOODSNAME'"` // 商品名称 Currencyid int64 `json:"currencyid" xorm:"'CURRENCYID'"` // 报价货币ID - goods TaCurrencyid int64 `json:"tacurrencyid" xorm:"'TACURRENCYID'"` // 报价货币ID - taaccount Goodunitid int64 `json:"goodunitid" xorm:"'GOODUNITID'"` // 报价单位ID Goodunit string `json:"goodunit" xorm:"'GOODUNIT'"` // 报价单位 Agreeunit float64 `json:"agreeunit" xorm:"'AGREEUNIT'"` // 合约单位 Decimalplace int64 `json:"decimalplace" xorm:"'DECIMALPLACE'"` // 报价小数位 Marketid int32 `json:"marketid" xorm:"'MARKETID'"` // 市场ID Trademode int32 `json:"trademode" xorm:"'TRADEMODE'"` // 交易模式 QTYDECIMALPLACE int32 `json:"qtydecimalplace" xorm:"'QTYDECIMALPLACE'"` // 成交量小数位 REFGOODSID int32 `json:"refgoodsid" xorm:"'REFGOODSID'"` // 参考商品ID REFGOODSCODE string `json:"refgoodscode" xorm:"'REFGOODSCODE'"` // 参考商品代码 MatchName string `json:"matchname" xorm:"'MATCHNAME'"` // ProviderUserID 企业名称 Mindeliverylot int64 `json:"mindeliverylot" xorm:"MINDELIVERYLOT"` // 最小交收手数(50模式) PROVIDERUSERID int64 `json:"provideruserid" xorm:"PROVIDERUSERID"` // 发售方用户ID(49)\供货商(50) PROVIDERACCOUNTID int64 `json:"provideraccountid" xorm:"PROVIDERACCOUNTID"` // 发售方资金账户ID(49)\供货商资金账户ID(50) RISKCONTROLMODE int32 `json:"riskcontrolmode" xorm:"RISKCONTROLMODE"` // 风控方式(52模式) 1:按单风控 2:按账户风控 } datas := make([]tradePosition, 0) engine := db.GetEngine() // ORACLE好像在JOIN里不支持别名功能(在XORM中) s := engine.Table("TRADEPOSITION"). Join("INNER", "GOODS", "TRADEPOSITION.GOODSID = GOODS.GOODSID AND GOODS.GOODSSTATUS <> 7"). Join("LEFT", "GOODSEX EX", "EX.GOODSID = GOODS.GOODSID"). Join("LEFT", "MARKET", "GOODS.MARKETID = MARKET.MARKETID"). Join("LEFT", "ENUMDICITEM", "GOODS.GOODUNITID = ENUMDICITEM.ENUMITEMNAME and ENUMDICITEM.ENUMDICCODE = 'goodsunit'"). Join("LEFT", "USERINFO UI", "UI.USERID = GOODS.PROVIDERUSERID"). Join("LEFT", "TAACCOUNT TA", "TA.ACCOUNTID = TRADEPOSITION.ACCOUNTID"). Select("TRADEPOSITION.*, GOODS.GOODSCODE, GOODS.GOODSNAME, GOODS.CURRENCYID, TA.CURRENCYID TACURRENCYID, GOODS.GOODUNITID,GOODS.QTYDECIMALPLACE, GOODS.REFGOODSID, GOODS.REFGOODSCODE, GOODS.PROVIDERUSERID, GOODS.PROVIDERACCOUNTID, " + "ENUMDICITEM.ENUMDICNAME as GOODUNIT, GOODS.AGREEUNIT, GOODS.DECIMALPLACE, MARKET.MARKETID, MARKET.TRADEMODE, MARKET.RISKCONTROLMODE, UI.CUSTOMERNAME as MATCHNAME, nvl(EX.MINDELIVERYLOT, 1) MINDELIVERYLOT"). Where(fmt.Sprintf(`TRADEPOSITION.ACCOUNTID in (%s)`, accIds)) if len(tradeModes) > 0 { s = s.And(fmt.Sprintf(`MARKET.TRADEMODE in (%s)`, tradeModes)) } if err := s.Find(&datas); err != nil { // 查询失败 logger.GetLogger().Errorf("QueryTradePosition failed: %s", err.Error()) return rst, false } // 获取盘面 goodGuotes := make([]models.Quoteday, 0) if len(datas) > 0 { var a models.InStrBuilder for i := range datas { a.Add(datas[i].Goodscode) } goodGuotes, _ = models.GetQuoteDays(a.InStr()) } // 获取汇率配置 exchangeRateConfigs := make([]models.ExchangeRateConfig, 0) if err := engine.Find(&exchangeRateConfigs); err != nil { // 查询失败 logger.GetLogger().Errorf("获取汇率配置失败, err: %s", err.Error()) return rst, false } rateMap := make(map[string]float64) for _, item := range exchangeRateConfigs { rateMap[fmt.Sprintf("%d_%d", item.ORICURRENCYID, item.DESCURRENCYID)] = item.EXCHANGERATE } fCalcPL := func(goodsCode string, buyOrSell int64, qty, holderPrice, agreeUnit float64, decimalPlace int64, exchangeRate float64) (positionPL float64, marketAmount float64, lastPrice float64) { positionPL = 0 for _, q := range goodGuotes { if goodsCode == q.Goodscode { if q.Last != 0 { lastPrice = utils.IntToFloat64(int(q.Last), int(decimalPlace)) } else if q.Presettle != 0 { lastPrice = utils.IntToFloat64(int(q.Presettle), int(decimalPlace)) } else { return } positionPL = (lastPrice - holderPrice) * qty * agreeUnit * exchangeRate positionPL, _ = strconv.ParseFloat(utils.FormatFloat(positionPL, 2), 64) if buyOrSell == 1 { // 卖方向 *-1 positionPL *= -1.0 } marketAmount = lastPrice * qty * agreeUnit * exchangeRate marketAmount, _ = strconv.ParseFloat(utils.FormatFloat(marketAmount, 2), 64) } } return } // 构建返回数据 for _, v := range datas { // 获取汇率 exchangeRate := 1.0 if v.Currencyid != v.TaCurrencyid { if rate, ok := rateMap[fmt.Sprintf("%d_%d", v.Currencyid, v.TaCurrencyid)]; ok { exchangeRate = rate } } // 构建买方向持仓汇总 if v.Buycurpositionqty > 0 { var tradePosition QueryTradePositionRsp // 反射数据 // struct -> json if jsonBytes, err := json.Marshal(v); err == nil { c := QtyCovert{QTYDECIMALPLACE: v.QTYDECIMALPLACE} // json -> struct _ = json.Unmarshal(jsonBytes, &tradePosition) tradePosition.MatchName = v.MatchName tradePosition.Tradeproperty = v.Tradeproperty tradePosition.REFGOODSID = v.REFGOODSID tradePosition.REFGOODSCODE = v.REFGOODSCODE tradePosition.BuyOrSell = 0 tradePosition.PositionQTY = c.CovertQty(v.Buypositionqty) tradePosition.HolderAmount = v.Buyholderamount tradePosition.CurPositionQTY = c.CovertQty(v.Buycurpositionqty) tradePosition.CurHolderAmount = v.Buycurholderamount tradePosition.FrozenQTY = c.CovertQty(v.Buyfrozenqty) tradePosition.OtherFrozenQTY = c.CovertQty(v.Buyotherfrozenqty) tradePosition.OpenReqQTY = c.CovertQty(v.Buyopenreqqty) tradePosition.OpenTotalQTY = c.CovertQty(v.Buyopentotalqty) tradePosition.CloseTotalQTY = c.CovertQty(v.Buyclosetotalqty) tradePosition.TNQTY = c.CovertQty(v.Buytnqty) tradePosition.TNUsedQTY = c.CovertQty(v.Buytnusedqty) tradePosition.CurTDPosition = c.CovertQty(v.Buycurtdposition) tradePosition.FreTDPosition = c.CovertQty(v.Buyfretdposition) tradePosition.EnableQTY = c.CovertQty(v.Buycurpositionqty - v.Buyfrozenqty - v.Buyotherfrozenqty) // 计算持仓均价 averagePrice := tradePosition.CurHolderAmount / float64(tradePosition.CurPositionQTY) / tradePosition.AgreeUnit / exchangeRate // #96004 改为固定3位小数 // #3524 又改为跟商品价格小数位走 2022.04.07 // 运维提出, 不要四舍五入, 改为去尾法 2022.04.26 tradePosition.AveragePrice, _ = decimal.NewFromFloat(averagePrice).Truncate(int32(v.Decimalplace + 2)).Float64() tradePosition.PositionPL, tradePosition.MarketAmount, tradePosition.LastPrice = fCalcPL(tradePosition.GoodsCode, tradePosition.BuyOrSell, tradePosition.CurPositionQTY, tradePosition.AveragePrice, tradePosition.AgreeUnit, tradePosition.DecimalPlace, exchangeRate) if tradePosition.CurHolderAmount > 1e-10 { tradePosition.PositionPLRate = tradePosition.PositionPL / tradePosition.CurHolderAmount tradePosition.PositionPLRate, _ = strconv.ParseFloat(utils.FormatFloat(tradePosition.PositionPLRate, 4), 64) } tradePosition.PKID = fmt.Sprintf("%v_%v_%v", tradePosition.AccountID, tradePosition.Goodsid, tradePosition.BuyOrSell) tradePosition.Mindeliverylot = v.Mindeliverylot tradePosition.RISKCONTROLMODE = v.RISKCONTROLMODE rst = append(rst, tradePosition) } } // 构建卖方向持仓汇总 if v.Tradeproperty != 2 && v.Sellcurpositionqty > 0 { var tradePosition QueryTradePositionRsp // 反射数据 // struct -> json if jsonBytes, err := json.Marshal(v); err == nil { c := QtyCovert{QTYDECIMALPLACE: v.QTYDECIMALPLACE} // json -> struct _ = json.Unmarshal(jsonBytes, &tradePosition) tradePosition.MatchName = v.MatchName tradePosition.Tradeproperty = v.Tradeproperty tradePosition.REFGOODSID = v.REFGOODSID tradePosition.REFGOODSCODE = v.REFGOODSCODE tradePosition.BuyOrSell = 1 tradePosition.PositionQTY = c.CovertQty(v.Sellpositionqty) tradePosition.HolderAmount = v.Sellholderamount tradePosition.CurPositionQTY = c.CovertQty(v.Sellcurpositionqty) tradePosition.CurHolderAmount = v.Sellcurholderamount tradePosition.FrozenQTY = c.CovertQty(v.Sellfrozenqty) tradePosition.OtherFrozenQTY = c.CovertQty(v.Sellotherfrozenqty) tradePosition.OpenReqQTY = c.CovertQty(v.Sellopenreqqty) tradePosition.OpenTotalQTY = c.CovertQty(v.Sellopentotalqty) tradePosition.CloseTotalQTY = c.CovertQty(v.Sellclosetotalqty) tradePosition.TNQTY = c.CovertQty(v.Selltnqty) tradePosition.TNUsedQTY = c.CovertQty(v.Selltnusedqty) tradePosition.CurTDPosition = c.CovertQty(v.Sellcurtdposition) tradePosition.FreTDPosition = c.CovertQty(v.Sellfretdposition) tradePosition.EnableQTY = c.CovertQty(v.Sellcurpositionqty - v.Sellfrozenqty - v.Sellotherfrozenqty) // 计算持仓均价 averagePrice := tradePosition.CurHolderAmount / float64(tradePosition.CurPositionQTY) / tradePosition.AgreeUnit / exchangeRate tradePosition.AveragePrice, _ = decimal.NewFromFloat(averagePrice).Truncate(int32(v.Decimalplace + 2)).Float64() tradePosition.PositionPL, tradePosition.MarketAmount, tradePosition.LastPrice = fCalcPL(tradePosition.GoodsCode, tradePosition.BuyOrSell, tradePosition.CurPositionQTY, tradePosition.AveragePrice, tradePosition.AgreeUnit, tradePosition.DecimalPlace, exchangeRate) if tradePosition.CurHolderAmount > 1e-10 { tradePosition.PositionPLRate = tradePosition.PositionPL / tradePosition.CurHolderAmount tradePosition.PositionPLRate, _ = strconv.ParseFloat(utils.FormatFloat(tradePosition.PositionPLRate, 4), 64) } tradePosition.PKID = fmt.Sprintf("%v_%v_%v", tradePosition.AccountID, tradePosition.Goodsid, tradePosition.BuyOrSell) tradePosition.Mindeliverylot = v.Mindeliverylot tradePosition.RISKCONTROLMODE = v.RISKCONTROLMODE rst = append(rst, tradePosition) } } } // 查询成功 logger.GetLogger().Debugln("QueryTradePosition successed: %v", rst) return rst, true } // QueryTradeOrderDetailReq 委托单查询请求参数(合约市场) type QueryTradeOrderDetailReq struct { app.PageInfo AccountID string `form:"accountID" binding:"required"` OrderStatus string `form:"orderStatus"` TradeMode string `form:"tradeMode"` OrderID int `form:"orderID"` IncOrderID string `form:"incOrderID"` GoodsID int `form:"goodsID"` // 商品ID } // QueryTradeOrderDetailRsp 委托单查询返回模型(合约市场) type QueryTradeOrderDetailRsp struct { Orderid string `json:"orderid" xorm:"'ORDERID'"` // 委托单号(100+Unix秒时间戳(10位)+2位(MarketServiceID)+xxxx) Tradedate string `json:"tradedate" xorm:"'TRADEDATE'" binding:"required"` // 交易日(yyyyMMdd) Buildtype int64 `json:"buildtype" xorm:"'BUILDTYPE'" binding:"required"` // 委托单据类型 - 1:建仓 2:平仓 3:先平后建 Preorderid string `json:"preorderid" xorm:"'PREORDERID'"` // 关联预埋单号(止盈止损单时填写) Cancelorderid string `json:"cancelorderid" xorm:"'CANCELORDERID'"` // 撤单单号(撤单时填写) Relatedid string `json:"relatedid" xorm:"'RELATEDID'"` // 关联单号(交割单) Marketid int64 `json:"marketid" xorm:"'MARKETID'" binding:"required"` // 市场ID Goodsid int64 `json:"goodsid" xorm:"'GOODSID'" binding:"required"` // 商品ID Accountid int64 `json:"accountid" xorm:"'ACCOUNTID'" binding:"required"` // 账户ID[报价币种] Buyorsell int64 `json:"buyorsell" xorm:"'BUYORSELL'" binding:"required"` // 买卖 - 0:买 1:卖 Pricemode int64 `json:"pricemode" xorm:"'PRICEMODE'" binding:"required"` // 取价方式 - 1:市价 2: 限价 Orderprice float64 `json:"orderprice" xorm:"'ORDERPRICE'"` // 委托价格 Orderqty float64 `json:"orderqty" xorm:"'ORDERQTY'" binding:"required"` // 委托数量 Tradeqty float64 `json:"tradeqty" xorm:"'TRADEQTY'"` // 成交数量 Cancelqty float64 `json:"cancelqty" xorm:"'CANCELQTY'"` // 撤单数量 Openqty float64 `json:"openqty" xorm:"'OPENQTY'"` // 开仓数量(先建后平操作,需要记录) Closeqty float64 `json:"closeqty" xorm:"'CLOSEQTY'"` // 平仓数量(先建后平操作 需要记录) Opentradeqty float64 `json:"opentradeqty" xorm:"'OPENTRADEQTY'"` // 开仓成交数量(先建后平操作,需要记录) Closetradeqty float64 `json:"closetradeqty" xorm:"'CLOSETRADEQTY'"` // 平仓成交数量(先建后平操作,需要记录) Freezemargin float64 `json:"freezemargin" xorm:"'FREEZEMARGIN'"` // 冻结保证金(冻结交易金额) Unfreezemargin float64 `json:"unfreezemargin" xorm:"'UNFREEZEMARGIN'"` // 解冻保证金 Freezecharge float64 `json:"freezecharge" xorm:"'FREEZECHARGE'"` // 冻结手续费 Unfreezecharge float64 `json:"unfreezecharge" xorm:"'UNFREEZECHARGE'"` // 解冻手续费 Openfreezecharge float64 `json:"openfreezecharge" xorm:"'OPENFREEZECHARGE'"` // 开仓冻结手续费(先建后平操作,需要记录) Closefreezecharge float64 `json:"closefreezecharge" xorm:"'CLOSEFREEZECHARGE'"` // 平仓冻结手续费(先建后平操作,需要记录) Openunfreezecharge float64 `json:"openunfreezecharge" xorm:"'OPENUNFREEZECHARGE'"` // 开仓解冻手续费(先建后平操作,需要记录) Closeunfreezecharge float64 `json:"closeunfreezecharge" xorm:"'CLOSEUNFREEZECHARGE'"` // 平仓解冻手续费(先建后平操作,需要记录) Validtype int64 `json:"validtype" xorm:"'VALIDTYPE'" binding:"required"` // 有效类型 - 1当日有效 2本周有效 3指定日期有效 4一直有效 5指定时间有效 Validtime time.Time `json:"validtime" xorm:"'VALIDTIME'"` // 有效期限 Volumetype int64 `json:"volumetype" xorm:"'VOLUMETYPE'"` // 当时间有效类型为 “立即执行否则取消 IOC” 时,需要此项 - 0:任意量 1:最小量(暂时不支持) 2:全部量 Operatetype int64 `json:"operatetype" xorm:"'OPERATETYPE'" binding:"required"` // 操作类型 - 1:正常下单 2:斩仓 3:转单 4:结算撤单 5:系统卖出(适用于先平后建的卖出) 6:行情源报价 7:(结算)到期强平 8:(结算)协议转让 9:系统对冲单 10:(结算)到期无效 11:交割协议转让 12:交割协议平仓 13:交割成交(所有权) 14:管理端强行平仓 15:管理端协议转让 Ordertime time.Time `json:"ordertime" xorm:"'ORDERTIME'" binding:"required"` // 委托时间 Orderstatus int64 `json:"orderstatus" xorm:"'ORDERSTATUS'"` // 委托状态 - 1: 委托请求 2:待冻结 3:委托成功 4: 委托失败 5:配对成功 6: 已撤销 7:部分成交 8:已成交 9:部成部撤 10:成交失败 11:已拒绝 12:经过摘牌(先摘后挂专用-先摘后挂已摘过) 13:冻结成功(通道交易专用) 14:通道已撤 15:通道部成部撤 16:成交失败违约(荷兰式竞拍专用) Listingselecttype int64 `json:"listingselecttype" xorm:"'LISTINGSELECTTYPE'"` // 挂牌点选类型 - 1:挂牌 2:摘牌 3:先摘后挂 Delistingtype int64 `json:"delistingtype" xorm:"'DELISTINGTYPE'"` // 摘牌类型 - 1:价格最优 2:点选成交 Ordersrc int64 `json:"ordersrc" xorm:"'ORDERSRC'"` // 委托来源 - 1:客户端 2:管理端 3:风控服务 4:交割服务 5:交易服务 6:交易日结 7:商品强平 8:管理端商品退市强平 9:交易接口 10:交割服务商被动(受托竞价) 11:预埋触发 Clienttype int64 `json:"clienttype" xorm:"'CLIENTTYPE'"` // 客户端类型 - 0:保留为未填终端类型 1:PC管理端 2:PC交易端 3:手机客户端_安卓 4:网页客户端 5:微信客户端 6:手机客户端_苹果 7:网上开户客户端 8:无效终端编号 9:报价终端(中江) Operatorid int64 `json:"operatorid" xorm:"'OPERATORID'"` // 登录账号(LoginID) GOODUNITID int32 `json:"goodunitid" xorm:"'GOODUNITID'"` // 商品单位id GoodsCode string `json:"goodscode" xorm:"GOODSCODE"` // 商品代码 GoodsName string `json:"goodsname" xorm:"GOODSNAME"` // 商品名称 DECIMALPLACE int32 `json:"decimalplace" xorm:"'DECIMALPLACE'"` // 商品报价小数位 QTYDECIMALPLACE int `json:"qtydecimalplace" xorm:"'QTYDECIMALPLACE'"` // 商品报价小数位 Marketname string `json:"marketname" xorm:"'MARKETNAME'"` // 市场名称 TradeMode int32 `json:"trademode" xorm:"'TRADEMODE'"` // 交易模式 ENUMDICNAME string `json:"enumdicname"` // 单位名称 Enableqty float64 `json:"enableqty" xorm:"ENABLEQTY"` // 可用数量 = 委托数量 - 成交数量 - 撤单数量 } func (r *QueryTradeOrderDetailRsp) calc() { fCovert := func(v *float64) { *v = *v / math.Pow10(r.QTYDECIMALPLACE) } fCovert(&r.Orderqty) fCovert(&r.Tradeqty) fCovert(&r.Cancelqty) fCovert(&r.Openqty) fCovert(&r.Closeqty) fCovert(&r.Opentradeqty) fCovert(&r.Closetradeqty) fCovert(&r.Enableqty) r.ENUMDICNAME = mtpcache.GetEnumDicitemName(r.GOODUNITID) } // QueryTradeOrderDetail 委托单查询请求(合约市场) // @Summary 委托单查询请求(合约市场) // @Produce json // @Security ApiKeyAuth // @Param accountID query string true "资金账户 - 格式:1,2,3" // @Param tradeMode query string false "交易模式 - 格式:1,2,3" // @Param orderStatus query string false "委托状态 - 格式:1,2,3" // @Param orderID query int false "委托单号" // @Param incOrderID query string false "增量委托单号" // @Param goodsID query int false "商品ID" // @Param page query int false "页码" // @Param pagesize query int false "每页条数" // @Param pageflag query int false "分页标志 0-page从0开始 1-page从1开始" // @Success 200 {object} QueryTradeOrderDetailRsp // @Failure 500 {object} app.Response // @Router /Order/QueryTradeOrderDetail [get] // @Tags 通用单据 // 参考通用查询:SearchTradeOrderDetail func QueryTradeOrderDetail(c *gin.Context) { appG := app.Gin{C: c} // 获取请求参数 var req QueryTradeOrderDetailReq if err := appG.C.ShouldBindQuery(&req); err != nil { logger.GetLogger().Errorf("QueryTradeOrderDetail failed: %s", err.Error()) appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil) return } datas := make([]QueryTradeOrderDetailRsp, 0) engine := db.GetEngine() // 由于int64类型数据(单号)过长是获取会有问题(可能是oci8组件问题),所以这里将可能会出问题的单号都用to_char来输出 s := engine.Table("TRADE_ORDERDETAIL"). Join("LEFT", "GOODS", "GOODS.GOODSID = TRADE_ORDERDETAIL.GOODSID"). Join("LEFT", "MARKET", "MARKET.MARKETID = TRADE_ORDERDETAIL.MARKETID"). Select(`to_char(TRADE_ORDERDETAIL.ORDERID) as ORDERID, to_char(TRADE_ORDERDETAIL.PREORDERID) as PREORDERID, to_char(TRADE_ORDERDETAIL.CANCELORDERID) as CANCELORDERID, to_char(TRADE_ORDERDETAIL.RELATEDID) as RELATEDID, TRADE_ORDERDETAIL.*, TRADE_ORDERDETAIL.ORDERQTY - TRADE_ORDERDETAIL.TRADEQTY - TRADE_ORDERDETAIL.CANCELQTY as ENABLEQTY, GOODS.GOODSCODE, GOODS.GOODSNAME,GOODS.DECIMALPLACE, GOODS.QTYDECIMALPLACE,GOODS.GOODUNITID, MARKET.MARKETNAME, MARKET.TRADEMODE`). // Where(fmt.Sprintf(`TRADE_ORDERDETAIL.ORDERSRC != 10 and TRADE_ORDERDETAIL.ACCOUNTID in (%s)`, req.AccountID)). Where("TRADE_ORDERDETAIL.ORDERSRC != 10"). In("TRADE_ORDERDETAIL.ACCOUNTID", strings.Split(req.AccountID, ",")). Desc("TRADE_ORDERDETAIL.ORDERTIME") if len(req.OrderStatus) > 0 { // s = s.And(fmt.Sprintf(`TRADE_ORDERDETAIL.ORDERSTATUS in (%s)`, req.OrderStatus)) s = s.In("TRADE_ORDERDETAIL.ORDERSTATUS", strings.Split(req.OrderStatus, ",")) } if len(req.TradeMode) > 0 { // s = s.And(fmt.Sprintf(`MARKET.TRADEMODE in (%s)`, req.TradeMode)) s = s.In("MARKET.TRADEMODE", strings.Split(req.TradeMode, ",")) } if req.OrderID > 0 { s = s.And("TRADE_ORDERDETAIL.ORDERID = ?", req.OrderID) } if req.IncOrderID != "" { // s = s.And(fmt.Sprintf("TRADE_ORDERDETAIL.ORDERID > %v", req.IncOrderID)) s = s.And("TRADE_ORDERDETAIL.ORDERID > ?", req.IncOrderID) } if req.GoodsID > 0 { s = s.And("TRADE_ORDERDETAIL.GOODSID = ?", req.GoodsID) } if err := s.Find(&datas); err != nil { // 查询失败 logger.GetLogger().Errorf("QueryTradeOrderDetail failed: %s", err.Error()) appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil) return } // 查询成功 logger.GetLogger().Debugf("QueryTradeOrderDetail successed: %v\n", datas) for i := range datas { datas[i].calc() } // appG.Response(http.StatusOK, e.SUCCESS, datas) // 查询成功返回 if req.PageSize > 0 { // 分页 var rst []QueryTradeOrderDetailRsp // 开始上标 // 终端分页1开始 p := req.Page if req.PageFlag != 0 { p -= 1 if p < 0 { p = 0 } } start := p * req.PageSize // 结束下标 end := start + req.PageSize if start <= len(datas) { // 判断结束下标是否越界 if end > len(datas) { end = len(datas) } rst = datas[start:end] } else { rst = datas[0:0] } logger.GetLogger().Debugf("QueryHisTradeOrderDetail successed: %v\n", rst) appG.ResponseByPage(http.StatusOK, e.SUCCESS, rst, app.PageInfo{Page: req.Page, PageSize: req.PageSize, Total: len(datas)}) } else { // 不分页 logger.GetLogger().Debugf("QueryHisTradeOrderDetail successed: %v\n", datas) appG.Response(http.StatusOK, e.SUCCESS, datas) } } // QueryHisTradeOrderDetailReq 历史委托单查询请求参数(合约市场) type QueryHisTradeOrderDetailReq struct { app.PageInfo AccountID string `form:"accountID" binding:"required"` // 资金账户 - 格式:1,2,3 OrderStatus string `form:"orderStatus"` // 委托状态 - 格式:1,2,3 TradeMode string `form:"tradeMode"` // 交易模式 - 格式:1,2,3 OrderID int `form:"orderID"` // 委托单号 StartDate string `form:"startDate"` // 开始时间 EndDate string `form:"endDate"` // 结束时间 GoodsID int `form:"goodsID"` // 商品ID } // QueryHisTradeOrderDetailRsp 历史委托单查询返回模型(合约市场) type QueryHisTradeOrderDetailRsp struct { models.Histradeorderdetail `xorm:"extends"` GoodsCode string `json:"goodscode" xorm:"GOODSCODE"` // 商品代码 GoodsName string `json:"goodsname" xorm:"GOODSNAME"` // 商品名称 DECIMALPLACE int32 `json:"decimalplace" xorm:"'DECIMALPLACE'"` // 商品报价小数位 QTYDECIMALPLACE int `json:"qtydecimalplace" xorm:"'QTYDECIMALPLACE'"` // 成交量小数位 GOODUNITID int32 `json:"goodunitid" xorm:"'GOODUNITID'"` // 商品单位id Marketname string `json:"marketname" xorm:"'MARKETNAME'"` // 市场名称 TradeMode int32 `json:"trademode" xorm:"'TRADEMODE'"` // 交易模式 ENUMDICNAME string `json:"enumdicname"` // 单位名称 } func (r *QueryHisTradeOrderDetailRsp) calc() { fCovert := func(v *float64) { *v = *v / math.Pow10(r.QTYDECIMALPLACE) } fCovert(&r.Orderqty) fCovert(&r.Tradeqty) fCovert(&r.Cancelqty) fCovert(&r.Openqty) fCovert(&r.Closeqty) fCovert(&r.Opentradeqty) fCovert(&r.Closetradeqty) r.ENUMDICNAME = mtpcache.GetEnumDicitemName(r.GOODUNITID) } // QueryHisTradeOrderDetail 历史委托单查询请求(合约市场) // @Summary 历史委托单查询请求(合约市场) // @Produce json // @Security ApiKeyAuth // @Param accountID query string true "资金账户 - 格式:1,2,3" // @Param tradeMode query string false "交易模式 - 格式:1,2,3" // @Param orderStatus query string false "委托状态 - 格式:1,2,3" // @Param orderID query int false "委托单号" // @Param startDate query string false "开始时间 - 闭区间,格式:yyyy-MM-dd" // @Param endDate query string false "结束时间 - 闭区间,格式:yyyy-MM-dd" // @Param goodsID query int false "商品ID" // @Param page query int false "页码" // @Param pagesize query int false "每页条数" // @Param pageflag query int false "分页标志 0-page从0开始 1-page从1开始" // @Success 200 {object} QueryHisTradeOrderDetailRsp // @Failure 500 {object} app.Response // @Router /Order/QueryHisTradeOrderDetail [get] // @Tags 通用单据 // 参考通用查询:Client_QueryHis_trade_orderdetail func QueryHisTradeOrderDetail(c *gin.Context) { appG := app.Gin{C: c} // 获取请求参数 var req QueryHisTradeOrderDetailReq if err := appG.C.ShouldBindQuery(&req); err != nil { logger.GetLogger().Errorf("QueryHisTradeOrderDetail failed: %s", err.Error()) appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil) return } datas := make([]QueryHisTradeOrderDetailRsp, 0) engine := db.GetEngine() s := engine.Table("HIS_TRADE_ORDERDETAIL"). Join("LEFT", "GOODS", "GOODS.GOODSID = HIS_TRADE_ORDERDETAIL.GOODSID"). Join("LEFT", "MARKET", "MARKET.MARKETID = HIS_TRADE_ORDERDETAIL.MARKETID"). Select(`to_char(HIS_TRADE_ORDERDETAIL.ORDERID) as ORDERID, to_char(HIS_TRADE_ORDERDETAIL.PREORDERID) as PREORDERID, to_char(HIS_TRADE_ORDERDETAIL.CANCELORDERID) as CANCELORDERID, to_char(HIS_TRADE_ORDERDETAIL.RELATEDID) as RELATEDID, HIS_TRADE_ORDERDETAIL.*, GOODS.GOODSCODE, GOODS.GOODSNAME,GOODS.DECIMALPLACE, GOODS.QTYDECIMALPLACE,GOODS.GOODUNITID, MARKET.MARKETNAME, MARKET.TRADEMODE`). // Where(fmt.Sprintf(`HIS_TRADE_ORDERDETAIL.ORDERSRC != 10 and HIS_TRADE_ORDERDETAIL.ISVALIDDATA = 1 and HIS_TRADE_ORDERDETAIL.ACCOUNTID in (%s)`, req.AccountID)). Where("HIS_TRADE_ORDERDETAIL.ORDERSRC != 10 and HIS_TRADE_ORDERDETAIL.ISVALIDDATA = 1"). In("HIS_TRADE_ORDERDETAIL.ACCOUNTID", strings.Split(req.AccountID, ",")). Desc("HIS_TRADE_ORDERDETAIL.ORDERTIME") if len(req.OrderStatus) > 0 { // s = s.And(fmt.Sprintf(`HIS_TRADE_ORDERDETAIL.ORDERSTATUS in (%s)`, req.OrderStatus)) s = s.In("HIS_TRADE_ORDERDETAIL.ORDERSTATUS", strings.Split(req.OrderStatus, ",")) } if len(req.TradeMode) > 0 { // s = s.And(fmt.Sprintf(`MARKET.TRADEMODE in (%s)`, req.TradeMode)) s = s.In("MARKET.TRADEMODE", strings.Split(req.TradeMode, ",")) } if req.OrderID > 0 { s = s.And("HIS_TRADE_ORDERDETAIL.ORDERID = ?", req.OrderID) } if len(req.StartDate) > 0 { // s = s.And(fmt.Sprintf("to_date(HIS_TRADE_ORDERDETAIL.HISTRADEDATE,'yyyyMMdd') >= to_date('%s','yyyy-MM-dd')", req.StartDate)) s = s.And("HIS_TRADE_ORDERDETAIL.HISTRADEDATE >= ?", strings.Replace(req.StartDate, "-", "", -1)) } if len(req.EndDate) > 0 { // s = s.And(fmt.Sprintf("to_date(HIS_TRADE_ORDERDETAIL.HISTRADEDATE,'yyyyMMdd') <= to_date('%s','yyyy-MM-dd')", req.EndDate)) s = s.And("HIS_TRADE_ORDERDETAIL.HISTRADEDATE <= ?", strings.Replace(req.EndDate, "-", "", -1)) } if req.GoodsID > 0 { s = s.And("HIS_TRADE_ORDERDETAIL.GOODSID = ?", req.GoodsID) } if err := s.Find(&datas); err != nil { // 查询失败 logger.GetLogger().Errorf("QueryHisTradeOrderDetail failed: %s", err.Error()) appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil) return } // 查询成功 logger.GetLogger().Debugln("QueryHisTradeOrderDetail successed: %v", datas) for i := range datas { datas[i].calc() } // appG.Response(http.StatusOK, e.SUCCESS, datas) // 查询成功返回 if req.PageSize > 0 { // 分页 var rst []QueryHisTradeOrderDetailRsp // 开始上标 // 终端分页1开始 p := req.Page if req.PageFlag != 0 { p -= 1 if p < 0 { p = 0 } } start := p * req.PageSize // 结束下标 end := start + req.PageSize if start <= len(datas) { // 判断结束下标是否越界 if end > len(datas) { end = len(datas) } rst = datas[start:end] } else { rst = datas[0:0] } logger.GetLogger().Debugln("QueryHisTradeOrderDetail successed: %v", rst) appG.ResponseByPage(http.StatusOK, e.SUCCESS, rst, app.PageInfo{Page: req.Page, PageSize: req.PageSize, Total: len(datas)}) } else { // 不分页 logger.GetLogger().Debugln("QueryHisTradeOrderDetail successed: %v", datas) appG.Response(http.StatusOK, e.SUCCESS, datas) } } // QueryTradeDetailReq 成交单查询请求参数 type QueryTradeDetailReq struct { AccountID string `form:"accountID" binding:"required"` TradeID int `form:"tradeID"` OrderID int `form:"orderID"` TradeMode string `form:"tradeMode"` BuildType int `form:"buildType"` TradeType string `form:"tradeType"` GoodsID int `form:"goodsID"` IncTradeID string `form:"incTradeID"` } // QueryTradeDetailRsp 成交单查询返回模型 type QueryTradeDetailRsp struct { models.Tradetradedetail `xorm:"extends"` TradePayInfo `xorm:"extends"` GoodsCode string `json:"goodscode" xorm:"GOODSCODE"` // 商品代码 GoodsName string `json:"goodsname" xorm:"GOODSNAME"` // 商品名称 DECIMALPLACE int32 `json:"decimalplace" xorm:"'DECIMALPLACE'"` // 商品报价小数位 QTYDECIMALPLACE int `json:"qtydecimalplace" xorm:"'QTYDECIMALPLACE'"` // 商品报价小数位 GOODUNITID int32 `json:"goodunitid" xorm:"'GOODUNITID'"` // 商品单位id Marketname string `json:"marketname" xorm:"'MARKETNAME'"` // 市场名称 TradeMode int32 `json:"trademode" xorm:"'TRADEMODE'"` // 交易模式 ListingSelectType int32 `json:"listingselecttype" xorm:"'LISTINGSELECTTYPE'"` // 关联委托单挂牌点选类型 - 1:挂牌 2:摘牌 3:先摘后挂 Charge float64 `json:"charge" xorm:"CHARGE"` // 手续费 ENUMDICNAME string `json:"enumdicname"` // 单位名称 } func (r *QueryTradeDetailRsp) calc() { fCovert := func(v *float64) { *v = *v / math.Pow10(r.QTYDECIMALPLACE) } fCovert(&r.Tradeqty) fCovert(&r.Openqty) fCovert(&r.Closeqty) r.ENUMDICNAME = mtpcache.GetEnumDicitemName(r.GOODUNITID) r.TOTALAMOUNT = r.Tradeamount + r.Opencharge + r.Closecharge r.RECVAMOUNT = r.Tradeamount - r.Opencharge - r.Closecharge } // QueryTradeDetail 成交单查询(合约市场) // @Summary 成交单查询(合约市场) // @Produce json // @Security ApiKeyAuth // @Param accountID query string true "资金账户 - 格式:1,2,3" // @Param tradeID query int false "成交单号" // @Param orderID query int false "委托单号" // @Param tradeMode query string false "交易模式 - 格式:1,2,3" // @Param buildType query int false "委托单据类型" // @Param tradeType query string false "成交类别 - 格式:1,2,3" // @Param goodsID query int false "商品ID" // @Param incTradeID query string false "增量成交单号,用于增量查询" // @Success 200 {object} QueryTradeDetailRsp // @Failure 500 {object} app.Response // @Router /Order/QueryTradeDetail [get] // @Tags 通用单据 // 参考通用查询:SearchAllTransactionDetailOrder func QueryTradeDetail(c *gin.Context) { appG := app.Gin{C: c} // 获取请求参数 var req QueryTradeDetailReq if err := appG.C.ShouldBindQuery(&req); err != nil { logger.GetLogger().Errorf("QueryTradeDetail failed: %s", err.Error()) appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil) return } datas := make([]QueryTradeDetailRsp, 0) engine := db.GetEngine() s := engine.Table("TRADE_TRADEDETAIL"). Join("LEFT", "GOODS", "GOODS.GOODSID = TRADE_TRADEDETAIL.GOODSID"). Join("LEFT", "MARKET", "MARKET.MARKETID = TRADE_TRADEDETAIL.MARKETID"). Join("LEFT", "TRADE_ORDERDETAIL", "TRADE_ORDERDETAIL.ORDERID = TRADE_TRADEDETAIL.ORDERID"). Join("LEFT", "TRADE_PAYORDER", "TRADE_PAYORDER.TRADEID = TRADE_TRADEDETAIL.TRADEID"). Select(`to_char(TRADE_TRADEDETAIL.TRADEID) as TRADEID, to_char(TRADE_TRADEDETAIL.ORDERID) as ORDERID, TRADE_TRADEDETAIL.*, CASE TRADE_TRADEDETAIL.BUILDTYPE WHEN 1 THEN TRADE_TRADEDETAIL.OPENCHARGE ELSE TRADE_TRADEDETAIL.CLOSECHARGE END as CHARGE, GOODS.GOODSCODE, GOODS.GOODSNAME, GOODS.DECIMALPLACE, GOODS.QTYDECIMALPLACE,GOODS.GOODUNITID, MARKET.MARKETNAME, MARKET.TRADEMODE, TRADE_ORDERDETAIL.LISTINGSELECTTYPE, TRADE_PAYORDER.ADVANCERATIO, TRADE_PAYORDER.PAYAMOUNT, TRADE_PAYORDER.TRADECHARGE`). Where(fmt.Sprintf("TRADE_TRADEDETAIL.ACCOUNTID in (%s)", req.AccountID)). Desc("TRADE_TRADEDETAIL.TRADEID") if req.IncTradeID != "" { s = s.And(fmt.Sprintf("TRADE_TRADEDETAIL.TRADEID > %v", req.IncTradeID)) } if req.TradeID > 0 { s = s.And("TRADE_TRADEDETAIL.TRADEID = ?", req.TradeID) } if req.OrderID > 0 { s = s.And("TRADE_TRADEDETAIL.ORDERID = ?", req.OrderID) } if req.GoodsID > 0 { s = s.And("TRADE_TRADEDETAIL.GOODSID = ?", req.GoodsID) } if len(req.TradeMode) > 0 { s = s.And(fmt.Sprintf("MARKET.TRADEMODE in (%s)", req.TradeMode)) } if req.BuildType > 0 { s = s.And("TRADE_TRADEDETAIL.BUILDTYPE = ?", req.BuildType) } if len(req.TradeType) > 0 { s = s.And(fmt.Sprintf("TRADE_TRADEDETAIL.TRADETYPE in (%s)", req.TradeType)) } if err := s.Find(&datas); err != nil { // 查询失败 logger.GetLogger().Errorf("QueryTradeDetail failed: %s", err.Error()) appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil) return } // 查询成功 logger.GetLogger().Debugln("QueryTradeDetail successed: %v", datas) for i := range datas { datas[i].calc() } appG.Response(http.StatusOK, e.SUCCESS, datas) } // QueryHisTradeDetailReq 历史成交单查询请求参数 type QueryHisTradeDetailReq struct { app.PageInfo AccountID string `form:"accountID" binding:"required"` TradeID int `form:"tradeID"` OrderID int `form:"orderID"` GoodsID int `form:"goodsID"` TradeMode string `form:"tradeMode"` BuildType int `form:"buildType"` TradeType string `form:"tradeType"` StartDate string `form:"startDate"` // 开始时间 EndDate string `form:"endDate"` // 结束时间 } // QueryHisTradeDetailRsp 历史成交单查询返回模型 type QueryHisTradeDetailRsp struct { models.Histradetradedetail `xorm:"extends"` TradePayInfo `xorm:"extends"` GoodsCode string `json:"goodscode" xorm:"GOODSCODE"` // 商品代码 GoodsName string `json:"goodsname" xorm:"GOODSNAME"` // 商品名称 DECIMALPLACE int32 `json:"decimalplace" xorm:"'DECIMALPLACE'"` // 商品报价小数位 QTYDECIMALPLACE int `json:"qtydecimalplace" xorm:"'QTYDECIMALPLACE'"` // 商品报价小数位 GOODUNITID int32 `json:"goodunitid" xorm:"'GOODUNITID'"` // 商品单位id Marketname string `json:"marketname" xorm:"'MARKETNAME'"` // 市场名称 TradeMode int32 `json:"trademode" xorm:"'TRADEMODE'"` // 交易模式 ListingSelectType int32 `json:"listingselecttype" xorm:"'LISTINGSELECTTYPE'"` // 关联委托单挂牌点选类型 - 1:挂牌 2:摘牌 3:先摘后挂 Charge float64 `json:"charge" xorm:"CHARGE"` // 手续费 ENUMDICNAME string `json:"enumdicname"` // 单位名称 } func (r *QueryHisTradeDetailRsp) calc() { fCovert := func(v *float64) { *v = *v / math.Pow10(r.QTYDECIMALPLACE) } fCovert(&r.Tradeqty) fCovert(&r.Openqty) fCovert(&r.Closeqty) r.ENUMDICNAME = mtpcache.GetEnumDicitemName(r.GOODUNITID) r.TOTALAMOUNT = r.Tradeamount + r.Opencharge + r.Closecharge r.RECVAMOUNT = r.Tradeamount - r.Opencharge - r.Closecharge } // QueryHisTradeDetail 历史成交单查询(合约市场) // @Summary 历史成交单查询(合约市场) // @Produce json // @Security ApiKeyAuth // @Param accountID query string true "资金账户 - 格式:1,2,3" // @Param tradeID query int false "成交单号" // @Param orderID query int false "委托单号" // @Param goodsID query int false "商品ID" // @Param tradeMode query string false "交易模式 - 格式:1,2,3" // @Param buildType query int false "委托单据类型" // @Param tradeType query string false "成交类别 - 格式:1,2,3" // @Param startDate query string false "开始时间 - 闭区间,格式:yyyy-MM-dd" // @Param endDate query string false "结束时间 - 闭区间,格式:yyyy-MM-dd" // @Param page query int false "页码" // @Param pagesize query int false "每页条数" // @Param pageflag query int false "分页标志 0-page从0开始 1-page从1开始" // @Success 200 {object} QueryHisTradeDetailRsp // @Failure 500 {object} app.Response // @Router /Order/QueryHisTradeDetail [get] // @Tags 通用单据 // 参考通用查询:Client_QueryHis_trade_transactiondetail func QueryHisTradeDetail(c *gin.Context) { appG := app.Gin{C: c} // 获取请求参数 var req QueryHisTradeDetailReq if err := appG.C.ShouldBindQuery(&req); err != nil { logger.GetLogger().Errorf("QueryHisTradeDetail failed: %s", err.Error()) appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil) return } accountIds := strings.Split(req.AccountID, ",") datas := make([]QueryHisTradeDetailRsp, 0) engine := db.GetEngine() s := engine.Table("HIS_TRADE_TRADEDETAIL"). Join("LEFT", "GOODS", "GOODS.GOODSID = HIS_TRADE_TRADEDETAIL.GOODSID"). Join("LEFT", "MARKET", "MARKET.MARKETID = HIS_TRADE_TRADEDETAIL.MARKETID"). Join("LEFT", "TRADE_PAYORDER", "TRADE_PAYORDER.TRADEID = HIS_TRADE_TRADEDETAIL.TRADEID"). Select(`to_char(HIS_TRADE_TRADEDETAIL.TRADEID) as TRADEID, to_char(HIS_TRADE_TRADEDETAIL.ORDERID) as ORDERID, HIS_TRADE_TRADEDETAIL.*, CASE HIS_TRADE_TRADEDETAIL.BUILDTYPE WHEN 1 THEN HIS_TRADE_TRADEDETAIL.OPENCHARGE ELSE HIS_TRADE_TRADEDETAIL.CLOSECHARGE END as CHARGE, GOODS.GOODSCODE, GOODS.GOODSNAME,GOODS.DECIMALPLACE, GOODS.QTYDECIMALPLACE, GOODS.GOODUNITID, MARKET.MARKETNAME, MARKET.TRADEMODE, TRADE_PAYORDER.ADVANCERATIO, TRADE_PAYORDER.PAYAMOUNT, TRADE_PAYORDER.TRADECHARGE`). // Where(fmt.Sprintf("HIS_TRADE_TRADEDETAIL.ISVALIDDATA = 1 and HIS_TRADE_TRADEDETAIL.ACCOUNTID in (%s)", req.AccountID)). Where("HIS_TRADE_TRADEDETAIL.ISVALIDDATA = 1"). In("HIS_TRADE_TRADEDETAIL.ACCOUNTID", accountIds). Desc("HIS_TRADE_TRADEDETAIL.TRADEID") if req.TradeID > 0 { s = s.And("HIS_TRADE_TRADEDETAIL.TRADEID = ?", req.TradeID) } if req.OrderID > 0 { s = s.And("HIS_TRADE_TRADEDETAIL.ORDERID = ?", req.OrderID) } if req.GoodsID > 0 { s = s.And("HIS_TRADE_TRADEDETAIL.GOODSID = ?", req.GoodsID) } if len(req.TradeMode) > 0 { // s = s.And(fmt.Sprintf("MARKET.TRADEMODE in (%s)", req.TradeMode)) tradeModes := strings.Split(req.TradeMode, ",") s = s.In("MARKET.TRADEMODE", tradeModes) } if req.BuildType > 0 { s = s.And("HIS_TRADE_TRADEDETAIL.BUILDTYPE = ?", req.BuildType) } if len(req.TradeType) > 0 { // s = s.And(fmt.Sprintf("HIS_TRADE_TRADEDETAIL.TRADETYPE in (%s)", req.TradeType)) tradeTypes := strings.Split(req.TradeType, ",") s = s.In("HIS_TRADE_TRADEDETAIL.TRADETYPE", tradeTypes) } if len(req.StartDate) > 0 { // s = s.And(fmt.Sprintf("to_date(HIS_TRADE_TRADEDETAIL.HISTRADEDATE,'yyyyMMdd') >= to_date('%s','yyyy-MM-dd')", req.StartDate)) s = s.And("HIS_TRADE_TRADEDETAIL.HISTRADEDATE >= ?", strings.Replace(req.StartDate, "-", "", -1)) } if len(req.EndDate) > 0 { // s = s.And(fmt.Sprintf("to_date(HIS_TRADE_TRADEDETAIL.HISTRADEDATE,'yyyyMMdd') <= to_date('%s','yyyy-MM-dd')", req.EndDate)) s = s.And("HIS_TRADE_TRADEDETAIL.HISTRADEDATE <= ?", strings.Replace(req.EndDate, "-", "", -1)) } if err := s.Find(&datas); err != nil { // 查询失败 logger.GetLogger().Errorf("QueryHisTradeDetail failed: %s", err.Error()) appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil) return } // 查询成功 logger.GetLogger().Debugln("QueryHisTradeDetail successed: %v", datas) for i := range datas { datas[i].calc() } // appG.Response(http.StatusOK, e.SUCCESS, datas) // 查询成功返回 if req.PageSize > 0 { // 分页 var rst []QueryHisTradeDetailRsp // 开始上标 // 终端分页1开始 p := req.Page if req.PageFlag != 0 { p -= 1 if p < 0 { p = 0 } } start := p * req.PageSize // 结束下标 end := start + req.PageSize if start <= len(datas) { // 判断结束下标是否越界 if end > len(datas) { end = len(datas) } rst = datas[start:end] } else { rst = datas[0:0] } logger.GetLogger().Debugln("QueryHisTradeDetail successed: %v", rst) appG.ResponseByPage(http.StatusOK, e.SUCCESS, rst, app.PageInfo{Page: req.Page, PageSize: req.PageSize, Total: len(datas)}) } else { // 不分页 logger.GetLogger().Debugln("QueryHisTradeDetail successed: %v", datas) appG.Response(http.StatusOK, e.SUCCESS, datas) } }