gitee.com/quant1x/engine@v1.8.4/datasource/base/tdx_kline.go (about) 1 package base 2 3 import ( 4 "gitee.com/quant1x/exchange" 5 "gitee.com/quant1x/gox/api" 6 "gitee.com/quant1x/num" 7 "gitee.com/quant1x/pandas" 8 "sync" 9 ) 10 11 var ( 12 klineMutex sync.RWMutex 13 routineLocalKLines = map[string][]KLine{} 14 ) 15 16 func checkKLineOffset(klines []KLine, date string) (offset int) { 17 rows := len(klines) 18 offset = 0 19 for i := 0; i < rows; i++ { 20 klineDate := klines[rows-1-i].Date 21 if klineDate < date { 22 return -1 23 } else if klineDate == date { 24 break 25 } else { 26 offset++ 27 } 28 } 29 if offset+1 >= rows { 30 return -1 31 } 32 return 33 } 34 35 // UpdateCacheKLines 更新缓存K线 36 func UpdateCacheKLines(securityCode string, klines []KLine) { 37 if len(klines) == 0 { 38 return 39 } 40 klineMutex.Lock() 41 routineLocalKLines[securityCode] = klines 42 klineMutex.Unlock() 43 } 44 45 // CheckoutKLines 捡出指定日期的K线数据 46 func CheckoutKLines(code, date string) []KLine { 47 securityCode := exchange.CorrectSecurityCode(code) 48 date = exchange.FixTradeDate(date) 49 // 1. 取缓存的K线 50 klineMutex.RLock() 51 cacheKLines, ok := routineLocalKLines[securityCode] 52 klineMutex.RUnlock() 53 if !ok { 54 cacheKLines = LoadBasicKline(securityCode) 55 UpdateCacheKLines(securityCode, cacheKLines) 56 } 57 rows := len(cacheKLines) 58 if rows == 0 { 59 return nil 60 } 61 // 1.1 检查是否最新数据 62 kline := cacheKLines[rows-1] 63 if kline.Date < date { 64 // 数据太旧, 重新加载 65 cacheKLines = LoadBasicKline(securityCode) 66 UpdateCacheKLines(securityCode, cacheKLines) 67 } 68 // 2. 对齐数据缓存的日期, 过滤可能存在停牌没有数据的情况 69 offset := checkKLineOffset(cacheKLines, date) 70 if offset < 0 { 71 return nil 72 } 73 // 3. 返回指定日期前的K线数据 74 klines := cacheKLines[0 : rows-offset] 75 return klines 76 } 77 78 // 由日线计算日线以上级别的K线 79 func getPeriodKLine(checkPeriod func(date ...string) (s, e string), securityCode string, cacheKLine ...[]KLine) (list []KLine) { 80 baseKLines := []KLine{} 81 if len(cacheKLine) > 0 { 82 baseKLines = cacheKLine[0] 83 } else { 84 baseKLines = LoadBasicKline(securityCode) 85 } 86 if len(baseKLines) == 0 { 87 return 88 } 89 90 var klines []KLine 91 var kline KLine 92 length := len(baseKLines) 93 for i, v := range baseKLines { 94 // 确定时间, 周线的日期是本周内最后一个交易日 95 if len(kline.Date) == 0 { 96 // 重新计算周线, 先确认周线范围 97 ws, we := checkPeriod(v.Date) 98 _ = ws 99 periodLastDate := exchange.FixTradeDate(we) 100 offset := i 101 for { 102 destDate := baseKLines[offset].Date 103 if destDate < periodLastDate { 104 offset++ 105 } 106 if offset >= length { 107 periodLastDate = destDate 108 break 109 } else if baseKLines[offset].Date == periodLastDate { 110 periodLastDate = baseKLines[offset].Date 111 break 112 } else if baseKLines[offset].Date > periodLastDate { 113 periodLastDate = destDate 114 break 115 } 116 } 117 kline.Date = periodLastDate 118 } 119 // 周线开盘价以第一天OPEN为准 120 if kline.Open == num.DType(0) { 121 kline.Open = v.Open 122 } 123 // 周线的收盘价以本周最后一个交易日的CLOSE为准 124 kline.Close = v.Close 125 if kline.High == num.DType(0) { 126 kline.High = v.High 127 } else if kline.High < v.High { 128 kline.High = v.High 129 } 130 if kline.Low == num.DType(0) { 131 kline.Low = v.Low 132 } else if kline.Low > v.Low { 133 kline.Low = v.Low 134 } 135 kline.Volume += v.Volume 136 kline.Amount += v.Amount 137 138 // 切换下一周 139 if kline.Date == v.Date || i+1 >= len(baseKLines) { 140 kline.Date = v.Date 141 klines = append(klines, kline) 142 kline = KLine{} 143 } 144 } 145 return klines 146 } 147 148 // 由日线计算日线以上级别的K线 149 func periodKLine(checkPeriod func(date ...string) (s, e string), securityCode string, cacheKLine ...[]KLine) (df pandas.DataFrame) { 150 klines := getPeriodKLine(checkPeriod, securityCode, cacheKLine...) 151 df = pandas.LoadStructs(klines) 152 return 153 } 154 155 // WKLine 周线 156 func WKLine(securityCode string, cacheKLine ...[]KLine) []KLine { 157 klines := getPeriodKLine(api.GetWeekDay, securityCode, cacheKLine...) 158 return klines 159 } 160 161 // WeeklyKLine 周线 162 func WeeklyKLine(securityCode string, cacheKLine ...[]KLine) (df pandas.DataFrame) { 163 return periodKLine(api.GetWeekDay, securityCode, cacheKLine...) 164 } 165 166 // MonthlyKLine 月K线 167 func MonthlyKLine(securityCode string, cacheKLine ...[]KLine) (df pandas.DataFrame) { 168 return periodKLine(api.GetMonthDay, securityCode, cacheKLine...) 169 }