gitee.com/quant1x/engine@v1.8.4/datasource/dfcf/shareholder.go (about) 1 package dfcf 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "gitee.com/quant1x/exchange" 7 "gitee.com/quant1x/gox/api" 8 "gitee.com/quant1x/gox/http" 9 "gitee.com/quant1x/gox/logger" 10 "gitee.com/quant1x/pkg/fastjson" 11 urlpkg "net/url" 12 "strings" 13 ) 14 15 const ( 16 errorCapitalBase = 90000 // 股本异常错误码基础值 17 urlEastmoneyGdfxHoldingAnalyse = "https://datacenter-web.eastmoney.com/api/data/v1/get" 18 EastmoneyGdfxHoldingAnalysePageSize = 500 19 ) 20 21 type HoldNumChangeState = int 22 23 const ( 24 HoldNumDampened HoldNumChangeState = -1 // 减少 25 HoldNumUnChanged HoldNumChangeState = 0 // 不变 26 HoldNumNewlyAdded HoldNumChangeState = 1 // 新进/新增 27 HoldNumIncrease HoldNumChangeState = 2 // 增加 28 HoldNumUnknownChanges HoldNumChangeState = -9 // 未知变化 29 ) 30 31 // CirculatingShareholder Top10CirculatingShareholders 32 type CirculatingShareholder struct { 33 SecurityCode string `dataframe:"security_code"` // 证券代码 34 SecurityName string `dataframe:"security_name"` // 证券名称 35 EndDate string `dataframe:"end_date"` // 报告日期 36 UpdateDate string `dataframe:"update_date"` // 更新日期 37 HolderType string `dataframe:"holder_type"` // 股东类型 38 HolderName string `dataframe:"holder_name"` // 股东名称 39 IsHoldOrg string `dataframe:"is_holdorg"` // 股东是否机构 40 HolderRank int `dataframe:"holder_rank"` // 股东排名 41 HoldNum int `dataframe:"hold_num"` // 期末持股-数量 42 FreeHoldNumRatio float64 `dataframe:"free_hold_num_ratio"` // 期末持股-比例 43 HoldNumChange int `dataframe:"hold_num_change"` // 期末持股-持股变动 44 HoldChangeName string `dataframe:"change_name"` // 期末持股-变化状态 45 HoldChangeState int `dataframe:"change_state"` // 期末持股-变化状态 46 HoldChangeRatio float64 `dataframe:"change_ratio"` // 期末持股-持股变化比例 47 HoldRatio float64 `dataframe:"hold_ratio"` // 期末持股-持股变动 48 HoldRatioChange float64 `dataframe:"hold_ratio_change"` // 期末持股-数量变化比例 49 } 50 51 // HoldingAnalyse 持股分析 52 type HoldingAnalyse struct { 53 SECUCODE string `json:"SECUCODE"` // "股票代码", 54 SECURITY_NAME string `json:"SECURITY_NAME_ABBR"` // "股票简称", 55 END_DATE string `json:"END_DATE"` // "报告期", 56 UPDATE_DATE string `json:"UPDATE_DATE"` // "公告日", 57 HOLDER_TYPE string `json:"HOLDER_TYPE"` // "股东类型", 58 HOLDER_NEWTYPE string `json:"HOLDER_NEWTYPE"` // "-", 59 HOLDER_NAME string `json:"HOLDER_NAME"` // "股东名称", 60 IS_HOLDORG string `json:"IS_HOLDORG"` // "是否机构", 61 HOLDER_RANK int `json:"HOLDER_RANK"` // "股东排名", 62 HOLD_NUM int `json:"HOLD_NUM"` // "期末持股-数量", 63 FREE_HOLDNUM_RATIO float64 `json:"FREE_HOLDNUM_RATIO"` // "-", 64 HOLD_NUM_CHANGE_NAME string `json:"HOLDNUM_CHANGE_NAME"` // "-", 65 XZCHANGE int `json:"XZCHANGE"` // "期末持股-数量变化", 66 CHANGE_RATIO float64 `json:"CHANGE_RATIO"` // "-", 67 HOLDER_STATE string `json:"HOLDER_STATE"` // "-", 68 REPORT_DATE_NAME string `json:"REPORT_DATE_NAME"` // ---华丽的分割线--- 69 HOLDER_MARKET_CAP float64 `json:"HOLDER_MARKET_CAP"` // "期末持股-流通市值", 70 HOLD_RATIO float64 `json:"HOLD_RATIO"` // "-", 71 SECURITY_CODE string `json:"SECURITY_CODE"` // "股票代码简写", 72 HOLD_CHANGE string `json:"HOLD_CHANGE"` // "-", 73 HOLD_RATIO_CHANGE float64 `json:"HOLD_RATIO_CHANGE"` // "期末持股-数量变化比例", 74 ORG_CODE string `json:"ORG_CODE"` // "-", 75 HOLDER_CODE string `json:"HOLDER_CODE"` // "-", 76 SECURITY_TYPE_CODE string `json:"SECURITY_TYPE_CODE"` // "-", 77 SHARES_TYPE string `json:"SHARES_TYPE"` // "-", 78 HOLDER_NEW string `json:"HOLDER_NEW"` // "-", 79 FREE_RATIO_QOQ string `json:"FREE_RATIO_QOQ"` // "-", 80 HOLDER_STATEE string `json:"HOLDER_STATEE"` // "-", 81 IS_REPORT string `json:"IS_REPORT"` // "-", 82 HOLDER_CODE_OLD string `json:"HOLDER_CODE_OLD"` // "-", 83 IS_MAX_REPORT_DATE string `json:"IS_MAX_REPORTDATE"` // "-", 84 COOPERATION_HOLDER_MARK string `json:"COOPERATION_HOLDER_MARK"` // "-", 85 MXID string `json:"MXID"` // "-", 86 LISTING_STATE string `json:"LISTING_STATE"` // "-", 87 NEW_CHANGE_RATIO string `json:"NEW_CHANGE_RATIO"` // "-", 88 HOLD_NUM_CHANGE string `json:"HOLD_NUM_CHANGE"` // "期末持股-持股变动", 89 } 90 91 // FreeHoldingAnalyse 东方财富网-数据中心-股东分析-股东持股明细-十大流通股东 92 // 93 // https://data.eastmoney.com/gdfx/HoldingAnalyse.html 94 func getFreeHoldingAnalyse(pageNumber ...int) ([]HoldingAnalyse, int, error) { 95 pageNo := 1 96 pages := 0 97 if len(pageNumber) > 0 { 98 pageNo = pageNumber[0] 99 } 100 pageSize := EastmoneyGdfxHoldingAnalysePageSize 101 _, qEnd := api.GetQuarterDay(9) 102 endDate := exchange.FixTradeDate(qEnd) 103 params := urlpkg.Values{ 104 "sortColumns": {"UPDATE_DATE,SECURITY_CODE,HOLDER_RANK"}, 105 "sortTypes": {"-1,1,1"}, 106 "pageSize": {fmt.Sprintf("%d", pageSize)}, 107 "pageNumber": {fmt.Sprintf("%d", pageNo)}, 108 "reportName": {"RPT_F10_EH_FREEHOLDERS"}, 109 "columns": {"ALL"}, 110 "source": {"WEB"}, 111 "client": {"WEB"}, 112 "filter": {fmt.Sprintf("(END_DATE>='%s')", endDate)}, 113 } 114 url := urlEastmoneyGdfxHoldingAnalyse + "?" + params.Encode() 115 data, err := http.Get(url) 116 //fmt.Println(api.Bytes2String(data)) 117 var holds = []HoldingAnalyse{} 118 obj, err := fastjson.ParseBytes(data) 119 if err != nil { 120 logger.Errorf("%+v\n", err) 121 return holds, pages, err 122 } 123 result := obj.Get("result") 124 if result == nil { 125 return holds, pages, nil 126 } 127 pages = result.GetInt("pages") 128 tData := result.Get("data") 129 if tData == nil { 130 return holds, pages, nil 131 } 132 text := tData.String() 133 err = json.Unmarshal(api.String2Bytes(text), &holds) 134 for i := 0; i < len(holds); i++ { 135 holds[i].END_DATE = exchange.FixTradeDate(holds[i].END_DATE) 136 holds[i].UPDATE_DATE = exchange.FixTradeDate(holds[i].UPDATE_DATE) 137 } 138 return holds, pages, err 139 } 140 141 func FreeHoldingAnalyse(pageNumber ...int) ([]CirculatingShareholder, int, error) { 142 pageNo := 1 143 pages := 0 144 if len(pageNumber) > 0 { 145 pageNo = pageNumber[0] 146 } 147 shareholders := []CirculatingShareholder{} 148 pageSize := EastmoneyGdfxHoldingAnalysePageSize 149 _, qEnd := api.GetQuarterDay(9) 150 endDate := exchange.FixTradeDate(qEnd) 151 params := urlpkg.Values{ 152 "sortColumns": {"UPDATE_DATE,SECURITY_CODE,HOLDER_RANK"}, 153 "sortTypes": {"-1,1,1"}, 154 "pageSize": {fmt.Sprintf("%d", pageSize)}, 155 "pageNumber": {fmt.Sprintf("%d", pageNo)}, 156 "reportName": {"RPT_F10_EH_FREEHOLDERS"}, 157 "columns": {"ALL"}, 158 "source": {"WEB"}, 159 "client": {"WEB"}, 160 "filter": {fmt.Sprintf("(END_DATE>='%s')", endDate)}, 161 } 162 url := urlEastmoneyGdfxHoldingAnalyse + "?" + params.Encode() 163 data, err := http.Get(url) 164 var holds = []HoldingAnalyse{} 165 obj, err := fastjson.ParseBytes(data) 166 if err != nil { 167 logger.Errorf("%+v\n", err) 168 return shareholders, pages, err 169 } 170 result := obj.Get("result") 171 if result == nil { 172 return shareholders, pages, nil 173 } 174 pages = result.GetInt("pages") 175 tData := result.Get("data") 176 if tData == nil { 177 return shareholders, pages, nil 178 } 179 text := tData.String() 180 err = json.Unmarshal(api.String2Bytes(text), &holds) 181 for i := 0; i < len(holds); i++ { 182 holds[i].END_DATE = exchange.FixTradeDate(holds[i].END_DATE) 183 holds[i].UPDATE_DATE = exchange.FixTradeDate(holds[i].UPDATE_DATE) 184 } 185 for _, v := range holds { 186 shareholder := CirculatingShareholder{ 187 //SecurityCode string `dataframe:"security_code"` // 证券代码 188 SecurityCode: v.SECUCODE, 189 //SecurityName string `dataframe:"security_name"` // 证券名称 190 SecurityName: v.SECURITY_NAME, 191 //EndDate string `dataframe:"end_date"` // 报告日期 192 EndDate: v.END_DATE, 193 //UpdateDate string `dataframe:"update_date"` // 更新日期 194 UpdateDate: v.UPDATE_DATE, 195 //HolderType string `dataframe:"holder_type"` // 股东类型 196 HolderType: v.HOLDER_NEWTYPE, 197 //HolderName string `dataframe:"holder_name"` // 股东名称 198 HolderName: v.HOLDER_NAME, 199 //IsHolderOrg string `dataframe:"is_holder_org"` // 股东是否机构 200 IsHoldOrg: v.IS_HOLDORG, 201 //HolderRank int `dataframe:"holder_rank"` // 股东排名 202 HolderRank: v.HOLDER_RANK, 203 //HoldNum int `dataframe:"hold_num"` // 期末持股-数量 204 HoldNum: v.HOLD_NUM, 205 //FreeHoldNumRatio float64 `dataframe:"hold_num_ratio"` // 期末持股-比例 206 FreeHoldNumRatio: v.FREE_HOLDNUM_RATIO, 207 //HoldNumChange string `dataframe:"hold_num_change"` // 期末持股-持股变动 208 HoldNumChange: v.XZCHANGE, 209 //HoldChangeName string `dataframe:"hold_change_name"` // 期末持股-变化状态 210 HoldChangeName: v.HOLD_NUM_CHANGE_NAME, 211 //HoldChangeRatio string `dataframe:"change_ratio"` // 期末持股-变化比例 212 HoldChangeRatio: v.CHANGE_RATIO, 213 //HoldRatio float64 `dataframe:"hold_ratio"` // 期末持股-持股变动 214 HoldRatio: v.HOLD_RATIO, 215 //HoldRatioChange float64 `dataframe:"hold_ratio_change"` // "期末持股-数量变化比例", 216 HoldRatioChange: v.HOLD_RATIO_CHANGE, 217 } 218 // 修订证券代码 219 _, mfalg, mcode := exchange.DetectMarket(shareholder.SecurityCode) 220 shareholder.SecurityCode = mfalg + mcode 221 //HoldChangeState int `dataframe:"change_state"` // 期末持股-变化状态 222 switch v.HOLD_NUM_CHANGE_NAME { 223 case "新进": 224 shareholder.HoldChangeState = HoldNumNewlyAdded 225 case "增加": 226 shareholder.HoldChangeState = HoldNumIncrease 227 case "减少": 228 shareholder.HoldChangeState = HoldNumDampened 229 case "不变": 230 shareholder.HoldChangeState = HoldNumUnChanged 231 default: // 未知变化报警 232 shareholder.HoldChangeState = HoldNumUnknownChanges 233 warning := fmt.Sprintf("%s: %s, 变化状态未知: %s", v.SECURITY_NAME, v.SECUCODE, v.HOLD_NUM_CHANGE_NAME) 234 logger.Warnf(warning) 235 } 236 shareholders = append(shareholders, shareholder) 237 } 238 return shareholders, pages, err 239 } 240 241 // FreeHoldingDetail 拉取近期的 242 func freeHoldingDetail() []CirculatingShareholder { 243 pageNo := 1 244 holds := []CirculatingShareholder{} 245 for { 246 list, pages, err := getFreeHoldingAnalyse(pageNo) 247 if err != nil || pages < 1 { 248 logger.Error(err) 249 break 250 } 251 count := len(list) 252 if count == 0 { 253 break 254 } 255 for _, v := range list { 256 shareholder := CirculatingShareholder{ 257 //SecurityCode string `dataframe:"security_code"` // 证券代码 258 SecurityCode: strings.TrimSpace(v.SECUCODE), 259 //SecurityName string `dataframe:"security_name"` // 证券名称 260 SecurityName: strings.TrimSpace(v.SECURITY_NAME), 261 //EndDate string `dataframe:"end_date"` // 报告日期 262 EndDate: strings.TrimSpace(v.END_DATE), 263 //UpdateDate string `dataframe:"update_date"` // 更新日期 264 UpdateDate: strings.TrimSpace(v.UPDATE_DATE), 265 //HolderType string `dataframe:"holder_type"` // 股东类型 266 HolderType: v.HOLDER_NEWTYPE, 267 //HolderName string `dataframe:"holder_name"` // 股东名称 268 HolderName: v.HOLDER_NAME, 269 //IsHolderOrg string `dataframe:"is_holder_org"` // 股东是否机构 270 IsHoldOrg: v.IS_HOLDORG, 271 //HolderRank int `dataframe:"holder_rank"` // 股东排名 272 HolderRank: v.HOLDER_RANK, 273 //HoldNum int `dataframe:"hold_num"` // 期末持股-数量 274 HoldNum: v.HOLD_NUM, 275 //FreeHoldNumRatio float64 `dataframe:"hold_num_ratio"` // 期末持股-比例 276 FreeHoldNumRatio: v.FREE_HOLDNUM_RATIO, 277 //HoldNumChange string `dataframe:"hold_num_change"` // 期末持股-持股变动 278 HoldNumChange: v.XZCHANGE, 279 //HoldChangeName string `dataframe:"hold_change_name"` // 期末持股-变化状态 280 HoldChangeName: v.HOLD_NUM_CHANGE_NAME, 281 //HoldChangeRatio string `dataframe:"change_ratio"` // 期末持股-变化比例 282 HoldChangeRatio: v.CHANGE_RATIO, 283 //HoldRatio float64 `dataframe:"hold_ratio"` // 期末持股-持股变动 284 HoldRatio: v.HOLD_RATIO, 285 //HoldRatioChange float64 `dataframe:"hold_ratio_change"` // "期末持股-数量变化比例", 286 HoldRatioChange: v.HOLD_RATIO_CHANGE, 287 } 288 // 修订证券代码 289 _, mfalg, mcode := exchange.DetectMarket(shareholder.SecurityCode) 290 shareholder.SecurityCode = mfalg + mcode 291 //HoldChangeState int `dataframe:"change_state"` // 期末持股-变化状态 292 switch v.HOLD_NUM_CHANGE_NAME { 293 case "新进": 294 shareholder.HoldChangeState = HoldNumNewlyAdded 295 case "增加": 296 shareholder.HoldChangeState = HoldNumIncrease 297 case "减少": 298 shareholder.HoldChangeState = HoldNumDampened 299 case "不变": 300 shareholder.HoldChangeState = HoldNumUnChanged 301 default: // 未知变化报警 302 shareholder.HoldChangeState = HoldNumUnknownChanges 303 warning := fmt.Sprintf("%s: %s, 变化状态未知: %s", v.SECURITY_NAME, v.SECUCODE, v.HOLD_NUM_CHANGE_NAME) 304 logger.Warnf(warning) 305 } 306 holds = append(holds, shareholder) 307 } 308 if count < EastmoneyGdfxHoldingAnalysePageSize { 309 break 310 } 311 pageNo += 1 312 break 313 } 314 return holds 315 }