Использование формулы Келли в программировании

Перевод статьи Agent Based Kelly Formula с любезного согласия Nathan Epstein

Введение

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

Критерий Келли - хорошо известная формула для определения оптимального размера ставок. Размер ставки - доля текущего банкролла, определяемая для оптимизации темпов роста по сравнению с последовательными ставками. Это - функция вероятности выигрыша каждой ставки (назовем ее p) и коэффициент (назовем его b).

Формула для оптимального размера ставки определяется как.

Эксперимент

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

Каждый агент имеет параметр, bet_on_heads, долю стоимости ставки головы (от -1 до +1 с -1: на хвостах -1,  1 - на головах). Если агент угадает правильно - он получит сумму ставки. Если агент угадает НЕправильно - он теряет сумму ставки (т.е. шансы 1-1 или b=1).

Мы создаем имитацию для каждого р в 0, 0,01, ..., 1. В каждой модели, мы создаем 1000 агентов и переворот 1000 раз. Это позволяет нам отслеживать эффективность каждого пари для каждого значения р.

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

Код

Код, используемый для моделирования (написан в Ruby) представлен ниже. Он также доступен в репозитории gist.

require 'csv'

class Simulation
  def initialize(prob_H,num_agents)
    @prob_H = prob_H
    @population = []
    for i in 1..num_agents
      amount_on_heads = 2*(i.to_f/num_agents) - 1 #uniform from -1 to 1
      @population.push(Agent.new(amount_on_heads))
    end
  end
  def flip(iterations)
    for i in 1..iterations
      rand < @prob_H ? outcome = 'H' : outcome = 'T'
      for agent in @population
        agent.bet(outcome)
      end
    end
  end
  def get_population
    return @population
  end
end

class Agent
  def initialize(amount_on_heads)
    @amount_on_heads = amount_on_heads
    @wealth = 1
  end
  def bet(outcome)
    outcome == 'H' ? @wealth = @wealth * (1 + @amount_on_heads) : @wealth = @wealth * (1 - @amount_on_heads)
  end
  def get_wealth
    return @wealth
  end
  def get_bet
    return @amount_on_heads
  end
end


# CONVENIENCE FUNCTIONS
def avg_weighted_bet(population)
  total_wealth = 0
  for agent in population
    total_wealth += agent.get_wealth
  end
  result = 0
  for agent in population
    result += agent.get_bet * (agent.get_wealth.to_f/total_wealth)
  end
  return result
end

def max_wealth_bet(population)
  max_wealth = population[0].get_wealth
  bet = population[0].get_bet
  for agent in population
    if agent.get_wealth > max_wealth
      max_wealth = agent.get_wealth
      bet = agent.get_bet
    end
  end
  return bet
end

# RUN THE SIMULATION FOR EACH PROBABILITY
kelly_values = []
max_values = []
avg_values = []

for i in 0..100
  prob_H = i.to_f/100
  num_agents = 1000
  kelly_values.push(2*prob_H - 1)

  s = Simulation.new(prob_H,num_agents)
  s.flip(1000)
  max_values.push(max_wealth_bet(s.get_population))
  avg_values.push(avg_weighted_bet(s.get_population))
end

CSV.open('./results.csv','w') do |csv|
  csv << kelly_values
  csv << max_values
  csv << avg_values
end

Результаты

Этот график указывает на богатство средневзвешенной стратегии (красная линия) и стратегии Келли (серая линия) функции р.

Следующий график отображает стратегию максимального богатства (красная линия) и стратегию Келли (серая линия) как функцию р.

Понятно, что максимальное и средневзвешенное богатство дают почти идентичные результаты, и это ясно по обе линии стратегии Келли. Таким образом, стратегия на основе модели произвела результат критерия Келли.