Существуют ли известные методы для создания реалистично выглядящих поддельных данных об акциях?

Недавно я написал некоторый код Javascript для создания случайных поддельных данных об акциях, так как хотел показать график, который на первый взгляд выглядел как настоящие данные об акциях, но все, что я придумал, это довольно глупо. Мне просто интересно, есть ли какие-нибудь ресурсы, которые объясняют, как это можно сделать «правильно», то есть, чтобы вы получали реалистично выглядящие данные, которые имеют те же закономерности, что и реальные биржевые данные?


person Mark Rhodes    schedule 21.12.2011    source источник


Ответы (11)


У меня была книга Фрактальный анализ рынка (недавно избавилась от нее), в которой говорилось о статистические свойства цен акций. Не очень полезно для инвестирования, но, возможно, это могло бы помочь вам.

Вам понадобится что-то, что моделирует случайный процесс с желаемыми статистическими свойствами. Двумя примерами случайных процессов являются гауссовский белый шум и винеровский процесс (последний моделирует броуновское движение, а также является пределом случайного блуждания с малыми шагами).

Если я правильно помню из книги «Фрактальный анализ рынка», было утверждение, что логарифм цен акций имеет характеристики, подобные так называемому «шуму 1/f» или "розовый шум", поэтому вы можете поискать статьи о создании розового шума в программном обеспечении. (а затем возьмите результаты и вставьте их в e^x) (редактировать: ой, я неправильно запомнил. Похоже, это больше похоже на дробное броуновское движение)

(Вот хорошее читаемое эссе, в котором рассказывается об истории за изучением фрактальных случайных процессов — и того, как разлив Нила связан с фондовым рынком — к сожалению, это не входит в технические данные, но, возможно, есть такие поисковые термины, как Показатель Херста, с которого можно начать.)

Проблема усложняется, если вам нужно несколько серий биржевых данных. (в этом случае между акциями существует некоторая корреляция, которая зависит от различных общих факторов, например, национальной экономики, типа отрасли и т. д.). Я не уверен, как вы могли бы это сделать, но сначала начните с одного случайного процесса.

person Jason S    schedule 21.12.2011
comment
Спасибо за это. Я должен получить чтение! Да, я понимаю, что вы имеете в виду, когда говорите о нескольких акциях. Я думаю, если вы хотите имитировать акции в определенном секторе, скажем, которые имеют тенденцию расти и падать вместе, это намного сложнее. Также, чтобы он хорошо выглядел в разные периоды - например. день, месяц и год, тогда это выглядит как настоящий вызов! - person Mark Rhodes; 22.12.2011
comment
Это также может быть новость, которая внезапно увлекает весь рынок в одном направлении. - person mouviciel; 22.12.2011

Простой алгоритм заключается в использовании простого числа волатильности, которое ограничивает, насколько акции могут измениться в течение заданного периода (скажем, одного дня). Чем выше число, тем выше волатильность. Таким образом, каждый день вы можете вычислять новую цену:

rnd = Random_Float(); // generate number, 0 <= x < 1.0
change_percent = 2 * volatility * rnd;
if (change_percent > volatility)
    change_percent -= (2 * volatility);
change_amount = old_price * change_percent;
new_price = old_price + change_amount;

Стабильная акция будет иметь число волатильности, возможно, 2%. Волатильность 10% показала бы довольно большие колебания.

Не идеально, но может выглядеть довольно реалистично.

Образцы

введите здесь описание изображения

