Home
Contact
Download
Releases
Installation
Read-Me
License
Monte Carlo
Strategy Objects
C++ Classes
C++ Files
mcovaluer.h
mcovaluer.cxx
mcov.cxx
|
mcovaluer.cxx
C++ Function Bodies for MCOV Software
This is the mcovaluer.cxx file that comes with a
MCOV distribution (without the
license section)...
// ================================================================
// Implementation of functions declared in mcovaluer.h
//
// See mcovaluer.h for more information.
//
// See copyright notice and license at end of this file.
//
// ----------------------------------------------------------------
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <ctime>
#include "mcovaluer.h"
using namespace std;
// ================================================================
// mcoOption - Option on an underlying financial instrument
//
// ----------------------------------------------------------------
// Construct an mcoOption
mcoOption::mcoOption (char put_call,
double strike_price, long days_to_expiry)
: m_put_call(put_call),
m_strike_price(strike_price),
m_days_to_expiry(days_to_expiry) {
m_iday_expiry = -1;
}
// ----------------------------------------------------------------
// Initialize the option and return true if it can be used
// with the passed dayset.
// Return true if this option's attributes are reasonable.
//
// This function is called by an mcoValuer function after the
// history is read but before any projection is done.
bool mcoOption::initialize (mcoDaySet *dayset) {
mcoErr *e = mcoErr::instance();
if (e->is_err()) return false;
if (!dayset) {
e->err("mcoOption::initialize called with null dayset");
return false;
}
if (m_put_call == 'p') {
m_put_call = 'P';
} else if (m_put_call == 'c') {
m_put_call = 'C';
} else if (m_put_call != 'P' && m_put_call != 'C') {
e->err("put_call must be P or C");
return false;
}
if (m_strike_price <= 0.0 || m_strike_price > 100000.0) {
e->err("Bad strike-price: ");
e->append (m_strike_price);
return false;
}
if (m_days_to_expiry < 1 || m_days_to_expiry > 500) {
e->err("Bad Days-to-expiry value: ");
e->append (m_days_to_expiry);
return false;
}
if (m_days_to_expiry > dayset->max_proj()) {
e->err("Days-to-expiry is too high: ");
e->append (m_days_to_expiry);
return false;
}
set_iday_expiry (dayset->iday_hist_last() + m_days_to_expiry);
}
// ================================================================
// mcoValuer - Object to determine value of an option
//
// ----------------------------------------------------------------
// Construct an mcoValuer
mcoValuer::mcoValuer (const char *hist_file,
mcoSellStratBase *ss, mcoPDayStratBase *ps,
mcoDayFactoryBase *df,
long max_hist, long max_proj) {
mcoErr *e = mcoErr::instance(); // There may be a singleton...
if (e) delete e;
e = mcoErr::instance(); // Create a fresh one.
if (df) {
m_day_factory = df;
m_owns_day_factory = false;
} else {
m_day_factory = new mcoDayFactory;
if (!m_day_factory) {
e->err("ERROR allocating day-factory");
cleanup();
return;
}
m_owns_day_factory = true;
}
m_dayset = new mcoDaySet (hist_file, m_day_factory,
max_hist, max_proj);
if (! m_dayset) {
if (!e->is_err()) e->err("ERROR creating dayset");
cleanup();
return;
}
if (ss) {
m_sell_strategy = ss;
ss->set_dayset(m_dayset);
m_owns_sell_strategy = false;
} else {
m_sell_strategy = new mcoSellStrategy1 (m_dayset);
if (!m_sell_strategy) {
e->err("ERROR allocating sell-strategy");
cleanup();
return;
}
m_owns_sell_strategy = true;
}
if (ps) {
m_pday_strategy = ps;
ps->set_dayset(m_dayset);
m_owns_pday_strategy = false;
} else {
m_pday_strategy = new mcoPDayStrategy1 (m_dayset);
if (!m_pday_strategy) {
e->err("ERROR allocating sell-strategy");
cleanup();
return;
}
m_owns_pday_strategy = true;
}
}
// ----------------------------------------------------------------
// Destruct an mcoValuer
mcoValuer::~mcoValuer (void) {
cleanup();
}
// ----------------------------------------------------------------
// Cleanup the mcoValuer so it can be deleted.
void mcoValuer::cleanup (void) {
if (m_pday_strategy && m_owns_pday_strategy) {
delete m_pday_strategy;
}
if (m_sell_strategy && m_owns_sell_strategy) {
delete m_sell_strategy;
}
if (m_day_factory && m_owns_day_factory) {
delete m_day_factory;
}
if (m_dayset) delete m_dayset;
mcoErr *e = mcoErr::instance();
if (e) delete e;
}
// ----------------------------------------------------------------
// Determine the value of an option.
double mcoValuer::option_value (mcoOption *opt, long num_tries) {
mcoErr *e = mcoErr::instance();
if (e->is_err()) return -9999999.99;
if ( ! opt->initialize(m_dayset) ) return -9999999.99;
if (num_tries < 1 || num_tries > 100000) {
e->err("Number of tries must be between 1 and 100000");
return -9999999.99;
}
double ave_tot = 0.0;
double ave_num = 0.0;
double ave_val = 0.0;
for (long itry=0; itryis_err()) return -9999999.99;
ave_tot += do_try(opt);
ave_num += 1.0;
} // end of loop through tries
if (ave_num > 0.0) ave_val = ave_tot / ave_num;
return ave_val;
}
// ----------------------------------------------------------------
// Do a try and return the value of the option.
double mcoValuer::do_try (mcoOption *opt) {
mcoErr *e = mcoErr::instance();
double opt_val = 0.0;
m_dayset->reset_projection();
for (long i=0; idays_to_expiry(); i++) {
// Identify day to use as prototype for price movement
long iday_proto = m_pday_strategy->prototype_iday();
if (e->is_err()) return -9999999.99;
// Apply prototype's action to day being projected
m_pday_strategy->apply_prototype(iday_proto);
if (e->is_err()) return -9999999.99;
// Decide if option should be sold this day
double price_if_sold = m_sell_strategy->price_if_sold(opt);
if (price_if_sold > 0.0) { // option was sold
opt_val = m_sell_strategy->option_bid(opt, price_if_sold);
break;
} // end of block if option is sold
if (e->is_err()) return -9999999.99;
} // end of loop through days until option expires.
return opt_val;
}
// ================================================================
// mcoDayBase - Base class for day in underlying instrument.
//
// ----------------------------------------------------------------
// Note that this day is set (called by set() functions)
void mcoDayBase::set_is_set (bool sis) {
m_is_set = sis;
if (sis) m_parent->note_day_is_set(m_iday);
}
// ================================================================
// mcoDay - A day for the underlying instrument.
//
// ----------------------------------------------------------------
// Return a pointer to a specified day, downcast to this type.
mcoDay * mcoDay::day (long iday) {
return ( (mcoDay*) parent()->day(iday) );
}
// ----------------------------------------------------------------
// Calculate m_close_chg1
void mcoDay::calc_close_chg1 (void) {
long prev_iday = iday() - 1;
if (prev_iday < 0) return; // no previous day
double prev_close = day(prev_iday)->price_close();
double prev_daynum = day(prev_iday)->daynum();
if (daynum() != prev_daynum+1) return; // days not continuous
if (prev_close >= 0.0) {
m_close_chg1 = m_price_close / prev_close;
}
}
// ----------------------------------------------------------------
// Set the values from separate fundamental values.
void mcoDay::set (long daynum, double prc_close) {
set_daynum(daynum);
m_price_close = prc_close;
calc_close_chg1();
set_is_set(true);
}
// ----------------------------------------------------------------
// Set the values from a non-comment record from an xxx.mcod file
bool mcoDay::set (const string& str) {
mcoErr *e = mcoErr::instance();
istringstream ist (str);
long a_daynum;
double a_price_close;
ist >> a_daynum >> a_price_close;
if (a_daynum < -20000 || a_daynum > 20000) {
e->err("ERROR: daynum must be between -20000 and 20000 : ");
e->append (a_daynum);
return false;
}
if (a_price_close < 0.01 || a_price_close > 10000.0) {
e->err("Error in price_close in history: ");
e->append(a_price_close);
e->append(" (daynum: ");
e->append(a_daynum);
e->append(")");
return false;
}
set (a_daynum, a_price_close);
return true;
}
// ================================================================
// mcoDaySet - Set of days - history and projection
//
// ----------------------------------------------------------------
// Construct a dayset.
mcoDaySet::mcoDaySet (const char *hist_file,
mcoDayFactoryBase *df,
long max_hist_days, long max_proj_days)
: m_max_hist(max_hist_days),
m_max_proj(max_proj_days) {
m_num_hist = m_num_proj = 0;
m_day = 0;
m_history_is_set = false;
mcoErr *e = mcoErr::instance();
if (!hist_file) {
e->err("Error: no history file specified");
cleanup();
return;
}
if (max_hist_days < 2 || max_hist_days > 100000) {
e->err("max_hist_days must be between 2 and 100000.");
cleanup();
return;
}
if (max_proj_days < 1 || max_proj_days > 1000) {
e->err("max_proj_days must be between 1 and 1000.");
cleanup();
return;
}
m_day = new (mcoDayBase*) [max_day()];
if (!m_day) {
e->err("ERROR allocating new day array");
cleanup();
return;
}
for (long i=0; iis_err()) {
e->err("Error: History file: ");
e->append (hist_file);
e->append (" has fewer than two days");
}
cleanup();
return;
}
m_history_is_set = true;
long daynum = m_day[iday_hist_last()]->daynum();
long iday_last = iday_proj_first() + max_proj() - 1;
for (long iday=iday_proj_first(); iday<=iday_last; iday++) {
m_day[iday] = df->new_day(this,iday);
if (!m_day[iday]) {
if (!e->is_err()) {
e->err("ERROR allocating creating new day");
}
cleanup();
return;
}
m_day[iday]->set_daynum(++daynum);
}
}
// ----------------------------------------------------------------
// Destruct a dayset.
mcoDaySet::~mcoDaySet (void) {
cleanup();
}
// ----------------------------------------------------------------
// Note that the indicated day has been set.
void mcoDaySet::note_day_is_set (long iday) {
if ( iday < num_set() ) {
mcoErr *e = mcoErr::instance();
e->err("Bug: Days set out of order");
return;
}
if (m_history_is_set) { // projected day
if ( (iday+1) > num_set() ) {
m_num_proj = (iday+1) - m_num_hist;
}
} else { // history day
if ( (iday+1) > m_num_hist) m_num_hist = iday + 1;
}
}
// ----------------------------------------------------------------
// Cleanup a dayset so that it can be deleted.
void mcoDaySet::cleanup (void) {
if (m_day) {
for (long i=0; ierr("Error opening history file ");
e->append (hist_file);
return false;
}
long iday = -1; // index into m_day
string str;
char buf[501];
while (true) { // records in history file...
if (e->is_err()) return false;
ifs.getline(buf,500); // read a line into the char-array.
if (ifs.eof()) break;
if (buf[0] == '#') continue;
str = buf; // Move C-style string into C++ string
if (m_num_hist >= max_hist()) {
e->err("Error: History file has too many days");
return false;
}
iday++;
m_day[iday] = df->new_day(this,iday);
if (!m_day[iday]) {
e->err("Error creating new day");
return false;
}
if ( ! m_day[iday]->set(str) ) return false;
} // end of loop through records in history file
return true; // success
}
// ----------------------------------------------------------------
// Reset the projection - the projected days
void mcoDaySet::reset_projection (void) {
if ( num_proj() <= 0 ) return;
for (long iday = iday_proj_first();
iday <= iday_proj_last(); iday++) {
day(iday)->reset();
}
m_num_proj = 0;
}
// ================================================================
// mcoSellStrategy1 - deciding when to sell and at what price
//
// ----------------------------------------------------------------
// Decide whether the option was sold during the last projected
// day. If it was, return the price of the underlying instrument
// at the time of the option sale; otherwise return 0.0.
double mcoSellStrategy1::price_if_sold (mcoOption *opt) {
if (dayset()->num_proj() >= opt->days_to_expiry() ) {
long iday_last = dayset()->iday_proj_last();
double prc = day(iday_last)->price_close();
if (opt->put_call() == 'P') {
if (prc < opt->strike_price()) return prc;
} else { // option is a call
if (prc > opt->strike_price()) return prc;
}
}
return 0.0;
}
// ----------------------------------------------------------------
// Estimate the time-value component of the bid for the option
// at the time the option is sold. Since, in this strategy,
// we sell the option just before expiry, time-value is zero.
double mcoSellStrategy1::rem_time_value (mcoOption *opt,
double price) {
return 0.0;
}
// ----------------------------------------------------------------
// Estimate the bid (the price someone is willing to pay)
// for the option which was sold when the underlying instrument
// was selling for 'price'.
double mcoSellStrategy1::option_bid (mcoOption *opt,
double price) {
double val = 0.0;
val += rem_time_value (opt, price);
double strike = opt->strike_price();
if (opt->put_call() == 'P') { // Option is a Put
if (price < strike) val += (strike - price);
} else {
if (price > strike) val += (price - strike);
}
val *= 0.99; // apply bid/ask spread
return val;
}
// ================================================================
// mcoPDayStrategy1 - pick/apply a prototype day
//
// This is a simple implementation of the strategy.
//
// ----------------------------------------------------------------
// Identify a day to use as a prototype for the next day
// to be projected.
//
// In this simple implementation of this strategy:
// pick a day of history (after the first) at random.
long mcoPDayStrategy1::prototype_iday (void) {
long n = dayset()->num_hist() - 2;
long iday = mcoRand::randnum(n) + 1; // 1(2nd) to end.
return iday;
}
// ----------------------------------------------------------------
// Apply a prototype day to the next day to be projected.
void mcoPDayStrategy1::apply_prototype (long iday_proto) {
long iday_prev = dayset()->num_set() - 1; // last day set
long daynum_prev = day(iday_prev)->daynum();
long iday_proj = iday_prev + 1;
long daynum_proj = daynum_prev + 1;
double close_prev = day(iday_prev)->price_close();
double close_chg1 = day(iday_proto)->close_chg1();
if (close_chg1 <= 0.0) close_chg1 = 1.0;
// do the projection of the closing-price...
double close_proj = close_prev * close_chg1;
day(iday_proj)->set(daynum_proj, close_proj);
}
// ================================================================
// mcoErr - Error status/message - a singleton.
//
// ----------------------------------------------------------------
// Definition of static data member.
mcoErr * mcoErr::m_instance = 0;
// ================================================================
// mcoRand - Random number generator - a singleton.
//
// ----------------------------------------------------------------
// Definition of static data member.
bool mcoRand::m_is_setup = false;
// ----------------------------------------------------------------
// Return a random number between zero and maxnum.
long mcoRand::randnum (long max_num) {
if (!mcoRand::m_is_setup) {
time_t tt;
struct tm *ptm;
time (&tt);
ptm = localtime(&tt);
int seed = ptm->tm_hour * 10000 +
ptm->tm_min * 100 +
ptm->tm_sec;
srand(seed);
mcoRand::m_is_setup = true;
srand(seed);
}
return int((double(max_num)*rand())/(RAND_MAX+1.0));
}
// ================================================================
|