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