person Jim Mischel    schedule 21.12.2011
comment
Downvoters: принято указывать причину с отрицательным голосом. - person Jim Mischel; 22.12.2011
comment
Я использовал это просто, чтобы возиться с несколькими вещами, это здорово! Однако, возможно, это просто моя математика, но сумма сдачи не должна быть такой: change_amount = (old_price / 100) * change_percent; - person wiggles; 02.07.2012
comment
Я создал реализацию Java на основе этого алгоритма, который очень хорошо работал для моих нужд. Поскольку вы не можете публиковать код в комментарии, я добавил ниже ответ с кодом: stackoverflow.com/a/22355778/1360592 - person Robin Zimmermann; 12.03.2014
comment
Я просто хочу, чтобы вы знали, что я возвращался к этому ответу несколько раз на протяжении многих лет. Я хотел бы проголосовать за это более одного раза. - person Ryan Guill; 14.03.2015
comment
@Jim Mischel - я добавил картинку, показывающую, как это выглядит. Надеюсь, это круто с тобой. Кстати отличный алгоритм. Ваше здоровье! - person potatopeelings; 02.07.2015
comment
Обратите внимание, что если ваше число volatility находится в диапазоне от 1 до 100, то да, вам нужно разделить на 100, как указано в комментарии. Но если ваш volatility представляет собой число с плавающей запятой от 0 до 1 (т. е. .02 равно 2%), то деление не требуется. - person Jim Mischel; 02.07.2015
comment
Упрощение: rnd = Random_Float() - 0.5;, а затем удалите if (change_percent > volatility) change_percent -= (2 * volatility); - person Lawrence Wagerfield; 22.10.2016
comment
не забудьте old_price = new_price в конце итерации - person maskalek; 05.05.2020

# The following is an adaptation from a program shown at page 140 in
# "Stochastic Simulations and Applications in Finance",
# a book written by Huynh, Lai and Soumaré.
# That program was written in MatLab and this one was written in R by me.
# That program produced many price paths and this one produces one.
# The latter is also somewhat simpler and faster.

# Y is the time period in years, for instance 1 (year)
# NbSteps is the number of steps in the simulation,
# for instance 250 (trading days in a year).
# DeltaY is the resulting time step.

# The computations shown implement the exact solution
# to the stochastic differential equation for
# the geometric Brownian motion modelling stock prices,
# with mean mu and volatility sigma, thus generating a stochastic price path
# such as that exhibited by stock prices when price jumps are rare.

PricePath <- function(Y,NbSteps,mu,sigma,InitPrice) {
    DeltaY <- Y/NbSteps; SqrtDeltaY <- sqrt(DeltaY)
    DeltaW <- SqrtDeltaY * rnorm(NbSteps)
    Increments <- (mu-sigma*sigma/2)*DeltaY + sigma*DeltaW
    ExpIncr <- exp(Increments)
    PricePath <- cumprod(c(InitPrice,ExpIncr))
    return(PricePath)
}

График вывода этой программы очень похож на траекторию движения цены акций:

person Jean-Victor Côté    schedule 22.12.2011

Есть несколько ответов, которые дают вполне хрестоматийный ответ: используйте геометрическое броуновское движение для моделирования цен на акции. Но есть одна важная причина считать это неправильным. Реальные цены акций не ведут себя как геометрическое броуновское движение (GBM). Я объясню это немного позже.

Причина, по которой GBM используется в учебниках для моделирования процесса цен на акции, заключается в простоте. Это поможет вам сдвинуть теорию с мертвой точки и получить некоторые основные результаты, которые кажутся «по существу» правильными. Однако это не означает, что вы должны думать, что именно так «выглядят» цены акций. Это было бы похоже на вывод уравнения движения без учета трения (что теоретически очень полезно), а затем думать, что это то, как движение выглядит в реальной жизни, например. все скользят на своих ботинках, как на коньках.

Одним из теоретически наиболее полезных свойств GBM является то, что будущие изменения не зависят от прошлых изменений. Верно ли это для цен на акции? Неа. Нисколько. Последовательная корреляция встречается повсеместно. Мало того, за большим снижением обычно следует повышенная волатильность, а за большим ростом обычно следует снижение волатильности.

Я предполагаю, что меня могут обвинить в придирках, но эти стилизованные факты широко известны инвесторам и экономистам, поэтому я думаю, будет справедливо сказать, что GBM не выглядит реалистичным для любого, кто знаком с поведением фондового рынка.

Специалисты по эконометрике придумали множество моделей цен на акции. Тот, который, кажется, работает во многих ситуациях, представляет собой авторегрессионную модель для условного среднего в сочетании с моделью типа (G)Arch для волатильности. Для модели волатильности асимметричный GARCH с распределением с толстым хвостом (например, t Стьюдента), по-видимому, лучше всего работает для различных финансовых рынков.

