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 }