qryOrder.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. package ermcp
  2. import (
  3. "mtp2_if/global/app"
  4. "mtp2_if/global/e"
  5. "mtp2_if/logger"
  6. "mtp2_if/models"
  7. "mtp2_if/utils"
  8. "net/http"
  9. "github.com/gin-gonic/gin"
  10. )
  11. // QueryErmcpTradePositionReq 获取企业风管期货持仓头寸信息请求参数
  12. type QueryErmcpTradePositionReq struct {
  13. AccountID int `form:"accountID" binding:"required"`
  14. MarketID int `form:"marketID"`
  15. }
  16. // QueryErmcpTradePositionRsp 获取企业风管期货持仓头寸信息返回模型
  17. type QueryErmcpTradePositionRsp struct {
  18. Goodsname string `json:"goodsname"` // 商品名称
  19. BuyOrSell int64 `json:"buyorsell"` // 方向 - 0:买 1:卖
  20. EnableQTY int64 `json:"enableqty"` // 可用量(总仓可用)
  21. CurPositionQTY int64 `json:"curpositionqty"` // 当前持仓总数量(总仓数量)
  22. Last float64 `json:"last"` // 现价
  23. CurHolderAmount float64 `json:"curholderamount" ` // 当前持仓总金额[商品币种]
  24. PositionPL float64 `json:"positionpl"` // 持仓盈亏
  25. PositionPLRate float64 `json:"positionplrate"` // 持仓盈亏率
  26. CurTDPosition int64 `json:"curtdposition"` // 期末今日头寸(今仓数量)
  27. CurTDPositionEnabled int64 `json:"curtdpositionenabled"` // 今仓可用
  28. AveragePrice float64 `json:"averageprice"` // 持仓均价
  29. UsedMargin float64 `json:"usedmargin"` // 占用保证金[商品币种]
  30. ExExehangeName string `json:"exexchangename"` // 外部交易所名称
  31. Goodsid int64 `json:"goodsid"` // 商品ID(自增ID SEQ_GOODS)
  32. Goodscode string `json:"goodscode"` // 商品代码(内部)
  33. Outgoodscode string `json:"outgoodscode"` // 商品代码(外部)
  34. Agreeunit float64 `json:"agreeunit"` // 合约单位
  35. Decimalplace int64 `json:"decimalplace"` // 报价小数位
  36. Marketid int64 `json:"marketid"` // 所属市场ID
  37. }
  38. // QueryErmcpTradePosition 获取企业风管期货持仓头寸信息
  39. // @Summary 获取企业风管期货持仓头寸信息
  40. // @Produce json
  41. // @Security ApiKeyAuth
  42. // @Param accountID query int true "资金账户ID"
  43. // @Param marketID query int false "所属市场ID"
  44. // @Success 200 {object} QueryErmcpTradePositionRsp
  45. // @Failure 500 {object} app.Response
  46. // @Router /Ermcp/QueryErmcpTradePosition [get]
  47. // @Tags 企业风险管理(app)
  48. func QueryErmcpTradePosition(c *gin.Context) {
  49. appG := app.Gin{C: c}
  50. // 获取请求参数
  51. var req QueryErmcpTradePositionReq
  52. if err := appG.C.ShouldBindQuery(&req); err != nil {
  53. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  54. appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
  55. return
  56. }
  57. rsp := make([]QueryErmcpTradePositionRsp, 0)
  58. // 获取资金账户信息
  59. taAccount, err := models.GetTaAccountByID(req.AccountID)
  60. if err != nil {
  61. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  62. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  63. return
  64. }
  65. if taAccount == nil {
  66. logger.GetLogger().Errorf("QueryErmcpTradePosition failed")
  67. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  68. return
  69. }
  70. // 母账户要从HEDGE_OUTTRADEPOSITION表查询持仓头寸(未生成内部头寸);子账户从TRADEPOSITION表获持仓头寸
  71. if taAccount.Ismain == 1 {
  72. // 母账户
  73. hedgeOutTradePositions, err := models.GetHedgeOutTradePositions(req.AccountID, req.MarketID)
  74. if err != nil {
  75. // 查询失败
  76. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  77. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  78. return
  79. }
  80. // 分解买卖方向的头寸
  81. for _, v := range hedgeOutTradePositions {
  82. // 分解买卖方向的头寸
  83. if v.Curbuyposition > 0 {
  84. // 买方向
  85. item := QueryErmcpTradePositionRsp{
  86. BuyOrSell: 0,
  87. EnableQTY: v.Curbuyposition - v.Fretdbuyposition - v.Freydbuyposition, // 买可用 = 期末买头寸 - 冻结今日买头寸 - 冻结上日买头寸
  88. CurPositionQTY: v.Curbuyposition,
  89. CurHolderAmount: 0, // FIXME: - 缺少数据?
  90. CurTDPosition: v.Curtdbuyposition,
  91. CurTDPositionEnabled: v.Curtdbuyposition - v.Fretdbuyposition, // 今仓买可用 = 期末今日买头寸 - 冻结今日买头寸
  92. UsedMargin: 0, // FIXME: - 缺少数据?
  93. Goodsid: v.Hedgegoodsid,
  94. Marketid: int64(v.Marketid),
  95. }
  96. // 获取对应商品信息
  97. goods, err := models.GetGoods(int(v.Hedgegoodsid))
  98. if err != nil {
  99. // 查询失败
  100. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  101. appG.Response(http.StatusBadRequest, e.ERROR_GET_GOODS_FAILED, nil)
  102. return
  103. }
  104. if goods == nil {
  105. logger.GetLogger().Errorf("QueryErmcpTradePosition failed")
  106. appG.Response(http.StatusBadRequest, e.ERROR_GET_GOODS_FAILED, nil)
  107. return
  108. }
  109. item.Goodscode = goods.Goodscode
  110. item.Outgoodscode = goods.Outgoodscode
  111. item.Goodsname = goods.Goodsname
  112. item.Agreeunit = goods.Agreeunit
  113. // 获取对应外部交易所名称
  114. exchange, err := models.GetExternalexchangeByGoodsGroupID(int(goods.Goodsgroupid))
  115. if err != nil {
  116. // 查询失败
  117. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  118. appG.Response(http.StatusBadRequest, e.ERROR_GET_EXEXCHANGE_FAILED, nil)
  119. return
  120. }
  121. if exchange == nil {
  122. logger.GetLogger().Errorf("QueryErmcpTradePosition failed")
  123. appG.Response(http.StatusBadRequest, e.ERROR_GET_EXEXCHANGE_FAILED, nil)
  124. return
  125. }
  126. item.ExExehangeName = exchange.Exchangefullname
  127. // 获取对应商品盘面信息
  128. quoteDays, err := models.GetQuoteDays("'" + goods.Outgoodscode + "'")
  129. if err != nil {
  130. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  131. appG.Response(http.StatusBadRequest, e.ERROR_GET_QUOTE_FAILED, nil)
  132. return
  133. }
  134. if len(quoteDays) > 0 {
  135. if quoteDays[0].Last != 0 {
  136. item.Last = utils.IntToFloat64(int(quoteDays[0].Last), int(goods.Decimalplace))
  137. }
  138. // 没有现价则尝试用昨结
  139. if item.Last == 0 && quoteDays[0].Presettle != 0 {
  140. item.Last = utils.IntToFloat64(int(quoteDays[0].Presettle), int(goods.Decimalplace))
  141. }
  142. }
  143. // FIXME: - 目前外部持仓头寸表里没有相关金额的字段,等相关服务处理
  144. rsp = append(rsp, item)
  145. }
  146. if v.Cursellposition > 0 {
  147. // 卖方向
  148. item := QueryErmcpTradePositionRsp{
  149. BuyOrSell: 1,
  150. EnableQTY: v.Cursellposition - v.Fretdsellposition - v.Freydsellposition,
  151. CurPositionQTY: v.Cursellposition,
  152. CurHolderAmount: 0, // FIXME: - 缺少数据?
  153. CurTDPosition: v.Curtdsellposition,
  154. CurTDPositionEnabled: v.Curtdsellposition - v.Fretdsellposition,
  155. UsedMargin: 0, // FIXME: - 缺少数据?
  156. Goodsid: v.Hedgegoodsid,
  157. Marketid: int64(v.Marketid),
  158. }
  159. // 获取对应商品信息
  160. goods, err := models.GetGoods(int(v.Hedgegoodsid))
  161. if err != nil {
  162. // 查询失败
  163. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  164. appG.Response(http.StatusBadRequest, e.ERROR_GET_GOODS_FAILED, nil)
  165. return
  166. }
  167. if goods == nil {
  168. logger.GetLogger().Errorf("QueryErmcpTradePosition failed")
  169. appG.Response(http.StatusBadRequest, e.ERROR_GET_GOODS_FAILED, nil)
  170. return
  171. }
  172. item.Goodscode = goods.Goodscode
  173. item.Outgoodscode = goods.Outgoodscode
  174. item.Goodsname = goods.Goodsname
  175. item.Agreeunit = goods.Agreeunit
  176. // 获取对应外部交易所名称
  177. exchange, err := models.GetExternalexchangeByGoodsGroupID(int(goods.Goodsgroupid))
  178. if err != nil {
  179. // 查询失败
  180. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  181. appG.Response(http.StatusBadRequest, e.ERROR_GET_EXEXCHANGE_FAILED, nil)
  182. return
  183. }
  184. if exchange == nil {
  185. logger.GetLogger().Errorf("QueryErmcpTradePosition failed")
  186. appG.Response(http.StatusBadRequest, e.ERROR_GET_EXEXCHANGE_FAILED, nil)
  187. return
  188. }
  189. item.ExExehangeName = exchange.Exchangefullname
  190. // 获取对应商品盘面信息
  191. quoteDays, err := models.GetQuoteDays("'" + goods.Outgoodscode + "'")
  192. if err != nil {
  193. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  194. appG.Response(http.StatusBadRequest, e.ERROR_GET_QUOTE_FAILED, nil)
  195. return
  196. }
  197. if len(quoteDays) > 0 {
  198. if quoteDays[0].Last != 0 {
  199. item.Last = utils.IntToFloat64(int(quoteDays[0].Last), int(goods.Decimalplace))
  200. }
  201. // 没有现价则尝试用昨结
  202. if item.Last == 0 && quoteDays[0].Presettle != 0 {
  203. item.Last = utils.IntToFloat64(int(quoteDays[0].Presettle), int(goods.Decimalplace))
  204. }
  205. }
  206. // FIXME: - 目前外部持仓头寸表里没有相关金额的字段,等相关服务处理
  207. rsp = append(rsp, item)
  208. }
  209. }
  210. } else {
  211. // 子账户
  212. tradePositions, err := models.GetTradePositions(req.AccountID, req.MarketID)
  213. if err != nil {
  214. // 查询失败
  215. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  216. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  217. return
  218. }
  219. // 分解买卖方向的头寸
  220. for _, v := range tradePositions {
  221. if v.Buycurpositionqty > 0 {
  222. // 买方向
  223. item := QueryErmcpTradePositionRsp{
  224. BuyOrSell: 0,
  225. EnableQTY: v.Buycurpositionqty - v.Buyfrozenqty, // 买可用 = 买当前持仓总数量 - 买持仓冻结数量
  226. CurPositionQTY: v.Buycurpositionqty,
  227. CurHolderAmount: v.Buycurholderamount,
  228. CurTDPosition: v.Buycurtdposition,
  229. CurTDPositionEnabled: v.Buycurtdposition - v.Buyfretdposition, // 今仓买可用 = 买期末今日头寸 - 买冻结今日头寸
  230. UsedMargin: v.Usedmargin,
  231. Goodsid: int64(v.Goodsid),
  232. }
  233. // 获取对应市场信息
  234. market, err := models.GetMarketByGoodsID(int(v.Goodsid))
  235. if err != nil {
  236. // 查询失败
  237. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  238. appG.Response(http.StatusBadRequest, e.ERROR_GET_MARKET_FAILED, nil)
  239. return
  240. }
  241. if market == nil {
  242. logger.GetLogger().Errorf("QueryErmcpTradePosition failed")
  243. appG.Response(http.StatusBadRequest, e.ERROR_GET_MARKET_FAILED, nil)
  244. return
  245. }
  246. item.Marketid = int64(market.Marketid)
  247. // 获取对应商品信息
  248. goods, err := models.GetGoods(int(v.Goodsid))
  249. if err != nil {
  250. // 查询失败
  251. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  252. appG.Response(http.StatusBadRequest, e.ERROR_GET_GOODS_FAILED, nil)
  253. return
  254. }
  255. if goods == nil {
  256. logger.GetLogger().Errorf("QueryErmcpTradePosition failed")
  257. appG.Response(http.StatusBadRequest, e.ERROR_GET_GOODS_FAILED, nil)
  258. return
  259. }
  260. item.Goodscode = goods.Goodscode
  261. item.Outgoodscode = goods.Outgoodscode
  262. item.Goodsname = goods.Goodsname
  263. item.Agreeunit = goods.Agreeunit
  264. // 获取对应外部交易所名称
  265. exchange, err := models.GetExternalexchangeByGoodsGroupID(int(goods.Goodsgroupid))
  266. if err != nil {
  267. // 查询失败
  268. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  269. appG.Response(http.StatusBadRequest, e.ERROR_GET_EXEXCHANGE_FAILED, nil)
  270. return
  271. }
  272. if exchange == nil {
  273. logger.GetLogger().Errorf("QueryErmcpTradePosition failed")
  274. appG.Response(http.StatusBadRequest, e.ERROR_GET_EXEXCHANGE_FAILED, nil)
  275. return
  276. }
  277. item.ExExehangeName = exchange.Exchangefullname
  278. // 获取对应商品盘面信息
  279. quoteDays, err := models.GetQuoteDays("'" + goods.Outgoodscode + "'")
  280. if err != nil {
  281. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  282. appG.Response(http.StatusBadRequest, e.ERROR_GET_QUOTE_FAILED, nil)
  283. return
  284. }
  285. if len(quoteDays) > 0 {
  286. if quoteDays[0].Last != 0 {
  287. item.Last = utils.IntToFloat64(int(quoteDays[0].Last), int(goods.Decimalplace))
  288. }
  289. // 没有现价则尝试用昨结
  290. if item.Last == 0 && quoteDays[0].Presettle != 0 {
  291. item.Last = utils.IntToFloat64(int(quoteDays[0].Presettle), int(goods.Decimalplace))
  292. }
  293. }
  294. // 计算持仓均价 = 买当前持仓总金额 / 买当前持仓总数量 / 合约单位
  295. item.AveragePrice = v.Buycurholderamount / float64(v.Buycurpositionqty) / goods.Agreeunit
  296. // 计算持仓盈亏:买方向持仓盈亏 = (最新价 - 持仓价) * 数量 * 合约单位
  297. // 知识点:交易服务在结算后,会按结算价更新持仓单金额,所以持仓均价就是持仓价(结算价)
  298. // 知识点:持仓盈亏是今日浮动盈亏,针对结算价进行计算;平仓盈亏是针对建仓价进行计算
  299. // if item.Last == 0 {
  300. // item.PositionPL = 0
  301. // } else {
  302. // item.PositionPL = (item.Last - item.AveragePrice) * float64(v.Buycurpositionqty) * goods.Agreeunit
  303. // }
  304. // FIXME: - 与老邓及王旭讨论过后,确认后期头寸相关价格会由交易服务落地,目前暂不进行计算
  305. }
  306. if v.Sellcurpositionqty > 0 {
  307. // 卖方向
  308. item := QueryErmcpTradePositionRsp{
  309. BuyOrSell: 0,
  310. EnableQTY: v.Sellcurpositionqty - v.Sellfrozenqty,
  311. CurPositionQTY: v.Sellcurpositionqty,
  312. CurHolderAmount: v.Sellcurholderamount,
  313. CurTDPosition: v.Sellcurtdposition,
  314. CurTDPositionEnabled: v.Sellcurtdposition - v.Sellfretdposition,
  315. UsedMargin: v.Usedmargin,
  316. Goodsid: int64(v.Goodsid),
  317. }
  318. // 获取对应市场信息
  319. market, err := models.GetMarketByGoodsID(int(v.Goodsid))
  320. if err != nil {
  321. // 查询失败
  322. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  323. appG.Response(http.StatusBadRequest, e.ERROR_GET_MARKET_FAILED, nil)
  324. return
  325. }
  326. if market == nil {
  327. logger.GetLogger().Errorf("QueryErmcpTradePosition failed")
  328. appG.Response(http.StatusBadRequest, e.ERROR_GET_MARKET_FAILED, nil)
  329. return
  330. }
  331. item.Marketid = int64(market.Marketid)
  332. // 获取对应商品信息
  333. goods, err := models.GetGoods(int(v.Goodsid))
  334. if err != nil {
  335. // 查询失败
  336. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  337. appG.Response(http.StatusBadRequest, e.ERROR_GET_GOODS_FAILED, nil)
  338. return
  339. }
  340. if goods == nil {
  341. logger.GetLogger().Errorf("QueryErmcpTradePosition failed")
  342. appG.Response(http.StatusBadRequest, e.ERROR_GET_GOODS_FAILED, nil)
  343. return
  344. }
  345. item.Goodscode = goods.Goodscode
  346. item.Outgoodscode = goods.Outgoodscode
  347. item.Goodsname = goods.Goodsname
  348. item.Agreeunit = goods.Agreeunit
  349. // 获取对应外部交易所名称
  350. exchange, err := models.GetExternalexchangeByGoodsGroupID(int(goods.Goodsgroupid))
  351. if err != nil {
  352. // 查询失败
  353. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  354. appG.Response(http.StatusBadRequest, e.ERROR_GET_EXEXCHANGE_FAILED, nil)
  355. return
  356. }
  357. if exchange == nil {
  358. logger.GetLogger().Errorf("QueryErmcpTradePosition failed")
  359. appG.Response(http.StatusBadRequest, e.ERROR_GET_EXEXCHANGE_FAILED, nil)
  360. return
  361. }
  362. item.ExExehangeName = exchange.Exchangefullname
  363. // 获取对应商品盘面信息
  364. quoteDays, err := models.GetQuoteDays("'" + goods.Outgoodscode + "'")
  365. if err != nil {
  366. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  367. appG.Response(http.StatusBadRequest, e.ERROR_GET_QUOTE_FAILED, nil)
  368. return
  369. }
  370. if len(quoteDays) > 0 {
  371. if quoteDays[0].Last != 0 {
  372. item.Last = utils.IntToFloat64(int(quoteDays[0].Last), int(goods.Decimalplace))
  373. }
  374. // 没有现价则尝试用昨结
  375. if item.Last == 0 && quoteDays[0].Presettle != 0 {
  376. item.Last = utils.IntToFloat64(int(quoteDays[0].Presettle), int(goods.Decimalplace))
  377. }
  378. }
  379. // 计算持仓均价 = 买当前持仓总金额 / 买当前持仓总数量 / 合约单位
  380. item.AveragePrice = v.Buycurholderamount / float64(v.Buycurpositionqty) / goods.Agreeunit
  381. // 计算持仓盈亏:卖方向持仓盈亏 = (持仓价 - 最新价) * 数量 * 合约单位
  382. // 知识点:交易服务在结算后,会按结算价更新持仓单金额,所以持仓均价就是持仓价(结算价)
  383. // 知识点:持仓盈亏是今日浮动盈亏,针对结算价进行计算;平仓盈亏是针对建仓价进行计算
  384. }
  385. }
  386. }
  387. // 查询成功返回
  388. logger.GetLogger().Debugln("QueryErmcpTradePosition successed: %v", rsp)
  389. appG.Response(http.StatusOK, e.SUCCESS, rsp)
  390. }