person C S    schedule 25.11.2013

Я написал быструю грязную версию javascript, вдохновленную ответом Питера П. здесь. Мне нужно было создать еженедельные, годовые и общие тренды, чтобы он принимал множество параметров и накладывал их, чтобы получить более сложный (фальшивый) тренд.

  function getRandomData(numPoints, center, min, max, cycles)
{
    var result = [];
    var phase = Math.random() * Math.PI;
    var y = center;

    function randomPlusMinus() { return (Math.random() * 2) - 1; }

    $.each(cycles, function(i,thisCycle) {
        thisCycle.phase = Math.random() * Math.PI;
        thisCycle.increment = Math.PI / thisCycle.length;
    });

    for (var i = 0; i < numPoints; i++)
    {
        $.each(cycles, function(i,thisCycle) {
            thisCycle.phase += thisCycle.increment * randomPlusMinus();
            y += (Math.sin(thisCycle.phase) * (thisCycle.variance / thisCycle.length) * (randomPlusMinus() * thisCycle.noise)) + (thisCycle.trend / thisCycle.length);

        });
        if (min) y = Math.max(y,min);
        if (max) y = Math.min(y,max);
        result.push(y);
    }

    return result;
}

var data = getRandomData(365,80,20,100,
                      [{ length: 7, variance: 50, noise: 1, trend: 0},
                       { length: 365, variance: 30, noise: 1, trend: 0},
                       { length: 700, variance: 2, noise: 0, trend: 100}]);

Я поместил туда диаграмму, чтобы показать результат: http://jsfiddle.net/z64Jr/3/

person Andrej Kyselica    schedule 07.01.2014

