lib/LMS.cpp

Go to the documentation of this file.
00001 /*
00002  *  Qtstalker stock charter
00003  *
00004  *  Copyright (C) 2001-2007 Stefan S. Stratigakos
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
00019  *  USA.
00020  */
00021 
00022 #include "LMS.h"
00023 #include "PrefDialog.h"
00024 #include <qdict.h>
00025 #include <qobject.h>
00026 #include <qmemarray.h>
00027 #include <math.h>
00028 
00029 LMS::LMS()
00030 {
00031   pluginName = "LMS";
00032   helpFile = "lms.html";
00033 
00034   colorKLabel = "colorK";
00035   color2DayLabel = "color2Day";
00036   color5DayLabel = "color5Day";
00037   labelLabel = "label";
00038   lineTypeKLabel = "lineTypeK";
00039   lineType2DayLabel = "lineType2Day";
00040   lineType5DayLabel = "lineType5Day";
00041   pluginLabel = "plugin";
00042   fkPeriodLabel = "fkPeriod";
00043   skPeriodLabel = "skPeriod";
00044   cmbIndexLabel = "cmbIndex";
00045   show2DayLabel = "show2Day";
00046   show5DayLabel = "show5Day";
00047   plotTestLabel = "plotTest";
00048 
00049   // format1: FK_PERIOD, SK_PERIOD, CMB_INDEX, SHOW_2DAY, SHOW_5DAY
00050 
00051   formatList.append(FormatInteger);
00052   formatList.append(FormatInteger);
00053   formatList.append(FormatString);
00054   formatList.append(FormatBool);
00055   formatList.append(FormatBool);
00056 
00057   setDefaults();
00058 }
00059 
00060 LMS::~LMS()
00061 {
00062 }
00063 
00064 void LMS::setDefaults()
00065 {
00066   colorK.setNamedColor("red");
00067   color2Day.setNamedColor("green");
00068   color5Day.setNamedColor("blue");
00069   lineTypeK = PlotLine::Line;
00070   lineType2Day = PlotLine::Line;
00071   lineType5Day = PlotLine::Line;
00072   label = pluginName;
00073 
00074   show2Day = TRUE;
00075   show5Day = FALSE;
00076   cycleFlag = TRUE;
00077   fkPeriod = 5;
00078   skPeriod = 5;
00079   cmbIndex = 1;
00080 
00081   //test pattern-- -- -----------------------------------------------------------------------
00082   testFlag = FALSE;
00083 }
00084 
00085 Indicator * LMS::calculate()
00086 {
00087   Indicator *output = new Indicator;
00088   output->setDateFlag(dateFlag);
00089   output->setLogScale(logScale);
00090 
00091   QPtrList<PlotLine> pll;
00092   pll.setAutoDelete(FALSE);
00093   getLMS(pll);
00094 
00095   int loop;
00096   for (loop = 0; loop < (int) pll.count(); loop++)
00097     output->addLine(pll.at(loop));
00098 
00099   return output;
00100 }
00101 
00102 void LMS::getLMS (QPtrList<PlotLine> &pll)
00103 {
00104   int i = 0;
00105   double sigPower = 0;
00106   double mu = 0;
00107   double xBar = 0;
00108 
00109   PlotLine *price = new PlotLine;
00110 
00111   //price = (h + l) / 2
00112   if (!testFlag)
00113   {
00114     for (i = 0; i < (int)data->count(); i++)
00115       price->append((data->getHigh(i) + data->getLow(i)) / 2);
00116   }
00117   //== == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
00118     //Test pattern for cycle freaks:-)
00119   else
00120   {
00121     double Pi = 3.1415926;
00122     double twoPi = 2 * Pi;
00123 
00124     for (i = 0; i < 125; i++)
00125       price->append(25 * sin(twoPi * i / 10));
00126 
00127     PlotLine *testLine = new PlotLine;
00128 
00129     for (i = 0; i < 125; i++)
00130       testLine->append(1 + (0.2 * sin(twoPi * i / 10)));
00131 
00132     QString labelTest = "Price";
00133     QColor color;
00134     color.setNamedColor("yellow");
00135 
00136     testLine->setColor(color);
00137     testLine->setLabel(labelTest);
00138     pll.append(testLine);
00139   }
00140 
00141   //== == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
00142 
00143   PlotLine *price_offset_4 = new PlotLine;
00144   //temps
00145   PlotLine *temp1 = new PlotLine;
00146 
00147   PlotLine *value1 = new PlotLine;
00148   //dual mode
00149   PlotLine *value2 = new PlotLine;
00150   PlotLine *value3 = new PlotLine;
00151 
00152   QMemArray< double > g(30);
00153   QMemArray< double > sigPredict(30);
00154 
00155   g.fill(0.0);
00156   sigPredict.fill(0.0);
00157 
00158   //Counter trend mode-- -- ------------------------------------------------------
00159   if (!cycleFlag)
00160   {
00161     int offset = 4;
00162 
00163     //price[4]
00164     for (i = 0; i < price->getSize(); i++)
00165     {
00166       if (i > offset - 1)
00167         price_offset_4->append(price->getData(i - offset));
00168     }
00169 
00170     //0.5(price - price[4]
00171     int priceIndex = price->getSize() - 1;
00172     for (i = price_offset_4->getSize() - 1; i >= 0; i--)
00173     {
00174       temp1->prepend(0.5 * (price->getData(priceIndex) - price_offset_4->getData(i)));
00175       priceIndex--;
00176     }
00177 
00178     //0.25(price + 0.5(price - price[4])
00179     priceIndex = price->getSize() - 1;
00180     for (i = temp1->getSize() - 1; i >= 0; i--)
00181     //work back for simplicity
00182     {
00183       temp1->setData(i, 0.25 * (temp1->getData(i) + price->getData(priceIndex)));
00184       priceIndex--;
00185     }
00186 
00187     //Value1 = .25 * (Price + .5 * (Price - Price[4])) + .75 * Value1[1];
00188     for (i = 0; i < temp1->getSize(); i++)
00189     {
00190       if (i == 0)
00191         value1->append(temp1->getData(i));
00192       else
00193         value1->append(temp1->getData(i) + (value1->getData(i - 1) * 0.75));
00194     }
00195   } //end counter trend mode
00196 
00197   // Cycle mode-- -- -----------------------------------------------------------------------
00198   else
00199   {
00200     //slowK(price, length, length);
00201     temp1 = slowK(price, fkPeriod, skPeriod);
00202 
00203     //0.2(2 * (SlowK(price, length, length) / 100 - .5))
00204     for (i = 0; i < temp1->getSize(); i++)
00205       temp1->setData(i, 0.2 * (2 * (temp1->getData(i)) / (100 - 0.5)));
00206 
00207     //Value1 = .2 * (2 * (SlowK(Length) / 100 - .5)) + .8 * Value1[1];
00208     for (i = 0; i < temp1->getSize(); i++)
00209     {
00210       if (i == 0)
00211         value1->append(temp1->getData(i));
00212       else
00213         value1->append(temp1->getData(i) + value1->getData(i - 1) * 0.8);
00214     }
00215   } //end cycle mode
00216     // end cycleFlag-- -- --------------------------------------------------------------------
00217 
00218   //if currentBar > length
00219   int j = 0;
00220   for (i = skPeriod; i < value1->getSize(); i++)
00221   {
00222     //Compute average power for normalization
00223     sigPower = 0;
00224     for (j = 0; j < skPeriod; j++)
00225       sigPower = sigPower + value1->getData(i - j) * value1->getData(i - j);
00226 
00227     sigPower /= skPeriod;
00228 
00229     //Convergence Factor
00230     if (sigPower > 0)
00231     mu = 0.25 / (sigPower * skPeriod);
00232 
00233     //Compute signal estimate
00234     xBar = 0;
00235     for (j = 1; j <= skPeriod; j++)
00236       xBar = xBar + value1->getData(i - j) * g[j];
00237 
00238     //Compute gain coefficients
00239     for (j = 1; j <= skPeriod; j++)
00240       g[j] = g[j] + (mu * (value1->getData(i) - xBar) * value1->getData(i - j));
00241 
00242     //Compute signal prediction waveform
00243     for (j = 0; j <= skPeriod; j++)
00244       sigPredict[j] = value1->getData(i - (skPeriod - j));
00245 
00246     //Extend signal prediction into the future
00247     int k = 0;
00248     for (j = skPeriod + 1; j <= skPeriod + 5; j++)
00249     {
00250       sigPredict[j] = 0;
00251 
00252       for (k = 1; k <= skPeriod; k++)
00253         sigPredict[j] = sigPredict[j] + sigPredict[j - k] * g[k];
00254     }
00255 
00256     value2->append(sigPredict[skPeriod + 2]);
00257     value3->append(sigPredict[skPeriod + 5]);
00258   }
00259 
00260   delete price;
00261   delete price_offset_4;
00262   delete temp1;
00263 
00264   //remove the first 1.5 * length values-- initial ramp up messes with scaling
00265   // ***n.b need a delete(index) function for PlotLine ***
00266   PlotLine *temp1a = new PlotLine;
00267   PlotLine *temp2 = new PlotLine;
00268   PlotLine *temp3 = new PlotLine;
00269 
00270   int index1 = value1->getSize() -1;
00271   int index2 = value2->getSize() - 1;
00272   int index3 = value3->getSize() - 1;
00273 
00274   for (i = value2->getSize() - 1; i >= (int)skPeriod * 1.5; i--)
00275   {
00276     temp1a->prepend(value1->getData(index1));
00277     temp2->prepend(value2->getData(index2));
00278     temp3->prepend(value3->getData(index3));
00279 
00280     index1--;
00281     index2--;
00282     index3--;
00283   }
00284 
00285   delete value1;
00286   delete value2;
00287   delete value3;
00288 
00289   value1 = temp1a;
00290   value2 = temp2;
00291   value3 = temp3;
00292 
00293   //output results:
00294 
00295   QString labelx = "SlowK";
00296 
00297   value1->setColor(colorK);
00298   value1->setLabel(labelx);
00299   value1->setType(lineTypeK);
00300   pll.append(value1);
00301 
00302   if (show2Day)
00303   {
00304     labelx = "2Day";
00305     value2->setColor(color2Day);
00306     value2->setLabel(labelx);
00307     value2->setType(lineType2Day);
00308     pll.append(value2);
00309   }
00310   else
00311     delete value2;
00312 
00313   if (show5Day)
00314   {
00315     labelx = "5Day";
00316     value3->setColor(color5Day);
00317     value3->setLabel(labelx);
00318     value3->setType(lineType5Day);
00319     pll.append(value3);
00320   }
00321   else
00322     delete value3;
00323 }
00324 
00325 PlotLine *LMS::slowK(PlotLine * inLine, int kPeriod, int slowKperiod)
00326 {
00327   PlotLine *k = new PlotLine();
00328   int loop;
00329   for (loop = kPeriod; loop < (int)inLine->getSize(); loop++)
00330   {
00331     int loop2;
00332     double l;
00333     double h;
00334     for (loop2 = 0, l = 9999999, h = 0; loop2 < kPeriod; loop2++)
00335     {
00336       double t = inLine->getData(loop - loop2);
00337       if (t > h)
00338         h = t;
00339       if (t < l)
00340         l = t;
00341     }
00342 
00343     double close = inLine->getData(loop);
00344     double t = ((close - l) / (h - l)) * 100;
00345     if (t > 100)
00346       t = 100;
00347     if (t < 0)
00348       t = 0;
00349 
00350     k->append(t);
00351   }
00352 
00353   PlotLine *k2 = getMA(k, 0, slowKperiod);
00354   delete k;
00355   k = k2;
00356 
00357   return k;
00358 }
00359 
00360 int LMS::indicatorPrefDialog(QWidget * w)
00361 {
00362   QString pl = QObject::tr("Parms");
00363   QString cl = QObject::tr("SlowK Color");
00364   QString cl2 = QObject::tr("2 Day prediction Color");
00365   QString cl3 = QObject::tr("5 Day Prediction Color");
00366   QString ll = QObject::tr("Label");
00367   QString ltl = QObject::tr("Line Type K");
00368   QString lt2 = QObject::tr("Line Type 2 Day");
00369   QString lt3 = QObject::tr("Line Type 5 Day");
00370   QString ck1 = QObject::tr("Show 2 Day Prediction");
00371   QString ck2 = QObject::tr("Show 5 Day Prediction");
00372   QString fk = QObject::tr("Fast K Period");
00373   QString sk = QObject::tr("Slow K Period");
00374   QString cmb = QObject::tr("Select Mode");
00375 
00376   //test pattern-- -- -----------------------------------------------------------------------
00377   QString ck3 = QObject::tr("Plot Test Pattern");
00378   //----------------------------------------------------------------------------------------
00379 
00380   PrefDialog * dialog = new PrefDialog(w);
00381   dialog->setCaption(QObject::tr("LMS Indicator"));
00382   dialog->createPage(pl);
00383   dialog->setHelpFile(helpFile);
00384   dialog->addColorItem(cl, pl, colorK);
00385   dialog->addComboItem(ltl, pl, lineTypes, lineTypeK);
00386   dialog->addColorItem(cl2, pl, color2Day);
00387   dialog->addComboItem(lt2, pl, lineTypes, lineType2Day);
00388   dialog->addColorItem(cl3, pl, color5Day);
00389   dialog->addComboItem(lt3, pl, lineTypes, lineType5Day);
00390   dialog->addTextItem(ll, pl, label);
00391 
00392   QStringList l;
00393   l << "Counter Trend" << "Cycle";
00394   dialog->addComboItem(cmb, pl, l, cycleFlag);
00395   dialog->addIntItem(fk, pl, fkPeriod, 2, 99999999);
00396   dialog->addIntItem(sk, pl, skPeriod, 2, 99999999);
00397   dialog->addCheckItem(ck1, pl, show2Day);
00398   dialog->addCheckItem(ck2, pl, show5Day);
00399 
00400   //test pattern-- -- -----------------------------------------------------------------------
00401   dialog->addCheckItem(ck3, pl, testFlag);
00402   //----------------------------------------------------------------------------------------
00403 
00404   int rc = dialog->exec();
00405 
00406   if (rc == QDialog::Accepted)
00407   {
00408     dialog->getColor(cl, colorK);
00409     dialog->getColor(cl2, color2Day);
00410     dialog->getColor(cl3, color5Day);
00411     lineTypeK = (PlotLine::LineType) dialog->getComboIndex(ltl);
00412     lineType2Day = (PlotLine::LineType) dialog->getComboIndex(lt2);
00413     lineType5Day = (PlotLine::LineType) dialog->getComboIndex(lt3);
00414     dialog->getText(ll, label);
00415     show2Day = dialog->getCheck(ck1);
00416     show5Day = dialog->getCheck(ck2);
00417     cmbIndex = dialog->getComboIndex(cmb);
00418 
00419     if (cmbIndex == 1)
00420       //0 = counter tredn, 1 = cycle
00421       cycleFlag = TRUE;
00422     else
00423       cycleFlag = FALSE;
00424 
00425     //test pattern-- -- -----------------------------------------------------------------------
00426     testFlag = dialog->getCheck(ck3);
00427     //----------------------------------------------------------------------------------------
00428 
00429     fkPeriod = dialog->getInt(fk);
00430     skPeriod = dialog->getInt(sk);
00431 
00432     rc = TRUE;
00433   }
00434   else
00435     rc = FALSE;
00436 
00437   delete dialog;
00438   return rc;
00439 }
00440 
00441 PlotLine *LMS::calculateCustom (QString &p, QPtrList<PlotLine> &d)
00442 {
00443   // format1: FK_PERIOD, SK_PERIOD, CMB_INDEX, SHOW_2DAY, SHOW_5DAY
00444 
00445   if (checkFormat(p, d, 5, 5))
00446     return 0;
00447 
00448   fkPeriod = formatStringList[0].toInt();
00449   skPeriod = formatStringList[1].toInt();
00450 
00451   if (! formatStringList[2].compare("Cycle"))
00452   {
00453     cmbIndex = 1;
00454     cycleFlag = TRUE;
00455   }
00456   else
00457   {
00458     if (! formatStringList[2].compare("Counter Trend"))
00459     {
00460       cmbIndex = 0;
00461       cycleFlag = FALSE;
00462     }
00463     else
00464     {
00465       qDebug("LMS::calculateCustom: invalid CMB_INDEX parm");
00466       return 0;
00467     }
00468   }
00469 
00470   if (! formatStringList[3].compare("TRUE"))
00471     show2Day = TRUE;
00472   else
00473     show2Day = FALSE;
00474 
00475   if (! formatStringList[4].compare("TRUE"))
00476     show5Day = TRUE;
00477   else
00478     show5Day = FALSE;
00479 
00480   QPtrList<PlotLine> pll;
00481   pll.setAutoDelete(FALSE);
00482   getLMS(pll);
00483 
00484   int loop;
00485   for (loop = pll.count() - 1; loop > 0; loop--)
00486     pll.remove(loop);
00487 
00488   return pll.at(0);
00489 }
00490 
00491 void LMS::getIndicatorSettings(Setting & dict)
00492 {
00493   QString ts = colorK.name();
00494   dict.setData(colorKLabel, ts);
00495   ts = color2Day.name();
00496   dict.setData(color2DayLabel, ts);
00497   ts = color5Day.name();
00498   dict.setData(color5DayLabel, ts);
00499   dict.setData(labelLabel, label);
00500   ts = QString::number(lineTypeK);
00501   dict.setData(lineTypeKLabel, ts);
00502   ts = QString::number(lineType2Day);
00503   dict.setData(lineType2DayLabel, ts);
00504   ts = QString::number(lineType5Day);
00505   dict.setData(lineType5DayLabel, ts);
00506   dict.setData(pluginLabel, pluginName);
00507   ts = QString::number(fkPeriod);
00508   dict.setData(fkPeriodLabel, ts);
00509   ts = QString::number(skPeriod);
00510   dict.setData(skPeriodLabel, ts);
00511   ts = QString::number(cmbIndex);
00512   dict.setData(cmbIndexLabel, ts);
00513   ts = QString::number(show2Day);
00514   dict.setData(show2DayLabel, ts);
00515   ts = QString::number(show5Day);
00516   dict.setData(show5DayLabel, ts);
00517   ts = QString::number(testFlag);
00518   dict.setData(plotTestLabel, ts);
00519 }
00520 
00521 void LMS::setIndicatorSettings(Setting & dict)
00522 {
00523   setDefaults();
00524 
00525   if (!dict.count())
00526     return;
00527 
00528   QString s;
00529   dict.getData(colorKLabel, s);
00530   if (s.length())
00531     colorK.setNamedColor(s);
00532 
00533   dict.getData(color2DayLabel, s);
00534   if (s.length())
00535     color2Day.setNamedColor(s);
00536 
00537   dict.getData(color5DayLabel, s);
00538   if (s.length())
00539     color5Day.setNamedColor(s);
00540 
00541   dict.getData(labelLabel, s);
00542   if (s.length())
00543     label = s;
00544 
00545   dict.getData(lineTypeKLabel, s);
00546   if (s.length())
00547     lineTypeK = (PlotLine::LineType) s.toInt();
00548 
00549   dict.getData(lineType2DayLabel, s);
00550   if (s.length())
00551     lineType2Day = (PlotLine::LineType) s.toInt();
00552 
00553   dict.getData(lineType5DayLabel, s);
00554   if (s.length())
00555     lineType5Day = (PlotLine::LineType) s.toInt();
00556 
00557   dict.getData(fkPeriodLabel, s);
00558   if (s.length())
00559     fkPeriod = s.toInt();
00560 
00561   dict.getData(skPeriodLabel, s);
00562   if (s.length())
00563     skPeriod = s.toInt();
00564 
00565   dict.getData(cmbIndexLabel, s);
00566   if (s.length())
00567     cmbIndex = s.toInt();
00568 
00569   if (cmbIndex == 1)
00570     cycleFlag = TRUE;
00571   else
00572     cycleFlag = FALSE;
00573   dict.getData(show2DayLabel, s);
00574   if (s.length())
00575     show2Day = s.toInt();
00576 
00577   dict.getData(show5DayLabel, s);
00578   if (s.length())
00579     show5Day = s.toInt();
00580 
00581   dict.getData(plotTestLabel, s);
00582   if (s.length())
00583     testFlag = s.toInt();
00584 }
00585 
00586 void LMS::formatDialog (QStringList &, QString &rv, QString &rs)
00587 {
00588   rs.truncate(0);
00589   rv.truncate(0);
00590   QString pl = QObject::tr("Parms");
00591   QString vl = QObject::tr("Variable Name");
00592   QString ck1 = QObject::tr("Show 2 Day Prediction");
00593   QString ck2 = QObject::tr("Show 5 Day Prediction");
00594   QString fk = QObject::tr("Fast K Period");
00595   QString sk = QObject::tr("Slow K Period");
00596   QString cmb = QObject::tr("Select Mode");
00597   PrefDialog *dialog = new PrefDialog(0);
00598   dialog->setCaption(QObject::tr("LMS Format"));
00599   dialog->createPage (pl);
00600   dialog->setHelpFile(helpFile);
00601 
00602   QString s;
00603   dialog->addTextItem(vl, pl, s);
00604   dialog->addIntItem(fk, pl, fkPeriod, 1, 999999);
00605   dialog->addIntItem(sk, pl, skPeriod, 1, 999999);
00606   QStringList l;
00607   l.append("Cycle");
00608   l.append("Counter Trend");
00609   dialog->addComboItem(cmb, pl, l, 0);
00610   dialog->addCheckItem(ck1, pl, show2Day);
00611   dialog->addCheckItem(ck2, pl, show5Day);
00612 
00613   int rc = dialog->exec();
00614   
00615   if (rc == QDialog::Accepted)
00616   {
00617     dialog->getText(vl, rv);
00618 
00619     int t = dialog->getInt(fk);
00620     rs.append(QString::number(t) + ",");
00621 
00622     t = dialog->getInt(sk);
00623     rs.append(QString::number(t) + ",");
00624 
00625     dialog->getCombo(cmb, s);
00626     rs.append(s + ",");
00627 
00628     t = dialog->getCheck(ck1);
00629     if (t)
00630       rs.append("TRUE,");
00631     else
00632       rs.append("FALSE,");
00633 
00634     t = dialog->getCheck(ck2);
00635     if (t)
00636       rs.append("TRUE");
00637     else
00638       rs.append("FALSE");
00639   }
00640 
00641   delete dialog;
00642 }
00643