candle_calc.go 7.8 KB

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