Commit 1c290c45 by Imanol Pérez Committed by GitHub

Upload files

parent c6339856
#include "Exception.hpp"
#include <iostream>
Exception::Exception(std::string sum, std::string prob)
{
problem = prob;
summary = sum;
std::cerr << "** Exception ("<<summary<<") **\n";
std::cerr << "Problem: " << problem << "\n\n";
}
#ifndef EXCEPTIONDEF
#define EXCEPTIONDEF
#include <string>
class Exception
{
public:
std::string problem, summary;
Exception(std::string sum, std::string problem);
void DebugPrint();
};
#endif
File added
#include <iostream>
#include "Organism.hpp"
#include <algorithm>
//////////////////////////////////////////////////////
// //
// Class for a single organism //
// //
// Imanol Perez //
// January 201 //
// //
//////////////////////////////////////////////////////
Organism::Organism() {
}
Organism::Organism(int i, int j)
{
/*
Constructor
*/
//Updates moving averages, which must be greater or equal to 0.
MA1=std::max(i, 0);
MA2=std::max(j, 0);
returns=0.0;
}
Organism::~Organism() { }
void Organism::DisposeObject() {
delete this;
}
bool Organism::isNull(void) {
/*
Checks if the organism is null.
An organism is considered null if both moving
averages are zero.
*/
return MA1==0 && MA2==0;
}
std::ostream& operator<<(std::ostream& output, Organism& org) {
/*
Allows to output an object of class Organism.
*/
if (org.returns!=0.0) output<<"Returns: "<<org.returns<<"\n";
output<<"First Moving Average: "<<org.MA1<<"\nSecond Moving Average: "<<org.MA2<<"\n";
return output;
}
#ifndef ORGANISMDEF
#define ORGANISMDEF
//////////////////////////////////////////////////////
// //
// Class for a single organism //
// //
// Imanol Perez //
// January 2017 //
// //
//////////////////////////////////////////////////////
#include <cmath>
#include "Exception.hpp"// This class throws errors using the class "error"
#include <algorithm>
class Organism;
class Organism
{
public:
int MA1; // first moving average
int MA2; // second moving average
double returns; // returns created by this organism
Organism(); // constructor
Organism(int, int); // constructor
~Organism();
void DisposeObject();
bool isNull(void); // checks if organism is null
//output
friend std::ostream& operator<<(std::ostream&, Organism&);
};
#endif
File added
#include <iostream>
#include "Quote.hpp"
#include "Stock.hpp"
#include "Organism.hpp"
#include "Population.hpp"
#include <algorithm>
#include "global.hpp"
#include <fstream>
//////////////////////////////////////////////////////
// //
// Class for the population //
// //
// Imanol Perez //
// January 2017 //
// //
//////////////////////////////////////////////////////
Population::Population() {
}
Population::Population(Stock S, int s, int ma)
{
/*
Constructor. Creates the object of class Population.
*/
size=s;
stock=S;
filled=0;
max_ma=ma;
organisms=new Organism[size];
// We fill in the population with null organisms.
for (int i=0; i<size; i++)
{
organisms[i] = Organism(0, 0); // Quotes with moving averages 0 are considered Null
}
}
void Population::addOrganism(Organism org) {
/*
We add the organism org to the population. If the population is full, throw exception.
*/
if (filled==size) throw Exception("Population limit reached", "There is no space to store more organisms");
organisms[filled]=org;
filled++;
}
double Population::fitness(Stock& s, int n, int start) {
/*
Fitness function that will work as the criteria to select the top 20% of organisms.
*/
if (n<0 or n>=filled) throw Exception("Index out of bounds", "The index is negative or too big");
double returns=1;
// Instead of calculating returns over all the interval available, it only
// runs through the interval specified in s, which was picked randomly.
// The objective is to have organisms that perform well in any random
// period of time.
for (int i=start; i<s.getFilled()-1; i++) {
// We run the algorithm: buy or sell S&P 500 depending on whether a mean average is larger
// or less than the other mean average.
if (s.sample(i-organisms[n].MA1+1, i).mean()>s.sample(i-organisms[n].MA2+1, i).mean()) {
returns*=s.getData(i+1).getPrice()/s.getData(i).getPrice();
} else {
returns*=s.getData(i).getPrice()/s.getData(i+1).getPrice();
}
}
return returns;
}
double Population::returns(int n) {
/*
Gives the overall returns of the organism n
*/
if (n<0 or n>=filled) throw Exception("Index out of bounds", "The index is negative or too big");
double returns=1;
for (int i=max_ma; i<stock.getFilled()-1; i++) {
if (stock.sample(i-organisms[n].MA1+1, i).mean()>stock.sample(i-organisms[n].MA2+1, i).mean()) {
returns*=stock.getData(i+1).getPrice()/stock.getData(i).getPrice();
} else {
returns*=stock.getData(i).getPrice()/stock.getData(i+1).getPrice();
}
}
return returns;
}
Population Population::top20(void) {
/*
It returns the top 20% of the organisms of the population
*/
// How many organisms form the 20% of the population?
int top20=floor(0.2*filled);
Population population=Population(stock, top20, max_ma);
{
// Select a random interval of length FITNESS_TIME_INTERVAL,
// and take a sample of S&P 500 for this interval.
// The objective is to obtain organisms that perform
// well in any random period of time.
int r=rand()%(stock.getFilled()-FITNESS_TIME_INTERVAL);
Stock S=stock.sample(std::max(0, r-max_ma), r+FITNESS_TIME_INTERVAL);
// We calculate fitness score of the organisms
for (int j=0; j<filled; j++) {
organisms[j].returns=fitness(S, j, max_ma);
}
}
// We store in the variable population the top 20% of the organisms
for (int i=0; i<top20; i++) {
for (int j=i+1; j<filled; j++) {
if (organisms[j].returns>organisms[i].returns) {
// Switch values between organisms[i] and organisms[j]
Organism temp=organisms[i];
organisms[i]=organisms[j];
organisms[j]=temp;
}
}
population.addOrganism(organisms[i]);
}
return population;
}
void Population::crossover(void) {
/*
Performs a crossover of the top 20% of the population to generate children.
*/
{
Population top= top20();
filled=0;
for (int i=0; i<top.size; i++) {
addOrganism(top.organisms[i]);
}
// We want to have a population of static size. Thus, while the population
// size is not the original one, create new children.
// To produce a children, pick two random and distinct parents. Take the
// first moving average of one of them, and the second moving average of
// the other one, and create a child.
while (filled!=size) {
int r1=rand()%top.size;
int r2=rand()%top.size;
if (r1==r2) continue;
if (rand()%2==0) {
addOrganism(Organism(top.organisms[r1].MA1, top.organisms[r2].MA2));
} else {
addOrganism(Organism(top.organisms[r2].MA1, top.organisms[r1].MA2));
}
}
}
}
void Population::mutation(void) {
/*
Mutates some of the children.
*/
int top20=floor(0.2*filled);
// We do not mutate the first 20% of the population, as these are the parents.
// We only want to mutate children.
for (int i=top20; i<filled; i++) {
// Not all children are mutated. A children will suffer from a mutation
// with probability MUTATION_PROBABILITY. In this case, we update
// the moving average of the children with a random value between 1
// and max_ma.
if ((double)rand()/(RAND_MAX)<=MUTATION_PROBABILITY) {
organisms[i].MA1=1+rand()%(max_ma+1);
}
if ((double)rand()/(RAND_MAX)<=MUTATION_PROBABILITY) {
organisms[i].MA2=1+rand()%(max_ma+1);
}
// Check if the organism i is in population, as we do not
// want to two identical children.
for (int j=0; j<i; j++) {
if (organisms[i].MA1==organisms[j].MA1 && organisms[i].MA2==organisms[j].MA2) {
// Prevent from moving to children i+1, in order
// to go to the mutation loop again with children i.
i-=1;
break;
}
}
}
}
std::ostream& operator<<(std::ostream& output, Population& population) {
/*
Allows to output an object of class Population.
*/
output<<"Population: "<<population.filled<<"\n";
output<<"Stock: "<<population.stock.getName()<<"\n\n";
for (int i=0; i<population.size; i++) {
if (population.organisms[i].isNull()) continue;
output<<"Organism no. "<<(i+1)<<":\n"<<population.organisms[i]<<"\n";
}
return output;
}
\ No newline at end of file
#ifndef POPULATIONDEF
#define POPULATIONDEF
//////////////////////////////////////////////////////
// //
// Class for the population //
// //
// Imanol Perez //
// December 2016 //
// //
//////////////////////////////////////////////////////
#include <cmath>
#include "Exception.hpp"// This class throws errors using the class "error"
#include "Quote.hpp"
#include "Stock.hpp"
#include "Organism.hpp"
#include <algorithm>
class Population;
class Population
{
public:
Population(); // constructor
Population(Stock, int, int); // constructor
void addOrganism(Organism); // Add organism
double fitness(Stock&, int, int); // fitness function: gives the returns of the organism in a random period of a specific length
double returns(int); // fitness function: gives the returns of the organism
Population top20(void); // returns the strongest 20% organisms
void crossover(void); // performs crossover
void mutation(void); // performs mutation of the new generation
Stock stock;
Organism* organisms;
int size, filled, max_ma;
//output
friend std::ostream& operator<<(std::ostream&, Population&);
};
#endif
File added
#include <iostream>
#include "Quote.hpp"
#include <ctime>
//////////////////////////////////////////////////////
// //
// Class that handles the quotes //
// of a certain stock in a certain date //
// //
// Imanol Perez //
// January 2017 //
// //
//////////////////////////////////////////////////////
Quote::Quote() {
}
Quote::Quote(std::string name, double price, std::string date)
{
// The price of the stock cannot be negative.
if (price<0) {
throw Exception("Negative price",
"The sprice of the stock must non negative");
}
// date must have the format YYYY/MM/DD
struct tm tm;
if (date!="0000/00/00" && !strptime(date.c_str(), "%Y/%m/%d", &tm)) {
throw Exception("Invalid date format", "Date format must be YYYY/MM/DD");
}
mPrice=price;
mName=name;
mDate=date;
}
std::string Quote::getName(void) {
return mName;
}
double Quote::getPrice(void) {
return mPrice;
}
void Quote::setPrice(double price) {
// The price of the stock cannot be negative.
if (price<0) {
throw Exception("Negative price",
"The sprice of the stock must non negative");
}
mPrice=price;
}
std::string Quote::getDate(void) {
/*
Returns the date of the quote
*/
return mDate;
}
void Quote::setDate(std::string date) {
/*
Updates the date of the stock
*/
// date must have format YYYY/MM/DD
struct tm tm;
if (date!="0000/00/00" && !strptime(date.c_str(), "%Y/%m/%d", &tm)) {
throw Exception("Invalid date format", "Date format must be YYYY/MM/DD");
}
mDate=date;
}
void Quote::increasePrice(double change) {
/*
Increases/decreases the price of the stock
*/
mPrice+=change;
}
void Quote::addReturn(double percentage) {
/*
We increase or decrease the price of the stock, by a determined percentage
*/
mPrice*=1+percentage;
}
bool Quote::isNull(void) {
/*
Checks if the quote is null
*/
return mDate=="0000/00/00";
}
std::ostream& operator<<(std::ostream& output, Quote& q) {
/*
Used to display a nice output of the class
*/
std::string name = q.getName();
double price = q.getPrice();
std::string date=q.getDate();
output<<"Name: "<<name<<"\nPrice: "<<price<<"\nDate: "<<date<<"\n";
return output;
}
#ifndef QUOTEDEF
#define QUOTEDEF
//////////////////////////////////////////////////////
// //
// Class that handles the quotes //
// of a certain stock in a certain date //
// //
// Imanol Perez //
// January 2017 //
// //
//////////////////////////////////////////////////////
#include <cmath>
#include "Exception.hpp"// This class throws errors using the class "error"
#include <ctime>
class Quote;
class Quote
{
private:
// member variables
double mPrice; // price of the stock
std::string mName; // name of the stock
std::string mDate; // date of the quote
public:
Quote(); // constructor
Quote(std::string, double, std::string); // constructor
std::string getName(void); // Get stock's name
double getPrice(void); // Get stock's price
void setPrice(double); // Set stock's price
std::string getDate(void); // Get stock's date
void setDate(std::string); // Set stock's date
void increasePrice(double); // Increase stock's price
void addReturn(double); // Add return (in percentage terms)
bool isNull(void); // Returns true if the quote is null
//output
friend std::ostream& operator<<(std::ostream&, Quote&);
};
#endif
File added
This diff is collapsed. Click to expand it.
#include <iostream>
#include "Quote.hpp"
#include "Stock.hpp"
#include <ctime>
#include <cstring>
//////////////////////////////////////////////////////
// //
// Class that handles the stock //
// prices //
// //
// Imanol Perez //
// January 2017 //
// //
//////////////////////////////////////////////////////
Stock::Stock() {
}
Stock::Stock(std::string name, int size) // Creates class with historical data of the stock, with a fixed size
{
if (size<1) throw Exception("Error in size", "The size of historical data must be at least equal to 1");
mName=name;
mData=new Quote[size];
mSize = size;
mFilled=0;
// We fill in the array mData with objects of class Quote.
for (int i=0; i<mSize; i++)
{
mData[i] = Quote(name, 0.0, "0000/00/00"); // Quotes with date 0000/00/00 are considered as Null
}
}
std::string Stock::getName(void) {
return mName;
}
int Stock::getFilled(void) {
/*
Returns the number of spaces in the class Stock.
*/
return mFilled;
}
std::ostream& operator<<(std::ostream& output, Stock& q) {
/*
Allows to output an object of class Stock.
*/
std::string name = q.getName();
output<<"Stock name: "<<name<<"\n";
if (!q.mData[0].isNull()) {
output<<"Start date: "<<q.mData[0].getDate()<<"\n";
output<<"End date: "<<q.mData[q.mFilled-1].getDate()<<"\n";
}
output<<"Length of available data: "<<q.mFilled<<"\n\n";
output<<" Date\t\t Price\n ------\t\t-------\n\n";
for (int i=0; i<q.mSize; i++) {
if (q.mData[i].isNull()) continue;
output<<q.mData[i].getDate()<<"\t "<<q.mData[i].getPrice()<<"\n";
}
return output;
}
void Stock::popLeft(void) {
/*
Deletes the first quote, and moves the rest of the quotes to the left.
*/
if (mSize==1) {
mData[0]=Quote(mName, 0.0, "0000/00/00");
mFilled=0;
return;
}
if (mFilled==0) return;
for (int i=1; i<mFilled; i++) {
mData[i-1]=mData[i];
}
mData[mFilled-1]=Quote(mName, 0.0, "0000/00/00");
mFilled--;
}
void Stock::addData(Quote q) {
/*
Adds new data to the stock's historical prices.
*/
// We add the quote q to the historical data.- If historical data is full, throw exception
if (mFilled==mSize) throw Exception("Data size limit reached", "There is no space to store more historical data");
// If Quote name doesn't match Stock name, throw exception
if (q.getName()!=mName) throw Exception("Invalid name", "Quote's name does not match stock's name");
// Sort quotes. Notice that the elements from 0 to mFilled-1 are already sorted.
if (mFilled==0) {
mData[0]=q;
mFilled++;
return;
}
for (int i=0; i<mFilled; i++) {
{
if (mData[i].getDate()>q.getDate()) {
mData[mFilled]=mData[i];
mData[i]=q;
break;
}
if (i==mFilled-1) {
mData[mFilled]=q;
}