籌碼面 - 台灣證券交易所買賣日報表查詢系統

閱讀時間約 1 分鐘

自從筆者開始研究量化交易之後,就聽說股價跟籌碼面脫不了關係,其中的重點就是要分析分點交易狀況。台灣證券交易所與證券櫃檯買賣中心都有提供買賣日報表查詢,但是為了避免太多機器人爬蟲造成主機負擔,一個需要輸入圖形驗證碼,一個需要勾選reCaptcha我不是機器人的欄位。

這一篇就先以程式自動輸入圖形驗證碼,並取得證券交易所每一檔股票的買賣日報表當作範例。

台灣證券交易所的買賣日報表查詢網路連結為https://bsr.twse.com.tw/bshtm/bsMenu.aspx。主要的邏輯架構也不難,先把台灣證券交易所的網頁抓下來,找到辨識驗證碼的欄位,透過OpenCV與OCR把圖型轉成數字,填回數字以及想要抓取的股票代碼,按下網頁確定的按鈕,網站就會吐出該股票代碼的買賣日報表,我們把這些資料做個欄位處理之後,存成一個文字檔案,再由其他程式做籌碼計算。

這邊要注意的是OCR套件不一定每次都可以辨識出正確的數字,因為台灣證券交易所的數字長度永遠都是5,所以我們可以在辨識的結尾判斷長度,如果不正確,就重新判斷一次。

另外就是台灣證券交易所如果偵測到大量的索取要求,將會直接把IP鎖住一陣子,所以在每次索取要求之間,我們都先暫停一段時間,這邊我們是設定一分鐘。主要程式碼就如下所示:

        private async Task<bool> GetTWSEBroker(string code, string path)
{
// https://bsr.twse.com.tw/bshtm/bsMenu.aspx
// https://bsr.twse.com.tw/bshtm/bsContent.aspx

int dlretry = 0;
int ocrretry = 0;
begin:
string reqtwse = "https://bsr.twse.com.tw/bshtm/bsMenu.aspx";
CookieContainer _cookies = new CookieContainer();
string csvtwse = await GetAsync(reqtwse, _cookies, 65001);
again:
string Captcha = FindImg(csvtwse);
//Debug.WriteLine(code + " 辨識驗證碼 " + Captcha);
if (Captcha.Length != 5)
{
if (ocrretry++ < 5)
{
goto again;
}
else
{
Debug.WriteLine(code + " 辨識驗證碼錯誤 " + Captcha);
}
}

NameValueCollection postParams = System.Web.HttpUtility.ParseQueryString(string.Empty);
postParams.Add("__EVENTTARGET", "");
postParams.Add("__EVENTARGUMNET", "");
postParams.Add("__LASTFOCUS", "");
postParams.Add("__VIEWSTATE", FindToken(csvtwse, "__VIEWSTATE"));
postParams.Add("__VIEWSTATEGENERATOR", FindToken(csvtwse, "__VIEWSTATEGENERATOR"));
postParams.Add("__EVENTVALIDATION", FindToken(csvtwse, "__EVENTVALIDATION"));
postParams.Add("RadioButton_Normal", "RadioButton_Normal");
postParams.Add("TextBox_Stkno", code);
postParams.Add("CaptchaControl1", Captcha);
postParams.Add("btnOK", "%E6%9F%A5%E8%A9%A2");

string responseInString = SetAsync(reqtwse, _cookies, postParams);
//Debug.WriteLine(responseInString);
if (FindContent(responseInString))
{
string csvurl = "https://bsr.twse.com.tw/bshtm/bsContent.aspx";
string csvline = await GetAsync(csvurl, _cookies, 950);

if (csvline.Count() > 0)
{
File.WriteAllText(path, "證券代碼 " + code + " 序號,券商,價格,買進股數,賣出股數\r\n");
int skipline = 0;
foreach (var line in csvline.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Replace(" ", "")).Select(s => s.Replace(" ", "")))
{
if (skipline++ < 3) continue;

try
{
string[] csv = line.Split(",");
string strData = string.Empty;
if (csv.Count() == 11)
{
if (csv[6] != "")
{
strData = string.Format("{0},{1},{2},{3},{4}\r\n{5},{6},{7},{8},{9}\r\n",
csv[0], csv[1], csv[2], csv[3], csv[4], csv[6], csv[7], csv[8], csv[9], csv[10]
);
}
else
{
strData = string.Format("{0},{1},{2},{3},{4}\r\n",
csv[0], csv[1], csv[2], csv[3], csv[4]
);
}

File.AppendAllText(path, strData);
}
else
{
File.Delete(path);
Debug.WriteLine("TWSE Err inline " + code);
}
}
catch
{
File.Delete(path);
Debug.WriteLine("TWSE Err File " + code);
}
}
}

return true;
}
else if (dlretry++ < 5)
{
//Debug.WriteLine("驗證碼錯誤");
Thread.Sleep(60000);
goto begin;
}

