Заказать токеномику

Агентное моделирование в токеномике

Когда табличная модель не справляется: агентное моделирование для стресс-тестирования токеномики. Код на Python, графики, разбор результатов.

Проблема: таблица считает средние, а система ломается на крайностях

Табличная модель токеномики оперирует агрегатами: общий supply, средняя цена, суммарный стейкинг. Это полезный инструмент — мы сами начинаем каждый проект с таблицы. Но у таблицы есть фундаментальное ограничение: она не моделирует поведение отдельных участников.

Рассмотрим стейкинг. Таблица говорит: «при APR 5% будет стейкаться 60% токенов». Один сценарий, одно число. Но в реальности стейк распределён неравномерно — 10 кошельков могут контролировать 25% стейка. Если три кита решат выйти одновременно, APR изменится, что спровоцирует реакцию остальных участников. Таблица этого не покажет.

Агентное моделирование (agent-based modeling, ABM) строит систему снизу вверх: каждый участник — отдельный агент со своим балансом, стратегией и порогами принятия решений. Модель запускается на сотни итераций, и на каждом шаге агенты принимают решения исходя из текущего состояния системы.

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

Когда нужна агентная модель, а когда хватит таблицы

ЗадачаТаблицаABM
Allocation и вестинг-графикиПодходитИзбыточно
Прогноз supply при заданной эмиссииПодходитИзбыточно
Unit-экономика (CAC, LTV)ПодходитИзбыточно
Стейкинг с неравномерным распределениемНе видит каскадовНеобходима
Governance-голосованиеНе видит атакНеобходима
AMM-пулы и ликвидностьНе видит проскальзыванияНеобходима
Экономики с несколькими типами участниковНе видит взаимодействийНеобходима
Когда табличная модель, а когда агентнаяДерево решений: если действия участника влияют на остальных — нужна ABM, иначе — таблицаДействия одного участникаменяют условия для остальных?НетДаТабличная модельallocation, вестинг, unit-экономикаАгентная модельстейкинг, AMM, governance

Правило простое: если действия одного участника меняют условия для остальных — нужна ABM. Если нет — таблицы достаточно.

Пример: стейкинг и банк-ран

Разберём конкретный случай, где табличная модель даёт ложную уверенность, а агентная симуляция выявляет системный риск.

Постановка задачи

Протокол с фиксированной эмиссией: 800 токенов в день распределяются между стейкерами пропорционально доле. При 60% застейканных токенов это даёт APR ~4.9% годовых.

Вопросы:

  • Сколько стейкеров останется, если APR ниже ожиданий части участников?
  • Что произойдёт, если 10 крупнейших кошельков выйдут одновременно?

Табличная модель ответит просто: «при выходе 10 стейкеров APR вырастет пропорционально». Но это не учитывает кто выходит (кит или мелкий холдер) и что произойдёт дальше (каскадная реакция).

Модель: 200 агентов с разными стратегиями

Каждый агент имеет три параметра:

ПараметрРаспределениеСмысл
БалансПарето (α=1.5)Несколько китов + много мелких, как в реальных сетях
Порог APRРавномерное (3–15%)Минимальный APR, ниже которого агент выходит
Задержка реакции1–14 днейНе все реагируют мгновенно

Распределение балансов выглядит так — степенной закон, топ-10 агентов контролируют ~22% стейка (конкретно при seed=42):

Распределение балансов агентов

Код симуляции

Полный код — можно скопировать в Google Colab и запустить:

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(42)

# === Параметры ===
num_agents = 200
num_steps = 365            # дней
total_supply = 10_000_000
daily_rewards = 800        # токенов/день (~4.9% APR при полном стейке)

# === Генерация агентов ===
# Балансы: степенной закон (Парето) — несколько китов, много мелких
raw = np.random.pareto(a=1.5, size=num_agents) + 1
balances = (raw / raw.sum() * total_supply * 0.6).astype(int)

# Порог APR: ниже этого значения агент выходит из стейкинга
apr_thresholds = np.random.uniform(0.03, 0.15, size=num_agents)

# Задержка реакции: сколько дней APR должен быть ниже порога
reaction_delay = np.random.randint(1, 15, size=num_agents)

# Состояние
is_staking = np.ones(num_agents, dtype=bool)
days_below_threshold = np.zeros(num_agents, dtype=int)

# Запись метрик
h_staked = np.zeros(num_steps)
h_apr = np.zeros(num_steps)
h_num = np.zeros(num_steps)

# === Симуляция ===
for day in range(num_steps):
    staked_total = balances[is_staking].sum()
    if staked_total == 0:
        break

    current_apr = (daily_rewards * 365) / staked_total

    h_staked[day] = staked_total
    h_apr[day] = current_apr
    h_num[day] = is_staking.sum()

    for i in range(num_agents):
        if not is_staking[i]:
            continue
        if current_apr < apr_thresholds[i]:
            days_below_threshold[i] += 1
            if days_below_threshold[i] >= reaction_delay[i]:
                is_staking[i] = False  # выход
        else:
            days_below_threshold[i] = 0  # сброс счётчика

Ключевая механика: на каждом шаге каждый агент проверяет текущий APR. Если APR ниже его порога дольше, чем его задержка реакции — он выходит. Выход одного агента уменьшает стейк, что меняет APR для всех остальных. Это и есть каскадный эффект, который невозможно увидеть в таблице.

Результаты

