gitee.com/quant1x/engine@v1.8.4/datasource/base/tdx_transaction.go (about) 1 package base 2 3 import ( 4 "gitee.com/quant1x/engine/cache" 5 "gitee.com/quant1x/engine/config" 6 "gitee.com/quant1x/exchange" 7 "gitee.com/quant1x/gotdx" 8 "gitee.com/quant1x/gotdx/quotes" 9 "gitee.com/quant1x/gox/api" 10 "gitee.com/quant1x/gox/logger" 11 "gitee.com/quant1x/gox/runtime" 12 "strconv" 13 "sync" 14 ) 15 16 //const ( 17 // defaultTradingDataBeginDate = "20231001" 18 //) 19 20 var ( 21 __historicalTradingDataOnce sync.Once 22 __historicalTradingDataMutex sync.Mutex 23 __historicalTradingDataBeginDate = config.GetDataConfig().Trans.BeginDate // 最早的时间 24 ) 25 26 func lazyInitHistoricalTradingData() { 27 date := config.GetDataConfig().Trans.BeginDate 28 __historicalTradingDataBeginDate = exchange.FixTradeDate(date, cache.TDX_FORMAT_PROTOCOL_DATE) 29 } 30 31 // UpdateBeginDateOfHistoricalTradingData 修改tick数据开始下载的日期 32 func UpdateBeginDateOfHistoricalTradingData(date string) { 33 __historicalTradingDataOnce.Do(lazyInitHistoricalTradingData) 34 __historicalTradingDataMutex.Lock() 35 defer __historicalTradingDataMutex.Unlock() 36 dt, err := api.ParseTime(date) 37 if err != nil { 38 return 39 } 40 date = dt.Format(cache.TDX_FORMAT_PROTOCOL_DATE) 41 __historicalTradingDataBeginDate = date 42 } 43 44 // RestoreBeginDateOfHistoricalTradingData 恢复默认的成交数据最早日期 45 func RestoreBeginDateOfHistoricalTradingData() { 46 UpdateBeginDateOfHistoricalTradingData(config.GetDataConfig().Trans.BeginDate) 47 } 48 49 // GetBeginDateOfHistoricalTradingData 获取系统默认的历史成交数据的最早日期 50 func GetBeginDateOfHistoricalTradingData() string { 51 __historicalTradingDataOnce.Do(lazyInitHistoricalTradingData) 52 __historicalTradingDataMutex.Lock() 53 defer __historicalTradingDataMutex.Unlock() 54 return __historicalTradingDataBeginDate 55 } 56 57 // GetHistoricalTradingData 获取指定日期的历史成交数据 58 // 59 // Deprecated: 废弃的函数, 推荐 CheckoutTransactionData [wangfeng on 2024/1/31 17:26] 60 func GetHistoricalTradingData(securityCode, tradeDate string) []quotes.TickTransaction { 61 securityCode = exchange.CorrectSecurityCode(securityCode) 62 tdxApi := gotdx.GetTdxApi() 63 offset := uint16(quotes.TDX_TRANSACTION_MAX) 64 start := uint16(0) 65 history := make([]quotes.TickTransaction, 0) 66 hs := make([]quotes.TransactionReply, 0) 67 u32Date := exchange.ToUint32Date(tradeDate) 68 for { 69 var data *quotes.TransactionReply 70 var err error 71 retryTimes := 0 72 for retryTimes < quotes.DefaultRetryTimes { 73 data, err = tdxApi.GetHistoryTransactionData(securityCode, u32Date, start, offset) 74 if err == nil && data != nil { 75 break 76 } 77 retryTimes++ 78 } 79 if err != nil { 80 logger.Errorf("code=%s, tradeDate=%s, error=%s", securityCode, tradeDate, err.Error()) 81 return []quotes.TickTransaction{} 82 } 83 if data == nil || data.Count == 0 { 84 break 85 } 86 hs = append(hs, *data) 87 if data.Count < offset { 88 break 89 } 90 start += offset 91 } 92 // 这里需要反转一下 93 hs = api.Reverse(hs) 94 for _, v := range hs { 95 history = append(history, v.List...) 96 } 97 98 return history 99 } 100 101 // GetAllHistoricalTradingData 下载全部历史成交数据 102 func GetAllHistoricalTradingData(securityCode string) { 103 defer runtime.CatchPanic("trans: code=%s", securityCode) 104 securityCode = exchange.CorrectSecurityCode(securityCode) 105 tdxApi := gotdx.GetTdxApi() 106 info, err := tdxApi.GetFinanceInfo(securityCode) 107 if err != nil { 108 return 109 } 110 tStart := strconv.FormatInt(int64(info.IPODate), 10) 111 fixStart := GetBeginDateOfHistoricalTradingData() 112 if tStart < fixStart { 113 tStart = fixStart 114 } 115 tEnd := exchange.Today() 116 dateRange := exchange.TradingDateRange(tStart, tEnd) 117 // 反转切片 118 dateRange = api.Reverse(dateRange) 119 if len(dateRange) == 0 { 120 return 121 } 122 today := dateRange[0] 123 ignore := false 124 for _, tradeDate := range dateRange { 125 if ignore { 126 continue 127 } 128 fname := cache.TransFilename(securityCode, tradeDate) 129 if tradeDate != today && api.FileIsValid(fname) { 130 // 如果已经存在, 假定之前的数据已经下载过了, 不需要继续 131 ignore = true 132 continue 133 } 134 list := GetHistoricalTradingDataByDate(securityCode, tradeDate) 135 if len(list) == 0 && tradeDate != today { 136 // 如果数据为空, 且不是当前日期, 认定为从这天起往前是没有分笔成交数据的 137 ignore = true 138 } 139 } 140 141 return 142 } 143 144 // GetHistoricalTradingDataByDate 获取指定日期的历史成交记录 145 func GetHistoricalTradingDataByDate(securityCode string, date string) (list []quotes.TickTransaction) { 146 securityCode = exchange.CorrectSecurityCode(securityCode) 147 list = CheckoutTransactionData(securityCode, date, false) 148 if len(list) == 0 { 149 return list 150 } 151 tickFile := cache.TransFilename(securityCode, date) 152 err := api.SlicesToCsv(tickFile, list) 153 if err != nil { 154 return []quotes.TickTransaction{} 155 } 156 157 return list 158 } 159 160 // CheckoutTransactionData 获取指定日期的分笔成交记录 161 // 162 // 先从缓存获取, 如果缓存不存在, 则从服务器下载 163 // K线附加成交数据 164 func CheckoutTransactionData(securityCode string, date string, ignorePreviousData bool) (list []quotes.TickTransaction) { 165 securityCode = exchange.CorrectSecurityCode(securityCode) 166 // 对齐日期格式: YYYYMMDD 167 tradeDate := exchange.FixTradeDate(date, cache.TDX_FORMAT_PROTOCOL_DATE) 168 if ignorePreviousData { 169 // 在默认日期之前的数据直接返回空 170 startDate := exchange.FixTradeDate(GetBeginDateOfHistoricalTradingData(), cache.TDX_FORMAT_PROTOCOL_DATE) 171 if tradeDate < startDate { 172 logger.Errorf("tick: code=%s, trade-date=%s, start-date=%s, 没有数据", securityCode, tradeDate, startDate) 173 return list 174 } 175 } 176 startTime := exchange.HistoricalTransactionDataFirstTime 177 filename := cache.TransFilename(securityCode, tradeDate) 178 if api.FileExist(filename) { 179 // 如果缓存存在 180 err := api.CsvToSlices(filename, &list) 181 cacheLength := len(list) 182 if err == nil && cacheLength > 0 { 183 lastTime := list[cacheLength-1].Time 184 if lastTime == exchange.HistoricalTransactionDataLastTime { 185 //logger.Warnf("tick: code=%s, trade-date=%s, 缓存存在", securityCode, tradeDate) 186 return 187 } 188 firstTime := "" 189 skipCount := 0 190 for i := 0; i < cacheLength; i++ { 191 tm := list[cacheLength-1-i].Time 192 if len(firstTime) == 0 { 193 firstTime = tm 194 startTime = firstTime 195 skipCount++ 196 continue 197 } 198 if tm < firstTime { 199 startTime = firstTime 200 break 201 } else { 202 skipCount++ 203 } 204 } 205 // 截取 startTime之前的记录 206 list = list[0 : cacheLength-skipCount] 207 } else { 208 logger.Errorf("tick: code=%s, trade-date=%s, 没有有效数据, %+v", securityCode, tradeDate, err) 209 } 210 } 211 212 tdxApi := gotdx.GetTdxApi() 213 offset := uint16(quotes.TDX_TRANSACTION_MAX) 214 u32Date := exchange.ToUint32Date(tradeDate) 215 // 只求增量, 分笔成交数据是从后往前取数据, 缓存是从前到后顺序存取 216 start := uint16(0) 217 history := make([]quotes.TickTransaction, 0) 218 hs := make([]quotes.TransactionReply, 0) 219 for { 220 var data *quotes.TransactionReply 221 var err error 222 retryTimes := 0 223 for retryTimes < quotes.DefaultRetryTimes { 224 if exchange.CurrentlyTrading(tradeDate) { 225 data, err = tdxApi.GetTransactionData(securityCode, start, offset) 226 } else { 227 data, err = tdxApi.GetHistoryTransactionData(securityCode, u32Date, start, offset) 228 } 229 if err == nil && data != nil { 230 break 231 } 232 retryTimes++ 233 } 234 if err != nil { 235 logger.Errorf("code=%s, tradeDate=%s, error=%s", securityCode, tradeDate, err.Error()) 236 return 237 } 238 if data == nil || data.Count == 0 { 239 break 240 } 241 var tmp quotes.TransactionReply 242 tmpList := api.Reverse(data.List) 243 for _, td := range tmpList { 244 // 追加包含startTime之后的记录 245 if td.Time >= startTime { 246 tmp.Count += 1 247 tmp.List = append(tmp.List, td) 248 } 249 } 250 tmp.List = api.Reverse(tmp.List) 251 hs = append(hs, tmp) 252 if tmp.Count < offset { 253 // 已经是最早的记录 254 // 需要排序 255 break 256 } 257 start += offset 258 } 259 // 这里需要反转一下 260 hs = api.Reverse(hs) 261 for _, v := range hs { 262 history = append(history, v.List...) 263 } 264 if len(history) == 0 { 265 return 266 } 267 list = append(list, history...) 268 269 return 270 }