gitee.com/quant1x/engine@v1.8.4/datasource/dfcf/shareholder_stock.go (about) 1 package dfcf 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "gitee.com/quant1x/engine/cache" 7 "gitee.com/quant1x/exchange" 8 "gitee.com/quant1x/gox/api" 9 "gitee.com/quant1x/gox/http" 10 "gitee.com/quant1x/gox/logger" 11 urlpkg "net/url" 12 ) 13 14 // 前十大流通股东 https://emweb.securities.eastmoney.com/PC_HSF10/ShareholderResearch/Index?type=web&code=sh600822#sdltgd-0 15 // 数据接口 https://emweb.securities.eastmoney.com/PC_HSF10/ShareholderResearch/PageAjax?code=SH600822 16 // 17 // 十大股东 https://datacenter-web.eastmoney.com/api/data/v1/get?callback=jQuery112308928698030561204_1687518793792&sortColumns=RANK&sortTypes=1&pageSize=10&pageNumber=1&reportName=RPT_DMSK_HOLDERS&columns=ALL&source=WEB&client=WEB&filter=(SECURITY_CODE%3D%22600115%22)(END_DATE%3D%272023-03-31%27) 18 // callback: jQuery112308928698030561204_1687518793792 19 //sortColumns: RANK 20 //sortTypes: 1 21 //pageSize: 10 22 //pageNumber: 1 23 //reportName: RPT_DMSK_HOLDERS 24 //columns: ALL 25 //source: WEB 26 //client: WEB 27 //filter: (SECURITY_CODE="600115")(END_DATE='2023-03-31') 28 29 type rawStockHolder struct { 30 Version string `json:"version"` 31 Result struct { 32 Pages int `json:"pages"` 33 Data []struct { 34 SECUCODE string `json:"SECUCODE"` 35 SECURITY_CODE string `json:"SECURITY_CODE"` 36 ORG_CODE string `json:"ORG_CODE"` 37 END_DATE string `json:"END_DATE"` 38 HOLDER_NAME string `json:"HOLDER_NAME"` 39 HOLD_NUM int64 `json:"HOLD_NUM"` 40 FREE_HOLDNUM_RATIO float64 `json:"FREE_HOLDNUM_RATIO"` 41 HOLD_NUM_CHANGE string `json:"HOLD_NUM_CHANGE"` 42 CHANGE_RATIO float64 `json:"CHANGE_RATIO"` 43 IS_HOLDORG string `json:"IS_HOLDORG"` 44 HOLDER_RANK int `json:"HOLDER_RANK"` 45 SECURITY_NAME_ABBR string `json:"SECURITY_NAME_ABBR"` 46 HOLDER_CODE string `json:"HOLDER_CODE"` 47 SECURITY_TYPE_CODE string `json:"SECURITY_TYPE_CODE"` 48 HOLDER_STATE string `json:"HOLDER_STATE"` 49 HOLDER_MARKET_CAP float64 `json:"HOLDER_MARKET_CAP"` 50 HOLD_RATIO float64 `json:"HOLD_RATIO"` 51 HOLD_CHANGE string `json:"HOLD_CHANGE"` 52 HOLD_RATIO_CHANGE float64 `json:"HOLD_RATIO_CHANGE"` 53 HOLDER_TYPE string `json:"HOLDER_TYPE"` 54 SHARES_TYPE string `json:"SHARES_TYPE"` 55 UPDATE_DATE string `json:"UPDATE_DATE"` 56 REPORTDATENAME string `json:"REPORT_DATE_NAME"` 57 REPORT_DATE_NAME string `json:"HOLDER_NEW"` 58 FREE_RATIO_QOQ string `json:"FREE_RATIO_QOQ"` 59 HOLDER_STATEE string `json:"HOLDER_STATEE"` 60 IS_REPORT string `json:"IS_REPORT"` 61 HOLDER_CODE_OLD string `json:"HOLDER_CODE_OLD"` 62 HOLDER_NEWTYPE string `json:"HOLDER_NEWTYPE"` 63 HOLDNUM_CHANGE_NAME string `json:"HOLDNUM_CHANGE_NAME"` 64 IS_MAX_REPORTDATE string `json:"IS_MAX_REPORTDATE"` 65 COOPERATION_HOLDER_MARK string `json:"COOPERATION_HOLDER_MARK"` 66 MXID string `json:"MXID"` 67 LISTING_STATE string `json:"LISTING_STATE"` 68 XZCHANGE int `json:"XZCHANGE"` 69 NEW_CHANGE_RATIO string `json:"NEW_CHANGE_RATIO"` 70 } `json:"data"` 71 Count int `json:"count"` 72 } `json:"result"` 73 Success bool `json:"success"` 74 Message string `json:"message"` 75 Code int `json:"code"` 76 } 77 78 // 前十大流通股东 https://data.eastmoney.com/gdfx/stock/600115.html 79 // 数据接口 https://datacenter-web.eastmoney.com/api/data/v1/get 80 //callback: jQuery112308928698030561204_1687518793796 81 //sortColumns: HOLDER_RANK 82 //sortTypes: 1 83 //pageSize: 10 84 //pageNumber: 1 85 //reportName: RPT_F10_EH_FREEHOLDERS 86 //columns: ALL 87 //source: WEB 88 //client: WEB 89 //filter: (SECURITY_CODE="600115")(END_DATE='2023-03-31') 90 91 const ( 92 urlTop10ShareHolder = "https://datacenter-web.eastmoney.com/api/data/v1/get" 93 ) 94 95 func ShareHolder(securityCode, date string, diffQuarters ...int) (list []CirculatingShareholder) { 96 _, _, code := exchange.DetectMarket(securityCode) 97 quarterEndDate := exchange.FixTradeDate(date) 98 _, _, qEnd := api.GetQuarterByDate(date, diffQuarters...) 99 quarterEndDate = exchange.FixTradeDate(qEnd) 100 params := urlpkg.Values{ 101 "sortColumns": {"HOLDER_RANK"}, 102 "sortTypes": {"1"}, 103 "pageSize": {"10"}, 104 "pageNumber": {"1"}, 105 "reportName": {"RPT_F10_EH_FREEHOLDERS"}, 106 "columns": {"ALL"}, 107 "source": {"WEB"}, 108 "client": {"WEB"}, 109 "filter": {fmt.Sprintf("(SECURITY_CODE=\"%s\")(END_DATE='%s')", code, quarterEndDate)}, 110 } 111 112 url := urlTop10ShareHolder + "?" + params.Encode() 113 data, err := http.Get(url) 114 //fmt.Println(api.Bytes2String(data)) 115 if err != nil { 116 return 117 } 118 var raw rawStockHolder 119 err = json.Unmarshal(data, &raw) 120 if err != nil || raw.Result.Count == 0 || len(raw.Result.Data) == 0 { 121 return 122 } 123 for _, v := range raw.Result.Data { 124 shareholder := CirculatingShareholder{ 125 SecurityCode: v.SECUCODE, 126 SecurityName: v.SECURITY_NAME_ABBR, 127 EndDate: exchange.FixTradeDate(v.END_DATE), 128 UpdateDate: exchange.FixTradeDate(v.UPDATE_DATE), 129 HolderType: v.HOLDER_NEWTYPE, 130 HolderName: v.HOLDER_NAME, 131 IsHoldOrg: v.IS_HOLDORG, 132 HolderRank: v.HOLDER_RANK, 133 HoldNum: int(v.HOLD_NUM), 134 FreeHoldNumRatio: v.FREE_HOLDNUM_RATIO, 135 HoldNumChange: v.XZCHANGE, 136 HoldChangeName: v.HOLDNUM_CHANGE_NAME, 137 HoldChangeRatio: v.CHANGE_RATIO, 138 HoldRatio: v.HOLD_RATIO, 139 HoldRatioChange: v.HOLD_RATIO_CHANGE, 140 } 141 // 修订证券代码 142 _, mfalg, mcode := exchange.DetectMarket(shareholder.SecurityCode) 143 shareholder.SecurityCode = mfalg + mcode 144 //HoldChangeState int `dataframe:"change_state"` // 期末持股-变化状态 145 switch v.HOLDNUM_CHANGE_NAME { 146 case "新进": 147 shareholder.HoldChangeState = HoldNumNewlyAdded 148 case "增加": 149 shareholder.HoldChangeState = HoldNumIncrease 150 case "减少": 151 shareholder.HoldChangeState = HoldNumDampened 152 case "不变": 153 shareholder.HoldChangeState = HoldNumUnChanged 154 default: // 未知变化报警 155 shareholder.HoldChangeState = HoldNumUnknownChanges 156 warning := fmt.Sprintf("%s: %s, 变化状态未知: %s", v.SECURITY_NAME_ABBR, v.SECUCODE, v.HOLDNUM_CHANGE_NAME) 157 logger.Warnf(warning) 158 } 159 list = append(list, shareholder) 160 } 161 api.SliceSort(list, func(a, b CirculatingShareholder) bool { 162 return a.HolderRank < b.HolderRank 163 }) 164 return 165 } 166 167 // cacheShareHolder 获取流动股东数据 168 func cacheShareHolder(securityCode, date string, diffQuarters ...int) (list []CirculatingShareholder) { 169 diff := 1 170 if len(diffQuarters) > 0 { 171 diff = diffQuarters[0] 172 } 173 _, _, last := api.GetQuarterByDate(date, diff) 174 filename := cache.Top10HoldersFilename(securityCode, last) 175 if api.FileExist(filename) { 176 err := api.CsvToSlices(filename, &list) 177 if err == nil && len(list) > 0 { 178 return 179 } 180 } 181 tmpList := ShareHolder(securityCode, last) 182 if len(tmpList) > 0 { 183 list = tmpList 184 } 185 if len(list) > 0 { 186 _ = api.SlicesToCsv(filename, list) 187 } 188 return 189 } 190 191 // GetCacheShareHolder 获取流动股东数据 192 func GetCacheShareHolder(securityCode, date string, diffQuarters ...int) (list []CirculatingShareholder) { 193 diff := 1 194 if len(diffQuarters) > 0 { 195 diff = diffQuarters[0] 196 } 197 for ; diff < 4; diff++ { 198 tmpList := cacheShareHolder(securityCode, date, diff) 199 if len(tmpList) == 0 { 200 continue 201 } 202 list = tmpList 203 break 204 } 205 return 206 }