1. 程式人生 > >【開源】C#.NET股票歷史資料採集,【附18年曆史資料和原始碼】

【開源】C#.NET股票歷史資料採集,【附18年曆史資料和原始碼】

重點重點:我沒有買股票,沒有買股票,股市是個坑,小心割韭菜哦。

本文的初衷是資料分析(分析結果就不說了,就是想看看篩選點資料),只不過搞下來發現比我想象的要簡單多了。本文采集的資料是:2000年到2018年2月份,上證和深證交易所所有的上市股票交易資料,按天採集,不是小時哦,有興趣的朋友,可以稍微改造,做到實時(這和我就無關了)。

1.資料採集需求

原始需求:想分析某些股票的歷史天交易資料裡面滿足某些條件的股票。

初步分析:需要股票的基礎資料,如名稱,編碼,交易所等資訊,然後就是每天的開票收盤的價格,漲幅等資訊。

以為很簡單,起始搞起來越滾越大,剛開始以為2個表就夠了,沒想到搞來搞去,有6個表了。

還好,我們有強大的XCode元件,資料庫設計,開發都極其簡單,總共零零散散也就10個小時不到就完工了。主要的時間不是寫程式碼,其實60%的時間都是在找資料,分析介面和想怎麼設計上面,以及跑資料,還好源資料都儲存下來了,重寫跑起來很快。

2.股市資料介面

    很早以前,有朋友也想讓我給給他採集股票實時資料,而且用的是商業介面,由於時間匆忙,而且對股票一無所知,所以就拒絕了。

  這次開工之前,心裡也很忐忑,會不會很複雜,反正是自己想玩和想看,所以抱著試一試的心態,沒想到比我想的要簡單很多。

  首先,我們得找到資料來源,否則一切無從談起,而且我需要的是歷史資料,對資料實時性要求不高:

  此處。。。。。。。。。。。。省略1萬字,因為搜尋和找了很多資源,最終用的是下面的介面,簡單,實測速度快,18年的資料不到20分鐘刷刷刷搞下來了。

2.1 股票基礎資料

  裡面包括了上證和深圳交易所的所有股票程式碼資訊,只需要直接採集即可,速度很快。

  如果要做實時,每天更新一次即可,注意:我開始也沒注意,股票程式碼有很多含義,除了交易所之外,還有啥創業板,基金之類的,我沒仔細研究,我只把我需要的型別進行了標記。可以在這裡看看程式碼的一些型別:https://baike.so.com/doc/4974613-5197406.html

  股票基礎資料結構比較簡單:

  編碼(唯一),名稱,交易所,型別1是要分析 ,0是暫時忽略的,上市日期

2.2 股票歷史天資料

  股票歷史天資料剛開始想應該很大,找了一些結構才發現,基本每天的主要指標也就10個欄位左右,計算一下,每隻股票就算20年,也就6000條而已。

  即使10000支股票,最多也就6000萬而已,所以剛開始的時候直接全部擼到一個表裡面了,實際上後面在分析的時候,極其不合理。分析的比較很複雜,搜尋非常慢,所以後來我把歷史資料進行了拆分,然後分析的時候多執行緒,速度瞬間提升10倍。由於XCode元件天生對分表分庫和資料庫反向工程的支援,所以開發起來非常快。

  它的格式很簡單,拼接股票程式碼和起始結束日期即可,後來還發現它還能查詢指數資訊:

  http://q.stock.sohu.com/hisHq?code={code}&start={start}&end={end},{code}替換為股票程式碼,大陸股票程式碼加字首cn_。

  返回的json格式很標準,使用了Newlife元件的JsonParser類,輕鬆搞定。根據返回的資料資訊,找了幾支股票核對一下,就知道其意義了。在後面的資料庫設計中會詳細描述。說明:採集的時候我是先用臨時表統一把返回的結果儲存,防止程式有bug,下次又去請求,浪費人家的流量。也是儲存在sqlite資料庫。

