/*	financial.js		1-11-2009		JavaScript
	Copyright (C)1985, 2008-2009 Steven Whitney.
	Initially published by http://25yearsofprogramming.com.

	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License (GPL)
	Version 3 as published by the Free Software Foundation.
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

Financial calculations.

REFERENCES
--Wikipedia
--How To Make Money In Stock Options, by Norman Saint-Peter.

*/
//----------------------------------------------------------------------------------------------
// COMPOUND INTEREST
// present value, future value, imputed compound interest rate per period.
// NumPeriods and InterestPerPeriod are relative to each other, regardless of the units used for either.
//----------------------------------------------------------------------------------------------
function PresentValue(NumPeriods, InterestPerPeriod, FutureValue)
{
	return FutureValue / Math.pow(1 + InterestPerPeriod, NumPeriods); 
}
function FutureValue(NumPeriods, InterestPerPeriod, PresentValue)
{
	return PresentValue * Math.pow(1 + InterestPerPeriod, NumPeriods); 
}
function ImputedInterest(PresentValue, FutureValue, NumPeriods)
{
	return Math.pow(FutureValue / PresentValue, 1 / NumPeriods) - 1; 
}
function NumPeriods(PresentValue, FutureValue, InterestPerPeriod)
{
	return (Math.log(FutureValue) - Math.log(PresentValue)) / Math.log(1 + InterestPerPeriod); 
}
//----------------------------------------------------------------------------------------------
// PERIODIC INTEREST RATES
// Given an annual rate, returns an array containing the rates for shorter periods. 
// The elements can be accessed as, for example, Rates["Daily"] or Rates.Daily.
function GetPeriodicInterestRates(AnnualRate)
{
	var Rates = new Array();
	Rates["Annually"] = AnnualRate;
	Rates["Semiannually"] = AnnualRate / 2;
	Rates["Quarterly"] = AnnualRate / 4;
	Rates["Monthly"] = AnnualRate / 12;
	Rates["Weekly"] = AnnualRate / 52;
	Rates["Daily"] = AnnualRate / 365;
	return Rates;
}
//----------------------------------------------------------------------------------------------
// 252 is generally used as the number of trading days in a year, 21 in a month.
// Those are what the values returned by this function round to, except for February.
// When calculating time to option expiration, you usually know the number of 
// calendar days, not trading days, so this can be used to convert the number.
// 365.25 days in a year, 5/7 are weekdays, - 9 U.S. trading holidays
// The multiplier is 0.68964505720152537400997359929598
function TradingDaysIn(CalendarDays)
{
	return CalendarDays * (((365.25 * 5/7) - 9) / 365.25);
}
// How many calendar days are required for the given number of trading days to occur.
// The multiplier is 1.4500212675457252233092301148447
function CalendarDaysFor(TradingDays)
{
	return TradingDays * (365.25 / ((365.25 * 5/7) - 9));
}
//----------------------------------------------------------------------------------------------
// Given a current stock price, its volatility, and a time period, these functions compute the 
// boundaries that the stock could be expected to stay within during a time period (with 68% probability).
// There is a 16% probability it will be above UpperLimit, and 16% probability it will be below LowerLimit.
// These are really just the 1 standard deviation points that define the price envelope at the end of the time period.
// Using these as indicators of "potential" upside and downside price targets is highly questionable 
// because the choice to use 1 standard deviation is arbitrary.
// TimePeriod is a fraction (or multiple) of the Volatility period: if volatility is annualized, 
// TimePeriod is the fraction of 1 year.
function UpperLimitPrice84(CurrentPrice, VolatilityPerPeriod, TimePeriod)
{
	return CurrentPrice * Math.exp(Math.sqrt(TimePeriod) * VolatilityPerPeriod); 
}
function LowerLimitPrice84(CurrentPrice, VolatilityPerPeriod, TimePeriod)
{
	return CurrentPrice * Math.exp(Math.sqrt(TimePeriod) * (-VolatilityPerPeriod)); 
}
//----------------------------------------------------------------------------------------------
// Given the current stock price, a price objective, and an annualized volatility, 
// calculates the number of CALENDAR days it should take for the stock to reach the objective.
// This equation is derived from the "potential upside and downside stock prices" equations.
// What this derivation does is start with the envelope and calculate at what 
// point in time the 1 standard deviation point first reaches the target price. 
// The probability that the price will actually have reached or exceeded the objective price is only 16%.
// Thus, this calculation has a lot more uncertainty in it than its name implies. 
function CalendarDaysToReachPrice16(CurrentPrice, TargetPrice, Volatility)
{
	var diff = Math.log(TargetPrice) - Math.log(CurrentPrice);
	var yearfrac = (diff * diff) / (Volatility * Volatility);
	// We now have the estimated time in fraction of a year.
	// .5 trading year = .5 calendar years (it's just a different number of days),
	// so we can simply multiply by the number of days in the type of year we want.
	return yearfrac * 365.25;
}
//----------------------------------------------------------------------------------------------
// Given current price, a target price, annualized volatility, years (or fraction) from now till target date,
// calculates the probability of stock price being below the target. 
// TimePeriod is a fraction (or multiple) of the Volatility period: 
// if volatility is annualized, TimePeriod is the fraction of 1 year.
function ProbabilityStockPriceBelow(CurrentPrice, TargetPrice, VolatilityPerPeriod, TimePeriod)
{
	// Prevents divide by zero. If time is 0, the probability is known to be either 0% or 100%.
	if(TimePeriod === 0)	
		return CurrentPrice < TargetPrice ? 1 : 0;
	return StandardNormalPx(Math.log(TargetPrice / CurrentPrice) / (VolatilityPerPeriod * Math.sqrt(TimePeriod)));
}
//----------------------------------------------------------------------------------------------
// Probability of stock price being above the target price. 
function ProbabilityStockPriceAbove(CurrentPrice, TargetPrice, VolatilityPerPeriod, TimePeriod)
{
	if(TimePeriod === 0)
		return CurrentPrice > TargetPrice ? 1 : 0;
	return StandardNormalQx(Math.log(TargetPrice / CurrentPrice) / (VolatilityPerPeriod * Math.sqrt(TimePeriod)));
}
//----------------------------------------------------------------------------------------------
// Functions for calculating value of a stock option using the Black-Scholes model.
function BlackScholesDen1(Current, Strike, TBillRate, Volatility, FractionalYear) 
{
	return (Math.log(Current / Strike) + ((TBillRate + ((Volatility * Volatility) / 2)) * FractionalYear)) / (Volatility * Math.sqrt(FractionalYear)); 
}
//----------------------------------------------------------------------------------------------
function BlackScholesDen2(Current, Strike, TBillRate, Volatility, FractionalYear)
{ 
	return (Math.log(Current / Strike) + ((TBillRate - ((Volatility * Volatility) / 2)) * FractionalYear)) / (Volatility * Math.sqrt(FractionalYear)); 
}
//----------------------------------------------------------------------------------------------
function BlackScholesCallHedgeRatio(Current, Strike, TBillRate, Volatility, FractionalYear)
{
	return StandardNormalPx(BlackScholesDen1(Current, Strike, TBillRate, Volatility, FractionalYear));
}
//----------------------------------------------------------------------------------------------
function BlackScholesPutHedgeRatio(Current, Strike, TBillRate, Volatility, FractionalYear)
{
	return BlackScholesCallHedgeRatio(Current, Strike, TBillRate, Volatility, FractionalYear) - 1;
}
//----------------------------------------------------------------------------------------------
function BlackScholesCallValue(Current, Strike, TBillRate, Volatility, FractionalYear)
{
	var a = (Current * BlackScholesCallHedgeRatio(Current, Strike, TBillRate, Volatility, FractionalYear));
	var b = (StandardNormalPx(BlackScholesDen2(Current, Strike, TBillRate, Volatility, FractionalYear)));
	var d = (Strike * Math.exp(TBillRate * (-FractionalYear)));
	return a - (b * d);
}
//----------------------------------------------------------------------------------------------
function BlackScholesPutValue(Current, Strike, TBillRate, Volatility, FractionalYear)
{
	var a = (Current * (StandardNormalPx(-BlackScholesDen1(Current, Strike, TBillRate, Volatility, FractionalYear))));
	var b = (StandardNormalPx(-BlackScholesDen2(Current, Strike, TBillRate, Volatility, FractionalYear)));
	var d = (Strike * Math.exp(-TBillRate * FractionalYear)); 
	return (b * d) - a;
}
//----------------------------------------------------------------------------------------------