Debug.WriteLine("TWSE Err download " + code);
return false;
}

為了可以取得網頁上面的資料,在這邊我們採用HtmlAgilityPack的HtmlDocument套件,幫助我們把網頁內容抓下來,並提取指定的欄位,其中辦識圖片中的數字,可以透過OpenCV先做圖片的切割,再透過Tesseract OCR的幫助,把每個圖片數字轉成實際數值,所以使用上要在C#先安裝HtmlAgilityPack、OpenCvSharp4以及Tesseract的套件。

我把相關的程式碼都放在下方,提供大家做參考。

        private string FindImg(string webdata)
{
try
{
if (webdata.Length == 0)
{
Debug.WriteLine("CaptchaImage has no challenge. Sleeping for a while now.");
Thread.Sleep(1800000);
return string.Empty;
}

string imgname = string.Empty;

HtmlDocument document = new HtmlDocument();
document.LoadHtml(webdata);

foreach (HtmlNode tag in document.DocumentNode.SelectNodes("//img"))
{
if (tag.Attributes["src"].Value.Contains("CaptchaImage"))
{
imgname = tag.Attributes["src"].Value;
}
}

string fname = @s_temppath + "CaptchaImage.JFIF";
if (File.Exists(fname))
{
File.Delete(fname);
}

using (WebClient webClient = new WebClient())
{
webClient.DownloadFile(new Uri("https://bsr.twse.com.tw/bshtm/" + imgname), fname);
//webClient.DownloadData
}

return DecodeCaptcha(@s_temppath + "CaptchaImage.JFIF");
}
catch (NullReferenceException)
{
// web return no page
Debug.WriteLine("CaptchaImage has no challenge. Sleeping for a while now.");
Thread.Sleep(1800000);
}
catch
{
//Debug.WriteLine("Exception in CaptchaImage");
Thread.Sleep(5000);
}
return string.Empty;
}
private string FindToken(string webdata, string item)
{
try
{
HtmlDocument document = new HtmlDocument();
document.LoadHtml(webdata);
string description = string.Empty;
foreach (HtmlNode tag in document.DocumentNode.SelectNodes("//input"))
{
if (tag.Attributes["name"] != null && tag.Attributes["id"] != null && tag.Attributes["name"].Value == item)
{
description = tag.Attributes["value"].Value;
}
}
return description;
//return System.Web.HttpUtility.UrlEncode(description);
}
catch (NullReferenceException)
{
// web return no page
Debug.WriteLine("CaptchaImage has no challenge. Sleeping for a while now.");
Thread.Sleep(1800000);
}
catch
{
;
}
return string.Empty;
}
private string DecodeCaptcha(string img)
{
var ocrtext = string.Empty;
// OpenCV#
using Mat captcha = new Mat(img, ImreadModes.Grayscale);
if (captcha.Empty())
{
return ocrtext;
}

// Convert the captcha to black and white.
using Mat captcha_bw = new Mat();
Cv2.Threshold(captcha, captcha_bw, 128, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);

// Erode the image to remove dot noise and that wierd line. I use a 3x3 rectengal as the kernal.
using Mat captcha_erode = new Mat();
using Mat element = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3));
Cv2.Erode(captcha_bw, captcha_erode, element);

// Some cosmetic
using Mat captcha_denoise = new Mat();
Cv2.FastNlMeansDenoising(captcha_erode, captcha_denoise, 50);

byte[] buffer = captcha_denoise.ToMemoryStream().ToArray();

// OCR
var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase);
path = Path.Combine(path, "tessdata");
path = path.Replace("file:\\", "");

using (var engine = new TesseractEngine(path, "eng", EngineMode.Default))
{
engine.SetVariable("tessedit_char_whitelist", "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ");
engine.SetVariable("tessedit_unrej_any_wd", true);
using (var ocr = Pix.LoadFromMemory(buffer))
{
using (var page = engine.Process(ocr))
{
ocrtext = page.GetText();
}
}
}

return ocrtext.Trim('\n');
}

一開始,我對於網頁互動爬取資料也不是很熟悉,所以土炮煉製了這一大段的程式去抓資料,中間走過不少冤枉路,雖然我實在找不到籌碼面怎麼樣可以幫助程式交易,但是還是把這些結果記錄下來,留個紀念。

