コード例 #1
0
wxString mmReportChartStocks::getHTMLText()
{
    mmHTMLBuilder hb;
    hb.init();
    hb.addHeader(2, _("Stocks Performance Charts"));

    wxTimeSpan dtDiff = dtRange_->end_date() - dtRange_->start_date();
    if (dtRange_->is_with_date() && dtDiff.GetDays() <= 366)
        hb.DisplayDateHeading(dtRange_->start_date(), dtRange_->end_date(), true);
    hb.addHorizontalLine();

    int count = 0, heldAt = -1;
    bool pointDot = false, showGridLines = false;
    wxTimeSpan dist;
    wxDate dateDt, precDateDt = wxInvalidDateTime;
    for (const auto& stock : Model_Stock::instance().all(Model_Stock::COL_HELDAT))
    {
        int dataCount = 0, freq = 1;
        Model_StockHistory::Data_Set histData = Model_StockHistory::instance().find(Model_StockHistory::SYMBOL(stock.SYMBOL),
            Model_StockHistory::DATE(dtRange_->start_date(), GREATER_OR_EQUAL),
            Model_StockHistory::DATE(dtRange_->end_date(), LESS_OR_EQUAL));
        std::stable_sort(histData.begin(), histData.end(), SorterByDATE());
        if (histData.size() <= 30)
            showGridLines = pointDot = true;
        else if (histData.size() <= 366)
            showGridLines = true;
        else
            freq = histData.size() / 366;
        std::vector<ValueTrio> aData;
        for (const auto& hist : histData)
        {
            if (dataCount % freq == 0)
            {
                ValueTrio val;
                dateDt = Model_StockHistory::DATE(hist);
                if (histData.size() <= 30)
                    val.label = mmGetDateForDisplay(dateDt);
                else if (precDateDt.IsValid() && dateDt.GetMonth() != precDateDt.GetMonth())
                    val.label = dateDt.GetMonthName(dateDt.GetMonth());
                else
                    val.label = "";
                val.amount = hist.VALUE;
                aData.push_back(val);
                precDateDt = dateDt;
            }
            dataCount++;
        }
        if (!aData.empty())
        {
            Model_Account::Data* account = Model_Account::instance().get(stock.HELDAT);
            hb.addHeader(1, wxString::Format("%s - (%s)", stock.STOCKNAME, account->ACCOUNTNAME));
            hb.addLineChart(aData, stock.STOCKNAME, count, 1000, 400, pointDot, showGridLines, true);
        }

        heldAt = stock.HELDAT;
        count++;
    }

    return hb.getHTMLText();
}
コード例 #2
0
ファイル: Model_Stock.cpp プロジェクト: dqf88/moneymanagerex
/**
Returns the last price date of a given stock
*/
wxString Model_Stock::lastPriceDate(const Self::Data* entity)
{
    wxString dtStr = entity->PURCHASEDATE;
    Model_StockHistory::Data_Set histData = Model_StockHistory::instance().find(SYMBOL(entity->SYMBOL));

    std::sort(histData.begin(), histData.end(), SorterByDATE());
    if (!histData.empty())
        dtStr = histData.back().DATE;

    return dtStr;
}
コード例 #3
0
void mmStockDialog::showStockHistory()
{
    priceListBox_->DeleteAllItems();
    if (m_stock->SYMBOL.IsEmpty())
        return;

    Model_Account::Data* account = Model_Account::instance().get(m_stock->HELDAT);
    Model_StockHistory::Data_Set histData = Model_StockHistory::instance().find(Model_StockHistory::SYMBOL(m_stock->SYMBOL));
    std::stable_sort(histData.begin(), histData.end(), SorterByDATE());
    std::reverse(histData.begin(), histData.end());
    if (histData.size()>300)
        histData.resize(300);
    if (!histData.empty())
    {
        int idx=0;
        for (const auto &d : histData)
        {
            wxListItem item;
            item.SetId(idx);
            item.SetData(d.HISTID);
            priceListBox_->InsertItem( item );
            const wxDate dtdt = Model_StockHistory::DATE(d);
            const wxString dispAmount = Model_Account::toString(d.VALUE, account, 4);
            priceListBox_->SetItem(idx, 0, mmGetDateForDisplay(dtdt));
            priceListBox_->SetItem(idx, 1, dispAmount);
            if (idx == 0)
            {
                priceDate_->SetValue(dtdt);
                currentPrice_->SetValue(dispAmount);
            }
            const wxString& priceAmount = Model_Account::toString(d.VALUE - m_stock->PURCHASEPRICE, account, 4);
            priceListBox_->SetItem(idx, 2, priceAmount);
            idx++;
        }
        priceListBox_->RefreshItems(0, --idx);
    }
}
コード例 #4
0
ファイル: summary.cpp プロジェクト: bacanhtai/moneymanagerex
wxString mmReportSummaryByDate::getHTMLText()
{
    int             i = 0, j;
    double          balancePerDay[5];
    mmHTMLBuilder   hb;
    wxString        datePrec;
    wxDate          date, dateStart = wxDate::Now(), dateEnd = wxDate::Now();
    wxDateSpan      span;
    mmHistoryItem   *pHistItem;
    mmHistoryData   arHistory;
    std::vector<balanceMap> balanceMapVec(Model_Account::instance().all().size());
    std::vector<std::map<wxDate, double>::const_iterator>   arIt(balanceMapVec.size());
    std::vector<double> arBalance(balanceMapVec.size());
    std::vector<wxString>   totBalanceData;
    std::vector<wxDate> arDates;

    hb.init();
    hb.addDivContainer();
    hb.addHeader(2, wxString::Format(_("Accounts Balance - %s"), mode_==0 ? _("Monthly Report"):_("Yearly Report")));
    hb.addDateNow();
    hb.addLineBreak();

    hb.startTable();
    hb.startThead();
    hb.startTableRow();
    hb.addTableHeaderCell(_("Date"));
    hb.addTableHeaderCell(_("Cash"), true);
    hb.addTableHeaderCell(_("Bank Accounts"), true);
    hb.addTableHeaderCell(_("Credit Card Accounts"), true);
    hb.addTableHeaderCell(_("Term Accounts"), true);
    hb.addTableHeaderCell(_("Total"), true);
    hb.addTableHeaderCell(_("Stocks"), true);
    hb.addTableHeaderCell(_("Balance"), true);
    hb.endTableRow();
    hb.endDiv();
    hb.endThead();

    for (const auto& account: Model_Account::instance().all())
    {
        if (Model_Account::type(account) != Model_Account::INVESTMENT)
        {
            //  in balanceMapVec ci sono i totali dei movimenti giorno per giorno
            const Model_Currency::Data* currency = Model_Account::currency(account);
            for (const auto& tran: Model_Account::transaction(account))
                balanceMapVec[i][Model_Checking::TRANSDATE(tran)] += Model_Checking::balance(tran, account.ACCOUNTID) * Model_CurrencyHistory::getDayRate(currency->id(), tran.TRANSDATE);
            if (Model_Account::type(account) != Model_Account::TERM && balanceMapVec[i].size())
            {
                date = balanceMapVec[i].begin()->first;
                if (date.IsEarlierThan(dateStart))
                    dateStart = date;
            }
            arBalance[i] = account.INITIALBAL * Model_CurrencyHistory::getDayRate(currency->id(), dateStart.FormatISODate());
        }
        else
        {
            Model_Stock::Data_Set stocks = Model_Stock::instance().find(Model_Stock::HELDAT(account.id()));
            for (const auto & stock : stocks)
            {
                arHistory.resize(arHistory.size() + 1);
                pHistItem = arHistory.data() + arHistory.size() - 1;
                pHistItem->acctId = account.id();
                pHistItem->stockId = stock.STOCKID;
                pHistItem->purchasePrice = stock.PURCHASEPRICE;
                pHistItem->purchaseDate = Model_Stock::PURCHASEDATE(stock);
                pHistItem->purchaseDateStr = stock.PURCHASEDATE;
                pHistItem->numShares = stock.NUMSHARES;
                pHistItem->stockHist = Model_StockHistory::instance().find(Model_StockHistory::SYMBOL(stock.SYMBOL));
                std::stable_sort(pHistItem->stockHist.begin(), pHistItem->stockHist.end(), SorterByDATE());
                std::reverse(pHistItem->stockHist.begin(), pHistItem->stockHist.end());
            }
        }
        i++;
    }

    if (mode_ == 0)
    {
        dateEnd -= wxDateSpan::Months(1);
        dateEnd.SetToLastMonthDay(dateEnd.GetMonth(), dateEnd.GetYear());
        span = wxDateSpan::Months(1);
    }
    else if (mode_ == 1)
    {
        dateEnd.Set(31, wxDateTime::Dec, wxDateTime::Now().GetYear());
        span = wxDateSpan::Years(1);
    }
    else
        wxASSERT(0);

    date = dateEnd;
    while (date.IsLaterThan(dateStart))
        date -= span;
    dateStart = date;

    i = 0;
    for (const auto& acctMap: balanceMapVec)
        arIt[i++] = acctMap.begin();

    //  prepare the dates array
    while (dateStart <= dateEnd)
    {
        if (mode_ == 0)
            dateStart.SetToLastMonthDay(dateStart.GetMonth(), dateStart.GetYear());
        arDates.push_back(dateStart);
        dateStart += span;
    }
    date = wxDate::Today();
    if (date.GetDay() != dateEnd.GetDay() || date.GetMonth() != dateEnd.GetMonth() || date.GetYear() != dateEnd.GetYear())
        arDates.push_back(date);

    for (const auto & dateStart : arDates)
    {
        i = 0;
        for (auto& account: Model_Account::instance().all())
        {
            if (Model_Account::type(account) != Model_Account::INVESTMENT)
            {
                for (; arIt[i] != balanceMapVec[i].end(); ++arIt[i])
                {
                    if (arIt[i]->first.IsLaterThan(dateStart))
                        break;
                    arBalance[i] += arIt[i]->second;
                }
            }
            else
            {
                double	convRate = 1.0;
                Model_Currency::Data* currency = Model_Account::currency(account);
                if (currency)
                    convRate = Model_CurrencyHistory::getDayRate(currency->id(), dateStart.FormatISODate());
                arBalance[i] = arHistory.getDailyBalanceAt(&account, dateStart) * convRate;
            }
            i++;
        }

        totBalanceData.push_back(dateStart.FormatISODate());
        for (j=0; j<5; j++)
            balancePerDay[j] = 0.0;
        for (j=0; j<5; j++)
        {
            i = 0;
            for (const auto& account: Model_Account::instance().all())
            {
                if ((j == 0 && Model_Account::type(account) == Model_Account::CASH) ||
                    (j == 1 && Model_Account::type(account) == Model_Account::CHECKING) ||
                    (j == 2 && Model_Account::type(account) == Model_Account::CREDIT_CARD) ||
                    (j == 3 && Model_Account::type(account) == Model_Account::TERM) ||
                    (j == 4 && Model_Account::type(account) == Model_Account::INVESTMENT))
                {
                    balancePerDay[j] += arBalance[i];
                }
                i++;
            }
            totBalanceData.push_back(Model_Currency::toCurrency(balancePerDay[j]));
        }
        totBalanceData.push_back(Model_Currency::toCurrency(balancePerDay[0] + balancePerDay[1] + balancePerDay[2] + balancePerDay[3]));
        totBalanceData.push_back(Model_Currency::toCurrency(balancePerDay[0] + balancePerDay[1] + balancePerDay[2] + balancePerDay[3] + balancePerDay[4]));
    }

    hb.startTbody();
    for (i = totBalanceData.size() - 8; i >= 0; i -= 8)
    {
        if (datePrec.Left(4) != totBalanceData[i].Left(4))
        {
            hb.startTotalTableRow();
            hb.addTableCell(totBalanceData[i].Left(4));
            hb.addTableCell("");
            hb.addTableCell("");
            hb.addTableCell("");
            hb.addTableCell("");
            hb.addTableCell("");
            hb.addTableCell("");
            hb.addTableCell("");
            hb.endTableRow();
        }
        hb.startTableRow();
        hb.addTableCell(mmGetDateForDisplay(mmGetStorageStringAsDate(totBalanceData[i])));
        hb.addTableCell(totBalanceData[i + 1], true);
        hb.addTableCell(totBalanceData[i + 2], true);
        hb.addTableCell(totBalanceData[i + 3], true);
        hb.addTableCell(totBalanceData[i + 4], true);
        hb.addTableCell(totBalanceData[i + 6], true);
        hb.addTableCell(totBalanceData[i + 5], true);
        hb.addTableCell(totBalanceData[i + 7], true);
        hb.endTableRow();
        datePrec = totBalanceData[i];
    }
    hb.endTbody();

    hb.endTable();
    hb.end();

    Model_Report::outputReportFile(hb.getHTMLText());
    return "";
}
コード例 #5
0
ファイル: Model_Stock.cpp プロジェクト: dqf88/moneymanagerex
/**
Returns the total stock balance at a given date
*/
double Model_Stock::getDailyBalanceAt(const Model_Account::Data *account, const wxDate& date)
{
    wxString strDate = date.FormatISODate();
    std::map<int, double> totBalance;

    Data_Set stocks = this->instance().find(HELDAT(account->id()));
    for (const auto & stock : stocks)
    {
        wxString precValueDate, nextValueDate;
        Model_StockHistory::Data_Set stock_hist = Model_StockHistory::instance().find(SYMBOL(stock.SYMBOL));
        std::stable_sort(stock_hist.begin(), stock_hist.end(), SorterByDATE());
        std::reverse(stock_hist.begin(), stock_hist.end());

        double valueAtDate = 0.0,  precValue = 0.0, nextValue = 0.0;

        for (const auto & hist : stock_hist)
        {
            // test for the date requested
            if (hist.DATE == strDate)
            {
                valueAtDate = hist.VALUE;
                break;
            }
            // if not found, search for previous and next date
            if (precValue == 0.0 && hist.DATE < strDate)
            {
                precValue = hist.VALUE;
                precValueDate = hist.DATE;
            }
            if (hist.DATE > strDate)
            {
                nextValue = hist.VALUE;
                nextValueDate = hist.DATE;
            }
            // end conditions: prec value assigned and price date < requested date
            if (precValue != 0.0 && hist.DATE < strDate)
                break;
        }
        if (valueAtDate == 0.0)
        {
            //  if previous not found but if the given date is after purchase date, takes purchase price
            if (precValue == 0.0 && date >= PURCHASEDATE(stock))
            {
                precValue = stock.PURCHASEPRICE;
                precValueDate = stock.PURCHASEDATE;
            }
            //  if next not found and the accoung is open, takes previous date
            if (nextValue == 0.0 && Model_Account::status(account) == Model_Account::OPEN)
            {
                nextValue = precValue;
                nextValueDate = precValueDate;
            }
            if (precValue > 0.0 && nextValue > 0.0 && precValueDate >= stock.PURCHASEDATE && nextValueDate >= stock.PURCHASEDATE)
                valueAtDate = precValue;
        }

        totBalance[stock.id()] += stock.NUMSHARES * valueAtDate;
    }

    double balance = 0.0;
    for (const auto& it : totBalance)
        balance += it.second;

    return balance;
}
コード例 #6
0
wxString mmReportSummaryByDate::getHTMLText()
{
    size_t account_types_num = Model_Account::INVESTMENT + 1;
    std::map<size_t, double> balancePerDay;
    mmHTMLBuilder   hb;
    wxString        datePrec;
    wxDate          date, dateStart = wxDate::Today(), dateEnd = wxDate::Today();
    wxDateSpan      span;
    mmHistoryItem   *pHistItem;
    mmHistoryData   arHistory;
    std::vector<balanceMap> balanceMapVec(Model_Account::instance().all().size());
    std::vector<std::map<wxDate, double>::const_iterator> arIt(balanceMapVec.size());
    std::vector<double> arBalance(balanceMapVec.size());
    std::vector<wxString> totBalanceData;
    std::vector<wxDate> arDates;

    hb.init();
    hb.addDivContainer();
    hb.addHeader(2, wxString::Format(_("Accounts Balance - %s")
        , mode_ == 0 ? _("Monthly Report") : _("Yearly Report")));
    hb.addDateNow();
    hb.addLineBreak();

    hb.startTable();
    hb.startThead();
    hb.startTableRow();
    hb.addTableHeaderCell(_("Date"));
    hb.addTableHeaderCell(_("Cash"), true);
    hb.addTableHeaderCell(_("Bank Accounts"), true);
    hb.addTableHeaderCell(_("Credit Card Accounts"), true);
    hb.addTableHeaderCell(_("Loan Accounts"), true);
    hb.addTableHeaderCell(_("Term Accounts"), true);
    hb.addTableHeaderCell(_("Crypto Wallets"), true);
    hb.addTableHeaderCell(_("Total"), true);
    hb.addTableHeaderCell(_("Stocks"), true);
    hb.addTableHeaderCell(_("Balance"), true);
    hb.endTableRow();
    hb.endDiv();
    hb.endThead();

    int i = 0;
    for (const auto& account: Model_Account::instance().all())
    {
        if (Model_Account::type(account) != Model_Account::INVESTMENT)
        {
            //  in balanceMapVec ci sono i totali dei movimenti giorno per giorno
            const Model_Currency::Data* currency = Model_Account::currency(account);
            for (const auto& tran : Model_Account::transaction(account))
            {
                balanceMapVec[i][Model_Checking::TRANSDATE(tran)]
                    += Model_Checking::balance(tran, account.ACCOUNTID)
                    * Model_CurrencyHistory::getDayRate(currency->id(), tran.TRANSDATE);
            }
            if (Model_Account::type(account) != Model_Account::TERM && balanceMapVec[i].size())
            {
                date = balanceMapVec[i].begin()->first;
                if (date.IsEarlierThan(dateStart)) {
                    dateStart = date;
                }
            }
            arBalance[i] = account.INITIALBAL * Model_CurrencyHistory::getDayRate(currency->id(), dateStart);
        }
        else
        {
            Model_Stock::Data_Set stocks = Model_Stock::instance().find(Model_Stock::HELDAT(account.id()));
            for (const auto & stock : stocks)
            {
                arHistory.resize(arHistory.size() + 1);
                pHistItem = arHistory.data() + arHistory.size() - 1;
                pHistItem->acctId = account.id();
                pHistItem->stockId = stock.STOCKID;
                pHistItem->purchasePrice = stock.PURCHASEPRICE;
                pHistItem->purchaseDate = Model_Stock::PURCHASEDATE(stock);
                pHistItem->purchaseDateStr = stock.PURCHASEDATE;
                pHistItem->numShares = stock.NUMSHARES;
                pHistItem->stockHist = Model_StockHistory::instance().find(Model_StockHistory::SYMBOL(stock.SYMBOL));
                std::stable_sort(pHistItem->stockHist.begin(), pHistItem->stockHist.end(), SorterByDATE());
                std::reverse(pHistItem->stockHist.begin(), pHistItem->stockHist.end());
            }
        }
        i++;
    }

    if (mode_ == 0)
    {
        dateEnd -= wxDateSpan::Months(1);
        dateEnd.SetToLastMonthDay(dateEnd.GetMonth(), dateEnd.GetYear());
        span = wxDateSpan::Months(1);
    }
    else if (mode_ == 1)
    {
        dateEnd.Set(31, wxDateTime::Dec, wxDateTime::Now().GetYear());
        span = wxDateSpan::Years(1);
    }
    else
    {
        wxFAIL_MSG("unknown report mode");
    }

    date = dateEnd;
    while (date.IsLaterThan(dateStart)) {
        date -= span;
    }
    dateStart = date;

    int c = 0;
    for (const auto& acctMap : balanceMapVec) {
        arIt[c++] = acctMap.begin();
    }

    //  prepare the dates array
    while (dateStart <= dateEnd)
    {
        if (mode_ == 0) {
            dateStart.SetToLastMonthDay(dateStart.GetMonth(), dateStart.GetYear());
        }
        arDates.push_back(dateStart);
        dateStart += span;
    }
    date = wxDate::Today().SetToLastMonthDay();
    if (date.GetDay() != dateEnd.GetDay()
        || date.GetMonth() != dateEnd.GetMonth()
        || date.GetYear() != dateEnd.GetYear()) {
        arDates.push_back(date);
    }


    for (const auto & dd : arDates)
    {
        int k = 0;
        double total = 0.0;
        for (auto& account: Model_Account::instance().all())
        {
            if (Model_Account::type(account) != Model_Account::INVESTMENT)
            {
                for (; arIt[k] != balanceMapVec[k].end(); ++arIt[k])
                {
                    if (arIt[k]->first.IsLaterThan(dd)) {
                        break;
                    }
                    arBalance[k] += arIt[k]->second;
                }
            }
            else
            {
                double convRate = 1.0;
                Model_Currency::Data* currency = Model_Account::currency(account);
                if (currency) {
                    convRate = Model_CurrencyHistory::getDayRate(currency->id(), dd);
                }
                arBalance[k] = arHistory.getDailyBalanceAt(&account, dd) * convRate;
            }
            k++;
        }

        // prepare columns for report: date, cash, checking, credit card, term, partial total, investment, grand total
        totBalanceData.push_back(dd.FormatISODate());
        for (size_t j = 0; j < account_types_num; j++) {
            balancePerDay[j] = 0.0;
        }
        int a = 0;
        for (const auto& account: Model_Account::instance().all())
        {
            double t = arBalance[a++];
            balancePerDay[Model_Account::type(account)] += t;
        }

        totBalanceData.push_back(Model_Currency::toCurrency(balancePerDay[Model_Account::CASH]));
        totBalanceData.push_back(Model_Currency::toCurrency(balancePerDay[Model_Account::CHECKING]));
        totBalanceData.push_back(Model_Currency::toCurrency(balancePerDay[Model_Account::CREDIT_CARD]));
        totBalanceData.push_back(Model_Currency::toCurrency(balancePerDay[Model_Account::LOAN]));
        totBalanceData.push_back(Model_Currency::toCurrency(balancePerDay[Model_Account::TERM]));
        totBalanceData.push_back(Model_Currency::toCurrency(balancePerDay[Model_Account::CRYPTO]));

        total = balancePerDay[Model_Account::CASH] + balancePerDay[Model_Account::CHECKING]
            + balancePerDay[Model_Account::CREDIT_CARD] + balancePerDay[Model_Account::LOAN]
            + balancePerDay[Model_Account::TERM] + balancePerDay[Model_Account::CRYPTO];

        totBalanceData.push_back(Model_Currency::toCurrency(total));
        totBalanceData.push_back(Model_Currency::toCurrency(balancePerDay[Model_Account::INVESTMENT]));
        total += balancePerDay[Model_Account::INVESTMENT];
        totBalanceData.push_back(Model_Currency::toCurrency(total));
    }

    hb.startTbody();
    int x = 1 + (account_types_num) + 2;
    for (int k = totBalanceData.size() - x; k >= 0; k -= x)
    {
        if (datePrec.Left(4) != totBalanceData[k].Left(4))
        {
            hb.startTotalTableRow();
            hb.addTableCell(totBalanceData[k].Left(4));
            hb.addEmptyTableCell(x-1);
            hb.endTableRow();
        }
        hb.startTableRow();
        hb.addTableCellDate(totBalanceData[k]);
        for (int j = 0; j < x - 1; j++) {
            hb.addTableCell(totBalanceData[k + j + 1], true);
        }
        hb.endTableRow();
        datePrec = totBalanceData[k];
    }
    hb.endTbody();

    hb.endTable();
    hb.end();

    return hb.getHTMLText();
}
コード例 #7
0
wxString mmReportChartStocks::getHTMLText()
{
    mmHTMLBuilder hb;
    hb.init();
    hb.addDivContainer();
    hb.addHeader(2, getReportTitle());
    hb.addDateNow();

    wxTimeSpan dtDiff = m_date_range->end_date() - m_date_range->start_date();
    if (m_date_range->is_with_date() && dtDiff.GetDays() <= 366)
        hb.DisplayDateHeading(m_date_range->start_date(), m_date_range->end_date(), true);
    hb.addHorizontalLine();

    bool pointDot = false, showGridLines = false;
    wxTimeSpan dist;
    wxDate precDateDt = wxInvalidDateTime;
    for (const auto& stock : Model_Stock::instance().all(Model_Stock::COL_HELDAT))
    {
        int dataCount = 0, freq = 1;
        Model_StockHistory::Data_Set histData = Model_StockHistory::instance().find(Model_StockHistory::SYMBOL(stock.SYMBOL),
            Model_StockHistory::DATE(m_date_range->start_date(), GREATER_OR_EQUAL),
            Model_StockHistory::DATE(m_date_range->end_date(), LESS_OR_EQUAL));
        std::stable_sort(histData.begin(), histData.end(), SorterByDATE());
        if (histData.size() <= 30)
            showGridLines = pointDot = true;
        else if (histData.size() <= 366)
            showGridLines = true;
        else
            freq = histData.size() / 366;
        std::vector<LineGraphData> aData;
        for (const auto& hist : histData)
        {
            if (dataCount % freq == 0)
            {
                LineGraphData val;
                val.xPos = mmGetDateForDisplay(hist.DATE);
                const wxDate dateDt = Model_StockHistory::DATE(hist);
                if (histData.size() <= 30)
                    val.label = val.xPos;
                else if (precDateDt.IsValid() && dateDt.GetMonth() != precDateDt.GetMonth())
                    val.label = wxGetTranslation(dateDt.GetEnglishMonthName(dateDt.GetMonth()));
                else
                    val.label = "";
                val.amount = hist.VALUE;
                aData.push_back(val);
                precDateDt = dateDt;
            }
            dataCount++;
        }
        if (!aData.empty())
        {
            hb.addDivRow();
            Model_Account::Data* account = Model_Account::instance().get(stock.HELDAT);
            hb.addHeader(1, wxString::Format("%s - (%s)", stock.STOCKNAME, account->ACCOUNTNAME));
            hb.addDivCol17_67();
            hb.addLineChart(aData, stock.STOCKNAME, 0, 1000, 400, pointDot, showGridLines);
            hb.endDiv();
            hb.endDiv();
        }
    }

    hb.endDiv();
    hb.end();

    return hb.getHTMLText();
}