Запускаем два сценария на одних и тех же агентах:

  • Без шока — система эволюционирует сама
  • С шоком — на день 60 принудительно выводим 10 крупнейших стейкеров

Каскадный выход из стейкинга

Сценарий без шока

МетрикаДень 0День 7День 14Равновесие
Стейкеров2001308080
Стейк6.0M3.7M2.4M2.4M
APR4.9%7.8%12.1%12.1%

Начальный APR 4.87% — ниже порога для 167 из 200 агентов. По мере выхода агентов APR растёт, и в итоге выходят только те 120, у которых порог оставался выше APR достаточно долго (≥ их reaction_delay). Остальные 47 из 167 «не успели» — к моменту срабатывания их задержки APR уже превысил их порог. Стейк падает с 6M до 2.4M, APR вырастает до 12.1% — и система стабилизируется на день 15. Оставшиеся 80 агентов довольны.

Табличная модель сказала бы: «60% стейкается при APR 4.9%». Симуляция показала: реально стейкается 24% (2.4M из 10M), а APR в равновесии — 12.1%, не 4.9%.

Сценарий с шоком (10 китов выходят на день 60)

На день 60 система уже в равновесии (80 стейкеров, APR 12.1%). Затем 10 крупнейших кошельков выходят одновременно:

МетрикаДо шокаПосле шокаНовое равновесие
Стейкеров807070
Стейк2.4M1.38M1.38M
APR12.1%21.2%21.2%

Выход 10 китов убирает ~1M токенов из стейка. APR скачком растёт до 21.2%. В этом конкретном прогоне каскад не возникает — оставшиеся 70 агентов (с более низкими порогами) довольны новым APR, и система остаётся в этом состоянии.

В более реалистичной модели (с учётом падения цены токена при массовом выходе) эффект был бы обратным: выход китов → давление на продажу → цена падает → реальная доходность в долларах снижается → каскад усиливается.

Что показала симуляция, чего не показала бы таблица

  1. Реальное равновесие (80 стейкеров, не 200) — при том же APR и том же supply
  2. Скорость каскада (14 дней до стабилизации) — конкретная динамика, не «мгновенный пересчёт»
  3. Роль задержки реакции — агенты с delay=14 выходят позже, растягивая каскад
  4. Распределение имеет значение — выход 10 китов убрал ~1M токенов, а выход 10 мелких убрал бы ~130K

Как масштабировать эту модель

Пример выше — базовый. Для реального проекта можно добавить:

Обратную связь через цену. Сейчас цена токена не меняется при выходе из стейкинга. В реальности выход → продажа → падение цены → снижение реальной доходности → каскад усиливается. Это превращает мягкую стабилизацию в жёсткий банк-ран.

Несколько типов агентов. «Фермеры» перемещаются между протоколами при изменении APR, «ходлеры» игнорируют APR и реагируют только на цену, «атакующие» целенаправленно дестабилизируют стейк.

Многократные прогоны. Один прогон — один исход. 100 прогонов с разными seed дают распределение исходов. Вопрос не «что произойдёт», а «в каком проценте прогонов стейк падает ниже 20% supply».

Инструменты

Для примера в этой статье достаточно NumPy + Matplotlib. Для более сложных моделей:

cadCAD — Python-фреймворк от BlockScience. Формализует модель как цепочку «состояние → политика → механизм обновления». Использовался для моделирования Filecoin; radCAD (CADLabs) применялся для Ethereum validator economics. Хороший выбор, когда модель перерастает один скрипт.

radCAD — независимая реализация движка cadCAD от CADLabs. Совместима со структурой модели (state variables, policies, state update functions), но быстрее и требует меньше шаблонного кода.

Mesa — популярный Python-фреймворк для ABM общего назначения (v3.x). Лучшая документация и активное сообщество; многие токеномисты используют Mesa вместо cadCAD.

Gauntlet Predator — закрытая ABM-платформа для DeFi risk assessment (Aave, Compound, MakerDAO). Индустриальный стандарт для симуляций ликвидности.

TokenSPICE — симулятор от Ocean Protocol. Работает с реальными EVM-контрактами через локальную EVM-сеть (Ganache). Тестирует не абстрактную модель, а конкретный Solidity-код. Проект не поддерживается с 2023 года, но код доступен.

Порядок работы

  1. Спроектируйте экономику в таблице. Allocation, вестинг, эмиссия, unit-экономика. Убедитесь, что модель предложения сходится.
  2. Определите критический механизм. Что может сломаться? Стейкинг, governance, ликвидность?
  3. Опишите типы агентов. Кто участники, какие у них цели? Какие параметры варьируются?
  4. Запустите 100+ прогонов. Один прогон ничего не доказывает.
  5. Анализируйте хвосты. Не средний исход, а 5-й перцентиль — что в 5% худших сценариев?
  6. Итерируйте параметры механизма. Цель — устойчивость в 95%+ прогонов.
Чек-лист: нужна ли агентная модель
  • В системе есть участники с конкурирующими интересами
  • Действия одного участника влияют на условия для других
  • Есть механизмы с обратной связью (стейкинг, AMM, bonding curve)
  • Важно понять устойчивость к экстремальным сценариям
  • Распределение позиций сильно неравномерное (есть киты)
  • Система включает governance с голосованием

3+ пунктов — агентная модель окупит вложения. 0–1 — начните с табличной модели.

Нужна агентная модель для вашего проекта?

Мы проектируем токеномику и проверяем её симуляциями — от табличных моделей до агентного моделирования

Обсудить проект