quote.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. package models
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "mtp2_if/db"
  7. "mtp2_if/logger"
  8. "mtp2_if/rediscli"
  9. "mtp2_if/utils"
  10. "strings"
  11. "time"
  12. "gopkg.in/mgo.v2/bson"
  13. )
  14. // CycleType 周期类型
  15. type CycleType int
  16. const (
  17. // CycleTypeSecond 周期类型 - 秒
  18. CycleTypeSecond CycleType = 0
  19. // CycleTypeMinutes1 周期类型 - 1分钟
  20. CycleTypeMinutes1 CycleType = 1
  21. // CycleTypeMinutes5 周期类型 - 5分钟
  22. CycleTypeMinutes5 CycleType = 2
  23. // CycleTypeMinutes30 周期类型 - 30分钟
  24. CycleTypeMinutes30 CycleType = 3
  25. // CycleTypeMinutes60 周期类型 - 60分钟
  26. CycleTypeMinutes60 CycleType = 4
  27. // CycleTypeMinutes120 周期类型 - 2小时
  28. CycleTypeMinutes120 CycleType = 120
  29. // CycleTypeMinutes240 周期类型 - 4小时
  30. CycleTypeMinutes240 CycleType = 240
  31. // CycleTypeMinutesDay 周期类型 - 日线
  32. CycleTypeMinutesDay CycleType = 11
  33. // CycleTypeWeek 周期类型 - 周线
  34. CycleTypeWeek CycleType = 12
  35. // CycleTypeMonth 周期类型 - 月线
  36. CycleTypeMonth CycleType = 13
  37. // CycleTypeYear 周期类型 - 年线
  38. CycleTypeYear CycleType = 14
  39. // CycleTypeTik 周期类型 - Tik
  40. CycleTypeTik CycleType = 10
  41. )
  42. // CycleData MongoDB中历史数据模型
  43. type CycleData struct {
  44. ID bson.ObjectId `json:"-" bson:"_id"` // id
  45. GC string `bson:"GC"` // 商品代码
  46. ST int `json:"-" bson:"ST"` // 时间戳
  47. SST string `bson:"SST"` // 时间文本
  48. Open int `bson:"Open"` // 开盘价
  49. High int `bson:"High"` // 最高价
  50. Low int `bson:"Low"` // 最低价
  51. Close int `bson:"Close"` // 收盘价
  52. TV int `bson:"TV"` // 总量
  53. TT int `bson:"TT"` // 总金额
  54. HV int `bson:"HV"` // 持仓量
  55. SP int `bson:"SP"` // 结算价,日线周期(包括)以上才有
  56. FI bool `json:"FI"` // 是否补充数据
  57. }
  58. // TikData MongoDB中Tik数据模型
  59. type TikData struct {
  60. ID bson.ObjectId `json:"-" bson:"_id"` // id
  61. GC string `bson:"GC"` // 商品代码
  62. TD int `bson:"TD"` // 交易日时间戳
  63. AT int `bson:"AT"` // 行情时间戳
  64. SAT string `bson:"SAT"` // 行情时间文本
  65. PE int `bson:"PE"` // 现价
  66. Vol int `bson:"Vol"` // 现量
  67. TT int `bson:"TT"` // 现金额
  68. Bid int `bson:"Bid"` // 买价
  69. BV int `bson:"BV"` // 买量
  70. Ask int `bson:"Ask"` // 卖价
  71. AV int `bson:"AV"` // 卖量
  72. HV int `bson:"HV"` // 持仓量
  73. HI int `bson:"HI"` // 单笔持仓
  74. TDR int `bson:"TDR"` // 交易方向
  75. TK int `bson:"TK"` // 交易类型
  76. OId int `bson:"OId"` // 行情序号
  77. }
  78. // Quoteday 行情盘面
  79. type Quoteday struct {
  80. Id int64 `xorm:"pk autoincr BIGINT(20)"`
  81. Exchangedate int64 `xorm:"not null BIGINT(20)"` // 交易日
  82. Goodscode string `xorm:"not null unique CHAR(10)"` // 商品代码
  83. Exchangecode int `xorm:"INT(11)"` // 交易所代码
  84. Preclose int64 `xorm:"default 0 BIGINT(20)"` // 昨收
  85. Opentime int64 `xorm:"BIGINT(20)"` // 开盘时间
  86. Opened int64 `xorm:"not null default 0 BIGINT(20)"` // 开盘价
  87. Highest int64 `xorm:"not null default 0 BIGINT(20)"` // 最高价
  88. Lowest int64 `xorm:"not null default 0 BIGINT(20)"` // 最低价
  89. Lasttime string `xorm:"VARCHAR(20)"` // 行情时间(只有现价变化行情时间才变化)
  90. Utclasttime int64 `xorm:"not null BIGINT(20)"` // utc的行情时间
  91. Last int64 `xorm:"not null BIGINT(20)"` // 最新价
  92. Lastvolume int64 `xorm:"default 0 BIGINT(20)"` // 最新成交量
  93. Lastturnover int64 `xorm:"default 0 BIGINT(20)"` // 最新成交金额
  94. Totalbidvolume int64 `xorm:"default 0 BIGINT(20)"` // 外盘
  95. Totalaskvolume int64 `xorm:"default 0 BIGINT(20)"` // 内盘
  96. Totalvolume int64 `xorm:"default 0 BIGINT(20)"` // 总量
  97. Totalturnover int64 `xorm:"default 0 BIGINT(20)"` // 总金额
  98. Bid int64 `xorm:"default 0 BIGINT(20)"` // 买1
  99. Bid2 int64 `xorm:"default 0 BIGINT(20)"` // 买2
  100. Bid3 int64 `xorm:"default 0 BIGINT(20)"` // 买3
  101. Bid4 int64 `xorm:"default 0 BIGINT(20)"` // 买4
  102. Bid5 int64 `xorm:"default 0 BIGINT(20)"` // 买5
  103. Bidvolume int64 `xorm:"default 0 BIGINT(20)"` // 买量1
  104. Bidvolume2 int64 `xorm:"default 0 BIGINT(20)"` // 买量2
  105. Bidvolume3 int64 `xorm:"default 0 BIGINT(20)"` // 买量3
  106. Bidvolume4 int64 `xorm:"default 0 BIGINT(20)"` // 买量4
  107. Bidvolume5 int64 `xorm:"default 0 BIGINT(20)"` // 买量5
  108. Ask int64 `xorm:"default 0 BIGINT(20)"` // 卖1
  109. Ask2 int64 `xorm:"default 0 BIGINT(20)"` // 卖2
  110. Ask3 int64 `xorm:"default 0 BIGINT(20)"` // 卖3
  111. Ask4 int64 `xorm:"default 0 BIGINT(20)"` // 卖4
  112. Ask5 int64 `xorm:"default 0 BIGINT(20)"` // 卖5
  113. Askvolume int64 `xorm:"default 0 BIGINT(20)"` // 卖量1
  114. Askvolume2 int64 `xorm:"default 0 BIGINT(20)"` // 卖量2
  115. Askvolume3 int64 `xorm:"default 0 BIGINT(20)"` // 卖量3
  116. Askvolume4 int64 `xorm:"default 0 BIGINT(20)"` // 卖量4
  117. Askvolume5 int64 `xorm:"default 0 BIGINT(20)"` // 卖量5
  118. Presettle int64 `xorm:"default 0 BIGINT(20)"` // 昨结价
  119. Settle int64 `xorm:"default 0 BIGINT(20)"` // 结算价
  120. Preholdvolume int64 `xorm:"default 0 BIGINT(20)"` // 昨持仓
  121. Holdvolume int64 `xorm:"default 0 BIGINT(20)"` // 持仓
  122. Averageprice int64 `xorm:"default 0 BIGINT(20)"` // 均价
  123. Orderid int64 `xorm:"default 0 BIGINT(20)"` // 序号
  124. Limitup int64 `xorm:"default 0 BIGINT(20)"` // 涨停价
  125. Limitdown int64 `xorm:"default 0 BIGINT(20)"` // 跌停价
  126. Inventory int64 `xorm:"default 0 BIGINT(20)"` // 库存
  127. Holdincrement int64 `xorm:"default 0 BIGINT(20)"` // 单笔持仓
  128. Iscleared int `xorm:"INT(11)"` // 是否清盘标志
  129. Issettled int `xorm:"INT(11)"` // 是否结算标志
  130. Bidqueueinfo string `xorm:"VARCHAR(2000)"` // 大利市买港股用
  131. Askqueueinfo string `xorm:"VARCHAR(2000)"` // 大利市卖港股用
  132. Bidorderid int64 `xorm:"BIGINT(20)"` // 买单号1
  133. Bidorderid2 int64 `xorm:"BIGINT(20)"` // 买单号2
  134. Bidorderid3 int64 `xorm:"BIGINT(20)"` // 买单号3
  135. Bidorderid4 int64 `xorm:"BIGINT(20)"` // 买单号4
  136. Bidorderid5 int64 `xorm:"BIGINT(20)"` // 买单号5
  137. Askorderid int64 `xorm:"BIGINT(20)"` // 卖单号1
  138. Askorderid2 int64 `xorm:"BIGINT(20)"` // 卖单号2
  139. Askorderid3 int64 `xorm:"BIGINT(20)"` // 卖单号3
  140. Askorderid4 int64 `xorm:"BIGINT(20)"` // 卖单号4
  141. Askorderid5 int64 `xorm:"BIGINT(20)"` // 卖单号5
  142. Lastlot int64 `xorm:"BIGINT(20)"` // 最新成交手数
  143. Totallot int64 `xorm:"BIGINT(20)"` // 总手数
  144. Strikeprice int64 `xorm:"BIGINT(20)"` // 发行价
  145. Cleartime int64 `xorm:"BIGINT(20)"` // 清盘时间
  146. Calloptionpremiums int64 `xorm:"default 0 BIGINT(20)"` // 认购期权1
  147. Calloptionpremiums2 int64 `xorm:"default 0 BIGINT(20)"` // 认购期权2
  148. Calloptionpremiums3 int64 `xorm:"default 0 BIGINT(20)"` // 认购期权3
  149. Calloptionpremiums4 int64 `xorm:"default 0 BIGINT(20)"` // 认购期权4
  150. Calloptionpremiums5 int64 `xorm:"default 0 BIGINT(20)"` // 认购期权5
  151. Putoptionpremiums int64 `xorm:"default 0 BIGINT(20)"` // 认沽期权1
  152. Putoptionpremiums2 int64 `xorm:"default 0 BIGINT(20)"` // 认沽期权2
  153. Putoptionpremiums3 int64 `xorm:"default 0 BIGINT(20)"` // 认沽期权3
  154. Putoptionpremiums4 int64 `xorm:"default 0 BIGINT(20)"` // 认沽期权4
  155. Putoptionpremiums5 int64 `xorm:"default 0 BIGINT(20)"` // 认沽期权5
  156. Nontotalvolume int64 `xorm:"default 0 BIGINT(20)"` // 非交易总量
  157. Nontotalholdervolume int64 `xorm:"default 0 BIGINT(20)"` // 非交易持仓量
  158. Nontotalturnover int64 `xorm:"default 0 BIGINT(20)"` // 非交易总金额
  159. Nontotallot int64 `xorm:"default 0 BIGINT(20)"` // 非交易总手数
  160. Publictradetype string `xorm:"VARCHAR(2)"` // 公共交易标志类型 港股专用
  161. Iep int64 `xorm:"default 0 BIGINT(20)"` // 平衡价 港股专用
  162. Iev int64 `xorm:"default 0 BIGINT(20)"` // 平衡量 港股专用
  163. Grepmarketprice int64 `xorm:"default 0 BIGINT(20)"` // 暗盘价 港股专用
  164. Bid6 int64 `xorm:"default 0 BIGINT(20)"` // 买6
  165. Bid7 int64 `xorm:"default 0 BIGINT(20)"` // 买7
  166. Bid8 int64 `xorm:"default 0 BIGINT(20)"` // 买8
  167. Bid9 int64 `xorm:"default 0 BIGINT(20)"` // 买9
  168. Bid10 int64 `xorm:"default 0 BIGINT(20)"` // 买10
  169. Bidvolume6 int64 `xorm:"default 0 BIGINT(20)"` // 买量6
  170. Bidvolume7 int64 `xorm:"default 0 BIGINT(20)"` // 买量7
  171. Bidvolume8 int64 `xorm:"default 0 BIGINT(20)"` // 买量8
  172. Bidvolume9 int64 `xorm:"default 0 BIGINT(20)"` // 买量9
  173. Bidvolume10 int64 `xorm:"default 0 BIGINT(20)"` // 买量10
  174. Ask6 int64 `xorm:"default 0 BIGINT(20)"` // 卖6
  175. Ask7 int64 `xorm:"default 0 BIGINT(20)"` // 卖7
  176. Ask8 int64 `xorm:"default 0 BIGINT(20)"` // 卖8
  177. Ask9 int64 `xorm:"default 0 BIGINT(20)"` // 卖9
  178. Ask10 int64 `xorm:"default 0 BIGINT(20)"` // 卖10
  179. Askvolume6 int64 `xorm:"default 0 BIGINT(20)"` // 卖量6
  180. Askvolume7 int64 `xorm:"default 0 BIGINT(20)"` // 卖量7
  181. Askvolume8 int64 `xorm:"default 0 BIGINT(20)"` // 卖量8
  182. Askvolume9 int64 `xorm:"default 0 BIGINT(20)"` // 卖量9
  183. Askvolume10 int64 `xorm:"default 0 BIGINT(20)"` // 卖量10
  184. Bidordervolume int64 `xorm:"default 0 BIGINT(20)"` // 买单量1
  185. Bidordervolume2 int64 `xorm:"default 0 BIGINT(20)"` // 买单量2
  186. Bidordervolume3 int64 `xorm:"default 0 BIGINT(20)"` // 买单量3
  187. Bidordervolume4 int64 `xorm:"default 0 BIGINT(20)"` // 买单量4
  188. Bidordervolume5 int64 `xorm:"default 0 BIGINT(20)"` // 买单量5
  189. Bidordervolume6 int64 `xorm:"default 0 BIGINT(20)"` // 买单量6
  190. Bidordervolume7 int64 `xorm:"default 0 BIGINT(20)"` // 买单量7
  191. Bidordervolume8 int64 `xorm:"default 0 BIGINT(20)"` // 买单量8
  192. Bidordervolume9 int64 `xorm:"default 0 BIGINT(20)"` // 买单量9
  193. Bidordervolume10 int64 `xorm:"default 0 BIGINT(20)"` // 买单量10
  194. Askordervolume int64 `xorm:"default 0 BIGINT(20)"` // 卖单量1
  195. Askordervolume2 int64 `xorm:"default 0 BIGINT(20)"` // 卖单量2
  196. Askordervolume3 int64 `xorm:"default 0 BIGINT(20)"` // 卖单量3
  197. Askordervolume4 int64 `xorm:"default 0 BIGINT(20)"` // 卖单量4
  198. Askordervolume5 int64 `xorm:"default 0 BIGINT(20)"` // 卖单量5
  199. Askordervolume6 int64 `xorm:"default 0 BIGINT(20)"` // 卖单量6
  200. Askordervolume7 int64 `xorm:"default 0 BIGINT(20)"` // 卖单量7
  201. Askordervolume8 int64 `xorm:"default 0 BIGINT(20)"` // 卖单量8
  202. Askordervolume9 int64 `xorm:"default 0 BIGINT(20)"` // 卖单量9
  203. Askordervolume10 int64 `xorm:"default 0 BIGINT(20)"` // 卖单量10
  204. }
  205. // TableName is Quoteday
  206. func (*Quoteday) TableName() string {
  207. return "quoteday"
  208. }
  209. // GetHistoryCycleDatas 获取历史数据
  210. // 参数 cycleType CycleType 周期类型
  211. // 参数 goodsCode string 商品代码
  212. // 参数 startTime time.Time 开始时间(闭区间)
  213. // 参数 endTime time.Time 结束时间(闭区间)
  214. // 参数 count int 条数
  215. // 参数 isAscForST bool 是否按时间顺序排序,默认为时间倒序排序
  216. // 返回值 []CycleData 历史数据
  217. // 返回值 error 错误
  218. func GetHistoryCycleDatas(cycleType CycleType, goodsCode string, startTime, endTime *time.Time, count int, isAscForST bool) ([]CycleData, error) {
  219. db := db.GetMongoDB()
  220. // 获取目标Collection
  221. collection := "mincycle"
  222. switch cycleType {
  223. case CycleTypeTik:
  224. collection = "quotetik"
  225. case CycleTypeMinutes1:
  226. collection = "mincycle"
  227. case CycleTypeMinutes5:
  228. collection = "min5cycle"
  229. case CycleTypeMinutes30:
  230. collection = "min30cycle"
  231. case CycleTypeMinutes60:
  232. collection = "min60cycle"
  233. case CycleTypeMinutes240:
  234. collection = "min240cycle"
  235. case CycleTypeMinutesDay:
  236. collection = "daycycle"
  237. case CycleTypeWeek:
  238. collection = "weekcycle"
  239. case CycleTypeMonth:
  240. collection = "monthcycle"
  241. case CycleTypeYear:
  242. collection = "yearcycle"
  243. default:
  244. return nil, errors.New("不支持的周期类型")
  245. }
  246. c := db.C(collection)
  247. // 按时间排序
  248. sort := "-ST"
  249. if isAscForST {
  250. sort = "ST"
  251. }
  252. // 查询数据
  253. var cycleDatas []CycleData
  254. m := bson.M{"GC": goodsCode}
  255. if startTime != nil && endTime == nil {
  256. m["ST"] = bson.M{"$gte": startTime.Unix()}
  257. } else if startTime == nil && endTime != nil {
  258. m["ST"] = bson.M{"$lte": endTime.Unix()}
  259. } else if startTime != nil && endTime != nil {
  260. m["ST"] = bson.M{"$gte": startTime.Unix(), "$lte": endTime.Unix()}
  261. }
  262. query := c.Find(m)
  263. if count > 0 {
  264. query = query.Limit(count)
  265. }
  266. if err := query.Sort(sort).All(&cycleDatas); err != nil {
  267. return nil, err
  268. }
  269. return cycleDatas, nil
  270. }
  271. // GetHistoryTikDatas 获取历史数据
  272. // 参数 goodsCode string 商品代码
  273. // 参数 startTime time.Time 开始时间(闭区间)
  274. // 参数 endTime time.Time 结束时间(闭区间)
  275. // 参数 count int 条数
  276. // 参数 isAscForST bool 是否按时间顺序排序,默认为时间倒序排序
  277. // 返回值 []TikData Tik数据
  278. // 返回值 error 错误
  279. func GetHistoryTikDatas(goodsCode string, startTime, endTime *time.Time, count int, isAscForST bool) ([]TikData, error) {
  280. db := db.GetMongoDB()
  281. // 获取目标Collection
  282. collection := "quotetik"
  283. c := db.C(collection)
  284. // 按时间排序
  285. sort := "-_id"
  286. if isAscForST {
  287. sort = "id"
  288. }
  289. // 查询数据
  290. var tikDatas []TikData
  291. m := bson.M{"GC": goodsCode}
  292. if startTime != nil && endTime == nil {
  293. m["AT"] = bson.M{"$gte": startTime.Unix()}
  294. } else if startTime == nil && endTime != nil {
  295. m["AT"] = bson.M{"$lte": endTime.Unix()}
  296. } else if startTime != nil && endTime != nil {
  297. m["AT"] = bson.M{"$gte": startTime.Unix(), "$lte": endTime.Unix()}
  298. }
  299. query := c.Find(m)
  300. if count > 0 {
  301. query = query.Limit(count)
  302. }
  303. if err := query.Sort(sort).All(&tikDatas); err != nil {
  304. return nil, err
  305. }
  306. return tikDatas, nil
  307. }
  308. // GetQuoteDays 获取目标商品的盘面数据
  309. // 参数 goodsCodes string 商品代码字串,以“,”分隔
  310. // 返回 []Quoteday 盘面数据
  311. // 返回 error error
  312. func GetQuoteDays(goodsCodes string) ([]Quoteday, error) {
  313. engine := db.GetMySQLEngine()
  314. datas := make([]Quoteday, 0)
  315. if len(goodsCodes) > 0 {
  316. // 指定商品代码查询
  317. // 处理商品代码, 让其可作为sql的in条件内容。 例如, 原字符串 ru2201,CU2406, => 处理成 'ru2201','CU2406'
  318. goodsCodes = strings.Trim(goodsCodes, ",")
  319. sCode := strings.Split(goodsCodes, ",")
  320. for i := range sCode {
  321. // 如果没有单引号, 则加上单引号
  322. if !strings.Contains(sCode[i], "'") {
  323. sCode[i] = "'" + sCode[i] + "'"
  324. }
  325. }
  326. Instr := strings.Join(sCode, ",")
  327. if err := engine.Where(fmt.Sprintf("goodscode in (%s)", Instr)).Find(&datas); err != nil {
  328. return nil, err
  329. }
  330. } else {
  331. // 不指定则查所有
  332. if err := engine.Find(&datas); err != nil {
  333. return nil, err
  334. }
  335. }
  336. return datas, nil
  337. }
  338. // SetRedisQuoteDays 将盘面数据同步到Redis
  339. func SetRedisQuoteDays() (err error) {
  340. engine := db.GetMySQLEngine()
  341. datas := make([]Quoteday, 0)
  342. if err = engine.Find(&datas); err != nil {
  343. return
  344. }
  345. b, err := json.Marshal(datas)
  346. if err != nil {
  347. return
  348. }
  349. redisCli := rediscli.GetRedisClient()
  350. err = redisCli.Set("Tourist:QuoteDay", b, 0).Err()
  351. return
  352. }
  353. // GetRedisQuoteDays 从Redis读取盘面数据
  354. func GetRedisQuoteDays(goodsCodes []string) (quoteDays []Quoteday, err error) {
  355. redisCli := rediscli.GetRedisClient()
  356. b, err := redisCli.Get("Tourist:QuoteDay").Bytes()
  357. if err != nil {
  358. return
  359. }
  360. var datas []Quoteday
  361. if err = json.Unmarshal(b, &datas); err != nil {
  362. return
  363. }
  364. quoteDays = make([]Quoteday, 0)
  365. for _, item := range datas {
  366. if utils.InArray(len(goodsCodes), func(i int) bool { return goodsCodes[i] == item.Goodscode }) {
  367. quoteDays = append(quoteDays, item)
  368. }
  369. }
  370. return
  371. }
  372. var Done chan bool
  373. func StartSyncRedisQuoteDay() {
  374. ticker := time.NewTicker(2 * time.Second)
  375. Done = make(chan bool)
  376. go func() {
  377. for {
  378. select {
  379. case <-Done:
  380. ticker.Stop()
  381. return
  382. case <-ticker.C:
  383. // 在这里执行定时任务的代码
  384. if err := SetRedisQuoteDays(); err != nil {
  385. logger.GetLogger().Errorf("Sync Redis failed: %s", err.Error())
  386. }
  387. }
  388. }
  389. }()
  390. }