• R/O
  • SSH
  • HTTPS

protra: 提交


Commit MetaInfo

修訂550 (tree)
時間2021-01-10 14:21:56
作者darai

Log Message

2021-01-10 darai <darai@users.sourceforge.jp>

#41025: バイナリデータ読み込み速度向上案

* Protra.Lib/Data/PriceData.cs (PriceData.GetPrices): バイナリデータ読み込み速度向上案反映。

Change Summary

差異

--- protra/trunk/ChangeLog.txt (revision 549)
+++ protra/trunk/ChangeLog.txt (revision 550)
@@ -1,3 +1,9 @@
1+2021-01-10 darai <darai@users.sourceforge.jp>
2+
3+ #41025: バイナリデータ読み込み速度向上案
4+
5+ * Protra.Lib/Data/PriceData.cs (PriceData.GetPrices): バイナリデータ読み込み速度向上案反映。
6+
17 2020-10-03 darai <darai@users.sourceforge.jp>
28
39 #40826: 東証障害による株価データダウンロードエラー
--- protra/trunk/Protra.Lib/Data/PriceData.cs (revision 549)
+++ protra/trunk/Protra.Lib/Data/PriceData.cs (revision 550)
@@ -1,4 +1,4 @@
1-// Copyright(C) 2010, 2013, 2014, 2018 panacoran <panacoran@users.sourceforge.jp>
1+// Copyright(C) 2010, 2013, 2014 panacoran <panacoran@users.sourceforge.jp>
22 //
33 // This program is part of Protra.
44 //
@@ -35,7 +35,7 @@
3535 /// <summary>
3636 /// レコードサイズ
3737 /// </summary>
38- public static readonly int RecordSize = 4 /* date */ + 4 * 4 /* prices */ + 8 /* volume */;
38+ public static readonly int RecordSize = 4 /* date */+ 4 * 4 /* prices */+ 8 /* volume */;
3939
4040 /// <summary>
4141 /// 証券コード
@@ -144,22 +144,31 @@
144144 /// <summary>
145145 /// タイムフレームを取得する。
146146 /// </summary>
147- public TimeFrame TimeFrame { get; }
147+ public TimeFrame TimeFrame { get; private set; }
148148
149149 /// <summary>
150150 /// 最初の株価データを取得する。
151151 /// </summary>
152- public Price First => _priceList.Count > 0 ? _priceList[0] : null;
152+ public Price First
153+ {
154+ get { return _priceList.Count > 0 ? _priceList[0] : null; }
155+ }
153156
154157 /// <summary>
155158 /// 最後の株価データを取得する。
156159 /// </summary>
157- public Price Last => _priceList.Count > 0 ? _priceList[_priceList.Count - 1] : null;
160+ public Price Last
161+ {
162+ get { return _priceList.Count > 0 ? _priceList[_priceList.Count - 1] : null; }
163+ }
158164
159165 /// <summary>
160166 /// リストの要素数を返す。
161167 /// </summary>
162- public int Count => _priceList.Count;
168+ public int Count
169+ {
170+ get { return _priceList.Count; }
171+ }
163172
164173 /// <summary>
165174 /// コンストラクタ
@@ -195,7 +204,10 @@
195204 /// </summary>
196205 /// <param name="index"></param>
197206 /// <returns></returns>
198- public Price this[int index] => _priceList[index];
207+ public Price this[int index]
208+ {
209+ get { return _priceList[index]; }
210+ }
199211
200212 /// <summary>
201213 /// 指定した日付を持つ株価データのインデックスを返す。
@@ -258,7 +270,6 @@
258270 var dir = Path.Combine(Global.DirPrice, code.Substring(0, 1));
259271 if (!Directory.Exists(dir))
260272 Directory.CreateDirectory(dir);
261-
262273 return Path.Combine(dir, code);
263274 }
264275
@@ -268,23 +279,20 @@
268279 /// <param name="code">証券コード</param>
269280 /// <param name="timeFrame">タイムフレーム</param>
270281 /// <param name="needLastWeek">終わっていない週足を返すか</param>
271- /// <param name="applySplit">分割を適用するか</param>
272- public static PriceList GetPrices(string code, TimeFrame timeFrame, bool needLastWeek = false,
273- bool applySplit = true)
282+ public static PriceList GetPrices(string code, TimeFrame timeFrame, bool needLastWeek = false)
274283 {
275284 var file = PricePath(code);
276285 if (!File.Exists(file))
277286 return null;
278-
279287 var prices = new List<Price>();
280288 using (var s = new FileStream(file, FileMode.Open))
281- {
282289 try
283290 {
284291 var buf = new byte[s.Length];
285292 s.Read(buf, 0, (int)s.Length);
286293 var b = new BinaryReader(new MemoryStream(buf));
287- while (true)
294+ var baseStream = b.BaseStream;
295+ while (baseStream.Position != baseStream.Length)
288296 {
289297 var p = new Price {Code = code};
290298 p.Read(b);
@@ -294,25 +302,16 @@
294302 catch (EndOfStreamException)
295303 {
296304 }
297- }
298-
299- if (applySplit)
305+ foreach (var split in GlobalEnv.BrandData[code].Split)
300306 {
301- foreach (var split in GlobalEnv.BrandData[code].Split)
302- {
303- if (split.Date > prices[prices.Count - 1].Date)
304- continue;
305-
306- foreach (var price in prices)
307- {
308- if (price.Date < split.Date)
309- price.Split(split.Ratio);
310- else
311- break;
312- }
313- }
307+ if (split.Date > prices[prices.Count - 1].Date)
308+ continue;
309+ foreach (var price in prices)
310+ if (price.Date < split.Date)
311+ price.Split(split.Ratio);
312+ else
313+ break;
314314 }
315-
316315 return timeFrame == TimeFrame.Daily
317316 ? new PriceList(prices, TimeFrame.Daily)
318317 : GenerateWeeklyPrices(prices, needLastWeek);
@@ -322,7 +321,6 @@
322321 {
323322 if (daily.Count == 0) // 空のデータファイルが存在する場合。
324323 return new PriceList(daily, TimeFrame.Weekly);
325-
326324 var weekly = new List<Price>();
327325 var code = daily[0].Code;
328326 var date = daily[0].Date;
@@ -359,19 +357,14 @@
359357 {
360358 if (d.High > high)
361359 high = d.High;
362-
363- if (low == 0 || d.Low > 0 && d.Low < low)
360+ if (low == 0 || (d.Low > 0 && d.Low < low))
364361 low = d.Low;
365-
366362 if (open == 0) // 最初に付いた値段が始値
367363 open = d.Open;
368-
369364 if (d.Close != 0)
370365 close = d.Close;
371-
372366 volume += d.Volume;
373367 }
374-
375368 prevDow = d.Date.DayOfWeek;
376369 }
377370
@@ -390,7 +383,6 @@
390383 };
391384 weekly.Add(w);
392385 }
393-
394386 return new PriceList(weekly, TimeFrame.Weekly);
395387 }
396388
@@ -403,13 +395,13 @@
403395 /// <param name="close">ファイルを閉じるか</param>
404396 public static void Add(Price price, bool close)
405397 {
406- if (!OpenFiles.TryGetValue(price.Code, out var s))
398+ FileStream s;
399+ if (!OpenFiles.TryGetValue(price.Code, out s))
407400 {
408401 var file = PricePath(price.Code);
409402 s = new FileStream(file, FileMode.OpenOrCreate);
410403 OpenFiles.Add(price.Code, s);
411404 }
412-
413405 if (s.Length >= Price.RecordSize)
414406 {
415407 s.Seek(-1 * Price.RecordSize, SeekOrigin.End);
@@ -418,12 +410,10 @@
418410 if (price.Date <= last.Date) // すでに存在する。
419411 goto Exit;
420412 }
421-
422413 price.Write(new BinaryWriter(s));
423414 Exit:
424415 if (!close)
425416 return;
426-
427417 s.Close();
428418 OpenFiles.Remove(price.Code);
429419 }
@@ -435,7 +425,6 @@
435425 {
436426 foreach (var s in OpenFiles.Values)
437427 s.Close();
438-
439428 OpenFiles.Clear();
440429 }
441430
@@ -483,10 +472,8 @@
483472 r.Read(b);
484473 if (r.Date < since)
485474 break;
486-
487475 s.Seek(-2 * Price.RecordSize, SeekOrigin.Current);
488476 }
489-
490477 s.SetLength(s.Seek(0, SeekOrigin.Current));
491478 }
492479 catch (IOException)
@@ -497,7 +484,6 @@
497484 s.Close();
498485 }
499486 }
500-
501487 MaxDate = since.AddDays(-1);
502488 }
503489
@@ -513,14 +499,12 @@
513499 foreach (var file in CollectFiles(""))
514500 {
515501 var code = Path.GetFileName(file);
516- if (string.Compare(code, start, StringComparison.Ordinal) < 0 ||
517- string.Compare(code, end, StringComparison.Ordinal) > 0)
502+ if (String.Compare(code, start, StringComparison.Ordinal) < 0 ||
503+ String.Compare(code, end, StringComparison.Ordinal) > 0)
518504 continue;
519-
520- var prices = GetPrices(code, TimeFrame.Daily, applySplit: false);
505+ var prices = GetPrices(code, TimeFrame.Daily);
521506 if (prices == null)
522507 continue;
523-
524508 if (!overwriteAll && File.Exists(file + ".csv"))
525509 {
526510 using (var dialog = new OverwriteDialog())
@@ -530,15 +514,12 @@
530514 var result = dialog.ShowDialog();
531515 if (result == DialogResult.Cancel)
532516 return false;
533-
534517 if (result == DialogResult.No)
535518 continue;
536-
537519 if (result == DialogResult.OK)
538520 overwriteAll = true;
539521 }
540522 }
541-
542523 FileStream f;
543524 Retry:
544525 try
@@ -550,26 +531,22 @@
550531 DialogResult result;
551532 using (new CenteredDialogHelper())
552533 result = MessageBox.Show(e.Message, "株価データの変換", MessageBoxButtons.AbortRetryIgnore);
553-
554534 if (result == DialogResult.Abort)
555535 return false;
556-
557536 if (result == DialogResult.Ignore)
558537 continue;
559-
560538 goto Retry;
561539 }
562-
563540 using (var txt = new StreamWriter(f, Encoding.ASCII))
564541 {
565542 foreach (var p in prices)
566- {
567- txt.WriteLine(string.Join(",", p.Date.ToString("d"), p.Open.ToString(), p.High.ToString(),
568- p.Low.ToString(), p.Close.ToString(), p.Volume.ToString()));
569- }
543+ txt.WriteLine(string.Join(",", new[]
544+ {
545+ p.Date.ToString("d"), p.Open.ToString(),
546+ p.High.ToString(), p.Low.ToString(), p.Close.ToString(), p.Volume.ToString()
547+ }));
570548 }
571549 }
572-
573550 return true;
574551 }
575552
@@ -585,10 +562,9 @@
585562 foreach (var file in CollectFiles(".csv"))
586563 {
587564 var code = Path.GetFileNameWithoutExtension(file);
588- if (string.Compare(code, start, StringComparison.Ordinal) < 0 ||
589- string.Compare(code, end, StringComparison.Ordinal) > 0)
565+ if (String.Compare(code, start, StringComparison.Ordinal) < 0 ||
566+ String.Compare(code, end, StringComparison.Ordinal) > 0)
590567 continue;
591-
592568 var prices = new List<Price>();
593569 Retry:
594570 var num = 0;
@@ -619,14 +595,10 @@
619595 {
620596 DialogResult result;
621597 using (new CenteredDialogHelper())
622- {
623598 result = MessageBox.Show(file + "の" + num + "行目に不正な値があります。" +
624599 "このファイルを無視して処理を継続しますか?", "株価データの変換", MessageBoxButtons.YesNo);
625- }
626-
627600 if (result == DialogResult.No)
628601 return false;
629-
630602 continue;
631603 }
632604 catch (IOException e)
@@ -634,16 +606,12 @@
634606 DialogResult result;
635607 using (new CenteredDialogHelper())
636608 result = MessageBox.Show(e.Message, "株価データの変換", MessageBoxButtons.AbortRetryIgnore);
637-
638609 if (result == DialogResult.Abort)
639610 return false;
640-
641611 if (result == DialogResult.Ignore)
642612 continue;
643-
644613 goto Retry;
645614 }
646-
647615 var dst = file.Substring(0, file.Length - 4);
648616 if (!overwriteAll && File.Exists(dst))
649617 {
@@ -654,25 +622,20 @@
654622 var result = dialog.ShowDialog();
655623 if (result == DialogResult.Cancel)
656624 return false;
657-
658625 if (result == DialogResult.No)
659626 continue;
660-
661627 if (result == DialogResult.OK)
662628 overwriteAll = true;
663629 }
664630 }
665-
666631 File.Delete(dst);
667632 foreach (var p in prices)
668633 Add(p, false);
669-
670634 CloseAll();
671635 var max = MaxDateByCode(code);
672636 if (max > MaxDate)
673637 MaxDate = max;
674638 }
675-
676639 return true;
677640 }
678641
@@ -679,19 +642,18 @@
679642 /// <summary>
680643 /// 指定した拡張子のファイルを株価データのディレクトリから探す。
681644 /// </summary>
682- /// <param name="extenstion">拡張子を指定する。</param>
645+ /// <param name="extention">拡張子を指定する。</param>
683646 /// <returns>ファイルのリストを返す。</returns>
684- private static IEnumerable<string> CollectFiles(string extenstion)
647+ private static IEnumerable<string> CollectFiles(string extention)
685648 {
686649 var result = new List<string>();
687650 foreach (var dir in Directory.GetDirectories(Global.DirPrice, "*"))
688- foreach (var path in Directory.GetFiles(Path.Combine(Global.DirPrice, dir), "*"))
689- {
690- var ext = Path.GetExtension(path);
691- if (string.Compare(ext, extenstion, StringComparison.InvariantCultureIgnoreCase) == 0)
692- result.Add(path);
693- }
694-
651+ foreach (var path in Directory.GetFiles(Path.Combine(Global.DirPrice, dir), "*"))
652+ {
653+ var ext = Path.GetExtension(path);
654+ if (ext != null && String.Compare(ext, extention, StringComparison.InvariantCultureIgnoreCase) == 0)
655+ result.Add(path);
656+ }
695657 return result;
696658 }
697659 }
Show on old repository browser