2.3 其他附加

  在後面分析的時候,我還用到了板塊資訊,相當於給每支股票加一個型別,屬於什麼板塊,這樣分析的時候有針對性。板塊有型別,然後每個型別下面又有一些股票程式碼,有2個表,資料來源也是搜狐的:

  當然如果還要做複雜和完善一點,還有很多資料要採集,比如公司的一些基本資訊,我暫時沒有用到,後面我會把程式碼開源,大家隨意折騰。

3.資料庫設計 

 資料庫設計我們採用XCode開發的設計規範,都用xml檔案,可以自動生成實體類,後面有時間我會針對XCode寫一篇開發實踐的文章,再一次帶大家溫習了XCode,在這裡感謝@大石頭,10多年碼農,X元件博大精深,極大的提高了開發效率,簡單,簡單,簡單到你有時候懷疑人生。

1.股票基礎資訊

<Table Name="StockBaseInfo" Description="股票基礎資訊" ConnName="stock_base">
    <Columns>
      <Column Name="Code" DataType="String" PrimaryKey="True" Description="股票編碼" />
      <Column Name="Name" DataType="String" Master="True" Description="名稱" />
      <Column Name="Exchange" DataType="String" Description="交易所" />
      <Column Name="Kind" DataType="Int32" Description="型別。1是要分析股票,0是暫時不分析" />
      <Column Name="StartDate" DataType="DateTime" Description="上市日期" />
      <Column Name="CreateDate" DataType="DateTime" Description="建立時間" />
    </Columns>
    <Indexes>
      <Index Columns="Name" />
      <Index Columns="StartDate" />
    </Indexes>
</Table>

2.股票歷史日資料

  其實在專案程式碼的xml檔案表結構中,還有一個歷史資訊,就是一次性獲取所有歷史Json文字儲存,避免重複抓取Json資料。結構很簡單,就不貼了。

<Table Name="StockDayData" Description="股票日資料" ConnName="stock_day">
    <Columns>
      <Column Name="ID" DataType="String" PrimaryKey="True" Description="編號。code+日期" />
      <Column Name="Code" DataType="String" Description="股票編碼" />
      <Column Name="StatDate" DataType="DateTime" Description="資料日期" />
      <Column Name="StartPrice" DataType="Double" Description="開盤價格" />
      <Column Name="EndPrice" DataType="Double" Description="收盤價格" />
      <Column Name="ChangePrice" DataType="Double" Description="漲跌金額" />
      <Column Name="ChangeRatio" DataType="Double" Description="漲跌幅度" />
      <Column Name="LowPrice" DataType="Double" Description="最低價格" />
      <Column Name="HighPrice" DataType="Double" Description="最高價格" />
      <Column Name="TotalHand" DataType="Int32" Description="總手" />
      <Column Name="TotalAmount" DataType="Double" Description="總金額(萬)" />
      <Column Name="HandRate" DataType="Double" Description="換手率" />
      <Column Name="UpdateDate" DataType="DateTime" Description="更新日期" />
    </Columns>
</Table>

3.板塊分類和股票板塊資訊

<Table Name="GroupKind" Description="板塊分類" ConnName="stock_base">
    <Columns>
      <Column Name="ID" DataType="String" PrimaryKey="True" Description="編碼。url相關" />
      <Column Name="Name" DataType="String" Master="True" Description="板塊名稱" />
      <Column Name="Kind" DataType="String" Description="分類。1.行業,2地域,3.概念" />
      <Column Name="Total" DataType="Int32" Description="總數" />
      <Column Name="CreateDate" DataType="DateTime" Description="建立時間" />
    </Columns>
    <Indexes>
      <Index Columns="Kind" />
      <Index Columns="Name" />
    </Indexes>
  </Table>
  <Table Name="StockGroup" Description="股票板塊資訊" ConnName="stock_base">
    <Columns>
      <Column Name="ID" DataType="String" PrimaryKey="True" Description="編號。groupid+stockid" />
      <Column Name="GroupID" DataType="String" Description="板塊ID" />
      <Column Name="Kind" DataType="String" Description="分類。1.行業,2地域,3.概念" />
      <Column Name="Code" DataType="String" Description="股票程式碼" />
      <Column Name="StockName" DataType="String" Description="股票名稱" />
      <Column Name="CreateDate" DataType="DateTime" Description="建立時間" />
    </Columns>
    <Indexes>
      <Index Columns="GroupID" />
      <Index Columns="Code" />
    </Indexes>
