qryOrder.go 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818
  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. "strconv"
  10. "github.com/gin-gonic/gin"
  11. )
  12. // QueryErmcpTradePositionReq 获取企业风管期货持仓头寸信息请求参数
  13. type QueryErmcpTradePositionReq struct {
  14. AccountID int `form:"accountID" binding:"required"`
  15. MarketID int `form:"marketID"`
  16. }
  17. // QueryErmcpTradePositionRsp 获取企业风管期货持仓头寸信息返回模型
  18. type QueryErmcpTradePositionRsp struct {
  19. Goodsname string `json:"goodsname"` // 商品名称
  20. BuyOrSell int64 `json:"buyorsell"` // 方向 - 0:买 1:卖
  21. EnableQTY int64 `json:"enableqty"` // 可用(总仓可用)
  22. CurPositionQTY int64 `json:"curpositionqty"` // 持仓(总仓数量, 期末头寸)
  23. Last float64 `json:"last"` // 现价
  24. CurTDPosition int64 `json:"curtdposition"` // 今仓数量(期末今日头寸)
  25. CurTDPositionEnabled int64 `json:"curtdpositionenabled"` // 今仓可用
  26. PositionAveragePrice float64 `json:"positionaverageprice"` // 持仓均价【头寸变化更新】= 持仓成本 / 期末头寸 / 合约单位
  27. OpenAveragePrice float64 `json:"openaverageprice" ` // 开仓均价【头寸变化更新】 = 开仓成本 / 期末头寸 / 合约单位
  28. PositionPL float64 `json:"positionpl"` // 盯市浮盈【实时行情更新】(MTP:浮动盈亏、持仓盈亏) 买方向 = (最新价 - 持仓均价) * 买期末头寸 * 合约单位;卖方向 = (持仓均价 - 最新价) * 卖期末头寸 * 合约单位
  29. OpenPL float64 `json:"openpl"` // 逐笔浮盈【实时行情更新】(MTP:开仓盈亏、平仓盈亏) 买方向 = (最新价 - 开仓均价) * 买期末头寸 * 合约单位;卖方向 = (开仓均价 - 最新价) * 卖期末头寸 * 合约单位
  30. PositionPLRate float64 `json:"positionplrate"` // 持仓盈亏比例【实时行情更新】 = 持仓盈亏 / 开仓成本
  31. UsedMargin float64 `json:"usedmargin"` // 占用保证金
  32. ExExehangeID uint64 `json:"exexehangeid"` // 外部交易所id
  33. ExExehangeCode string `json:"exexehangecode"` // 外部交易所代码
  34. ExExehangeName string `json:"exexchangename"` // 外部交易所名称
  35. OpenCost float64 `json:"opencost"` // 开仓成本
  36. PositionCost float64 `json:"positioncost"` // 持仓成本
  37. Goodsid int64 `json:"goodsid"` // 商品ID(自增ID SEQ_GOODS)
  38. Goodscode string `json:"goodscode"` // 商品代码(内部)
  39. Outgoodscode string `json:"outgoodscode"` // 商品代码(外部)
  40. Agreeunit float64 `json:"agreeunit"` // 合约单位
  41. Decimalplace int64 `json:"decimalplace"` // 报价小数位
  42. Marketid int64 `json:"marketid"` // 所属市场ID
  43. }
  44. // QueryErmcpTradePosition 获取企业风管期货持仓头寸信息
  45. // @Summary 获取企业风管期货持仓头寸信息
  46. // @Description 本接口只使用于通道交易相关头寸查询;子账户持仓头寸占用保证金为0;
  47. // @Produce json
  48. // @Security ApiKeyAuth
  49. // @Param accountID query int true "资金账户ID"
  50. // @Param marketID query int false "所属市场ID"
  51. // @Success 200 {object} QueryErmcpTradePositionRsp
  52. // @Failure 500 {object} app.Response
  53. // @Router /Ermcp/QueryErmcpTradePosition [get]
  54. // @Tags 企业风险管理(app)
  55. func QueryErmcpTradePosition(c *gin.Context) {
  56. appG := app.Gin{C: c}
  57. // 获取请求参数
  58. var req QueryErmcpTradePositionReq
  59. if err := appG.C.ShouldBindQuery(&req); err != nil {
  60. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  61. appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
  62. return
  63. }
  64. rsp := make([]QueryErmcpTradePositionRsp, 0)
  65. // 获取资金账户信息
  66. taAccount, err := models.GetTaAccountByID(req.AccountID)
  67. if err != nil {
  68. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  69. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  70. return
  71. }
  72. if taAccount == nil {
  73. logger.GetLogger().Errorf("QueryErmcpTradePosition failed")
  74. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  75. return
  76. }
  77. if taAccount.Ismain == 1 {
  78. // 母账户,从HEDGE_OUTTRADEPOSITION表查询持仓头寸(未生成内部头寸)
  79. hedgeOutTradePositions, err := models.GetHedgeOutTradePositions(req.AccountID, req.MarketID)
  80. if err != nil {
  81. // 查询失败
  82. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  83. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  84. return
  85. }
  86. // 分解买卖方向的头寸
  87. for _, v := range hedgeOutTradePositions {
  88. // 分解买卖方向的头寸
  89. if v.Curbuyposition > 0 {
  90. // 买方向
  91. item := QueryErmcpTradePositionRsp{
  92. BuyOrSell: 0,
  93. EnableQTY: v.Curbuyposition - v.Fretdbuyposition - v.Freydbuyposition, // 买可用 = 期末买头寸 - 冻结今日买头寸 - 冻结上日买头寸
  94. CurPositionQTY: v.Curbuyposition,
  95. CurTDPosition: v.Curtdbuyposition,
  96. CurTDPositionEnabled: v.Curtdbuyposition - v.Fretdbuyposition, // 今仓买可用 = 期末今日买头寸 - 冻结今日买头寸
  97. UsedMargin: v.Buyusemargin,
  98. OpenCost: v.Buyopencost,
  99. PositionCost: v.Buypositioncost,
  100. Goodsid: v.Hedgegoodsid,
  101. Marketid: int64(v.Marketid),
  102. }
  103. // 获取对应商品信息
  104. goods, err := models.GetGoods(int(v.Hedgegoodsid))
  105. if err != nil {
  106. // 查询失败
  107. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  108. appG.Response(http.StatusBadRequest, e.ERROR_GET_GOODS_FAILED, nil)
  109. return
  110. }
  111. if goods == nil {
  112. logger.GetLogger().Errorf("QueryErmcpTradePosition failed")
  113. appG.Response(http.StatusBadRequest, e.ERROR_GET_GOODS_FAILED, nil)
  114. return
  115. }
  116. item.Goodscode = goods.Goodscode
  117. item.Outgoodscode = goods.Outgoodscode
  118. item.Goodsname = goods.Goodsname
  119. item.Agreeunit = goods.Agreeunit
  120. item.Decimalplace = goods.Decimalplace
  121. // 获取对应外部交易所名称
  122. exchange, err := models.GetExternalexchangeByGoodsGroupID(int(goods.Goodsgroupid))
  123. if err != nil {
  124. // 查询失败
  125. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  126. appG.Response(http.StatusBadRequest, e.ERROR_GET_EXEXCHANGE_FAILED, nil)
  127. return
  128. }
  129. if exchange == nil {
  130. logger.GetLogger().Errorf("QueryErmcpTradePosition failed")
  131. appG.Response(http.StatusBadRequest, e.ERROR_GET_EXEXCHANGE_FAILED, nil)
  132. return
  133. }
  134. item.ExExehangeName = exchange.Exchangefullname
  135. // 获取对应商品盘面信息
  136. quoteDays, err := models.GetQuoteDays("'" + goods.Outgoodscode + "'")
  137. if err != nil {
  138. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  139. appG.Response(http.StatusBadRequest, e.ERROR_GET_QUOTE_FAILED, nil)
  140. return
  141. }
  142. if len(quoteDays) > 0 {
  143. if quoteDays[0].Last != 0 {
  144. item.Last = utils.IntToFloat64(int(quoteDays[0].Last), int(goods.Decimalplace))
  145. }
  146. // 没有现价则尝试用昨结
  147. if item.Last == 0 && quoteDays[0].Presettle != 0 {
  148. item.Last = utils.IntToFloat64(int(quoteDays[0].Presettle), int(goods.Decimalplace))
  149. }
  150. }
  151. // 计算价格与盈亏
  152. // 开仓均价 = 开仓成本 / 期末头寸 / 合约单位
  153. item.OpenAveragePrice = v.Buyopencost / float64(v.Curbuyposition) / goods.Agreeunit
  154. item.OpenAveragePrice, _ = strconv.ParseFloat(utils.FormatFloat(item.OpenAveragePrice, int(goods.Decimalplace)), 64)
  155. // 持仓均价 = 持仓成本 / 期末头寸 / 合约单位
  156. item.PositionAveragePrice = v.Buypositioncost / float64(v.Curbuyposition) / goods.Agreeunit
  157. item.PositionAveragePrice, _ = strconv.ParseFloat(utils.FormatFloat(item.PositionAveragePrice, int(goods.Decimalplace)), 64)
  158. // 盯市浮盈【实时行情更新】(MTP:浮动盈亏、持仓盈亏) 买方向 = (最新价 - 持仓均价) * 买期末头寸 * 合约单位;卖方向 = (持仓均价 - 最新价) * 卖期末头寸 * 合约单位
  159. if item.Last != 0 {
  160. item.PositionPL = (item.Last - item.PositionAveragePrice) * float64(v.Curbuyposition) * goods.Agreeunit
  161. item.PositionPL, _ = strconv.ParseFloat(utils.FormatFloat(item.PositionPL, 2), 64)
  162. }
  163. // 逐笔浮盈【实时行情更新】(MTP:开仓盈亏、平仓盈亏) 买方向 = (最新价 - 开仓均价) * 买期末头寸 * 合约单位;卖方向 = (开仓均价 - 最新价) * 卖期末头寸 * 合约单位
  164. if item.Last != 0 {
  165. item.OpenPL = (item.Last - item.OpenAveragePrice) * float64(v.Curbuyposition) * goods.Agreeunit
  166. item.OpenPL, _ = strconv.ParseFloat(utils.FormatFloat(item.OpenPL, 2), 64)
  167. }
  168. // 持仓盈亏比例 = 持仓盈亏 / 开仓成本
  169. if item.PositionPL != 0 && v.Buyopencost != 0 {
  170. item.PositionPLRate = item.PositionPL / v.Buyopencost
  171. item.PositionPLRate, _ = strconv.ParseFloat(utils.FormatFloat(item.PositionPLRate, 4), 64)
  172. }
  173. rsp = append(rsp, item)
  174. }
  175. if v.Cursellposition > 0 {
  176. // 卖方向
  177. item := QueryErmcpTradePositionRsp{
  178. BuyOrSell: 1,
  179. EnableQTY: v.Cursellposition - v.Fretdsellposition - v.Freydsellposition,
  180. CurPositionQTY: v.Cursellposition,
  181. CurTDPosition: v.Curtdsellposition,
  182. CurTDPositionEnabled: v.Curtdsellposition - v.Fretdsellposition,
  183. UsedMargin: v.Sellusemargin,
  184. OpenCost: v.Sellopencost,
  185. PositionCost: v.Sellpositioncost,
  186. Goodsid: v.Hedgegoodsid,
  187. Marketid: int64(v.Marketid),
  188. }
  189. // 获取对应商品信息
  190. goods, err := models.GetGoods(int(v.Hedgegoodsid))
  191. if err != nil {
  192. // 查询失败
  193. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  194. appG.Response(http.StatusBadRequest, e.ERROR_GET_GOODS_FAILED, nil)
  195. return
  196. }
  197. if goods == nil {
  198. logger.GetLogger().Errorf("QueryErmcpTradePosition failed")
  199. appG.Response(http.StatusBadRequest, e.ERROR_GET_GOODS_FAILED, nil)
  200. return
  201. }
  202. item.Goodscode = goods.Goodscode
  203. item.Outgoodscode = goods.Outgoodscode
  204. item.Goodsname = goods.Goodsname
  205. item.Agreeunit = goods.Agreeunit
  206. item.Decimalplace = goods.Decimalplace
  207. // 获取对应外部交易所名称
  208. exchange, err := models.GetExternalexchangeByGoodsGroupID(int(goods.Goodsgroupid))
  209. if err != nil {
  210. // 查询失败
  211. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  212. appG.Response(http.StatusBadRequest, e.ERROR_GET_EXEXCHANGE_FAILED, nil)
  213. return
  214. }
  215. if exchange == nil {
  216. logger.GetLogger().Errorf("QueryErmcpTradePosition failed")
  217. appG.Response(http.StatusBadRequest, e.ERROR_GET_EXEXCHANGE_FAILED, nil)
  218. return
  219. }
  220. item.ExExehangeName = exchange.Exchangefullname
  221. // 获取对应商品盘面信息
  222. quoteDays, err := models.GetQuoteDays("'" + goods.Outgoodscode + "'")
  223. if err != nil {
  224. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  225. appG.Response(http.StatusBadRequest, e.ERROR_GET_QUOTE_FAILED, nil)
  226. return
  227. }
  228. if len(quoteDays) > 0 {
  229. if quoteDays[0].Last != 0 {
  230. item.Last = utils.IntToFloat64(int(quoteDays[0].Last), int(goods.Decimalplace))
  231. }
  232. // 没有现价则尝试用昨结
  233. if item.Last == 0 && quoteDays[0].Presettle != 0 {
  234. item.Last = utils.IntToFloat64(int(quoteDays[0].Presettle), int(goods.Decimalplace))
  235. }
  236. }
  237. // 计算价格与盈亏
  238. // 开仓均价 = 开仓成本 / 期末头寸 / 合约单位
  239. item.OpenAveragePrice = v.Sellopencost / float64(v.Cursellposition) / goods.Agreeunit
  240. item.OpenAveragePrice, _ = strconv.ParseFloat(utils.FormatFloat(item.OpenAveragePrice, int(goods.Decimalplace)), 64)
  241. // 持仓均价 = 持仓成本 / 期末头寸 / 合约单位
  242. item.PositionAveragePrice = v.Sellpositioncost / float64(v.Cursellposition) / goods.Agreeunit
  243. item.PositionAveragePrice, _ = strconv.ParseFloat(utils.FormatFloat(item.PositionAveragePrice, int(goods.Decimalplace)), 64)
  244. // 盯市浮盈【实时行情更新】(MTP:浮动盈亏、持仓盈亏) 买方向 = (最新价 - 持仓均价) * 买期末头寸 * 合约单位;卖方向 = (持仓均价 - 最新价) * 卖期末头寸 * 合约单位
  245. if item.Last != 0 {
  246. item.PositionPL = (item.PositionAveragePrice - item.Last) * float64(v.Cursellposition) * goods.Agreeunit
  247. item.PositionPL, _ = strconv.ParseFloat(utils.FormatFloat(item.PositionPL, 2), 64)
  248. }
  249. // 逐笔浮盈【实时行情更新】(MTP:开仓盈亏、平仓盈亏) 买方向 = (最新价 - 开仓均价) * 买期末头寸 * 合约单位;卖方向 = (开仓均价 - 最新价) * 卖期末头寸 * 合约单位
  250. if item.Last != 0 {
  251. item.OpenPL = (item.OpenAveragePrice - item.Last) * float64(v.Cursellposition) * goods.Agreeunit
  252. item.OpenPL, _ = strconv.ParseFloat(utils.FormatFloat(item.OpenPL, 2), 64)
  253. }
  254. // 持仓盈亏比例 = 持仓盈亏 / 开仓成本
  255. if item.PositionPL != 0 && v.Sellopencost != 0 {
  256. item.PositionPLRate = item.PositionPL / v.Sellopencost
  257. item.PositionPLRate, _ = strconv.ParseFloat(utils.FormatFloat(item.PositionPLRate, 4), 64)
  258. }
  259. rsp = append(rsp, item)
  260. }
  261. }
  262. } else {
  263. // 子账户
  264. tradePositions, err := models.GetTradePositions(req.AccountID, req.MarketID)
  265. if err != nil {
  266. // 查询失败
  267. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  268. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  269. return
  270. }
  271. // 分解买卖方向的头寸
  272. for _, v := range tradePositions {
  273. if v.Buycurpositionqty > 0 {
  274. // 买方向
  275. item := QueryErmcpTradePositionRsp{
  276. BuyOrSell: 0,
  277. EnableQTY: v.Buycurpositionqty - v.Buyfrozenqty, // 买可用 = 买当前持仓总数量 - 买持仓冻结数量
  278. CurPositionQTY: v.Buycurpositionqty,
  279. CurTDPosition: v.Buycurtdposition,
  280. CurTDPositionEnabled: v.Buycurtdposition - v.Buyfretdposition, // 今仓买可用 = 期末今日买头寸 - 冻结今日买头寸
  281. Goodsid: int64(v.Goodsid),
  282. }
  283. // 获取对应市场信息
  284. market, err := models.GetMarketByGoodsID(int(v.Goodsid))
  285. if err != nil {
  286. // 查询失败
  287. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  288. appG.Response(http.StatusBadRequest, e.ERROR_GET_MARKET_FAILED, nil)
  289. return
  290. }
  291. if market == nil {
  292. logger.GetLogger().Errorf("QueryErmcpTradePosition failed")
  293. appG.Response(http.StatusBadRequest, e.ERROR_GET_MARKET_FAILED, nil)
  294. return
  295. }
  296. item.Marketid = int64(market.Marketid)
  297. // 获取对应商品信息
  298. goods, err := models.GetGoods(int(v.Goodsid))
  299. if err != nil {
  300. // 查询失败
  301. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  302. appG.Response(http.StatusBadRequest, e.ERROR_GET_GOODS_FAILED, nil)
  303. return
  304. }
  305. if goods == nil {
  306. logger.GetLogger().Errorf("QueryErmcpTradePosition failed")
  307. appG.Response(http.StatusBadRequest, e.ERROR_GET_GOODS_FAILED, nil)
  308. return
  309. }
  310. item.Goodscode = goods.Goodscode
  311. item.Outgoodscode = goods.Outgoodscode
  312. item.Goodsname = goods.Goodsname
  313. item.Agreeunit = goods.Agreeunit
  314. item.Decimalplace = goods.Decimalplace
  315. // 获取对应外部交易所名称
  316. exchange, err := models.GetExternalexchangeByGoodsGroupID(int(goods.Goodsgroupid))
  317. if err != nil {
  318. // 查询失败
  319. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  320. appG.Response(http.StatusBadRequest, e.ERROR_GET_EXEXCHANGE_FAILED, nil)
  321. return
  322. }
  323. if exchange == nil {
  324. logger.GetLogger().Errorf("QueryErmcpTradePosition failed")
  325. appG.Response(http.StatusBadRequest, e.ERROR_GET_EXEXCHANGE_FAILED, nil)
  326. return
  327. }
  328. item.ExExehangeID = exchange.Autoid
  329. item.ExExehangeCode = exchange.Exexchangecode
  330. item.ExExehangeName = exchange.Exchangefullname
  331. // 获取对应商品盘面信息
  332. quoteDays, err := models.GetQuoteDays("'" + goods.Outgoodscode + "'")
  333. if err != nil {
  334. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  335. appG.Response(http.StatusBadRequest, e.ERROR_GET_QUOTE_FAILED, nil)
  336. return
  337. }
  338. if len(quoteDays) > 0 {
  339. if quoteDays[0].Last != 0 {
  340. item.Last = utils.IntToFloat64(int(quoteDays[0].Last), int(goods.Decimalplace))
  341. }
  342. // 没有现价则尝试用昨结
  343. if item.Last == 0 && quoteDays[0].Presettle != 0 {
  344. item.Last = utils.IntToFloat64(int(quoteDays[0].Presettle), int(goods.Decimalplace))
  345. }
  346. }
  347. // 子账户需要从内部持仓明细(通道)表汇总计划开仓成本和开仓均价
  348. hedgeInnerHolderDetails, _ := models.GetHedgeInnerHolderDetails(req.AccountID, int(item.Goodsid), 0)
  349. for _, detail := range hedgeInnerHolderDetails {
  350. // 开仓成本 = 建仓价 * 持仓数量 * 合约单位
  351. item.OpenCost += detail.Openprice * float64(detail.Holderqty) * goods.Agreeunit
  352. }
  353. // 开仓均价 = 开仓成本 / 期末头寸 / 合约单位
  354. item.OpenAveragePrice = item.OpenCost / float64(item.CurPositionQTY) / goods.Agreeunit
  355. item.OpenAveragePrice, _ = strconv.ParseFloat(utils.FormatFloat(item.OpenAveragePrice, int(goods.Decimalplace)), 64)
  356. // 持仓成本
  357. item.PositionCost = v.Buycurholderamount
  358. // 持仓均价 = 持仓成本 / 期末头寸 / 合约单位
  359. item.PositionAveragePrice = v.Buycurholderamount / float64(v.Buycurpositionqty) / goods.Agreeunit
  360. item.PositionAveragePrice, _ = strconv.ParseFloat(utils.FormatFloat(item.PositionAveragePrice, int(goods.Decimalplace)), 64)
  361. // 盯市浮盈【实时行情更新】(MTP:浮动盈亏、持仓盈亏) 买方向 = (最新价 - 持仓均价) * 买期末头寸 * 合约单位;卖方向 = (持仓均价 - 最新价) * 卖期末头寸 * 合约单位
  362. if item.Last != 0 {
  363. item.PositionPL = (item.Last - item.PositionAveragePrice) * float64(v.Buycurpositionqty) * goods.Agreeunit
  364. item.PositionPL, _ = strconv.ParseFloat(utils.FormatFloat(item.PositionPL, 2), 64)
  365. }
  366. // 逐笔浮盈【实时行情更新】(MTP:开仓盈亏、平仓盈亏) 买方向 = (最新价 - 开仓均价) * 买期末头寸 * 合约单位;卖方向 = (开仓均价 - 最新价) * 卖期末头寸 * 合约单位
  367. if item.Last != 0 {
  368. item.OpenPL = (item.Last - item.OpenAveragePrice) * float64(v.Buycurpositionqty) * goods.Agreeunit
  369. item.OpenPL, _ = strconv.ParseFloat(utils.FormatFloat(item.OpenPL, 2), 64)
  370. }
  371. // 持仓盈亏比例 = 持仓盈亏 / 开仓成本
  372. if item.PositionPL != 0 && item.OpenCost != 0 {
  373. item.PositionPLRate = item.PositionPL / item.OpenCost
  374. item.PositionPLRate, _ = strconv.ParseFloat(utils.FormatFloat(item.PositionPLRate, 4), 64)
  375. }
  376. rsp = append(rsp, item)
  377. }
  378. if v.Sellcurpositionqty > 0 {
  379. // 卖方向
  380. item := QueryErmcpTradePositionRsp{
  381. BuyOrSell: 1,
  382. EnableQTY: v.Sellcurpositionqty - v.Sellfrozenqty, // 买可用 = 买当前持仓总数量 - 买持仓冻结数量
  383. CurPositionQTY: v.Sellcurpositionqty,
  384. CurTDPosition: v.Sellcurtdposition,
  385. CurTDPositionEnabled: v.Sellcurtdposition - v.Sellfretdposition, // 今仓买可用 = 期末今日买头寸 - 冻结今日买头寸
  386. Goodsid: int64(v.Goodsid),
  387. }
  388. // 获取对应市场信息
  389. market, err := models.GetMarketByGoodsID(int(v.Goodsid))
  390. if err != nil {
  391. // 查询失败
  392. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  393. appG.Response(http.StatusBadRequest, e.ERROR_GET_MARKET_FAILED, nil)
  394. return
  395. }
  396. if market == nil {
  397. logger.GetLogger().Errorf("QueryErmcpTradePosition failed")
  398. appG.Response(http.StatusBadRequest, e.ERROR_GET_MARKET_FAILED, nil)
  399. return
  400. }
  401. item.Marketid = int64(market.Marketid)
  402. // 获取对应商品信息
  403. goods, err := models.GetGoods(int(v.Goodsid))
  404. if err != nil {
  405. // 查询失败
  406. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  407. appG.Response(http.StatusBadRequest, e.ERROR_GET_GOODS_FAILED, nil)
  408. return
  409. }
  410. if goods == nil {
  411. logger.GetLogger().Errorf("QueryErmcpTradePosition failed")
  412. appG.Response(http.StatusBadRequest, e.ERROR_GET_GOODS_FAILED, nil)
  413. return
  414. }
  415. item.Goodscode = goods.Goodscode
  416. item.Outgoodscode = goods.Outgoodscode
  417. item.Goodsname = goods.Goodsname
  418. item.Agreeunit = goods.Agreeunit
  419. item.Decimalplace = goods.Decimalplace
  420. // 获取对应外部交易所名称
  421. exchange, err := models.GetExternalexchangeByGoodsGroupID(int(goods.Goodsgroupid))
  422. if err != nil {
  423. // 查询失败
  424. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  425. appG.Response(http.StatusBadRequest, e.ERROR_GET_EXEXCHANGE_FAILED, nil)
  426. return
  427. }
  428. if exchange == nil {
  429. logger.GetLogger().Errorf("QueryErmcpTradePosition failed")
  430. appG.Response(http.StatusBadRequest, e.ERROR_GET_EXEXCHANGE_FAILED, nil)
  431. return
  432. }
  433. item.ExExehangeName = exchange.Exchangefullname
  434. // 获取对应商品盘面信息
  435. quoteDays, err := models.GetQuoteDays("'" + goods.Outgoodscode + "'")
  436. if err != nil {
  437. logger.GetLogger().Errorf("QueryErmcpTradePosition failed: %s", err.Error())
  438. appG.Response(http.StatusBadRequest, e.ERROR_GET_QUOTE_FAILED, nil)
  439. return
  440. }
  441. if len(quoteDays) > 0 {
  442. if quoteDays[0].Last != 0 {
  443. item.Last = utils.IntToFloat64(int(quoteDays[0].Last), int(goods.Decimalplace))
  444. }
  445. // 没有现价则尝试用昨结
  446. if item.Last == 0 && quoteDays[0].Presettle != 0 {
  447. item.Last = utils.IntToFloat64(int(quoteDays[0].Presettle), int(goods.Decimalplace))
  448. }
  449. }
  450. // 子账户需要从内部持仓明细(通道)表汇总计划开仓成本和开仓均价
  451. hedgeInnerHolderDetails, _ := models.GetHedgeInnerHolderDetails(req.AccountID, int(item.Goodsid), 1)
  452. for _, detail := range hedgeInnerHolderDetails {
  453. // 开仓成本 = 建仓价 * 持仓数量 * 合约单位
  454. item.OpenCost += detail.Openprice * float64(detail.Holderqty) * goods.Agreeunit
  455. }
  456. // 开仓均价 = 开仓成本 / 期末头寸 / 合约单位
  457. item.OpenAveragePrice = item.OpenCost / float64(item.CurPositionQTY) / goods.Agreeunit
  458. item.OpenAveragePrice, _ = strconv.ParseFloat(utils.FormatFloat(item.OpenAveragePrice, int(goods.Decimalplace)), 64)
  459. // 持仓成本
  460. item.PositionCost = v.Sellcurholderamount
  461. // 持仓均价 = 持仓成本 / 期末头寸 / 合约单位
  462. item.PositionAveragePrice = v.Sellcurholderamount / float64(v.Sellcurpositionqty) / goods.Agreeunit
  463. item.PositionAveragePrice, _ = strconv.ParseFloat(utils.FormatFloat(item.PositionAveragePrice, int(goods.Decimalplace)), 64)
  464. // 盯市浮盈【实时行情更新】(MTP:浮动盈亏、持仓盈亏) 买方向 = (最新价 - 持仓均价) * 买期末头寸 * 合约单位;卖方向 = (持仓均价 - 最新价) * 卖期末头寸 * 合约单位
  465. if item.Last != 0 {
  466. item.PositionPL = (item.PositionAveragePrice - item.Last) * float64(v.Sellcurpositionqty) * goods.Agreeunit
  467. item.PositionPL, _ = strconv.ParseFloat(utils.FormatFloat(item.PositionPL, 2), 64)
  468. }
  469. // 逐笔浮盈【实时行情更新】(MTP:开仓盈亏、平仓盈亏) 买方向 = (最新价 - 开仓均价) * 买期末头寸 * 合约单位;卖方向 = (开仓均价 - 最新价) * 卖期末头寸 * 合约单位
  470. if item.Last != 0 {
  471. item.OpenPL = (item.OpenAveragePrice - item.Last) * float64(v.Sellcurpositionqty) * goods.Agreeunit
  472. item.OpenPL, _ = strconv.ParseFloat(utils.FormatFloat(item.OpenPL, 2), 64)
  473. }
  474. // 持仓盈亏比例 = 持仓盈亏 / 开仓成本
  475. if item.PositionPL != 0 && item.OpenCost != 0 {
  476. item.PositionPLRate = item.PositionPL / item.OpenCost
  477. item.PositionPLRate, _ = strconv.ParseFloat(utils.FormatFloat(item.PositionPLRate, 4), 64)
  478. }
  479. rsp = append(rsp, item)
  480. }
  481. }
  482. }
  483. // 查询成功返回
  484. logger.GetLogger().Debugln("QueryErmcpTradePosition successed: %v", rsp)
  485. appG.Response(http.StatusOK, e.SUCCESS, rsp)
  486. }
  487. // QueryErmcpInnerHolderDetailsReq 获取企业风管期货内部持仓单信息请求参数
  488. type QueryErmcpInnerHolderDetailsReq struct {
  489. AccountID int `form:"accountID" binding:"required"`
  490. GoodsID int `form:"goodsID"`
  491. BuyOrSell int `form:"buyOrSell"`
  492. }
  493. // QueryErmcpInnerHolderDetails 获取企业风管期货内部持仓单信息
  494. // @Summary 获取企业风管期货内部持仓单信息
  495. // @Produce json
  496. // @Security ApiKeyAuth
  497. // @Param accountID query int true "资金账户ID"
  498. // @Param goodsID query int false "商品ID"
  499. // @Param buyOrSell query int false "买卖方向,0:买 1:卖"
  500. // @Success 200 {object} models.Hedgeinnerholderdetail
  501. // @Failure 500 {object} app.Response
  502. // @Router /Ermcp/QueryErmcpInnerHolderDetails [get]
  503. // @Tags 企业风险管理(app)
  504. func QueryErmcpInnerHolderDetails(c *gin.Context) {
  505. appG := app.Gin{C: c}
  506. // 获取请求参数
  507. var req QueryErmcpInnerHolderDetailsReq
  508. if err := appG.C.ShouldBindQuery(&req); err != nil {
  509. logger.GetLogger().Errorf("QueryErmcpInnerHolderDetails failed: %s", err.Error())
  510. appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
  511. return
  512. }
  513. var r models.Hedgeinnerholderdetail
  514. rst, err := r.GetList(req.AccountID, req.GoodsID, req.BuyOrSell)
  515. if err != nil {
  516. logger.GetLogger().Errorf("QueryErmcpInnerHolderDetails failed: %s", err.Error())
  517. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  518. return
  519. }
  520. // 查询成功返回
  521. logger.GetLogger().Debugln("QueryErmcpInnerHolderDetails successed: %v", rst)
  522. appG.Response(http.StatusOK, e.SUCCESS, rst)
  523. }
  524. // QueryErmcpOrderDetailsReq 获取企业风管期货委托单信息请求参数
  525. type QueryErmcpOrderDetailsReq struct {
  526. AccountID int `form:"accountID" binding:"required"`
  527. }
  528. // QueryErmcpOrderDetails 获取企业风管期货委托单信息
  529. // @Summary 获取企业风管期货委托单信息
  530. // @Produce json
  531. // @Security ApiKeyAuth
  532. // @Param accountID query int true "资金账户ID"
  533. // @Success 200 {object} models.QueryHedgeOrderDetailRsp
  534. // @Failure 500 {object} app.Response
  535. // @Router /Ermcp/QueryErmcpOrderDetails [get]
  536. // @Tags 企业风险管理(app)
  537. func QueryErmcpOrderDetails(c *gin.Context) {
  538. appG := app.Gin{C: c}
  539. // 获取请求参数
  540. var req QueryErmcpOrderDetailsReq
  541. if err := appG.C.ShouldBindQuery(&req); err != nil {
  542. logger.GetLogger().Errorf("QueryErmcpOrderDetails failed: %s", err.Error())
  543. appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
  544. return
  545. }
  546. // 获取资金账户信息
  547. taAccount, err := models.GetTaAccountByID(req.AccountID)
  548. if err != nil {
  549. logger.GetLogger().Errorf("QueryErmcpOrderDetails failed: %s", err.Error())
  550. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  551. return
  552. }
  553. if taAccount == nil {
  554. logger.GetLogger().Errorf("QueryErmcpOrderDetails failed")
  555. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  556. return
  557. }
  558. rst := make([]models.QueryHedgeOrderDetailRsp, 0)
  559. if taAccount.Ismain == 1 {
  560. // 母账户 -> 外部委托单
  561. rst, err = models.GetHedgeOutOrderDetails(req.AccountID)
  562. if err != nil {
  563. // 查询失败
  564. logger.GetLogger().Errorf("QueryErmcpOrderDetails failed: %s", err.Error())
  565. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  566. return
  567. }
  568. } else {
  569. // 子账户 -> 内部委托单
  570. rst, err = models.GetHedgeInnerOrderDetails(req.AccountID)
  571. if err != nil {
  572. // 查询失败
  573. logger.GetLogger().Errorf("QueryErmcpOrderDetails failed: %s", err.Error())
  574. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  575. return
  576. }
  577. }
  578. // 查询成功返回
  579. logger.GetLogger().Debugln("QueryErmcpOrderDetails successed: %v", rst)
  580. appG.Response(http.StatusOK, e.SUCCESS, rst)
  581. }
  582. // QueryErmcpHisOrderDetailsReq 获取企业风管期货历史委托单信息请求参数
  583. type QueryErmcpHisOrderDetailsReq struct {
  584. AccountID int `form:"accountID" binding:"required"`
  585. StartDate string `form:"startDate"` // 开始时间
  586. EndDate string `form:"endDate"` // 结束时间
  587. }
  588. // QueryErmcpHisOrderDetails 获取企业风管期货历史委托单信息
  589. // @Summary 获取企业风管期货历史委托单信息
  590. // @Produce json
  591. // @Security ApiKeyAuth
  592. // @Param accountID query int true "资金账户ID"
  593. // @Param startDate query string false "开始时间 - 闭区间,格式:yyyy-MM-dd"
  594. // @Param endDate query string false "结束时间 - 闭区间,格式:yyyy-MM-dd"
  595. // @Success 200 {object} models.QueryHedgeOrderDetailRsp
  596. // @Failure 500 {object} app.Response
  597. // @Router /Ermcp/QueryErmcpHisOrderDetails [get]
  598. // @Tags 企业风险管理(app)
  599. func QueryErmcpHisOrderDetails(c *gin.Context) {
  600. appG := app.Gin{C: c}
  601. // 获取请求参数
  602. var req QueryErmcpHisOrderDetailsReq
  603. if err := appG.C.ShouldBindQuery(&req); err != nil {
  604. logger.GetLogger().Errorf("QueryErmcpHisOrderDetails failed: %s", err.Error())
  605. appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
  606. return
  607. }
  608. // 获取资金账户信息
  609. taAccount, err := models.GetTaAccountByID(req.AccountID)
  610. if err != nil {
  611. logger.GetLogger().Errorf("QueryErmcpHisOrderDetails failed: %s", err.Error())
  612. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  613. return
  614. }
  615. if taAccount == nil {
  616. logger.GetLogger().Errorf("QueryErmcpHisOrderDetails failed")
  617. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  618. return
  619. }
  620. rst := make([]models.QueryHedgeOrderDetailRsp, 0)
  621. if taAccount.Ismain == 1 {
  622. // 母账户 -> 外部历史委托单
  623. rst, err = models.GetHisHedgeOutOrderDetails(req.AccountID, req.StartDate, req.EndDate)
  624. if err != nil {
  625. // 查询失败
  626. logger.GetLogger().Errorf("QueryErmcpHisOrderDetails failed: %s", err.Error())
  627. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  628. return
  629. }
  630. } else {
  631. // 子账户 -> 内部历史委托单
  632. rst, err = models.GetHisHedgeInnerOrderDetails(req.AccountID, req.StartDate, req.EndDate)
  633. if err != nil {
  634. // 查询失败
  635. logger.GetLogger().Errorf("QueryErmcpHisOrderDetails failed: %s", err.Error())
  636. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  637. return
  638. }
  639. }
  640. // 查询成功返回
  641. logger.GetLogger().Debugln("QueryErmcpHisOrderDetails successed: %v", rst)
  642. appG.Response(http.StatusOK, e.SUCCESS, rst)
  643. }
  644. // QueryHedgeTradeDetailReq 获取企业风管期货成交单信息请求参数
  645. type QueryHedgeTradeDetailReq struct {
  646. AccountID int `form:"accountID" binding:"required"`
  647. GoodsID int `form:"goodsID"`
  648. BuyOrSell int `form:"buyOrSell"`
  649. OrderID int `form:"orderID"`
  650. }
  651. // QueryErmcpTradeDetails 获取企业风管期货成交单信息
  652. // @Summary 获取企业风管期货成交单信息
  653. // @Produce json
  654. // @Security ApiKeyAuth
  655. // @Param accountID query int true "资金账户ID"
  656. // @Param goodsID query int false "商品ID"
  657. // @Param buyOrSell query int false "买卖方向,0:买 1:卖"
  658. // @Param orderID query int false "关联委托单号"
  659. // @Success 200 {object} models.QueryHedgeTradeDetailRsp
  660. // @Failure 500 {object} app.Response
  661. // @Router /Ermcp/QueryErmcpTradeDetails [get]
  662. // @Tags 企业风险管理(app)
  663. func QueryErmcpTradeDetails(c *gin.Context) {
  664. appG := app.Gin{C: c}
  665. // 获取请求参数
  666. var req QueryHedgeTradeDetailReq
  667. if err := appG.C.ShouldBindQuery(&req); err != nil {
  668. logger.GetLogger().Errorf("QueryErmcpTradeDetails failed: %s", err.Error())
  669. appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
  670. return
  671. }
  672. // 获取资金账户信息
  673. taAccount, err := models.GetTaAccountByID(req.AccountID)
  674. if err != nil {
  675. logger.GetLogger().Errorf("QueryErmcpTradeDetails failed: %s", err.Error())
  676. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  677. return
  678. }
  679. if taAccount == nil {
  680. logger.GetLogger().Errorf("QueryErmcpTradeDetails failed")
  681. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  682. return
  683. }
  684. rst := make([]models.QueryHedgeTradeDetailRsp, 0)
  685. if taAccount.Ismain == 1 {
  686. // 母账户 -> 外部成交单
  687. rst, err = models.GetHedgeOutTradeDetails(req.AccountID, req.GoodsID, req.BuyOrSell, req.OrderID)
  688. if err != nil {
  689. // 查询失败
  690. logger.GetLogger().Errorf("QueryErmcpTradeDetails failed: %s", err.Error())
  691. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  692. return
  693. }
  694. } else {
  695. // 子账户 -> 内部成交单
  696. rst, err = models.GetHedgeInnerTradeDetails(req.AccountID, req.GoodsID, req.BuyOrSell, req.OrderID)
  697. if err != nil {
  698. // 查询失败
  699. logger.GetLogger().Errorf("QueryErmcpTradeDetails failed: %s", err.Error())
  700. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  701. return
  702. }
  703. }
  704. // 查询成功返回
  705. logger.GetLogger().Debugln("QueryErmcpTradeDetails successed: %v", rst)
  706. appG.Response(http.StatusOK, e.SUCCESS, rst)
  707. }
  708. // QueryHedgeHisTradeDetaislReq 获取企业风管期货历史成交单信息请求参数
  709. type QueryHedgeHisTradeDetaislReq struct {
  710. AccountID int `form:"accountID" binding:"required"`
  711. GoodsID int `form:"goodsID"`
  712. BuyOrSell int `form:"buyOrSell"`
  713. OrderID int `form:"orderID"`
  714. StartDate string `form:"startDate"` // 开始时间
  715. EndDate string `form:"endDate"` // 结束时间
  716. }
  717. // QueryErmcpHisTradeDetails 获取企业风管期货历史成交单信息
  718. // @Summary 获取企业风管期货历史成交单信息
  719. // @Produce json
  720. // @Security ApiKeyAuth
  721. // @Param accountID query int true "资金账户ID"
  722. // @Param goodsID query int false "商品ID"
  723. // @Param buyOrSell query int false "买卖方向,0:买 1:卖"
  724. // @Param orderID query int false "关联委托单号"
  725. // @Param startDate query string false "开始时间 - 闭区间,格式:yyyy-MM-dd"
  726. // @Param endDate query string false "结束时间 - 闭区间,格式:yyyy-MM-dd"
  727. // @Success 200 {object} models.QueryHedgeTradeDetailRsp
  728. // @Failure 500 {object} app.Response
  729. // @Router /Ermcp/QueryErmcpHisTradeDetails [get]
  730. // @Tags 企业风险管理(app)
  731. func QueryErmcpHisTradeDetails(c *gin.Context) {
  732. appG := app.Gin{C: c}
  733. // 获取请求参数
  734. var req QueryHedgeHisTradeDetaislReq
  735. if err := appG.C.ShouldBindQuery(&req); err != nil {
  736. logger.GetLogger().Errorf("QueryErmcpHisTradeDetails failed: %s", err.Error())
  737. appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
  738. return
  739. }
  740. // 获取资金账户信息
  741. taAccount, err := models.GetTaAccountByID(req.AccountID)
  742. if err != nil {
  743. logger.GetLogger().Errorf("QueryErmcpHisTradeDetails failed: %s", err.Error())
  744. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  745. return
  746. }
  747. if taAccount == nil {
  748. logger.GetLogger().Errorf("QueryErmcpHisTradeDetails failed")
  749. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  750. return
  751. }
  752. rst := make([]models.QueryHedgeTradeDetailRsp, 0)
  753. if taAccount.Ismain == 1 {
  754. // 母账户 -> 外部历史成交单
  755. rst, err = models.GetHisHedgeOutTradeDetails(req.AccountID, req.GoodsID, req.BuyOrSell, req.OrderID, req.StartDate, req.EndDate)
  756. if err != nil {
  757. // 查询失败
  758. logger.GetLogger().Errorf("QueryErmcpHisTradeDetails failed: %s", err.Error())
  759. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  760. return
  761. }
  762. } else {
  763. // 子账户 -> 内部历史成交单
  764. rst, err = models.GetHisHedgeInnerTradeDetails(req.AccountID, req.GoodsID, req.BuyOrSell, req.OrderID, req.StartDate, req.EndDate)
  765. if err != nil {
  766. // 查询失败
  767. logger.GetLogger().Errorf("QueryErmcpHisTradeDetails failed: %s", err.Error())
  768. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  769. return
  770. }
  771. }
  772. // 查询成功返回
  773. logger.GetLogger().Debugln("QueryErmcpHisTradeDetails successed: %v", rst)
  774. appG.Response(http.StatusOK, e.SUCCESS, rst)
  775. }