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  }