/*================================================================================
* Индикатор: Inverted Normal Distribution (обратное распределение)
* Платформа: TSLab версия 1.1.8.0
* Дата создания: 20.07.2010
*================================================================================*/
using System;
using System.Collections.Generic;
using TSLab.Script;
using TSLab.Script.Handlers;
using TSLab.DataSource;
using TSLab.Script.Helpers;
namespace inv_nd
{
public class InvNormalDistr : IDoubleAccum3Handler, IContextUses
{
public const double DBL_EPSILON = 0.0000001;
public int lower_tail = 1;
public int log_p = 0;
//[HandlerParameter]
//public int Period { get; set; }
//--------------------------------------------------------------------------------
double ML_POSINF()
{
return ((-1.0) / (0.0));
}
//--------------------------------------------------------------------------------
double ML_NEGINF()
{
return ((-1.0) / (0.0));
}
//--------------------------------------------------------------------------------
double R_D__0()
{
return (log_p != 0 ? ML_NEGINF() : 0.0);
}
//--------------------------------------------------------------------------------
double R_D__1()
{
return (log_p != 0? 0.0 : 1.0);
}
//--------------------------------------------------------------------------------
double R_DT_0()
{
return (lower_tail != 0 ? R_D__0() : R_D__1());
}
//--------------------------------------------------------------------------------
double R_DT_1()
{
return (lower_tail != 0 ? R_D__1() : R_D__0());
}
//--------------------------------------------------------------------------------
bool R_Q_P01_check(double p)
{
return ((log_p != 0 && p > 0) || (log_p == 0 && (p < 0 || p > 1)));
}
//--------------------------------------------------------------------------------
double R_D_Cval(double p)
{
return (lower_tail != 0 ? (1 - (p)) : (p));
}
//--------------------------------------------------------------------------------
double R_D_Lval(double p)
{
return (lower_tail != 0 ? (p) : (1 - (p)));
}
//--------------------------------------------------------------------------------
double R_DT_qIv(double p)
{
return (log_p != 0 ? (lower_tail != 0 ? Math.Exp(p) : -expm1(p)) : R_D_Lval(p));
}
//--------------------------------------------------------------------------------
double R_DT_CIv(double p)
{
return (log_p != 0 ? (lower_tail != 0 ? -expm1(p) : Math.Exp(p)) : R_D_Cval(p));
}
//--------------------------------------------------------------------------------
double expm1(double x)
{
//double y, a = fabs(x);
double y, a = Math.Abs(x);
if (a < DBL_EPSILON) return x;
if (a > 0.697) return Math.Exp(x) - 1; /* negligible cancellation */
if (a > 0.00000001) // 1e-8
y = Math.Exp(x) - 1;
else /* Taylor expansion, more accurate in this range */
y = (x / 2 + 1) * x;
/* Newton step for solving log(1 + y) = x for y : */
/* WARNING: does not work for y ~ -1: bug in 1.5.0 */
y -= (1 + y) * (Math.Log(1+y) - x);
return y;
}
//================================================================================
double qnorm(double p, double mu, double sigma)
{
double p_, q, r, val;
lower_tail = 1;
log_p = 0;
if (p == R_DT_0()) return ML_NEGINF();
if (p == R_DT_1()) return ML_POSINF();
if (R_Q_P01_check(p)) return 0;
if(sigma < 0) return 0;
if(sigma == 0) return mu;
p_ = R_DT_qIv(p); /* real lower_tail prob. p */
q = p_ - 0.5;
if (Math.Abs(q) <= 0.425)
{ /* 0.075 <= p <= 0.925 */
r = 0.180625 - q * q;
val =
q * (((((((r * 2509.0809287301226727 +
33430.575583588128105) * r + 67265.770927008700853) * r +
45921.953931549871457) * r + 13731.693765509461125) * r +
1971.5909503065514427) * r + 133.14166789178437745) * r +
3.387132872796366608)
/ (((((((r * 5226.495278852854561 +
28729.085735721942674) * r + 39307.89580009271061) * r +
21213.794301586595867) * r + 5394.1960214247511077) * r +
687.1870074920579083) * r + 42.313330701600911252) * r + 1.0);
}
else
{ /* closer than 0.075 from {0,1} boundary */
/* r = min(p, 1-p) < 0.075 */
if (q > 0)
r = R_DT_CIv(p);/* 1-p */
else
r = p_;/* = R_DT_Iv(p) ^= p */
r = Math.Sqrt(- ((log_p != 0 &&
((lower_tail != 0 && q <= 0) || (lower_tail == 0 && q > 0))) ?
p : /* else */ Math.Log(r)));
/* r = sqrt(-log(r)) <==> min(p, 1-p) = exp( - r^2 ) */
if (r <= 5.0)
{ /* <==> min(p,1-p) >= exp(-25) ~= 1.3888e-11 */
r += -1.6;
val = (((((((r * 7.7454501427834140764e-4 +
0.0227238449892691845833) * r + 0.24178072517745061177) *
r + 1.27045825245236838258) * r +
3.64784832476320460504) * r + 5.7694972214606914055) *
r + 4.6303378461565452959) * r +
1.42343711074968357734)
/ (((((((r *
1.05075007164441684324e-9 + 5.475938084995344946e-4) *
r + 0.0151986665636164571966) * r +
0.14810397642748007459) * r + 0.68976733498510000455) *
r + 1.6763848301838038494) * r +
2.05319162663775882187) * r + 1.0);
}
else
{ /* very close to 0 or 1 */
r += -5.0;
val = (((((((r * 2.01033439929228813265e-7 +
2.71155556874348757815e-5) * r +
0.0012426609473880784386) * r + 0.026532189526576123093) *
r + 0.29656057182850489123) * r +
1.7848265399172913358) * r + 5.4637849111641143699) *
r + 6.6579046435011037772)
/ (((((((r *
2.04426310338993978564e-15 + 1.4215117583164458887e-7)*
r + 1.8463183175100546818e-5) * r +
7.868691311456132591e-4) * r + 0.0148753612908506148525)
* r + 0.13692988092273580531) * r +
0.59983220655588793769) * r + 1.0);
}
if(q < 0.0)
val = -val;
/* return (q >= 0.)? r : -r ;*/
}
return mu + sigma * val;
}
//--------------------------------------------------------------------------------
public IList<double> Execute (IList<double> source1, IList<double> source2, IList<double> source3)
//public IList<double> Execute(ISecurity source)
{
double p = 0;
double mu = 0;
double sigma = 0;
double inv_nd = 0;
IList<double> list = new List<double>(source1.Count);
for (int bar = 0; bar < source1.Count; bar++)
{
p = source1[bar];
mu = source2[bar];
sigma = source3[bar];
inv_nd = qnorm(p, mu, sigma);
list.Add(inv_nd);
}
return list;
}
public IContext Context { get; set; }
}
}