qryOrder.go 32 KB

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