</Table>

4.關鍵資訊採集

 下面我們把資料採集過程簡單分析一下,然後把原始碼和資料庫共享給大家。套路很簡單,熟悉起來很快就可以搞定。

我的部落格中,前幾年,寫過好幾篇關於C#資料採集的方法,套路都比較通用,主要是:HtmlAgilityPack + XCode

   HtmlAgilityPack是.NET 下的一個強大的HTML 解析類庫,支援用 XPath 。配合上自帶的HAPExplorer,很快就可以解決問題。

  具體使用可以參考上面2篇文章,下面我們也會上實際程式碼。

4.1 基礎資料採集

我們發現上海和深圳交易所的列表分別在下面位置:

/html[1]/body[1]/div[9]/div[2]/div[1]/ul[1]
/html[1]/body[1]/div[9]/div[2]/div[1]/ul[2]

還往下一個層級就是li標籤列表,在HtmlAgilityPack中有現成的方法獲取整個列表,並進行解析,如下面程式碼: 

/// 獲取所有股票程式碼和名稱基礎資訊
public static void ReadAllStockBaseInfo()
{
	//上海:/html[1]/body[1]/div[9]/div[2]/div[1]/ul[1]
	//下級是li列表 ,Text值就是股票名稱和程式碼  XXX()
	//深圳:上海:/html[1]/body[1]/div[9]/div[2]/div[1]/ul[2]
	string url = @"http://quote.eastmoney.com/stocklist.html";

	HtmlWeb htmlweb = new HtmlWeb();
	htmlweb.OverrideEncoding = Encoding.GetEncoding(936);
	HtmlDocument doc = htmlweb.Load(url);

	Dictionary<string, string> dic = new Dictionary<string, string>()
	{
		{"上海",@"/html[1]/body[1]/div[9]/div[2]/div[1]/ul[1]" },
		{"深圳",@"/html[1]/body[1]/div[9]/div[2]/div[1]/ul[2]" }
	};

	#region 獲取
	Dictionary<String, StockBaseInfo> list = new Dictionary<string, StockBaseInfo>();
	foreach (var item in dic)
	{
		//獲取所有子節點
		var res = doc.DocumentNode.SelectSingleNode(item.Value).SelectNodes(@"li");
		if (res.Count > 0)
		{
			foreach (var node in res)
			{
				//獲取名稱和程式碼
				var name = node.InnerText.Trim();
				if (name.IsNullOrEmpty()) continue;
				var str = name.Split('(', ')');
				if (str.Length < 2) continue;

				StockBaseInfo et = new StockBaseInfo()
				{
					Code = str[1],
					Name = str[0],
					Exchange = item.Key,
					StartDate = new DateTime(2000, 1, 1),
					CreateDate = DateTime.Now 
				};
				if(!list.ContainsKey(et.Code))
				{
					list.Add(et.Code,et);
				}
			}
		}
	}
	list.ToValueArray().Insert(true);
	#endregion
}

獲取到子節點後,解析名稱,然後用批量Insert到資料庫。

用XCode預設都是使用Sqlite資料庫,輕量級,非常方便,資料庫表結構都是自動新建。

