Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple iterations of random double numbers tend to get smaller

I am creating a stock trading simulator where the last days's trade price is taken as opening price and simulated through out the current day.

For that I am generating random double numbers that may be somewhere -5% of lastTradePrice and 5% above the lastTradePrice. However after around 240 iterations I see how the produced double number gets smaller and smaller closing to zero.

Random rand = new Random();
Thread.Sleep(rand.Next(0,10));
Random random = new Random();
double lastTradeMinus5p = model.LastTradePrice - model.LastTradePrice * 0.05;
double lastTradePlus5p = model.LastTradePrice + model.LastTradePrice * 0.05;
model.LastTradePrice = random.NextDouble() * (lastTradePlus5p - lastTradeMinus5p) + lastTradeMinus5p;

As you can see I am trying to get random seed by utilising Thread.sleep(). And yet its not truly randomised. Why is there this tendency to always produce smaller numbers?

enter image description here

Update:

The math itself is actually fine, despite the downwards trend as Jon has proven it. Getting random double numbers between range is also explained here.

The real problem was the seed of Random. I have followed Jon's advice to keep the same Random instance across the thread for all three prices. And this already is producing better results; the price is actually bouncing back upwards. I am still investigating and open to suggestions how to improve this. The link Jon has given provides an excellent article how to produce a random instance per thread.

Btw the whole project is open source if you are interested. (Using WCF, WPF in Browser, PRISM 4.2, .NET 4.5 Stack)

The TransformPrices call is happening here on one separate thread.

This is what happens if I keep the same instance of random: enter image description here

And this is generated via RandomProvider.GetThreadRandom(); as pointed out in the article: enter image description here

like image 905
Houman Avatar asked Feb 25 '14 10:02

Houman


People also ask

What happens when you draw an infinite number of random samples?

Therefore, when drawing an infinite number of random samples, the variance of the sampling distribution will be lower the larger the size of each sample is. In other words, the bell shape will be narrower when each sample is large instead of small, because in that way each sample mean will be closer to the center of the bell.

Why does the sum of two random variables equal standard deviation?

It's a consequence of the simple fact that the standard deviation of the sum of two random variables is smaller than the sum of the standard deviations (it can only be equal when the two variables are perfectly correlated).

What is the probability of picking all p picks from d distinct numbers?

Let's generalize by picking p numbers from 1\dots n with replacement. Let us compute the probability of choosing d distinct numbers. Choose one of the \binom {n} {d} sets of d distinct numbers. The probability of selecting all p picks from those d distinct numbers is \left (\frac {d} {n}ight)^p.


1 Answers

Firstly, calling Thread.Sleep like this is not a good way of getting a different seed. It would be better to use a single instance of Random per thread. See my article on randomness for some suggested approaches.

However, your code is also inherently biased downwards. Suppose we "randomly" get 0.0 and 1.0 from the random number generator, starting with a price of $100. That will give:

  • Day 0: $100
  • Day 1: $95 (-5% = $5)
  • Day 2: $99.75 (+5% = $4.75)

Now we can equally randomly get 1.0 and 0.0:

  • Day 0: $100
  • Day 1: $105 (+5% = $5)
  • Day 2: $99.75 (-5% = $5.25)

Note how we've got down in both cases, despite this being "fair". If the value increases, that means it can go down further on the next roll of the dice, so to speak... but if the value decreases, it can't bounce back as far.

EDIT: To give an idea of how a "reasonably fair" RNG is still likely to give a decreasing value, here's a little console app:

using System;

class Test
{
    static void Main()
    {
        Random random = new Random();
        int under100 = 0;
        for (int i = 0; i < 100; i++)
        {
            double price = 100;
            double sum = 0;

            for (int j = 0; j < 1000; j++)
            {
                double lowerBound = price * 0.95;
                double upperBound = price * 1.05;
                double sample = random.NextDouble();
                sum += sample;
                price = sample * (upperBound - lowerBound) + lowerBound;                
            }
            Console.WriteLine("Average: {0:f2} Price: {1:f2}", sum / 1000, price);
            if (price < 100)
            {
                under100++;
            }
        }
        Console.WriteLine("Samples with a final price < 100: {0}", under100);
    }
}

On my machine, the "average" value is always very close to 0.5 (rarely less then 0.48 or more than 0.52) but the majority of "final prices" are always below 100 - about 65-70% of them.

like image 56
Jon Skeet Avatar answered Oct 29 '22 22:10

Jon Skeet