// --------------------------------------------------------------------------------------------------------------------
//
// 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));
}
}
}
}