- /*
- このプログラムはKabu+が提供するデータを利用しています。
- 日本株全銘柄 株価一覧表 https://kabu.plus/
- */
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.IO;
- using System.Net;
- using Zanetti.Data;
- //株価一覧表(新フォーマット)
- //SC(株価コード)、名称、市場、業種、日時、株価、前日比、前日終値、始値、高値、安値、VWAP、出来高、出来高率、売買代金、時価総額、値幅下限、値幅上限、高値日付、年初来高値、年初来高値乖離率、安値日付、年初来安値、年初来安値乖離率
- //1時間当たりのアクセス回数制限がStandardコースで4回なので、複数日付株価取得は不可能と思われます(未確認)
- namespace Zanetti.DataSource.Specialized
- {
- internal class KabuPlusDataSource : DailyDataSource
- {
- public KabuPlusDataSource(int[] dates) : base(dates)
- {
- }
- //適宜、IDとパスワードを変更
- private const string SITE_ID = "trial";
- private const string SITE_PASSWORD = "PW@20170129";
- private const int mindate = 20170104;//データがこれ以前は存在しない。ただし、1年分の株価しか閲覧できない仕様がどうなるかを確かめてから仕様を固める
- public override void Run()
- {
- //var ld = Util.GuessLatestTradeDate();
- var date = _dates[0];//時間当たりのデータ取得制限のため指定した日付のみ取得
- var newdata = new Dictionary<int, NewDailyData>();
- for (int i = 0; i < 4; i++)
- {
- FillData(date, MakeUrl(date, i), ref newdata);
- }
- foreach (AbstractBrand br in Env.BrandCollection.Values)
- {
- if (br.Market == MarketType.B && !IsSupportedIndex(br.Code) || br.Market == MarketType.Custom || ((BasicBrand)br).Obsolete)
- continue;
- using (var farm = (DailyDataFarm)br.CreateDailyFarm(_dates.Length))
- {
- var traceFlag = false;
- if (date < mindate) continue;
- NewDailyData td;
- if (newdata.TryGetValue(br.Code, out td))
- {
- farm.UpdateDataFarm(date, td);
- }
- else
- {
- if (traceFlag)
- continue;
- traceFlag = true;
- Debug.WriteLine("Data not found(KabuPlus) : code=" + br.Code + " market=" + br.Market);
- }
- farm.Save(Util.GetDailyDataFileName(br.Code));
- SendMessage(AsyncConst.WM_ASYNCPROCESS, br.Code, AsyncConst.LPARAM_PROGRESS_SUCCESSFUL);
- }
- }
- }
- private readonly Dictionary<DateTime, int> _marketVolume = new Dictionary<DateTime, int>();
- private readonly Dictionary<DateTime, NewDailyData> _nikkei225 = new Dictionary<DateTime, NewDailyData>();
- private readonly Dictionary<DateTime, NewDailyData> _topix = new Dictionary<DateTime, NewDailyData>();
- private void InsertIndices(DateTime date, Dictionary<int, NewDailyData> result)
- {
- result[(int)BuiltInIndex.Nikkei225] = _nikkei225[date];
- result[(int)BuiltInIndex.TOPIX] = _topix[date];
- }
- private void FillData(int date, string url, ref Dictionary<int, NewDailyData> result)
- {
- var uri = new Uri(url);
- using (var webClient = new System.Net.WebClient())
- {
- webClient.Credentials = new NetworkCredential(SITE_ID, SITE_PASSWORD);
- //var enc = new System.Text.UTF8Encoding();
- using (var reader = new StreamReader(webClient.OpenRead(url), System.Text.Encoding.GetEncoding("shift_jis")))
- {
- string line;
- while ((line = reader.ReadLine()) != null)
- {
- var tokens = line.Replace("\"", "").Split(',');
- if (tokens.Length != 17 || tokens[0].Length != 4)
- continue;
- var code = int.Parse(tokens[0]);
- code = code == 1 ? 101 : code == 2 ? 102 : code;
- var br = Env.BrandCollection.FindBrand(code) as BasicBrand;
- if (br == null || !CheckMarket(br.Market, tokens[2]))//個別のみ通す
- continue;
- if (String2Int(tokens[4]) != date)
- continue;
- var volume = (int)ParseField(tokens[13]);
- var shift = IsIndex(code) ? 100 : 10; // 指数は100倍、株式は10倍で記録する
- var td = new NewDailyData
- {
- volume = volume,
- open = (int)(ParseField(tokens[9]) * shift),
- high = (int)(ParseField(tokens[10]) * shift),
- low = (int)(ParseField(tokens[11]) * shift),
- close = (int)(ParseField(tokens[5]) * shift)
- };
- result.Add(code, td);
- }
- }
- }
- }
- private string MakeUrl(int date, int kind)
- {
- var url_base = "https://csvex.com/kabu.plus/csv";
- switch (kind)
- {
- case 0://個別株
- return string.Format("{0}/japan-all-stock-prices/daily/japan-all-stock-prices_{1:D8}.csv", url_base, date);
- case 1://ETF・ETN
- return string.Format("{0}/tosho-etf-stock-prices/daily/tosho-etf-stock-prices_{1:D8}.csv", url_base, date);
- case 2://REIT
- return string.Format("{0}/tosho-reit-stock-prices/daily/tosho-reit-stock-prices_{1:D8}.csv", url_base, date);
- case 3://上場ファンド
- return string.Format("{0}/tosho-fund-and-others-stock-prices/daily/tosho-fund-and-others-stock-prices_{1:D8}.csv", url_base, date);
- }
- return null;
- }
- private bool IsIndex(int code)
- {
- return code == (int)BuiltInIndex.Nikkei225 ||
- code == (int)BuiltInIndex.TOPIX;
- }
- private int String2Int(string s)
- {
- DateTime dt = DateTime.Now;
- return DateTime.TryParse(s, out dt) ? int.Parse(dt.ToString("yyyyMMdd")) : -1;
- }
- private bool CheckMarket(MarketType market, string name)
- {
- switch (name)
- {
- case "東証":
- case "東証1部":
- case "東証一部":
- return market == MarketType.T1;
- case "東証2部":
- case "東証二部":
- return market == MarketType.T2;
- case "東証マザ":
- case "東証マザーズ":
- case "東証マザーズ外国":
- case "東証マザーズ審査":
- return market == MarketType.M;
- case "東証TPM":
- return market == MarketType.Custom;
- case "東証1部外国":
- return market == MarketType.T1;
- case "東証2部外国":
- return market == MarketType.T2;
- case "大証":
- case "大証1部":
- return market == MarketType.O1;
- case "大証2部":
- return market == MarketType.O2;
- case "東証JQグロース":
- case "東証JQスタンダード":
- case "東証JQスタンダード外国":
- case "JQ":
- case "JQS":
- case "JQスタンダード":
- case "JQスタンダード外国":
- case "JQグロース":
- case "JQG":
- case "JQNEO":
- return market == MarketType.J;
- case "HCスタンダード":
- case "HCスタンダード外国":
- case "HCグロース":
- return market == MarketType.H;
- case "福証":
- case "福証QB":
- case "福証Q-Board":
- case "札証":
- case "札証アンビシャス":
- case "札証アンビ":
- case "名証":
- case "名証一部":
- case "名証二部":
- case "名証セント":
- return false;
- }
- return false;
- }
- private bool IsSupportedIndex(int code)
- {
- return code == (int)BuiltInIndex.Nikkei225 ||
- code == (int)BuiltInIndex.TOPIX;
- }
- private double ParseField(string s)
- {
- // 空文字列を0として扱う。
- return s.Replace("-","").Replace("\t","").Trim() == "" ? 0 : double.Parse(s);
- }
- }
- }