candle_calc.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. package base
  2. //一个更加简单的计算K线的接口
  3. //提供
  4. //1. Peek
  5. //2. Align
  6. //3. Next
  7. import "tickserver/api/lmaxapi/markinfo"
  8. import "encoding/binary"
  9. import "io"
  10. import "fmt"
  11. import "unsafe"
  12. type result struct {
  13. data *OhlcGo
  14. isnew bool
  15. err error
  16. }
  17. type CandleCalc struct {
  18. candle *Candle
  19. reader io.Reader
  20. tick TickGo
  21. retTick TickGo
  22. nextTick TickGo
  23. num int
  24. peek int
  25. ret result
  26. last result
  27. symbolId int
  28. period int
  29. maxComp int
  30. minPeriod int
  31. }
  32. func NewCandleCalc(symbolId int, period int, trans *TimezoneTrans, reader io.Reader) (*CandleCalc, error) {
  33. name, err := markinfo.SymbolName(symbolId)
  34. if err != nil {return nil, err}
  35. point, err := markinfo.SymbolPoint(name)
  36. if err != nil {return nil, err}
  37. candle , err := NewCandle(period, point, nil, 0)
  38. if err != nil {
  39. return nil, err
  40. }
  41. candle.SetTimezoneTrans(trans)
  42. calc := CandleCalc{}
  43. calc.candle = candle
  44. calc.reader = reader
  45. calc.symbolId = symbolId
  46. calc.period = period
  47. calc.maxComp = 12 * 3600
  48. calc.minPeriod = 60
  49. return &calc, nil
  50. }
  51. func (calc *CandleCalc) SetConf(key int, conf interface{}) (int, error) {
  52. if key == CANDLE_AUTOCOMPLETE_MAX {
  53. calc.maxComp = conf.(int)
  54. }
  55. return calc.candle.Set(key, conf)
  56. }
  57. func (calc *CandleCalc) SetMinPeriod(period int) {
  58. calc.minPeriod = period
  59. }
  60. func (calc *CandleCalc) PeriodSecond() int {
  61. return calc.period
  62. }
  63. func (calc *CandleCalc) NodataAlignTime() int {
  64. return calc.maxComp
  65. }
  66. func (calc *CandleCalc) readTick() error {
  67. calc.retTick = calc.tick
  68. if calc.tick.Time == 0 {//first time
  69. err := calc.readNextTick()
  70. if err != nil { return err }
  71. calc.tick = calc.nextTick
  72. return nil
  73. } else {
  74. if calc.nextTick == calc.tick { //nextTick 已经被读取了
  75. err := calc.readNextTick()
  76. if err != nil { return err }
  77. }
  78. t1 := calc.minPeriod * (int(calc.nextTick.Time) /calc.minPeriod)
  79. t2 := calc.minPeriod * (int(calc.tick.Time) /calc.minPeriod)
  80. if t1 - t2 > calc.minPeriod && t1 - t2 < calc.maxComp { //需要补全,不需要读取next
  81. calc.tick.Time = int32(t2 + calc.minPeriod)
  82. return nil
  83. } else {
  84. calc.tick = calc.nextTick
  85. return nil
  86. }
  87. }
  88. return nil
  89. }
  90. func (calc *CandleCalc) readNextTick() (error) {
  91. //保存上一个tick
  92. for {
  93. err := binary.Read(calc.reader, binary.LittleEndian, &calc.nextTick)
  94. if err != nil {
  95. return err
  96. }
  97. //检查tick是否往回走了,避免这样的tick
  98. if calc.retTick.Time > calc.nextTick.Time || (calc.retTick.Time == calc.nextTick.Time && calc.retTick.Ms > calc.nextTick.Ms) {
  99. //直接忽略这样的tick
  100. fmt.Println("error tick.", calc.retTick, calc.nextTick)
  101. continue
  102. }
  103. break
  104. }
  105. return nil
  106. }
  107. func (calc *CandleCalc) Next() (*OhlcGo, bool, error) {
  108. if calc.peek > 0 {
  109. calc.peek = 0
  110. return calc.ret.data, calc.ret.isnew, calc.ret.err
  111. }
  112. if calc.num > 0 {
  113. calc.num--
  114. calc.ret.isnew = true
  115. return calc.readNext()
  116. }
  117. err := calc.readTick()
  118. if err != nil {
  119. return nil, false, err
  120. }
  121. calc.num = calc.candle.UpdateTick((*Tick)(unsafe.Pointer(&calc.tick)))
  122. if calc.num == 0 {
  123. calc.ret.isnew = false
  124. return calc.readNext()
  125. } else {
  126. calc.num--
  127. calc.ret.isnew = true
  128. return calc.readNext()
  129. }
  130. return nil, false, io.EOF
  131. }
  132. func (calc *CandleCalc) readNext() (*OhlcGo, bool, error) {
  133. ohlc := Ohlc{}
  134. calc.candle.Next(&ohlc)
  135. if calc.last.data != nil && calc.last.data.Time == calc.ret.data.Time {
  136. calc.last.isnew = false
  137. }
  138. calc.last = calc.ret
  139. //赋值
  140. tmp := ohlc.ToGOStruct()
  141. calc.ret.data = &tmp
  142. calc.ret.err = nil
  143. //fmt.Println(tmp)
  144. return calc.ret.data, calc.ret.isnew, calc.ret.err
  145. }
  146. //只能向前查看一个数据
  147. func (calc *CandleCalc) Peek() (*OhlcGo, bool, error) {
  148. if calc.peek == 0 {
  149. calc.ret.data, calc.ret.isnew, calc.ret.err = calc.Next()
  150. }
  151. calc.peek++
  152. return calc.ret.data, calc.ret.isnew, calc.ret.err
  153. }
  154. func (calc *CandleCalc) Align(time int32) (*OhlcGo, bool, error) {
  155. //补全前先往前查看一下
  156. calc.Peek()
  157. if calc.ret.data == nil && calc.last.data == nil { //保证有数据
  158. return nil, false, fmt.Errorf("no current or last data, align failed")
  159. }
  160. //第一个点的补全比较特殊,可以前后补全
  161. if calc.last.data == nil {
  162. ohlc := *calc.ret.data
  163. ohlc.Time = time
  164. //上次返回的数据
  165. calc.last = calc.ret
  166. calc.last.data = &ohlc
  167. return &ohlc, calc.ret.isnew, calc.ret.err
  168. }
  169. if time == 0 {
  170. return calc.last.data, false, calc.last.err
  171. }
  172. current := *calc.last.data
  173. if calc.ret.data == nil {
  174. goto align
  175. }
  176. //补全不能大于ret的时间,否则时间会往回走, 所以一般补全前要peek一下
  177. if time > calc.ret.data.Time {
  178. if calc.ret.data.TickVolumn == 0 {//补全的数据,忽略到time
  179. goto align
  180. }
  181. fmt.Println(calc.tick, calc.period, time)
  182. panic(fmt.Sprintf("%d", calc.ret.data.Time))
  183. return nil, true, fmt.Errorf("time > peek Time align time error.")
  184. }
  185. if time < current.Time {
  186. return nil, true, fmt.Errorf("time < current Time align time error.")
  187. }
  188. align:
  189. //时间没有变,那么就用current
  190. if time == current.Time {
  191. calc.last.isnew = false
  192. return &current, false, calc.last.err
  193. }
  194. //往前补一个
  195. current.Time = time
  196. current.Open = current.Close
  197. current.High = current.Close
  198. current.Low = current.Close
  199. current.TickVolumn = 0
  200. current.RealVolumn = 0
  201. //更新last
  202. calc.last.data = &current
  203. calc.last.isnew = true
  204. calc.last.err = nil
  205. if calc.ret.data != nil && calc.ret.data.Time == current.Time {
  206. calc.ret.isnew = false
  207. }
  208. return &current, true, nil
  209. }
  210. func (calc *CandleCalc) LastTick() (TickGo) {
  211. return calc.tick
  212. }
  213. func (calc *CandleCalc) Last() (TickGo) {
  214. return calc.tick
  215. }
  216. func (calc *CandleCalc) RetTime() int32 {
  217. return calc.ret.data.Time
  218. }
  219. func (calc *CandleCalc) LastTime() int32 {
  220. return calc.last.data.Time
  221. }
  222. func (calc *CandleCalc) TickTime() int64 {
  223. return int64(calc.tick.Time) * 1000 + int64(calc.tick.Ms)
  224. }
  225. func (calc *CandleCalc) AlignTick() (TickGo) {
  226. return calc.retTick
  227. }
  228. func (calc *CandleCalc) AlignTickTime(t int64) (TickGo) {
  229. tick := calc.retTick
  230. tick.Time = int32(t/1000)
  231. tick.Ms = int16(t % 1000)
  232. return tick
  233. }