コピペ: OmegaChart ファイルをドロップしてデータ更新 Data.cs 追加する部分には//☆DataImporter 20190211

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

このコピペの URL

JavaScript での埋め込み

iframe での埋め込み

元のテキスト