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  }