ermcpExposure.go 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  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. )
  15. //实时敞口
  16. type ErmcpRealExposureModel struct {
  17. MiddleGoodsID uint32 // 套保品种
  18. AreaUserID uint32 // 所属机构
  19. OriBuyPlanQty float64 // 期初采购计划数量
  20. OriBuyPricedQty float64 // 期初采购合同已定价数量
  21. OriSellPlanQty float64 // 期初销售计划数量
  22. OriSellPricedQty float64 // 期初销售合同已定价数量
  23. OriBuyFutureQty float64 // 期初买入期货数量
  24. OriSellFutureQty float64 // 期初卖出期货数量
  25. BuyPlanQty float64 // 采购计划数量
  26. BuyPricedQty float64 // 采购合同已定价数量
  27. SellPlanQty float64 // 销售计划数量
  28. SellPricedQty float64 // 销售合同已定价数量
  29. BuyFutureQty float64 // 买入期货数量
  30. SellFutureQty float64 // 卖出期货数量
  31. TotalSpotQty float64 // 现货数量
  32. TotalFutureQty float64 // 期货数量
  33. TotalExposure float64 // 总敞口
  34. TotalHedgeRatio float64 // 敞口比例
  35. TotalNeedHedgeQty float64 // 期货应套保量
  36. NeedHedgeExposoure float64 // 应套保敞口
  37. NeedHedgeRatio float64 // 应套保敞口比例
  38. MiddleGoodsName string // 套保品种名称
  39. MiddleGoodsCode string // 套保品种代码
  40. MiddleGoodsHedgeRatio float64 // 应套保比例
  41. OriTotalSpotQty float64 // 期初现货数量=(期初销售计划数量-期初销售合同已定价数量)-(期初采购计划数量-期初采购合同已定价数量)
  42. OriTotalFutuQty float64 // 期初期货数量=期初买入期货数量-期初卖出期货数量
  43. DiffSpotQty float64 // 今日变动量(现货) = 现货数量 - 期初现货数量
  44. DiffFutuQty float64 // 今日变动量(期货) = (买入 - 买入期初) - (卖出 - 卖出期初)
  45. }
  46. // 计算相关字段
  47. func (r *ErmcpRealExposureModel) calc() {
  48. r.OriTotalSpotQty = (r.OriSellPlanQty - r.OriSellPricedQty) - (r.OriBuyPlanQty - r.OriBuyPricedQty)
  49. r.OriTotalFutuQty = r.OriBuyFutureQty - r.OriSellFutureQty
  50. r.DiffSpotQty = r.TotalSpotQty - r.OriTotalSpotQty
  51. r.DiffFutuQty = (r.BuyFutureQty - r.OriBuyFutureQty) - (r.SellFutureQty - r.OriSellFutureQty)
  52. }
  53. func (r *ErmcpRealExposureModel) ParseFromProto(v *pb.ErmcpAreaExposure) {
  54. r.MiddleGoodsID = *v.MiddleGoodsID
  55. r.AreaUserID = *v.AreaUserID
  56. r.OriBuyPlanQty = *v.OriBuyPlanQty
  57. r.OriBuyPricedQty = *v.OriBuyPricedQty
  58. r.OriSellPlanQty = *v.OriSellPlanQty
  59. r.OriSellPricedQty = *v.OriSellPricedQty
  60. r.OriBuyFutureQty = float64(*v.OriBuyFutureQty)
  61. r.OriSellFutureQty = float64(*v.OriSellFutureQty)
  62. r.BuyPlanQty = *v.BuyPlanQty
  63. r.BuyPricedQty = *v.BuyPricedQty
  64. r.SellPlanQty = *v.SellPlanQty
  65. r.SellPricedQty = *v.SellPricedQty
  66. r.BuyFutureQty = *v.BuyFutureQty
  67. r.SellFutureQty = *v.SellFutureQty
  68. r.TotalSpotQty = *v.TotalSpotQty
  69. r.TotalFutureQty = *v.TotalFutureQty
  70. r.TotalExposure = *v.TotalExposure
  71. r.TotalHedgeRatio = *v.TotalHedgeRatio
  72. r.TotalNeedHedgeQty = *v.TotalNeedHedgeQty
  73. r.NeedHedgeExposoure = *v.NeedHedgeExposoure
  74. r.NeedHedgeRatio = *v.NeedHedgeRatio
  75. // 执行相关计算
  76. r.calc()
  77. }
  78. // 实时敞口数据: Redis数据 + 套保品种信息表
  79. func (r *ErmcpRealExposureModel) GetData() ([]ErmcpRealExposureModel, error) {
  80. // 获取关联的套路商品
  81. if sGoods, err := mtpcache.GetMiddleGoodsByUserID(r.AreaUserID); err == nil {
  82. sData := make([]ErmcpRealExposureModel, 0)
  83. // 从Redis获取数据
  84. for i := range sGoods {
  85. key := fmt.Sprintf("ErmcpAreaExposure:%d_%d", sGoods[i].AREAUSERID, sGoods[i].MIDDLEGOODSID)
  86. if ret, err := rediscli.GetRedisClient().Get(key).Result(); err == nil {
  87. if len(ret) > 0 {
  88. var data pb.ErmcpAreaExposure
  89. if err := proto.Unmarshal([]byte(ret), &data); err == nil {
  90. var m = ErmcpRealExposureModel{MiddleGoodsName: sGoods[i].MIDDLEGOODSNAME,
  91. MiddleGoodsCode: sGoods[i].MIDDLEGOODSCODE, MiddleGoodsHedgeRatio: sGoods[i].NEEDHEDGERATIO}
  92. m.ParseFromProto(&data)
  93. sData = append(sData, m)
  94. }
  95. }
  96. }
  97. }
  98. return sData, nil
  99. }
  100. return nil, nil
  101. }
  102. /*************敞口明细**************/
  103. //敞口现货明细结构
  104. type ErmcpExposureDetailModel struct {
  105. Createtime string `json:"createtime" xorm:"'createtime'"` // 时间
  106. Areauserid uint32 `json:"areauserid" xorm:"'areauserid'"` // 机构ID
  107. Logtype int32 `json:"logtype" xorm:"'logtype'"` // 类型 - 1:套保计划 2:现货合同
  108. Contracttype int32 `json:"contracttype" xorm:"'contracttype'"` // 现货合同类型 - 1:采购 -1:销售
  109. Wrstandardid int32 `json:"wrstandardid" xorm:"'wrstandardid'"` // 现货商品ID
  110. Qty float64 `json:"qty" xorm:"'qty'"` // 数量
  111. RelateNo string `json:"relateNo" xorm:"'relateNo'"` // 现货合同/套保计划编号
  112. Middlegoodsname string `json:"middlegoodsname" xorm:"'middlegoodsname'"` // 套保商品名称
  113. Middlegoodscode string `json:"middlegoodscode" xorm:"'middlegoodscode'"` // 套保商品代码
  114. MiddlegoodsId int32 `json:"middlegoodsId" xorm:"'middlegoodsId'"` // 套保商品id
  115. Unitid int32 `json:"-" xorm:"'unitid'"` // 现货商品单位ID
  116. Wrstandardname string `json:"wrstandardname" xorm:"'wrstandardname'"` // 现货商品名称
  117. Wrstandardcode string `json:"wrstandardcode" xorm:"'wrstandardcode'"` // 现货商品代码
  118. Enumdicname string `json:"enumdicname" xorm:"'enumdicname'"` // 现货商品单位名称
  119. ChangeQty float64 `json:"changeQty" xorm:"'changeQty'"` // 套保变动量
  120. Convertfactor float64 `json:"convertfactor" xorm:"'convertfactor'"` // 标仓系数
  121. Convertratio float64 `json:"convertratio" xorm:"'convertratio'"` // 套保系数
  122. }
  123. func (r *ErmcpExposureDetailModel) buildSql() string {
  124. str := "with tmp as" +
  125. " (select 2 as LogType," +
  126. " s.spotcontractid as relatedid," +
  127. " s.contractno as relateNo," +
  128. " s.qty " +
  129. " from ermcp_spotcontract s" +
  130. " union all" +
  131. " select 1, t.hedgeplanid as relateid, t.hedgeplanno as relateNo, t.planqty as qty " +
  132. " from ermcp_hedgeplan t)" +
  133. "select to_char(t.createtime, 'yyyy-mm-dd hh24:mi:ss') createtime," +
  134. " t.middlegoodsid," +
  135. " t.areauserid," +
  136. " t.logtype," +
  137. " t.contracttype," +
  138. " wc.wrstandardid," +
  139. " tmp.qty," +
  140. " t.convertfactor," +
  141. " t.convertratio," +
  142. " t.qty changeQty," +
  143. " tmp.relateNo," +
  144. " m.middlegoodsname," +
  145. " m.middlegoodscode," +
  146. " w.unitid," +
  147. " w.wrstandardname," +
  148. " w.wrstandardcode," +
  149. " e.enumdicname" +
  150. " from ermcp_spotexposurelog t" +
  151. " left join erms2_wrsconvertdetail wc" +
  152. " on t.wrstandardid = wc.wrstandardid" +
  153. " and t.middlegoodsid = wc.middlegoodsid" +
  154. " left join erms_middlegoods m" +
  155. " on t.middlegoodsid = m.middlegoodsid" +
  156. " left join wrstandard w" +
  157. " on t.wrstandardid = w.wrstandardid" +
  158. " left join enumdicitem e" +
  159. " on w.unitid = e.enumitemname" +
  160. " and e.enumdiccode = 'goodsunit'" +
  161. " left join tmp" +
  162. " on t.logtype = tmp.LogType" +
  163. " and t.relatedid = tmp.relatedid" +
  164. " where t.middlegoodsid=%v and t.areauserid=%v"
  165. return fmt.Sprintf(str, r.MiddlegoodsId, r.Areauserid)
  166. }
  167. // 处理数据
  168. func (r *ErmcpExposureDetailModel) Calc() {
  169. // 销售合同转换为负数
  170. if r.Logtype == 2 && r.Contracttype == -1 {
  171. r.ChangeQty *= -1
  172. r.Qty *= -1
  173. }
  174. // 采购计划 转换为负数
  175. if r.Logtype == 1 && r.Contracttype == 1 {
  176. r.ChangeQty *= -1
  177. r.Qty *= -1
  178. }
  179. }
  180. // 查询敞口现货明细
  181. func (r *ErmcpExposureDetailModel) GetData() ([]ErmcpExposureDetailModel, error) {
  182. e := db.GetEngine()
  183. s := e.SQL(r.buildSql())
  184. sData := make([]ErmcpExposureDetailModel, 0)
  185. if err := s.Find(&sData); err != nil {
  186. return nil, err
  187. }
  188. for i := range sData {
  189. sData[i].Calc()
  190. }
  191. return sData, nil
  192. }
  193. /// 现货头寸
  194. // 现货头寸数据
  195. type AreaSpotModel struct {
  196. WRSTANDARDID int32 `json:"wrstandardid" xorm:"'WRSTANDARDID'"` // 现货商品ID
  197. WRSTANDARDNAME string `json:"wrstandardname" xorm:"'WRSTANDARDNAME'"` // 现货品种
  198. WRSTANDARDCODE string `json:"wrstandardcode" xorm:"'WRSTANDARDCODE'"` // 现货品种代码
  199. AREAUSERID int32 `json:"areauserid" xorm:"'AREAUSERID'"` // 所属机构
  200. ORIBUYPLANQTY float64 `json:"-" xorm:"'ORIBUYPLANQTY'"` // 期初采购计划数量
  201. ORIBUYPRICEDQTY float64 `json:"-" xorm:"'ORIBUYPRICEDQTY'"` // 期初采购合同已定价数量
  202. ORISELLPLANQTY float64 `json:"-" xorm:"'ORISELLPLANQTY'"` // 期初销售计划数量
  203. ORISELLPRICEDQTY float64 `json:"-" xorm:"'ORISELLPRICEDQTY'"` // 期初销售合同已定价数量
  204. BUYPLANQTY float64 `json:"-" xorm:"'BUYPLANQTY'"` // 采购计划数量
  205. BUYPRICEDQTY float64 `json:"-" xorm:"'BUYPRICEDQTY'"` // 采购合同已定价数量
  206. SELLPLANQTY float64 `json:"-" xorm:"'SELLPLANQTY'"` // 销售计划数量
  207. SELLPRICEDQTY float64 `json:"-" xorm:"'SELLPRICEDQTY'"` // 销售合同已定价数量
  208. TOTALSPOTQTY float64 `json:"totalspotqty" xorm:"'TOTALSPOTQTY'"` // 当前数量(现货头寸总量) = (销售计划数量 - 销售已定价数量) - (采购计划数量 - 采购已定价数量)
  209. OriToalSpotQty float64 `json:"oritoalspotqty" xorm:"'OriToalSpotQty'"` // 昨日数量
  210. IncreaseQty float64 `json:"increaseqty" xorm:"'IncreaseQty'"` // 增加数量=销售计划数量+采购已定价数量
  211. DecreaseQty float64 `json:"decreaseqty" xorm:"'DecreaseQty'"` // 减少数量=-(销售已定价数量+采购计划数量)
  212. UPDATETIME string `json:"updatetime" xorm:"'UPDATETIME'"` // 更新时间
  213. }
  214. // 进行相关字段的值计算
  215. func (r *AreaSpotModel) calc() {
  216. r.IncreaseQty = r.SELLPLANQTY + r.BUYPRICEDQTY
  217. r.DecreaseQty = (r.SELLPRICEDQTY + r.BUYPLANQTY) * -1
  218. r.OriToalSpotQty = (r.ORISELLPLANQTY - r.ORISELLPRICEDQTY) - (r.ORIBUYPLANQTY - r.ORIBUYPRICEDQTY)
  219. }
  220. func (r *AreaSpotModel) buildSql() string {
  221. str := "select t.WRSTANDARDID," +
  222. " w.WRSTANDARDNAME," +
  223. " w.WRSTANDARDCODE," +
  224. " t.AREAUSERID," +
  225. " t.ORIBUYPLANQTY," +
  226. " t.ORIBUYPRICEDQTY," +
  227. " t.ORISELLPLANQTY," +
  228. " t.ORISELLPRICEDQTY," +
  229. " t.BUYPLANQTY," +
  230. " t.BUYPRICEDQTY," +
  231. " t.SELLPLANQTY," +
  232. " t.SELLPRICEDQTY," +
  233. " t.TOTALSPOTQTY," +
  234. " to_char(t.UPDATETIME,'yyyy-mm-dd hh24:mi:ss') UPDATETIME" +
  235. " from ermcp_areaspot t" +
  236. " left join wrstandard w" +
  237. " on t.wrstandardid = w.wrstandardid" +
  238. " where t.areauserid=%v"
  239. return fmt.Sprintf(str, r.AREAUSERID)
  240. }
  241. // 从数据库中查询现货头寸
  242. func (r *AreaSpotModel) GetData() ([]AreaSpotModel, error) {
  243. e := db.GetEngine()
  244. sData := make([]AreaSpotModel, 0)
  245. if err := e.SQL(r.buildSql()).Find(&sData); err != nil {
  246. return nil, err
  247. }
  248. for i := range sData {
  249. sData[i].calc()
  250. }
  251. return sData, nil
  252. }
  253. // 现货头寸-现货明细
  254. type ErmcpAreaSpotDetailModel struct {
  255. Relatedid string `json:"relatedid" xorm:"'relatedid'"` // 套保计划ID/现货合同ID
  256. Relatedno string `json:"relatedno" xorm:"'relatedno'"` // 编号
  257. LogType int32 `json:"logtype" xorm:"'logType'"` // 记录类型 1-套保 2-现货合同
  258. Contracttype int32 `json:"contracttype" xorm:"'contracttype'"` // 合同类型 1-采购 -1-销售
  259. Wrstandardname string `json:"wrstandardname" xorm:"'wrstandardname'"` // 现货商品名称
  260. Wrstandardcode string `json:"wrstandardcode" xorm:"'wrstandardcode'"` // 现货商品代码
  261. Qty float64 `json:"qty" xorm:"'qty'"` // 数量
  262. Strtime string `json:"strtime" xorm:"'strtime'"` // 时间
  263. Enumdicname string `json:"enumdicname"` // 现货商品单位名称
  264. Recordname string `json:"recordname"` // 类型名称
  265. CREATETIME string `json:"createtime" xorm:"'CREATETIME'"` // 创建时间
  266. Unitid int32 `json:"-" xorm:"'UNITID'"` // 单位ID
  267. UserId int `json:"-"` // 所属用户ID
  268. WrstandardId int32 `json:"-"` // 现货商品ID
  269. }
  270. // 组建查询SQL
  271. func (r *ErmcpAreaSpotDetailModel) buildSql() string {
  272. str := "with tmp as" +
  273. " (select to_char(t.hedgeplanid) relatedid," +
  274. " t.hedgeplanno relatedno," +
  275. " 1 as logType," +
  276. " t.contracttype" +
  277. " from ermcp_hedgeplan t" +
  278. " where t.areauserid = %v" +
  279. " and t.wrstandardid = %v" +
  280. " union all " +
  281. " select to_char(t.spotcontractid)," +
  282. " t.contractno," +
  283. " 2 as logType," +
  284. " t.contracttype" +
  285. " from ermcp_spotcontract t" +
  286. " where t.userid = %v" +
  287. " and t.wrstandardid = %v)" +
  288. "select t.relatedid," +
  289. " tmp.relatedno," +
  290. " t.LogType," +
  291. " tmp.contracttype," +
  292. " t.RealQty qty," +
  293. " to_char(t.createtime, 'yyyy-mm-dd hh:mi:ss') createtime," +
  294. " w.wrstandardname," +
  295. " w.wrstandardcode," +
  296. " w.unitid" +
  297. " from ermcp_spotlog t" +
  298. " inner join tmp" +
  299. " on t.LogType = tmp.logType" +
  300. " and t.relatedid = tmp.relatedid" +
  301. " and t.areauserid = %v" +
  302. " and t.wrstandardid = %v" +
  303. " left join wrstandard w" +
  304. " on t.wrstandardid = w.wrstandardid"
  305. return fmt.Sprintf(str, r.UserId, r.WrstandardId, r.UserId, r.WrstandardId, r.UserId, r.WrstandardId)
  306. }
  307. // 现货头寸-明细:数据加工处理
  308. func (r *ErmcpAreaSpotDetailModel) Calc() {
  309. var logTypeName, contractTypeName string
  310. if r.LogType == 1 {
  311. logTypeName = "计划"
  312. } else {
  313. logTypeName = "合同"
  314. }
  315. if r.Contracttype == 1 {
  316. contractTypeName = "采购"
  317. } else {
  318. contractTypeName = "销售"
  319. }
  320. // 销售合同 数量转为负数
  321. if r.LogType == 2 && r.Contracttype == -1 {
  322. if r.Qty > 0 {
  323. r.Qty = r.Qty * -1
  324. }
  325. }
  326. // 采购计划 数量转为负数
  327. if r.LogType == 1 && r.Contracttype == 1 {
  328. if r.Qty > 0 {
  329. r.Qty = r.Qty * -1
  330. }
  331. }
  332. r.Recordname = contractTypeName + logTypeName
  333. r.Enumdicname = mtpcache.GetEnumDicitemName(r.Unitid)
  334. }
  335. // 现货头寸-明细:从数据库中查询敞口现货头寸明细数据
  336. func (r *ErmcpAreaSpotDetailModel) GetData() ([]interface{}, error) {
  337. sData := make([]ErmcpAreaSpotDetailModel, 0)
  338. err := db.GetEngine().SQL(r.buildSql()).Find(&sData)
  339. iDatas := make([]interface{}, 0)
  340. for i := range sData {
  341. // 注意要传指针类型(&sData[i]),因为要接口转换
  342. iDatas = append(iDatas, &sData[i])
  343. }
  344. return iDatas, err
  345. }
  346. ///////////////////////////
  347. /*历史/历史敞口*/
  348. type ErmcpHisExposure struct {
  349. RECKONDATE string `json:"reckondate" xorm:"'RECKONDATE'"` // 日照时期(yyyyMMdd)
  350. MIDDLEGOODSID int32 `json:"middlegoodsid" xorm:"'MIDDLEGOODSID'"` // 套保品种ID
  351. AREAUSERID int32 `json:"areauserid" xorm:"'AREAUSERID'"` // 所属机构
  352. TOTALSPOTQTY float64 `json:"totalspotqty" xorm:"'TOTALSPOTQTY'"` // 现货头寸总量
  353. TOTALFUTUREQTY float64 `json:"totalfutureqty" xorm:"'TOTALFUTUREQTY'"` // 期货头寸总量
  354. TOTALEXPOSURE float64 `json:"totalexposure" xorm:"'TOTALEXPOSURE'"` // 总敞口
  355. TOTALHEDGERATIO float64 `json:"totalhedgeratio" xorm:"'TOTALHEDGERATIO'"` // 敞口比例
  356. TOTALNEEDHEDGEQTY float64 `json:"totalneedhedgeqty" xorm:"'TOTALNEEDHEDGEQTY'"` // 应套保总量
  357. NEEDHEDGEEXPOSOURE float64 `json:"needhedgeexposourE" xorm:"'NEEDHEDGEEXPOSOURE'"` // 应套保敞口
  358. NEEDHEDGERATIO float64 `json:"needhedgeratio" xorm:"'NEEDHEDGERATIO'"` // 应套保敞口比例
  359. MIDDLEGOODSNAME string `json:"middlegoodsname" xorm:"'MIDDLEGOODSNAME'"` // 套保品种名称
  360. MIDDLEGOODSCODE string `json:"middlegoodscode" xorm:"'MIDDLEGOODSCODE'"` // 套保品种代码
  361. LastNum int32 `json:"-"` // 查询条数
  362. }
  363. // 历史分品种嵌套结构
  364. type ErmcpHisExposureS struct {
  365. MIDDLEGOODSID int32 `json:"middlegoodsid"` // 套保品种ID
  366. MIDDLEGOODSNAME string `json:"middlegoodsname"` // 套保品种名称
  367. Data []ErmcpHisExposure `json:"data"` // 历史敞口
  368. }
  369. func (r *ErmcpHisExposure) buildSql() string {
  370. str := "select *" +
  371. " from (select t.RECKONDATE," +
  372. " t.MIDDLEGOODSID," +
  373. " t.AREAUSERID," +
  374. " t.TOTALSPOTQTY," +
  375. " t.TOTALFUTUREQTY," +
  376. " t.TOTALEXPOSURE," +
  377. " t.TOTALHEDGERATIO," +
  378. " t.TOTALNEEDHEDGEQTY," +
  379. " t.NEEDHEDGEEXPOSOURE," +
  380. " t.NEEDHEDGERATIO," +
  381. " g.MIDDLEGOODSNAME," +
  382. " g.MIDDLEGOODSCODE" +
  383. " from Reckon_ERMCP_AreaExposure t" +
  384. " left join erms_middlegoods g" +
  385. " on t.middlegoodsid = g.middlegoodsid" +
  386. " where t.areauserid = %v" +
  387. " order by t.middlegoodsid, t.reckondate desc) a" +
  388. " where rownum <= %v"
  389. if r.LastNum <= 0 {
  390. r.LastNum = 100000 //限制最多查10W条
  391. }
  392. return fmt.Sprintf(str, r.AREAUSERID, r.LastNum)
  393. }
  394. // 获取历史敞口
  395. func (r *ErmcpHisExposure) GetData() ([]ErmcpHisExposure, error) {
  396. e := db.GetEngine()
  397. sData := make([]ErmcpHisExposure, 0)
  398. if err := e.SQL(r.buildSql()).Find(&sData); err != nil {
  399. return nil, err
  400. }
  401. return sData, nil
  402. }
  403. // 套保品种关联交易商品
  404. type ErmcpTradeGoods struct {
  405. MIDDLEGOODSID int32 `json:"middlegoodsid" xorm:"'MIDDLEGOODSID'"` // 套保商品id
  406. MIDDLEGOODSNAME string `json:"middlegoodsname" xorm:"'MIDDLEGOODSNAME'"` // 套保商品名称
  407. MIDDLEGOODSCODE string `json:"middlegoodscode" xorm:"'MIDDLEGOODSCODE'"` // 套保商品代码
  408. SRCGOODSGROUPID int32 `json:"srcgoodsgroupid" xorm:"'SRCGOODSGROUPID'"` // 源期货品种id
  409. DESTGOODSGROUPID int32 `json:"destgoodsgroupid" xorm:"'DESTGOODSGROUPID'"` // 目标期货品种id
  410. CONVERTRATIO float64 `json:"convertratio" xorm:"'CONVERTRATIO'"` // 折算系数
  411. GOODSID int32 `json:"goodsid" xorm:"pk 'GOODSID'"` // 商品id
  412. GOODSCODE string `json:"goodscode" xorm:"'GOODSCODE'"` // 商品代码
  413. GOODSNAME string `json:"goodsname" xorm:"'GOODSNAME'"` // 商品名称
  414. GOODSGROUPID int32 `json:"goodsgroupid" xorm:"'GOODSGROUPID'"` // 商品组id
  415. GOODSUNITID int32 `json:"goodsunitid" xorm:"'GOODSUNITID'"` // 套保品种单位id
  416. AREAUSERID int32 `json:"areauserid" xorm:"'AREAUSERID'"` // 所属机构id
  417. AGREEUNIT float64 `json:"agreeunit" xorm:"'agreeunit'"` // 合约单位
  418. }
  419. func (r *ErmcpTradeGoods) buildSq() string {
  420. sqlId := "SELECT t.MIDDLEGOODSID," +
  421. " t.MIDDLEGOODSNAME," +
  422. " t.MIDDLEGOODSCODE," +
  423. " t.GOODSUNITID," +
  424. " t.AREAUSERID," +
  425. " c.SRCGOODSGROUPID," +
  426. " c.DESTGOODSGROUPID," +
  427. " c.CONVERTRATIO," +
  428. " g.GOODSID," +
  429. " g.GOODSCODE," +
  430. " g.GOODSNAME," +
  431. " g.GOODSGROUPID," +
  432. " g.AGREEUNIT" +
  433. " FROM ERMS_MIDDLEGOODS t" +
  434. " INNER JOIN ERMCP_GGCONVERTCONFIG c" +
  435. " ON t.GOODSGROUPID = c.DESTGOODSGROUPID" +
  436. " INNER JOIN GOODS g" +
  437. " ON c.SRCGOODSGROUPID = g.GOODSGROUPID" +
  438. " WHERE t.AREAUSERID = %v" +
  439. " AND t.MIDDLEGOODSID = %v"
  440. sqlId = fmt.Sprintf(sqlId, r.AREAUSERID, r.MIDDLEGOODSID)
  441. return sqlId
  442. }
  443. // 获取套保商品关联的交易商品
  444. func (r *ErmcpTradeGoods) GetData() (map[int32]*ErmcpTradeGoods, error) {
  445. mData := make(map[int32]*ErmcpTradeGoods, 0)
  446. err := db.GetEngine().SQL(r.buildSq()).Find(&mData)
  447. return mData, err
  448. }
  449. // 获取用户头寸(子账户)
  450. type ErmcpTradePosition struct {
  451. USERID int32 `json:"userid" xorm:"'userid'"` // 用户id
  452. GOODSID int32 `json:"goodsid" xorm:"'goodsid'"` // 商品id
  453. BUYPOSITIONQTY int64 `json:"buypositionqty" xorm:"'Buypositionqty'"` // 买期初持仓
  454. BUYCURPOSITIONQTY int64 `json:"buycurpositionqty" xorm:"'Buycurpositionqty'"` // 买当前持仓
  455. SELLPOSITIONQTY int64 `json:"sellpositionqty" xorm:"'Sellpositionqty'"` // 卖期初持仓
  456. SELLCURPOSITIONQTY int64 `json:"sellcurpositionqty" xorm:"'Sellcurpositionqty'"` // 卖当前持仓
  457. }
  458. func (r *ErmcpTradePosition) buildSql() string {
  459. sqlId := "select a.relateduserid userid," +
  460. " a.goodsid," +
  461. " sum(a.buypositionqty) buypositionqty," +
  462. " sum(a.buycurpositionqty) buycurpositionqty," +
  463. " sum(a.sellpositionqty) sellpositionqty," +
  464. " sum(a.sellcurpositionqty) sellcurpositionqty" +
  465. " from (select ta.userid, t.*" +
  466. " from tradeposition t" +
  467. " inner join taaccount ta" +
  468. " on t.accountid = ta.accountid" +
  469. " where ta.relateduserid = %v and ismain=0" +
  470. " ) a" +
  471. " group by a.userid, a.goodsid"
  472. sqlId = fmt.Sprintf(sqlId, r.USERID)
  473. return sqlId
  474. }
  475. // 获取用户持仓头寸(子账户)
  476. func (r *ErmcpTradePosition) GetData() ([]ErmcpTradePosition, error) {
  477. sData := make([]ErmcpTradePosition, 0)
  478. err := db.GetEngine().SQL(r.buildSql()).Find(&sData)
  479. return sData, err
  480. }
  481. // 用户头寸(母账户)
  482. type ErmcpHedgePosition struct {
  483. RELATEDUSERID int32 `json:"relateduserid" xorm:"'RELATEDUSERID'"` // 关联用户id
  484. ACCOUNTID int64 `json:"accountid" xorm:"'ACCOUNTID'"` // 资金账号[外部母账户]
  485. HEDGEGOODSID int32 `json:"hedgegoodsid" xorm:"'HEDGEGOODSID'"` // 对冲合约ID
  486. HEDGEACCOUNTCODE string `json:"hedgeaccountcode" xorm:"'HEDGEACCOUNTCODE'"` // 对冲账号
  487. TRADEDATE string `json:"tradedate" xorm:"'TRADEDATE'"` // 交易日(yyyyMMdd)
  488. MARKETID int32 `json:"marketid" xorm:"'mARKETID'"` // 市场ID
  489. YDBUYPOSITION int32 `json:"ydbuyposition" xorm:"'YDBUYPOSITION'"` // 期初买头寸
  490. CURBUYPOSITION int32 `json:"curbuyposition" xorm:"'CURBUYPOSITION'"` // 期末买头寸
  491. CURYDBUYPOSITION int32 `json:"curydbuyposition" xorm:"'CURYDBUYPOSITION'"` // 期末上日买头寸
  492. CURTDBUYPOSITION int32 `json:"curtdbuyposition" xorm:"'CURTDBUYPOSITION'"` // 期末今日买头寸
  493. FREYDBUYPOSITION int32 `json:"freydbuyposition" xorm:"'FREYDBUYPOSITION'"` // 冻结上日买头寸
  494. FRETDBUYPOSITION int32 `json:"fretdbuyposition" xorm:"'FRETDBUYPOSITION'"` // 冻结今日买头寸
  495. YDSELLPOSITION int32 `json:"ydsellposition" xorm:"'YDSELLPOSITION'"` // 期初卖头寸
  496. CURSELLPOSITION int32 `json:"cursellposition" xorm:"'CURSELLPOSITION'"` // 期末卖头寸
  497. CURYDSELLPOSITION int32 `json:"curydsellposition" xorm:"'CURYDSELLPOSITION'"` // 期末上日卖头寸
  498. CURTDSELLPOSITION int32 `json:"curtdsellposition" xorm:"'CURTDSELLPOSITION'"` // 期末今日卖头寸
  499. FREYDSELLPOSITION int32 `json:"freydsellposition" xorm:"'FREYDSELLPOSITION'"` // 冻结上日卖头寸
  500. FRETDSELLPOSITION int32 `json:"fretdsellposition" xorm:"'FRETDSELLPOSITION'"` // 冻结今日卖头寸
  501. GOODSID int32 `json:"goodsid" xorm:"'GOODSID'"` // 商品id
  502. GOODSCODE string `json:"goodscode" xorm:"'GOODSCODE'"` // 商品代码
  503. GOODSNAME string `json:"goodsname" xorm:"'GOODSNAME'"` // 商品名称
  504. TotalYdQty int32 `json:"totalydqty"` // 昨日数量(净头寸) = 期初买头寸 - 期初卖头寸
  505. TotalCurQty int32 `json:"totalcurqty"` // 当前数量(净头寸) = 期末买头寸 - 期末卖头寸
  506. IncreaseQty int32 `json:"increaseqty"` // 增加数量 = 期末买头寸 - 期初买头寸
  507. DecreaseQty int32 `json:"decreaseqty"` // 减少数量 = (期末卖头寸 - 期初卖头寸)*-1
  508. }
  509. func (r *ErmcpHedgePosition) Calc() {
  510. r.TotalYdQty = r.YDBUYPOSITION - r.YDSELLPOSITION
  511. r.TotalCurQty = r.CURBUYPOSITION - r.CURSELLPOSITION
  512. r.IncreaseQty = r.CURBUYPOSITION - r.YDBUYPOSITION
  513. r.DecreaseQty = (r.CURSELLPOSITION - r.YDSELLPOSITION) * -1
  514. }
  515. func (r *ErmcpHedgePosition) buildSql() string {
  516. sqlId := "select ta.RELATEDUSERID," +
  517. " t.ACCOUNTID," +
  518. " t.HEDGEGOODSID," +
  519. " t.HEDGEACCOUNTCODE," +
  520. " t.TRADEDATE," +
  521. " t.MARKETID," +
  522. " t.YDBUYPOSITION," +
  523. " t.CURBUYPOSITION," +
  524. " t.CURYDBUYPOSITION," +
  525. " t.CURTDBUYPOSITION," +
  526. " t.FREYDBUYPOSITION," +
  527. " t.FRETDBUYPOSITION," +
  528. " t.YDSELLPOSITION," +
  529. " t.CURSELLPOSITION," +
  530. " t.CURYDSELLPOSITION," +
  531. " t.CURTDSELLPOSITION," +
  532. " t.FREYDSELLPOSITION," +
  533. " t.FRETDSELLPOSITION," +
  534. " g.goodsid," +
  535. " g.goodscode," +
  536. " g.goodsname" +
  537. " from hedge_outtradeposition t" +
  538. " inner join taaccount ta" +
  539. " on t.accountid = ta.accountid" +
  540. " and ta.ismain = 1" +
  541. " and ta.relateduserid = %v" +
  542. " left join goods g" +
  543. " on t.hedgegoodsid = g.goodsid"
  544. sqlId = fmt.Sprintf(sqlId, r.RELATEDUSERID)
  545. return sqlId
  546. }
  547. // 获取对冲头寸(母账号头寸)
  548. func (r *ErmcpHedgePosition) GetData() ([]ErmcpHedgePosition, error) {
  549. sData := make([]ErmcpHedgePosition, 0)
  550. err := db.GetEngine().SQL(r.buildSql()).Find(&sData)
  551. for i := range sData {
  552. sData[i].Calc()
  553. }
  554. return sData, err
  555. }
  556. // 实时敞口\期货明细(头寸)
  557. type ErmcpExposurePostion struct {
  558. AREAUSERID int32 `json:"areauserid" xorm:"'AREAUSERID'"` // 所属机构id
  559. MIDDLEGOODSID int32 `json:"middlegoodsid" xorm:"'MIDDLEGOODSID'"` // 套保商品id
  560. GOODSID int32 `json:"goodsid" xorm:"'GOODSID'"` // 商品id
  561. GOODSCODE string `json:"goodscode" xorm:"'GOODSCODE'"` // 商品代码
  562. GOODSNAME string `json:"goodsname" xorm:"'GOODSNAME'"` // 商品名称
  563. YdQty int64 `json:"ydqty" xorm:"'YdQty'"` // 昨日持仓
  564. CurQty int64 `json:"curqty" xorm:"'CurQty'"` // 当前持仓
  565. DiffQty int64 `json:"diffqty" xorm:"'DiffQty'"` // 持仓变动量=当前持仓-昨日持仓
  566. DiffHedgeQty float64 `json:"diffhedgeqty" xorm:"'DiffHedgeQty'"` // 套保品种变动量=持仓变动量*期货合约单位*期货品种系数
  567. AGREEUNIT string `json:"agreeunit"` // 合约单位
  568. CONVERTRATIO float64 `json:"convertratio"` // 期货品种系数(折算系数)
  569. }
  570. // 子账户相关计算(不一定用得到,现在说都是查母账号的)
  571. func (r *ErmcpExposurePostion) ParseFromPos(val *ErmcpTradeGoods, data *ErmcpTradePosition) {
  572. r.AREAUSERID = val.AREAUSERID
  573. r.MIDDLEGOODSID = val.MIDDLEGOODSID
  574. r.GOODSID = val.MIDDLEGOODSID
  575. r.GOODSCODE = val.GOODSCODE
  576. r.GOODSNAME = val.GOODSNAME
  577. //相关计算
  578. r.YdQty = data.BUYPOSITIONQTY - data.SELLPOSITIONQTY
  579. r.CurQty = data.BUYCURPOSITIONQTY - data.SELLCURPOSITIONQTY
  580. r.DiffQty = r.CurQty - r.YdQty
  581. r.DiffHedgeQty = float64(r.DiffQty) * float64(val.AGREEUNIT) * val.CONVERTRATIO
  582. r.CONVERTRATIO = val.CONVERTRATIO
  583. if strName := mtpcache.GetEnumDicitemName(val.GOODSUNITID); len(strName) > 0 {
  584. r.AGREEUNIT = fmt.Sprintf("%v%v/手", val.AGREEUNIT, strName)
  585. }
  586. }
  587. // 母账户相关计算
  588. func (r *ErmcpExposurePostion) ParseFromHedgePos(val *ErmcpTradeGoods, data *ErmcpHedgePosition) {
  589. r.AREAUSERID = val.AREAUSERID
  590. r.MIDDLEGOODSID = val.MIDDLEGOODSID
  591. r.GOODSID = val.MIDDLEGOODSID
  592. r.GOODSCODE = val.GOODSCODE
  593. r.GOODSNAME = val.GOODSNAME
  594. //相关计算
  595. r.YdQty = int64(data.YDBUYPOSITION - data.YDSELLPOSITION)
  596. r.CurQty = int64(data.CURBUYPOSITION - data.CURSELLPOSITION)
  597. r.DiffQty = r.CurQty - r.YdQty
  598. r.DiffHedgeQty = float64(r.DiffQty) * float64(val.AGREEUNIT) * val.CONVERTRATIO
  599. r.CONVERTRATIO = val.CONVERTRATIO
  600. if strName := mtpcache.GetEnumDicitemName(val.GOODSUNITID); len(strName) > 0 {
  601. r.AGREEUNIT = fmt.Sprintf("%v%v/手", val.AGREEUNIT, strName)
  602. }
  603. }
  604. // 获取敞口明细期货头寸
  605. func (r *ErmcpExposurePostion) GetDataEx() (interface{}, error) {
  606. // 查询交易商品
  607. mg := ErmcpTradeGoods{AREAUSERID: r.AREAUSERID, MIDDLEGOODSID: r.MIDDLEGOODSID}
  608. sGoods, err := mg.GetData()
  609. if err != nil || sGoods == nil || len(sGoods) == 0 {
  610. return nil, err
  611. }
  612. // 查询头寸(母账号)
  613. mp := ErmcpHedgePosition{RELATEDUSERID: r.AREAUSERID}
  614. sPostion, err1 := mp.GetData()
  615. if err1 != nil || sPostion == nil || len(sPostion) == 0 {
  616. return nil, err1
  617. }
  618. // 合并处理
  619. sData := make([]ErmcpExposurePostion, 0)
  620. for i := range sPostion {
  621. if val, ok := sGoods[sPostion[i].HEDGEGOODSID]; ok {
  622. d := ErmcpExposurePostion{}
  623. d.ParseFromHedgePos(val, &sPostion[i])
  624. sData = append(sData, d)
  625. }
  626. }
  627. return sData, nil
  628. }
  629. // 敞口/期货头寸/期货明细
  630. type ErmcpHedgePositionDetail struct {
  631. HEDGEGOODSID int32 `json:"hedgegoodsid" xorm:"'HEDGEGOODSID'"` // 商品id
  632. BUYORSELL int32 `json:"buyorsell" xorm:"'BUYORSELL'"` // 买卖方向 0-买 1-卖
  633. TRADEQTY int32 `json:"tradeqty" xorm:"'TRADEQTY'"` // 数量(成交数量)
  634. CHANNELBUILDTYPE int32 `json:"channelbuildtype" xorm:"'CHANNELBUILDTYPE'"` // 开平方向 1-建仓 2-平仓
  635. TRADETIME string `json:"tradetime" xorm:"'TRADETIME'"` // 时间(成交时间)
  636. GOODSCODE string `json:"goodscode" xorm:"'GOODSCODE'"` // 商品代码
  637. GOODSNAME string `json:"goodsname" xorm:"'GOODSNAME'"` // 商品名称
  638. AREAUSERID int32 `json:"-"` // 所属机构id
  639. }
  640. func (r *ErmcpHedgePositionDetail) Calc() {
  641. if r.BUYORSELL == 1 && r.TRADEQTY > 0 {
  642. r.TRADEQTY = r.TRADEQTY * -1
  643. }
  644. }
  645. func (r *ErmcpHedgePositionDetail) buildSql() string {
  646. sqlId := "select t.hedgegoodsid," +
  647. " t.buyorsell," +
  648. " tradeqty," +
  649. " t.channelbuildtype," +
  650. " to_char(t.tradetime, 'yyyy-mm-dd hh24:mi:ss') tradetime," +
  651. " g.goodscode," +
  652. " g.goodsname" +
  653. " from hedge_outtradedetail t" +
  654. " inner join taaccount ta" +
  655. " on t.accountid = ta.accountid" +
  656. " and ta.ismain = 1" +
  657. " and ta.relateduserid = %v" +
  658. " left join goods g" +
  659. " on t.hedgegoodsid = g.goodsid" +
  660. " where t.hedgegoodsid = %v" +
  661. " union all " +
  662. "select t.hedgegoodsid," +
  663. " t.buyorsell," +
  664. " tradeqty," +
  665. " t.channelbuildtype," +
  666. " to_char(t.tradetime, 'yyyy-mm-dd hh24:mi:ss') tradetime," +
  667. " g.goodscode," +
  668. " g.goodsname" +
  669. " from his_hedge_outtradedetail t" +
  670. " inner join taaccount ta" +
  671. " on t.accountid = ta.accountid" +
  672. " and ta.ismain = 1" +
  673. " and ta.relateduserid = %v" +
  674. " left join goods g" +
  675. " on t.hedgegoodsid = g.goodsid" +
  676. " where t.isvalid = 1" +
  677. " and t.hedgegoodsid = %v"
  678. sqlId = fmt.Sprintf(sqlId, r.AREAUSERID, r.HEDGEGOODSID, r.AREAUSERID, r.HEDGEGOODSID)
  679. return sqlId
  680. }
  681. // 获取持仓头寸明细(成交记录)
  682. func (r *ErmcpHedgePositionDetail) GetDataEx() (interface{}, error) {
  683. sData := make([]ErmcpHedgePositionDetail, 0)
  684. err := db.GetEngine().SQL(r.buildSql()).Find(&sData)
  685. for i := range sData {
  686. sData[i].Calc()
  687. }
  688. return sData, err
  689. }