plugins/quote/Yahoo/Yahoo.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 "Yahoo.h"
00023 #include "Bar.h"
00024 #include "DBIndexItem.h"
00025 #include "Exchange.h"
00026 #include <qfile.h>
00027 #include <qtextstream.h>
00028 #include <qdir.h>
00029 #include <qdatetime.h>
00030 #include <qnetwork.h>
00031 #include <qsettings.h>
00032 #include "DbPlugin.h"
00033 #include "../../../pics/newchart.xpm"
00034 #include <qinputdialog.h>
00035 #include <qmessagebox.h>
00036 #include <qlayout.h>
00037 #include <qlabel.h>
00038 #include <qframe.h>
00039 
00040 Yahoo::Yahoo ()
00041 {
00042   pluginName = "Yahoo";
00043   helpFile = "yahoo.html";
00044   url.setAutoDelete(TRUE);
00045   currentUrl = 0;
00046   fileCount = 0;
00047   fileCounter = 0;
00048   
00049   config.getData(Config::DataPath, dataPath);
00050   dataPath.append("/Stocks/Yahoo");
00051 
00052   config.getData(Config::Home, file);
00053   file.append("/yahooDownload");
00054   
00055   qInitNetworkProtocols();
00056 
00057   buildGui();
00058   
00059   loadSettings();
00060   
00061   connect(this, SIGNAL(signalGetFileDone(bool)), this, SLOT(fileDone(bool)));
00062   connect(this, SIGNAL(signalTimeout()), this, SLOT(timeoutError()));
00063 
00064   monthList.append("Jan");
00065   monthList.append("Feb");
00066   monthList.append("Mar");
00067   monthList.append("Apr");
00068   monthList.append("May");
00069   monthList.append("Jun");
00070   monthList.append("Jul");
00071   monthList.append("Aug");
00072   monthList.append("Sep");
00073   monthList.append("Oct");
00074   monthList.append("Nov");
00075   monthList.append("Dec");
00076   
00077   resize(400, 450);
00078 }
00079 
00080 Yahoo::~Yahoo ()
00081 {
00082   plug.close();
00083   saveSettings();
00084 }
00085 
00086 void Yahoo::buildGui ()
00087 {
00088   setCaption(tr("Yahoo Quotes"));
00089 
00090   config.getData(Config::DataPath, dataPath);
00091   dataPath.append("/Stocks/Yahoo");
00092 
00093   QString s = "new";
00094   QString s2 = tr("New Symbol");
00095   toolbar->addButton(s, newchart, s2);
00096   QObject::connect(toolbar->getButton(s), SIGNAL(clicked()), this, SLOT(newStock()));
00097   
00098   QLabel *label = new QLabel(tr("Method"), baseWidget);
00099   grid->addWidget(label, 0, 0);
00100   
00101   method = new QComboBox(baseWidget);
00102   method->insertItem("History", 0);
00103   method->insertItem("Auto History", 1);
00104   method->insertItem("Quote", 2);
00105   method->insertItem("Fundamental", 3);
00106   QObject::connect(method, SIGNAL(activated(int)), this, SLOT(methodChanged(int)));
00107   grid->addWidget(method, 0, 1);
00108   
00109   label = new QLabel(tr("Start Date"), baseWidget);
00110   grid->addWidget(label, 1, 0);
00111 
00112   sdate = new QDateEdit(QDate::currentDate(), baseWidget);
00113   sdate->setAutoAdvance(TRUE);
00114   sdate->setOrder(QDateEdit::YMD);
00115   grid->addWidget(sdate, 1, 1);
00116 
00117   label = new QLabel(tr("End Date"), baseWidget);
00118   grid->addWidget(label, 2, 0);
00119   
00120   edate = new QDateEdit(QDate::currentDate(), baseWidget);
00121   edate->setAutoAdvance(TRUE);
00122   edate->setOrder(QDateEdit::YMD);
00123   grid->addWidget(edate, 2, 1);
00124 
00125   QDate dt = QDate::currentDate();
00126   if (dt.dayOfWeek() == 6)
00127     dt = dt.addDays(-1);
00128   else
00129   {
00130     if (dt.dayOfWeek() == 7)
00131       dt = dt.addDays(-2);
00132   }
00133   edate->setDate(dt);
00134   sdate->setDate(QDate(dt.year() - 10, 1, 1));
00135   
00136   adjustment = new QCheckBox(tr("Adjustment"), baseWidget);
00137   grid->addWidget(adjustment, 3, 0);
00138   
00139   allSymbols = new QCheckBox(tr("All Symbols"), baseWidget);
00140   connect(allSymbols, SIGNAL(toggled(bool)), this, SLOT(allSymbolsChecked(bool)));
00141   grid->addWidget(allSymbols, 4, 0);
00142 
00143   QStringList l;  
00144   list = new FileButton(baseWidget, l, dataPath);
00145   grid->addWidget(list, 4, 1);
00146 }
00147 
00148 void Yahoo::update ()
00149 {
00150   plug.close();
00151   errorLoop = 0;
00152   url.clear();
00153   errorList.clear();
00154 
00155   if (allSymbols->isChecked())
00156     allSymbolsChecked(TRUE);
00157   else
00158     allSymbolsChecked(FALSE);
00159 
00160   QDir dir;
00161   int loop;
00162   for (loop = 0; loop < (int) symbolList.count(); loop++)
00163   {
00164     fileCount++;
00165     QString path = dataPath + "/";
00166     QFileInfo fi(symbolList[loop]);
00167     if (fi.extension(FALSE).length())
00168       path.append(fi.extension(FALSE).upper());
00169     else
00170       path.append("US");
00171     path.append("/");
00172     path.append(symbolList[loop]);
00173     if (! dir.exists(path, TRUE))
00174       continue;
00175       
00176     if (! method->currentText().compare("History"))
00177       createHistoryUrls(symbolList[loop]);
00178     else
00179     {
00180       if (! method->currentText().compare("Auto History"))
00181         createAutoHistoryUrls(path, symbolList[loop]);
00182       else
00183       {
00184         if (! method->currentText().compare("Quote"))
00185           createQuoteUrls(symbolList[loop]);
00186         else
00187           createFundamentalUrls(symbolList[loop]);
00188       }
00189     }
00190   }
00191 
00192   if (! url.count())
00193   {
00194     downloadComplete();
00195     QString ss(tr("No symbols selected. Done"));
00196     printStatusLogMessage(ss);
00197     return;
00198   }
00199   
00200   currentUrl = url.first();
00201 
00202   startDownload();
00203 }
00204 
00205 void Yahoo::startDownload ()
00206 {
00207   QString s, ts;
00208   ts = "url";
00209   currentUrl->getData(ts, s);
00210   getFile(s);
00211   fileCounter++;
00212   progressBar->setProgress(fileCounter, fileCount);
00213 }
00214 
00215 void Yahoo::fileDone (bool d)
00216 {
00217   if (d)
00218   {
00219 //    QString ss(tr("Network error aborting"));
00220 //    printStatusLogMessage(ss);
00221 //    printStatusLogMessage(stringDone);
00222 //    downloadComplete();
00223 //    return;
00224   }
00225   else
00226   {
00227     if (method->currentText().contains("History"))
00228       parseHistory();
00229     else
00230     {
00231       if (method->currentText().contains("Quote"))
00232         parseQuote();
00233       else
00234         parseFundamental();
00235     }
00236   }
00237 
00238   currentUrl = url.next();
00239   if (! currentUrl)
00240   {
00241     downloadComplete();
00242     printStatusLogMessage(stringDone);
00243     printErrorList();
00244     progressBar->reset();
00245     return;
00246   }
00247 
00248   errorLoop = 0;
00249   startDownload();    
00250 }
00251 
00252 void Yahoo::timeoutError ()
00253 {
00254   QString ts = "symbol";
00255   QString ts2;
00256   errorLoop++;
00257   if (errorLoop == retrySpin->value())
00258   {
00259     currentUrl->getData(ts, ts2);
00260     QString ss = tr("Timeout: retry limit skipping") + " " + ts2 + " " + tr("skipped");
00261     printStatusLogMessage(ss);
00262     errorList.append(ts2);
00263     
00264     errorLoop = 0;
00265     currentUrl = url.next();
00266     if (! currentUrl)
00267     {
00268       downloadComplete();
00269       printStatusLogMessage(stringDone);
00270       printErrorList();
00271       return;
00272     }
00273 
00274     startDownload();
00275   }
00276   else
00277   {
00278     currentUrl->getData(ts, ts2);
00279     QString ss = tr("Timeout: retry") + " " + QString::number(errorLoop + 1) + " " + ts2;
00280     printStatusLogMessage(ss);
00281     startDownload();
00282   }
00283 }
00284 
00285 void Yahoo::parseHistory ()
00286 {
00287   if (! data.length())
00288     return;
00289 
00290   if (data.contains("No data available"))
00291     return;
00292 
00293   if (data.contains("No Prices in this date range"))
00294     return;
00295     
00296   // strip off the header
00297   QString s = "Date,Open,High,Low,Close";
00298   int p = data.find(s, 0, TRUE);
00299   if (p != -1)
00300     data.remove(0, p + s.length());
00301 
00302   QFile f(file);
00303   if (! f.open(IO_WriteOnly))
00304     return;
00305   QTextStream stream(&f);
00306   stream << data;
00307   f.close();
00308 
00309   f.setName(file);
00310   if (! f.open(IO_ReadOnly))
00311     return;
00312   stream.setDevice(&f);
00313 
00314   s = dataPath + "/";
00315   QString ts = "symbol";
00316   QString ts2;
00317   currentUrl->getData(ts, ts2);
00318   QFileInfo fi(ts2);
00319   if (fi.extension(FALSE).length())
00320     s.append(fi.extension(FALSE).upper());
00321   else
00322     s.append("US");
00323   s.append("/");
00324   s.append(ts2);
00325 
00326   if (plug.open(s, chartIndex))
00327   {
00328     QString ss(tr("Could not open db"));
00329     printStatusLogMessage(ss);
00330     f.close();
00331     return;
00332   }
00333 
00334   QString fn = ts2;
00335 
00336   // verify if this chart can be updated by this plugin
00337   DBIndexItem item;
00338   chartIndex->getIndexItem(fn, item);
00339   item.getSymbol(s);  
00340   if (! s.length())
00341   {
00342     if (plug.createNewStock())
00343     {
00344       f.close();
00345       plug.close();
00346       return;
00347     }
00348 
00349     chartIndex->getIndexItem(fn, item);
00350 
00351     item.setSymbol(ts2);
00352     item.setTitle(ts2);
00353     item.setQuotePlugin(pluginName);
00354 
00355     chartIndex->setIndexItem(fn, item);
00356   }
00357 
00358 //  item.getQuotePlugin(s);
00359 //  if (s.compare(pluginName))
00360 //  {
00361 //    s = ts2 + " - " + tr("skipping update. Source does not match destination");
00362 //    printStatusLogMessage(s);
00363 //    f.close();
00364 //    plug.close();
00365 //    return;
00366 //  }
00367 
00368   while(stream.atEnd() == 0)
00369   {
00370     ts = stream.readLine();
00371     stripJunk(ts, s);
00372 
00373     QStringList l = QStringList::split(",", s, FALSE);
00374     if (l.count() < 5)
00375       continue;
00376 
00377     // date
00378     QString date = parseDate(l[0]);
00379     Bar bar;
00380     if (bar.setDate(date))
00381     {
00382       QString ss = ts2 + " - " + tr("Bad date") + " " + l[0];
00383       qDebug("Yahoo::parseHistory: %s - Bad date %s", ts2.latin1(), l[0].latin1());
00384       printStatusLogMessage(ss);
00385       continue;
00386     }
00387 
00388     if (setTFloat(l[1], FALSE))
00389       continue;
00390     else
00391       bar.setOpen(tfloat);
00392 
00393     if (setTFloat(l[2], FALSE))
00394       continue;
00395     else
00396       bar.setHigh(tfloat);
00397 
00398     if (setTFloat(l[3], FALSE))
00399       continue;
00400     else
00401       bar.setLow(tfloat);
00402 
00403     if (setTFloat(l[4], FALSE))
00404       continue;
00405     else
00406       bar.setClose(tfloat);
00407 
00408     if (l.count() >= 6)
00409     {
00410       if (setTFloat(l[5], FALSE))
00411         continue;
00412       else
00413         bar.setVolume(tfloat);
00414     }
00415 
00416     if (bar.verify())
00417       continue;
00418 
00419     // adjusted close
00420     if (adjustment->isChecked())
00421     {
00422       double adjclose = 0;
00423       if (l.count() >= 7)
00424       {
00425         if (setTFloat(l[6], FALSE))
00426           continue;
00427         else
00428           adjclose = tfloat;
00429         // apply yahoo's adjustments through all the data, not just closing price
00430         // i.e. adjust for stock splits and dividends
00431         float factor = bar.getClose() / adjclose;
00432         if (factor != 1)
00433         {
00434           bar.setHigh(bar.getHigh() / factor);
00435           bar.setLow(bar.getLow() / factor);
00436           bar.setOpen(bar.getOpen() / factor);
00437           bar.setClose(bar.getClose() / factor);
00438           bar.setVolume(bar.getVolume() * factor);
00439         }
00440       }
00441     }
00442 
00443     plug.setBar(bar);
00444 
00445     emit signalWakeup();
00446   }
00447 
00448   f.close();
00449   plug.close();
00450 }
00451 
00452 void Yahoo::parseQuote ()
00453 {
00454   if (! data.length())
00455     return;
00456 
00457   QFile f(file);
00458   if (! f.open(IO_WriteOnly))
00459     return;
00460   QTextStream stream(&f);
00461   stream << data;
00462   f.close();
00463 
00464   f.setName(file);
00465   if (! f.open(IO_ReadOnly))
00466     return;
00467   stream.setDevice(&f);
00468 
00469   QString s = dataPath + "/";
00470   QString ts = "symbol";
00471   QString ts2;
00472   currentUrl->getData(ts, ts2);
00473   QFileInfo fi(ts2);
00474   if (fi.extension(FALSE).length())
00475     s.append(fi.extension(FALSE).upper());
00476   else
00477     s.append("US");
00478   s.append("/");
00479   s.append(ts2);
00480   
00481   if (plug.open(s, chartIndex))
00482   {
00483     QString ss(tr("Could not open db"));
00484     printStatusLogMessage(ss);
00485     f.close();
00486     return;
00487   }
00488 
00489   QString fn = ts2;
00490 
00491   // verify if this chart can be updated by this plugin
00492   DBIndexItem item;
00493   chartIndex->getIndexItem(fn, item);
00494   item.getSymbol(s);    
00495   if (! s.length())
00496   {
00497     if (plug.createNewStock())
00498     {
00499       f.close();
00500       plug.close();
00501       return;
00502     }
00503 
00504     chartIndex->getIndexItem(fn, item);
00505 
00506     item.setSymbol(ts2);
00507     item.setTitle(ts2);
00508     item.setQuotePlugin(pluginName);
00509 
00510     chartIndex->setIndexItem(fn, item);
00511   }
00512 
00513 //  item.getQuotePlugin(s);
00514 //  if (s.compare(pluginName))
00515 //  {
00516 //    s = ts2 + " - " + tr("skipping update. Source does not match destination");
00517 //    printStatusLogMessage(s);
00518 //    f.close();
00519 //    plug.close();
00520 //    return;
00521 //  }
00522 
00523   while(stream.atEnd() == 0)
00524   {
00525     ts = stream.readLine();
00526     stripJunk(ts, s);
00527 
00528     QStringList l = QStringList::split(",", s, FALSE);
00529     if (l.count() < 9 || l.count() > 10)
00530       continue;
00531 
00532     // get date
00533     QStringList l2 = QStringList::split("/", l[3], FALSE);
00534     if (l2.count() != 3)
00535       continue;
00536     QString date = l2[2];
00537     if (l2[0].toInt() < 10)
00538       date.append("0");
00539     date.append(l2[0]);
00540     if (l2[1].toInt() < 10)
00541       date.append("0");
00542     date.append(l2[1]);
00543     date.append("000000");
00544 
00545     Bar bar;
00546     if (bar.setDate(date))
00547     {
00548       QString ss = ts2 + " - " + tr("Bad date") + " " + l[3];
00549       qDebug("Yahoo::parseQuote: %s - Bad date %s", ts2.latin1(), l[3].latin1());
00550       printStatusLogMessage(ss);
00551       continue;
00552     }
00553 
00554     if (setTFloat(l[6], FALSE))
00555       continue;
00556     else
00557       bar.setOpen(tfloat);
00558 
00559     if (setTFloat(l[7], FALSE))
00560       continue;
00561     else
00562       bar.setHigh(tfloat);
00563 
00564     if (setTFloat(l[8], FALSE))
00565       continue;
00566     else
00567       bar.setLow(tfloat);
00568 
00569     if (setTFloat(l[2], FALSE))
00570       continue;
00571     else
00572       bar.setClose(tfloat);
00573 
00574     if (l.count() == 10)
00575     {
00576       if (setTFloat(l[9], FALSE))
00577         continue;
00578       else
00579         bar.setVolume(tfloat);
00580     }
00581 
00582     if (bar.verify())
00583       continue;
00584       
00585     plug.setBar(bar);
00586 
00587     emit signalWakeup();
00588   }
00589 
00590   f.close();
00591   plug.close();
00592 }
00593 
00594 QString Yahoo::parseDate (QString &d)
00595 {
00596   QString s;
00597 
00598   QStringList l = QStringList::split("-", d, FALSE);
00599   if (l.count() != 3)
00600     return s;
00601 
00602   bool ok;
00603   int t = l[1].toInt(&ok);
00604   if (ok)
00605   {
00606     // new date format YYYY-MM-DD
00607     s = l[0] + l[1] + l[2];
00608     s.append("000000");
00609     return s;
00610   }
00611 
00612   // old date format
00613 
00614   // get year
00615   s = l[2];
00616   if (s.toInt() > 29)
00617     s.prepend("19");
00618   else
00619     s.prepend("20");
00620 
00621   // get month
00622   t = monthList.findIndex(l[1]);
00623   if (t == -1)
00624     return s;
00625   if (t < 9)
00626     s.append("0" + QString::number(t + 1));
00627   else
00628     s.append(QString::number(t + 1));
00629 
00630   // get day
00631   if (l[0].toInt() < 10)
00632     s.append("0");
00633   s.append(l[0]);
00634   s.append("000000");
00635 
00636   return s;
00637 }
00638 
00639 void Yahoo::loadSettings ()
00640 {
00641   QSettings settings;
00642   settings.beginGroup("/Qtstalker/Yahoo plugin");
00643 
00644   QString s = settings.readEntry("/Adjustment", "0");
00645   adjustment->setChecked(s.toInt());
00646   
00647   s = settings.readEntry("/Method", "History");
00648   setMethod(s);
00649   
00650   s = settings.readEntry("/Retries", "3");
00651   retrySpin->setValue(s.toInt());
00652   
00653   s = settings.readEntry("/Timeout", "15");
00654   timeoutSpin->setValue(s.toInt());
00655   
00656   s = settings.readEntry("/AllSymbols", "1");
00657   allSymbols->setChecked(s.toInt());
00658   allSymbolsChecked(s.toInt());
00659   
00660   settings.endGroup();
00661 }
00662 
00663 void Yahoo::saveSettings ()
00664 {
00665   QSettings settings;
00666   settings.beginGroup("/Qtstalker/Yahoo plugin");
00667   
00668   settings.writeEntry("/Adjustment", QString::number(adjustment->isChecked()));
00669   settings.writeEntry("/Method", method->currentText());
00670   settings.writeEntry("/Retries", retrySpin->text());
00671   settings.writeEntry("/Timeout", timeoutSpin->text());
00672   settings.writeEntry("/AllSymbols", QString::number(allSymbols->isChecked()));
00673 
00674   settings.endGroup();
00675 }
00676 
00677 void Yahoo::printErrorList ()
00678 {
00679   int loop;
00680   for (loop = 0; loop < (int) errorList.count(); loop++)
00681   {
00682     QString s = tr("Unable to download") + " " + errorList[loop];
00683     printStatusLogMessage(s);
00684   }
00685 }       
00686 
00687 void Yahoo::cancelUpdate ()
00688 {
00689   if (op)
00690   {
00691     timer->stop();
00692     op->stop();
00693   }
00694   
00695   downloadComplete();
00696   printStatusLogMessage(stringCanceled);
00697   progressBar->reset();
00698 }
00699 
00700 void Yahoo::parseFundamental ()
00701 {
00702   if (! data.length())
00703     return;
00704 
00705   if (data.contains("data available"))
00706     return;
00707     
00708   QStringList l = QStringList::split("yfnc_tablehead1", data, FALSE);
00709   int loop;
00710   Setting fund;
00711   for (loop = 1; loop < (int) l.count(); loop++)
00712   {
00713     QString k = l[loop];
00714     int p = k.find(">", 0, TRUE);
00715     if (p == -1)
00716       continue;
00717     p++;
00718     k.remove(0, p);
00719     p = k.find("<", 0, TRUE);
00720     if (p == -1)
00721       continue;
00722     k.truncate(p);
00723     
00724     if (k.contains("&sup"))
00725       k.truncate(k.length() - 6);
00726     if (k.contains("&amp"))
00727       k.remove(k.find("&", 0, TRUE), 5);
00728     k = k.stripWhiteSpace();
00729     if (! k.length())
00730       continue;
00731     
00732     QString d = l[loop];
00733     p = d.find("yfnc_tabledata1", 0, TRUE);
00734     if (p == -1)
00735       continue;
00736     p = d.find(">", p, TRUE);
00737     if (p == -1)
00738       continue;
00739     p++;
00740     d.remove(0, p);
00741     p = d.find("<", 0, TRUE);
00742     if (p == -1)
00743       continue;
00744     d.truncate(p);
00745     d = d.stripWhiteSpace();  
00746     if (! d.length())
00747       continue;
00748 
00749     fund.setData(k, d);
00750   }
00751       
00752   QString s = dataPath + "/";
00753   QString ts = "symbol";
00754   QString ts2;
00755   currentUrl->getData(ts, ts2);
00756   QFileInfo fi(ts2);
00757   if (fi.extension(FALSE).length())
00758     s.append(fi.extension(FALSE).upper());
00759   else
00760     s.append("US");
00761   s.append("/");
00762   s.append(ts2);
00763   
00764   if (plug.open(s, chartIndex))
00765   {
00766     QString ss(tr("Could not open db"));
00767     printStatusLogMessage(ss);
00768     return;
00769   }
00770 
00771   QString fn = ts2;
00772   
00773   // verify if this chart can be updated by this plugin
00774   DBIndexItem item;
00775   chartIndex->getIndexItem(fn, item);
00776   item.getSymbol(s);  
00777   if (! s.length())
00778   {
00779     if(plug.createNewStock())
00780     {
00781       plug.close();
00782       return;
00783     }
00784 
00785     chartIndex->getIndexItem(fn, item);
00786 
00787     item.setQuotePlugin(pluginName);
00788     item.setSymbol(ts2);
00789     QString title = ts2;
00790     int p = data.find("yfnc_leftnav1", 0, TRUE);
00791     if (p != -1)
00792     {
00793       p = data.find("b>", p, TRUE);
00794       if (p != -1)
00795       {
00796         p = p + 2;
00797         int p2 = data.find("<", p, TRUE);
00798         if (p2 != -1)
00799         {
00800           s = data.mid(p, p2 - p);
00801           if (s.length())
00802             title = s;
00803         }
00804       }
00805     }
00806     item.setTitle(title);
00807 
00808     chartIndex->setIndexItem(fn, item);
00809   }
00810   else
00811   {
00812     QString s2;
00813     item.getTitle(s2);
00814     if (! s.compare(s2))
00815     {
00816       int p = data.find("yfnc_leftnav1", 0, TRUE);
00817       if (p != -1)
00818       {
00819         p = data.find("b>", p, TRUE);
00820         if (p != -1)
00821         {
00822           p = p + 2;
00823           int p2 = data.find("<", p, TRUE);
00824           if (p2 != -1)
00825           {
00826             s = data.mid(p, p2 - p);
00827             if (s.length())
00828             {
00829               item.setTitle(s);
00830               chartIndex->setIndexItem(fn, item);
00831             }
00832           }
00833         }
00834       }
00835     }
00836   }
00837   
00838 //  item.getQuotePlugin(s);
00839 //  if (s.compare(pluginName))
00840 //  {
00841 //    s = ts2 + " - " + tr("skipping update. Source does not match destination");
00842 //    printStatusLogMessage(s);
00843 //    plug.close();
00844 //    return;
00845 //  }
00846 
00847   // include date of this update
00848   QDate dt = QDate::currentDate();
00849   ts = "updateDate";
00850   ts2 = dt.toString("yyyy-MM-dd");
00851   fund.setData(ts, ts2);
00852   fund.getString(ts2);
00853   ts = "Fundamentals";
00854   chartIndex->setFundamentals(fn, ts2);
00855     
00856   plug.close();
00857 
00858   emit signalWakeup();
00859 }
00860 
00861 void Yahoo::loadAllSymbols ()
00862 {
00863   symbolList.clear();
00864   
00865   QDir dir(dataPath);
00866   int loop;
00867   for (loop = 2; loop < (int) dir.count(); loop++)
00868   {
00869     QString s = dir.absPath() + "/" + dir[loop];
00870     QFileInfo fi(s);
00871     if (fi.isDir())
00872     {
00873       int loop2;
00874       QDir dir2(s);
00875       for (loop2 = 2; loop2 < (int) dir2.count(); loop2++)
00876         symbolList.append(dir2[loop2]);
00877     }
00878   }
00879   
00880   symbolList.sort();
00881 }
00882 
00883 void Yahoo::createHistoryUrls (QString &d)
00884 {
00885   if (sdate->date().daysTo(edate->date()) > 199) 
00886   { 
00887     QDate tsdate = sdate->date();
00888     QDate tedate = sdate->date();
00889           
00890     while (tsdate <= edate->date())
00891     {
00892       tsdate = tedate;
00893       tedate = tsdate.addDays(199);
00894       if (tedate.dayOfWeek() == 6)
00895         tedate = tedate.addDays(-1);
00896       else
00897       {
00898         if (tedate.dayOfWeek() == 7)
00899           tedate = tedate.addDays(-2);
00900       }
00901             
00902       if (tedate > edate->date())
00903         tedate = edate->date();
00904             
00905       QString s = "http://ichart.yahoo.com/table.csv?s=";
00906       s.append(d);
00907       s.append("&a=");
00908       s.append(QString::number(tsdate.month() - 1));
00909       s.append("&b=");
00910       s.append(tsdate.toString("dd"));
00911       s.append("&c=");
00912       s.append(tsdate.toString("yy"));
00913       s.append("&d=");
00914       s.append(QString::number(tedate.month() - 1));
00915       s.append("&e=");
00916       s.append(tedate.toString("dd"));
00917       s.append("&f=");
00918       s.append(tedate.toString("yy"));
00919       s.append("&g=d&q=q&y=0&x=.csv");
00920             
00921       Setting *set = new Setting;
00922       QString ts = "url";
00923       set->setData(ts, s);
00924       ts = "symbol";
00925       set->setData(ts, d);
00926       url.append(set);
00927             
00928       if (tedate == edate->date())
00929         break;
00930     }
00931   }
00932   else 
00933   { 
00934     QString s = "http://ichart.yahoo.com/table.csv?s=";
00935     s.append(d);
00936     s.append("&a=");
00937     s.append(QString::number(sdate->date().month() - 1));
00938     s.append("&b=");
00939     s.append(sdate->date().toString("dd"));
00940     s.append("&c=");
00941     s.append(sdate->date().toString("yy"));
00942     s.append("&d=");
00943     s.append(QString::number(edate->date().month() - 1));
00944     s.append("&e=");
00945     s.append(edate->date().toString("dd"));
00946     s.append("&f=");
00947     s.append(edate->date().toString("yy"));
00948     s.append("&g=d&q=q&y=0&x=.csv");
00949     
00950     Setting *set = new Setting;
00951     QString ts = "url";
00952     set->setData(ts, s);
00953     ts = "symbol";
00954     set->setData(ts, d);
00955     url.append(set);
00956   }
00957 }
00958 
00959 void Yahoo::createAutoHistoryUrls (QString &path, QString &d)
00960 {
00961   if (plug.open(path, chartIndex))
00962   {
00963     qDebug("Yahoo::createAutoHistoryUrls:could not open db");
00964     return;
00965   }
00966 
00967   QFileInfo fi(path);
00968   QString fn = fi.fileName();
00969 
00970   // verify if this chart can be updated by this plugin
00971   QString s;
00972   DBIndexItem item;
00973   chartIndex->getIndexItem(fn, item);
00974   item.getQuotePlugin(s);
00975   if (! s.length())
00976   {
00977     item.setQuotePlugin(pluginName);
00978     chartIndex->setIndexItem(fn, item);
00979   }
00980 //  else
00981 //  {
00982 //    if (s.compare(pluginName))
00983 //    {
00984 //      qDebug("Yahoo::createAutoHistoryUrls:source not same as destination");
00985 //      plug.close();
00986 //      return;
00987 //    }
00988 //  }
00989 
00990   QDate edt = QDate::currentDate();        
00991   if (edt.dayOfWeek() == 6)
00992     edt = edt.addDays(-1);
00993   else
00994   {
00995     if (edt.dayOfWeek() == 7)
00996       edt = edt.addDays(-2);
00997   }
00998         
00999   Bar bar;
01000   plug.getLastBar(bar);
01001   if (bar.getEmptyFlag())
01002   {
01003     QDate dt = edt;
01004     dt = dt.addDays(-365);
01005     s = dt.toString("yyyyMMdd000000");
01006     bar.setDate(s);
01007   }
01008 
01009   QDateTime dt;
01010   bar.getDate(dt);
01011   if (dt.date() == edt)
01012   {
01013 //    qDebug("Yahoo::createAutoHistoryUrls:barDate == endDate");
01014     plug.close();
01015     return;
01016   }
01017                 
01018   s = "http://ichart.yahoo.com/table.csv?s=";
01019   s.append(d);
01020   s.append("&a=");
01021   s.append(QString::number(dt.date().month() - 1));
01022   s.append("&b=");
01023   s.append(dt.toString("dd"));
01024   s.append("&c=");
01025   s.append(dt.toString("yy"));
01026   s.append("&d=");
01027   s.append(QString::number(edt.month() - 1));
01028   s.append("&e=");
01029   s.append(edt.toString("dd"));
01030   s.append("&f=");
01031   s.append(edt.toString("yy"));
01032   s.append("&g=d&q=q&y=0&x=.csv");
01033         
01034   plug.close();
01035   
01036   Setting *set = new Setting;
01037   QString ts = "url";
01038   set->setData(ts, s);
01039   ts = "symbol";
01040   set->setData(ts, d);
01041   url.append(set);
01042 }
01043 
01044 void Yahoo::createQuoteUrls (QString &d)
01045 {
01046   // multiple quotes: download.finance.yahoo.com/d/quotes.csv?s=IBM+RHAT+SCOX+MSFT+GOLD&f=sl1d1t1c1ohgv 
01047   // multiple close only: download.finance.yahoo.com/d/quotes.csv?s=IBM+RHAT+SCOX+MSFT+GOLD&f=sl1
01048   // URLPrefix = "http://download.finance.yahoo.com/d/quotes.csv?s=";
01049   // URLPostfix = "&f=snl1d1t1c1ohgv&e=.csv";   
01050   QString s = "http://download.finance.yahoo.com/d/quotes.csv?s=";
01051   s.append(d);
01052   s.append("&f=snl1d1t1c1ohgv&e=.csv");
01053   
01054   Setting *set = new Setting;
01055   QString ts = "url";
01056   set->setData(ts, s);
01057   ts = "symbol";
01058   set->setData(ts, d);
01059   url.append(set);
01060 }
01061 
01062 void Yahoo::createFundamentalUrls (QString &d)
01063 {
01064   QString s = "http://finance.yahoo.com/q/ks?s=" + d;
01065   Setting *set = new Setting;
01066   QString ts = "url";
01067   set->setData(ts, s);
01068   ts = "symbol";
01069   set->setData(ts, d);
01070   url.append(set);
01071 }
01072 
01073 void Yahoo::newStock ()
01074 {
01075   bool ok = FALSE;
01076   QString symbols = QInputDialog::getText(tr("New Yahoo Symbols"),
01077                                           tr("Enter symbols to add. Note: separate symbols with a space"),
01078                                           QLineEdit::Normal,
01079                                           QString::null,
01080                                           &ok,
01081                                           this);
01082   if (! symbols.length())
01083     return;
01084 
01085   QStringList l = QStringList::split(" ", symbols, FALSE);
01086   
01087   QString s;
01088   config.getData(Config::DataPath, s);
01089   s.append("/Stocks");
01090   QDir dir(s);
01091   if (! dir.exists(s))
01092   {
01093     if (! dir.mkdir(s))
01094     {
01095       qDebug("YahooDialog::newStock: Unable to create %s directory", s.latin1());
01096       return;
01097     }
01098   }
01099   
01100   if (! dir.exists(dataPath))
01101   {
01102     if (! dir.mkdir(dataPath))
01103     {
01104       qDebug("YahooDialog::newStock: Unable to create %s directory", dataPath.latin1());
01105       return;
01106     }
01107   }
01108   
01109   int loop;
01110   for (loop = 0; loop < (int) l.count(); loop++)
01111   {
01112     QString exchange;
01113     QString s = dataPath + "/";
01114     QFileInfo fi(l[loop]);
01115     if (fi.extension(FALSE).length())
01116     {
01117       exchange = fi.extension(FALSE).upper();
01118       s.append(fi.extension(FALSE).upper());
01119       if (! dir.exists(s, TRUE))
01120       {
01121         if (! dir.mkdir(s))
01122         {
01123           qDebug("YahooDialog::newStock: Unable to create %s directory", s.latin1());
01124           continue;
01125         }
01126       }
01127     }
01128     else
01129     {
01130       s.append("US");
01131       if (! dir.exists(s, TRUE))
01132       {
01133         if (! dir.mkdir(s))
01134         {
01135           qDebug("YahooDialog::newStock: Unable to create %s directory", s.latin1());
01136           continue;
01137         }
01138       }
01139     }
01140     s.append("/");
01141     s.append(l[loop]);
01142     if (dir.exists(s, TRUE))
01143       continue;
01144 
01145     if (plug.open(s, chartIndex))
01146     {
01147       qDebug("YahooDialog::newStock: could not open db %s", s.latin1());
01148       plug.close();
01149       continue;
01150     }
01151           
01152     plug.createNewStock();
01153 
01154     QFileInfo fi2(s);
01155     QString fn = fi2.fileName();
01156     DBIndexItem item;
01157     chartIndex->getIndexItem(fn, item);
01158     getExchange(exchange, s);
01159     item.setExchange(s);
01160     chartIndex->setIndexItem(fn, item);
01161 
01162     plug.close();
01163   }
01164 }
01165 
01166 void Yahoo::setMethod (QString d)
01167 {
01168   if (! d.compare("History"))
01169   {
01170     method->setCurrentItem(0);
01171     methodChanged(0);
01172   }
01173   else
01174   {
01175     if (! d.compare("Auto History"))
01176     {
01177       method->setCurrentItem(1);
01178       methodChanged(1);
01179     }
01180     else
01181     {
01182       if (! d.compare("Quote"))
01183       {
01184         method->setCurrentItem(2);
01185         methodChanged(2);
01186       }
01187       else
01188       {
01189         method->setCurrentItem(3);
01190         methodChanged(3);
01191       }
01192     }
01193   }
01194 }
01195 
01196 void Yahoo::methodChanged (int d)
01197 {
01198   switch (d)
01199   {
01200     case 0:
01201       adjustment->setEnabled(TRUE);
01202       sdate->setEnabled(TRUE);
01203       edate->setEnabled(TRUE);
01204       break;
01205     case 1:
01206       adjustment->setEnabled(TRUE);
01207       sdate->setEnabled(FALSE);
01208       edate->setEnabled(FALSE);
01209       break;
01210     case 2:
01211       adjustment->setEnabled(FALSE);
01212       sdate->setEnabled(FALSE);
01213       edate->setEnabled(FALSE);
01214       break;
01215     case 3:
01216       adjustment->setEnabled(FALSE);
01217       sdate->setEnabled(FALSE);
01218       edate->setEnabled(FALSE);
01219       break;
01220     default:
01221       break;
01222   }
01223 }
01224 
01225 void Yahoo::allSymbolsChecked (bool d)
01226 {
01227   if (d)
01228   {
01229     list->setEnabled(FALSE);
01230     loadAllSymbols();
01231   }
01232   else
01233   {
01234     list->setEnabled(TRUE);
01235     list->getFile(fileList);
01236     int loop;
01237     symbolList.clear();
01238     for (loop = 0; loop < (int) fileList.count(); loop++)
01239     {
01240       QFileInfo fi(fileList[loop]);
01241       symbolList.append(fi.fileName());
01242     }
01243   }
01244 }
01245 
01246 void Yahoo::getExchange (QString &ext, QString &exchange)
01247 {
01248   while (1)
01249   {
01250     if (! ext.compare("BA"))
01251     {
01252       exchange = QString::number(Exchange::BASE);
01253       break;
01254     }
01255 
01256     if (! ext.compare("VA"))
01257     {
01258       exchange = QString::number(Exchange::VASE);
01259       break;
01260     }
01261 
01262     if (! ext.compare("AX"))
01263     {
01264       exchange = QString::number(Exchange::AXSE);
01265       break;
01266     }
01267 
01268     if (! ext.compare("SA"))
01269     {
01270       exchange = QString::number(Exchange::SASE);
01271       break;
01272     }
01273 
01274     if (! ext.compare("TO"))
01275     {
01276       exchange = QString::number(Exchange::TOSE);
01277       break;
01278     }
01279 
01280     if (! ext.compare("V"))
01281     {
01282       exchange = QString::number(Exchange::TSXVE);
01283       break;
01284     }
01285 
01286     if (! ext.compare("SS"))
01287     {
01288       exchange = QString::number(Exchange::SSSE);
01289       break;
01290     }
01291 
01292     if (! ext.compare("SZ"))
01293     {
01294       exchange = QString::number(Exchange::SZSE);
01295       break;
01296     }
01297 
01298     if (! ext.compare("CO"))
01299     {
01300       exchange = QString::number(Exchange::COSE);
01301       break;
01302     }
01303 
01304     if (! ext.compare("PA"))
01305     {
01306       exchange = QString::number(Exchange::PASE);
01307       break;
01308     }
01309 
01310     if (! ext.compare("BE"))
01311     {
01312       exchange = QString::number(Exchange::BESE);
01313       break;
01314     }
01315 
01316     if (! ext.compare("BM"))
01317     {
01318       exchange = QString::number(Exchange::BMSE);
01319       break;
01320     }
01321 
01322     if (! ext.compare("DU"))
01323     {
01324       exchange = QString::number(Exchange::DUSE);
01325       break;
01326     }
01327 
01328     if (! ext.compare("F"))
01329     {
01330       exchange = QString::number(Exchange::FSE);
01331       break;
01332     }
01333 
01334     if (! ext.compare("HM"))
01335     {
01336       exchange = QString::number(Exchange::HMSE);
01337       break;
01338     }
01339 
01340     if (! ext.compare("HA"))
01341     {
01342       exchange = QString::number(Exchange::HASE);
01343       break;
01344     }
01345 
01346     if (! ext.compare("MU"))
01347     {
01348       exchange = QString::number(Exchange::MUSE);
01349       break;
01350     }
01351 
01352     if (! ext.compare("SG"))
01353     {
01354       exchange = QString::number(Exchange::SGSE);
01355       break;
01356     }
01357 
01358     if (! ext.compare("DE"))
01359     {
01360       exchange = QString::number(Exchange::XETRA);
01361       break;
01362     }
01363 
01364     if (! ext.compare("HK"))
01365     {
01366       exchange = QString::number(Exchange::HKSE);
01367       break;
01368     }
01369 
01370     if (! ext.compare("BO"))
01371     {
01372       exchange = QString::number(Exchange::BOSE);
01373       break;
01374     }
01375 
01376     if (! ext.compare("NS"))
01377     {
01378       exchange = QString::number(Exchange::NSEOI);
01379       break;
01380     }
01381 
01382     if (! ext.compare("JK"))
01383     {
01384       exchange = QString::number(Exchange::JKSE);
01385       break;
01386     }
01387 
01388     if (! ext.compare("TA"))
01389     {
01390       exchange = QString::number(Exchange::TASE);
01391       break;
01392     }
01393 
01394     if (! ext.compare("MI"))
01395     {
01396       exchange = QString::number(Exchange::MISE);
01397       break;
01398     }
01399 
01400     if (! ext.compare("KS"))
01401     {
01402       exchange = QString::number(Exchange::KSSE);
01403       break;
01404     }
01405 
01406     if (! ext.compare("KQ"))
01407     {
01408       exchange = QString::number(Exchange::KOSDAQ);
01409       break;
01410     }
01411 
01412     if (! ext.compare("MX"))
01413     {
01414       exchange = QString::number(Exchange::MXSE);
01415       break;
01416     }
01417 
01418     if (! ext.compare("AS"))
01419     {
01420       exchange = QString::number(Exchange::ASSE);
01421       break;
01422     }
01423 
01424     if (! ext.compare("NZ"))
01425     {
01426       exchange = QString::number(Exchange::NZSE);
01427       break;
01428     }
01429 
01430     if (! ext.compare("OL"))
01431     {
01432       exchange = QString::number(Exchange::OLSE);
01433       break;
01434     }
01435 
01436     if (! ext.compare("SI"))
01437     {
01438       exchange = QString::number(Exchange::SISE);
01439       break;
01440     }
01441 
01442     if (! ext.compare("BC"))
01443     {
01444       exchange = QString::number(Exchange::BCSE);
01445       break;
01446     }
01447 
01448     if (! ext.compare("BI"))
01449     {
01450       exchange = QString::number(Exchange::BISE);
01451       break;
01452     }
01453 
01454     if (! ext.compare("MF"))
01455     {
01456       exchange = QString::number(Exchange::MFIM);
01457       break;
01458     }
01459 
01460     if (! ext.compare("MC"))
01461     {
01462       exchange = QString::number(Exchange::MCCATS);
01463       break;
01464     }
01465 
01466     if (! ext.compare("MA"))
01467     {
01468       exchange = QString::number(Exchange::MASE);
01469       break;
01470     }
01471 
01472     if (! ext.compare("ST"))
01473     {
01474       exchange = QString::number(Exchange::STSE);
01475       break;
01476     }
01477 
01478     if (! ext.compare("SW"))
01479     {
01480       exchange = QString::number(Exchange::SWE);
01481       break;
01482     }
01483 
01484     if (! ext.compare("TWO"))
01485     {
01486       exchange = QString::number(Exchange::TWOOTC);
01487       break;
01488     }
01489 
01490     if (! ext.compare("TW"))
01491     {
01492       exchange = QString::number(Exchange::TWSE);
01493       break;
01494     }
01495 
01496     if (! ext.compare("L"))
01497     {
01498       exchange = QString::number(Exchange::LSE);
01499       break;
01500     }
01501 
01502     break;
01503   }
01504 }
01505 
01506 //***********************************************************************
01507 //***********************************************************************
01508 //***********************************************************************
01509 
01510 QuotePlugin * createQuotePlugin ()
01511 {
01512   Yahoo *o = new Yahoo;
01513   return ((QuotePlugin *) o);
01514 }
01515