Я хотел ответить на сообщение Джима Мишеля выше (https://stackoverflow.com/a/8597889/1360592), но так как Я хотел включить код, я вынужден поместить свой ответ здесь.

Основываясь на алгоритме Джима Мишеля, я сделал следующую реализацию Java, и она хорошо работала для моих нужд, генерируя числа, которые при графическом отображении давали визуально привлекательные, реалистично выглядящие котировки акций.

Java:

private float getNextPrice(float oldPrice)
{
    // Instead of a fixed volatility, pick a random volatility
    // each time, between 2 and 10.
    float volatility = _random.nextFloat() * 10 + 2;

    float rnd = _random.nextFloat();

    float changePercent = 2 * volatility * rnd;

    if (changePercent > volatility) {
        changePercent -= (2 * volatility);
    }
    float changeAmount = oldPrice * changePercent/100;
    float newPrice = oldPrice + changeAmount;

    // Add a ceiling and floor.
    if (newPrice < MIN_PRICE) {
        newPrice += Math.abs(changeAmount) * 2;
    } else if (newPrice > MAX_PRICE) {
        newPrice -= Math.abs(changeAmount) * 2;
    }

    return newPrice;

}

Обратите внимание, что, как указал wiggles в своем комментарии, мне нужно было разделить процент на 100 при объявлении переменной changeAmount.

person Robin Zimmermann    schedule 12.03.2014

Взгляните на Yahoo Finance, они предлагают бесплатные отложенные данные с фондовой биржи и графики.

Вот статья об использовании фида: http://www.codeproject.com/KB/aspnet/StockQuote.aspx

Вам понадобится JQuery или вы можете просто использовать XMLHttpRequest для использования службы. К вашему сведению, есть плагин для JQuery для обработки CSV: http://code.google.com/p/js-tables/

person Nickz    schedule 21.12.2011
comment
... или, в зависимости от необходимости, можно было бы загрузить фактические ряды цен на акции с длинной историей (что означает: без оперативных обновлений). - person Predictor; 23.12.2011

Мне нужно было создать фиктивные рыночные данные для симулятора, над которым я работал. Мне нужно было, чтобы данные выглядели как рыночные данные, но оставались в определенных диапазонах, чтобы они были предсказуемы с точки зрения начальной цены, максимума/минимума за день.

В конце концов, я объединил синусоидальные волны разных частот, а затем добавил некоторую случайность, и результаты не просто выглядят хорошо, но и согласуются (вы не получите ничего, что выглядело бы странно). Даже там, где синусоида может быть воспринята, она все еще выглядит нормально.

Случайно сгенерированные рыночные данные

Код написан на языке сценариев BASIC, но он должен быть очень простым для понимания и преобразования на любой нужный вам язык. Получив массив нормализованных данных, умножьте значения на максимальное значение, которое вы хотите получить, чтобы получить ограниченный набор данных.

dim values[] as float
dim offsets[] as integer
dim frequencies[] as float

function GetPoint(x#, f#, a#, o#)

    f# = 360.0 / f#

    x# = FMod(x# + o#, f#)
    angle# = (x# / f#) * 360.0

    r# = Sin(angle#) * a#

endfunction r#

function Generate()

    // Empty arrays
    offsets.Length = -1
    frequencies.Length = -1
    values.Length = -1

    offsets.Insert(Random(0, 359))
    offsets.Insert(Random(0, 359))
    offsets.Insert(Random(0, 359))

    f# = Random(100, 300)
    f# = f# / 1000.0
    frequencies.Insert(f#)
    f# = Random(500, 1000)
    f# = f# / 1000.0
    frequencies.Insert(f#)
    f# = Random(2000, 4000)
    f# = f# / 1000.0
    frequencies.Insert(f#)

    c# = 0
    for i = 0 to 1919
        v# = 0
        v# = v# + GetPoint(i, frequencies[0], 190, offsets[0])
        v# = v# + GetPoint(i, frequencies[1], 85, offsets[1])
        v# = v# + GetPoint(i, frequencies[2], 40, offsets[2])

        r# = Random(0, 40)
        r# = r# - 20.0

        c# = Clamp(c# + r#, c# - 40, c# + 40)
        v# = v# + c#

        values.Insert(v#)
    next i

    start# = values[0]
    max# = 0.0
    for i = 0 to values.Length
        values[i] = values[i] - start#
        if Abs(values[i]) > max#
            max# = Abs(values[i])
        endif
    next i

    // Normalize
    for i = 0 to values.Length
        values[i] = (values[i] / max#)
    next i

endfunction

function Clamp(v#, min#, max#)

    if v# < min#
        exitfunction min#
    elseif v# > max#
        exitfunction max#
    endif

endfunction v#
person John Stabler    schedule 20.05.2017
comment
Я преобразовал это в ES6, и сгенерированные данные не имеют смысла по отношению к вашему примерному графику. Можете ли вы объяснить, как сгенерированные данные должны быть представлены в виде графика? Спасибо. - person PRS; 03.07.2017
comment
Данные нормализованы, поэтому вам нужно будет умножить их на любое максимальное значение, которое вы ищете. Затем просто переберите данные и постройте график. - person John Stabler; 21.07.2017

Вот моя попытка в рубине! :) Это выведет строку, которую вы можете скопировать и вставить в диаграммы Google. Я допускаю положительный, отрицательный или нулевой тренд данных. Этот код, вероятно, можно было бы оптимизировать и/или настроить для обеспечения случайности/регулярности.

Диаграммы Google: https://code.google.com/apis/ajax/playground/?type=visualization#line_chart

# In order to generate a semi-realistic looking graph behavior
# we use a sine function to generate period behavior.  In order to avoid
# a graph that is too regular, we introduce randomness at two levels:
# The delta between steps across the x-axis is random, but within a range(deltavariance)
# The wavelength of the sine function is varied by randomly incrementing the index we pass
# to the sine function(sine_index)

# CONFIGURATION VARIABLES
yvalue = 1 # start value
range = 100 # y-range
deltavariance = 10 # allowable variance between changes
sine_index, wavelength = 0, 0.33 #index into our sine function that determines whether we change direction or not
i, maxi = 0, 100 # our counter and its maximum
data = {sine_index => yvalue} # seed our data structure with its first value
trend = :positive # :negative, :none # do we want the graph to trend upwards, downwards or neither
periodmin, periodmax = 0, 0 # vars to enforce trending
direction = 1 # start in a positive direction, -1 for negative

# DO NOT EDIT BELOW THIS LINE
while(i < maxi)

  olddirection = direction
  direction = Math.sin(sine_index).to_f
  direction = direction < 0 ? direction.floor : direction.ceil

  delta = rand(deltavariance) 
  yvalue += delta * direction

  if trend == :positive 
    yvalue = periodmin if yvalue < periodmin
    periodmin = yvalue if olddirection < direction
  elsif trend == :negative
    yvalue = periodmax if yvalue > periodmax
    periodmax = yvalue if olddirection > direction

  end

  data[sine_index] = yvalue
  sine_index += Math.sin(rand) # Math.sin(rand) will give random numbers from -1..1
  i += 1
end

code = <<-CODE
function drawVisualization() {
  // Create and populate the data table.
  var data = google.visualization.arrayToDataTable([
    ['x', 'Cats'],
    DATASTR
  ]);

  // Create and draw the visualization.
  new google.visualization.LineChart(document.getElementById('visualization')).
      draw(data, {curveType: "function",
                  width: 500, height: 400,
                  vAxis: {maxValue: 10}}
          );
}
CODE

datastr = data.collect{|k,v|  "[#{k},#{v}]"}.join(",")
code = code.gsub('DATASTR', datastr)
puts code
person Peter P.    schedule 20.11.2013
comment
извините, не знаю, почему подсветка синтаксиса не работает... см. эту пасту: pastie.org/8494639 - person Peter P.; 20.11.2013

double price=2000;
    while (true) {
        double min =  (price*-.02);
        double max =  (price*.02);
        double randomNum = ThreadLocalRandom.current().nextDouble(min, max+1);
        price=price+randomNum;
        System.out.println(price);
    }

Это в джаве. Просто нанесите результат в столбец Excel, чтобы увидеть график. Используйте большой набор значений для построения графика в Excel. Интересно видеть, насколько это похоже на реальные биржевые данные.

person rajaraja chola    schedule 11.01.2017

Вот код, который я создал для своего использования. Цены создаются для новой свечи, которая включает в себя открытие, максимум, минимум, закрытие и объем. Новые цены генерируются на основе % волатильности. Я использовал всего 5% для цен.

Код основан на C#.

public class PriceBar
{
    public DateTime Date { get; set; }
    public double Open { get; set; }
    public double High { get; set; }
    public double Low { get; set; }
    public double Close { get; set; }
    public long Volume { get; set; }
}

public static double GetRandomNumber(double minimum, double maximum)
{
    Random random = new Random();
    return random.NextDouble() * (maximum - minimum) + minimum;
}

public static void GenerateRandomBar(PriceBar newBar)
{
    double fluct = 0.025;
    double volFluct = 0.40;

    //Open is equal to the previous close
    newBar.Open = newBar.Close;
    newBar.Close = GetRandomNumber(newBar.Close - newBar.Close * fluct, newBar.Close + newBar.Close * fluct);
    newBar.High = GetRandomNumber(Math.Max(newBar.Close, newBar.Open), Math.Max(newBar.Close, newBar.Open) + Math.Abs(newBar.Close - newBar.Open) * fluct);
    newBar.Low = GetRandomNumber(Math.Min(newBar.Close, newBar.Open), Math.Min(newBar.Close, newBar.Open) - Math.Abs(newBar.Close - newBar.Open) * fluct);
    newBar.Volume = (long)GetRandomNumber(newBar.Volume * volFluct, newBar.Volume);
}

Применение:

Создайте экземпляр PriceBar, заполните цены предыдущего бара. Передайте экземпляр PriceBar функции GenerateRandomBar(). Он вернет PriceBar с новыми значениями.

person Hao Nguyen    schedule 05.08.2014
comment
Это не то, как вы генерируете данные HOLC. Реалистично выглядящий (фальшивый) поток ордеров, однажды сгенерированный, может быть разложен на временные рамки, которые в основном представляют собой группу всех ордеров, размещенных в течение определенных периодов (1 м, 3 м, 10 м, 1 день и т. д.). Затем вы можете извлечь цену открытия, максимальную, минимальную и цену закрытия соответственно на основе тиковых данных. Генерация случайных данных HOLC не имеет никакого смысла. - person Rikki; 29.08.2020