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  }