4.2 股票歷史資料

  我們使用2.2節中提到的介面,如下,配合前面採集到的所有股票基礎資料,就可以便利進行歷史資料抓取了,說一下,這個介面很給力,速度相當快。我是從2000年1月1日開始採集的,截止時間是2018年2月10日(放假閒的你懂的)。歷史json資料按股票ID單獨儲存,後面寫了一個轉換程式單獨從歷史資料庫轉換即可。

  http://q.stock.sohu.com/hisHq?code={code}&start={start}&end={end},{code}替換為股票程式碼,大陸股票程式碼加字首cn_。

 這裡對老司機來說,其實沒多少難度,就是拼接URL,請求獲取json資料,然後解析json格式,我解析用了Newlife的JsonParser,用起來很簡單有空我單獨講一下,就是把Json用字典和List<Object>儲存下來,知道結構後,直接強制轉換和取值即可。上程式碼:

public static void GetHistoryFromWeb(string stockCode, DateTime start, DateTime end,string type="cn")
{
	string url = @"http://q.stock.sohu.com/hisHq?code={3}_{0}&start={1}&end={2}".F(stockCode, start.ToString("yyyyMMdd"),
		end.ToString("yyyyMMdd"),type);
	WebClientX client = new WebClientX();
	client.Timeout = 1000 * 120;
	var text = client.GetHtml(url);
	var doc = new HtmlDocument();
	doc.LoadHtml(text);
	var value = doc.DocumentNode.InnerText;
	var et = new StockHisText()
	{
		Code = stockCode,
		Start = start,
		End = end,
		HisText = value
	};
	try
	{
		if (type == "zs") et.Code = "{0}_{1}".F("Index",et.Code);//加字首區分
		et.Insert();
	}
	catch(Exception err)
	{
		XTrace.WriteException(err);
	}
}

上面是獲取單個股票其指定日期範圍內的歷史資料,直接到歷史表,下面是解析部分,外面套的迴圈就不貼程式碼了,可以下載原始碼看。

public static void PraseHistoryData()
{
	var all = FindAll();
	int index = 1;
	Parallel.For(0, all.Count, new ParallelOptions() { MaxDegreeOfParallelism = 1 }, i => 
	{
		XTrace.WriteLine("進度:{0}/{1}",index ++,all.Count);
		#region 單個文字解析
		JsonParser jp = new JsonParser(all[i].HisText);
		var decode = (List<object>)jp.Decode();
		if (decode.Count < 1) return;
		var main = (Dictionary<string, object>)decode[0];//字典
		if (main.ContainsKey("hq"))
		{
			var obj = (List<object>)main["hq"];
			if (obj.Count > 0)
			{
				List<StockDayData> res = new List<StockDayData>();
				foreach (var item in obj)
				{
					#region 單條記錄解析
		//item是一個10個元素的陣列
		//日期,今開價格,今天收盤價格,漲跌金額,漲跌幅度,最低價格,最高價格,總手,總金額(萬),換手率
		//"2018-02-09", "31.46", "31.46", "2.86", "10.00%", "31.46", "31.46", "303", "95.32", "0.15%"
					var list = (List<object>)item;
					StockDayData sd = new StockDayData()
					{
						Code = all[i].Code,
						StatDate = list[0].ToDateTime(),
						StartPrice = list[1].ToDouble(),
						EndPrice = list[2].ToDouble(),
						ChangePrice = list[3].ToDouble(),
						ChangeRatio = ((string)list[4]).Replace("%", "").ToDouble(),
						LowPrice = list[5].ToDouble(),
						HighPrice = list[6].ToDouble(),
						TotalHand = list[7].ToInt(),
						TotalAmount = list[8].ToDouble(),
						HandRate = ((string)list[9]).Replace("%", "").ToDouble(),
						UpdateDate = DateTime.Now
					};
					sd.ID = "{0}_{1}".F(sd.Code, sd.StatDate.ToString("yyyyMMdd"));
					#endregion

					res.Add(sd);
				}
				res.Save(true);
			}
		}
		#endregion
	});
}

 我的程式碼裡面有直接把歷史資料解析分庫儲存的,方法在 股票歷史文字資料.Biz.cs 檔案的,PraseHistoryDataV2方法中。分庫方法非常簡單,儲存之前修改一下連結即可。

