Files
Work/analytic/MAINWND.CPP
2024-08-07 09:12:07 -04:00

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)
{
}