gitee.com/quant1x/engine@v1.8.4/tracker/mod_sector.go (about)

     1  package tracker
     2  
     3  import (
     4  	"fmt"
     5  	"gitee.com/quant1x/engine/cache"
     6  	"gitee.com/quant1x/engine/config"
     7  	"gitee.com/quant1x/engine/factors"
     8  	"gitee.com/quant1x/engine/market"
     9  	"gitee.com/quant1x/engine/models"
    10  	"gitee.com/quant1x/exchange"
    11  	"gitee.com/quant1x/gox/api"
    12  	"gitee.com/quant1x/gox/concurrent"
    13  	"gitee.com/quant1x/gox/logger"
    14  	"gitee.com/quant1x/gox/progressbar"
    15  	"gitee.com/quant1x/gox/tags"
    16  	"gitee.com/quant1x/num"
    17  	"gitee.com/quant1x/pandas"
    18  	"gitee.com/quant1x/pkg/tablewriter"
    19  	"os"
    20  	"slices"
    21  	"sort"
    22  	"sync"
    23  	"time"
    24  )
    25  
    26  // ScanAllSectors 扫描板块
    27  func ScanAllSectors(barIndex *int, model models.Strategy) {
    28  	tradeRule := config.GetStrategyParameterByCode(model.Code())
    29  	if tradeRule == nil {
    30  		logger.Errorf("strategy[%d]: trade rule not found", model.Code())
    31  		return
    32  	}
    33  	// 执行板块指数的检测
    34  	typeBlocks := TopBlockWithType(barIndex, tradeRule)
    35  	// 不分板块类型, 所有的板块放在一起排序
    36  	allBlocks := []SectorInfo{}
    37  	for _, v := range typeBlocks {
    38  		allBlocks = append(allBlocks, v...)
    39  	}
    40  	// 扫描板块内个股排名
    41  	blockCount := len(allBlocks)
    42  	fmt.Println()
    43  	bar := progressbar.NewBar(*barIndex, "执行[板块个股涨幅扫描]", blockCount)
    44  	for i := 0; i < blockCount; i++ {
    45  		bar.Add(1)
    46  		block := &allBlocks[i]
    47  		//blockCode := block.Code
    48  		topCode := SecurityUnknown
    49  		topName := SecurityUnknown
    50  		topRate := float64(0.00)
    51  		stockCodes := block.StockCodes
    52  		stockSnapshots := []factors.QuoteSnapshot{}
    53  		for _, s := range stockCodes {
    54  			stockCode := s
    55  			securityCode := exchange.CorrectSecurityCode(stockCode)
    56  			tmpBlocks, _ := __stock2Block[securityCode]
    57  			if len(tmpBlocks) == 0 {
    58  				tmpBlocks = make([]SectorInfo, 0)
    59  			}
    60  			tmpBlocks = append(tmpBlocks, *block)
    61  			__stock2Block[securityCode] = tmpBlocks
    62  			snapshot := models.GetStrategySnapshot(securityCode)
    63  			if snapshot == nil {
    64  				continue
    65  			}
    66  			stockSnapshots = append(stockSnapshots, *snapshot)
    67  		}
    68  		if len(stockSnapshots) == 0 {
    69  			continue
    70  		}
    71  
    72  		sort.Slice(stockSnapshots, func(i, j int) bool {
    73  			a := stockSnapshots[i]
    74  			b := stockSnapshots[j]
    75  			return StockSort(a, b)
    76  		})
    77  
    78  		stockList := []string{}
    79  		for j := 0; j < len(stockSnapshots) && j < tradeRule.Rules.StockTopNInSector; j++ {
    80  			si := stockSnapshots[j]
    81  			stockCode := si.SecurityCode
    82  			if market.IsNeedIgnore(stockCode) {
    83  				continue
    84  			}
    85  			stockList = append(stockList, stockCode)
    86  		}
    87  		__block2Top[block.Code] = stockList
    88  		stockTopList := slices.Clone(stockSnapshots)
    89  		sort.Slice(stockTopList, func(i, j int) bool {
    90  			a := stockTopList[i]
    91  			b := stockTopList[j]
    92  			return a.ChangeRate > b.ChangeRate
    93  		})
    94  		topStock := stockTopList[0]
    95  		topCode = topStock.SecurityCode
    96  		f10 := factors.GetL5F10(topCode)
    97  		if f10 != nil {
    98  			topName = f10.SecurityName
    99  		}
   100  		topRate = num.NetChangeRate(topStock.LastClose, topStock.Price)
   101  		total := 0
   102  		limits := 0
   103  		ling := 0
   104  		up := 0
   105  		down := 0
   106  		for j := 0; j < len(stockSnapshots); j++ {
   107  			gp := stockSnapshots[j]
   108  			total += 1
   109  			zfLimit := exchange.MarketLimit(gp.SecurityCode)
   110  			lastClose := num.Decimal(gp.LastClose)
   111  			zhangting := num.Decimal(lastClose * float64(1.000+zfLimit))
   112  			price := num.Decimal(gp.Price)
   113  			if price >= zhangting {
   114  				limits += 1
   115  			}
   116  			if price > lastClose {
   117  				up++
   118  			} else if price < lastClose {
   119  				down++
   120  			} else {
   121  				ling += 1
   122  			}
   123  			gp.TopNo = j
   124  			_, ok := __stock2Rank[gp.SecurityCode]
   125  			if !ok {
   126  				__stock2Rank[gp.SecurityCode] = gp
   127  			}
   128  		}
   129  		for j, v := range allBlocks {
   130  			if v.Code == block.Code {
   131  				allBlocks[j].TopCode = topCode
   132  				allBlocks[j].TopName = topName
   133  				allBlocks[j].TopRate = topRate
   134  				allBlocks[j].Count = total
   135  				allBlocks[j].LimitUpNum = limits
   136  				allBlocks[j].UpCount = up
   137  				allBlocks[j].NoChangeNum = ling
   138  				allBlocks[j].DownCount = down
   139  				__mapBlockData[v.Code] = allBlocks[j]
   140  			}
   141  		}
   142  	}
   143  
   144  	// 输出 板块排行表格
   145  	var lastBlocks []SectorInfo
   146  	isHead := tradeRule.Flag == models.OrderFlagHead
   147  	if isHead {
   148  		lastBlocks = api.Filter(allBlocks, sectorFilterForHead)
   149  	} else {
   150  		lastBlocks = api.Filter(allBlocks, sectorFilterForTick)
   151  	}
   152  	bn := len(lastBlocks)
   153  	if bn >= tradeRule.Rules.SectorsTopN {
   154  		bn = tradeRule.Rules.SectorsTopN
   155  	}
   156  	topBlocks := lastBlocks[:bn]
   157  	blkTable := tablewriter.NewWriter(os.Stdout)
   158  	blkHeaders := tags.GetHeadersByTags(SectorInfo{})
   159  	blkTable.SetHeader(blkHeaders)
   160  	blkValues := [][]string{}
   161  	for _, block := range topBlocks {
   162  		values := tags.GetValuesByTags(block)
   163  		blkValues = append(blkValues, values)
   164  		// 是否从前排板块中检索个股
   165  		if tradeRule.Rules.SectorsFilter {
   166  			__allStocks = append(__allStocks, block.StockCodes...)
   167  		}
   168  	}
   169  	blkTable.AppendBulk(blkValues)
   170  	fmt.Println()
   171  	blkTable.Render()
   172  
   173  	*barIndex++
   174  	// 执行策略
   175  	// 获取全部证券代码
   176  	stockCodes := []string{}
   177  	for bkn, v := range topBlocks {
   178  		bc := v.Code
   179  		sl, ok := __block2Top[bc]
   180  		if ok {
   181  			stockCodes = append(stockCodes, sl...)
   182  		}
   183  		_ = bkn
   184  	}
   185  	stockCodes = api.Unique(stockCodes)
   186  
   187  	count := len(stockCodes)
   188  	fmt.Println("")
   189  	bar = progressbar.NewBar(*barIndex, "执行["+model.Name()+"]", count)
   190  	*barIndex++
   191  	mapStock := concurrent.NewTreeMap[string, models.ResultInfo]()
   192  	mainStart := time.Now()
   193  	var wg = sync.WaitGroup{}
   194  	for i, v := range stockCodes {
   195  		securityCode := v
   196  		bar.Add(1)
   197  		wg.Add(1)
   198  		go evaluate(model, &wg, securityCode, mapStock)
   199  		_ = i
   200  	}
   201  	wg.Wait()
   202  	fmt.Println()
   203  	table := tablewriter.NewWriter(os.Stdout)
   204  	table.SetHeader(tags.GetHeadersByTags(models.ResultInfo{}))
   205  
   206  	elapsedTime := time.Since(mainStart) / time.Millisecond
   207  	goals := mapStock.Size()
   208  	message := fmt.Sprintf("总耗时: %.3fs, 总记录: %d, 命中: %d, 平均: %.3f/s\n", float64(elapsedTime)/1000, count, goals, float64(count)/(float64(elapsedTime)/1000))
   209  	fmt.Printf(message)
   210  	logger.Infof(message)
   211  	fmt.Println("")
   212  	// 执行曲线回归
   213  	wg = sync.WaitGroup{}
   214  	bar = progressbar.NewBar(*barIndex, "执行[综合策略]", goals)
   215  	*barIndex++
   216  	rs := make([]models.ResultInfo, 0)
   217  	mapStock.Each(func(key string, value models.ResultInfo) {
   218  		bar.Add(1)
   219  		row := value
   220  		stockCode := row.Code
   221  		bs, ok := __stock2Block[stockCode]
   222  		if ok {
   223  			tb := bs[0]
   224  			if block, ok := __mapBlockData[tb.Code]; ok {
   225  				row.BlockType = block.Type
   226  				row.BlockName = block.Name
   227  				row.BlockRate = block.ChangeRate
   228  				row.BlockTop = block.Rank
   229  				row.BlockZhangTing = fmt.Sprintf("%d/%d", block.LimitUpNum, block.Count)
   230  				row.BlockDescribe = fmt.Sprintf("%d/%d/%d", block.UpCount, block.DownCount, block.NoChangeNum)
   231  				row.BlockTopName = block.TopName
   232  				row.BlockTopRate = block.TopRate
   233  				shot, ok1 := __stock2Rank[stockCode]
   234  				if ok1 {
   235  					row.BlockRank = shot.TopNo
   236  				}
   237  			}
   238  		}
   239  		predict := func(info models.ResultInfo, rs *[]models.ResultInfo, tbl *tablewriter.Table) {
   240  			defer wg.Done()
   241  			wg.Add(1)
   242  			info.Predict()
   243  			*rs = append(*rs, info)
   244  			tbl.Append(tags.GetValuesByTags(info))
   245  		}
   246  		predict(row, &rs, table)
   247  	})
   248  	wg.Wait()
   249  	fmt.Println("")
   250  	output(model.Code(), rs)
   251  	table.Render()
   252  }
   253  
   254  func output(strategyNo uint64, v []models.ResultInfo) {
   255  	df := pandas.LoadStructs(v)
   256  	filename := fmt.Sprintf("%s/%s/%s-%d.csv", cache.GetRootPath(), models.CACHE_STRATEGY_PATH, cache.Today(), strategyNo)
   257  	_ = df.WriteCSV(filename)
   258  }
   259  
   260  // 个股评估
   261  func evaluate(api models.Strategy, wg *sync.WaitGroup, code string, result *concurrent.TreeMap[string, models.ResultInfo]) {
   262  	defer wg.Done()
   263  	api.Evaluate(code, result)
   264  }