// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) 2014 OxyPlot contributors // // // Creates realistic OHLCV items. // // -------------------------------------------------------------------------------------------------------------------- namespace ExampleLibrary { using System; using System.Collections.Generic; using OxyPlot.Axes; using OxyPlot.Series; /// /// Creates realistic OHLCV items. /// public static class OhlcvItemGenerator { /// /// The random number generator. /// private static readonly Random Rand = new Random(); /// /// Creates bars governed by a MR process. /// /// N. /// X0. /// V0. /// Csigma. /// Esigma. /// Kappa. /// /// The process. /// public static IEnumerable MRProcess( int n, double x0 = 100.0, double v0 = 500, double csigma = 0.50, double esigma = 0.75, double kappa = 0.01) { double x = x0; var baseT = DateTime.UtcNow; for (int ti = 0; ti < n; ti++) { var dx_c = -kappa * (x - x0) + RandomNormal(0, csigma); var dx_1 = -kappa * (x - x0) + RandomNormal(0, esigma); var dx_2 = -kappa * (x - x0) + RandomNormal(0, esigma); var open = x; var close = x = x + dx_c; var low = Min(open, close, open + dx_1, open + dx_2); var high = Max(open, close, open + dx_1, open + dx_2); var dp = close - open; var v = v0 * Math.Exp(Math.Abs(dp) / csigma); var dir = (dp < 0) ? -Math.Min(-dp / esigma, 1.0) : Math.Min(dp / esigma, 1.0); var skew = (dir + 1) / 2.0; var buyvol = skew * v; var sellvol = (1 - skew) * v; var nowT = baseT.AddSeconds(ti); var t = DateTimeAxis.ToDouble(nowT); yield return new OhlcvItem(t, open, high, low, close, buyvol, sellvol); } } /// /// Finds the minimum of the specified a, b, c and d. /// /// A. /// B. /// C. /// D. /// The minimum. private static double Min(double a, double b, double c, double d) { return Math.Min(a, Math.Min(b, Math.Min(c, d))); } /// /// Finds the maximum of the specified a, b, c and d. /// /// A. /// B. /// C. /// D. /// The maximum. private static double Max(double a, double b, double c, double d) { return Math.Max(a, Math.Max(b, Math.Max(c, d))); } /// /// Gets random normal /// /// Mu. /// Sigma. /// private static double RandomNormal(double mu, double sigma) { return InverseCumNormal(Rand.NextDouble(), mu, sigma); } /// /// Fast approximation for inverse cum normal /// /// probability /// Mean /// std dev private static double InverseCumNormal(double p, double mu, double sigma) { const double A1 = -3.969683028665376e+01; const double A2 = 2.209460984245205e+02; const double A3 = -2.759285104469687e+02; const double A4 = 1.383577518672690e+02; const double A5 = -3.066479806614716e+01; const double A6 = 2.506628277459239e+00; const double B1 = -5.447609879822406e+01; const double B2 = 1.615858368580409e+02; const double B3 = -1.556989798598866e+02; const double B4 = 6.680131188771972e+01; const double B5 = -1.328068155288572e+01; const double C1 = -7.784894002430293e-03; const double C2 = -3.223964580411365e-01; const double C3 = -2.400758277161838e+00; const double C4 = -2.549732539343734e+00; const double C5 = 4.374664141464968e+00; const double C6 = 2.938163982698783e+00; const double D1 = 7.784695709041462e-03; const double D2 = 3.224671290700398e-01; const double D3 = 2.445134137142996e+00; const double D4 = 3.754408661907416e+00; const double Xlow = 0.02425; const double Xhigh = 1.0 - Xlow; double z, r; if (p < Xlow) { // Rational approximation for the lower region 0 /// Cumulative for a N(0,1) distribution /// /// The n0. /// The x coordinate. private static double CumN0(double x) { const double B1 = 0.319381530; const double B2 = -0.356563782; const double B3 = 1.781477937; const double B4 = -1.821255978; const double B5 = 1.330274429; const double P = 0.2316419; const double C = 0.39894228; if (x >= 0.0) { double t = 1.0 / (1.0 + (P * x)); return (1.0 - C * Math.Exp(-x * x / 2.0) * t * (t * (t * (t * (t * B5 + B4) + B3) + B2) + B1)); } else { double t = 1.0 / (1.0 - P * x); return (C * Math.Exp(-x * x / 2.0) * t * (t * (t * (t * (t * B5 + B4) + B3) + B2) + B1)); } } } }