qryOrder.go 34 KB

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