OmegaChartのソースコードの保守
Revision | 91231cd3fa57ce1280f1cbc59aef208c3b46e712 (tree) |
---|---|
Time | 2022-04-04 22:58:00 |
Author | panacoran <panacoran@user...> |
Commiter | panacoran |
複数市場対応で市場チェックしていたのを出来高ベースに変える
@@ -2,6 +2,7 @@ | ||
2 | 2 | // This program is part of OmegaChart. |
3 | 3 | // OmegaChart is licensed under the Apache License, Version 2.0. |
4 | 4 | |
5 | +using System; | |
5 | 6 | using System.Collections.Generic; |
6 | 7 | using System.Diagnostics; |
7 | 8 | using System.IO; |
@@ -68,63 +69,35 @@ namespace Zanetti.DataSource.Specialized | ||
68 | 69 | if (code > 1002 && code < 1300) // 各種指数を無視する。 |
69 | 70 | continue; |
70 | 71 | code = code == 1001 ? (int)BuiltInIndex.Nikkei225 : code == 1002 ? (int)BuiltInIndex.TOPIX : code; |
71 | - var br = Env.BrandCollection.FindBrand(code) as BasicBrand; | |
72 | - if (br == null || | |
73 | - (d2.Year < 2006 ? !CheckMarketOld(br.Market, tokens[8]) : !CheckMarket(br.Market, tokens[2]))) | |
72 | + if (!(Env.BrandCollection.FindBrand(code) is BasicBrand)) | |
74 | 73 | continue; |
75 | - var vv = IsIndex(code) ? 0.001 : 1; | |
76 | - var pv = IsIndex(code) ? 100 : 10; // 指数は100倍、株価は10倍で記録。 | |
77 | - result[code] = new NewDailyData | |
74 | + try | |
78 | 75 | { |
79 | - open = (int)(double.Parse(tokens[3]) * pv), | |
80 | - high = (int)(double.Parse(tokens[4]) * pv), | |
81 | - low = (int)(double.Parse(tokens[5]) * pv), | |
82 | - close = (int)(double.Parse(tokens[6]) * pv), | |
83 | - volume = (int)(double.Parse(tokens[7]) * vv), | |
84 | - }; | |
76 | + var vv = IsIndex(code) ? 0.001 : 1; | |
77 | + var pv = IsIndex(code) ? 100 : 10; // 指数は100倍、株価は10倍で記録。 | |
78 | + var td = new NewDailyData | |
79 | + { | |
80 | + volume = (int)(double.Parse(tokens[7]) * vv) | |
81 | + }; | |
82 | + // 複数市場に上場している銘柄には複数のエントリがある。出来高の多いほうをとる。 | |
83 | + if (!result.TryGetValue(code, out var existing) || existing.volume < td.volume) | |
84 | + { | |
85 | + result[code] = td; | |
86 | + td.open = (int)(double.Parse(tokens[3]) * pv); | |
87 | + td.high = (int)(double.Parse(tokens[4]) * pv); | |
88 | + td.low = (int)(double.Parse(tokens[5]) * pv); | |
89 | + td.close = (int)(double.Parse(tokens[6]) * pv); | |
90 | + td.volume = (int)(double.Parse(tokens[7]) * vv); | |
91 | + } | |
92 | + } | |
93 | + catch (FormatException) | |
94 | + { | |
95 | + } | |
85 | 96 | } |
86 | 97 | } |
87 | 98 | return result; |
88 | 99 | } |
89 | 100 | |
90 | - private bool CheckMarketOld(MarketType market, string name) | |
91 | - { | |
92 | - switch (int.Parse(name)) | |
93 | - { | |
94 | - case 1: | |
95 | - return market == MarketType.T1 || | |
96 | - market == MarketType.B; // 指数は東証1部 | |
97 | - case 2: | |
98 | - return market == MarketType.T2; | |
99 | - case 3: | |
100 | - return market == MarketType.J; | |
101 | - } | |
102 | - return false; | |
103 | - } | |
104 | - | |
105 | - private bool CheckMarket(MarketType market, string name) | |
106 | - { | |
107 | - switch (int.Parse(name)) | |
108 | - { | |
109 | - case 1: | |
110 | - return market == MarketType.T1 || | |
111 | - market == MarketType.B; // 指数は東証1部 | |
112 | - case 2: | |
113 | - return market == MarketType.T2; | |
114 | - case 3: | |
115 | - return market == MarketType.M; | |
116 | - case 4: | |
117 | - return market == MarketType.J; | |
118 | - case 6: | |
119 | - return market == MarketType.O1; | |
120 | - case 7: | |
121 | - return market == MarketType.O2; | |
122 | - case 8: | |
123 | - return market == MarketType.H; | |
124 | - } | |
125 | - return false; | |
126 | - } | |
127 | - | |
128 | 101 | private bool IsIndex(int code) |
129 | 102 | { |
130 | 103 | return code == (int)BuiltInIndex.Nikkei225 || |
@@ -14,6 +14,7 @@ using System.IO; | ||
14 | 14 | using System.Collections; |
15 | 15 | using System.Diagnostics; |
16 | 16 | using Zanetti.Data; |
17 | +using System.Collections.Generic; | |
17 | 18 | |
18 | 19 | namespace Zanetti.DataSource.Specialized { |
19 | 20 | internal class MujinzouDataSource : DailyDataSource { |
@@ -33,44 +34,46 @@ namespace Zanetti.DataSource.Specialized { | ||
33 | 34 | } |
34 | 35 | |
35 | 36 | public override void Run() { |
36 | - Hashtable[] newdata = new Hashtable[_dates.Length]; | |
37 | - //データをまずダウンロード | |
38 | - for(int i=0; i<_dates.Length; i++) { | |
39 | - newdata[i] = FillData(_dates[i]); | |
40 | - SendMessage(AsyncConst.WM_ASYNCPROCESS, _dates[i] | DATE_MASK, AsyncConst.LPARAM_PROGRESS_SUCCESSFUL); | |
41 | - } | |
42 | - | |
43 | - //各データの追加と保存 | |
44 | - IDictionaryEnumerator ie = Env.BrandCollection.GetEnumerator(); | |
45 | - while(ie.MoveNext()) { | |
46 | - AbstractBrand br = (AbstractBrand)ie.Value; | |
47 | - if((br.Market==MarketType.B && !IsMujinzouSupportedIndices(br.Code)) || br.Market==MarketType.Custom) continue; | |
48 | - | |
49 | - bool trace_flag = false; | |
50 | - using(DailyDataFarm f = (DailyDataFarm)br.CreateDailyFarm(_dates.Length)) { | |
51 | - for(int i=0; i<_dates.Length; i++) { | |
52 | - NewDailyData td = (NewDailyData)newdata[i][br.Code]; | |
53 | - if(td==null) { | |
54 | - if(!trace_flag) { | |
55 | - trace_flag = true; | |
56 | - Debug.WriteLine("Data not found(mujinzou) : code="+br.Code+" market="+br.Market.ToString()); | |
57 | - } | |
58 | - } | |
59 | - else | |
60 | - f.UpdateDataFarm(_dates[i], td); | |
61 | - } | |
62 | - f.Save(Util.GetDailyDataFileName(br.Code)); | |
63 | - } | |
64 | - SendMessage(AsyncConst.WM_ASYNCPROCESS, br.Code, AsyncConst.LPARAM_PROGRESS_SUCCESSFUL); | |
65 | - } | |
37 | + var newdata = new Dictionary<int, Dictionary<int, NewDailyData>>(); | |
38 | + foreach (var date in _dates) | |
39 | + { | |
40 | + newdata[date] = FillData(date); | |
41 | + SendMessage(AsyncConst.WM_ASYNCPROCESS, (date | DATE_MASK), AsyncConst.LPARAM_PROGRESS_SUCCESSFUL); | |
42 | + } | |
43 | + foreach (AbstractBrand br in Env.BrandCollection.Values) | |
44 | + { | |
45 | + if (br.Market == MarketType.B && !IsDomesticIndex(br.Code) || br.Market == MarketType.Custom) | |
46 | + continue; | |
47 | + using (var farm = (DailyDataFarm)br.CreateDailyFarm(_dates.Length)) | |
48 | + { | |
49 | + var traceFlag = false; | |
50 | + foreach (var date in _dates) | |
51 | + { | |
52 | + NewDailyData td; | |
53 | + if (newdata[date].TryGetValue(br.Code, out td)) | |
54 | + { | |
55 | + farm.UpdateDataFarm(date, td); | |
56 | + } | |
57 | + else | |
58 | + { | |
59 | + if (traceFlag) | |
60 | + continue; | |
61 | + traceFlag = true; | |
62 | + Debug.WriteLine("Data not found(mujinzou) : code=" + br.Code + " market=" + br.Market); | |
63 | + } | |
64 | + } | |
65 | + farm.Save(Util.GetDailyDataFileName(br.Code)); | |
66 | + SendMessage(AsyncConst.WM_ASYNCPROCESS, br.Code, AsyncConst.LPARAM_PROGRESS_SUCCESSFUL); | |
67 | + } | |
68 | + } | |
66 | 69 | } |
67 | 70 | |
68 | 71 | |
69 | 72 | //ある日付に対して、コードのint値からPanRollingTradeDataへのハッシュテーブルを構築して返す |
70 | - private Hashtable FillData(int date) { | |
73 | + private Dictionary<int, NewDailyData> FillData(int date) { | |
71 | 74 | TextReader r = null; |
72 | 75 | try { |
73 | - Hashtable result = new Hashtable(); | |
76 | + var result = new Dictionary<int, NewDailyData>(); | |
74 | 77 | DateTime d2 = Util.IntToDate(date); |
75 | 78 | //無尽蔵にはデータが2種類あり、日経先物等の有無、名証銘柄の有無、出来高0のときの扱い、が異なるようだ。先物のデータがとれるようにこちらを使用する |
76 | 79 | //2007/3/1, eonetからのデータが入手不能になる。標準をinfoseekに切り替えるとともに、ついでに設定ファイルで切り替え可能にした。相場が大荒れの時期に面倒くさいことが起きたものだ。 |
@@ -81,45 +84,42 @@ namespace Zanetti.DataSource.Specialized { | ||
81 | 84 | : "d_data/" + d2.ToString(@"yyyy\d/yy_MM\d/TyyMMdd"); |
82 | 85 | var ext = d2.Year >= 2015 ? ".zip" : ".lzh"; |
83 | 86 | var url = $"http://{domain}/{path}{ext}"; |
84 | - r = new StreamReader(Util.ExtractData(url), Encoding.Default); | |
85 | - | |
86 | - string line = r.ReadLine(); | |
87 | - while(line!=null) { | |
88 | - string[] t = line.Split(','); | |
89 | - //例 0 1 2 3 4 5 6 7, 8, 9 | |
90 | - //2005/5/20,1001,11,1001 日経平均,11104,11110,11034,11037,1257840000,東証1部 | |
91 | - if(t.Length==10 && t[1].Length==4) { | |
87 | + using (var reader = new StreamReader(Util.ExtractData(url), Encoding.Default)) | |
88 | + { | |
89 | + string line; | |
90 | + while ((line = reader.ReadLine()) != null) | |
91 | + { | |
92 | + string[] t = line.Split(','); | |
93 | + //例 0 1 2 3 4 5 6 7, 8, 9 | |
94 | + //2005/5/20,1001,11,1001 日経平均,11104,11110,11034,11037,1257840000,東証1部 | |
95 | + if (t.Length != 10 || t[1].Length != 4) | |
96 | + continue; | |
92 | 97 | int code = ParseCode(t[1]); |
93 | - | |
94 | - BasicBrand br = Env.BrandCollection.FindBrand(code) as BasicBrand; | |
95 | - if(br!=null && CheckMarket(br, Util.ParseInt(t[2], 0))) { | |
96 | - | |
97 | - double vv = 1, pv = 10; // 株価は10倍で記録 | |
98 | - //倍率調整 | |
99 | - if(IsDomesticIndex(code)) { | |
100 | - vv = 0.001; //DreamVisorのものにあわせる格好で。1000株単位かな | |
101 | - pv = 100; | |
98 | + if (!(Env.BrandCollection.FindBrand(code) is BasicBrand)) | |
99 | + continue; | |
100 | + try | |
101 | + { | |
102 | + var vv = IsDomesticIndex(code) ? 0.001 : 1; | |
103 | + var pv = IsDomesticIndex(code) ? 100 : 10; // 指数は100倍、株価は10倍で記録。 | |
104 | + var td = new NewDailyData | |
105 | + { | |
106 | + volume = (int)(double.Parse(t[8]) * vv) | |
107 | + }; | |
108 | + // 複数市場に上場している銘柄には複数のエントリがある。出来高の多いほうをとる。 | |
109 | + if (!result.TryGetValue(code, out var existing) || existing.volume < td.volume) | |
110 | + { | |
111 | + result[code] = td; | |
112 | + td.open = (int)(double.Parse(t[4]) * pv); | |
113 | + td.high = (int)(double.Parse(t[5]) * pv); | |
114 | + td.low = (int)(double.Parse(t[6]) * pv); | |
115 | + td.close = (int)(double.Parse(t[7]) * pv); | |
116 | + td.volume = (int)(double.Parse(t[8]) * vv); | |
102 | 117 | } |
103 | - if(code==(int)BuiltInIndex.TOPIX_F) { //TOPIX先物は整数単位で記録されている | |
104 | - pv = 10; | |
105 | - } | |
106 | - | |
107 | - NewDailyData td = new NewDailyData(); | |
108 | - try { | |
109 | - td.volume = (int)(Double.Parse(t[8]) * vv); | |
110 | - NewDailyData existing = (NewDailyData)result[code]; | |
111 | - //Debug.WriteLine(line); | |
112 | - td.open = (int)(Double.Parse(t[4]) * pv); | |
113 | - td.high = (int)(Double.Parse(t[5]) * pv); | |
114 | - td.low = (int)(Double.Parse(t[6]) * pv); | |
115 | - td.close = (int)(Double.Parse(t[7]) * pv); | |
116 | - } | |
117 | - catch (FormatException) { | |
118 | - } | |
119 | - result[code] = td; | |
118 | + } | |
119 | + catch (FormatException) | |
120 | + { | |
120 | 121 | } |
121 | 122 | } |
122 | - line = r.ReadLine(); | |
123 | 123 | } |
124 | 124 | return result; |
125 | 125 | } |
@@ -128,30 +128,6 @@ namespace Zanetti.DataSource.Specialized { | ||
128 | 128 | } |
129 | 129 | } |
130 | 130 | |
131 | - private static bool CheckMarket(BasicBrand br, int muj) { | |
132 | - MarketType mt = br.Market; | |
133 | - switch(mt) { | |
134 | - //2006/12/26のデータより、東証はすべてコード11, 大証1・2部は21, ヘラクレスは23に変更になった。旧データを読んだときでも大丈夫なように古い判定も残しておく | |
135 | - case MarketType.B: | |
136 | - return muj==11; //指数は東証一部として記録されている | |
137 | - case MarketType.T1: | |
138 | - return muj==11; | |
139 | - case MarketType.T2: | |
140 | - return muj==11 || muj==12; | |
141 | - case MarketType.O1: | |
142 | - return muj==21; | |
143 | - case MarketType.O2: | |
144 | - return muj==21 || muj==22; | |
145 | - case MarketType.M: | |
146 | - return muj==21 || muj==13; | |
147 | - case MarketType.J: | |
148 | - return muj==91; | |
149 | - case MarketType.H: | |
150 | - return muj==23 || muj==24; | |
151 | - default: | |
152 | - return false; | |
153 | - } | |
154 | - } | |
155 | 131 | private static bool IsMujinzouSupportedIndices(int code) { |
156 | 132 | return code==(int)BuiltInIndex.Nikkei225 || |
157 | 133 | code==(int)BuiltInIndex.TOPIX || |