5.原始碼和資料庫

Sqlite很好玩,強烈推薦工具,navicat,可以去CSDN找一個破解版下載玩玩。

相關推薦

開源C#.NET股票歷史資料採集18年曆資料原始碼

重點重點:我沒有買股票,沒有買股票,股市是個坑,小心割韭菜哦。 本文的初衷是資料分析(分析結果就不說了,就是想看看篩選點資料),只不過搞下來發現比我想象的要簡單多了。本文采集的資料是:2000年到2018年2月份,上證和深證交易所所有的上市股票交易資料,按天採集,不是小時哦,有興趣的朋友,可以稍微改

.Net碼農C#.net檔案批量上傳解決方案下載(swfupload)2015-8-28更新

因為最近專案需要多檔案同時上傳所以自己在網上找了下方法。swfupload做到了,所以我把我的C#.net環境的多檔案同時上傳共享給大家!(本例項最大隻能上傳500M的資料,如需要上傳更大的下面會告訴大家如何設定) 功能完全支援ie和firefox瀏覽器! 一般的WEB方式檔案上傳只能一個一個的進行上傳

C#C#判斷檔案路徑是否存在不存在則建立資料

//判斷檔案路徑是否存在,不存在則建立資料夾 if (!System.IO.Directory.Exists(@"D:\Export")) { System.IO.Directory.CreateDirectory(@"D:\Export");//不存在就建立目錄

資料結構c++ 實現連結串列的建立查詢列印刪除插入

//程式很簡單,但是要捋順邏輯關係,留著備用 #include #include"stdafx.h" using namespace std; struct node { int data; node* next; }; node * created_hea

c++c++中重載輸出操作符為什麽要返回引用

不返回 定義 類型 AS 標準 操作符 連續 新的 輸出 針對:ostream & operator <<(ostream & os, const ClassType &object) 說明幾點: 1.第一個形參為對ostream對象的引

Python1:python介紹,歷史,解釋器語言分析

國內 系統運維 更新 進行 清晰 naconda linu 內存 pen python介紹 Python(英國發音:/?pa?θ?n/ 美國發音:/?pa?θɑ?n/), 是一種面向對象、解釋型計算機程序設計語言,由Guido van Rossum於1989年發明,第一個公

演算法C++用連結串列實現一個箱子排序原始碼詳解

01 箱子排序 1.1 什麼是分配排序? 分配排序的基本思想:排序過程無須比較關鍵字,而是通過"分配"和"收集"過程來實現排序.它們的時間複雜度可達到線性階:O(n)。 1.2 什麼是箱子排序? 箱子排序是分配排序的一種,箱子排序也稱桶排序(Bucket Sort),其基本思想是:設定若干個箱子,依次掃描待

FIF_Bro的部落格】C++ 的最大優點是它是一門強大兼顧了底層效率的高階語言。這使得 C++ 幾乎沒有任何侷限性無所不能。只要你是一個追求極致達到偏執的人你幾乎總可以追尋到它的影子存在。這門語言超高的開發成本使得只有偏執的人才會對它痴狂

C++ 的最大優點是,它是一門強大,兼顧了底層效率的,高階語言。這使得 C++ 幾乎沒有任何侷限性,無所不能。只要你是一個追求極致達到偏執的人,你幾乎總可以追尋到它的影子和存在。這門語言超高的開發成本...

AndroidAndroid Camera實時資料採集及通過MediaCodec硬編碼編碼資料的流程

// video device. private Camera camera; private MediaCodec vencoder; private MediaCodecInfo vmci; private MediaCodec.BufferInfo vebi; private byte[] vbuff

