470 lines
13 KiB
C++
470 lines
13 KiB
C++
#include <analytic/mainwnd.hpp>
|
|
#include <analytic/money.hpp>
|
|
#include <analytic/bond.hpp>
|
|
#include <analytic/portfolio.hpp>
|
|
#include <analytic/catmull.hpp>
|
|
#include <common/openfile.hpp>
|
|
#include <gui/extent.hpp>
|
|
#include <gui/expose.hpp>
|
|
#include <gui/configure.hpp>
|
|
#include <gui/purehdc.hpp>
|
|
|
|
MainWindow::MainWindow(Application &mainApp)
|
|
: Window(mainApp), mCurrentRow(0)
|
|
{
|
|
initHandlers();
|
|
createControls();
|
|
initControls();
|
|
}
|
|
|
|
MainWindow::~MainWindow()
|
|
{
|
|
}
|
|
|
|
void MainWindow::initHandlers(void)
|
|
{
|
|
mCancelHandler.setCallback(this,&cancelHandler);
|
|
mCalcHandler.setCallback(this,&calcHandler);
|
|
mAddHandler.setCallback(this,&addHandler);
|
|
mDelHandler.setCallback(this,&delHandler);
|
|
mSetHandler.setCallback(this,&setHandler);
|
|
mSaveHandler.setCallback(this,&saveHandler);
|
|
mLoadHandler.setCallback(this,&loadHandler);
|
|
mSelectRowHandler.setCallback(this,&selectRowHandler);
|
|
mSaveFileSelectHandler.setCallback(this,&saveFileSelectHandler);
|
|
mLoadFileSelectHandler.setCallback(this,&loadFileSelectHandler);
|
|
}
|
|
|
|
void MainWindow::createControls(void)
|
|
{
|
|
create();
|
|
size(InitialWidth,InitialHeight);
|
|
setCaption("Portfolio v1.0.0");
|
|
position(CenterPosition);
|
|
|
|
show();
|
|
|
|
mPixmap.create(*this,220,120);
|
|
mPixmap.clear();
|
|
|
|
mLabelBond.create("Bond:");
|
|
mLabelCoupon.create("Coupon:");
|
|
mLabelYTM.create("YTM:");;
|
|
mLabelPar.create("Par:");
|
|
mLabelPrice.create("Price:");
|
|
mLabelYield.create("Yield:");
|
|
mLabelYieldValue.create();
|
|
|
|
mEntryBond.create();
|
|
mEntryCoupon.create();
|
|
mEntryYTM.create();
|
|
mEntryPar.create();
|
|
mEntryPrice.create();
|
|
|
|
mCancelButton.setHandler(&mCancelHandler);
|
|
mCancelButton.create("Quit");
|
|
mCalcButton.setHandler(&mCalcHandler);
|
|
mCalcButton.create("Yield");
|
|
|
|
mAddButton.setHandler(&mAddHandler);
|
|
mAddButton.create("Add");
|
|
mDelButton.setHandler(&mDelHandler);
|
|
mDelButton.create("Remove");
|
|
mSaveButton.setHandler(&mSaveHandler);
|
|
mSaveButton.create("Save");
|
|
mLoadButton.setHandler(&mLoadHandler);
|
|
mLoadButton.create("Load");
|
|
mSetButton.setHandler(&mSetHandler);
|
|
mSetButton.create("Set");
|
|
|
|
mStatusBar.create();
|
|
Block<String> strColTitles;
|
|
strColTitles.insert(String("Bond"));
|
|
strColTitles.insert(String("CPN"));
|
|
strColTitles.insert(String("YTM"));
|
|
strColTitles.insert(String("Par"));
|
|
strColTitles.insert(String("Price"));
|
|
mPortfolioList.create(strColTitles);
|
|
mPortfolioList.setSelectRowHandler(&mSelectRowHandler);
|
|
mPortfolioList.setColumnWidth(0,50);
|
|
mPortfolioList.setColumnWidth(1,50);
|
|
mPortfolioList.setColumnWidth(2,50);
|
|
mPortfolioList.setColumnWidth(3,100);
|
|
mPortfolioList.setColumnWidth(4,100);
|
|
mWinGrid.create(14,6);
|
|
mWinGrid.setColSpacing(52);
|
|
mWinGrid.setRowSpacing(3);
|
|
|
|
mWinGrid.attach(mCancelButton,4,6,0,1);
|
|
mWinGrid.attach(mCalcButton,4,6,1,2);
|
|
mWinGrid.attach(mAddButton,4,6,7,8);
|
|
mWinGrid.attach(mDelButton,4,6,8,9);
|
|
mWinGrid.attach(mSetButton,4,6,9,10);
|
|
mWinGrid.attach(mSaveButton,4,6,2,3);
|
|
mWinGrid.attach(mLoadButton,4,6,3,4);
|
|
mWinGrid.attach(mStatusBar,0,6,13,14);
|
|
mWinGrid.attach(mPortfolioList,0,5,0,6);
|
|
|
|
mWinGrid.attach(mLabelBond,3,4,6,7);
|
|
mWinGrid.attach(mLabelCoupon,3,4,7,8);
|
|
mWinGrid.attach(mLabelYTM,3,4,8,9);
|
|
mWinGrid.attach(mLabelPar,3,4,9,10);
|
|
mWinGrid.attach(mLabelPrice,3,4,10,11);
|
|
mWinGrid.attach(mLabelYield,3,4,11,12);
|
|
mWinGrid.attach(mLabelYieldValue,4,5,11,12);
|
|
mWinGrid.attach(mEntryBond,4,5,6,7);
|
|
mWinGrid.attach(mEntryCoupon,4,5,7,8);
|
|
mWinGrid.attach(mEntryYTM,4,5,8,9);
|
|
mWinGrid.attach(mEntryPar,4,5,9,10);
|
|
mWinGrid.attach(mEntryPrice,4,5,10,11);
|
|
mWinGrid.attach(mPixmap,0,4,6,11);
|
|
|
|
*this+=mWinGrid;
|
|
mWinGrid.show();
|
|
mPixmap.show();
|
|
mCancelButton.show();
|
|
mCalcButton.show();
|
|
mAddButton.show();
|
|
mDelButton.show();
|
|
mSaveButton.show();
|
|
mLoadButton.show();
|
|
mSetButton.show();
|
|
mStatusBar.show();
|
|
mPortfolioList.show();
|
|
mLabelBond.show();
|
|
mLabelCoupon.show();
|
|
mLabelYTM.show();
|
|
mLabelPar.show();
|
|
mLabelPrice.show();
|
|
mLabelYield.show();
|
|
mLabelYieldValue.show();
|
|
|
|
mEntryBond.show();
|
|
mEntryCoupon.show();
|
|
mEntryYTM.show();
|
|
mEntryPar.show();
|
|
mEntryPrice.show();
|
|
}
|
|
|
|
void MainWindow::initControls(void)
|
|
{
|
|
mStatusBar.setText("Ready.");
|
|
}
|
|
|
|
// callbacks
|
|
|
|
int MainWindow::cancelHandler(CallbackData &someCallbackData)
|
|
{
|
|
CallbackData cbData(someCallbackData);
|
|
quit();
|
|
return 0;
|
|
}
|
|
|
|
int MainWindow::calcHandler(CallbackData &someCallbackData)
|
|
{
|
|
calcYield();
|
|
return 0;
|
|
}
|
|
|
|
void MainWindow::calcYield(void)
|
|
{
|
|
Portfolio portfolio;
|
|
String strYield;
|
|
|
|
getPortfolio(portfolio);
|
|
if(!portfolio.size())return;
|
|
Rate yield(portfolio.yield());
|
|
::sprintf(strYield,"%5.3lf",yield.decimalRate()*100.00);
|
|
mLabelYieldValue.setLabel(strYield);
|
|
}
|
|
|
|
int MainWindow::addHandler(CallbackData &someCallbackData)
|
|
{
|
|
String strEntry;
|
|
String strFormat;
|
|
int row;
|
|
|
|
mPortfolioList.addRow();
|
|
row=mPortfolioList.getRowCount();
|
|
mEntryBond.getText(strEntry);
|
|
mPortfolioList.setCellData(row-1,0,strEntry);
|
|
mEntryCoupon.getText(strEntry);
|
|
::sprintf(strFormat,"%5.3lf",::atof(strEntry));
|
|
mPortfolioList.setCellData(row-1,1,strFormat);
|
|
mEntryYTM.getText(strEntry);
|
|
::sprintf(strFormat,"%d",::atoi(strEntry));
|
|
mPortfolioList.setCellData(row-1,2,strFormat);
|
|
mEntryPar.getText(strEntry);
|
|
mPortfolioList.setCellData(row-1,3,(String)Money(::atof(strEntry)));
|
|
mEntryPrice.getText(strEntry);
|
|
mPortfolioList.setCellData(row-1,4,(String)Money(::atof(strEntry)));
|
|
calcYield();
|
|
graphCashflows();
|
|
return 0;
|
|
}
|
|
|
|
int MainWindow::delHandler(CallbackData &someCallbackData)
|
|
{
|
|
if(!mPortfolioList.getRowCount())return 0;
|
|
mPortfolioList.removeRow(currentRow());
|
|
calcYield();
|
|
graphCashflows();
|
|
return 0;
|
|
}
|
|
|
|
int MainWindow::saveHandler(CallbackData &someCallbackData)
|
|
{
|
|
if(!mOpenDialog.create("Save Portfolio"))return 0;
|
|
mOpenDialog.setSelectHandler(&mSaveFileSelectHandler);
|
|
}
|
|
|
|
int MainWindow::loadHandler(CallbackData &someCallbackData)
|
|
{
|
|
if(!mOpenDialog.create("Load Portfolio"))return 0;
|
|
mOpenDialog.setSelectHandler(&mLoadFileSelectHandler);
|
|
}
|
|
|
|
int MainWindow::setHandler(CallbackData &someCallbackData)
|
|
{
|
|
String strEntry;
|
|
String strFormat;
|
|
|
|
if(!mPortfolioList.getRowCount())return 0;
|
|
mEntryBond.getText(strEntry);
|
|
mPortfolioList.setCellData(currentRow(),0,strEntry);
|
|
mEntryCoupon.getText(strEntry);
|
|
::sprintf(strFormat,"%5.3lf",::atof(strEntry));
|
|
mPortfolioList.setCellData(currentRow(),1,strFormat);
|
|
mEntryYTM.getText(strEntry);
|
|
::sprintf(strFormat,"%d",::atoi(strEntry));
|
|
mPortfolioList.setCellData(currentRow(),2,strFormat);
|
|
mEntryPar.getText(strEntry);
|
|
mPortfolioList.setCellData(currentRow(),3,(String)Money(::atof(strEntry)));
|
|
mEntryPrice.getText(strEntry);
|
|
mPortfolioList.setCellData(currentRow(),4,(String)Money(::atof(strEntry)));
|
|
calcYield();
|
|
graphCashflows();
|
|
return 0;
|
|
}
|
|
|
|
int MainWindow::saveFileSelectHandler(CallbackData &someCallbackData)
|
|
{
|
|
String strPathFileName(*(String*)someCallbackData.data());
|
|
Block<String> listLines;
|
|
File saveFile;
|
|
|
|
if(strPathFileName.isNull())return 0;
|
|
if(!getLines(listLines))return 0;
|
|
saveFile.open(strPathFileName,"wb");
|
|
for(int index=0;index<listLines.size();index++)saveFile.writeLine(listLines[index]);
|
|
saveFile.close();
|
|
return 0;
|
|
}
|
|
|
|
int MainWindow::loadFileSelectHandler(CallbackData &someCallbackData)
|
|
{
|
|
String strPathFileName(*(String*)someCallbackData.data());
|
|
Block<String> strLines;
|
|
String strLine;
|
|
File inFile;
|
|
char *ptrLine;
|
|
int rows;
|
|
|
|
inFile.open(strPathFileName,"rb");
|
|
if(!inFile.isOkay())return 0;
|
|
mPortfolioList.clear();
|
|
while(!inFile.eof())
|
|
{
|
|
inFile.getLine(strLine);
|
|
if(strLine.isNull())continue;
|
|
mPortfolioList.addRow();
|
|
rows=mPortfolioList.getRowCount();
|
|
ptrLine=(char*)strLine;
|
|
ptrLine=::strtok(ptrLine,",");
|
|
if(!ptrLine)continue;
|
|
mPortfolioList.setCellData(rows-1,0,ptrLine);
|
|
ptrLine=::strtok(0,",");
|
|
if(!ptrLine)continue;
|
|
mPortfolioList.setCellData(rows-1,1,ptrLine);
|
|
ptrLine=::strtok(0,",");
|
|
if(!ptrLine)continue;
|
|
mPortfolioList.setCellData(rows-1,2,ptrLine);
|
|
ptrLine=::strtok(0,",");
|
|
if(!ptrLine)continue;
|
|
mPortfolioList.setCellData(rows-1,3,(String)Money(::atof(ptrLine)));
|
|
ptrLine=::strtok(0,",\0");
|
|
if(!ptrLine)continue;
|
|
mPortfolioList.setCellData(rows-1,4,(String)Money(::atof(ptrLine)));
|
|
}
|
|
calcYield();
|
|
graphCashflows();
|
|
return 0;
|
|
}
|
|
|
|
void MainWindow::graphCashflows(void)
|
|
{
|
|
GlobalData<double> cashflows;
|
|
GlobalData<FloatPairs> srcPairs;
|
|
GlobalData<FloatPairs> dstPairs;
|
|
CatmullRom splineGen;
|
|
Portfolio portfolio;
|
|
double maxFlow;
|
|
double clampFactor;
|
|
int recLen;
|
|
|
|
mPixmap.clear();
|
|
getPortfolio(portfolio);
|
|
portfolio.getCashflows(cashflows);
|
|
recLen=mPixmap.width()/cashflows.size();
|
|
if(!cashflows.size())return;
|
|
for(int index=0;index<cashflows.size();index++)
|
|
{
|
|
if(!index)maxFlow=cashflows[index];
|
|
else if(cashflows[index]>maxFlow)maxFlow=cashflows[index];
|
|
}
|
|
clampFactor=(float)mPixmap.height()/(float)maxFlow;
|
|
for(int index=0;index<cashflows.size();index++)cashflows[index]=cashflows[index]*clampFactor;
|
|
PureDevice pureDevice(*this);
|
|
pureDevice.setForeground(RGBColor(0,255,0));
|
|
for(int index=0,xLoc=0;index<cashflows.size();index++,xLoc+=recLen)
|
|
{
|
|
Rectangle rect(xLoc,mPixmap.height()-cashflows[index],xLoc+5,mPixmap.height());
|
|
mPixmap.pixmap().rectangle(pureDevice,rect);
|
|
}
|
|
mPixmap.draw();
|
|
}
|
|
|
|
void MainWindow::graphCashflowsSpline(void)
|
|
{
|
|
GlobalData<double> cashflows;
|
|
GlobalData<FloatPairs> srcPairs;
|
|
GlobalData<FloatPairs> dstPairs;
|
|
CatmullRom splineGen;
|
|
Portfolio portfolio;
|
|
double maxFlow;
|
|
double clampFactor;
|
|
|
|
mPixmap.clear();
|
|
getPortfolio(portfolio);
|
|
portfolio.getCashflows(cashflows);
|
|
if(!cashflows.size())return;
|
|
for(int index=0;index<cashflows.size();index++)
|
|
{
|
|
if(!index)maxFlow=cashflows[index];
|
|
else if(cashflows[index]>maxFlow)maxFlow=cashflows[index];
|
|
}
|
|
clampFactor=(float)mPixmap.height()/(float)maxFlow;
|
|
for(int index=0;index<cashflows.size();index++)cashflows[index]=cashflows[index]*clampFactor;
|
|
srcPairs.size(cashflows.size());
|
|
dstPairs.size(mPixmap.width());
|
|
clampFactor=srcPairs.size()/(float)mPixmap.width();
|
|
double invFactor=(float)mPixmap.width()/(float)srcPairs.size();
|
|
for(int index=0;index<srcPairs.size();index++)srcPairs[index]=FloatPairs(((float)index+1.00)*invFactor,cashflows[index]);
|
|
for(int index=0;index<dstPairs.size();index++)dstPairs[index]=FloatPairs(index+1,0.00);
|
|
dstPairs[0].column(srcPairs[0].column());
|
|
dstPairs[dstPairs.size()-1].column(srcPairs[srcPairs.size()-1].column());
|
|
splineGen.performSpline(srcPairs,dstPairs);
|
|
PureDevice pureDevice(*this);
|
|
pureDevice.setForeground(RGBColor(0,255,0));
|
|
for(int index=0;index<dstPairs.size();index++)
|
|
mPixmap.pixmap().line(pureDevice,Point(index,mPixmap.height()),Point(index,mPixmap.height()-dstPairs[index].row()));
|
|
mPixmap.draw();
|
|
}
|
|
|
|
int MainWindow::selectRowHandler(CallbackData &someCallbackData)
|
|
{
|
|
String strEntry;
|
|
|
|
Point &rcPoint=*((Point*)someCallbackData.data());
|
|
mCurrentRow=rcPoint.x();
|
|
mPortfolioList.getCellData(rcPoint.x(),0,strEntry);
|
|
mEntryBond.setText(strEntry);
|
|
mPortfolioList.getCellData(rcPoint.x(),1,strEntry);
|
|
mEntryCoupon.setText(strEntry);
|
|
mPortfolioList.getCellData(rcPoint.x(),2,strEntry);
|
|
mEntryYTM.setText(strEntry);
|
|
mPortfolioList.getCellData(rcPoint.x(),3,strEntry);
|
|
strEntry.removeTokens("$ ,");
|
|
mEntryPar.setText(strEntry);
|
|
mPortfolioList.getCellData(rcPoint.x(),4,strEntry);
|
|
strEntry.removeTokens("$ ,");
|
|
mEntryPrice.setText(strEntry);
|
|
return 0;
|
|
}
|
|
|
|
int MainWindow::getLines(Block<String> &listLines)
|
|
{
|
|
String strEntry;
|
|
String strLine;
|
|
int rows;
|
|
|
|
listLines.remove();
|
|
rows=mPortfolioList.getRowCount();
|
|
for(int row=0;row<rows;row++)
|
|
{
|
|
String strLine;
|
|
mPortfolioList.getCellData(row,0,strEntry);
|
|
strLine+=strEntry+String(",");
|
|
mPortfolioList.getCellData(row,1,strEntry);
|
|
strLine+=strEntry+String(",");
|
|
mPortfolioList.getCellData(row,2,strEntry);
|
|
strLine+=strEntry+String(",");
|
|
mPortfolioList.getCellData(row,3,strEntry);
|
|
strEntry.removeTokens("$ ,");
|
|
strLine+=strEntry+String(",");
|
|
mPortfolioList.getCellData(row,4,strEntry);
|
|
strEntry.removeTokens("$ ,");
|
|
strLine+=strEntry;
|
|
listLines.insert(strLine);
|
|
}
|
|
return listLines.size();
|
|
}
|
|
|
|
int MainWindow::getPortfolio(Portfolio &portfolio)
|
|
{
|
|
String strEntry;
|
|
String strLine;
|
|
int rows;
|
|
|
|
portfolio.remove();
|
|
rows=mPortfolioList.getRowCount();
|
|
for(int row=0;row<rows;row++)
|
|
{
|
|
Bond bond;
|
|
|
|
mPortfolioList.getCellData(row,1,strEntry);
|
|
bond.coupon(Coupon(::atof(strEntry),Annual));
|
|
mPortfolioList.getCellData(row,2,strEntry);
|
|
bond.ytm(::atoi(strEntry));
|
|
mPortfolioList.getCellData(row,3,strEntry);
|
|
strEntry.removeTokens("$ ,");
|
|
bond.par(::atof(strEntry));
|
|
mPortfolioList.getCellData(row,4,strEntry);
|
|
strEntry.removeTokens("$ ,");
|
|
bond.price(::atof(strEntry));
|
|
portfolio.insert(FinancialInstrument());
|
|
portfolio[portfolio.size()-1]=::new Bond(bond);
|
|
portfolio[portfolio.size()-1].disposition(PointerDisposition::Delete);
|
|
}
|
|
return portfolio.size();
|
|
}
|
|
|
|
int MainWindow::currentRow(void)const
|
|
{
|
|
return mCurrentRow;
|
|
}
|
|
|
|
// virtuals
|
|
|
|
void MainWindow::exposeEvent(const Expose &expose)
|
|
{
|
|
}
|
|
|
|
void MainWindow::configureEvent(const Configure &configure)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
|