qryOrder.go 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814
  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. // QueryErmcpInnerHolderDetailsReq 获取企业风管期货内部持仓单信息请求参数
  484. type QueryErmcpInnerHolderDetailsReq struct {
  485. AccountID int `form:"accountID" binding:"required"`
  486. GoodsID int `form:"goodsID"`
  487. BuyOrSell int `form:"buyOrSell"`
  488. }
  489. // QueryErmcpInnerHolderDetails 获取企业风管期货内部持仓单信息
  490. // @Summary 获取企业风管期货内部持仓单信息
  491. // @Produce json
  492. // @Security ApiKeyAuth
  493. // @Param accountID query int true "资金账户ID"
  494. // @Param goodsID query int false "商品ID"
  495. // @Param buyOrSell query int false "买卖方向,0:买 1:卖"
  496. // @Success 200 {object} models.Hedgeinnerholderdetail
  497. // @Failure 500 {object} app.Response
  498. // @Router /Ermcp/QueryErmcpInnerHolderDetails [get]
  499. // @Tags 企业风险管理(app)
  500. func QueryErmcpInnerHolderDetails(c *gin.Context) {
  501. appG := app.Gin{C: c}
  502. // 获取请求参数
  503. var req QueryErmcpInnerHolderDetailsReq
  504. if err := appG.C.ShouldBindQuery(&req); err != nil {
  505. logger.GetLogger().Errorf("QueryErmcpInnerHolderDetails failed: %s", err.Error())
  506. appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
  507. return
  508. }
  509. var r models.Hedgeinnerholderdetail
  510. rst, err := r.GetList(req.AccountID, req.GoodsID, req.BuyOrSell)
  511. if err != nil {
  512. logger.GetLogger().Errorf("QueryErmcpInnerHolderDetails failed: %s", err.Error())
  513. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  514. return
  515. }
  516. // 查询成功返回
  517. logger.GetLogger().Debugln("QueryErmcpInnerHolderDetails successed: %v", rst)
  518. appG.Response(http.StatusOK, e.SUCCESS, rst)
  519. }
  520. // QueryErmcpOrderDetailsReq 获取企业风管期货委托单信息请求参数
  521. type QueryErmcpOrderDetailsReq struct {
  522. AccountID int `form:"accountID" binding:"required"`
  523. }
  524. // QueryErmcpOrderDetails 获取企业风管期货委托单信息
  525. // @Summary 获取企业风管期货委托单信息
  526. // @Produce json
  527. // @Security ApiKeyAuth
  528. // @Param accountID query int true "资金账户ID"
  529. // @Success 200 {object} models.QueryHedgeOrderDetailRsp
  530. // @Failure 500 {object} app.Response
  531. // @Router /Ermcp/QueryErmcpOrderDetails [get]
  532. // @Tags 企业风险管理(app)
  533. func QueryErmcpOrderDetails(c *gin.Context) {
  534. appG := app.Gin{C: c}
  535. // 获取请求参数
  536. var req QueryErmcpOrderDetailsReq
  537. if err := appG.C.ShouldBindQuery(&req); err != nil {
  538. logger.GetLogger().Errorf("QueryErmcpOrderDetails failed: %s", err.Error())
  539. appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
  540. return
  541. }
  542. // 获取资金账户信息
  543. taAccount, err := models.GetTaAccountByID(req.AccountID)
  544. if err != nil {
  545. logger.GetLogger().Errorf("QueryErmcpOrderDetails failed: %s", err.Error())
  546. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  547. return
  548. }
  549. if taAccount == nil {
  550. logger.GetLogger().Errorf("QueryErmcpOrderDetails failed")
  551. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  552. return
  553. }
  554. rst := make([]models.QueryHedgeOrderDetailRsp, 0)
  555. if taAccount.Ismain == 1 {
  556. // 母账户 -> 外部委托单
  557. rst, err = models.GetHedgeOutOrderDetails(req.AccountID)
  558. if err != nil {
  559. // 查询失败
  560. logger.GetLogger().Errorf("QueryErmcpOrderDetails failed: %s", err.Error())
  561. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  562. return
  563. }
  564. } else {
  565. // 子账户 -> 内部委托单
  566. rst, err = models.GetHedgeInnerOrderDetails(req.AccountID)
  567. if err != nil {
  568. // 查询失败
  569. logger.GetLogger().Errorf("QueryErmcpOrderDetails failed: %s", err.Error())
  570. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  571. return
  572. }
  573. }
  574. // 查询成功返回
  575. logger.GetLogger().Debugln("QueryErmcpOrderDetails successed: %v", rst)
  576. appG.Response(http.StatusOK, e.SUCCESS, rst)
  577. }
  578. // QueryErmcpHisOrderDetailsReq 获取企业风管期货历史委托单信息请求参数
  579. type QueryErmcpHisOrderDetailsReq struct {
  580. AccountID int `form:"accountID" binding:"required"`
  581. StartDate string `form:"startDate"` // 开始时间
  582. EndDate string `form:"endDate"` // 结束时间
  583. }
  584. // QueryErmcpHisOrderDetails 获取企业风管期货历史委托单信息
  585. // @Summary 获取企业风管期货历史委托单信息
  586. // @Produce json
  587. // @Security ApiKeyAuth
  588. // @Param accountID query int true "资金账户ID"
  589. // @Param startDate query string false "开始时间 - 闭区间,格式:yyyy-MM-dd"
  590. // @Param endDate query string false "结束时间 - 闭区间,格式:yyyy-MM-dd"
  591. // @Success 200 {object} models.QueryHedgeOrderDetailRsp
  592. // @Failure 500 {object} app.Response
  593. // @Router /Ermcp/QueryErmcpHisOrderDetails [get]
  594. // @Tags 企业风险管理(app)
  595. func QueryErmcpHisOrderDetails(c *gin.Context) {
  596. appG := app.Gin{C: c}
  597. // 获取请求参数
  598. var req QueryErmcpHisOrderDetailsReq
  599. if err := appG.C.ShouldBindQuery(&req); err != nil {
  600. logger.GetLogger().Errorf("QueryErmcpHisOrderDetails failed: %s", err.Error())
  601. appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
  602. return
  603. }
  604. // 获取资金账户信息
  605. taAccount, err := models.GetTaAccountByID(req.AccountID)
  606. if err != nil {
  607. logger.GetLogger().Errorf("QueryErmcpHisOrderDetails failed: %s", err.Error())
  608. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  609. return
  610. }
  611. if taAccount == nil {
  612. logger.GetLogger().Errorf("QueryErmcpHisOrderDetails failed")
  613. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  614. return
  615. }
  616. rst := make([]models.QueryHedgeOrderDetailRsp, 0)
  617. if taAccount.Ismain == 1 {
  618. // 母账户 -> 外部历史委托单
  619. rst, err = models.GetHisHedgeOutOrderDetails(req.AccountID, req.StartDate, req.EndDate)
  620. if err != nil {
  621. // 查询失败
  622. logger.GetLogger().Errorf("QueryErmcpHisOrderDetails failed: %s", err.Error())
  623. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  624. return
  625. }
  626. } else {
  627. // 子账户 -> 内部历史委托单
  628. rst, err = models.GetHisHedgeInnerOrderDetails(req.AccountID, req.StartDate, req.EndDate)
  629. if err != nil {
  630. // 查询失败
  631. logger.GetLogger().Errorf("QueryErmcpHisOrderDetails failed: %s", err.Error())
  632. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  633. return
  634. }
  635. }
  636. // 查询成功返回
  637. logger.GetLogger().Debugln("QueryErmcpHisOrderDetails successed: %v", rst)
  638. appG.Response(http.StatusOK, e.SUCCESS, rst)
  639. }
  640. // QueryHedgeTradeDetailReq 获取企业风管期货成交单信息请求参数
  641. type QueryHedgeTradeDetailReq struct {
  642. AccountID int `form:"accountID" binding:"required"`
  643. GoodsID int `form:"goodsID"`
  644. BuyOrSell int `form:"buyOrSell"`
  645. OrderID int `form:"orderID"`
  646. }
  647. // QueryErmcpTradeDetails 获取企业风管期货成交单信息
  648. // @Summary 获取企业风管期货成交单信息
  649. // @Produce json
  650. // @Security ApiKeyAuth
  651. // @Param accountID query int true "资金账户ID"
  652. // @Param goodsID query int false "商品ID"
  653. // @Param buyOrSell query int false "买卖方向,0:买 1:卖"
  654. // @Param orderID query int false "关联委托单号"
  655. // @Success 200 {object} models.QueryHedgeTradeDetailRsp
  656. // @Failure 500 {object} app.Response
  657. // @Router /Ermcp/QueryErmcpTradeDetails [get]
  658. // @Tags 企业风险管理(app)
  659. func QueryErmcpTradeDetails(c *gin.Context) {
  660. appG := app.Gin{C: c}
  661. // 获取请求参数
  662. var req QueryHedgeTradeDetailReq
  663. if err := appG.C.ShouldBindQuery(&req); err != nil {
  664. logger.GetLogger().Errorf("QueryErmcpTradeDetails failed: %s", err.Error())
  665. appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
  666. return
  667. }
  668. // 获取资金账户信息
  669. taAccount, err := models.GetTaAccountByID(req.AccountID)
  670. if err != nil {
  671. logger.GetLogger().Errorf("QueryErmcpTradeDetails failed: %s", err.Error())
  672. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  673. return
  674. }
  675. if taAccount == nil {
  676. logger.GetLogger().Errorf("QueryErmcpTradeDetails failed")
  677. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  678. return
  679. }
  680. rst := make([]models.QueryHedgeTradeDetailRsp, 0)
  681. if taAccount.Ismain == 1 {
  682. // 母账户 -> 外部成交单
  683. rst, err = models.GetHedgeOutTradeDetails(req.AccountID, req.GoodsID, req.BuyOrSell, req.OrderID)
  684. if err != nil {
  685. // 查询失败
  686. logger.GetLogger().Errorf("QueryErmcpTradeDetails failed: %s", err.Error())
  687. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  688. return
  689. }
  690. } else {
  691. // 子账户 -> 内部成交单
  692. rst, err = models.GetHedgeInnerTradeDetails(req.AccountID, req.GoodsID, req.BuyOrSell, req.OrderID)
  693. if err != nil {
  694. // 查询失败
  695. logger.GetLogger().Errorf("QueryErmcpTradeDetails failed: %s", err.Error())
  696. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  697. return
  698. }
  699. }
  700. // 查询成功返回
  701. logger.GetLogger().Debugln("QueryErmcpTradeDetails successed: %v", rst)
  702. appG.Response(http.StatusOK, e.SUCCESS, rst)
  703. }
  704. // QueryHedgeHisTradeDetaislReq 获取企业风管期货历史成交单信息请求参数
  705. type QueryHedgeHisTradeDetaislReq struct {
  706. AccountID int `form:"accountID" binding:"required"`
  707. GoodsID int `form:"goodsID"`
  708. BuyOrSell int `form:"buyOrSell"`
  709. OrderID int `form:"orderID"`
  710. StartDate string `form:"startDate"` // 开始时间
  711. EndDate string `form:"endDate"` // 结束时间
  712. }
  713. // QueryErmcpHisTradeDetails 获取企业风管期货历史成交单信息
  714. // @Summary 获取企业风管期货历史成交单信息
  715. // @Produce json
  716. // @Security ApiKeyAuth
  717. // @Param accountID query int true "资金账户ID"
  718. // @Param goodsID query int false "商品ID"
  719. // @Param buyOrSell query int false "买卖方向,0:买 1:卖"
  720. // @Param orderID query int false "关联委托单号"
  721. // @Param startDate query string false "开始时间 - 闭区间,格式:yyyy-MM-dd"
  722. // @Param endDate query string false "结束时间 - 闭区间,格式:yyyy-MM-dd"
  723. // @Success 200 {object} models.QueryHedgeTradeDetailRsp
  724. // @Failure 500 {object} app.Response
  725. // @Router /Ermcp/QueryErmcpHisTradeDetails [get]
  726. // @Tags 企业风险管理(app)
  727. func QueryErmcpHisTradeDetails(c *gin.Context) {
  728. appG := app.Gin{C: c}
  729. // 获取请求参数
  730. var req QueryHedgeHisTradeDetaislReq
  731. if err := appG.C.ShouldBindQuery(&req); err != nil {
  732. logger.GetLogger().Errorf("QueryErmcpHisTradeDetails failed: %s", err.Error())
  733. appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
  734. return
  735. }
  736. // 获取资金账户信息
  737. taAccount, err := models.GetTaAccountByID(req.AccountID)
  738. if err != nil {
  739. logger.GetLogger().Errorf("QueryErmcpHisTradeDetails failed: %s", err.Error())
  740. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  741. return
  742. }
  743. if taAccount == nil {
  744. logger.GetLogger().Errorf("QueryErmcpHisTradeDetails failed")
  745. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  746. return
  747. }
  748. rst := make([]models.QueryHedgeTradeDetailRsp, 0)
  749. if taAccount.Ismain == 1 {
  750. // 母账户 -> 外部历史成交单
  751. rst, err = models.GetHisHedgeOutTradeDetails(req.AccountID, req.GoodsID, req.BuyOrSell, req.OrderID, req.StartDate, req.EndDate)
  752. if err != nil {
  753. // 查询失败
  754. logger.GetLogger().Errorf("QueryErmcpHisTradeDetails failed: %s", err.Error())
  755. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  756. return
  757. }
  758. } else {
  759. // 子账户 -> 内部历史成交单
  760. rst, err = models.GetHisHedgeInnerTradeDetails(req.AccountID, req.GoodsID, req.BuyOrSell, req.OrderID, req.StartDate, req.EndDate)
  761. if err != nil {
  762. // 查询失败
  763. logger.GetLogger().Errorf("QueryErmcpHisTradeDetails failed: %s", err.Error())
  764. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  765. return
  766. }
  767. }
  768. // 查询成功返回
  769. logger.GetLogger().Debugln("QueryErmcpHisTradeDetails successed: %v", rst)
  770. appG.Response(http.StatusOK, e.SUCCESS, rst)
  771. }