更新於 2024/09/16閱讀時間約 1 分鐘

散戶指標 - 小台多空比的查詢實作

自從筆者研究程式交易之後,就發現自己以往的操作模式非常符合散戶小台多空比的趨勢,現在則發現微台多空比更符合,不愧為韭菜中的韭菜!
這篇文章也是網路爬蟲的應用之一,透過台灣期貨交易所的公開資料來計算散戶小台多空比,也就是將
小台指散戶多空比 = 小台指散戶留倉量/小台指全體未平倉量 = -1 * 小台指三大法人未平倉量/小台全體未平倉量
其原理是小台指散戶多空比,通常視為散戶籌碼指標,與散戶指標對作,反而容易賺錢。正值越大,表示散戶做多部位越多;負值越大,表示散戶做空部位越多。
需要注意的是台灣期貨交易所產生的資料是五大碼(Big-5)格式,所以我們需要轉換為UTF格式做後續處理。
        private decimal RetailMxf(DateTime date)
        {
            decimal retailMxfLongShortRatio = 0;
            try
            {
                string day = goodday(date, "");
                string query = goodday(date, "/");
                string path = Path.Combine(@s_homepath, day, "futDataDown_" + day + ".csv");

                List<string> csvData = new();
                string url = "https://www.taifex.com.tw/cht/3/futDataDown";
                if (!File.Exists(path))
                {
                    Filebase.CreateDir(day, s_homepath);
                    using (var wb = new WebClient())
                    {
                        string responseInString = string.Empty;
                        //wb.Headers.Add("Content-Type", "multipart/form-data");
                        var data = new NameValueCollection();
                        data.Add("down_type", "1");
                        data.Add("queryStartDate", query);
                        data.Add("queryEndDate", query);
                        data.Add("commodity_id", "MTX");

                        var response = wb.UploadValues(url, "POST", data);

                        if (response != null)
                        {
                            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
                            responseInString = Encoding.GetEncoding(950).GetString(response);
                            File.WriteAllText(path, responseInString);
                            csvData = responseInString.Split("\r\n").Skip(1).Where(row => row.Length > 0).ToList();
                        }
                    }
                }
                else
                {
                    csvData = File.ReadAllLines(path).Skip(1).Where(row => row.Length > 0).ToList();
                }

                decimal mxfMarketOi = 0;
                for (int i = 0; i < csvData.Count; i++)
                {
                    string[] csv = csvData[i].Split(",");

                    // 僅取日盤並排除價差合約
                    if (csv.Count() == 20 && csv[17] == "一般" && csv[18] == "")
                    {
                        // 計算小型臺指全市場未平倉口數
                        mxfMarketOi += Convert.ToDecimal(csv[11]);
                    }
                }

                path = Path.Combine(@s_homepath, day, "futContractsDate_" + day + ".csv");
                url = "https://www.taifex.com.tw/cht/3/futContractsDateDown";
                if (!File.Exists(path))
                {
                    Filebase.CreateDir(day, s_homepath);
                    using (var wb = new WebClient())
                    {
                        string responseInString = string.Empty;
                        //wb.Headers.Add("Content-Type", "multipart/form-data");
                        var data = new NameValueCollection();
                        data.Add("queryStartDate", query);
                        data.Add("queryEndDate", query);
                        data.Add("commodityId", "MXF");

                        var response = wb.UploadValues(url, "POST", data);

                        if (response != null)
                        {
                            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
                            responseInString = Encoding.GetEncoding(950).GetString(response);
                            File.WriteAllText(path, responseInString);
                            csvData = responseInString.Split("\r\n").Skip(1).Where(row => row.Length > 0).ToList();
                        }
                    }
                }
                else
                {
                    csvData = File.ReadAllLines(path).Skip(1).Where(row => row.Length > 0).ToList();
                }

                decimal dealersLongOiVolume = 0, sitcLongOiVolume = 0, finiLongOiVolume = 0;
                decimal dealersShortOiVolume = 0, sitcShortOiVolume = 0, finiShortOiVolume = 0;

                for (int i = 0; i < csvData.Count; i++)
                {
                    string[] csv = csvData[i].Split(",");

                    if (csv.Count() == 15)
                    {
                        if (csv[2] == "自營商")
                        {
                            dealersLongOiVolume = Convert.ToDecimal(csv[9]);
                            dealersShortOiVolume = Convert.ToDecimal(csv[11]);
                        }

                        if (csv[2] == "投信")
                        {
                            sitcLongOiVolume = Convert.ToDecimal(csv[9]);
                            sitcShortOiVolume = Convert.ToDecimal(csv[11]);
                        }

                        if (csv[2] == "外資及陸資")
                        {
                            finiLongOiVolume = Convert.ToDecimal(csv[9]);
                            finiShortOiVolume = Convert.ToDecimal(csv[11]);
                        }
                    }
                }

                // 計算三大法人小型臺指多方未平倉口數
                var instInvestorsMxfLongOi = dealersLongOiVolume + sitcLongOiVolume + finiLongOiVolume;

                // 計算三大法人小型臺指空方未平倉口數
                var instInvestorsMxfShortOi = dealersShortOiVolume + sitcShortOiVolume + finiShortOiVolume;

                // 計算散戶小型臺指多方未平倉口數
                var retailMxfLongOi = mxfMarketOi - instInvestorsMxfLongOi;

                // 計算散戶小型臺指空方未平倉口數
                var retailMxfShortOi = mxfMarketOi - instInvestorsMxfShortOi;

                // 散戶小型臺指淨未平倉口數
                var retailMxfNetOi = retailMxfLongOi - retailMxfShortOi;

                // 計算散戶小台多空比
                retailMxfLongShortRatio = Math.Round(retailMxfNetOi / mxfMarketOi * 10000) / 10000;
            }
            catch (Exception e)
            {
                Debug.WriteLine("Exception " + e);
            }
            // https://www.macromicro.me/charts/20069/tw-mtx-long-to-short-ratio-of-individual-player
            // 正值越大,表示散戶做多部位越多;負值越大,表示散戶做空部位越多
            //Debug.WriteLine("散戶小台多空比 " + retailMxfLongShortRatio);
            return retailMxfLongShortRatio * 100;
        }

前文有提到微台多空比更符合散戶趨勢,理論上可以把索取資料格式從 MTX 改成 TMF,並採用類似的計算公式即可,不過筆者現在幾乎躺平,有機會再來實作。
類似的擷取方式也適用在臺指選擇權波動率指數、買賣權未平倉量、外資選擇權,資料網址如下,實作就不一一列出。
string url = "https://www.taifex.com.tw/cht/7/getVixData?filesname=" + day;
string url = "https://www.taifex.com.tw/cht/3/pcRatioDown";
string url = "https://www.taifex.com.tw/cht/3/optContractsDateDown";

在此還是祝福大家都能夠賺大錢~
分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.