工作筆記C語言的字串真麻煩好好梳理下

C的字串 C的字串很麻煩,不能像C++那樣對字串+ ,長度又不能隨便變。真TMD煩,有一句粗話真不知道當講不當講。時間全都浪費在處理字串上了。這個筆記中我要好好總結下,避免浪費時間。

C#.NET 程序員的福利自己寫的一個XML操作類可實現像jquery一樣方便的xml操作且不用專門去處理命名空間。

console region ignorecas node 處理 命名空間 void clone 一個 此工具是進入一家新公司之後實現的,主要是工作當中操作 xml 的時間太多,因為公司按任務計“工作量”,領導給我安排的時間遠遠不夠完善此工具【悲哀的

C語言給NI資料採集卡程式設計序實現多路資料的同時採集

  因為寫的上一篇NI資料採集卡的程式有人留言說想要實現多路資料的同時採集,我沒有及時回覆,深感抱歉,在此寫一篇關於NI資料採集卡的多路資料同時採集的程式     第一個程式實現的功能:六路資料同時採集,採集有限個數據,並且儲存到txt

C#進行影象識別與資料採集進而實現對視訊裡的資料採集

窗體佈局的滑鼠移動距離問題oledb資料型別不一致如何更新窗體佈局的滑鼠移動距離問題oledb資料型別不一致如何更新 我的vs2008今天怎麼不能用了啊麻煩進來看看為什麼開發windowsForm程式Gridview隱身無法使用我的vs2008今天怎麼不能用了啊麻煩進來看看為

春節來臨-你可能需要動態全屏閃爍的網頁賀卡附帶演示地址原始碼

大神輕噴,我技術有限,純屬娛樂,不過有新的想法歡迎交流。 1.背景 之前看見別人做的動態文字視訊,還有炫酷的PPT,我就想自己嘗試做一下。 別人是用軟體做的,我想試試html。 然後就有了後面的故事了,開啟後播放速度會越來越快,最後會回到開始的速度,自己可以修改。 演

C#/.NET 單例模式——懶漢式餓漢式三種實現方法

C# 單例模式 ——懶漢式,餓漢式# 註釋: /// 單例模式 /// /// 餓漢式 :第一時間建立例項,類載入就馬上建立 /// 懶漢式 :需要才建立例項,延遲載入 /// /// 單例模式會長期持有一個物件,不會釋放 /// 普通例項使用完後釋放 /// /// 單例

使用C#.NET 實現高效能IPX/SPX SOCKET伺服器 原始碼

 要實現 IPX/SPX 必須自己寫IPX地址類 它派生於 EndPoint. 因為.NET沒有提供此類所以必須自己寫 public class IPXEndPoint : EndPoint { byte[] NetNum;

機器視覺20個視覺應用專案展示機器代替人眼來做測量判斷!

機器視覺的應用案例1.印表機透明塑膠檢測2. 智慧卡OCR字元檢測3.電池產品定位檢測4.鋰電池

一步步教您學會大資料採集之“什麼值得買”推薦商品資料採集教程

本文主要介紹如何使用后羿採集器的智慧模式,免費採集“什麼值得買”商品價格、圖片、標題及推薦人等資訊。 採集工具簡介: 后羿採集器是一款基於人工智慧技術的網路爬蟲工具,只需要輸入網址就能夠自動識別網頁資料,無需配置即可完成資料採集,是業內首家支援三種作業系統(包括Windows、Mac和Linux

別人給我一個介面是個url地址讓我推送資料過去然後得到別人返回的資料怎麼呼叫這個介面呢?

1:客戶端地址:http://1*2.***.**.1*4:7**8/peasentProducts/save(需要把服務端資料傳送到客戶端) 2:自己在控制層把資料放在放在一個map集合中,自己寫一個類封裝一個方法,把資料傳送過去   3:controller---控制層程式