\( c^T x + ( 1/2 ) x^T Q x \) wrt. the vector \( x \)
You might wonder what is so special about this objective which is quadratic in the unknowns, that can not be done by Minuit/Fumili . Well, we have in addition the following boundary conditions on \( x \):
\[ A x = b \\
clo \le C x \le cup \\
xlo \le x \le xup
\]
Not all these constraints have to be defined . Our example will only use \( xlo \), \( A \) and \( b \) Still, this could be handled by a general non-linear minimizer like Minuit by introducing so-called "slack" variables . However, quadp is tailored to objective functions not more complex than being quadratic . This allows usage of solving techniques which are even stable for problems involving for instance 500 variables, 100 inequality conditions and 50 equality conditions .
Enough said about quadratic programming, let's return to our example . Suppose, after a long day of doing physics, you have a look at your investments and realize that an early retirement is not possible, given the returns of your stocks . So what now ? ROOT to the rescue ...
In 1990 Harry Markowitz was awarded the Nobel prize for economics: " his work provided new tools
for weighing the risks and rewards of different investments and for valuing corporate stocks and bonds" . In plain English, he developed the tools to balance greed and fear, we want the maximum return with the minimum amount of risk. Our stock portfolio should be at the "Efficient Frontier". To quantify better the risk we are willing to take, we define a utility function \( U(x) \). It describes as a function of our total assets \( x \), our "satisfaction" . A common choice is \( 1-exp(-k*x) \) (the reason for the exponent will be clear later) . The parameter \( k \) is the risk-aversion factor . For small values of \( k \) the satisfaction is small for small values of \( x \); by increasing \( x \) the satisfaction can still be increased significantly . For large values of \( k \), \( U(x) \) increases rapidly to 1, there is no increase in satisfaction for additional dollars earned .
Suppose we have for nrStocks the historical daily returns \( r = closing_price(n) - closing_price(n-1) \). Define a vector \( x \) of length of \( nrStocks \), which contains the fraction of our money invested in each stock . We can calculate the average daily return \( z \) of our portfolio and its variance using the portfolio covariance Covar :
Assuming that the daily returns have a Normal distribution, \( N(x) \), so will \( z \) with mean \( r^T x \) and variance \( x^T Covar x \)
\[ E(u(x)) = Int (1-exp(-k*x) N(x) dx \\
= 1-exp(-k (r^T x - 0.5 k x^T Covar x) ) \\
\]
Its value is maximised by maximising \( r^T x -0.5 k x^T Covar x \) under the condition \( sum (x_i) = 1 \), meaning we want all our money invested and \( x_i \ge 0 \), we can not "short" a stock
We calculate the optimal portfolio for 2.0 and 10.0 .
const Int_t nrStocks = 10;
static const Char_t *stocks[] =
{"GE","SUNW","QCOM","BRCM","TYC","IBM","AMAT","C","PFE","HD"};
class TStockDaily {
public:
TStockDaily() {
fDate = fVol = fOpen = fHigh = fLow = fClose = fCloseAdj = 0;
}
virtual ~TStockDaily() {}
};
}
{
TStockDaily *data = 0;
for (
Int_t i = 0; i < nrEntries; i++) {
closeAdj[i] = data->fCloseAdj/100.;
}
for (
Int_t i = 1; i < nrEntries; i++)
(*
r)[i-1] = closeAdj[i]/closeAdj[i-1];
}
#ifndef __ROOTCLING__
{
const Int_t nrVar = nrStocks;
const Int_t nrInEqual = 0;
TQpDataDens *prob = (
TQpDataDens *)qp->
MakeData(
c,Q,xlo,ixlo,xup,ixup,A,
b,C,clo,iclo,cup,icup);
delete qp; delete prob; delete vars; delete resid; delete s;
if (status != 0) {
cout << "Could not solve this problem." <<endl;
}
return weight;
}
#endif
void portfolio()
{
const Int_t sDay = 20000809;
const Int_t eDay = 20040602;
const char *fname = "stock.root";
if (!
gSystem->AccessPathName(fname)) {
}
for (
Int_t i = 0; i < nrStocks; i++) {
}
const Int_t nrData = data[0].GetSize();
for (
Int_t i = 0; i < nrStocks; i++)
r[i] = data[i].GetSum()/nrData;
for (
Int_t i = 0; i < nrStocks; i++) {
for (
Int_t j = 0; j <= i; j++) {
for (
Int_t k = 0; k < nrData; k++) {
}
Covar(i,j) = Covar(j,i) =
sum/nrData;
}
}
const TVectorD weight1 = OptimalInvest(2.0,
r,Covar);
const TVectorD weight2 = OptimalInvest(10.,
r,Covar);
cout << "stock daily daily w1 w2" <<endl;
cout << "symb return sdv " <<endl;
for (
Int_t i = 0; i < nrStocks; i++)
printf(
"%s\t: %.3f %.3f %.3f %.3f\n",stocks[i],
r[i],
TMath::Sqrt(Covar[i][i]),weight1[i],weight2[i]);
TF1 *
f1 =
new TF1(
"f1",RiskProfile,0,2.5,1);
f1->GetHistogram()->SetXTitle(
"dollar");
f1->GetHistogram()->SetYTitle(
"utility");
f1->GetHistogram()->SetMinimum(0.0);
f1->GetHistogram()->SetMaximum(1.0);
TF1 *f2 =
new TF1(
"f2",RiskProfile,0,2.5,1);
legend1->
AddEntry(f2,
"1-exp(-10.*x)",
"l");
TH1F *
h1 =
new TH1F(
"h1",
"Portfolio Distribution",nrStocks,0,0);
TH1F *h2 =
new TH1F(
"h2",
"Portfolio Distribution",nrStocks,0,0);
for (
Int_t i = 0; i < nrStocks; i++) {
h1->Fill(stocks[i],weight1[i]);
h2->
Fill(stocks[i],weight2[i]);
}
h2->
Draw(
"BAR2SAME HIST");
}
int Int_t
Signed integer 4 bytes (int).
char Char_t
Character 1 byte (char).
double Double_t
Double 8 bytes.
#define ClassDef(name, id)
TMatrixTSym< Double_t > TMatrixDSym
TMatrixT< Double_t > TMatrixD
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
TVectorT< Double_t > TVectorD
Array of floats (32 bits per element).
virtual void SetFillColor(Color_t fcolor)
Set the fill area color.
virtual void SetLineColor(Color_t lcolor)
Set the line color.
A TTree is a list of TBranches.
virtual Int_t GetEntry(Long64_t entry=0, Int_t getall=0)
Read all leaves of entry and return total number of bytes read.
void Draw(Option_t *option="") override
Default Draw method for all objects.
virtual void SetParameter(Int_t param, Double_t value)
A file, usually with extension .root, that stores data and code in the form of serialized objects in ...
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
Create / open a file.
Derived class of TQpSolverBase implementing Gondzio-correction version of Mehrotra's original predict...
Int_t Solve(TQpDataBase *prob, TQpVar *iterate, TQpResidual *resid) override
Solve the quadratic programming problem as formulated through prob, store the final solution in itera...
1-D histogram with a float per channel (see TH1 documentation)
virtual Int_t Fill(Double_t x)
Increment bin with abscissa X by 1.
void Draw(Option_t *option="") override
Draw this histogram with options.
virtual void SetBarWidth(Float_t width=0.5)
Set the width of bars as fraction of the bin width for drawing mode "B".
virtual void SetBarOffset(Float_t offset=0.25)
Set the bar offset as fraction of the bin width for drawing mode "B".
TLegendEntry * AddEntry(const TObject *obj, const char *label="", Option_t *option="lpf")
void Draw(Option_t *option="") override
Draw this box with its current attributes.
Data for the dense QP formulation.
dense matrix problem formulation
TQpVar * MakeVariables(const TQpDataBase *data) override
Setup the variables.
virtual TQpDataBase * MakeData(Double_t *c, Double_t *Q, Double_t *xlo, Bool_t *ixlo, Double_t *xup, Bool_t *ixup, Double_t *A, Double_t *bA, Double_t *C, Double_t *clo, Bool_t *iclo, Double_t *cup, Bool_t *icup)
Setup the data.
TQpResidual * MakeResiduals(const TQpDataBase *data) override
Setup the residuals.
The Residuals class calculates and stores the quantities that appear on the right-hand side of the li...
Class containing the variables for the general QP formulation.
static const TString & GetTutorialDir()
Get the tutorials directory in the installation. Static utility function.
A TTree represents a columnar dataset.
virtual Int_t SetBranchAddress(const char *bname, void *add, TBranch **ptr, TClass *realClass, EDataType datatype, bool isptr, bool suppressMissingBranchError)
virtual TBranch * GetBranch(const char *name)
Return pointer to the branch with the given name in this tree or its friends.
virtual Long64_t GetEntries() const
constexpr Double_t C()
Velocity of light in .
Double_t Exp(Double_t x)
Returns the base-e exponential function of x, which is e raised to the power x.
Double_t Sqrt(Double_t x)
Returns the square root of x.
static uint64_t sum(uint64_t i)