• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

OmegaChartのソースコードの保守


Commit MetaInfo

Revisão5b7c4bb6608fd3025fc30a28da452e2149bc6404 (tree)
Hora2015-03-26 19:39:58
Autorpanacoran <panacoran@user...>
Commiterpanacoran

Mensagem de Log

Data.csのコーディングスタイルを元に戻す

Mudança Sumário

Diff

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