order.go 49 KB

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