order.go 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  1. package order
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "math"
  6. "mtp2_if/db"
  7. "mtp2_if/global/app"
  8. "mtp2_if/global/e"
  9. "mtp2_if/logger"
  10. "mtp2_if/models"
  11. "mtp2_if/mtpcache"
  12. "mtp2_if/utils"
  13. "net/http"
  14. "strconv"
  15. "time"
  16. "github.com/gin-gonic/gin"
  17. "github.com/shopspring/decimal"
  18. )
  19. type QtyCovert struct {
  20. QTYDECIMALPLACE int32
  21. }
  22. // CovertQty 根据数位 放大缩小
  23. func (r *QtyCovert) CovertQty(v int64) float64 {
  24. return float64(v) / math.Pow10(int(r.QTYDECIMALPLACE))
  25. }
  26. // 成交付款信息
  27. type TradePayInfo struct {
  28. PAYAMOUNT float64 `json:"payamount" xorm:"PAYAMOUNT"` // 支付金额(付款金额)
  29. ADVANCERATIO float64 `json:"advanceratio" xorm:"ADVANCERATIO"` // 首付比率
  30. TRADECHARGE float64 `json:"-" xorm:"TRADECHARGE"` // 成交手续费(买方)
  31. TOTALAMOUNT float64 `json:"totalamount"` // 订单总额 = 成交金额 + 手续费
  32. RECVAMOUNT float64 `json:"recvamount"` // 到账金额 = 成交金额 - 手续费
  33. }
  34. // QueryTradePositionReq 持仓汇总查询请求参数(合约市场)
  35. type QueryTradePositionReq struct {
  36. AccountID string `form:"accountID" binding:"required"`
  37. TradeMode string `form:"tradeMode"`
  38. }
  39. // QueryTradePositionRsp 持仓汇总查询返回模型(合约市场)
  40. type QueryTradePositionRsp struct {
  41. AccountID int64 `json:"accountid" xorm:"'ACCOUNTID'"` // 资金账户
  42. BuyOrSell int64 `json:"buyorsell" xorm:"'BUYORSELL'" ` // 方向 - 0:买 1:卖
  43. Goodsid int32 `json:"goodsid" xorm:"'GOODSID'" binding:"required"` // 商品Id
  44. GoodsCode string `json:"goodscode" xorm:"GOODSCODE"` // 商品代码
  45. GoodsName string `json:"goodsname" xorm:"GOODSNAME"` // 商品名称
  46. AgreeUnit float64 `json:"agreeunit" xorm:"'AGREEUNIT'"` // 合约单位
  47. CurrencyID int64 `json:"currencyid" xorm:"'CURRENCYID'"` // 报价货币ID
  48. GoodUnitID int64 `json:"goodunitid" xorm:"'GOODUNITID'"` // 报价单位ID
  49. Goodunit string `json:"goodunit" xorm:"'GOODUNIT'"` // 报价单位
  50. DecimalPlace int64 `json:"decimalplace" xorm:"'DECIMALPLACE'"` // 报价小数位
  51. MarketID int64 `json:"marketid" xorm:"'MARKETID'"` // 所属市场ID
  52. TradeMode int32 `json:"trademode" xorm:"'TRADEMODE'"` // 交易模式
  53. PositionQTY float64 `json:"positionqty" xorm:"'POSITIONQTY'"` // 期初持仓数量
  54. HolderAmount float64 `json:"holderamount" xorm:"'HOLDERAMOUNT'"` // 期初持仓总金额[商品币种]
  55. CurPositionQTY float64 `json:"curpositionqty" xorm:"'CURPOSITIONQTY'"` // 当前持仓总数量
  56. CurHolderAmount float64 `json:"curholderamount" xorm:"'CURHOLDERAMOUNT'"` // 当前持仓总金额[商品币种]
  57. FrozenQTY float64 `json:"frozenqty" xorm:"'FROZENQTY'"` // 持仓冻结数量
  58. OtherFrozenQTY float64 `json:"otherfrozenqty" xorm:"'OTHERFROZENQTY'"` // 持仓其他冻结数量(交割冻结)
  59. OpenReqQTY float64 `json:"openreqqty" xorm:"'OPENREQQTY'"` // 开仓申请数量(用于比较最大持仓数量)
  60. OpenTotalQTY float64 `json:"opentotalqty" xorm:"'OPENTOTALQTY'"` // 开仓总数量
  61. CloseTotalQTY float64 `json:"closetotalqty" xorm:"'CLOSETOTALQTY'"` // 平仓总数量
  62. TNQTY float64 `json:"tnqty" xorm:"'TNQTY'"` // T+N冻结总量
  63. TNUsedQTY float64 `json:"tnusedqty" xorm:"'TNUSEDQTY'"` // T+N使用量(可以使用T+N的冻结数量)
  64. CurTDPosition float64 `json:"curtdposition" xorm:"'CURTDPOSITION'"` // 期末今日头寸
  65. FreTDPosition float64 `json:"fretdposition" xorm:"'FRETDPOSITION'"` // 冻结今日头寸
  66. EnableQTY float64 `json:"enableqty" xorm:"'ENABLEQTY'"` // 可用量
  67. AveragePrice float64 `json:"averageprice" xorm:"AVERAGEPRICE"` // 持仓均价
  68. Usedmargin float64 `json:"usedmargin" xorm:"'USEDMARGIN'"` // 占用保证金[商品币种]
  69. QTYDECIMALPLACE int32 `json:"qtydecimalplace"` // 成交量小数位
  70. PositionPL float64 `json:"positionpl"` // 持仓盈亏 买方向 = (最新价 - 持仓均价) * 买期末头寸 * 合约单位;卖方向 = (持仓均价 - 最新价) * 卖期末头寸 * 合约单位
  71. PositionPLRate float64 `json:"positionplrate"` // 持仓盈亏比例【实时行情更新】 = 持仓盈亏 / 开仓成本
  72. MarketAmount float64 `json:"marketamount"` // 市值
  73. LastPrice float64 `json:"lastprice"` // 最新价
  74. Tradeproperty int32 `json:"tradeproperty"` // 交易属性
  75. }
  76. // QueryTradePosition 持仓汇总查询(合约市场)
  77. // @Summary 持仓汇总查询(合约市场)
  78. // @Produce json
  79. // @Security ApiKeyAuth
  80. // @Param accountID query string true "资金账户 - 格式:1,2,3"
  81. // @Param tradeMode query string false "交易模式 - 格式:1,2,3"
  82. // @Success 200 {object} QueryTradePositionRsp
  83. // @Failure 500 {object} app.Response
  84. // @Router /Order/QueryTradePosition [get]
  85. // @Tags 通用单据
  86. // 参考通用查询:SearchTradePositionDetail
  87. func QueryTradePosition(c *gin.Context) {
  88. appG := app.Gin{C: c}
  89. // 获取请求参数
  90. var req QueryTradePositionReq
  91. if err := appG.C.ShouldBindQuery(&req); err != nil {
  92. logger.GetLogger().Errorf("QueryTradePosition failed: %s", err.Error())
  93. appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
  94. return
  95. }
  96. rst, ret := GetTradePosition(req.AccountID, req.TradeMode)
  97. if ret {
  98. appG.Response(http.StatusOK, e.SUCCESS, rst)
  99. } else {
  100. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  101. }
  102. }
  103. // GetTradePosition 获取持仓汇总数据, 成功返回true, 失败返回false
  104. func GetTradePosition(accIds string, tradeModes string) (rst []QueryTradePositionRsp, ret bool) {
  105. rst = make([]QueryTradePositionRsp, 0)
  106. // 查询数据
  107. type tradePosition struct {
  108. models.Tradeposition `xorm:"extends"`
  109. Goodscode string `json:"goodscode" xorm:"'GOODSCODE'"` // 商品代码(内部)
  110. Goodsname string `json:"goodsname" xorm:"'GOODSNAME'"` // 商品名称
  111. Currencyid int64 `json:"currencyid" xorm:"'CURRENCYID'"` // 报价货币ID
  112. Goodunitid int64 `json:"goodunitid" xorm:"'GOODUNITID'"` // 报价单位ID
  113. Goodunit string `json:"goodunit" xorm:"'GOODUNIT'"` // 报价单位
  114. Agreeunit float64 `json:"agreeunit" xorm:"'AGREEUNIT'"` // 合约单位
  115. Decimalplace int64 `json:"decimalplace" xorm:"'DECIMALPLACE'"` // 报价小数位
  116. Marketid int32 `json:"marketid" xorm:"'MARKETID'"` // 市场ID
  117. Trademode int32 `json:"trademode" xorm:"'TRADEMODE'"` // 交易模式
  118. QTYDECIMALPLACE int32 `json:"qtydecimalplace" xorm:"'QTYDECIMALPLACE'"` // 成交量小数位
  119. }
  120. datas := make([]tradePosition, 0)
  121. engine := db.GetEngine()
  122. // ORACLE好像在JOIN里不支持别名功能(在XORM中)
  123. s := engine.Table("TRADEPOSITION").
  124. Join("LEFT", "GOODS", "TRADEPOSITION.GOODSID = GOODS.GOODSID").
  125. Join("LEFT", "MARKET", "GOODS.MARKETID = MARKET.MARKETID").
  126. Join("LEFT", "ENUMDICITEM", "GOODS.GOODUNITID = ENUMDICITEM.ENUMITEMNAME and ENUMDICITEM.ENUMDICCODE = 'goodsunit'").
  127. Select("TRADEPOSITION.*, GOODS.GOODSCODE, GOODS.GOODSNAME, GOODS.CURRENCYID, GOODS.GOODUNITID,GOODS.QTYDECIMALPLACE, ENUMDICITEM.ENUMDICNAME as GOODUNIT, GOODS.AGREEUNIT, GOODS.DECIMALPLACE, MARKET.MARKETID, MARKET.TRADEMODE").
  128. Where(fmt.Sprintf(`TRADEPOSITION.ACCOUNTID in (%s)`, accIds))
  129. if len(tradeModes) > 0 {
  130. s = s.And(fmt.Sprintf(`MARKET.TRADEMODE in (%s)`, tradeModes))
  131. }
  132. if err := s.Find(&datas); err != nil {
  133. // 查询失败
  134. logger.GetLogger().Errorf("QueryTradePosition failed: %s", err.Error())
  135. return rst, false
  136. }
  137. // 获取盘面
  138. goodGuotes := make([]models.Quoteday, 0)
  139. if len(datas) > 0 {
  140. var a models.InStrBuilder
  141. for i := range datas {
  142. a.Add(datas[i].Goodscode)
  143. }
  144. goodGuotes, _ = models.GetQuoteDays(a.InStr())
  145. }
  146. fCalcPL := func(goodsCode string, buyOrSell int64, qty, holderPrice,
  147. agreeUnit float64, decimalPlace int64) (positionPL float64, marketAmount float64, lastPrice float64) {
  148. positionPL = 0
  149. for _, q := range goodGuotes {
  150. if goodsCode == q.Goodscode {
  151. if q.Last != 0 {
  152. lastPrice = utils.IntToFloat64(int(q.Last), int(decimalPlace))
  153. } else if q.Presettle != 0 {
  154. lastPrice = utils.IntToFloat64(int(q.Presettle), int(decimalPlace))
  155. } else {
  156. return
  157. }
  158. positionPL = (lastPrice - holderPrice) * qty * agreeUnit
  159. positionPL, _ = strconv.ParseFloat(utils.FormatFloat(positionPL, 2), 64)
  160. if buyOrSell == 1 {
  161. // 卖方向 *-1
  162. positionPL *= -1.0
  163. }
  164. marketAmount = lastPrice * qty * agreeUnit
  165. marketAmount, _ = strconv.ParseFloat(utils.FormatFloat(marketAmount, 2), 64)
  166. }
  167. }
  168. return
  169. }
  170. // 构建返回数据
  171. for _, v := range datas {
  172. // 构建买方向持仓汇总
  173. if v.Buycurpositionqty > 0 {
  174. var tradePosition QueryTradePositionRsp
  175. // 反射数据
  176. // struct -> json
  177. if jsonBytes, err := json.Marshal(v); err == nil {
  178. c := QtyCovert{QTYDECIMALPLACE: v.QTYDECIMALPLACE}
  179. // json -> struct
  180. _ = json.Unmarshal(jsonBytes, &tradePosition)
  181. tradePosition.Tradeproperty = v.Tradeproperty
  182. tradePosition.BuyOrSell = 0
  183. tradePosition.PositionQTY = c.CovertQty(v.Buypositionqty)
  184. tradePosition.HolderAmount = v.Buyholderamount
  185. tradePosition.CurPositionQTY = c.CovertQty(v.Buycurpositionqty)
  186. tradePosition.CurHolderAmount = v.Buycurholderamount
  187. tradePosition.FrozenQTY = c.CovertQty(v.Buyfrozenqty)
  188. tradePosition.OtherFrozenQTY = c.CovertQty(v.Buyotherfrozenqty)
  189. tradePosition.OpenReqQTY = c.CovertQty(v.Buyopenreqqty)
  190. tradePosition.OpenTotalQTY = c.CovertQty(v.Buyopentotalqty)
  191. tradePosition.CloseTotalQTY = c.CovertQty(v.Buyclosetotalqty)
  192. tradePosition.TNQTY = c.CovertQty(v.Buytnqty)
  193. tradePosition.TNUsedQTY = c.CovertQty(v.Buytnusedqty)
  194. tradePosition.CurTDPosition = c.CovertQty(v.Buycurtdposition)
  195. tradePosition.FreTDPosition = c.CovertQty(v.Buyfretdposition)
  196. tradePosition.EnableQTY = c.CovertQty(v.Buycurpositionqty - v.Buyfrozenqty - v.Buyotherfrozenqty)
  197. // 计算持仓均价
  198. averagePrice := tradePosition.CurHolderAmount / float64(tradePosition.CurPositionQTY) / tradePosition.AgreeUnit
  199. //tradePosition.AveragePrice, _ = strconv.ParseFloat(utils.FormatFloat(averagePrice, int(v.Decimalplace)), 64)
  200. // #96004 改为固定3位小数
  201. tradePosition.AveragePrice, _ = decimal.NewFromFloat(averagePrice).Round(3).Float64()
  202. tradePosition.PositionPL, tradePosition.MarketAmount, tradePosition.LastPrice = fCalcPL(tradePosition.GoodsCode, tradePosition.BuyOrSell, tradePosition.CurPositionQTY,
  203. tradePosition.AveragePrice, tradePosition.AgreeUnit, tradePosition.DecimalPlace)
  204. if tradePosition.CurHolderAmount > 1e-10 {
  205. tradePosition.PositionPLRate = tradePosition.PositionPL / tradePosition.CurHolderAmount
  206. tradePosition.PositionPLRate, _ = strconv.ParseFloat(utils.FormatFloat(tradePosition.PositionPLRate, 4), 64)
  207. }
  208. rst = append(rst, tradePosition)
  209. }
  210. }
  211. // 构建卖方向持仓汇总
  212. if v.Tradeproperty != 2 && v.Sellcurpositionqty > 0 {
  213. var tradePosition QueryTradePositionRsp
  214. // 反射数据
  215. // struct -> json
  216. if jsonBytes, err := json.Marshal(v); err == nil {
  217. c := QtyCovert{QTYDECIMALPLACE: v.QTYDECIMALPLACE}
  218. // json -> struct
  219. _ = json.Unmarshal(jsonBytes, &tradePosition)
  220. tradePosition.Tradeproperty = v.Tradeproperty
  221. tradePosition.BuyOrSell = 1
  222. tradePosition.PositionQTY = c.CovertQty(v.Sellpositionqty)
  223. tradePosition.HolderAmount = v.Sellholderamount
  224. tradePosition.CurPositionQTY = c.CovertQty(v.Sellcurpositionqty)
  225. tradePosition.CurHolderAmount = v.Sellcurholderamount
  226. tradePosition.FrozenQTY = c.CovertQty(v.Sellfrozenqty)
  227. tradePosition.OtherFrozenQTY = c.CovertQty(v.Sellotherfrozenqty)
  228. tradePosition.OpenReqQTY = c.CovertQty(v.Sellopenreqqty)
  229. tradePosition.OpenTotalQTY = c.CovertQty(v.Sellopentotalqty)
  230. tradePosition.CloseTotalQTY = c.CovertQty(v.Sellclosetotalqty)
  231. tradePosition.TNQTY = c.CovertQty(v.Selltnqty)
  232. tradePosition.TNUsedQTY = c.CovertQty(v.Selltnusedqty)
  233. tradePosition.CurTDPosition = c.CovertQty(v.Sellcurtdposition)
  234. tradePosition.FreTDPosition = c.CovertQty(v.Sellfretdposition)
  235. tradePosition.EnableQTY = c.CovertQty(v.Sellcurpositionqty - v.Sellfrozenqty - v.Sellotherfrozenqty)
  236. // 计算持仓均价
  237. averagePrice := tradePosition.CurHolderAmount / float64(tradePosition.CurPositionQTY) / tradePosition.AgreeUnit
  238. //tradePosition.AveragePrice, _ = strconv.ParseFloat(utils.FormatFloat(averagePrice, int(v.Decimalplace)), 64)
  239. // #96004 改为固定3位小数
  240. tradePosition.AveragePrice, _ = decimal.NewFromFloat(averagePrice).Round(3).Float64()
  241. tradePosition.PositionPL, tradePosition.MarketAmount, tradePosition.LastPrice = fCalcPL(tradePosition.GoodsCode, tradePosition.BuyOrSell, tradePosition.CurPositionQTY,
  242. tradePosition.AveragePrice, tradePosition.AgreeUnit, tradePosition.DecimalPlace)
  243. if tradePosition.CurHolderAmount > 1e-10 {
  244. tradePosition.PositionPLRate = tradePosition.PositionPL / tradePosition.CurHolderAmount
  245. tradePosition.PositionPLRate, _ = strconv.ParseFloat(utils.FormatFloat(tradePosition.PositionPLRate, 4), 64)
  246. }
  247. rst = append(rst, tradePosition)
  248. }
  249. }
  250. }
  251. // 查询成功
  252. logger.GetLogger().Debugln("QueryTradePosition successed: %v", rst)
  253. return rst, true
  254. }
  255. // QueryTradeOrderDetailReq 委托单查询请求参数(合约市场)
  256. type QueryTradeOrderDetailReq struct {
  257. AccountID string `form:"accountID" binding:"required"`
  258. OrderStatus string `form:"orderStatus"`
  259. TradeMode string `form:"tradeMode"`
  260. OrderID int `form:"orderID"`
  261. }
  262. // QueryTradeOrderDetailRsp 委托单查询返回模型(合约市场)
  263. type QueryTradeOrderDetailRsp struct {
  264. Orderid string `json:"orderid" xorm:"'ORDERID'"` // 委托单号(100+Unix秒时间戳(10位)+2位(MarketServiceID)+xxxx)
  265. Tradedate string `json:"tradedate" xorm:"'TRADEDATE'" binding:"required"` // 交易日(yyyyMMdd)
  266. Buildtype int64 `json:"buildtype" xorm:"'BUILDTYPE'" binding:"required"` // 委托单据类型 - 1:建仓 2:平仓 3:先平后建
  267. Preorderid string `json:"preorderid" xorm:"'PREORDERID'"` // 关联预埋单号(止盈止损单时填写)
  268. Cancelorderid string `json:"cancelorderid" xorm:"'CANCELORDERID'"` // 撤单单号(撤单时填写)
  269. Relatedid string `json:"relatedid" xorm:"'RELATEDID'"` // 关联单号(交割单)
  270. Marketid int64 `json:"marketid" xorm:"'MARKETID'" binding:"required"` // 市场ID
  271. Goodsid int64 `json:"goodsid" xorm:"'GOODSID'" binding:"required"` // 商品ID
  272. Accountid int64 `json:"accountid" xorm:"'ACCOUNTID'" binding:"required"` // 账户ID[报价币种]
  273. Buyorsell int64 `json:"buyorsell" xorm:"'BUYORSELL'" binding:"required"` // 买卖 - 0:买 1:卖
  274. Pricemode int64 `json:"pricemode" xorm:"'PRICEMODE'" binding:"required"` // 取价方式 - 1:市价 2: 限价
  275. Orderprice float64 `json:"orderprice" xorm:"'ORDERPRICE'"` // 委托价格
  276. Orderqty float64 `json:"orderqty" xorm:"'ORDERQTY'" binding:"required"` // 委托数量
  277. Tradeqty float64 `json:"tradeqty" xorm:"'TRADEQTY'"` // 成交数量
  278. Cancelqty float64 `json:"cancelqty" xorm:"'CANCELQTY'"` // 撤单数量
  279. Openqty float64 `json:"openqty" xorm:"'OPENQTY'"` // 开仓数量(先建后平操作,需要记录)
  280. Closeqty float64 `json:"closeqty" xorm:"'CLOSEQTY'"` // 平仓数量(先建后平操作 需要记录)
  281. Opentradeqty float64 `json:"opentradeqty" xorm:"'OPENTRADEQTY'"` // 开仓成交数量(先建后平操作,需要记录)
  282. Closetradeqty float64 `json:"closetradeqty" xorm:"'CLOSETRADEQTY'"` // 平仓成交数量(先建后平操作,需要记录)
  283. Freezemargin float64 `json:"freezemargin" xorm:"'FREEZEMARGIN'"` // 冻结保证金(冻结交易金额)
  284. Unfreezemargin float64 `json:"unfreezemargin" xorm:"'UNFREEZEMARGIN'"` // 解冻保证金
  285. Freezecharge float64 `json:"freezecharge" xorm:"'FREEZECHARGE'"` // 冻结手续费
  286. Unfreezecharge float64 `json:"unfreezecharge" xorm:"'UNFREEZECHARGE'"` // 解冻手续费
  287. Openfreezecharge float64 `json:"openfreezecharge" xorm:"'OPENFREEZECHARGE'"` // 开仓冻结手续费(先建后平操作,需要记录)
  288. Closefreezecharge float64 `json:"closefreezecharge" xorm:"'CLOSEFREEZECHARGE'"` // 平仓冻结手续费(先建后平操作,需要记录)
  289. Openunfreezecharge float64 `json:"openunfreezecharge" xorm:"'OPENUNFREEZECHARGE'"` // 开仓解冻手续费(先建后平操作,需要记录)
  290. Closeunfreezecharge float64 `json:"closeunfreezecharge" xorm:"'CLOSEUNFREEZECHARGE'"` // 平仓解冻手续费(先建后平操作,需要记录)
  291. Validtype int64 `json:"validtype" xorm:"'VALIDTYPE'" binding:"required"` // 有效类型 - 1当日有效 2本周有效 3指定日期有效 4一直有效 5指定时间有效
  292. Validtime time.Time `json:"validtime" xorm:"'VALIDTIME'"` // 有效期限
  293. Volumetype int64 `json:"volumetype" xorm:"'VOLUMETYPE'"` // 当时间有效类型为 “立即执行否则取消 IOC” 时,需要此项 - 0:任意量 1:最小量(暂时不支持) 2:全部量
  294. Operatetype int64 `json:"operatetype" xorm:"'OPERATETYPE'" binding:"required"` // 操作类型 - 1:正常下单 2:斩仓 3:转单 4:结算撤单 5:系统卖出(适用于先平后建的卖出) 6:行情源报价 7:(结算)到期强平 8:(结算)协议转让 9:系统对冲单 10:(结算)到期无效 11:交割协议转让 12:交割协议平仓 13:交割成交(所有权) 14:管理端强行平仓 15:管理端协议转让
  295. Ordertime time.Time `json:"ordertime" xorm:"'ORDERTIME'" binding:"required"` // 委托时间
  296. Orderstatus int64 `json:"orderstatus" xorm:"'ORDERSTATUS'"` // 委托状态 - 1: 委托请求 2:待冻结 3:委托成功 4: 委托失败 5:配对成功 6: 已撤销 7:部分成交 8:已成交 9:部成部撤 10:成交失败 11:已拒绝 12:经过摘牌(先摘后挂专用-先摘后挂已摘过) 13:冻结成功(通道交易专用) 14:通道已撤 15:通道部成部撤 16:成交失败违约(荷兰式竞拍专用)
  297. Listingselecttype int64 `json:"listingselecttype" xorm:"'LISTINGSELECTTYPE'"` // 挂牌点选类型 - 1:挂牌 2:摘牌 3:先摘后挂
  298. Delistingtype int64 `json:"delistingtype" xorm:"'DELISTINGTYPE'"` // 摘牌类型 - 1:价格最优 2:点选成交
  299. Ordersrc int64 `json:"ordersrc" xorm:"'ORDERSRC'"` // 委托来源 - 1:客户端 2:管理端 3:风控服务 4:交割服务 5:交易服务 6:交易日结 7:商品强平 8:管理端商品退市强平 9:交易接口 10:交割服务商被动(受托竞价) 11:预埋触发
  300. Clienttype int64 `json:"clienttype" xorm:"'CLIENTTYPE'"` // 客户端类型 - 0:保留为未填终端类型 1:PC管理端 2:PC交易端 3:手机客户端_安卓 4:网页客户端 5:微信客户端 6:手机客户端_苹果 7:网上开户客户端 8:无效终端编号 9:报价终端(中江)
  301. Operatorid int64 `json:"operatorid" xorm:"'OPERATORID'"` // 登录账号(LoginID)
  302. GOODUNITID int32 `json:"goodunitid" xorm:"'GOODUNITID'"` // 商品单位id
  303. GoodsCode string `json:"goodscode" xorm:"GOODSCODE"` // 商品代码
  304. GoodsName string `json:"goodsname" xorm:"GOODSNAME"` // 商品名称
  305. DECIMALPLACE int32 `json:"decimalplace" xorm:"'DECIMALPLACE'"` // 商品报价小数位
  306. QTYDECIMALPLACE int `json:"qtydecimalplace" xorm:"'QTYDECIMALPLACE'"` // 商品报价小数位
  307. Marketname string `json:"marketname" xorm:"'MARKETNAME'"` // 市场名称
  308. TradeMode int32 `json:"trademode" xorm:"'TRADEMODE'"` // 交易模式
  309. ENUMDICNAME string `json:"enumdicname"` // 单位名称
  310. Enableqty float64 `json:"enableqty" xorm:"ENABLEQTY"` // 可用数量 = 委托数量 - 成交数量 - 撤单数量
  311. }
  312. func (r *QueryTradeOrderDetailRsp) calc() {
  313. fCovert := func(v *float64) {
  314. *v = *v / math.Pow10(r.QTYDECIMALPLACE)
  315. }
  316. fCovert(&r.Orderqty)
  317. fCovert(&r.Tradeqty)
  318. fCovert(&r.Cancelqty)
  319. fCovert(&r.Openqty)
  320. fCovert(&r.Closeqty)
  321. fCovert(&r.Opentradeqty)
  322. fCovert(&r.Closetradeqty)
  323. fCovert(&r.Enableqty)
  324. r.ENUMDICNAME = mtpcache.GetEnumDicitemName(r.GOODUNITID)
  325. }
  326. // QueryTradeOrderDetail 委托单查询请求(合约市场)
  327. // @Summary 委托单查询请求(合约市场)
  328. // @Produce json
  329. // @Security ApiKeyAuth
  330. // @Param accountID query string true "资金账户 - 格式:1,2,3"
  331. // @Param tradeMode query string false "交易模式 - 格式:1,2,3"
  332. // @Param orderStatus query string false "委托状态 - 格式:1,2,3"
  333. // @Param orderID query int false "委托单号"
  334. // @Success 200 {object} QueryTradeOrderDetailRsp
  335. // @Failure 500 {object} app.Response
  336. // @Router /Order/QueryTradeOrderDetail [get]
  337. // @Tags 通用单据
  338. // 参考通用查询:SearchTradeOrderDetail
  339. func QueryTradeOrderDetail(c *gin.Context) {
  340. appG := app.Gin{C: c}
  341. // 获取请求参数
  342. var req QueryTradeOrderDetailReq
  343. if err := appG.C.ShouldBindQuery(&req); err != nil {
  344. logger.GetLogger().Errorf("QueryTradeOrderDetail failed: %s", err.Error())
  345. appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
  346. return
  347. }
  348. datas := make([]QueryTradeOrderDetailRsp, 0)
  349. engine := db.GetEngine()
  350. // 由于int64类型数据(单号)过长是获取会有问题(可能是oci8组件问题),所以这里将可能会出问题的单号都用to_char来输出
  351. s := engine.Table("TRADE_ORDERDETAIL").
  352. Join("LEFT", "GOODS", "GOODS.GOODSID = TRADE_ORDERDETAIL.GOODSID").
  353. Join("LEFT", "MARKET", "MARKET.MARKETID = TRADE_ORDERDETAIL.MARKETID").
  354. 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,
  355. TRADE_ORDERDETAIL.*, TRADE_ORDERDETAIL.ORDERQTY - TRADE_ORDERDETAIL.TRADEQTY - TRADE_ORDERDETAIL.CANCELQTY as ENABLEQTY,
  356. GOODS.GOODSCODE, GOODS.GOODSNAME,GOODS.DECIMALPLACE, GOODS.QTYDECIMALPLACE,GOODS.GOODUNITID, MARKET.MARKETNAME, MARKET.TRADEMODE`).
  357. Where(fmt.Sprintf(`TRADE_ORDERDETAIL.ORDERSRC != 10 and TRADE_ORDERDETAIL.ACCOUNTID in (%s)`, req.AccountID)).
  358. Desc("TRADE_ORDERDETAIL.ORDERTIME")
  359. if len(req.OrderStatus) > 0 {
  360. s = s.And(fmt.Sprintf(`TRADE_ORDERDETAIL.ORDERSTATUS in (%s)`, req.OrderStatus))
  361. }
  362. if len(req.TradeMode) > 0 {
  363. s = s.And(fmt.Sprintf(`MARKET.TRADEMODE in (%s)`, req.TradeMode))
  364. }
  365. if req.OrderID > 0 {
  366. s = s.And("TRADE_ORDERDETAIL.ORDERID = ?", req.OrderID)
  367. }
  368. if err := s.Find(&datas); err != nil {
  369. // 查询失败
  370. logger.GetLogger().Errorf("QueryTradeOrderDetail failed: %s", err.Error())
  371. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  372. return
  373. }
  374. // 查询成功
  375. logger.GetLogger().Debugln("QueryTradeOrderDetail successed: %v", datas)
  376. for i := range datas {
  377. datas[i].calc()
  378. }
  379. appG.Response(http.StatusOK, e.SUCCESS, datas)
  380. }
  381. // QueryHisTradeOrderDetailReq 历史委托单查询请求参数(合约市场)
  382. type QueryHisTradeOrderDetailReq struct {
  383. AccountID string `form:"accountID" binding:"required"` // 资金账户 - 格式:1,2,3
  384. OrderStatus string `form:"orderStatus"` // 委托状态 - 格式:1,2,3
  385. TradeMode string `form:"tradeMode"` // 交易模式 - 格式:1,2,3
  386. OrderID int `form:"orderID"` // 委托单号
  387. StartDate string `form:"startDate"` // 开始时间
  388. EndDate string `form:"endDate"` // 结束时间
  389. }
  390. // QueryHisTradeOrderDetailRsp 历史委托单查询返回模型(合约市场)
  391. type QueryHisTradeOrderDetailRsp struct {
  392. models.Histradeorderdetail `xorm:"extends"`
  393. GoodsCode string `json:"goodscode" xorm:"GOODSCODE"` // 商品代码
  394. GoodsName string `json:"goodsname" xorm:"GOODSNAME"` // 商品名称
  395. DECIMALPLACE int32 `json:"decimalplace" xorm:"'DECIMALPLACE'"` // 商品报价小数位
  396. QTYDECIMALPLACE int `json:"qtydecimalplace" xorm:"'QTYDECIMALPLACE'"` // 成交量小数位
  397. GOODUNITID int32 `json:"goodunitid" xorm:"'GOODUNITID'"` // 商品单位id
  398. Marketname string `json:"marketname" xorm:"'MARKETNAME'"` // 市场名称
  399. TradeMode int32 `json:"trademode" xorm:"'TRADEMODE'"` // 交易模式
  400. ENUMDICNAME string `json:"enumdicname"` // 单位名称
  401. }
  402. func (r *QueryHisTradeOrderDetailRsp) calc() {
  403. fCovert := func(v *float64) {
  404. *v = *v / math.Pow10(r.QTYDECIMALPLACE)
  405. }
  406. fCovert(&r.Orderqty)
  407. fCovert(&r.Tradeqty)
  408. fCovert(&r.Cancelqty)
  409. fCovert(&r.Openqty)
  410. fCovert(&r.Closeqty)
  411. fCovert(&r.Opentradeqty)
  412. fCovert(&r.Closetradeqty)
  413. r.ENUMDICNAME = mtpcache.GetEnumDicitemName(r.GOODUNITID)
  414. }
  415. // QueryHisTradeOrderDetail 历史委托单查询请求(合约市场)
  416. // @Summary 历史委托单查询请求(合约市场)
  417. // @Produce json
  418. // @Security ApiKeyAuth
  419. // @Param accountID query string true "资金账户 - 格式:1,2,3"
  420. // @Param tradeMode query string false "交易模式 - 格式:1,2,3"
  421. // @Param orderStatus query string false "委托状态 - 格式:1,2,3"
  422. // @Param orderID query int false "委托单号"
  423. // @Param startDate query string false "开始时间 - 闭区间,格式:yyyy-MM-dd"
  424. // @Param endDate query string false "结束时间 - 闭区间,格式:yyyy-MM-dd"
  425. // @Success 200 {object} QueryHisTradeOrderDetailRsp
  426. // @Failure 500 {object} app.Response
  427. // @Router /Order/QueryHisTradeOrderDetail [get]
  428. // @Tags 通用单据
  429. // 参考通用查询:Client_QueryHis_trade_orderdetail
  430. func QueryHisTradeOrderDetail(c *gin.Context) {
  431. appG := app.Gin{C: c}
  432. // 获取请求参数
  433. var req QueryHisTradeOrderDetailReq
  434. if err := appG.C.ShouldBindQuery(&req); err != nil {
  435. logger.GetLogger().Errorf("QueryHisTradeOrderDetail failed: %s", err.Error())
  436. appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
  437. return
  438. }
  439. datas := make([]QueryHisTradeOrderDetailRsp, 0)
  440. engine := db.GetEngine()
  441. s := engine.Table("HIS_TRADE_ORDERDETAIL").
  442. Join("LEFT", "GOODS", "GOODS.GOODSID = HIS_TRADE_ORDERDETAIL.GOODSID").
  443. Join("LEFT", "MARKET", "MARKET.MARKETID = HIS_TRADE_ORDERDETAIL.MARKETID").
  444. 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,
  445. HIS_TRADE_ORDERDETAIL.*,
  446. GOODS.GOODSCODE, GOODS.GOODSNAME,GOODS.DECIMALPLACE, GOODS.QTYDECIMALPLACE,GOODS.GOODUNITID, MARKET.MARKETNAME, MARKET.TRADEMODE`).
  447. Where(fmt.Sprintf(`HIS_TRADE_ORDERDETAIL.ORDERSRC != 10 and HIS_TRADE_ORDERDETAIL.ISVALIDDATA = 1 and HIS_TRADE_ORDERDETAIL.ACCOUNTID in (%s)`, req.AccountID)).
  448. Desc("HIS_TRADE_ORDERDETAIL.ORDERTIME")
  449. if len(req.OrderStatus) > 0 {
  450. s = s.And(fmt.Sprintf(`HIS_TRADE_ORDERDETAIL.ORDERSTATUS in (%s)`, req.OrderStatus))
  451. }
  452. if len(req.TradeMode) > 0 {
  453. s = s.And(fmt.Sprintf(`MARKET.TRADEMODE in (%s)`, req.TradeMode))
  454. }
  455. if req.OrderID > 0 {
  456. s = s.And("HIS_TRADE_ORDERDETAIL.ORDERID = ?", req.OrderID)
  457. }
  458. if len(req.StartDate) > 0 {
  459. s = s.And(fmt.Sprintf("to_date(HIS_TRADE_ORDERDETAIL.HISTRADEDATE,'yyyyMMdd') >= to_date('%s','yyyy-MM-dd')", req.StartDate))
  460. }
  461. if len(req.EndDate) > 0 {
  462. s = s.And(fmt.Sprintf("to_date(HIS_TRADE_ORDERDETAIL.HISTRADEDATE,'yyyyMMdd') <= to_date('%s','yyyy-MM-dd')", req.EndDate))
  463. }
  464. if err := s.Find(&datas); err != nil {
  465. // 查询失败
  466. logger.GetLogger().Errorf("QueryHisTradeOrderDetail failed: %s", err.Error())
  467. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  468. return
  469. }
  470. // 查询成功
  471. logger.GetLogger().Debugln("QueryHisTradeOrderDetail successed: %v", datas)
  472. for i := range datas {
  473. datas[i].calc()
  474. }
  475. appG.Response(http.StatusOK, e.SUCCESS, datas)
  476. }
  477. // QueryTradeDetailReq 成交单查询请求参数
  478. type QueryTradeDetailReq struct {
  479. AccountID string `form:"accountID" binding:"required"`
  480. TradeID int `form:"tradeID"`
  481. OrderID int `form:"orderID"`
  482. TradeMode string `form:"tradeMode"`
  483. BuildType int `form:"buildType"`
  484. TradeType string `form:"tradeType"`
  485. GoodsID int `form:"goodsID"`
  486. }
  487. // QueryTradeDetailRsp 成交单查询返回模型
  488. type QueryTradeDetailRsp struct {
  489. models.Tradetradedetail `xorm:"extends"`
  490. TradePayInfo `xorm:"extends"`
  491. GoodsCode string `json:"goodscode" xorm:"GOODSCODE"` // 商品代码
  492. GoodsName string `json:"goodsname" xorm:"GOODSNAME"` // 商品名称
  493. DECIMALPLACE int32 `json:"decimalplace" xorm:"'DECIMALPLACE'"` // 商品报价小数位
  494. QTYDECIMALPLACE int `json:"qtydecimalplace" xorm:"'QTYDECIMALPLACE'"` // 商品报价小数位
  495. GOODUNITID int32 `json:"goodunitid" xorm:"'GOODUNITID'"` // 商品单位id
  496. Marketname string `json:"marketname" xorm:"'MARKETNAME'"` // 市场名称
  497. TradeMode int32 `json:"trademode" xorm:"'TRADEMODE'"` // 交易模式
  498. ListingSelectType int32 `json:"listingselecttype" xorm:"'LISTINGSELECTTYPE'"` // 关联委托单挂牌点选类型 - 1:挂牌 2:摘牌 3:先摘后挂
  499. Charge float64 `json:"charge" xorm:"CHARGE"` // 手续费
  500. ENUMDICNAME string `json:"enumdicname"` // 单位名称
  501. }
  502. func (r *QueryTradeDetailRsp) calc() {
  503. fCovert := func(v *float64) {
  504. *v = *v / math.Pow10(r.QTYDECIMALPLACE)
  505. }
  506. fCovert(&r.Tradeqty)
  507. fCovert(&r.Openqty)
  508. fCovert(&r.Closeqty)
  509. r.ENUMDICNAME = mtpcache.GetEnumDicitemName(r.GOODUNITID)
  510. r.TOTALAMOUNT = r.Tradeamount + r.Opencharge + r.Closecharge
  511. r.RECVAMOUNT = r.Tradeamount - r.Opencharge - r.Closecharge
  512. }
  513. // QueryTradeDetail 成交单查询(合约市场)
  514. // @Summary 成交单查询(合约市场)
  515. // @Produce json
  516. // @Security ApiKeyAuth
  517. // @Param accountID query string true "资金账户 - 格式:1,2,3"
  518. // @Param tradeID query int false "成交单号"
  519. // @Param orderID query int false "委托单号"
  520. // @Param tradeMode query string false "交易模式 - 格式:1,2,3"
  521. // @Param buildType query int false "委托单据类型"
  522. // @Param tradeType query string false "成交类别 - 格式:1,2,3"
  523. // @Param goodsID query int false "商品ID"
  524. // @Success 200 {object} QueryTradeDetailRsp
  525. // @Failure 500 {object} app.Response
  526. // @Router /Order/QueryTradeDetail [get]
  527. // @Tags 通用单据
  528. // 参考通用查询:SearchAllTransactionDetailOrder
  529. func QueryTradeDetail(c *gin.Context) {
  530. appG := app.Gin{C: c}
  531. // 获取请求参数
  532. var req QueryTradeDetailReq
  533. if err := appG.C.ShouldBindQuery(&req); err != nil {
  534. logger.GetLogger().Errorf("QueryTradeDetail failed: %s", err.Error())
  535. appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
  536. return
  537. }
  538. datas := make([]QueryTradeDetailRsp, 0)
  539. engine := db.GetEngine()
  540. s := engine.Table("TRADE_TRADEDETAIL").
  541. Join("LEFT", "GOODS", "GOODS.GOODSID = TRADE_TRADEDETAIL.GOODSID").
  542. Join("LEFT", "MARKET", "MARKET.MARKETID = TRADE_TRADEDETAIL.MARKETID").
  543. Join("LEFT", "TRADE_ORDERDETAIL", "TRADE_ORDERDETAIL.ORDERID = TRADE_TRADEDETAIL.ORDERID").
  544. Join("LEFT", "TRADE_PAYORDER", "TRADE_PAYORDER.TRADEID = TRADE_TRADEDETAIL.TRADEID").
  545. Select(`to_char(TRADE_TRADEDETAIL.TRADEID) as TRADEID, to_char(TRADE_TRADEDETAIL.ORDERID) as ORDERID,
  546. TRADE_TRADEDETAIL.*, CASE TRADE_TRADEDETAIL.BUILDTYPE WHEN 1 THEN TRADE_TRADEDETAIL.OPENCHARGE ELSE TRADE_TRADEDETAIL.CLOSECHARGE END as CHARGE,
  547. GOODS.GOODSCODE, GOODS.GOODSNAME, GOODS.DECIMALPLACE, GOODS.QTYDECIMALPLACE,GOODS.GOODUNITID, MARKET.MARKETNAME, MARKET.TRADEMODE,
  548. TRADE_ORDERDETAIL.LISTINGSELECTTYPE, TRADE_PAYORDER.ADVANCERATIO, TRADE_PAYORDER.PAYAMOUNT, TRADE_PAYORDER.TRADECHARGE`).
  549. Where(fmt.Sprintf("TRADE_TRADEDETAIL.ACCOUNTID in (%s)", req.AccountID)).
  550. Desc("TRADE_TRADEDETAIL.TRADETIME")
  551. if req.TradeID > 0 {
  552. s = s.And("TRADE_TRADEDETAIL.TRADEID = ?", req.TradeID)
  553. }
  554. if req.OrderID > 0 {
  555. s = s.And("TRADE_TRADEDETAIL.ORDERID = ?", req.OrderID)
  556. }
  557. if req.GoodsID > 0 {
  558. s = s.And("TRADE_TRADEDETAIL.GOODSID = ?", req.GoodsID)
  559. }
  560. if len(req.TradeMode) > 0 {
  561. s = s.And(fmt.Sprintf("MARKET.TRADEMODE in (%s)", req.TradeMode))
  562. }
  563. if req.BuildType > 0 {
  564. s = s.And("TRADE_TRADEDETAIL.BUILDTYPE = ?", req.BuildType)
  565. }
  566. if len(req.TradeType) > 0 {
  567. s = s.And(fmt.Sprintf("TRADE_TRADEDETAIL.TRADETYPE in (%s)", req.TradeType))
  568. }
  569. if err := s.Find(&datas); err != nil {
  570. // 查询失败
  571. logger.GetLogger().Errorf("QueryTradeDetail failed: %s", err.Error())
  572. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  573. return
  574. }
  575. // 查询成功
  576. logger.GetLogger().Debugln("QueryTradeDetail successed: %v", datas)
  577. for i := range datas {
  578. datas[i].calc()
  579. }
  580. appG.Response(http.StatusOK, e.SUCCESS, datas)
  581. }
  582. // QueryHisTradeDetailReq 历史成交单查询请求参数
  583. type QueryHisTradeDetailReq struct {
  584. AccountID string `form:"accountID" binding:"required"`
  585. TradeID int `form:"tradeID"`
  586. OrderID int `form:"orderID"`
  587. GoodsID int `form:"goodsID"`
  588. TradeMode string `form:"tradeMode"`
  589. BuildType int `form:"buildType"`
  590. TradeType string `form:"tradeType"`
  591. StartDate string `form:"startDate"` // 开始时间
  592. EndDate string `form:"endDate"` // 结束时间
  593. }
  594. // QueryHisTradeDetailRsp 历史成交单查询返回模型
  595. type QueryHisTradeDetailRsp struct {
  596. models.Histradetradedetail `xorm:"extends"`
  597. TradePayInfo `xorm:"extends"`
  598. GoodsCode string `json:"goodscode" xorm:"GOODSCODE"` // 商品代码
  599. GoodsName string `json:"goodsname" xorm:"GOODSNAME"` // 商品名称
  600. DECIMALPLACE int32 `json:"decimalplace" xorm:"'DECIMALPLACE'"` // 商品报价小数位
  601. QTYDECIMALPLACE int `json:"qtydecimalplace" xorm:"'QTYDECIMALPLACE'"` // 商品报价小数位
  602. GOODUNITID int32 `json:"goodunitid" xorm:"'GOODUNITID'"` // 商品单位id
  603. Marketname string `json:"marketname" xorm:"'MARKETNAME'"` // 市场名称
  604. TradeMode int32 `json:"trademode" xorm:"'TRADEMODE'"` // 交易模式
  605. ListingSelectType int32 `json:"listingselecttype" xorm:"'LISTINGSELECTTYPE'"` // 关联委托单挂牌点选类型 - 1:挂牌 2:摘牌 3:先摘后挂
  606. Charge float64 `json:"charge" xorm:"CHARGE"` // 手续费
  607. ENUMDICNAME string `json:"enumdicname"` // 单位名称
  608. }
  609. func (r *QueryHisTradeDetailRsp) calc() {
  610. fCovert := func(v *float64) {
  611. *v = *v / math.Pow10(r.QTYDECIMALPLACE)
  612. }
  613. fCovert(&r.Tradeqty)
  614. fCovert(&r.Openqty)
  615. fCovert(&r.Closeqty)
  616. r.ENUMDICNAME = mtpcache.GetEnumDicitemName(r.GOODUNITID)
  617. r.TOTALAMOUNT = r.Tradeamount + r.Opencharge + r.Closecharge
  618. r.RECVAMOUNT = r.Tradeamount - r.Opencharge - r.Closecharge
  619. }
  620. // QueryHisTradeDetail 历史成交单查询(合约市场)
  621. // @Summary 历史成交单查询(合约市场)
  622. // @Produce json
  623. // @Security ApiKeyAuth
  624. // @Param accountID query string true "资金账户 - 格式:1,2,3"
  625. // @Param tradeID query int false "成交单号"
  626. // @Param orderID query int false "委托单号"
  627. // @Param goodsID query int false "商品ID"
  628. // @Param tradeMode query string false "交易模式 - 格式:1,2,3"
  629. // @Param buildType query int false "委托单据类型"
  630. // @Param tradeType query string false "成交类别 - 格式:1,2,3"
  631. // @Param startDate query string false "开始时间 - 闭区间,格式:yyyy-MM-dd"
  632. // @Param endDate query string false "结束时间 - 闭区间,格式:yyyy-MM-dd"
  633. // @Success 200 {object} QueryHisTradeDetailRsp
  634. // @Failure 500 {object} app.Response
  635. // @Router /Order/QueryHisTradeDetail [get]
  636. // @Tags 通用单据
  637. // 参考通用查询:Client_QueryHis_trade_transactiondetail
  638. func QueryHisTradeDetail(c *gin.Context) {
  639. appG := app.Gin{C: c}
  640. // 获取请求参数
  641. var req QueryHisTradeDetailReq
  642. if err := appG.C.ShouldBindQuery(&req); err != nil {
  643. logger.GetLogger().Errorf("QueryHisTradeDetail failed: %s", err.Error())
  644. appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
  645. return
  646. }
  647. datas := make([]QueryHisTradeDetailRsp, 0)
  648. engine := db.GetEngine()
  649. s := engine.Table("HIS_TRADE_TRADEDETAIL").
  650. Join("LEFT", "GOODS", "GOODS.GOODSID = HIS_TRADE_TRADEDETAIL.GOODSID").
  651. Join("LEFT", "MARKET", "MARKET.MARKETID = HIS_TRADE_TRADEDETAIL.MARKETID").
  652. Join("LEFT", "HIS_TRADE_ORDERDETAIL", "HIS_TRADE_ORDERDETAIL.ORDERID = HIS_TRADE_TRADEDETAIL.ORDERID").
  653. Join("LEFT", "TRADE_PAYORDER", "TRADE_PAYORDER.TRADEID = HIS_TRADE_TRADEDETAIL.TRADEID").
  654. Select(`to_char(HIS_TRADE_TRADEDETAIL.TRADEID) as TRADEID, to_char(HIS_TRADE_TRADEDETAIL.ORDERID) as ORDERID,
  655. HIS_TRADE_TRADEDETAIL.*, CASE HIS_TRADE_TRADEDETAIL.BUILDTYPE WHEN 1 THEN HIS_TRADE_TRADEDETAIL.OPENCHARGE ELSE HIS_TRADE_TRADEDETAIL.CLOSECHARGE END as CHARGE,
  656. GOODS.GOODSCODE, GOODS.GOODSNAME,GOODS.DECIMALPLACE, GOODS.QTYDECIMALPLACE, GOODS.GOODUNITID, MARKET.MARKETNAME, MARKET.TRADEMODE,
  657. HIS_TRADE_ORDERDETAIL.LISTINGSELECTTYPE, TRADE_PAYORDER.ADVANCERATIO, TRADE_PAYORDER.PAYAMOUNT, TRADE_PAYORDER.TRADECHARGE`).
  658. Where(fmt.Sprintf("HIS_TRADE_TRADEDETAIL.ISVALIDDATA = 1 and HIS_TRADE_TRADEDETAIL.ACCOUNTID in (%s)", req.AccountID)).
  659. Desc("HIS_TRADE_TRADEDETAIL.TRADETIME")
  660. if req.TradeID > 0 {
  661. s = s.And("HIS_TRADE_TRADEDETAIL.TRADEID = ?", req.TradeID)
  662. }
  663. if req.OrderID > 0 {
  664. s = s.And("HIS_TRADE_TRADEDETAIL.ORDERID = ?", req.OrderID)
  665. }
  666. if req.GoodsID > 0 {
  667. s = s.And("HIS_TRADE_TRADEDETAIL.GOODSID = ?", req.GoodsID)
  668. }
  669. if len(req.TradeMode) > 0 {
  670. s = s.And(fmt.Sprintf("MARKET.TRADEMODE in (%s)", req.TradeMode))
  671. }
  672. if req.BuildType > 0 {
  673. s = s.And("HIS_TRADE_TRADEDETAIL.BUILDTYPE = ?", req.BuildType)
  674. }
  675. if len(req.TradeType) > 0 {
  676. s = s.And(fmt.Sprintf("HIS_TRADE_TRADEDETAIL.TRADETYPE in (%s)", req.TradeType))
  677. }
  678. if len(req.StartDate) > 0 {
  679. s = s.And(fmt.Sprintf("to_date(HIS_TRADE_TRADEDETAIL.HISTRADEDATE,'yyyyMMdd') >= to_date('%s','yyyy-MM-dd')", req.StartDate))
  680. }
  681. if len(req.EndDate) > 0 {
  682. s = s.And(fmt.Sprintf("to_date(HIS_TRADE_TRADEDETAIL.HISTRADEDATE,'yyyyMMdd') <= to_date('%s','yyyy-MM-dd')", req.EndDate))
  683. }
  684. if err := s.Find(&datas); err != nil {
  685. // 查询失败
  686. logger.GetLogger().Errorf("QueryHisTradeDetail failed: %s", err.Error())
  687. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  688. return
  689. }
  690. // 查询成功
  691. logger.GetLogger().Debugln("QueryHisTradeDetail successed: %v", datas)
  692. for i := range datas {
  693. datas[i].calc()
  694. }
  695. appG.Response(http.StatusOK, e.SUCCESS, datas)
  696. }