myco-bonding-curve/notebooks/04_composed_system.ipynb

275 lines
9.1 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Composed MYCO System\n",
"\n",
"Full system simulation combining financial deposits, commitment channels, and reserve management."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"\n",
"%matplotlib inline\n",
"plt.rcParams['figure.figsize'] = (14, 5)\n",
"plt.rcParams['figure.dpi'] = 100"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Token Launch Scenario\n",
"\n",
"50 depositors over 30 days, then some redemptions at days 60-90."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from src.composed.simulator import scenario_token_launch\n",
"\n",
"np.random.seed(42)\n",
"result = scenario_token_launch(n_assets=3, total_raise=100_000, n_depositors=50, duration=90)\n",
"\n",
"fig, axes = plt.subplots(2, 2, figsize=(14, 10))\n",
"\n",
"# Supply\n",
"ax = axes[0, 0]\n",
"ax.plot(result.times, result.supply, 'b-', linewidth=2)\n",
"ax.set_xlabel('Day')\n",
"ax.set_ylabel('MYCO Supply')\n",
"ax.set_title('Token Supply Over Time')\n",
"ax.axvspan(0, 30, alpha=0.1, color='green', label='Deposit phase')\n",
"ax.axvspan(60, 90, alpha=0.1, color='red', label='Redemption phase')\n",
"ax.legend()\n",
"\n",
"# Reserve Value\n",
"ax = axes[0, 1]\n",
"ax.plot(result.times, result.reserve_value, 'g-', linewidth=2)\n",
"ax.set_xlabel('Day')\n",
"ax.set_ylabel('Reserve Value (USD)')\n",
"ax.set_title('Total Reserve Value')\n",
"\n",
"# Backing Ratio\n",
"ax = axes[1, 0]\n",
"ax.plot(result.times, result.backing_ratio, 'r-', linewidth=2)\n",
"ax.axhline(y=1.0, color='k', linestyle='--', alpha=0.5, label='Par (1:1)')\n",
"ax.set_xlabel('Day')\n",
"ax.set_ylabel('Backing Ratio')\n",
"ax.set_title('Backing Ratio (Reserve / Supply)')\n",
"ax.legend()\n",
"\n",
"# Cumulative minted vs redeemed\n",
"ax = axes[1, 1]\n",
"ax.plot(result.times, result.financial_minted, 'b-', label='Financial minted')\n",
"ax.plot(result.times, result.total_redeemed, 'r-', label='Total redeemed')\n",
"ax.set_xlabel('Day')\n",
"ax.set_ylabel('MYCO')\n",
"ax.set_title('Cumulative Minted vs Redeemed')\n",
"ax.legend()\n",
"\n",
"plt.tight_layout()\n",
"plt.show()\n",
"\n",
"print(f'Final supply: {result.supply[-1]:,.2f} MYCO')\n",
"print(f'Final reserve: ${result.reserve_value[-1]:,.2f}')\n",
"print(f'Final backing ratio: {result.backing_ratio[-1]:.4f}')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Bank Run Scenario\n",
"\n",
"All holders try to redeem simultaneously. Flow dampening protects remaining holders."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from src.composed.simulator import scenario_bank_run\n",
"\n",
"result = scenario_bank_run(initial_reserve=100_000, n_assets=3, redemption_fraction=0.05, duration=100)\n",
"\n",
"fig, axes = plt.subplots(1, 3, figsize=(18, 5))\n",
"\n",
"ax = axes[0]\n",
"ax.plot(result.times, result.supply, 'b-', linewidth=2)\n",
"ax.set_xlabel('Day')\n",
"ax.set_ylabel('MYCO Supply')\n",
"ax.set_title('Supply During Bank Run')\n",
"ax.axvline(x=10, color='r', linestyle='--', alpha=0.5, label='Run starts')\n",
"ax.legend()\n",
"\n",
"ax = axes[1]\n",
"ax.plot(result.times, result.reserve_value, 'g-', linewidth=2)\n",
"ax.set_xlabel('Day')\n",
"ax.set_ylabel('Reserve Value')\n",
"ax.set_title('Reserve Preservation (flow dampening)')\n",
"ax.axvline(x=10, color='r', linestyle='--', alpha=0.5)\n",
"\n",
"ax = axes[2]\n",
"ax.plot(result.times, result.backing_ratio, 'r-', linewidth=2)\n",
"ax.axhline(y=1.0, color='k', linestyle='--', alpha=0.5)\n",
"ax.set_xlabel('Day')\n",
"ax.set_ylabel('Backing Ratio')\n",
"ax.set_title('Backing Ratio During Bank Run')\n",
"\n",
"plt.tight_layout()\n",
"plt.show()\n",
"\n",
"print(f'Reserve preserved: ${result.reserve_value[-1]:,.2f} ({result.reserve_value[-1]/100000*100:.1f}% of initial)')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Mixed Issuance Scenario\n",
"\n",
"Monthly financial deposits + weekly labor contributions over 1 year."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from src.composed.simulator import scenario_mixed_issuance\n",
"\n",
"result = scenario_mixed_issuance(n_assets=3, duration=365)\n",
"\n",
"fig, axes = plt.subplots(2, 2, figsize=(14, 10))\n",
"\n",
"ax = axes[0, 0]\n",
"ax.plot(result.times, result.supply, 'b-', linewidth=2)\n",
"ax.set_xlabel('Day')\n",
"ax.set_ylabel('MYCO Supply')\n",
"ax.set_title('Total Supply (Financial + Commitment)')\n",
"\n",
"ax = axes[0, 1]\n",
"ax.plot(result.times, result.financial_minted, 'b-', label='Financial')\n",
"ax.plot(result.times, result.commitment_minted, 'g-', label='Commitment')\n",
"ax.set_xlabel('Day')\n",
"ax.set_ylabel('Cumulative MYCO')\n",
"ax.set_title('Financial vs Commitment Issuance')\n",
"ax.legend()\n",
"\n",
"ax = axes[1, 0]\n",
"ax.plot(result.times, result.backing_ratio, 'r-', linewidth=2)\n",
"ax.axhline(y=1.0, color='k', linestyle='--', alpha=0.5)\n",
"ax.set_xlabel('Day')\n",
"ax.set_ylabel('Backing Ratio')\n",
"ax.set_title('Backing Ratio (diluted by commitment minting)')\n",
"\n",
"ax = axes[1, 1]\n",
"ax.plot(result.times, result.imbalance, 'purple', linewidth=2)\n",
"ax.set_xlabel('Day')\n",
"ax.set_ylabel('Imbalance')\n",
"ax.set_title('Reserve Imbalance Over Time')\n",
"\n",
"plt.tight_layout()\n",
"plt.show()\n",
"\n",
"fin = result.financial_minted[-1]\n",
"com = result.commitment_minted[-1]\n",
"total = fin + com\n",
"print(f'Financial minted: {fin:,.2f} ({fin/total*100:.1f}%)')\n",
"print(f'Commitment minted: {com:,.2f} ({com/total*100:.1f}%)')\n",
"print(f'Final backing ratio: {result.backing_ratio[-1]:.4f}')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Interactive: Custom Deposit/Redeem"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from src.composed.myco_surface import MycoSystem, MycoSystemConfig\n",
"\n",
"system = MycoSystem(MycoSystemConfig(n_reserve_assets=3))\n",
"\n",
"# Series of operations\n",
"operations = [\n",
" ('deposit', np.array([5000.0, 3000.0, 2000.0]), 0),\n",
" ('deposit', np.array([1000.0, 1000.0, 1000.0]), 1),\n",
" ('deposit', np.array([2000.0, 500.0, 500.0]), 2), # Imbalanced\n",
" ('redeem', 500.0, 5),\n",
" ('deposit', np.array([1000.0, 1000.0, 1000.0]), 10),\n",
" ('redeem', 1000.0, 15),\n",
" ('redeem', 2000.0, 16), # Rapid redemptions → flow penalty\n",
"]\n",
"\n",
"log = []\n",
"for op, amount, t in operations:\n",
" if op == 'deposit':\n",
" minted, meta = system.deposit(amount, float(t))\n",
" metrics = system.get_metrics()\n",
" log.append({\n",
" 'time': t, 'op': 'deposit', 'value': float(np.sum(amount)),\n",
" 'minted': minted, 'supply': metrics['supply'],\n",
" 'reserve': metrics['reserve_value'], 'br': metrics['backing_ratio'],\n",
" 'fee': meta.get('fee_rate', 0),\n",
" })\n",
" else:\n",
" amounts_out, meta = system.redeem(amount, float(t))\n",
" metrics = system.get_metrics()\n",
" log.append({\n",
" 'time': t, 'op': 'redeem', 'value': float(np.sum(amounts_out)),\n",
" 'burned': amount, 'supply': metrics['supply'],\n",
" 'reserve': metrics['reserve_value'], 'br': metrics['backing_ratio'],\n",
" 'flow_penalty': meta.get('flow_penalty', 1.0),\n",
" })\n",
"\n",
"# Display log\n",
"print(f'{\"Time\":>5} {\"Op\":>8} {\"Value\":>10} {\"Supply\":>12} {\"Reserve\":>12} {\"BR\":>8} {\"Extra\":>15}')\n",
"print('-' * 75)\n",
"for entry in log:\n",
" extra = ''\n",
" if entry['op'] == 'deposit':\n",
" extra = f'fee={entry[\"fee\"]:.4f}'\n",
" else:\n",
" extra = f'penalty={entry.get(\"flow_penalty\", 1.0):.4f}'\n",
" print(f'{entry[\"time\"]:>5} {entry[\"op\"]:>8} {entry[\"value\"]:>10.2f} {entry[\"supply\"]:>12.2f} {entry[\"reserve\"]:>12.2f} {entry[\"br\"]:>8.4f} {extra:>15}')"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python",
"version": "3.11.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}