4會員
5內容數
留言0
查看全部
發表第一個留言支持創作者!
Gary Hu的沙龍 的其他內容
本文將討論在EWDK環境下如何取得時區差值與日光節約時間開啟與否的相關資訊,並記錄下相關研究結果。
身為會寫一點程式碼的工程師,量化交易投資無疑是最具吸引力的投資方式。試想只要寫個小程式定期去追蹤股市大盤交易指數,然後自動下單買入賣出,就會賺進源源不絕的財富,光用想的口水都快流下來了。 坐而言不如起而行。這邊有幾個小問題需要克服: 即時報價 下單買賣 交易策略
本文將討論在EWDK環境下如何取得時區差值與日光節約時間開啟與否的相關資訊,並記錄下相關研究結果。
身為會寫一點程式碼的工程師,量化交易投資無疑是最具吸引力的投資方式。試想只要寫個小程式定期去追蹤股市大盤交易指數,然後自動下單買入賣出,就會賺進源源不絕的財富,光用想的口水都快流下來了。 坐而言不如起而行。這邊有幾個小問題需要克服: 即時報價 下單買賣 交易策略
你可能也想看
Thumbnail
1.加權指數與櫃買指數 週五的加權指數在非農就業數據開出來後,雖稍微低於預期,但指數仍向上噴出,在美股開盤後於21500形成一個爆量假突破後急轉直下,就一路收至最低。 台股方面走勢需觀察週一在斷頭潮出現後,週二或週三開始有無買單進場支撐,在沒有明確的反轉訊號形成前,小夥伴盡量不要貿然抄底,或是追空
Thumbnail
重點摘要: 1.9 月降息 2 碼、進一步暗示年內還有 50 bp 降息 2.SEP 上修失業率預期,但快速的降息速率將有助失業率觸頂 3.未來幾個月經濟數據將繼續轉弱,經濟復甦的時點或是 1Q25 季底附近
Thumbnail
近期的「貼文發佈流程 & 版型大更新」功能大家使用了嗎? 新版式整體視覺上「更加凸顯圖片」,為了搭配這次的更新,我們推出首次貼文策展 ❤️ 使用貼文功能並完成這次的指定任務,還有機會獲得富士即可拍,讓你的美好回憶都可以用即可拍珍藏!
Thumbnail
深入探討了在台灣旅遊與市場觀察的經驗,從首爾的旅遊心得到市場風格的變化,以及對任天堂和輝達(NVIDIA)未來發展的展望。了解最新的投資策略和市場動向,幫助投資者在動盪的市場中保持競爭力。
Thumbnail
分析了當前投資市場現況,聚焦於DDR3缺貨漲價、MCU題材、任天堂概念股及穩懋半導體的投資機會。此外,提供了在主流股未現時如何有效配置資金的投資策略建議,適合關注二三線題材股的投資者參考。
Thumbnail
因為選擇權來不急萎縮,只好用超大幅震盪 昨天頭尾如果波浪抓得好 一天3000點沒問題啊 光夜盤 開盤之後20400~19955 這樣450點 然後19955~20748 800點 20748~20230 又是500點 為啥那麼洗? 就是選擇權太貴了 上週五開始 一跌2700點
Thumbnail
臺股最近短線修正,投資者心情不安。長線交易者應有獲利,若有虧損則可能存在交易行為問題。投機和賭博只在一線之隔,應在進出場時機掌握好理由。無論交易週期長短,都應做好完善的交易規劃。
Thumbnail
探索投資遊戲產業的策略與風險管理,從資金配置到與潛力團隊的互動。深入分析市場動態與槓桿調整,並提供投資心態和決策建議。了解如何平衡夢想與風險,實現穩定收益。
Thumbnail
本書介紹了海龜交易方法,以及如何通過理性操作和堅守原則來獲得成功。書中還介紹了期貨交易王子理查·丹尼斯的實驗,以及一項能讓投資新手獲利百萬的計劃。無論是否使用海龜交易方法,這裡提供了判斷選擇的五個問題。欲知更多詳情,請訪問https://igrape.net/3GIIu。
Thumbnail
對沖就是一種避險方式,當一開始建立的部位已經不再是「低風險機會時」,就必須隨著目前趨勢建立期貨或選擇權部位,藉此鎖住獲利。使用對沖避險一定會比裸賣的策略獲取更少的利潤,但它可以有效控制虧損風險,防止帳戶瞬間承受巨大虧損。
Thumbnail
菜雞最適合的無腦交易策略:網格交易! 人是不理性的,但機器是理性的。用 24 小時不斷交易的機器人來幫助新手獲利 什麼是網格交易? 一言以蔽之:用機器人自動低買高賣
「道狗」投資法是一個非常簡單的股票操作方法,這個方法投資標的明確,一年中買賣各一次。這對因工作繁忙而沒有太多時間研究和操作股票的小散非常適用。持有股票的時間是一年,在稅率上也比較合理,對一般的證券賬戶和退休賬戶都適用。 具體操作方法就是在每年年初的時候把道瓊指數的30支股票中股息率最高的5支股票同
Thumbnail
1.加權指數與櫃買指數 週五的加權指數在非農就業數據開出來後,雖稍微低於預期,但指數仍向上噴出,在美股開盤後於21500形成一個爆量假突破後急轉直下,就一路收至最低。 台股方面走勢需觀察週一在斷頭潮出現後,週二或週三開始有無買單進場支撐,在沒有明確的反轉訊號形成前,小夥伴盡量不要貿然抄底,或是追空
Thumbnail
重點摘要: 1.9 月降息 2 碼、進一步暗示年內還有 50 bp 降息 2.SEP 上修失業率預期,但快速的降息速率將有助失業率觸頂 3.未來幾個月經濟數據將繼續轉弱,經濟復甦的時點或是 1Q25 季底附近
Thumbnail
近期的「貼文發佈流程 & 版型大更新」功能大家使用了嗎? 新版式整體視覺上「更加凸顯圖片」,為了搭配這次的更新,我們推出首次貼文策展 ❤️ 使用貼文功能並完成這次的指定任務,還有機會獲得富士即可拍,讓你的美好回憶都可以用即可拍珍藏!
Thumbnail
深入探討了在台灣旅遊與市場觀察的經驗,從首爾的旅遊心得到市場風格的變化,以及對任天堂和輝達(NVIDIA)未來發展的展望。了解最新的投資策略和市場動向,幫助投資者在動盪的市場中保持競爭力。
Thumbnail
分析了當前投資市場現況,聚焦於DDR3缺貨漲價、MCU題材、任天堂概念股及穩懋半導體的投資機會。此外,提供了在主流股未現時如何有效配置資金的投資策略建議,適合關注二三線題材股的投資者參考。
Thumbnail
因為選擇權來不急萎縮,只好用超大幅震盪 昨天頭尾如果波浪抓得好 一天3000點沒問題啊 光夜盤 開盤之後20400~19955 這樣450點 然後19955~20748 800點 20748~20230 又是500點 為啥那麼洗? 就是選擇權太貴了 上週五開始 一跌2700點
Thumbnail
臺股最近短線修正,投資者心情不安。長線交易者應有獲利,若有虧損則可能存在交易行為問題。投機和賭博只在一線之隔,應在進出場時機掌握好理由。無論交易週期長短,都應做好完善的交易規劃。
Thumbnail
探索投資遊戲產業的策略與風險管理,從資金配置到與潛力團隊的互動。深入分析市場動態與槓桿調整,並提供投資心態和決策建議。了解如何平衡夢想與風險,實現穩定收益。
Thumbnail
本書介紹了海龜交易方法,以及如何通過理性操作和堅守原則來獲得成功。書中還介紹了期貨交易王子理查·丹尼斯的實驗,以及一項能讓投資新手獲利百萬的計劃。無論是否使用海龜交易方法,這裡提供了判斷選擇的五個問題。欲知更多詳情,請訪問https://igrape.net/3GIIu。
Thumbnail
對沖就是一種避險方式,當一開始建立的部位已經不再是「低風險機會時」,就必須隨著目前趨勢建立期貨或選擇權部位,藉此鎖住獲利。使用對沖避險一定會比裸賣的策略獲取更少的利潤,但它可以有效控制虧損風險,防止帳戶瞬間承受巨大虧損。
Thumbnail
菜雞最適合的無腦交易策略:網格交易! 人是不理性的,但機器是理性的。用 24 小時不斷交易的機器人來幫助新手獲利 什麼是網格交易? 一言以蔽之:用機器人自動低買高賣
「道狗」投資法是一個非常簡單的股票操作方法,這個方法投資標的明確,一年中買賣各一次。這對因工作繁忙而沒有太多時間研究和操作股票的小散非常適用。持有股票的時間是一年,在稅率上也比較合理,對一般的證券賬戶和退休賬戶都適用。 具體操作方法就是在每年年初的時候把道瓊指數的30支股票中股息率最高的5支股票同