1 /**
2 * Copyright Mikael H�gdahl - triyana@users.sourceforge.net
3 *
4 * This source is distributed under the terms of the Q Public License version 1.0,
5 * created by Trolltech (www.trolltech.com).
6 */
7
8 #include <math.h>
9 #include "MHPrice.h"
10 #include "MHDate.h"
11
12 const double MHPrice::MIN_VALUE = -999999999999.0;
13 const double MHPrice::MAX_VALUE = 999999999999.0;
14 const double MHPrice::ZERO_VALUE = 0.000000000001;
15
16
17
18 /**
19 * Copy constructor
20 * @param const MHPrice& - Point to copy from
21 */
MHPrice(const MHPrice & x)22 MHPrice::MHPrice (const MHPrice& x) :
23 MH() {
24 aHigh = x.aHigh;
25 aLow = x.aLow;
26 aClose = x.aClose;
27 aOpen = x.aOpen;
28 aVol = x.aVol;
29 strncpy (aDate, x.aDate, 8);
30 aDate[8] = '\0';
31 }
32
33
34
35 /**
36 * Create new data point
37 * @param const char* - Date value in the form of YYYYMMDD
38 * @param double - Data point
39 */
MHPrice(const char * d,double h)40 MHPrice::MHPrice (const char* d, double h) :
41 MH() {
42 aHigh = h;
43 aLow = h;
44 aClose = h;
45 aOpen = h;
46 aVol = h;
47 strncpy (aDate, d, 8);
48 aDate[8] = '\0';
49 }
50
51
52
53 /**
54 * Create new numerical data point
55 * @param double - X point
56 * @param double - Y point
57 */
MHPrice(double h,double c)58 MHPrice::MHPrice (double h, double c) :
59 MH() {
60 aHigh = h;
61 aLow = 0.0;
62 aClose = c;
63 aOpen = 0.0;
64 aVol = 0.0;
65 aDate[0] = '\0';
66 }
67
68
69
70 /**
71 * Create new data point
72 * @param const char* - Date value in the form of YYYYMMDD
73 * @param double - Highest value in this data point
74 * @param double - Lowest value in this data point
75 * @param double - Last value in this data point
76 * @param double - Open value in this data point
77 * @param double - Volume value in this data point
78 */
MHPrice(const char * d,double h,double l,double c,double o,double v)79 MHPrice::MHPrice (const char* d, double h, double l, double c, double o, double v) :
80 MH() {
81 aHigh = h;
82 aLow = l;
83 aClose = c;
84 aOpen = o;
85 aVol = v;
86 strncpy (aDate, d, 8);
87 aDate[8] = '\0';
88 }
89
90
91
92 /**
93 * Operator =
94 * @param const MHPrice& - Right side of expression
95 */
operator =(const MHPrice & x)96 MHPrice& MHPrice::operator=(const MHPrice& x) {
97 strncpy (aDate, x.aDate, 8);
98 aDate[8] = '\0';
99 aHigh = x.aHigh;
100 aLow = x.aLow;
101 aClose = x.aClose;
102 aOpen = x.aOpen;
103 aVol = x.aVol;
104 return *this;
105 }
106
107
108
109 /**
110 * Make a vector with the ATR model (Average True Range)
111 * @param MHVector* - Vector with MHPrices
112 * @param MHVector* - The vector with converted data
113 * @param int - Number of points in range
114 */
ATR(MHVector * in,MHVector * out,int nMvg)115 void MHPrice::ATR (MHVector* in, MHVector* out, int nMvg) {
116 int nSize = in->Size();
117 double nGetr = 0;
118 double nTot = 0;
119 double nPrevC = 0;
120 double nPrevGetr = 0;
121 MHPrice* p = 0;
122
123 if (nMvg < 2 || nMvg > in->Size()) return;
124 nMvg--;
125
126 // Iterate through all data points and calc ATR data
127 for (int f = 0; f < nSize; f++) {
128 p = (MHPrice*)(*in)[f];
129
130 if (f == 0) {
131 nGetr = p->aHigh - p->aLow;
132 nTot += nGetr;
133 }
134 else {
135 double t1 = p->aHigh - p->aLow;
136 double t2 = fabs(p->aHigh - nPrevC);
137 double t3 = fabs(p->aLow - nPrevC);
138
139 if (t1 > t2 && t1 > t3) nGetr = t1;
140 else if (t2 > t1 && t2 > t3) nGetr = t2;
141 else nGetr = t3;
142
143 nTot += nGetr;
144
145 if (f == nMvg) {
146 nPrevGetr = nTot / (nMvg + 1);
147 out->Push (new MHPrice (p->aDate, nPrevGetr));
148 }
149 else if (f > nMvg) {
150 nPrevGetr = ((nPrevGetr * nMvg) + nGetr) / (nMvg + 1);
151 out->Push (new MHPrice (p->aDate, nPrevGetr));
152 }
153 }
154 nPrevC = p->aClose;
155 }
156 }
157
158
159
160 /**
161 * Adjust price and volume
162 * If volume is less than 0 then the volume is divided with the price factor
163 */
Adjust(double price,double volume)164 void MHPrice::Adjust (double price, double volume) {
165 if (price > 0.0000001) {
166 aHigh *= price;
167 aLow *= price;
168 aClose *= price;
169 aOpen *= price;
170 }
171 if (volume > 0.0000001)
172 aVol *= volume;
173 else
174 aVol /= price;
175 }
176
177
178
179 /**
180 * Make a vector with the Bollinger model
181 * @param MHVector* - Vector with MHPrices
182 * @param MHVector* - The vector with converted data
183 * @param MHVector* - The vector with converted data + 2 * std. dev.
184 * @param MHVector* - The vector with converted data - 2 * std. dev.
185 * @param int - Number of points to use in moving average
186 */
Bollinger(MHVector * in,MHVector * mvg,MHVector * upper,MHVector * lower,int nMvg)187 void MHPrice::Bollinger (MHVector* in, MHVector* mvg, MHVector* upper, MHVector* lower, int nMvg) {
188 MHVector stddev;
189 MHPrice* ps = 0;
190 MHPrice* pm = 0;
191
192 MHPrice::MovingAverage (in, mvg, nMvg);
193 MHPrice::StdDev (in, &stddev, nMvg);
194
195 // Create two new dataseries with mvg +/- standard deviations * 2
196 for (int i = 0; i < stddev.Size(); i++) {
197 ps = (MHPrice*)stddev[i];
198 pm = (MHPrice*)mvg->Get (i);
199
200 if (pm) {
201 upper->Push (new MHPrice (ps->aDate, pm->aClose + (ps->aClose) * 2));
202 lower->Push (new MHPrice (ps->aDate, pm->aClose - (ps->aClose) * 2));
203 }
204 }
205 stddev.Erase();
206 }
207
208
209
210 /**
211 * Compare two price objects or one price with a string object
212 * @param MH* - THe other object
213 * @param int - Sort type, not used
214 * @return int - 1, 0, -1
215 */
Compare(const MH * o,int type)216 int MHPrice::Compare (const MH* o, int type) {
217 if (*(((MH*)o)->Class() + 2) == 'S')
218 return compare((MHString*)o);
219 else
220 return compare((MHPrice*)o);
221 }
222
223
224
225 /**
226 * Copy points to new vector, create new points
227 * @param MHVector* - In serie
228 * @param MHVector* - Out serie
229 * @param const char* - Start date, if 0 then all data is copied
230 * @param const char* - Stop date, if 0 then all data is copied
231 */
Copy(MHVector * in,MHVector * out,const char * pStartDate,const char * pStopDate)232 void MHPrice::Copy (MHVector* in, MHVector* out, const char* pStartDate, const char* pStopDate) {
233 MHPrice* p;
234 for (int f = 0; f < in->Size(); f++) {
235 p = (MHPrice*)(*in)[f];
236 if (pStartDate == 0 || pStopDate == 0)
237 out->Push (new MHPrice (*p));
238 else if (*p >= pStartDate && *p <= pStopDate)
239 out->Push (new MHPrice (*p));
240 }
241 }
242
243
244
245 /**
246 * Copy pointers to points to new vector
247 * @param MHVector* - In serie
248 * @param MHVector* - Out serie
249 */
CopyPointers(MHVector * in,MHVector * out)250 void MHPrice::CopyPointers (MHVector* in, MHVector* out) {
251 for (int f = 0; f < in->Size(); f++)
252 out->Push ((MHPrice*)(*in)[f]);
253 }
254
255
256
257 /**
258 * Fix slave list so it's range is the same as master
259 * @param MHVector* - In serie
260 * @param MHVector* - Out serie
261 */
Cut(MHVector * in,MHVector * out)262 void MHPrice::Cut (MHVector* in, MHVector* out) {
263 MHPrice* p1 = (MHPrice*)in->First();
264 MHPrice* p2 = (MHPrice*)in->Last();
265 MHPrice* p;
266 MHVector v;
267
268 if (!p1 || !p2) return;
269
270 for (int f = 0; f < out->Size(); f++) {
271 p = (MHPrice*) (*out)[f];
272
273 if (*p >= *p1 && *p <= *p2) {
274 // First date must be the same
275 if (v.Size() == 0 && *p != *p1)
276 v.Push (new MHPrice(*p1));
277 v.Push (new MHPrice(*p));
278 }
279 }
280 // Last date must be the same
281 p = (MHPrice*) v.Last();
282 if (p && *p != *p2)
283 v.Push (new MHPrice(*p2));
284
285 out->Erase();
286 MHPrice::CopyPointers (&v, out);
287 v.Empty();
288 }
289
290
291
292 /**
293 * Convert day price data to weekly data
294 * @param MHVector* - In serie
295 * @param MHVector* - Out serie
296 * @param int - One of MHDate::MONDAY - MHDate::SUNDAY
297 */
Day2Week(MHVector * in,MHVector * out,int nWeekDay)298 void MHPrice::Day2Week (MHVector* in, MHVector* out, int nWeekDay) {
299 bool Init = false;
300 MHString StopStr, StartStr;
301 MHPrice* p;
302 MHPrice p2;
303 MHDate StopDate;
304
305 for (int f = 0; f < in->Size(); f++) {
306 p = (MHPrice*) (*in)[f];
307
308 if (Init == false) {
309 // Initiate first date.
310 // Move stopdate to right day in week
311 MHDate tmp;
312
313 tmp.Set (p->aDate);
314 tmp.GotoWeekday (nWeekDay);
315 tmp.Get (MHDate::LONG_DATE, StopStr);
316 StopDate = tmp;
317
318 // Then move start date back one week
319 tmp.AddDays (-7);
320 tmp.Get (MHDate::LONG_DATE, StartStr);
321
322 p2 = *p;
323 Init = true;
324 }
325
326 if (*p > StopStr()) {
327 // Current point is out of range so save old point to out vector
328 p2.SetDate (StopStr());
329 out->Push (new MHPrice(p2));
330
331 // Set current point as last point
332 p2 = *p;
333 }
334 else if (*p > StartStr() && *p <= StopStr()) {
335 // Save last point for every time serie range
336 if (p2 == "")
337 p2 = *p;
338 else {
339 if (p->aHigh > p2.aHigh) p2.aHigh = p->aHigh;
340 if (p->aLow < p2.aLow) p2.aLow = p->aLow;
341 p2.aVol += p->aVol;
342 p2.aClose = p->aClose;
343 }
344 }
345
346 // Set new range if point is outside current range
347 while (*p > StopStr()) {
348 StartStr = StopStr;
349 StopDate.AddDays (7);
350 StopDate.Get (MHDate::LONG_DATE, StopStr);
351 }
352 }
353 if (StopStr != MHString("")) {
354 p2.SetDate (StopStr());
355 out->Push (new MHPrice(p2));
356 }
357 }
358
359
360
361 /**
362 * Create vector with the difference of two vectors
363 * @param MHVector* - Vector 1
364 * @param MHVector* - Vector 2
365 * @param MHVector* - Out vector
366 * @param MHVector* - Out vector with only 0.0 values in it, default 0
367 */
Diff(MHVector * in1,MHVector * in2,MHVector * out,MHVector * out2)368 void MHPrice::Diff (MHVector* in1, MHVector* in2, MHVector* out, MHVector* out2) {
369 MHPrice* p1 = 0;
370 MHPrice* p2 = 0;
371
372 for (int f = 0; f < in1->Size(); f++) {
373 p1 = (MHPrice*) in1->Get(f);
374 p2 = (MHPrice*) in2->Find (p1, MHVector::FIND_EXACT);
375
376 if (p1 && p2) {
377 out->Push (new MHPrice (p1->aDate, p1->aClose - p2->aClose, 0.0, p1->aClose - p2->aClose, 0.0, 0.0));
378 out2->Push (new MHPrice (p1->aDate, 0.0, 0.0, 0.0, 0.0, 0.0));
379 }
380 }
381 }
382
383
384
385 /**
386 * Make a vector with the exponential moving average of price data
387 * @param MHVector* - In serie
388 * @param MHVector* - Out serie
389 * @param int - Number of points in moving average
390 */
ExponentialMovingAverage(MHVector * in,MHVector * out,int nMvg)391 void MHPrice::ExponentialMovingAverage (MHVector* in, MHVector* out, int nMvg) {
392 double sma = 0.0;
393 double prev = 0.0;
394 double multi = 2.0 / double(nMvg + 1.0);
395 MHPrice* p;
396
397 if (nMvg > 1 && nMvg < in->Size()) {
398 // Iterate through all data points
399 for (int f = 0; f < in->Size(); f++) {
400 p = (MHPrice*) (*in)[f];
401
402 if (f < (nMvg - 1)) {
403 sma += p->aClose;
404 }
405 else if (f == (nMvg - 1)) {
406 sma += p->aClose;
407 prev = sma / nMvg;
408 out->Push (new MHPrice (p->aDate, prev));
409 }
410 else {
411 prev = ((p->aClose - prev) * multi) + prev;
412
413 out->Push (new MHPrice (p->aDate, prev));
414 }
415 }
416 }
417 }
418
419
420
421 /**
422 * Make a vector with the exponential moving average of price data
423 * @param MHVector* - In serie
424 * @param MHVector* - MACD out serie
425 * @param MHVector* - EMA MACD out serie
426 * @param int - Number of points in short ema
427 * @param int - Number of points in long ema
428 * @param int - Number of points in ema of macd
429 */
MACD(MHVector * in,MHVector * macd1,MHVector * macd2,int emaShort,int emaLong,int emaMacd)430 void MHPrice::MACD (MHVector* in, MHVector* macd1, MHVector* macd2, int emaShort, int emaLong, int emaMacd) {
431 MHPrice* p1 = 0;
432 MHPrice* p2 = 0;
433 MHVector macdShort;
434 MHVector macdLong;
435 int emaDiff = emaLong - emaShort;
436
437 if (emaDiff <= 0) return;
438 ExponentialMovingAverage (in, &macdShort, emaShort);
439 ExponentialMovingAverage (in, &macdLong, emaLong);
440
441 for (int f = 0; f < macdLong.Size(); f++) {
442 p1 = (MHPrice*) macdLong.Get(f);
443 p2 = (MHPrice*) macdShort.Get(f + emaDiff);
444
445 if (p1 && p2) {
446 macd1->Push (new MHPrice (p1->aDate, p2->aClose - p1->aClose));
447 }
448 }
449 ExponentialMovingAverage (macd1, macd2, emaMacd);
450 macdShort.Erase ();
451 macdLong.Erase ();
452 }
453
454
455
456 /**
457 * Make a vector with the Momentum model
458 * @param MHVector* - Vector with MHPrices
459 * @param MHVector* - The vector with converted data
460 * @param MHVector* - The vector with zero line
461 * @param int - Number of days back in time
462 */
Momentum(MHVector * in,MHVector * out,MHVector * zero,int nMvg)463 void MHPrice::Momentum (MHVector* in, MHVector* out, MHVector* zero, int nMvg) {
464 int nSize = in->Size();
465 int nStart = nMvg - 1;
466 MHPrice* p;
467 MHPrice* p2;
468
469 if (nMvg < 2 && nMvg > nSize)
470 return;
471
472 // Iterate through all data points and calc RSI data
473 for (int f = 1; f < nSize; f++) {
474 if (f >= nStart) {
475 p = (MHPrice*) (*in)[f];
476 p2 = (MHPrice*) (*in)[f - nStart];
477 out->Push (new MHPrice (p->aDate, p->aClose - p2->aClose));
478 zero->Push (new MHPrice (p->aDate, 0));
479 }
480 }
481 }
482
483
484
485 /**
486 * Make a vector with moving average of price data
487 * @param MHVector* - In serie
488 * @param MHVector* - Out serie
489 * @param int - Number of points in moving average
490 */
MovingAverage(MHVector * in,MHVector * out,int nMvg)491 void MHPrice::MovingAverage (MHVector* in, MHVector* out, int nMvg) {
492 int nCount = 0;
493 double nSum = 0;
494 double* v = new double [in->Size()];
495 MHPrice* p;
496
497 if (nMvg > 1 && nMvg < in->Size()) {
498 // Iterate through all data points
499 for (int f = 0; f < in->Size(); f++) {
500 p = (MHPrice*) (*in)[f];
501 nCount++;
502
503 if (nCount < nMvg) {
504 // Add data until the first moving average price can be calculated
505 v[nCount - 1] = p->aClose;
506 nSum += p->aClose;
507 }
508 else if (nCount == nMvg) {
509 // This is the first point
510 v[nCount - 1] = p->aClose;
511 nSum += p->aClose;
512 out->Push (new MHPrice (p->aDate, nSum / nMvg));
513 }
514 else {
515 // And here comes the rest
516 v[nCount - 1] = p->aClose;
517
518 // Remove oldest data in range and add current to sum
519 nSum -= v[nCount - (nMvg + 1)];
520 nSum += p->aClose;
521
522 // save new point, (point 2 and forward)
523 out->Push (new MHPrice (p->aDate, nSum / nMvg));
524 }
525 }
526 }
527 delete []v;
528 }
529
530
531
532 /**
533 * Make a vector with all buy/sell signals
534 * @param MHVector* - Short moving average
535 * @param MHVector* - Long moving average
536 * @param MHVector* - Out serie
537 */
MovingAverageSignals(MHVector * in_short,MHVector * in_long,MHVector * out)538 void MHPrice::MovingAverageSignals (MHVector* in_short, MHVector* in_long, MHVector* out) {
539 MHPrice* priceShort;
540 MHPrice* priceLong;
541 int signal = 0;
542
543 for (int f = 0; f < in_short->Size(); f++) {
544 priceShort = (MHPrice*) (*in_short)[f];
545 priceLong = (MHPrice*) in_long->Find (priceShort, MHVector::FIND_EXACT, 0, 0);
546
547 if (priceShort && priceLong) {
548 if (signal == 0) {
549 // Initiate first signal, next time signal change start to store them in out vector
550 if (priceShort->aClose < priceLong->aClose)
551 signal = SELL;
552 else if (priceShort->aClose > priceLong->aClose)
553 signal = BUY;
554 }
555 else {
556 if (signal == BUY && priceShort->aClose < priceLong->aClose) {
557 signal = SELL;
558 out->Push (new MHPrice (priceShort->aDate, priceShort->aClose));
559 }
560 else if (signal == SELL && priceShort->aClose > priceLong->aClose) {
561 signal = BUY;
562 out->Push (new MHPrice (priceShort->aDate, priceShort->aClose));
563 }
564
565 }
566 }
567 }
568 }
569
570
571
572 /**
573 * Create a list with MHPrices that are normalised with
574 * the first data point as the reference point
575 * @param MHVector* - Vector with MHPrices
576 * @param MHVector* - The vector with converted data
577 * @param const double& - Start number
578 */
Normalise(MHVector * in,MHVector * out,double nOrigo)579 void MHPrice::Normalise (MHVector* in, MHVector* out, double nOrigo) {
580 bool bFirst = true;
581 double nFactor = 0;
582 MHPrice* p;
583
584 for (int f = 0; f < in->Size(); f++) {
585 p = (MHPrice*) (*in)[f];
586 if (p->aClose < 0)
587 continue;
588
589 if (bFirst == true) {
590 nFactor = p->aClose / nOrigo;
591 bFirst = false;
592 }
593 out->Push(new MHPrice (
594 p->aDate,
595 p->aHigh / nFactor,
596 p->aLow / nFactor,
597 p->aClose / nFactor,
598 p->aOpen / nFactor,
599 p->aVol / nFactor));
600 }
601 }
602
603
604
605 /**
606 * Print to outstream all data points for a vector
607 * @param MHVector* - In serie
608 */
Print(MHVector * in)609 void MHPrice::Print (MHVector* in) {
610 for (int f = 0; f < in->Size(); f++)
611 ;//cout << *((MHPrice*)(*in)[f]) << endl;
612 }
613
614
615
616 /**
617 * Make a vector with the Relative Strength Index
618 * @param MHVector* - Vector with MHPrices
619 * @param MHVector* - The vector with converted data
620 * @param int - Number of points to use
621 */
RSI(MHVector * in,MHVector * out,int nMvg)622 void MHPrice::RSI (MHVector* in, MHVector* out, int nMvg) {
623 double nAvgGain = 0;
624 double nAvgLoss = 0;
625 double nDiff;
626 MHPrice* p;
627 MHPrice* pp;
628
629 if (nMvg < 2 || nMvg > in->Size()) return;
630
631 // Iterate through all data points and calc RSI data
632 for (int f = 1; f < in->Size(); f++) {
633 p = (MHPrice*) (*in)[f];
634 pp = (MHPrice*) (*in)[f - 1];
635 nDiff = p->aClose - pp->aClose;
636
637 if (f <= nMvg) {
638 if (nDiff > 0)
639 nAvgGain += nDiff;
640 else
641 nAvgLoss += fabs(nDiff);
642 }
643
644 if (f == nMvg) {
645 nAvgGain = nAvgGain / nMvg;
646 nAvgLoss = nAvgLoss / nMvg;
647 out->Push (new MHPrice (p->aDate, 100 - (100 / (1 + (nAvgGain / nAvgLoss)))));
648 }
649 else if (f > nMvg) {
650 nAvgGain = ((nAvgGain * (nMvg - 1)) + ((nDiff > 0) ? fabs(nDiff) : 0)) / nMvg;
651 nAvgLoss = ((nAvgLoss * (nMvg - 1)) + ((nDiff < 0) ? fabs(nDiff) : 0)) / nMvg;
652 out->Push (new MHPrice (p->aDate, 100 - (100 / (1 + (nAvgGain / nAvgLoss)))));
653 }
654 }
655 }
656
657
658
659 /**
660 * Make a vector with all buy/sell signals for rsi moel
661 * @param MHVector* - In serie
662 * @param MHVector* - Out serie
663 * @param double - Low value
664 * @param double - High value
665 */
RSISignals(MHVector * in,MHVector * out,double low,double high)666 void MHPrice::RSISignals (MHVector* in, MHVector* out, double low, double high) {
667 MHPrice* price;
668 double last = 0.0;
669 int signal = NEUTRAL;
670 int signal2 = NEUTRAL;
671
672 for (int f = 0; f < in->Size(); f++) {
673 price = (MHPrice*) (*in)[f];
674
675 if (signal == NEUTRAL && price->aClose >= high) {
676 signal = SELL;
677 }
678 else if (signal == SELL && signal2 == NEUTRAL && price->aClose < last) {
679 out->Push (new MHPrice (price->aDate, -1, -1, price->aClose, SELL, -1));
680 signal2 = SELL;
681 }
682 else if (signal == SELL && signal2 == SELL && price->aClose < high) {
683 signal = signal2 = NEUTRAL;
684 }
685 else if (signal == NEUTRAL && price->aClose <= low) {
686 signal = BUY;
687 }
688 else if (signal == BUY && signal2 == NEUTRAL && price->aClose > last) {
689 out->Push (new MHPrice (price->aDate, -1, -1, price->aClose, BUY, -1));
690 signal2 = BUY;
691 }
692 else if (signal == BUY && signal2 == BUY && price->aClose > low) {
693 signal = signal2 = NEUTRAL;
694 }
695 last = price->aClose;
696 }
697 }
698
699
700
701 /**
702 * Save points to file
703 * @param const char* - The filename
704 * @param MHVector* - In serie
705 * @return bool - true if ok
706 */
Save(const char * pFilename,MHVector * in)707 bool MHPrice::Save (const char* pFilename, MHVector* in) {
708 FILE* file = fopen (pFilename, "wb");
709 char buffer[201];
710 MHPrice* p;
711
712 if (file) {
713 for (int f = 0; f < in->Size(); f++) {
714 p = (MHPrice*)(*in)[f];
715 snprintf (buffer, 200, "%s\t%f\t%f\t%f\t%f\t%f\n", p->aDate, p->aHigh, p->aLow, p->aClose, p->aOpen, p->aVol);
716 fwrite (buffer, sizeof(char), strlen(buffer), file);
717 }
718 fclose (file);
719 return true;
720 }
721 return false;
722 }
723
724
725
726 /**
727 * Make a vector with data converted to standar deviation
728 * @param MHVector* - In serie
729 * @param MHVector* - Out serie
730 * @param int - Number of points for average
731 */
StdDev(MHVector * in,MHVector * out,int nDays)732 void MHPrice::StdDev (MHVector* in, MHVector* out, int nDays) {
733 int nCount = 0;
734 double nMean = 0;
735 double nDev = 0;
736 double nDev2 = 0;
737 double nSum = 0;
738 MHPrice* p;
739
740 if (nDays < 2 || nDays > in->Size()) return;
741
742 for (int f = 0; f < in->Size(); f++) {
743 p = (MHPrice*)(*in)[f];
744 nCount++;
745 nSum += p->aClose;
746
747 if (nCount >= nDays) {
748 nMean = nSum / nDays;
749
750 // Create nDays points
751 nDev2 = 0;
752 for (int j = nCount - nDays; j < nCount; j++) {
753 p = (MHPrice*) (*in)[j];
754 nDev = p->aClose - nMean;
755 nDev *= nDev;
756 nDev2 += nDev;
757 }
758 nDev2 /= nDays;
759 nDev2 = sqrt (nDev2);
760
761 p = (MHPrice*) (*in)[nCount - 1];
762 out->Push (new MHPrice (p->aDate, nDev2));
763
764 p = (MHPrice*) (*in)[nCount - nDays];
765 nSum -= p->aClose;
766 }
767 }
768 }
769
770
771
772 /**
773 * Make a vector with the stochastics formula
774 * @param MHVector* - In serie
775 * @param MHVector* - Out serie
776 * @param int - %k no. of days
777 * @param int - smoothing of %k
778 * @param int - %d no. of days
779 */
Stochastics(MHVector * in,MHVector * kout,MHVector * dout,MHVector * out20,MHVector * out80,int k,int sma,int d)780 void MHPrice::Stochastics (MHVector* in, MHVector* kout, MHVector* dout, MHVector* out20, MHVector* out80, int k, int sma, int d) {
781 double high, low, kval, diff1, diff2;
782 MHPrice* p;
783 MHPrice* p2;
784 MHVector ve;
785
786 kout->Erase ();
787 dout->Erase ();
788 for (int f = 0; f < in->Size(); f++) {
789 p = (MHPrice*)(*in)[f];
790
791 if ((f + 1) >= k) {
792 high = p->aHigh;
793 low = p->aLow;
794
795 // Get max/min prices for current range
796 for (int j = ((f + 1) - k); j < ((f + 1) - 1); j++) {
797 p2 = (MHPrice*) (*in)[j];
798 if (p2->aHigh > high) high = p2->aHigh;
799 if (p2->aLow < low) low = p2->aLow;
800 }
801
802 diff1 = p->aClose - low;
803 diff2 = high - low;
804 if (diff2 > 0.00001) {
805 kval = 100 * (diff1 / diff2);
806 ve.Push (new MHPrice (p->aDate, kval));
807 if (out20)
808 out20->Push (new MHPrice (p->aDate, 20.0));
809 if (out80)
810 out80->Push (new MHPrice (p->aDate, 80.0));
811 }
812 }
813 }
814 if (sma > 1)
815 MHPrice::MovingAverage (&ve, kout, sma);
816 else
817 MHPrice::Copy (&ve, kout);
818
819 MHPrice::MovingAverage (kout, dout, d);
820 ve.Erase ();
821 }
822
823
824
825 /**
826 * Validate point and try to fix missing data
827 */
Validate()828 void MHPrice::Validate () {
829 MHDate now;
830 if (strlen(aDate) != 8) SetDate (now.Get (MHDate::LONG_DATE));
831 if (aClose > aHigh) aHigh = aClose;
832 if (aClose < aLow) aLow = aClose;
833 if (aOpen < 0.0000001 && aOpen > -0.0000001) aOpen = -1;
834 if (aVol < 0.0000001 && aVol > -0.0000001) aVol = -1;
835 if (aClose < 0.0000001 && aClose > -0.0000001) {
836 aHigh = aLow =aClose = -1;
837 }
838 }
839
840
841
842 /**
843 * Make a vector with only volume data
844 * @param MHVector* - Vector with MHPrices
845 * @param MHVector* - The vector with converted data
846 */
Volume(MHVector * in,MHVector * out)847 void MHPrice::Volume (MHVector* in, MHVector* out) {
848 MHPrice* p;
849
850 for (int f = 0; f < in->Size(); f++) {
851 p = (MHPrice*) (*in)[f];
852 if (p->aVol >= 0.0000001)
853 out->Push (new MHPrice (p->aDate, p->aVol));
854 }
855 }
856