ermcpExposure.go 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972
  1. /**
  2. * @Author: zou.yingbin
  3. * @Create : 2021/1/18 9:26
  4. * @Modify : 2021/1/18 9:26
  5. */
  6. package models
  7. import (
  8. "fmt"
  9. "github.com/golang/protobuf/proto"
  10. "mtp2_if/db"
  11. "mtp2_if/mtpcache"
  12. "mtp2_if/pb"
  13. "mtp2_if/rediscli"
  14. "mtp2_if/utils"
  15. )
  16. // ErmcpRealExposureModel 实时敞口
  17. type ErmcpRealExposureModel struct {
  18. MiddleGoodsID uint32 `json:"MiddleGoodsID" xorm:"'MiddleGoodsID'"` // 套保品种
  19. AreaUserID uint32 `json:"AreaUserID" xorm:"'AreaUserID'"` // 所属机构
  20. OriBuyPlanQty float64 `json:"OriBuyPlanQty" xorm:"'OriBuyPlanQty'"` // 期初采购计划数量
  21. OriBuyPricedQty float64 `json:"OriBuyPricedQty" xorm:"'OriBuyPricedQty'"` // 期初采购合同已定价数量
  22. OriSellPlanQty float64 `json:"OriSellPlanQty" xorm:"'OriSellPlanQty'"` // 期初销售计划数量
  23. OriSellPricedQty float64 `json:"OriSellPricedQty" xorm:"'OriSellPricedQty'"` // 期初销售合同已定价数量
  24. OriBuyFutureQty float64 `json:"OriBuyFutureQty" xorm:"'OriBuyFutureQty'"` // 期初买入期货数量
  25. OriSellFutureQty float64 `json:"OriSellFutureQty" xorm:"'OriSellFutureQty'"` // 期初卖出期货数量
  26. BuyPlanQty float64 `json:"BuyPlanQty" xorm:"'BuyPlanQty'"` // 采购计划数量
  27. BuyPricedQty float64 `json:"BuyPricedQty" xorm:"'BuyPricedQty'"` // 采购合同已定价数量
  28. SellPlanQty float64 `json:"SellPlanQty" xorm:"'SellPlanQty'"` // 销售计划数量
  29. SellPricedQty float64 `json:"SellPricedQty" xorm:"'SellPricedQty'"` // 销售合同已定价数量
  30. BuyFutureQty float64 `json:"BuyFutureQty" xorm:"'BuyFutureQty'"` // 买入期货数量
  31. SellFutureQty float64 `json:"SellFutureQty" xorm:"'SellFutureQty'"` // 卖出期货数量
  32. TotalSpotQty float64 `json:"TotalSpotQty" xorm:"'TotalSpotQty'"` // 现货总量 平安:采销定价净值
  33. TotalFutureQty float64 `json:"TotalFutureQty" xorm:"'TotalFutureQty'"` // 期货总量 平安:保值净持仓量
  34. TotalExposure float64 `json:"TotalExposure" xorm:"'TotalExposure'"` // 总敞口 平安:净敞口
  35. TotalHedgeRatio float64 `json:"TotalHedgeRatio" xorm:"'TotalHedgeRatio'"` // 敞口比例
  36. TotalNeedHedgeQty float64 `json:"TotalNeedHedgeQty" xorm:"'TotalNeedHedgeQty'"` // 应套保总量(现货应套保总量)
  37. NeedHedgeExposoure float64 `json:"NeedHedgeExposoure" xorm:"'NeedHedgeExposoure'"` // 应套保敞口(套保敞口)
  38. NeedHedgeRatio float64 `json:"NeedHedgeRatio" xorm:"'NeedHedgeRatio'"` // 应套保敞口比例
  39. GOODSUNITID int32 `json:"-" xorm:"'GOODSUNITID'"` // 品种单位ID
  40. MiddleGoodsName string `json:"MiddleGoodsName" xorm:"'MiddleGoodsName'"` // 套保品种名称
  41. MiddleGoodsCode string `json:"MiddleGoodsCode" xorm:"'MiddleGoodsCode'"` // 套保品种代码
  42. MiddleGoodsHedgeRatio float64 `json:"MiddleGoodsHedgeRatio" xorm:"'needhedgeratio'"` // 套保比例
  43. NEEDARBITRAGEQTY float64 `json:"needarbitrageqty" xorm:"'NEEDARBITRAGEQTY'"` // 应套利量
  44. NEEDHEDGEQTY float64 `json:"needhedgeqty" xorm:"'NEEDHEDGEQTY'"` // 应套保量
  45. HEDGEQTY float64 `json:"hedgeqty" xorm:"'hedgeqty'"` // 套保量
  46. ARBITRAGEQTY float64 `json:"arbitrageqty" xorm:"'arbitrageqty'"` // 套利量
  47. NEEDARBITRAGERATIO float64 `json:"needarbitrageratio" xorm:"'needarbitrageratio'"` // 套利比例
  48. ORIHEDGEQTY float64 `json:"orihedgeqty" xorm:"'ORIHEDGEQTY'"` // 期初套保量
  49. ORIARBITRAGEQTY float64 `json:"oriarbitrageqty" xorm:"'ORIARBITRAGEQTY'"` // 期初套利量
  50. ORITOTALNEEDHEDGEQTY float64 `json:"oritotalneedhedgeqty" xorm:"'ORITOTALNEEDHEDGEQTY'"` // 期初现货应套保量
  51. ORITOTALFUTUREQTY float64 `json:"oritotalfutureqty" xorm:"'ORITOTALFUTUREQTY'"` // 期初期货总量
  52. ORINEEDHEDGEEXPOSOURE float64 `json:"orineedhedgeexposoure" xorm:"'ORINEEDHEDGEEXPOSOURE'"` // 期初套保敞口
  53. ORITOTALEXPOSURE float64 `json:"oritotalexposure" xorm:"'ORITOTALEXPOSURE'"` // 期初总敞口
  54. ORITOTALSPOTQTY float64 `json:"OriTotalSpotQty" xorm:"'ORITOTALSPOTQTY'"` // 期初现货总量
  55. ENUMDICNAME string // 单位名称
  56. DiffSpotQty SFLOAT64 // 变动量(现货总量) = 现货数量 - 期初现货数量 平安:采销定价净值今日变动
  57. DiffFutuQty SFLOAT64 // 变动量(期货总量) 平安:保值净持仓量今日变动
  58. DiffHedgeQty SFLOAT64 // 套保变动量
  59. DiffArbitrageQty SFLOAT64 // 套利变动量
  60. DiffSpotHedgeQty SFLOAT64 // 变动量(现货应套保总量) 平安:应套保量今日变动
  61. DiffExposoureQty SFLOAT64 // 变动量(套保敞口)
  62. DiffQty SFLOAT64 // 变动量(总敞口) 平安:净敞口今日变动
  63. }
  64. // calc 计算相关字段
  65. func (r *ErmcpRealExposureModel) calc() {
  66. r.DiffSpotQty.Set(r.TotalSpotQty - r.ORITOTALSPOTQTY)
  67. r.DiffSpotQty.Round(2)
  68. r.DiffFutuQty.Set(r.TotalFutureQty - r.ORITOTALFUTUREQTY)
  69. r.DiffFutuQty.Round(2)
  70. r.DiffHedgeQty.Set(r.HEDGEQTY - r.ORIHEDGEQTY)
  71. r.DiffHedgeQty.Round(2)
  72. r.DiffArbitrageQty.Set(r.ARBITRAGEQTY - r.ORIARBITRAGEQTY)
  73. r.DiffArbitrageQty.Round(2)
  74. r.DiffSpotHedgeQty.Set(r.TotalNeedHedgeQty - r.ORITOTALNEEDHEDGEQTY)
  75. r.DiffSpotHedgeQty.Round(2)
  76. r.DiffExposoureQty.Set(r.NeedHedgeExposoure - r.ORINEEDHEDGEEXPOSOURE)
  77. r.DiffExposoureQty.Round(2)
  78. r.DiffQty.Set(r.TotalExposure - r.ORITOTALEXPOSURE)
  79. r.DiffQty.Round(2)
  80. if r.ENUMDICNAME == "" {
  81. r.ENUMDICNAME = mtpcache.GetEnumDicitemName(r.GOODSUNITID)
  82. }
  83. }
  84. func (r *ErmcpRealExposureModel) buildSql() string {
  85. var sqlId utils.SQLVal = "select t.MiddleGoodsID," +
  86. " t.AreaUserID," +
  87. " t.OriBuyPlanQty," +
  88. " t.OriBuyPricedQty," +
  89. " t.OriSellPlanQty," +
  90. " t.OriSellPricedQty," +
  91. " t.OriBuyFutureQty," +
  92. " t.OriSellFutureQty," +
  93. " t.BuyPlanQty," +
  94. " t.BuyPricedQty," +
  95. " t.SellPlanQty," +
  96. " t.SellPricedQty," +
  97. " t.BuyFutureQty," +
  98. " t.SellFutureQty," +
  99. " t.TotalSpotQty," +
  100. " t.TotalFutureQty," +
  101. " t.TotalExposure," +
  102. " t.TotalHedgeRatio," +
  103. " t.TotalNeedHedgeQty," +
  104. " t.NeedHedgeExposoure," +
  105. " t.NeedHedgeRatio," +
  106. " g.middlegoodsname," +
  107. " g.middlegoodscode," +
  108. " g.goodsunitid," +
  109. " g.needhedgeratio," +
  110. " t.needarbitrageqty," +
  111. " t.needhedgeqty," +
  112. " t.hedgeqty," +
  113. " t.arbitrageqty," +
  114. " t.orihedgeqty," +
  115. " t.oriarbitrageqty," +
  116. " t.oritotalneedhedgeqty," +
  117. " t.oritotalfutureqty," +
  118. " t.orineedhedgeexposoure," +
  119. " t.oritotalexposure," +
  120. " t.ORITOTALSPOTQTY," +
  121. " g.needarbitrageratio" +
  122. " from ermcp_areaexposure t" +
  123. " left join erms_middlegoods g" +
  124. " on t.middlegoodsid = g.middlegoodsid" +
  125. " where 1 = 1"
  126. sqlId.And("t.AreaUserID", r.AreaUserID)
  127. return sqlId.String()
  128. }
  129. // ParseFromProto 从协议中获取数据
  130. func (r *ErmcpRealExposureModel) ParseFromProto(v *pb.ErmcpAreaExposure) {
  131. r.MiddleGoodsID = *v.MiddleGoodsID
  132. r.AreaUserID = *v.AreaUserID
  133. r.OriBuyPlanQty = *v.OriBuyPlanQty
  134. r.OriBuyPricedQty = *v.OriBuyPricedQty
  135. r.OriSellPlanQty = *v.OriSellPlanQty
  136. r.OriSellPricedQty = *v.OriSellPricedQty
  137. r.OriBuyFutureQty = float64(*v.OriBuyFutureQty)
  138. r.OriSellFutureQty = float64(*v.OriSellFutureQty)
  139. r.BuyPlanQty = *v.BuyPlanQty
  140. r.BuyPricedQty = *v.BuyPricedQty
  141. r.SellPlanQty = *v.SellPlanQty
  142. r.SellPricedQty = *v.SellPricedQty
  143. r.BuyFutureQty = *v.BuyFutureQty
  144. r.SellFutureQty = *v.SellFutureQty
  145. r.TotalSpotQty = *v.TotalSpotQty
  146. r.TotalFutureQty = *v.TotalFutureQty
  147. r.TotalExposure = *v.TotalExposure
  148. r.TotalHedgeRatio = *v.TotalHedgeRatio
  149. r.TotalNeedHedgeQty = *v.TotalNeedHedgeQty
  150. r.NeedHedgeExposoure = *v.NeedHedgeExposoure
  151. r.NeedHedgeRatio = *v.NeedHedgeRatio
  152. // 执行相关计算
  153. r.calc()
  154. }
  155. // GetData 实时敞口数据: Redis数据 + 套保品种信息表
  156. func (r *ErmcpRealExposureModel) GetData() ([]ErmcpRealExposureModel, error) {
  157. // 获取关联的套路商品
  158. if sGoods, err := mtpcache.GetMiddleGoodsByUserID(r.AreaUserID); err == nil {
  159. sData := make([]ErmcpRealExposureModel, 0)
  160. // 从Redis获取数据
  161. for i := range sGoods {
  162. key := fmt.Sprintf("ErmcpAreaExposure:%d_%d", sGoods[i].AREAUSERID, sGoods[i].MIDDLEGOODSID)
  163. if ret, err := rediscli.GetRedisClient().Get(key).Result(); err == nil {
  164. if len(ret) > 0 {
  165. var data pb.ErmcpAreaExposure
  166. if err := proto.Unmarshal([]byte(ret), &data); err == nil {
  167. var m = ErmcpRealExposureModel{MiddleGoodsName: sGoods[i].MIDDLEGOODSNAME,
  168. MiddleGoodsCode: sGoods[i].MIDDLEGOODSCODE, MiddleGoodsHedgeRatio: sGoods[i].NEEDHEDGERATIO,
  169. ENUMDICNAME: mtpcache.GetEnumDicitemName(sGoods[i].GOODSUNITID)}
  170. m.ParseFromProto(&data)
  171. sData = append(sData, m)
  172. }
  173. }
  174. }
  175. }
  176. return sData, nil
  177. }
  178. return nil, nil
  179. }
  180. // GetDataEx 从数据库中查询实时敞口
  181. func (r *ErmcpRealExposureModel) GetDataEx() (interface{}, error) {
  182. sData := make([]ErmcpRealExposureModel, 0)
  183. err := db.GetEngine().SQL(r.buildSql()).Find(&sData)
  184. for i := range sData {
  185. sData[i].calc()
  186. }
  187. return sData, err
  188. }
  189. /*************敞口明细**************/
  190. // ErmcpExposureDetailModel 敞口现货明细结构
  191. type ErmcpExposureDetailModel struct {
  192. Createtime string `json:"createtime" xorm:"'createtime'"` // 时间
  193. Areauserid uint32 `json:"areauserid" xorm:"'areauserid'"` // 机构ID
  194. Logtype int32 `json:"logtype" xorm:"'logtype'"` // 类型 - 1:套保计划 2:现货合同
  195. Contracttype int32 `json:"contracttype" xorm:"'contracttype'"` // 现货合同类型 - 1:采购 -1:销售
  196. Wrstandardid int32 `json:"wrstandardid" xorm:"'wrstandardid'"` // 现货商品ID
  197. Qty float64 `json:"qty" xorm:"'qty'"` // 数量
  198. RelateNo string `json:"relateNo" xorm:"'relateNo'"` // 现货合同/套保计划编号
  199. Middlegoodsname string `json:"middlegoodsname" xorm:"'middlegoodsname'"` // 套保商品名称
  200. Middlegoodscode string `json:"middlegoodscode" xorm:"'middlegoodscode'"` // 套保商品代码
  201. MiddlegoodsId int32 `json:"middlegoodsId" xorm:"'middlegoodsId'"` // 套保商品id
  202. Unitid int32 `json:"-" xorm:"'unitid'"` // 现货商品单位ID
  203. Wrstandardname string `json:"wrstandardname" xorm:"'wrstandardname'"` // 现货商品名称
  204. Wrstandardcode string `json:"wrstandardcode" xorm:"'wrstandardcode'"` // 现货商品代码
  205. Enumdicname string `json:"enumdicname" xorm:"'enumdicname'"` // 现货商品单位名称
  206. ChangeQty float64 `json:"changeQty" xorm:"'changeQty'"` // 套保变动量
  207. Convertfactor float64 `json:"convertfactor" xorm:"'convertfactor'"` // 标仓系数
  208. Convertratio float64 `json:"convertratio" xorm:"'convertratio'"` // 套保系数
  209. }
  210. func (r *ErmcpExposureDetailModel) buildSql() string {
  211. str := "with tmp as" +
  212. " (select 2 as LogType," +
  213. " s.spotcontractid as relatedid," +
  214. " s.contractno as relateNo," +
  215. " s.qty " +
  216. " from ermcp_spotcontract s" +
  217. " union all" +
  218. " select 1, t.hedgeplanid as relateid, t.hedgeplanno as relateNo, t.planqty as qty " +
  219. " from ermcp_hedgeplan t)" +
  220. "select to_char(t.createtime, 'yyyy-mm-dd hh24:mi:ss') createtime," +
  221. " t.middlegoodsid," +
  222. " t.areauserid," +
  223. " t.logtype," +
  224. " t.contracttype," +
  225. " wc.wrstandardid," +
  226. " t.qty / t.convertfactor / t.convertratio as qty," +
  227. " t.convertfactor," +
  228. " t.convertratio," +
  229. " t.qty changeQty," +
  230. " tmp.relateNo," +
  231. " m.middlegoodsname," +
  232. " m.middlegoodscode," +
  233. " w.unitid," +
  234. " w.wrstandardname," +
  235. " w.wrstandardcode," +
  236. " e.enumdicname" +
  237. " from ermcp_spotexposurelog t" +
  238. " left join erms2_wrsconvertdetail wc" +
  239. " on t.wrstandardid = wc.wrstandardid" +
  240. " and t.middlegoodsid = wc.middlegoodsid" +
  241. " left join erms_middlegoods m" +
  242. " on t.middlegoodsid = m.middlegoodsid" +
  243. " left join wrstandard w" +
  244. " on t.wrstandardid = w.wrstandardid" +
  245. " left join enumdicitem e" +
  246. " on w.unitid = e.enumitemname" +
  247. " and e.enumdiccode = 'goodsunit'" +
  248. " left join tmp" +
  249. " on t.logtype = tmp.LogType" +
  250. " and t.relatedid = tmp.relatedid" +
  251. " where t.middlegoodsid=%v and t.areauserid=%v and t.tradedate=to_char(sysdate, 'yyyymmdd')"
  252. return fmt.Sprintf(str, r.MiddlegoodsId, r.Areauserid)
  253. }
  254. // Calc 处理数据
  255. func (r *ErmcpExposureDetailModel) Calc() {
  256. // 销售合同转换为负数
  257. if r.Logtype == 2 && r.Contracttype == -1 {
  258. r.ChangeQty *= -1
  259. r.Qty *= -1
  260. }
  261. // 采购计划 转换为负数
  262. if r.Logtype == 1 && r.Contracttype == 1 {
  263. r.ChangeQty *= -1
  264. r.Qty *= -1
  265. }
  266. }
  267. // GetData 查询敞口现货明细
  268. func (r *ErmcpExposureDetailModel) GetData() ([]ErmcpExposureDetailModel, error) {
  269. e := db.GetEngine()
  270. s := e.SQL(r.buildSql())
  271. sData := make([]ErmcpExposureDetailModel, 0)
  272. if err := s.Find(&sData); err != nil {
  273. return nil, err
  274. }
  275. for i := range sData {
  276. sData[i].Calc()
  277. }
  278. return sData, nil
  279. }
  280. /// 现货头寸
  281. // AreaSpotModel 现货头寸数据
  282. type AreaSpotModel struct {
  283. WRSTANDARDID int32 `json:"wrstandardid" xorm:"'WRSTANDARDID'"` // 现货商品ID
  284. WRSTANDARDNAME string `json:"wrstandardname" xorm:"'WRSTANDARDNAME'"` // 现货品种
  285. WRSTANDARDCODE string `json:"wrstandardcode" xorm:"'WRSTANDARDCODE'"` // 现货品种代码
  286. AREAUSERID int32 `json:"areauserid" xorm:"'AREAUSERID'"` // 所属机构
  287. ORIBUYPLANQTY float64 `json:"-" xorm:"'ORIBUYPLANQTY'"` // 期初采购计划数量
  288. ORIBUYPRICEDQTY float64 `json:"-" xorm:"'ORIBUYPRICEDQTY'"` // 期初采购合同已定价数量
  289. ORISELLPLANQTY float64 `json:"-" xorm:"'ORISELLPLANQTY'"` // 期初销售计划数量
  290. ORISELLPRICEDQTY float64 `json:"-" xorm:"'ORISELLPRICEDQTY'"` // 期初销售合同已定价数量
  291. BUYPLANQTY float64 `json:"-" xorm:"'BUYPLANQTY'"` // 采购计划数量
  292. BUYPRICEDQTY float64 `json:"-" xorm:"'BUYPRICEDQTY'"` // 采购合同已定价数量
  293. SELLPLANQTY float64 `json:"-" xorm:"'SELLPLANQTY'"` // 销售计划数量
  294. SELLPRICEDQTY float64 `json:"-" xorm:"'SELLPRICEDQTY'"` // 销售合同已定价数量
  295. TOTALSPOTQTY float64 `json:"totalspotqty" xorm:"'TOTALSPOTQTY'"` // 当前数量(现货头寸总量) = (销售计划数量 - 销售已定价数量) - (采购计划数量 - 采购已定价数量)
  296. OriToalSpotQty float64 `json:"oritoalspotqty" xorm:"'OriToalSpotQty'"` // 昨日数量
  297. IncreaseQty float64 `json:"increaseqty" xorm:"'IncreaseQty'"` // 增加数量=销售计划数量+采购已定价数量
  298. DecreaseQty float64 `json:"decreaseqty" xorm:"'DecreaseQty'"` // 减少数量=-(销售已定价数量+采购计划数量)
  299. UPDATETIME string `json:"updatetime" xorm:"'UPDATETIME'"` // 更新时间
  300. }
  301. // calc 进行相关字段的值计算
  302. func (r *AreaSpotModel) calc() {
  303. /*
  304. 增加数量=今日销售计划数量+今日采购已定价数量
  305. 减少数量=-(今日销售已定价数量+今日采购计划数量)
  306. 其中,
  307. 今日销售计划数量=期末销售计划数量-期初销售计划数量
  308. 今日采购已定价数量=期末采购已定价数量-期初采购已定价数量
  309. 今日销售已定价数量=期末销售已定价数量-期初销售已定价数量
  310. 今日采购计划数量=期末采购计划数量-期初采购计划数量
  311. */
  312. r.IncreaseQty = r.SELLPLANQTY - r.ORISELLPLANQTY + r.BUYPRICEDQTY - r.ORIBUYPRICEDQTY
  313. r.DecreaseQty = (r.SELLPRICEDQTY - r.ORISELLPRICEDQTY + r.BUYPLANQTY - r.ORIBUYPLANQTY) * -1
  314. r.OriToalSpotQty = (r.ORISELLPLANQTY - r.ORISELLPRICEDQTY) - (r.ORIBUYPLANQTY - r.ORIBUYPRICEDQTY)
  315. }
  316. func (r *AreaSpotModel) buildSql() string {
  317. str := "select t.WRSTANDARDID," +
  318. " w.WRSTANDARDNAME," +
  319. " w.WRSTANDARDCODE," +
  320. " t.AREAUSERID," +
  321. " t.ORIBUYPLANQTY," +
  322. " t.ORIBUYPRICEDQTY," +
  323. " t.ORISELLPLANQTY," +
  324. " t.ORISELLPRICEDQTY," +
  325. " t.BUYPLANQTY," +
  326. " t.BUYPRICEDQTY," +
  327. " t.SELLPLANQTY," +
  328. " t.SELLPRICEDQTY," +
  329. " t.TOTALSPOTQTY," +
  330. " to_char(t.UPDATETIME,'yyyy-mm-dd hh24:mi:ss') UPDATETIME" +
  331. " from ermcp_areaspot t" +
  332. " left join wrstandard w" +
  333. " on t.wrstandardid = w.wrstandardid" +
  334. " where t.areauserid=%v"
  335. return fmt.Sprintf(str, r.AREAUSERID)
  336. }
  337. // GetData 从数据库中查询现货头寸
  338. func (r *AreaSpotModel) GetData() ([]AreaSpotModel, error) {
  339. e := db.GetEngine()
  340. sData := make([]AreaSpotModel, 0)
  341. if err := e.SQL(r.buildSql()).Find(&sData); err != nil {
  342. return nil, err
  343. }
  344. for i := range sData {
  345. sData[i].calc()
  346. }
  347. return sData, nil
  348. }
  349. // ErmcpAreaSpotDetailModel 现货头寸-现货明细
  350. type ErmcpAreaSpotDetailModel struct {
  351. Relatedid string `json:"relatedid" xorm:"'relatedid'"` // 套保计划ID/现货合同ID
  352. Relatedno string `json:"relatedno" xorm:"'relatedno'"` // 编号
  353. LogType int32 `json:"logtype" xorm:"'logType'"` // 记录类型 1-套保 2-现货合同
  354. Contracttype int32 `json:"contracttype" xorm:"'contracttype'"` // 合同类型 1-采购 -1-销售
  355. Wrstandardname string `json:"wrstandardname" xorm:"'wrstandardname'"` // 现货商品名称
  356. Wrstandardcode string `json:"wrstandardcode" xorm:"'wrstandardcode'"` // 现货商品代码
  357. Qty float64 `json:"qty" xorm:"'qty'"` // 数量
  358. Strtime string `json:"strtime" xorm:"'strtime'"` // 时间
  359. Enumdicname string `json:"enumdicname"` // 现货商品单位名称
  360. Recordname string `json:"recordname"` // 类型名称
  361. CREATETIME string `json:"createtime" xorm:"'CREATETIME'"` // 创建时间
  362. Unitid int32 `json:"-" xorm:"'UNITID'"` // 单位ID
  363. UserId int `json:"-"` // 所属用户ID
  364. WrstandardId int32 `json:"-"` // 现货商品ID
  365. }
  366. // buildSql 组建查询SQL(只查当前日期的)
  367. func (r *ErmcpAreaSpotDetailModel) buildSql() string {
  368. str := "with tmp as" +
  369. " (select to_char(t.hedgeplanid) relatedid," +
  370. " t.hedgeplanno relatedno," +
  371. " 1 as logType," +
  372. " t.contracttype" +
  373. " from ermcp_hedgeplan t" +
  374. " where t.areauserid = %v" +
  375. " and t.wrstandardid = %v" +
  376. " union all " +
  377. " select to_char(t.spotcontractid)," +
  378. " t.contractno," +
  379. " 2 as logType," +
  380. " t.contracttype" +
  381. " from ermcp_spotcontract t" +
  382. " where t.userid = %v" +
  383. " and t.wrstandardid = %v)" +
  384. "select t.relatedid," +
  385. " tmp.relatedno," +
  386. " t.LogType," +
  387. " tmp.contracttype," +
  388. " t.RealQty qty," +
  389. " to_char(t.createtime, 'yyyy-mm-dd hh24:mi:ss') createtime," +
  390. " w.wrstandardname," +
  391. " w.wrstandardcode," +
  392. " w.unitid" +
  393. " from ermcp_spotlog t" +
  394. " inner join tmp" +
  395. " on t.LogType = tmp.logType" +
  396. " and t.relatedid = tmp.relatedid" +
  397. " and t.areauserid = %v" +
  398. " and t.wrstandardid = %v" +
  399. " left join wrstandard w" +
  400. " on t.wrstandardid = w.wrstandardid" +
  401. " where t.tradedate=to_char(sysdate, 'yyyymmdd')"
  402. return fmt.Sprintf(str, r.UserId, r.WrstandardId, r.UserId, r.WrstandardId, r.UserId, r.WrstandardId)
  403. }
  404. // Calc 现货头寸-明细:数据加工处理
  405. func (r *ErmcpAreaSpotDetailModel) Calc() {
  406. var logTypeName, contractTypeName string
  407. if r.LogType == 1 {
  408. logTypeName = "计划"
  409. } else {
  410. logTypeName = "合同"
  411. }
  412. if r.Contracttype == 1 {
  413. contractTypeName = "采购"
  414. } else {
  415. contractTypeName = "销售"
  416. }
  417. // 销售合同 数量转为负数
  418. if r.LogType == 2 && r.Contracttype == -1 {
  419. if r.Qty > 0 {
  420. r.Qty = r.Qty * -1
  421. }
  422. }
  423. // 采购计划 数量转为负数
  424. if r.LogType == 1 && r.Contracttype == 1 {
  425. if r.Qty > 0 {
  426. r.Qty = r.Qty * -1
  427. }
  428. }
  429. r.Recordname = contractTypeName + logTypeName
  430. r.Enumdicname = mtpcache.GetEnumDicitemName(r.Unitid)
  431. }
  432. // GetData 现货头寸-明细:从数据库中查询敞口现货头寸明细数据
  433. func (r *ErmcpAreaSpotDetailModel) GetData() ([]interface{}, error) {
  434. sData := make([]ErmcpAreaSpotDetailModel, 0)
  435. err := db.GetEngine().SQL(r.buildSql()).Find(&sData)
  436. iDatas := make([]interface{}, 0)
  437. for i := range sData {
  438. // 注意要传指针类型(&sData[i]),因为要接口转换
  439. iDatas = append(iDatas, &sData[i])
  440. }
  441. return iDatas, err
  442. }
  443. ///////////////////////////
  444. // ErmcpHisExposure 历史/历史敞口
  445. type ErmcpHisExposure struct {
  446. RECKONDATE string `json:"reckondate" xorm:"'RECKONDATE'"` // 日照时期(yyyyMMdd)
  447. MIDDLEGOODSID int32 `json:"-" xorm:"'MIDDLEGOODSID'"` // 套保品种ID
  448. AREAUSERID int32 `json:"-" xorm:"'AREAUSERID'"` // 所属机构
  449. TOTALEXPOSURE float64 `json:"totalexposure" xorm:"'TOTALEXPOSURE'"` // 总敞口
  450. NEEDHEDGEEXPOSOURE float64 `json:"needhedgeexposoure" xorm:"'NEEDHEDGEEXPOSOURE'"` // 应套保敞口
  451. MIDDLEGOODSNAME string `json:"-" xorm:"'MIDDLEGOODSNAME'"` // 套保品种名称
  452. MIDDLEGOODSCODE string `json:"-" xorm:"'MIDDLEGOODSCODE'"` // 套保品种代码
  453. GOODSUNITID int32 `json:"-" xorm:"'GOODSUNITID'"` // 套保品种单位id
  454. LastNum int32 `json:"-"` // 查询条数
  455. }
  456. // ErmcpHisExposureS 历史分品种嵌套结构
  457. type ErmcpHisExposureS struct {
  458. MIDDLEGOODSID int32 `json:"middlegoodsid"` // 套保品种ID
  459. MIDDLEGOODSNAME string `json:"middlegoodsname"` // 套保品种名称
  460. MIDDLEGOODSCODE string `json:"middlegoodscode"` // 套保品种代码
  461. ENUMDICNAME string `json:"enumdicname"` // 单位名称
  462. Data []ErmcpHisExposure `json:"data"` // 历史敞口
  463. }
  464. func (r *ErmcpHisExposure) buildSql() string {
  465. str := "select a.*, g.middlegoodsname, g.middlegoodscode, g.goodsunitid from (" +
  466. "select t.middlegoodsid," +
  467. " t.areauserid," +
  468. " t.totalexposure," +
  469. " t.needhedgeexposoure," +
  470. " t.reckondate" +
  471. " from RECKON_ERMCP_AREAEXPOSURE t" +
  472. " inner join RECKON_ERMCP_AREAEXPOSURE t2" +
  473. " on t.middlegoodsid = t2.middlegoodsid" +
  474. " and t.reckondate <= t2.reckondate" +
  475. " where t.areauserid=%v" +
  476. " group by t.middlegoodsid," +
  477. " t.areauserid," +
  478. " t.reckondate," +
  479. " t.totalexposure," +
  480. " t.needhedgeexposoure" +
  481. " having count(1) <= %v" +
  482. " order by t.middlegoodsid, t.reckondate desc" +
  483. ")a left join erms_middlegoods g on a.middlegoodsid=g.middlegoodsid"
  484. if r.LastNum <= 0 {
  485. r.LastNum = 1000 //限制最多查1000条(每个品种)
  486. }
  487. return fmt.Sprintf(str, r.AREAUSERID, r.LastNum)
  488. }
  489. // GetData 获取历史敞口
  490. func (r *ErmcpHisExposure) GetData() ([]ErmcpHisExposureS, error) {
  491. e := db.GetEngine()
  492. sData := make([]ErmcpHisExposure, 0)
  493. if err := e.SQL(r.buildSql()).Find(&sData); err != nil {
  494. return nil, err
  495. }
  496. // 按套保品种合并处理
  497. mData := make(map[int32]*[]ErmcpHisExposure)
  498. for i := range sData {
  499. if v, ok := mData[sData[i].MIDDLEGOODSID]; ok {
  500. *v = append(*v, sData[i])
  501. } else {
  502. d := make([]ErmcpHisExposure, 0)
  503. d = append(d, sData[i])
  504. mData[sData[i].MIDDLEGOODSID] = &d
  505. }
  506. }
  507. lst := make([]ErmcpHisExposureS, 0)
  508. for _, v := range mData {
  509. if len(*v) >= 1 {
  510. val := ErmcpHisExposureS{
  511. MIDDLEGOODSID: (*v)[0].MIDDLEGOODSID,
  512. MIDDLEGOODSCODE: (*v)[0].MIDDLEGOODSCODE,
  513. MIDDLEGOODSNAME: (*v)[0].MIDDLEGOODSNAME,
  514. ENUMDICNAME: mtpcache.GetEnumDicitemName((*v)[0].GOODSUNITID),
  515. }
  516. // 旧的敞口数据找不到对应的套保商品
  517. if val.MIDDLEGOODSCODE == "" {
  518. continue
  519. }
  520. for i := range *v {
  521. val.Data = append(val.Data, (*v)[i])
  522. }
  523. lst = append(lst, val)
  524. }
  525. }
  526. return lst, nil
  527. }
  528. // ErmcpTradeGoods 套保品种关联交易商品
  529. type ErmcpTradeGoods struct {
  530. MIDDLEGOODSID int32 `json:"middlegoodsid" xorm:"'MIDDLEGOODSID'"` // 套保商品id
  531. MIDDLEGOODSNAME string `json:"middlegoodsname" xorm:"'MIDDLEGOODSNAME'"` // 套保商品名称
  532. MIDDLEGOODSCODE string `json:"middlegoodscode" xorm:"'MIDDLEGOODSCODE'"` // 套保商品代码
  533. SRCGOODSGROUPID int32 `json:"srcgoodsgroupid" xorm:"'SRCGOODSGROUPID'"` // 源期货品种id
  534. DESTGOODSGROUPID int32 `json:"destgoodsgroupid" xorm:"'DESTGOODSGROUPID'"` // 目标期货品种id
  535. CONVERTRATIO float64 `json:"convertratio" xorm:"'CONVERTRATIO'"` // 折算系数
  536. GOODSID int32 `json:"goodsid" xorm:"pk 'GOODSID'"` // 商品id
  537. GOODSCODE string `json:"goodscode" xorm:"'GOODSCODE'"` // 商品代码
  538. GOODSNAME string `json:"goodsname" xorm:"'GOODSNAME'"` // 商品名称
  539. GOODSGROUPID int32 `json:"goodsgroupid" xorm:"'GOODSGROUPID'"` // 商品组id
  540. GOODSUNITID int32 `json:"goodsunitid" xorm:"'GOODSUNITID'"` // 套保品种单位id
  541. AREAUSERID int64 `json:"areauserid" xorm:"'AREAUSERID'"` // 所属机构id
  542. AGREEUNIT float64 `json:"agreeunit" xorm:"'agreeunit'"` // 合约单位
  543. }
  544. func (r *ErmcpTradeGoods) buildSq() string {
  545. sqlId := "SELECT t.MIDDLEGOODSID," +
  546. " t.MIDDLEGOODSNAME," +
  547. " t.MIDDLEGOODSCODE," +
  548. " t.GOODSUNITID," +
  549. " t.AREAUSERID," +
  550. " c.SRCGOODSGROUPID," +
  551. " c.DESTGOODSGROUPID," +
  552. " c.CONVERTRATIO," +
  553. " g.GOODSID," +
  554. " g.GOODSCODE," +
  555. " g.GOODSNAME," +
  556. " g.GOODSGROUPID," +
  557. " g.AGREEUNIT" +
  558. " FROM ERMS_MIDDLEGOODS t" +
  559. " INNER JOIN ERMCP_GGCONVERTCONFIG c" +
  560. " ON t.GOODSGROUPID = c.DESTGOODSGROUPID" +
  561. " INNER JOIN GOODS g" +
  562. " ON c.SRCGOODSGROUPID = g.GOODSGROUPID" +
  563. " WHERE t.AREAUSERID = %v" +
  564. " AND t.MIDDLEGOODSID = %v"
  565. sqlId = fmt.Sprintf(sqlId, r.AREAUSERID, r.MIDDLEGOODSID)
  566. return sqlId
  567. }
  568. // GetData 获取套保商品关联的交易商品
  569. func (r *ErmcpTradeGoods) GetData() (map[int32]*ErmcpTradeGoods, error) {
  570. mData := make(map[int32]*ErmcpTradeGoods, 0)
  571. err := db.GetEngine().SQL(r.buildSq()).Find(&mData)
  572. return mData, err
  573. }
  574. // ErmcpTradePosition 获取用户头寸(子账户)
  575. type ErmcpTradePosition struct {
  576. USERID int64 `json:"userid" xorm:"'userid'"` // 用户id
  577. GOODSID int32 `json:"goodsid" xorm:"'goodsid'"` // 商品id
  578. BUYPOSITIONQTY int64 `json:"buypositionqty" xorm:"'Buypositionqty'"` // 买期初持仓
  579. BUYCURPOSITIONQTY int64 `json:"buycurpositionqty" xorm:"'Buycurpositionqty'"` // 买当前持仓
  580. SELLPOSITIONQTY int64 `json:"sellpositionqty" xorm:"'Sellpositionqty'"` // 卖期初持仓
  581. SELLCURPOSITIONQTY int64 `json:"sellcurpositionqty" xorm:"'Sellcurpositionqty'"` // 卖当前持仓
  582. GOODSCODE string `json:"goodscode" xorm:"'GOODSCODE'"` // 商品代码
  583. GOODSNAME string `json:"goodsname" xorm:"'GOODSNAME'"` // 商品名称
  584. }
  585. func (r *ErmcpTradePosition) buildSql() string {
  586. sqlId := "select b.*, g.goodscode,g.goodsname from (" +
  587. "select a.userid," +
  588. " a.goodsid," +
  589. " sum(a.buypositionqty) buypositionqty," +
  590. " sum(a.buycurpositionqty) buycurpositionqty," +
  591. " sum(a.sellpositionqty) sellpositionqty," +
  592. " sum(a.sellcurpositionqty) sellcurpositionqty" +
  593. " from (select ta.relateduserid userid, t.*" +
  594. " from tradeposition t" +
  595. " inner join taaccount ta" +
  596. " on t.accountid = ta.accountid" +
  597. " where ta.relateduserid = %v" +
  598. " and ismain = 0) a" +
  599. " group by a.userid, a.goodsid" +
  600. " ) b left join goods g on b.goodsid=g.goodsid"
  601. sqlId = fmt.Sprintf(sqlId, r.USERID)
  602. return sqlId
  603. }
  604. // GetData 获取用户持仓头寸(子账户)
  605. func (r *ErmcpTradePosition) GetData() ([]ErmcpTradePosition, error) {
  606. sData := make([]ErmcpTradePosition, 0)
  607. err := db.GetEngine().SQL(r.buildSql()).Find(&sData)
  608. return sData, err
  609. }
  610. // ErmcpHedgePosition 用户头寸(母账户)
  611. type ErmcpHedgePosition struct {
  612. RELATEDUSERID int64 `json:"relateduserid" xorm:"'RELATEDUSERID'"` // 关联用户id
  613. ACCOUNTID int64 `json:"accountid" xorm:"'ACCOUNTID'"` // 资金账号[外部母账户]
  614. HEDGEGOODSID int32 `json:"hedgegoodsid" xorm:"'HEDGEGOODSID'"` // 对冲合约ID
  615. HEDGEACCOUNTCODE string `json:"hedgeaccountcode" xorm:"'HEDGEACCOUNTCODE'"` // 对冲账号
  616. TRADEDATE string `json:"tradedate" xorm:"'TRADEDATE'"` // 交易日(yyyyMMdd)
  617. MARKETID int32 `json:"marketid" xorm:"'mARKETID'"` // 市场ID
  618. YDBUYPOSITION int32 `json:"ydbuyposition" xorm:"'YDBUYPOSITION'"` // 期初买头寸
  619. CURBUYPOSITION int32 `json:"curbuyposition" xorm:"'CURBUYPOSITION'"` // 期末买头寸
  620. CURYDBUYPOSITION int32 `json:"curydbuyposition" xorm:"'CURYDBUYPOSITION'"` // 期末上日买头寸
  621. CURTDBUYPOSITION int32 `json:"curtdbuyposition" xorm:"'CURTDBUYPOSITION'"` // 期末今日买头寸
  622. FREYDBUYPOSITION int32 `json:"freydbuyposition" xorm:"'FREYDBUYPOSITION'"` // 冻结上日买头寸
  623. FRETDBUYPOSITION int32 `json:"fretdbuyposition" xorm:"'FRETDBUYPOSITION'"` // 冻结今日买头寸
  624. YDSELLPOSITION int32 `json:"ydsellposition" xorm:"'YDSELLPOSITION'"` // 期初卖头寸
  625. CURSELLPOSITION int32 `json:"cursellposition" xorm:"'CURSELLPOSITION'"` // 期末卖头寸
  626. CURYDSELLPOSITION int32 `json:"curydsellposition" xorm:"'CURYDSELLPOSITION'"` // 期末上日卖头寸
  627. CURTDSELLPOSITION int32 `json:"curtdsellposition" xorm:"'CURTDSELLPOSITION'"` // 期末今日卖头寸
  628. FREYDSELLPOSITION int32 `json:"freydsellposition" xorm:"'FREYDSELLPOSITION'"` // 冻结上日卖头寸
  629. FRETDSELLPOSITION int32 `json:"fretdsellposition" xorm:"'FRETDSELLPOSITION'"` // 冻结今日卖头寸
  630. GOODSID int32 `json:"goodsid" xorm:"'GOODSID'"` // 商品id
  631. GOODSCODE string `json:"goodscode" xorm:"'GOODSCODE'"` // 商品代码
  632. GOODSNAME string `json:"goodsname" xorm:"'GOODSNAME'"` // 商品名称
  633. TotalYdQty int32 `json:"totalydqty"` // 昨日数量(净头寸) = 期初买头寸 - 期初卖头寸
  634. TotalCurQty int32 `json:"totalcurqty"` // 当前数量(净头寸) = 期末买头寸 - 期末卖头寸
  635. IncreaseQty int32 `json:"increaseqty"` // 增加数量 = 期末买头寸 - 期初买头寸
  636. DecreaseQty int32 `json:"decreaseqty"` // 减少数量 = (期末卖头寸 - 期初卖头寸)*-1
  637. }
  638. // Calc 计算母账号头寸相关数据
  639. func (r *ErmcpHedgePosition) Calc() {
  640. r.TotalYdQty = r.YDBUYPOSITION - r.YDSELLPOSITION
  641. r.TotalCurQty = r.CURBUYPOSITION - r.CURSELLPOSITION
  642. r.IncreaseQty = r.CURBUYPOSITION - r.YDBUYPOSITION
  643. r.DecreaseQty = (r.CURSELLPOSITION - r.YDSELLPOSITION) * -1
  644. }
  645. func (r *ErmcpHedgePosition) buildSql() string {
  646. sqlId := "select ta.RELATEDUSERID," +
  647. " t.ACCOUNTID," +
  648. " t.HEDGEGOODSID," +
  649. " t.HEDGEACCOUNTCODE," +
  650. " t.TRADEDATE," +
  651. " t.MARKETID," +
  652. " t.YDBUYPOSITION," +
  653. " t.CURBUYPOSITION," +
  654. " t.CURYDBUYPOSITION," +
  655. " t.CURTDBUYPOSITION," +
  656. " t.FREYDBUYPOSITION," +
  657. " t.FRETDBUYPOSITION," +
  658. " t.YDSELLPOSITION," +
  659. " t.CURSELLPOSITION," +
  660. " t.CURYDSELLPOSITION," +
  661. " t.CURTDSELLPOSITION," +
  662. " t.FREYDSELLPOSITION," +
  663. " t.FRETDSELLPOSITION," +
  664. " g.goodsid," +
  665. " g.goodscode," +
  666. " g.goodsname" +
  667. " from hedge_outtradeposition t" +
  668. " inner join taaccount ta" +
  669. " on t.accountid = ta.accountid" +
  670. " and ta.ismain = 1" +
  671. " and ta.relateduserid = %v" +
  672. " left join goods g" +
  673. " on t.hedgegoodsid = g.goodsid"
  674. sqlId = fmt.Sprintf(sqlId, r.RELATEDUSERID)
  675. return sqlId
  676. }
  677. // GetData 获取对冲头寸(母账号头寸)
  678. func (r *ErmcpHedgePosition) GetData() ([]ErmcpHedgePosition, error) {
  679. sData := make([]ErmcpHedgePosition, 0)
  680. err := db.GetEngine().SQL(r.buildSql()).Find(&sData)
  681. for i := range sData {
  682. sData[i].Calc()
  683. }
  684. return sData, err
  685. }
  686. // ErmcpExposurePostion 实时敞口\期货明细(头寸)
  687. type ErmcpExposurePostion struct {
  688. AREAUSERID int64 `json:"areauserid" xorm:"'AREAUSERID'"` // 所属机构id
  689. MIDDLEGOODSID int32 `json:"middlegoodsid" xorm:"'MIDDLEGOODSID'"` // 套保商品id
  690. GOODSID int32 `json:"goodsid" xorm:"'GOODSID'"` // 商品id
  691. GOODSCODE string `json:"goodscode" xorm:"'GOODSCODE'"` // 商品代码
  692. GOODSNAME string `json:"goodsname" xorm:"'GOODSNAME'"` // 商品名称
  693. YdQty int64 `json:"ydqty" xorm:"'YdQty'"` // 昨日持仓
  694. CurQty int64 `json:"curqty" xorm:"'CurQty'"` // 当前持仓
  695. DiffQty int64 `json:"diffqty" xorm:"'DiffQty'"` // 持仓变动量=当前持仓-昨日持仓
  696. DiffHedgeQty float64 `json:"diffhedgeqty" xorm:"'DiffHedgeQty'"` // 套保品种变动量=持仓变动量*期货合约单位*期货品种系数
  697. AGREEUNIT string `json:"agreeunit"` // 合约单位
  698. CONVERTRATIO float64 `json:"convertratio"` // 期货品种系数(折算系数)
  699. }
  700. // ParseFromPos 子账户相关计算(不一定用得到,现在说都是查母账号的)
  701. func (r *ErmcpExposurePostion) ParseFromPos(val *ErmcpTradeGoods, data *ErmcpTradePosition) {
  702. r.AREAUSERID = val.AREAUSERID
  703. r.MIDDLEGOODSID = val.MIDDLEGOODSID
  704. r.GOODSID = val.GOODSID
  705. r.GOODSCODE = val.GOODSCODE
  706. r.GOODSNAME = val.GOODSNAME
  707. //相关计算
  708. r.YdQty = data.BUYPOSITIONQTY - data.SELLPOSITIONQTY
  709. r.CurQty = data.BUYCURPOSITIONQTY - data.SELLCURPOSITIONQTY
  710. r.DiffQty = r.CurQty - r.YdQty
  711. r.DiffHedgeQty = float64(r.DiffQty) * float64(val.AGREEUNIT) * val.CONVERTRATIO
  712. r.CONVERTRATIO = val.CONVERTRATIO
  713. if strName := mtpcache.GetEnumDicitemName(val.GOODSUNITID); len(strName) > 0 {
  714. r.AGREEUNIT = fmt.Sprintf("%v%v/手", val.AGREEUNIT, strName)
  715. }
  716. }
  717. // ParseFromHedgePos 母账户相关计算
  718. func (r *ErmcpExposurePostion) ParseFromHedgePos(val *ErmcpTradeGoods, data *ErmcpHedgePosition) {
  719. r.AREAUSERID = val.AREAUSERID
  720. r.MIDDLEGOODSID = val.MIDDLEGOODSID
  721. r.GOODSID = val.GOODSID
  722. r.GOODSCODE = val.GOODSCODE
  723. r.GOODSNAME = val.GOODSNAME
  724. //相关计算
  725. r.YdQty = int64(data.YDBUYPOSITION - data.YDSELLPOSITION)
  726. r.CurQty = int64(data.CURBUYPOSITION - data.CURSELLPOSITION)
  727. r.DiffQty = r.CurQty - r.YdQty
  728. r.DiffHedgeQty = float64(r.DiffQty) * float64(val.AGREEUNIT) * val.CONVERTRATIO
  729. r.CONVERTRATIO = val.CONVERTRATIO
  730. if strName := mtpcache.GetEnumDicitemName(val.GOODSUNITID); len(strName) > 0 {
  731. r.AGREEUNIT = fmt.Sprintf("%v%v/手", val.AGREEUNIT, strName)
  732. }
  733. }
  734. // GetDataEx 获取敞口明细期货头寸
  735. func (r *ErmcpExposurePostion) GetDataEx() (interface{}, error) {
  736. sData := make([]ErmcpExposurePostion, 0)
  737. // 查询交易商品
  738. mg := ErmcpTradeGoods{AREAUSERID: mtpcache.GetAreaUserId(r.AREAUSERID, 0), MIDDLEGOODSID: r.MIDDLEGOODSID}
  739. sGoods, err := mg.GetData()
  740. if err != nil || sGoods == nil || len(sGoods) == 0 {
  741. return sData, err
  742. }
  743. if mtpcache.IsAreaUserId(r.AREAUSERID) {
  744. // 查询头寸(母账号)
  745. mp := ErmcpHedgePosition{RELATEDUSERID: r.AREAUSERID}
  746. sPostion, err1 := mp.GetData()
  747. if err1 != nil || sPostion == nil || len(sPostion) == 0 {
  748. return sData, err1
  749. }
  750. // 合并处理
  751. for i := range sPostion {
  752. if val, ok := sGoods[sPostion[i].HEDGEGOODSID]; ok {
  753. d := ErmcpExposurePostion{}
  754. d.ParseFromHedgePos(val, &sPostion[i])
  755. sData = append(sData, d)
  756. }
  757. }
  758. } else {
  759. // 查询头寸(子账号)
  760. mp := ErmcpTradePosition{USERID: r.AREAUSERID}
  761. sPostion, err1 := mp.GetData()
  762. if err1 != nil || sPostion == nil || len(sPostion) == 0 {
  763. return sData, err1
  764. }
  765. // 合并处理
  766. for i := range sPostion {
  767. if val, ok := sGoods[sPostion[i].GOODSID]; ok {
  768. d := ErmcpExposurePostion{}
  769. d.ParseFromPos(val, &sPostion[i])
  770. sData = append(sData, d)
  771. }
  772. }
  773. }
  774. return sData, nil
  775. }
  776. // ErmcpHedgePositionDetail 敞口/期货头寸/期货明细
  777. type ErmcpHedgePositionDetail struct {
  778. HEDGEGOODSID int32 `json:"hedgegoodsid" xorm:"'HEDGEGOODSID'"` // 商品id
  779. BUYORSELL int32 `json:"buyorsell" xorm:"'BUYORSELL'"` // 买卖方向 0-买 1-卖
  780. TRADEQTY int32 `json:"tradeqty" xorm:"'TRADEQTY'"` // 数量(成交数量)
  781. CHANNELBUILDTYPE int32 `json:"channelbuildtype" xorm:"'CHANNELBUILDTYPE'"` // 开平方向 1-建仓 2-平仓
  782. TRADETIME string `json:"tradetime" xorm:"'TRADETIME'"` // 时间(成交时间)
  783. GOODSCODE string `json:"goodscode" xorm:"'GOODSCODE'"` // 商品代码
  784. GOODSNAME string `json:"goodsname" xorm:"'GOODSNAME'"` // 商品名称
  785. AREAUSERID int32 `json:"-"` // 所属机构id
  786. }
  787. // Calc 计算期货明细相关数据
  788. func (r *ErmcpHedgePositionDetail) Calc() {
  789. if r.BUYORSELL == 1 && r.TRADEQTY > 0 {
  790. r.TRADEQTY = r.TRADEQTY * -1
  791. }
  792. }
  793. func (r *ErmcpHedgePositionDetail) buildSql() string {
  794. var sqlId string
  795. if mtpcache.IsAreaUserId(int64(r.AREAUSERID)) {
  796. // 机构查外部表
  797. sqlId = "select t.hedgegoodsid," +
  798. " t.buyorsell," +
  799. " tradeqty," +
  800. " t.channelbuildtype," +
  801. " to_char(t.tradetime, 'yyyy-mm-dd hh24:mi:ss') tradetime," +
  802. " g.goodscode," +
  803. " g.goodsname" +
  804. " from hedge_outtradedetail t" +
  805. " inner join taaccount ta" +
  806. " on t.accountid = ta.accountid" +
  807. " and ta.ismain = 1" +
  808. " and ta.relateduserid = %v" +
  809. " left join goods g" +
  810. " on t.hedgegoodsid = g.goodsid" +
  811. " where t.hedgegoodsid = %v"
  812. } else {
  813. // 交易员查内部表
  814. sqlId = "select t.goodsid hedgegoodsid," +
  815. " t.buyorsell," +
  816. " tradeqty," +
  817. " t.channelbuildtype," +
  818. " to_char(t.tradetime, 'yyyy-mm-dd hh24:mi:ss') tradetime," +
  819. " g.goodscode," +
  820. " g.goodsname" +
  821. " from hedge_innertradedetail t" +
  822. " inner join taaccount ta" +
  823. " on t.accountid = ta.accountid" +
  824. " and ta.relateduserid = %v" +
  825. " left join goods g" +
  826. " on t.goodsid = g.goodsid" +
  827. " where t.goodsid = %v"
  828. }
  829. sqlId = fmt.Sprintf(sqlId, r.AREAUSERID, r.HEDGEGOODSID)
  830. return sqlId
  831. }
  832. // GetDataEx 获取持仓头寸明细(成交记录)
  833. func (r *ErmcpHedgePositionDetail) GetDataEx() (interface{}, error) {
  834. sData := make([]ErmcpHedgePositionDetail, 0)
  835. err := db.GetEngine().SQL(r.buildSql()).Find(&sData)
  836. for i := range sData {
  837. sData[i].Calc()
  838. }
  839. return sData, err
  840. }
  841. // ErmcpMiddlegoodsRelateGoods 套保商品关联主动合约
  842. type ErmcpMiddlegoodsRelateGoods struct {
  843. MIDDLEGOODSID int32 `json:"middlegoodsid" xorm:"'MIDDLEGOODSID'"` // 套保商品id
  844. MIDDLEGOODSCODE string `json:"middlegoodsswcode" xorm:"'MIDDLEGOODSCODE'"` // 套保商品代码
  845. MIDDLEGOODSNAME string `json:"middlegoodsname" xorm:"'MIDDLEGOODSNAME'"` // 套保商品名称
  846. NEEDHEDGERATIO float64 `json:"needhedgeratio" xorm:"'NEEDHEDGERATIO'"` // 应套保比例
  847. NEEDARBITRAGERATIO float64 `json:"needarbitrageratio" xorm:"'NEEDARBITRAGERATIO'"` // 应套利比例
  848. GOODSGROUPID int32 `json:"goodsgroupid" xorm:"'GOODSGROUPID'"` // 交易品种id
  849. CONVERTRATIO float64 `json:"convertratio" xorm:"'CONVERTRATIO'"` // 折算系数
  850. GOODSID int32 `json:"goodsid" xorm:"GOODSID"` // 商品Id
  851. GOODSCODE string `json:"goodscode" xorm:"'GOODSCODE'"` // 交易商品代码
  852. GOODSNAME string `json:"goodsname" xorm:"'GOODSNAME'"` // 交易商品名称
  853. GOODUNITID int32 `json:"goodunitid" xorm:"'GOODUNITID'"` // 交易商品单位id
  854. AGREEUNIT float64 `json:"agreeunit" xorm:"'AGREEUNIT'"` // 合约乘数
  855. ENUMDICNAME string `json:"enumdicname"` // 单位名称(交易商品)
  856. }
  857. func (r *ErmcpMiddlegoodsRelateGoods) calc() {
  858. r.ENUMDICNAME = mtpcache.GetEnumDicitemName(r.GOODUNITID)
  859. }
  860. func (r *ErmcpMiddlegoodsRelateGoods) buildSql() string {
  861. var sqlId utils.SQLVal = "with tmp as" +
  862. " (select a.*, g.goodsid, g.goodscode, g.goodsname" +
  863. " from (select row_number() over(partition by t.goodscode order by t.tradedate desc, t.sortindex) cn," +
  864. " t.*" +
  865. " from GoodsSortByPrePosition t) a" +
  866. " left join goods g" +
  867. " on a.goodscode = g.goodscode" +
  868. " where cn = 1)" +
  869. "select t.middlegoodsid," +
  870. " t.middlegoodscode," +
  871. " t.middlegoodsname," +
  872. " t.needhedgeratio," +
  873. " t.needarbitrageratio," +
  874. " t.goodsgroupid," +
  875. " c.convertratio," +
  876. " g.goodsid," +
  877. " g.goodscode," +
  878. " g.goodsname," +
  879. " g.agreeunit," +
  880. " g.goodunitid" +
  881. " from erms_middlegoods t" +
  882. " inner join ermcp_ggconvertconfig c" +
  883. " on t.goodsgroupid = c.destgoodsgroupid" +
  884. " inner join goods g" +
  885. " on g.goodsgroupid = c.srcgoodsgroupid" +
  886. " where 1 = 1 and g.goodsstatus = 3 and g.goodsid in (select goodsid from tmp)"
  887. sqlId.And("t.MIDDLEGOODSID", r.MIDDLEGOODSID)
  888. return sqlId.String()
  889. }
  890. // GetDataEx 获取套保商品关联主动合约
  891. func (r *ErmcpMiddlegoodsRelateGoods) GetDataEx() (interface{}, error) {
  892. sData := make([]ErmcpMiddlegoodsRelateGoods, 0)
  893. err := db.GetEngine().SQL(r.buildSql()).Find(&sData)
  894. for i := range sData {
  895. sData[i].calc()
  896. }
  897. return sData, err
  898. }