gitee.com/quant1x/engine@v1.8.4/tracker/mod_stock.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/engine/storages" 11 "gitee.com/quant1x/exchange" 12 "gitee.com/quant1x/gox/api" 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/pkg/tablewriter" 18 "os" 19 "sort" 20 "time" 21 ) 22 23 var ( 24 __allStocks = []string{} 25 //__topSectors = []SectorInfo{} 26 // 缓存板块前三的个股 27 __block2Top = map[string][]string{} 28 // 缓存个股所在的板块列表 29 __stock2Block = map[string][]SectorInfo{} 30 // 缓存个股的排名 31 __stock2Rank = map[string]factors.QuoteSnapshot{} 32 // 个股对应板块 33 __mapBlockData = map[string]SectorInfo{} 34 ) 35 36 // AllScan 全市场扫描 37 func AllScan(barIndex *int, model models.Strategy) { 38 today := exchange.IndexToday() 39 dates := exchange.TradingDateRange(exchange.MARKET_CN_FIRST_DATE, today) 40 days := len(dates) 41 currentlyDay := dates[days-1] 42 updateTime := "15:00:59" 43 todayIsTradeDay := false 44 if today == currentlyDay { 45 todayIsTradeDay = true 46 now := time.Now() 47 nowTime := now.Format(exchange.CN_SERVERTIME_FORMAT) 48 if nowTime < exchange.CN_TradingStartTime { 49 currentlyDay = dates[days-2] 50 } else if nowTime >= exchange.CN_TradingStartTime && nowTime <= exchange.CN_TradingStopTime { 51 updateTime = now.Format(exchange.TimeOnly) 52 } 53 } 54 // 全市场扫描 55 tradeRule := config.GetStrategyParameterByCode(model.Code()) 56 if tradeRule == nil { 57 logger.Errorf("strategy[%d]: trade rule not found", model.Code()) 58 return 59 } 60 var stockCodes []string 61 needFilter := false 62 // 检查板块扫描的结果是否存在股票列表 63 if len(__allStocks) > 0 { 64 // 确定前排板块中的前排个股 65 __allStocks = api.Unique(__allStocks) 66 stockCodes = __allStocks 67 needFilter = true 68 } else { 69 // 板块扫描结果没有输出个股列表 70 // 查看规则配置 71 if tradeRule == nil { 72 // 如果规则没有配置, 则取全部有效的代码列表 73 stockCodes = market.GetStockCodeList() 74 needFilter = true 75 } else { 76 // 如果规则配置有效, 股票代码列表从规则中获取 77 stockCodes = tradeRule.StockList() 78 } 79 } 80 if needFilter && tradeRule != nil { 81 stockCodes = tradeRule.Filter(stockCodes) 82 } 83 stockSnapshots := []factors.QuoteSnapshot{} 84 stockCount := len(stockCodes) 85 *barIndex++ 86 bar := progressbar.NewBar(*barIndex, "执行[全市场扫描]", stockCount) 87 for start := 0; start < stockCount; start++ { 88 bar.Add(1) 89 code := stockCodes[start] 90 securityCode := exchange.CorrectSecurityCode(code) 91 if exchange.AssertIndexBySecurityCode(securityCode) { 92 continue 93 } 94 v := models.GetTickFromMemory(securityCode) 95 if v != nil { 96 snapshot := models.QuoteSnapshotFromProtocol(*v) 97 stockSnapshots = append(stockSnapshots, snapshot) 98 } 99 } 100 if len(stockSnapshots) == 0 { 101 return 102 } 103 if todayIsTradeDay && updateTime >= StoreSnapshotTimeBegin && updateTime < StoreSnapshotTimeEnd { 104 var cacheSnapshots []factors.Misc 105 for _, v := range stockSnapshots { 106 securityCode := exchange.GetSecurityCode(v.Market, v.Code) 107 snapshot := factors.GetL5Misc(securityCode) 108 if snapshot == nil { 109 snapshot = &factors.Misc{ 110 Date: currentlyDay, 111 Code: securityCode, 112 } 113 } 114 //snapshot.OpenBiddingDirection, snapshot.OpenVolumeDirection = v.CheckDirection() 115 cacheSnapshots = append(cacheSnapshots, *snapshot) 116 factors.UpdateL5Misc(snapshot) 117 } 118 if len(cacheSnapshots) > 0 { 119 factors.RefreshL5Misc() 120 } 121 } 122 // 过滤不符合条件的个股 123 stockSnapshots = api.Filter(stockSnapshots, func(snapshot factors.QuoteSnapshot) bool { 124 return model.Filter(tradeRule.Rules, snapshot) == nil 125 }) 126 // 排序 127 sortedStatus := model.Sort(stockSnapshots) 128 if sortedStatus == models.SortDefault || sortedStatus == models.SortNotExecuted { 129 sort.Slice(stockSnapshots, func(i, j int) bool { 130 a := stockSnapshots[i] 131 b := stockSnapshots[j] 132 if a.OpenTurnZ > b.OpenTurnZ { 133 return true 134 } 135 return a.OpenTurnZ == b.OpenTurnZ && a.OpeningChangeRate > b.OpeningChangeRate 136 }) 137 } 138 139 // 输出二维表格 140 tbl := tablewriter.NewWriter(os.Stdout) 141 tbl.SetHeader(tags.GetHeadersByTags(models.Statistics{})) 142 topN := models.CountTopN 143 if topN <= 0 { 144 topN = tradeRule.Total 145 } 146 if topN > len(stockSnapshots) { 147 topN = len(stockSnapshots) 148 } 149 votingResults := []models.Statistics{} 150 stockSnapshots = stockSnapshots[:topN] 151 now := time.Now() 152 orderCreateTime := now.Format(cache.TimeStampMilli) 153 for _, v := range stockSnapshots { 154 ticket := models.Statistics{ 155 Date: currentlyDay, // 日期 156 Code: v.SecurityCode, // 证券代码 157 Name: v.Name, // 证券名称 158 Active: int(v.Active), // 活跃度 159 LastClose: v.LastClose, // 昨收 160 Open: v.Open, // 开盘价 161 OpenRaise: v.OpeningChangeRate, // 开盘涨幅 162 Price: v.Price, // 现价 163 UpRate: v.ChangeRate, // 涨跌幅 164 OpenPremiumRate: v.PremiumRate, // 集合竞价买入溢价率 165 OpenVolume: v.OpenVolume, // 集合竞价-开盘量, 单位是股 166 TurnZ: v.OpenTurnZ, // 开盘换手率z 167 QuantityRatio: v.OpenQuantityRatio, // 开盘量比 168 AveragePrice: v.Amount / float64(v.Vol), // 均价线 169 ChangePower: v.ChangePower, // 涨跌力度 170 AverageBiddingVolume: v.AverageBiddingVolume, // 委托均量 171 UpdateTime: orderCreateTime, // 更新时间 172 } 173 if v.Open < v.LastClose { 174 ticket.Tendency += "低开" 175 } else if v.Open == v.LastClose { 176 ticket.Tendency += "平开" 177 } else { 178 ticket.Tendency += "高开" 179 } 180 if ticket.AveragePrice < v.Open { 181 ticket.Tendency += ",回落" 182 } else { 183 ticket.Tendency += ",拉升" 184 } 185 if v.Price > ticket.AveragePrice { 186 ticket.Tendency += ",强势" 187 } else { 188 ticket.Tendency += ",弱势" 189 } 190 191 bs, ok := __stock2Block[ticket.Code] 192 if ok { 193 tb := bs[0] 194 if block, ok := __mapBlockData[tb.Code]; ok { 195 ticket.BlockName = block.Name 196 ticket.BlockRate = block.ChangeRate 197 ticket.BlockTop = block.Rank 198 shot, ok1 := __stock2Rank[ticket.Code] 199 if ok1 { 200 ticket.BlockRank = shot.TopNo 201 } 202 } 203 } 204 votingResults = append(votingResults, ticket) 205 } 206 gtP1 := 0 // 存在溢价 207 gtP2 := 0 // 超过1% 208 gtP3 := 0 209 gtP4 := 0 210 gtP5 := 0 211 yields := 0.00 212 for _, v := range votingResults { 213 rate := num.NetChangeRate(v.Open, v.Price) 214 if rate > 0 { 215 gtP1 += 1 216 } 217 if rate >= 1.00 { 218 gtP2 += 1 219 } 220 if rate >= 2.00 { 221 gtP3 += 1 222 } 223 if rate >= 3.00 { 224 gtP4 += 1 225 } 226 if rate >= 5.00 { 227 gtP5 += 1 228 } 229 yields += rate 230 tbl.Append(tags.GetValuesByTags(v)) 231 } 232 yields /= float64(len(votingResults)) 233 fmt.Println() // 输出一个换行 234 tbl.Render() 235 count := len(stockSnapshots) 236 fmt.Println() 237 238 fmt.Println(currentlyDay + " " + updateTime + ", 胜率统计:") 239 fmt.Printf("\t==> 胜 率: %d/%d, %.2f%%, 收益率: %.2f%%\n", gtP1, count, 100*float64(gtP1)/float64(count), yields) 240 fmt.Printf("\t==> 溢价超1%%: %d/%d, %.2f%%\n", gtP2, count, 100*float64(gtP2)/float64(count)) 241 fmt.Printf("\t==> 溢价超2%%: %d/%d, %.2f%%\n", gtP3, count, 100*float64(gtP3)/float64(count)) 242 fmt.Printf("\t==> 溢价超3%%: %d/%d, %.2f%%\n", gtP4, count, 100*float64(gtP4)/float64(count)) 243 fmt.Printf("\t==> 溢价超5%%: %d/%d, %.2f%%\n", gtP5, count, 100*float64(gtP5)/float64(count)) 244 fmt.Println() 245 // 存储 246 storages.OutputStatistics(model, currentlyDay, votingResults) 247 }