格式
Plain text
提交日期
2015-01-29 03:05
Publication Period
Unlimited
  1. /*
  2. * Copyright (c) Daisuke OKAJIMA All rights reserved.
  3. *
  4. * $Id$
  5. */
  6. // Copyright (c) 2014 panacoran <panacoran@users.sourceforge.jp>
  7. // This program is part of OmegaChart.
  8. // OmegaChart is licensed under the Apache License, Version 2.0.
  9. using System;
  10. using System.IO;
  11. using System.Collections;
  12. using System.Diagnostics;
  13. using System.Text;
  14. using Zanetti.Arithmetic;
  15. using Zanetti.Arithmetic.Series;
  16. using Zanetti.Indicators;
  17. namespace Zanetti.Data
  18. {
  19. //primitive indicatorをサポートするためのもの
  20. internal class DataFarmPrimitiveAccess
  21. {
  22. //delegateの引数になるためにこの形でないとだめ
  23. internal static double GetDate(TradeData tr)
  24. {
  25. return (double)tr.Farm.GetInt(tr.Offset);
  26. }
  27. internal static double GetOpen(TradeData tr)
  28. {
  29. return AdjustPrice((double)tr.Farm.GetInt(tr.Offset + DataFarm.OPEN_OFFSET), tr);
  30. }
  31. internal static double GetHigh(TradeData tr)
  32. {
  33. return AdjustPrice((double)tr.Farm.GetInt(tr.Offset + DataFarm.HIGH_OFFSET), tr);
  34. }
  35. internal static double GetLow(TradeData tr)
  36. {
  37. return AdjustPrice((double)tr.Farm.GetInt(tr.Offset + DataFarm.LOW_OFFSET), tr);
  38. }
  39. internal static double GetClose(TradeData tr)
  40. {
  41. return AdjustPrice((double)tr.Farm.GetInt(tr.Offset + DataFarm.CLOSE_OFFSET), tr);
  42. }
  43. internal static double GetVolume(TradeData tr)
  44. {
  45. //オーバーフロー対策の一時しのぎ
  46. return AdjustVolume((double)(uint)tr.Farm.GetInt(tr.Offset + DataFarm.VOLUME_OFFSET), tr);
  47. }
  48. internal static double GetCreditLong(TradeData tr)
  49. {
  50. return AdjustVolume((double)tr.Farm.GetInt(tr.Offset + DataFarm.CREDITLONG_OFFSET), tr);
  51. }
  52. internal static double GetCreditShort(TradeData tr)
  53. {
  54. return AdjustVolume((double)tr.Farm.GetInt(tr.Offset + DataFarm.CREDITSHORT_OFFSET), tr);
  55. }
  56. private static double AdjustPrice(double value, TradeData tr)
  57. {
  58. double split = Env.Preference.AdjustSplit ? tr.Farm.CalcSplitRatio(tr.Date) : 1;
  59. if (value == 0 && GetVolume(tr) == 0)
  60. { //出来高がない日は価格が0と記入されているので前日の終値で代用
  61. TradeData pr = tr.Prev;
  62. return pr == null ? 0 : GetClose(tr.Prev);
  63. }
  64. else
  65. return tr.Farm.Brand.PriceScale * value / split;
  66. }
  67. private static double AdjustVolume(double value, TradeData tr)
  68. {
  69. double split = Env.Preference.AdjustSplit ? tr.Farm.CalcSplitRatio(tr.Date) : 1;
  70. return value * split;
  71. }
  72. }
  73. internal class NewDailyData
  74. {
  75. public int open;
  76. public int high;
  77. public int low;
  78. public int close;
  79. public int volume;
  80. }
  81. internal abstract class DataFarm : IDisposable
  82. {
  83. public const int RECORD_LENGTH = 32;
  84. public const int OPEN_OFFSET = 4;
  85. public const int HIGH_OFFSET = 8;
  86. public const int LOW_OFFSET = 12;
  87. public const int CLOSE_OFFSET = 16;
  88. public const int VOLUME_OFFSET = 20;
  89. public const int CREDITSHORT_OFFSET = 24;
  90. public const int CREDITLONG_OFFSET = 28;
  91. protected bool _isEmpty; //エラーなどで利用不能なことを示すフラグ
  92. protected AbstractBrand _brand;
  93. protected byte[] _farm; //一次データ。同一のDataFarmオブジェクトを他の銘柄に使いまわすときもあるので、必要以上の長さが確保されることもある
  94. protected int _byteLength; //_farmの論理的な長さ
  95. protected TradeData[] _data; //必要に応じて生成されるTradeDataの列。一目など未来の日付のデータがあると配列の長さは_farmに対応する分より大きいこともある
  96. protected int _filledLength; //最新日付までの長さ
  97. public DataFarm()
  98. {
  99. }
  100. public abstract void LoadFor(AbstractBrand br);
  101. public AbstractBrand Brand
  102. {
  103. get
  104. {
  105. return _brand;
  106. }
  107. }
  108. public int TotalLength
  109. {
  110. get
  111. {
  112. return _data.Length;
  113. }
  114. }
  115. public int FilledLength
  116. {
  117. get
  118. {
  119. return _filledLength;
  120. }
  121. }
  122. public bool IsEmpty
  123. {
  124. get
  125. {
  126. return _isEmpty;
  127. }
  128. }
  129. public byte[] RawDataImage
  130. {
  131. get
  132. {
  133. return _farm;
  134. }
  135. }
  136. internal int GetInt(int offset)
  137. {
  138. if (offset >= _byteLength)
  139. throw new IndexOutOfRangeException();
  140. unsafe
  141. {
  142. fixed (byte* p = &_farm[0])
  143. {
  144. return *(int*)(p + offset);
  145. }
  146. }
  147. }
  148. public TradeData GetByIndex(int index)
  149. {
  150. Debug.Assert(_data != null);
  151. if (index < 0 || index >= _data.Length)
  152. throw new TradeDataOverflowException(index.ToString() + " is out of range");
  153. TradeData td = _data[index];
  154. if (td != null) return td; //cache hit
  155. td = new TradeData(this, index, index * RECORD_LENGTH);
  156. _data[index] = td;
  157. return td;
  158. }
  159. public abstract int LastDate { get; }
  160. public abstract int FirstDate { get; }
  161. public int DateToIndex(int date)
  162. {
  163. return DateToIndex(0, _filledLength, date);
  164. }
  165. private int DateToIndex(int begin, int end, int date)
  166. {
  167. //binary search
  168. if (end - begin <= 1)
  169. return begin;
  170. else
  171. {
  172. int h = (begin + end) / 2;
  173. int t = GetByIndex(h).Date;
  174. if (date < t)
  175. return DateToIndex(begin, h, date);
  176. else
  177. return DateToIndex(h, end, date);
  178. }
  179. }
  180. //分割比率の取得
  181. public double CalcSplitRatio(int date)
  182. {
  183. return _brand.CalcSplitRatio(date, this.LastDate);
  184. }
  185. public void Dispose()
  186. {
  187. _farm = null;
  188. _data = null;
  189. }
  190. internal static int GetInt(byte[] rawdata, int offset)
  191. {
  192. Debug.Assert(rawdata.Length > 0);
  193. unsafe
  194. {
  195. fixed (byte* p = &rawdata[0])
  196. {
  197. return *(int*)(p + offset);
  198. }
  199. }
  200. }
  201. internal static void SetInt(byte[] rawdata, int offset, int value)
  202. {
  203. unsafe
  204. {
  205. fixed (byte* p = &rawdata[0])
  206. {
  207. *(int*)(p + offset) = value;
  208. }
  209. }
  210. }
  211. internal static void SetUInt(byte[] rawdata, int offset, uint value)
  212. {
  213. unsafe
  214. {
  215. fixed (byte* p = &rawdata[0])
  216. {
  217. *(uint*)(p + offset) = value;
  218. }
  219. }
  220. }
  221. protected static int AdjustPrice(int raw, double ratio)
  222. {
  223. return (int)((double)raw / ratio);
  224. }
  225. protected static int AdjustVolume(int raw, double ratio)
  226. {
  227. return (int)((double)raw * ratio);
  228. }
  229. }
  230. internal class DailyDataFarm : DataFarm
  231. {
  232. protected int _extraDataOffset; //1日単位でデータの追加をしたときのために
  233. public DailyDataFarm()
  234. : base()
  235. {
  236. }
  237. public override void LoadFor(AbstractBrand br)
  238. {
  239. _brand = br;
  240. Construct(Util.GetDailyDataFileName(br.Code), 0);
  241. }
  242. public void LoadFor(AbstractBrand br, int extra_dates)
  243. {
  244. _brand = br;
  245. Construct(Util.GetDailyDataFileName(br.Code), extra_dates);
  246. }
  247. private void Construct(string filename, int extra_dates)
  248. {
  249. _isEmpty = true;
  250. #if DOJIMA
  251. Dojima.DojimaUtil.HalfDailyDataFarmCache.Clear(_brand);
  252. #endif
  253. if (File.Exists(filename))
  254. {
  255. int length = (int)new FileInfo(filename).Length;
  256. if (length == 0) return;
  257. if (_farm == null || _farm.Length < length + extra_dates * RECORD_LENGTH)
  258. _farm = new byte[length + extra_dates * RECORD_LENGTH];
  259. int future_length = Env.CurrentIndicators.GetAddedFutureLength(ChartFormat.Daily);
  260. _filledLength = length / RECORD_LENGTH;
  261. _data = new TradeData[_filledLength + future_length];
  262. _byteLength = length;
  263. _extraDataOffset = 0;
  264. _isEmpty = false;
  265. FileStream s = null;
  266. try
  267. {
  268. s = new FileStream(filename, FileMode.Open);
  269. s.Read(_farm, 0, length);
  270. }
  271. finally
  272. {
  273. if (s != null) s.Close();
  274. }
  275. // 個別銘柄の株価データの先頭にある出来高0のデータを取り除く
  276. var basic = _brand as BasicBrand;
  277. if (basic == null || basic.Market == MarketType.B || basic.Market == MarketType.Custom)
  278. return;
  279. var idx = 0;
  280. for (var i = 0; i < _filledLength; i++)
  281. {
  282. unsafe
  283. {
  284. var head = i * RECORD_LENGTH;
  285. fixed (byte* p = &_farm[0])
  286. {
  287. if (*(int*)(p + head + VOLUME_OFFSET) == 0)
  288. idx += RECORD_LENGTH;
  289. else
  290. break;
  291. }
  292. }
  293. }
  294. if (idx == 0)
  295. return;
  296. _byteLength -= idx;
  297. _filledLength = _byteLength / RECORD_LENGTH;
  298. for (var i = 0; i < _byteLength; i++)
  299. _farm[i] = _farm[i + idx];
  300. }
  301. }
  302. public void Save(string filename)
  303. {
  304. if (_farm != null)
  305. { //エラーハンドリングできていない
  306. FileStream s = new FileStream(filename, FileMode.Create);
  307. s.Write(_farm, 0, _byteLength + _extraDataOffset);
  308. s.Close();
  309. }
  310. }
  311. internal void WriteExtraData(int record_offset, int value)
  312. {
  313. unsafe
  314. {
  315. fixed (byte* p = &_farm[0])
  316. {
  317. *(int*)(p + _byteLength + _extraDataOffset + record_offset) = value;
  318. }
  319. }
  320. }
  321. internal void ProgressExtraDataAddress()
  322. {
  323. _extraDataOffset += RECORD_LENGTH;
  324. Debug.Assert(_extraDataOffset <= _farm.Length);
  325. }
  326. //連続的に複数の日付を更新することもできるが、増加方向であることが必須
  327. internal void UpdateDataFarm(int date, NewDailyData td)
  328. {
  329. int ld;
  330. if (this.IsEmpty)
  331. {
  332. //とりあえず1日書き込める分だけ初期化
  333. if (_farm == null)
  334. {
  335. _farm = new byte[RECORD_LENGTH * 200]; //この上限はどこかで取得すべきだが
  336. _filledLength = 0;
  337. _data = null;
  338. _byteLength = 0;
  339. _extraDataOffset = 0;
  340. }
  341. ld = 0;
  342. }
  343. else
  344. ld = this.LastDate;
  345. int offset;
  346. if (ld < date)
  347. {
  348. offset = _byteLength + _extraDataOffset; //emptyのときは常にこれ
  349. _extraDataOffset += RECORD_LENGTH;
  350. }
  351. else
  352. {
  353. offset = _byteLength - RECORD_LENGTH;
  354. do
  355. {
  356. int t = GetInt(offset);
  357. if (t == date)
  358. break;
  359. else if (t < date)
  360. {
  361. offset += RECORD_LENGTH;
  362. break;
  363. }
  364. else
  365. offset -= RECORD_LENGTH;
  366. } while (true);
  367. }
  368. unsafe
  369. {
  370. fixed (byte* p = &_farm[0])
  371. {
  372. byte* a = p + offset;
  373. *(int*)(a + 0) = date;
  374. *(int*)(a + 4) = td.open;
  375. *(int*)(a + 8) = td.high;
  376. *(int*)(a + 12) = td.low;
  377. *(int*)(a + 16) = td.close;
  378. *(int*)(a + 20) = td.volume;
  379. }
  380. }
  381. }
  382. //次の2つはTradeDataを作らないようにしている、注意
  383. public override int LastDate
  384. {
  385. get
  386. {
  387. return GetInt(_byteLength - RECORD_LENGTH);
  388. }
  389. }
  390. public override int FirstDate
  391. {
  392. get
  393. {
  394. return GetInt(0);
  395. }
  396. }
  397. }
  398. internal class WeeklyDataFarm : DataFarm
  399. {
  400. private int _firstDate;
  401. private int _lastDate;
  402. public WeeklyDataFarm()
  403. : base()
  404. {
  405. }
  406. public override void LoadFor(AbstractBrand br)
  407. {
  408. _brand = br;
  409. Construct(Util.GetDailyDataFileName(br.Code));
  410. }
  411. private void Construct(string filename)
  412. {
  413. _isEmpty = true;
  414. if (File.Exists(filename))
  415. {
  416. int length = (int)new FileInfo(filename).Length;
  417. if (length > 0)
  418. {
  419. //まずは日足を読む
  420. byte[] daily = new byte[length];
  421. FileStream s = null;
  422. try
  423. {
  424. s = new FileStream(filename, FileMode.Open);
  425. s.Read(daily, 0, length);
  426. }
  427. finally
  428. {
  429. if (s != null) s.Close();
  430. }
  431. _isEmpty = false;
  432. _firstDate = GetInt(daily, 0);
  433. _lastDate = GetInt(daily, daily.Length - RECORD_LENGTH);
  434. var daily_begin = Util.IntToDate(GetInt(daily, 0));
  435. var weekly_begin = daily_begin.AddDays(-(int)daily_begin.DayOfWeek);
  436. var daily_end = Util.IntToDate(GetInt(daily, daily.Length - RECORD_LENGTH));
  437. var weekly_end = daily_end.AddDays(-(int)daily_end.DayOfWeek);
  438. _filledLength = (int)(weekly_end - weekly_begin).TotalDays / 7 + 1;
  439. _data = new TradeData[_filledLength + Env.CurrentIndicators.GetAddedFutureLength(ChartFormat.Weekly)];
  440. //byte[]部分のデータ読み
  441. _farm = new byte[_data.Length * RECORD_LENGTH];
  442. _byteLength = _farm.Length;
  443. int offset = 0;
  444. var weekly = weekly_begin;
  445. for (int i = 0; i < _filledLength; i++, weekly = weekly.AddDays(7))
  446. {
  447. offset = FillWeeklyData(i * RECORD_LENGTH, daily, offset, Util.DateToInt(weekly));
  448. if (offset >= daily.Length) break;
  449. }
  450. }
  451. }
  452. }
  453. private int FillWeeklyData(int farmoffset, byte[] daily, int offset, int firstdate)
  454. {
  455. int enddate = Util.DateToInt(Util.IntToDate(firstdate).AddDays(7));
  456. int vol = 0, high = Int32.MinValue, low = Int32.MaxValue;
  457. int open = 0, close = 0, cre_long = 0, cre_short = 0;
  458. int today = GetInt(daily, offset);
  459. bool is_index = _brand.IsBuiltIn;
  460. // base_splitを得るのに最初の取引日である 'today' を使うのは誤り。
  461. // 下の、SetInt(_farm, farmoffset, wi.FirstDate);
  462. // で、後に式を評価する際に用いられる基準日として日曜基準で 'wi.FirstDate' を使っているのだから、
  463. // ここでもこの値を使うべき。 2005/3/15 T. SARUKI
  464. //
  465. double base_split = this.CalcSplitRatio(firstdate); //分割を考慮する場合は期間内の調整が要る
  466. while (offset <= daily.Length - RECORD_LENGTH && today < enddate)
  467. {
  468. //if(!is_index && today>20031201) Debugger.Break();
  469. double split = Env.Preference.AdjustSplit ? this.CalcSplitRatio(today) / base_split : 1;
  470. int v = AdjustVolume(GetInt(daily, offset + VOLUME_OFFSET), split);
  471. if (is_index || v != 0)
  472. { //非indexで出来高0の日は集計しない
  473. if (open == 0) open = AdjustPrice(GetInt(daily, offset + OPEN_OFFSET), split);
  474. close = AdjustPrice(GetInt(daily, offset + CLOSE_OFFSET), split);
  475. high = Math.Max(high, AdjustPrice(GetInt(daily, offset + HIGH_OFFSET), split));
  476. low = Math.Min(low, AdjustPrice(GetInt(daily, offset + LOW_OFFSET), split));
  477. cre_long = AdjustVolume(GetInt(daily, offset + CREDITLONG_OFFSET), split);
  478. cre_short = AdjustVolume(GetInt(daily, offset + CREDITSHORT_OFFSET), split);
  479. vol += v;
  480. }
  481. offset += RECORD_LENGTH;
  482. if (offset < daily.Length) today = GetInt(daily, offset);
  483. }
  484. SetInt(_farm, farmoffset, firstdate);
  485. SetInt(_farm, farmoffset + OPEN_OFFSET, open);
  486. SetInt(_farm, farmoffset + HIGH_OFFSET, high);
  487. SetInt(_farm, farmoffset + LOW_OFFSET, low);
  488. SetInt(_farm, farmoffset + CLOSE_OFFSET, close);
  489. SetInt(_farm, farmoffset + VOLUME_OFFSET, vol);
  490. SetInt(_farm, farmoffset + CREDITLONG_OFFSET, cre_long);
  491. SetInt(_farm, farmoffset + CREDITSHORT_OFFSET, cre_short);
  492. return offset;
  493. }
  494. public override int LastDate
  495. {
  496. get
  497. {
  498. return _lastDate;
  499. }
  500. }
  501. public override int FirstDate
  502. {
  503. get
  504. {
  505. return _firstDate;
  506. }
  507. }
  508. }
  509. internal class MonthlyDataFarm : DataFarm
  510. {
  511. private int _firstDate;
  512. private int _lastDate;
  513. public MonthlyDataFarm()
  514. : base()
  515. {
  516. }
  517. public override void LoadFor(AbstractBrand br)
  518. {
  519. _brand = br;
  520. Construct(Util.GetDailyDataFileName(br.Code));
  521. }
  522. private void Construct(string filename)
  523. {
  524. _isEmpty = true;
  525. if (File.Exists(filename))
  526. {
  527. int length = (int)new FileInfo(filename).Length;
  528. if (length > 0)
  529. {
  530. //まずは日足を読む
  531. byte[] daily = new byte[length];
  532. _isEmpty = false;
  533. FileStream s = null;
  534. try
  535. {
  536. s = new FileStream(filename, FileMode.Open);
  537. s.Read(daily, 0, length);
  538. }
  539. finally
  540. {
  541. if (s != null) s.Close();
  542. }
  543. _firstDate = GetInt(daily, 0);
  544. _lastDate = GetInt(daily, daily.Length - RECORD_LENGTH);
  545. DateTime monthly_begin = new DateTime(_firstDate / 10000, (_firstDate % 10000) / 100, (_firstDate % 100));
  546. DateTime monthly_end = new DateTime(_lastDate / 10000, (_lastDate % 10000) / 100, (_lastDate % 100));
  547. _filledLength = (monthly_end.Year - monthly_begin.Year) * 12 + monthly_end.Month + 1 - monthly_begin.Month;
  548. _data = new TradeData[_filledLength + Env.CurrentIndicators.GetAddedFutureLength(ChartFormat.Monthly)];
  549. // 以下WeeklyIndexとかぶって冗長
  550. //byte[]部分のデータ読み
  551. _farm = new byte[_data.Length * RECORD_LENGTH];
  552. _byteLength = _farm.Length;
  553. DateTime yearmonth = monthly_begin;
  554. int offset = 0;
  555. for (int i = 0; i < _filledLength; i++)
  556. {
  557. offset = FillMonthlyData(i * RECORD_LENGTH, daily, offset, yearmonth);
  558. if (offset >= daily.Length) break;
  559. yearmonth = yearmonth.AddMonths(1);
  560. }
  561. }
  562. }
  563. }
  564. // このメソッドもWeeklyIndexのFillWeeklyDataとかぶってかなり冗長
  565. private int FillMonthlyData(int farmoffset, byte[] daily, int offset, DateTime yearmonth)
  566. {
  567. DateTime endmonth = yearmonth.AddMonths(1);
  568. int enddate = endmonth.Year * 10000 + endmonth.Month * 100 + 1;
  569. int vol = 0, high = Int32.MinValue, low = Int32.MaxValue;
  570. int open = 0, close = 0, cre_long = 0, cre_short = 0;
  571. int today = GetInt(daily, offset);
  572. bool is_index = _brand.IsBuiltIn;
  573. // base_splitを得るのに最初の取引日である 'today' を使うのは誤り。
  574. // 下の、SetInt(_farm, farmoffset, yearmonth.Year * 10000 + yearmonth.Month * 100 + 1);
  575. // で、後に式を評価する際に用いられる基準日として月の初日である 'yearmonth.Year * 10000 + yearmonth.Month * 100 + 1' を使っているのだから、
  576. // ここでもこの値を使うべき。 2005/3/15 T. SARUKI
  577. //
  578. double base_split = this.CalcSplitRatio(Util.DateToInt(yearmonth.Year, yearmonth.Month, 1));
  579. while (offset <= daily.Length - RECORD_LENGTH && today < enddate)
  580. {
  581. double split = Env.Preference.AdjustSplit ? this.CalcSplitRatio(today) / base_split : 1;
  582. int v = AdjustVolume(GetInt(daily, offset + VOLUME_OFFSET), split);
  583. if (is_index || v != 0)
  584. { //非indexで出来高0の日は集計しない
  585. if (open == 0) open = AdjustPrice(GetInt(daily, offset + OPEN_OFFSET), split);
  586. close = AdjustPrice(GetInt(daily, offset + CLOSE_OFFSET), split);
  587. high = Math.Max(high, AdjustPrice(GetInt(daily, offset + HIGH_OFFSET), split));
  588. low = Math.Min(low, AdjustPrice(GetInt(daily, offset + LOW_OFFSET), split));
  589. cre_long = AdjustVolume(GetInt(daily, offset + CREDITLONG_OFFSET), split);
  590. cre_short = AdjustVolume(GetInt(daily, offset + CREDITSHORT_OFFSET), split);
  591. vol += v;
  592. }
  593. offset += RECORD_LENGTH;
  594. if (offset < daily.Length) today = GetInt(daily, offset);
  595. }
  596. SetInt(_farm, farmoffset, yearmonth.Year * 10000 + yearmonth.Month * 100 + 1);
  597. SetInt(_farm, farmoffset + OPEN_OFFSET, open);
  598. SetInt(_farm, farmoffset + HIGH_OFFSET, high);
  599. SetInt(_farm, farmoffset + LOW_OFFSET, low);
  600. SetInt(_farm, farmoffset + CLOSE_OFFSET, close);
  601. SetInt(_farm, farmoffset + VOLUME_OFFSET, vol);
  602. SetInt(_farm, farmoffset + CREDITLONG_OFFSET, cre_long);
  603. SetInt(_farm, farmoffset + CREDITSHORT_OFFSET, cre_short);
  604. return offset;
  605. }
  606. public override int LastDate
  607. {
  608. get
  609. {
  610. return _lastDate;
  611. }
  612. }
  613. public override int FirstDate
  614. {
  615. get
  616. {
  617. return _firstDate;
  618. }
  619. }
  620. }
  621. internal class YearlyDataFarm : DataFarm
  622. {
  623. private int _firstDate;
  624. private int _lastDate;
  625. public YearlyDataFarm()
  626. : base()
  627. {
  628. }
  629. public override void LoadFor(AbstractBrand br)
  630. {
  631. _brand = br;
  632. Construct(Util.GetDailyDataFileName(br.Code));
  633. }
  634. private void Construct(string filename)
  635. {
  636. _isEmpty = true;
  637. if (File.Exists(filename))
  638. {
  639. int length = (int)new FileInfo(filename).Length;
  640. if (length > 0)
  641. {
  642. //まずは日足を読む
  643. byte[] daily = new byte[length];
  644. _isEmpty = false;
  645. FileStream s = null;
  646. try
  647. {
  648. s = new FileStream(filename, FileMode.Open);
  649. s.Read(daily, 0, length);
  650. }
  651. finally
  652. {
  653. if (s != null) s.Close();
  654. }
  655. _firstDate = GetInt(daily, 0);
  656. _lastDate = GetInt(daily, daily.Length - RECORD_LENGTH);
  657. DateTime yearly_begin = new DateTime(_firstDate / 10000, (_firstDate % 10000) / 100, (_firstDate % 100));
  658. DateTime yearly_end = new DateTime(_lastDate / 10000, (_lastDate % 10000) / 100, (_lastDate % 100));
  659. _filledLength = yearly_end.Year - yearly_begin.Year + 1;
  660. _data = new TradeData[_filledLength + Env.CurrentIndicators.GetAddedFutureLength(ChartFormat.Yearly)];
  661. // 以下WeeklyIndexとかぶって冗長
  662. //byte[]部分のデータ読み
  663. _farm = new byte[_data.Length * RECORD_LENGTH];
  664. _byteLength = _farm.Length;
  665. DateTime yearmonth = yearly_begin;
  666. int offset = 0;
  667. for (int i = 0; i < _filledLength; i++)
  668. {
  669. offset = FillYearlyData(i * RECORD_LENGTH, daily, offset, yearmonth);
  670. if (offset >= daily.Length) break;
  671. yearmonth = yearmonth.AddYears(1);
  672. }
  673. }
  674. }
  675. }
  676. // このメソッドもWeeklyIndexのFillWeeklyDataとかぶってかなり冗長
  677. private int FillYearlyData(int farmoffset, byte[] daily, int offset, DateTime yearmonth)
  678. {
  679. DateTime endyear = yearmonth.AddYears(1);
  680. int enddate = endyear.Year * 10000 + 101;
  681. int high = Int32.MinValue, low = Int32.MaxValue;
  682. int open = 0, close = 0, cre_long = 0, cre_short = 0;
  683. uint vol = 0;
  684. int today = GetInt(daily, offset);
  685. bool is_index = _brand.IsBuiltIn;
  686. // base_splitを得るのに最初の取引日である 'today' を使うのは誤り。
  687. // 下の、SetInt(_farm, farmoffset, yearmonth.Year * 10000 + yearmonth.Month * 100 + 1);
  688. // で、後に式を評価する際に用いられる基準日として月の初日である 'yearmonth.Year * 10000 + yearmonth.Month * 100 + 1' を使っているのだから、
  689. // ここでもこの値を使うべき。 2005/3/15 T. SARUKI
  690. //
  691. double base_split = this.CalcSplitRatio(Util.DateToInt(yearmonth.Year, 1, 1));
  692. while (offset <= daily.Length - RECORD_LENGTH && today < enddate)
  693. {
  694. double split = Env.Preference.AdjustSplit ? this.CalcSplitRatio(today) / base_split : 1;
  695. int v = AdjustVolume(GetInt(daily, offset + VOLUME_OFFSET), split);
  696. if (is_index || v != 0)
  697. { //非indexで出来高0の日は集計しない
  698. if (open == 0) open = AdjustPrice(GetInt(daily, offset + OPEN_OFFSET), split);
  699. close = AdjustPrice(GetInt(daily, offset + CLOSE_OFFSET), split);
  700. high = Math.Max(high, AdjustPrice(GetInt(daily, offset + HIGH_OFFSET), split));
  701. low = Math.Min(low, AdjustPrice(GetInt(daily, offset + LOW_OFFSET), split));
  702. cre_long = AdjustVolume(GetInt(daily, offset + CREDITLONG_OFFSET), split);
  703. cre_short = AdjustVolume(GetInt(daily, offset + CREDITSHORT_OFFSET), split);
  704. vol += (uint)(v / 10);
  705. }
  706. offset += RECORD_LENGTH;
  707. if (offset < daily.Length) today = GetInt(daily, offset);
  708. }
  709. SetInt(_farm, farmoffset, yearmonth.Year * 10000 + 101);
  710. SetInt(_farm, farmoffset + OPEN_OFFSET, open);
  711. SetInt(_farm, farmoffset + HIGH_OFFSET, high);
  712. SetInt(_farm, farmoffset + LOW_OFFSET, low);
  713. SetInt(_farm, farmoffset + CLOSE_OFFSET, close);
  714. SetUInt(_farm, farmoffset + VOLUME_OFFSET, vol);
  715. SetInt(_farm, farmoffset + CREDITLONG_OFFSET, cre_long);
  716. SetInt(_farm, farmoffset + CREDITSHORT_OFFSET, cre_short);
  717. return offset;
  718. }
  719. public override int LastDate
  720. {
  721. get
  722. {
  723. return _lastDate;
  724. }
  725. }
  726. public override int FirstDate
  727. {
  728. get
  729. {
  730. return _firstDate;
  731. }
  732. }
  733. }
  734. //他の銘柄から導出される銘柄
  735. internal class DerivedDataFarm : DataFarm
  736. {
  737. private int _firstDate;
  738. private int _lastDate;
  739. private DerivedBrand _derivedBrand;
  740. private ChartFormat _chartFormat;
  741. public DerivedDataFarm(DerivedBrand br, ChartFormat fmt)
  742. : base()
  743. {
  744. _derivedBrand = br;
  745. _chartFormat = fmt;
  746. }
  747. public override void LoadFor(AbstractBrand br)
  748. {
  749. Debug.Assert(br is DerivedBrand);
  750. _brand = br;
  751. _derivedBrand = (DerivedBrand)br;
  752. Construct(_derivedBrand);
  753. }
  754. private void Construct(DerivedBrand br)
  755. {
  756. DataFarm[] fs = new DataFarm[br.Dependencies.Length];
  757. int len = Int32.MaxValue;
  758. int shortest_farm_index = 0;
  759. for (int i = 0; i < fs.Length; i++)
  760. {
  761. DataFarm f = Env.BrandCollection.ReserveFarm(br.Dependencies[i], _chartFormat);
  762. if (f.IsEmpty)
  763. {
  764. _isEmpty = true;
  765. return; //一つでも利用不可があればダメ
  766. }
  767. fs[i] = f;
  768. if (f.FilledLength < len)
  769. {
  770. shortest_farm_index = i;
  771. len = f.FilledLength;
  772. }
  773. }
  774. DataFarm shortest_farm = fs[shortest_farm_index];
  775. if (_farm == null || _farm.Length < len * RECORD_LENGTH) _farm = new byte[len * RECORD_LENGTH];
  776. _byteLength = len * RECORD_LENGTH;
  777. _data = new TradeData[len + Env.CurrentIndicators.GetAddedFutureLength(_chartFormat)];
  778. _filledLength = len;
  779. _isEmpty = false;
  780. _firstDate = shortest_farm.GetByIndex(0).Date;
  781. _lastDate = shortest_farm.GetByIndex(shortest_farm.FilledLength - 1).Date;
  782. //データの構築 本当はここも遅延評価すると効率的だが
  783. FillData(len, shortest_farm_index, br, fs);
  784. }
  785. private void FillData(int len, int shortest_farm_index, DerivedBrand br, DataFarm[] deps)
  786. {
  787. int[] indexmap = new int[deps.Length];
  788. EvalResult[][] args = new EvalResult[4][];
  789. for (int i = 0; i < 4; i++)
  790. {
  791. args[i] = new EvalResult[deps.Length];
  792. for (int j = 0; j < deps.Length; j++) args[i][j] = new EvalResult(0);
  793. }
  794. Indicator[] inds = new Indicator[] {
  795. Env.CurrentIndicators.GetPrimitive(PrimitiveIndicator.Open),
  796. Env.CurrentIndicators.GetPrimitive(PrimitiveIndicator.High),
  797. Env.CurrentIndicators.GetPrimitive(PrimitiveIndicator.Low),
  798. Env.CurrentIndicators.GetPrimitive(PrimitiveIndicator.Close)};
  799. TradeData[] tds = new TradeData[deps.Length];
  800. Evaluator ev = new Evaluator(br.Name);
  801. for (int i = 0; i < len; i++)
  802. {
  803. ev.BaseIndex = i;
  804. //日付の決定
  805. int date = deps[shortest_farm_index].GetByIndex(i).Date;
  806. int farmoffset = i * RECORD_LENGTH;
  807. for (int j = 0; j < deps.Length; j++)
  808. {
  809. int candidate = indexmap[j] + 1; //多くの場合日付とindexは一致しているので、DateToIndexの実行回数を減らすためindexmapを用意
  810. TradeData td = candidate < deps[j].TotalLength ? deps[j].GetByIndex(candidate) : null;
  811. if (td == null || td.Date != date)
  812. {
  813. candidate = deps[j].DateToIndex(date);
  814. td = deps[j].GetByIndex(candidate);
  815. }
  816. indexmap[j] = candidate;
  817. for (int k = 0; k < inds.Length; k++)
  818. args[k][j].DoubleVal = td.GetValue(inds[k]);
  819. }
  820. //日付
  821. SetInt(_farm, farmoffset, date);
  822. //4本値の計算
  823. Expression expr = br.Expression;
  824. ev.Args = args[0];
  825. int open = (int)((EvalResult)expr.Apply(ev)).DoubleVal;
  826. SetInt(_farm, farmoffset + OPEN_OFFSET, open);
  827. ev.Args = args[3];
  828. int close = (int)((EvalResult)expr.Apply(ev)).DoubleVal;
  829. SetInt(_farm, farmoffset + CLOSE_OFFSET, close);
  830. ev.Args = args[1];
  831. int v1 = (int)((EvalResult)expr.Apply(ev)).DoubleVal;
  832. ev.Args = args[2];
  833. int v2 = (int)((EvalResult)expr.Apply(ev)).DoubleVal;
  834. //計算式により、それぞれの高値・安値で計算したものが結果としてどうなるかは変わってしまう
  835. SetInt(_farm, farmoffset + HIGH_OFFSET, Math.Max(Math.Max(open, close), Math.Max(v1, v2)));
  836. SetInt(_farm, farmoffset + LOW_OFFSET, Math.Min(Math.Min(open, close), Math.Min(v1, v2)));
  837. }
  838. }
  839. public override int LastDate
  840. {
  841. get
  842. {
  843. return _lastDate;
  844. }
  845. }
  846. public override int FirstDate
  847. {
  848. get
  849. {
  850. return _firstDate;
  851. }
  852. }
  853. }
  854. //internal delegate double Calculate(Indicator indicator, TradeData data);
  855. //節の種類
  856. internal enum Fushi
  857. {
  858. Unknown,
  859. None,
  860. High,
  861. Low
  862. }
  863. /// 日足・週足・月足などの1件のレコード
  864. internal class TradeData
  865. {
  866. private DataFarm _farm;
  867. private int _index;
  868. private int _offset;
  869. private double[] _data;
  870. private Fushi _fushi;
  871. public TradeData(DataFarm farm, int index, int offset)
  872. {
  873. _farm = farm;
  874. _index = index;
  875. _offset = offset;
  876. _data = new double[Env.CurrentIndicators.IndicatorCount];
  877. _fushi = Fushi.Unknown;
  878. for (int i = 0; i < _data.Length; i++)
  879. _data[i] = Double.NaN;
  880. }
  881. public DataFarm Farm
  882. {
  883. get
  884. {
  885. return _farm;
  886. }
  887. }
  888. public int Index
  889. {
  890. get
  891. {
  892. return _index;
  893. }
  894. }
  895. public int Offset
  896. {
  897. get
  898. {
  899. return _offset;
  900. }
  901. }
  902. public TradeData Prev
  903. {
  904. get
  905. {
  906. return _index > 0 ? _farm.GetByIndex(_index - 1) : null;
  907. }
  908. }
  909. public TradeData Next
  910. {
  911. get
  912. {
  913. return _index < _farm.TotalLength - 1 ? _farm.GetByIndex(_index + 1) : null;
  914. }
  915. }
  916. public bool IsFuture
  917. {
  918. get
  919. {
  920. return _index >= _farm.FilledLength;
  921. }
  922. }
  923. public bool CoversDate(int date)
  924. {
  925. if (date == this.Date)
  926. return true;
  927. else
  928. {
  929. int c = this.Date;
  930. if (c > date)
  931. return false;
  932. else
  933. {
  934. TradeData next = this.Next;
  935. return next != null && date < next.Date;
  936. }
  937. }
  938. }
  939. public double GetValue(Indicator indicator)
  940. {
  941. double t = _data[indicator.LaneID];
  942. //overflowによる演算不可はPositiveInfinityであらわす
  943. if (Double.IsPositiveInfinity(t)) return Double.NaN;
  944. if (!Double.IsNaN(t)) return t; //キャッシュにヒット
  945. try
  946. {
  947. if (indicator.CheckRange(this))
  948. {
  949. t = indicator.Calculate(this);
  950. _data[indicator.LaneID] = t;
  951. }
  952. else
  953. t = Double.NaN;
  954. return t;
  955. }
  956. catch (TradeDataOverflowException)
  957. {
  958. //Debug.WriteLine("Out of range!");
  959. _data[indicator.LaneID] = Double.PositiveInfinity;
  960. return Double.NaN;
  961. }
  962. }
  963. public int Date
  964. {
  965. get
  966. {
  967. return (int)GetValue(Env.CurrentIndicators.GetPrimitive(PrimitiveIndicator.Date));
  968. }
  969. }
  970. public double Open
  971. {
  972. get
  973. {
  974. return GetValue(Env.CurrentIndicators.GetPrimitive(PrimitiveIndicator.Open));
  975. }
  976. }
  977. public double High
  978. {
  979. get
  980. {
  981. return GetValue(Env.CurrentIndicators.GetPrimitive(PrimitiveIndicator.High));
  982. }
  983. }
  984. public double Low
  985. {
  986. get
  987. {
  988. return GetValue(Env.CurrentIndicators.GetPrimitive(PrimitiveIndicator.Low));
  989. }
  990. }
  991. public double Close
  992. {
  993. get
  994. {
  995. return GetValue(Env.CurrentIndicators.GetPrimitive(PrimitiveIndicator.Close));
  996. }
  997. }
  998. public double Volume
  999. {
  1000. get
  1001. {
  1002. return GetValue(Env.CurrentIndicators.GetPrimitive(PrimitiveIndicator.Volume));
  1003. }
  1004. }
  1005. public double CreditLong
  1006. {
  1007. get
  1008. {
  1009. return GetValue(Env.CurrentIndicators.GetPrimitive(PrimitiveIndicator.CreditLong));
  1010. }
  1011. }
  1012. public double CreditShort
  1013. {
  1014. get
  1015. {
  1016. return GetValue(Env.CurrentIndicators.GetPrimitive(PrimitiveIndicator.CreditShort));
  1017. }
  1018. }
  1019. //節の計算
  1020. public Fushi Fushi
  1021. {
  1022. get
  1023. {
  1024. if (_fushi != Fushi.Unknown) return _fushi;
  1025. double h1 = Double.MinValue;
  1026. double l1 = Double.MaxValue;
  1027. double h2 = Double.MinValue;
  1028. double l2 = Double.MaxValue;
  1029. int fushi = Env.Preference.FushiRange;
  1030. //あまり端に表示しても仕方ない
  1031. if (_index < fushi || _index > _farm.FilledLength - fushi)
  1032. {
  1033. _fushi = Fushi.None;
  1034. return _fushi;
  1035. }
  1036. for (int i = _index - fushi; i < _index; i++)
  1037. {
  1038. h1 = Math.Max(h1, _farm.GetByIndex(i).High);
  1039. l1 = Math.Min(l1, _farm.GetByIndex(i).Low);
  1040. }
  1041. for (int i = _index + 1; i < _index + fushi; i++)
  1042. {
  1043. h2 = Math.Max(h2, _farm.GetByIndex(i).High);
  1044. l2 = Math.Min(l2, _farm.GetByIndex(i).Low);
  1045. }
  1046. //過去に同値があるときは無視、未来にあるときは節
  1047. if (h1 < this.High && h2 <= this.High)
  1048. _fushi = Fushi.High;
  1049. else if (l1 > this.Low && l2 >= this.Low)
  1050. _fushi = Fushi.Low;
  1051. else
  1052. _fushi = Fushi.None;
  1053. return _fushi;
  1054. }
  1055. }
  1056. }
  1057. internal class TradeDataOverflowException : ApplicationException
  1058. {
  1059. public TradeDataOverflowException(string msg)
  1060. : base(msg)
  1061. {
  1062. }
  1063. }
  1064. internal class IndicatorTimeSeries : TimeSeries
  1065. {
  1066. protected DataFarm _farm;
  1067. protected int _begin;
  1068. protected int _end;
  1069. protected Indicator _indicator;
  1070. public IndicatorTimeSeries(DataFarm farm, Indicator ind, int begin, int end)
  1071. {
  1072. _farm = farm;
  1073. _begin = begin;
  1074. _end = end;
  1075. _indicator = ind;
  1076. }
  1077. public override int Count
  1078. {
  1079. get
  1080. {
  1081. return _end - _begin;
  1082. }
  1083. }
  1084. public int BeginIndex
  1085. {
  1086. get
  1087. {
  1088. return _begin;
  1089. }
  1090. }
  1091. public int EndIndex
  1092. {
  1093. get
  1094. {
  1095. return _end;
  1096. }
  1097. }
  1098. public override double LastValue
  1099. {
  1100. get
  1101. {
  1102. return _farm.GetByIndex(_end - 1).GetValue(_indicator);
  1103. }
  1104. }
  1105. protected class IndicatorCursor : TimeSeries.Cursor
  1106. {
  1107. private int _index;
  1108. private IndicatorTimeSeries _parent;
  1109. public IndicatorCursor(IndicatorTimeSeries parent)
  1110. {
  1111. _parent = parent;
  1112. _index = _parent._begin;
  1113. }
  1114. public override bool HasNext
  1115. {
  1116. get
  1117. {
  1118. return _index < _parent._end;
  1119. }
  1120. }
  1121. public override double Next
  1122. {
  1123. get
  1124. {
  1125. return _parent._farm.GetByIndex(_index++).GetValue(_parent._indicator);
  1126. }
  1127. }
  1128. }
  1129. public override Cursor CreateCursor()
  1130. {
  1131. return new IndicatorCursor(this);
  1132. }
  1133. }
  1134. }
下载 可打印视图

网址

Embed with JavaScript

Embed with iframe

原始文本