//Get unread news or all news for last year const bool getNewsRSS(std::vector<WebsiteNews>& WebsiteNewsList) { wxString RssContent; if (site_content(mmex::weblink::NewsRSS, RssContent) != wxURL_NOERR) return false; wxStringInputStream RssContentStream(RssContent); wxXmlDocument RssDocument; if (!RssDocument.Load(RssContentStream)) return false; if (RssDocument.GetRoot()->GetName() != "rss") return false; const wxString news_last_read_date_str = Model_Setting::instance().GetStringSetting(INIDB_NEWS_LAST_READ_DATE, ""); wxDate news_last_read_date; if (!news_last_read_date.ParseISODate(news_last_read_date_str)) news_last_read_date = wxDateTime::Today().Subtract(wxDateSpan::Year()); wxXmlNode* RssRoot = RssDocument.GetRoot()->GetChildren()->GetChildren(); while (RssRoot) { if (RssRoot->GetName() == "item") { WebsiteNews website_news; wxXmlNode* News = RssRoot->GetChildren(); while (News) { wxString ElementName = News->GetName(); if (ElementName == "title") website_news.Title = News->GetChildren()->GetContent(); else if (ElementName == "link") website_news.Link = News->GetChildren()->GetContent(); else if (ElementName == "description") website_news.Description = News->GetChildren()->GetContent(); else if (ElementName == "pubDate") { wxDateTime Date; const wxString DateString = News->GetChildren()->GetContent(); if (!DateString.IsEmpty()) Date.ParseDate(DateString); if (!Date.IsValid()) Date = wxDateTime::Today().Subtract(wxDateSpan::Year()); //Seems invalid date, mark it as 1 year old website_news.Date = Date; } News = News->GetNext(); } wxLogDebug("%s - %s", news_last_read_date.FormatISODate(), website_news.Date.FormatISODate()); if (news_last_read_date.IsEarlierThan(website_news.Date)) WebsiteNewsList.push_back(website_news); } RssRoot = RssRoot->GetNext(); } if (WebsiteNewsList.size() == 0) return false; return true; }
const bool mmHomePagePanel::getNewsRSS(std::vector<WebsiteNews>& WebsiteNewsList) { wxString RssContent; if (site_content(mmex::weblink::NewsRSS, RssContent) != wxURL_NOERR) return false; wxStringInputStream RssContentStream(RssContent); wxXmlDocument RssDocument; if (!RssDocument.Load(RssContentStream)) return false; if (RssDocument.GetRoot()->GetName() != "rss") return false; wxXmlNode* RssRoot = RssDocument.GetRoot()->GetChildren()->GetChildren(); while (RssRoot) { if (RssRoot->GetName() == "item") { WebsiteNews website_news; wxXmlNode* News = RssRoot->GetChildren(); while(News) { wxString ElementName = News->GetName(); if (ElementName == "title") website_news.Title = News->GetChildren()->GetContent(); else if (ElementName == "link") website_news.Link = News->GetChildren()->GetContent(); else if (ElementName == "description") website_news.Description = News->GetChildren()->GetContent(); else if (ElementName == "pubDate") { wxDateTime Date = wxDateTime::Today(); wxString DateString = News->GetChildren()->GetContent(); if (!DateString.IsEmpty()) Date.ParseDate(DateString); if (!Date.IsValid()) Date = wxDateTime::Today(); website_news.Date = Date; } News = News->GetNext(); } WebsiteNewsList.push_back(website_news); } RssRoot = RssRoot->GetNext(); } if (WebsiteNewsList.size() == 0) return false; return true; }
bool mmMainCurrencyDialog::HistoryDownloadBce() { wxString XmlContent; if (site_content(mmex::weblink::BceCurrencyHistory, XmlContent) != wxURL_NOERR) return false; wxStringInputStream XmlContentStream(XmlContent); wxXmlDocument XmlDocument; if (!XmlDocument.Load(XmlContentStream)) return false; if (XmlDocument.GetRoot()->GetName() != "gesmes:Envelope") return false; wxXmlNode* XmlRoot = XmlDocument.GetRoot()->GetChildren(); while (XmlRoot->GetName() != "Cube") XmlRoot = XmlRoot->GetNext(); if (XmlRoot->GetName() != "Cube") return false; double Rate; wxDateTime HistoryDate; XmlRoot = XmlRoot->GetChildren(); //Go inside <Cube> while (XmlRoot) //<Cube time="2015-07-03"> { HistoryDate.ParseDate(XmlRoot->GetAttribute("time")); CurrencyHistoryRate CurrencyHistory; wxXmlNode* XmlRate = XmlRoot->GetChildren(); while (XmlRate) //<Cube currency="USD" rate="1.1096"/> { CurrencyHistory.BaseCurrency = "EUR"; CurrencyHistory.Date = HistoryDate; CurrencyHistory.Currency = XmlRate->GetAttribute("currency"); XmlRate->GetAttribute("rate").ToDouble(&Rate); CurrencyHistory.Rate = Rate; _BceCurrencyHistoryRatesList.push_back(CurrencyHistory); XmlRate = XmlRate->GetNext(); } XmlRoot = XmlRoot->GetNext(); } if (_BceCurrencyHistoryRatesList.size() == 0) return false; return true; }
void mmStockDialog::OnHistoryDownloadButton(wxCommandEvent& /*event*/) { /* Example stock history download: https://code.google.com/p/yahoo-finance-managed/wiki/csvHistQuotesDownload */ if (m_stock->SYMBOL.IsEmpty()) return; const wxDateTime& StartDate = Model_Stock::PURCHASEDATE(m_stock); wxDateTime EndDate = wxDate::Today(); const wxTimeSpan time = EndDate - StartDate; long intervalMonths = EndDate.GetMonth() - StartDate.GetMonth() + 12 * (EndDate.GetYear() - StartDate.GetYear()) - (EndDate.GetDay() < StartDate.GetDay()); //Define frequency enum { DAILY, WEEKLY, MONTHLY }; wxArrayString FreqStrs; FreqStrs.Add(_("Days")); FreqStrs.Add(_("Weeks")); if (intervalMonths > 0) FreqStrs.Add(_("Months")); int freq = wxGetSingleChoiceIndex(_("Specify type frequency of stock history") , _("Stock History Update"), FreqStrs); long interval = 0; switch (freq) { case DAILY: interval = time.GetDays(); break; case WEEKLY: interval = time.GetWeeks(); break; case MONTHLY: interval = intervalMonths; break; default: return; } int nrPrices = (int) wxGetNumberFromUser(_("Specify how many stock history prices download from purchase date") , wxString::Format(_("Number of %s:"), FreqStrs.Item(freq).Lower()), _("Stock History Update") , interval, 1L, 9999L, this, wxDefaultPosition); if (nrPrices <= 0) { mmErrorDialogs::MessageInvalid(this, FreqStrs[freq]); return; } else { switch (freq) { case DAILY: EndDate = wxDate(StartDate).Add(wxDateSpan::Days(nrPrices)); break; case WEEKLY: EndDate = wxDate(StartDate).Add(wxDateSpan::Weeks(nrPrices)); break; case MONTHLY: EndDate = wxDate(StartDate).Add(wxDateSpan::Months(nrPrices)); break; default: break; } } if (EndDate > wxDate::Today()) { mmErrorDialogs::MessageWarning(this, _("End date is in the future\nQuotes will be updated until today") , _("Stock History Error")); EndDate = wxDate::Today(); } wxString CSVQuotes; wxString URL = mmex::weblink::YahooQuotesHistory; URL += m_stock->SYMBOL; URL += wxString::Format("&a=%i", StartDate.GetMonth()); URL += wxString::Format("&b=%i", StartDate.GetDay()); URL += wxString::Format("&c=%i", StartDate.GetYear()); URL += wxString::Format("&d=%i", EndDate.GetMonth()); URL += wxString::Format("&e=%i", EndDate.GetDay()); URL += wxString::Format("&f=%i", EndDate.GetYear()); switch (freq) { case DAILY: URL += "&g=d"; break; case WEEKLY: URL += "&g=w"; break; case MONTHLY: URL += "&g=m"; break; default: break; } URL += "&ignore=.csv"; wxLogDebug("Start Date:%s End Date:%s URL:%s", StartDate.FormatISODate(), EndDate.FormatISODate(), URL); int err_code = site_content(URL, CSVQuotes); if (err_code != wxURL_NOERR) { if (err_code == -1) CSVQuotes = _("Stock history not found!"); mmErrorDialogs::MessageError(this, CSVQuotes, _("Stock History Error")); return; } double dPrice; wxString dateStr; Model_StockHistory::Data *data; wxStringTokenizer tkz(CSVQuotes, "\r\n"); Model_StockHistory::instance().Savepoint(); while (tkz.HasMoreTokens()) { wxStringTokenizer tkzSingleLine(tkz.GetNextToken(), ","); std::vector<wxString> tokens; while (tkzSingleLine.HasMoreTokens()) { const wxString& token = tkzSingleLine.GetNextToken(); tokens.push_back(token); } if (tokens[0].Contains("-")) { dateStr = tokens[0]; tokens[6].ToDouble(&dPrice); if (Model_StockHistory::instance().find( Model_StockHistory::SYMBOL(m_stock->SYMBOL), Model_StockHistory::DB_Table_STOCKHISTORY_V1::DATE(dateStr) ).size() == 0 && dPrice > 0) { data = Model_StockHistory::instance().create(); data->SYMBOL = m_stock->SYMBOL; data->DATE = dateStr; data->VALUE = dPrice; data->UPDTYPE = Model_StockHistory::ONLINE; Model_StockHistory::instance().save(data); } } } Model_StockHistory::instance().ReleaseSavepoint(); showStockHistory(); }
/*** Trigger a quote download ***/ bool mmStocksPanel::onlineQuoteRefresh(wxString& sError) { if(listCtrlAccount_->m_stocks.size() < 1) { sError = _("Nothing to update"); return false; } //Symbol, (Amount, Name) std::map<wxString, std::pair<double, wxString> > stocks_data; wxString site = ""; for (const auto &stock : listCtrlAccount_->m_stocks) { const wxString symbol = stock.SYMBOL.Upper(); if (!symbol.IsEmpty()) { if (stocks_data.find(symbol) == stocks_data.end()) { stocks_data[symbol] = std::make_pair(stock.CURRENTPRICE, ""); site << symbol << "+"; } } } if (site.Right(1).Contains("+")) site.RemoveLast(1); //Sample: http://finance.yahoo.com/d/quotes.csv?s=SBER.ME+GAZP.ME&f=sl1c4n&e=.csv //Sample CSV: "SBER.ME",85.49,"RUB","SBERBANK" site = wxString::Format(mmex::weblink::YahooQuotes, site); refresh_button_->SetBitmapLabel(wxBitmap(wxImage(led_yellow_xpm).Scale(16,16))); stock_details_->SetLabelText(_("Connecting...")); wxString sOutput; int err_code = site_content(site, sOutput); if (err_code != wxURL_NOERR) { sError = sOutput; return false; } //--// wxString StockSymbolWithSuffix, sName, StockQuoteCurrency; double dPrice = 0.0; wxStringTokenizer tkz(sOutput, "\r\n"); while (tkz.HasMoreTokens()) { const wxString csvline = tkz.GetNextToken(); StockSymbolWithSuffix = ""; StockQuoteCurrency = ""; wxRegEx pattern("\"([^\"]+)\",([^,][0-9.]+),\"([^\"]*)\",\"([^\"]*)\""); if (pattern.Matches(csvline)) { StockSymbolWithSuffix = pattern.GetMatch(csvline, 1); pattern.GetMatch(csvline, 2).ToDouble(&dPrice); StockQuoteCurrency = pattern.GetMatch(csvline, 3); sName = pattern.GetMatch(csvline, 4); } bool updated = !StockSymbolWithSuffix.IsEmpty(); /* HACK FOR GBP http://sourceforge.net/p/moneymanagerex/bugs/414/ http://sourceforge.net/p/moneymanagerex/bugs/360/ 1. If the share has GBp as currency, its downloaded value in pence 2. If the share has another currency, we don't need to modify the price */ if (updated && dPrice > 0) { if (StockQuoteCurrency == "GBp") dPrice = dPrice / 100; stocks_data[StockSymbolWithSuffix].first = dPrice; stocks_data[StockSymbolWithSuffix].second = sName; sError << wxString::Format(_("%s\t -> %s\n") , StockSymbolWithSuffix, wxString::Format("%0.4f", dPrice)); } } for (auto &s: listCtrlAccount_->m_stocks) { std::map<wxString, std::pair<double, wxString> >::const_iterator it = stocks_data.find(s.SYMBOL.Upper()); if (it == stocks_data.end()) continue; dPrice = it->second.first; s.CURRENTPRICE = dPrice; s.VALUE = dPrice * s.NUMSHARES; if (s.STOCKNAME.empty()) s.STOCKNAME = it->second.second; Model_Stock::instance().save(&s); } // Now refresh the display int selected_id = -1; if (listCtrlAccount_->get_selectedIndex() > -1) selected_id = listCtrlAccount_->m_stocks[listCtrlAccount_->get_selectedIndex()].STOCKID; listCtrlAccount_->doRefreshItems(selected_id); // We are done! LastRefreshDT_ = wxDateTime::Now(); StocksRefreshStatus_ = true; refresh_button_->SetBitmapLabel(wxBitmap(wxImage(led_green_xpm).Scale(16,16))); strLastUpdate_.Printf(_("%s on %s"), LastRefreshDT_.FormatTime() , LastRefreshDT_.FormatDate()); Model_Infotable::instance().Set("STOCKS_LAST_REFRESH_DATETIME", strLastUpdate_); return true; }
bool mmMainCurrencyDialog::OnlineUpdateCurRate(int curr_id, bool hide) { wxString base_symbol = wxEmptyString; wxString msg = wxEmptyString; wxString site = mmex::weblink::YahooQuotes; bool ok = true; Model_Currency::Data * base_currency = Model_Currency::GetBaseCurrency(); if (base_currency) base_symbol = base_currency->CURRENCY_SYMBOL.Upper(); ok = !base_symbol.empty(); if (!ok) msg = _("Could not find base currency symbol!"); auto currencies = Model_Currency::instance().all(); wxString sOutput; if (ok) { wxString buffer = wxEmptyString; for (const auto ¤cy : currencies) { const wxString symbol = currency.CURRENCY_SYMBOL.Upper(); if (curr_id > 0 && currency.CURRENCYID != curr_id) continue; if (!symbol.IsEmpty()) buffer << symbol << base_symbol << "=X+"; } if (buffer.Right(1).Contains("+")) buffer.RemoveLast(1); site = wxString::Format(site, buffer); int err_code = site_content(site, sOutput); if (err_code != wxURL_NOERR) { msg = sOutput; ok = false; } } if (ok) { wxString CurrencySymbol, sName; double dRate = 1; std::map<wxString, std::pair<double, wxString> > currency_data; // Break it up into lines wxStringTokenizer tkz(sOutput, "\r\n"); while (tkz.HasMoreTokens()) { wxString csvline = tkz.GetNextToken(); wxRegEx pattern("\"(...)...=X\",([^,][0-9.]+),\"([^\"]*)\",\"([^\"]*)\""); if (pattern.Matches(csvline)) { CurrencySymbol = pattern.GetMatch(csvline, 1); pattern.GetMatch(csvline, 2).ToDouble(&dRate); sName = pattern.GetMatch(csvline, 4); currency_data[CurrencySymbol] = std::make_pair(dRate, sName); } } msg = _("Currency rate updated"); msg << "\n\n"; Model_CurrencyHistory::instance().Savepoint(); for (auto ¤cy : currencies) { if (!cbShowAll_->IsChecked() && !Model_Account::is_used(currency)) continue; const wxString currency_symbol = currency.CURRENCY_SYMBOL.Upper(); if (!currency_symbol.IsEmpty()) { if (currency_data.find(currency_symbol) != currency_data.end()) { msg << wxString::Format("%s\t: %0.6f -> %0.6f\n" , currency_symbol, currency.BASECONVRATE, currency_data[currency_symbol].first); currency.BASECONVRATE = currency_data[currency_symbol].first; if (base_symbol == currency_symbol) continue; Model_CurrencyHistory::instance().addUpdate(currency.CURRENCYID, wxDateTime::Today(), currency.BASECONVRATE, Model_CurrencyHistory::ONLINE); Model_Currency::instance().save(¤cy); } else { if (curr_id < 0) msg << wxString::Format(_("%s\t: %s\n"), currency_symbol, _("Invalid value ")); } } } //Model_Currency::instance().save(currencies); BASECONVRATE IS FIXED AND USED IF HISTORY NOT FOUND Model_CurrencyHistory::instance().ReleaseSavepoint(); wxMessageDialog msgDlg(this, msg, _("Currency rate updated")); if (!hide) msgDlg.ShowModal(); fillControls(); ShowCurrencyHistory(); } else { wxMessageDialog msgDlg(this, msg, _("Error"), wxOK | wxICON_ERROR); msgDlg.ShowModal(); } return ok; }