Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import math
- import statistics as stat
- import random
- import numpy as np
- import matplotlib.pyplot as plt
- '''
- Most recent update: 2020-10-16
- Code written by Hikaru Sunakawa (@shammoo25 on Telegram), 2020-07-16, Japan.
- This script simulates AMPL economics with user-defined initial conditions. You are able to configure the initial
- AMPL price, AMPL supply and the amount of AMPL in your wallet. You must also choose how many days you want to simulate,
- and how many simulations you want to perform. You may also choose to plot the results, by configuring the plot_results
- and max_plots parameters. At the end of the script, when all simulations have been performed, statistics about the
- simulations will be printed to the console.
- The volatiltiy and demand coefficients used in this configuration produce "adequately similar" price action (based
- purely on a qualitative assessment of the output simulation plots versus the actual AMPL data plots over the last 90
- days), but these coefficients can be changed to whatever you like for the purpose of experimentation.
- AMPL and Oracle price changes are random, determined using volatility ranges and dynamically changing weights which
- favour either an up or down price movement.
- Note that the random number functions do not have defined seeds, meaning that the results will be different every time
- the script is run
- Please modify the code as you see fit if you feel that it can be improved or corrected. Please let me know on my
- telegram handle above if you have any interesting suggestions
- '''
- ############################################ MODIFY THE FOLLOWING VALUES ###############################################
- sim_number = 10000 # Number of simulations to perform (if doing more than 1000 simulations, set print_daily and plot_results to False to vastly improve performance)
- days = 90 # Number of days per simulation
- print_daily = False # Print the daily stats to the console during each simulation? Will improve performance if False
- plot_results = False # Plot simulation results? True or False. Will output the maximum number of figures determined by max_plots
- max_plots = 20 # Maximum number of plot figures to output (1 plot figure per simulation)
- init_ampl_balance = 1000 # Initial amount of AMPL in wallet
- init_ampl_price = 0.92 # [USD] Initial price of AMPL
- init_supply = 166929000.0 # Initial TOTAL supply of AMPL
- price_target = 1.014 # [USD] Price target used in rebase calculation
- demand_threshold = 0.05 # [USD] The difference between AMPL price and $1.00, used for changing demand coefficients
- equal_chance = False # If this is True, then every day there is the same chance of a upward or downward price movement, and the demand coefficients below are not used
- low_price_demand = 1.70 # The higher this coefficient, the higher the chance of an upward price movement when price is within demand_threshold of $1.00
- high_price_demand = 1.20 # The higher this coefficient, the higher the chance of an upward price movement when price is outside demand_threshold of $1.00
- min_low_volatility = 0.02 # The higher this value, the higher the minimum possible value of the daily AMPL and Oracle price swings when price is within demand_threshold of $1.00
- max_low_volatility = 0.08 # The higher this value, the higher the maximum possible value of the daily AMPL and Oracle price swings when price is within demand_threshold of $1.00
- min_high_volatility = 0.10 # The higher this value, the higher the minimum possible value of the daily AMPL and Oracle price swings when price is outside demand_threshold of $1.00
- max_high_volatility = 0.30 # The higher this value, the higher the maximum possible value of the daily AMPL and Oracle price swings when price is outside demand_threshold of $1.00
- ########################################################################################################################
- # Constants
- rebase_lag = 10 # [days] Lag used in rebase calculation
- contraction_threshold = price_target * 0.95 # [USD] Oracle rate window lower value. Between this value and expansion_threshold, rebase will not take place
- expansion_threshold = price_target * 1.05 # [USD] Oracle rate window higher value
- # Initialize
- days += 1
- ampl_price = np.zeros((days, sim_number))
- supply = np.zeros((days, sim_number))
- my_balance = np.zeros((days, sim_number))
- rebase = np.zeros((days, sim_number))
- market_cap = np.zeros((days, sim_number))
- ampl_value = np.zeros((days, sim_number))
- init_ampl_value = init_ampl_price * init_ampl_balance
- init_market_cap = init_supply * init_ampl_price
- ################################################### SIMULATE ###########################################################
- for s in range(sim_number):
- for x in range(days):
- if x == 0:
- ampl_price[0, s] = init_ampl_price
- supply[0, s] = init_supply
- my_balance[0, s] = init_ampl_balance
- rebase[0, s] = 0.0
- market_cap[0, s] = init_market_cap
- ampl_value[0, s] = init_ampl_value
- else:
- # Determine demand strength and volatility
- if math.fabs(ampl_price[x - 1, s] - 1.00) < demand_threshold:
- demand_strength = random.uniform(1.0, low_price_demand)
- volatility = random.uniform(min_low_volatility, max_low_volatility)
- else:
- demand_strength = random.uniform(min(low_price_demand, high_price_demand),
- max(low_price_demand, high_price_demand))
- volatility = random.uniform(min_high_volatility, max_high_volatility)
- # Determine direction of movement
- direction_list = [1.0] + [-1.0]
- if equal_chance:
- up_weight = 50
- down_weight = 50
- else:
- up_weight = demand_strength
- down_weight = 1 / demand_strength
- direction = random.choices(direction_list, weights=(up_weight, down_weight), k=1)
- direction = float(direction[0])
- # Calculate price, balance, supply and market cap
- ampl_price[x, s] = ampl_price[x - 1, s] * (1.0 + (volatility * direction)) # Calculate pre-rebase AMPL price
- # Determine Oracle rate based on average AMPL price (using previous post-rebase price and current pre-rebase price), then calculate subsequent rebase amount
- oracle_price = (ampl_price[x - 1, s] + ampl_price[x, s]) / 2
- if contraction_threshold <= oracle_price <= expansion_threshold:
- rebase[x, s] = 0.0
- else:
- rebase[x, s] = (oracle_price - price_target) / price_target / rebase_lag
- ampl_price[x, s] *= (1 - rebase[x - 1, s]) # Calculate post-rebase AMPL price
- my_balance[x, s] = my_balance[x - 1, s] * (1 + rebase[x, s])
- supply[x, s] = supply[x - 1, s] * (1 + rebase[x, s])
- market_cap[x, s] = ampl_price[x, s] * supply[x, s]
- ampl_value[x, s] = my_balance[x, s] * ampl_price[x, s]
- if print_daily:
- print("Sim " + str(s + 1),
- "| Day " + str(x),
- "| AMPL price = $" + str('%.2f' % (ampl_price[x, s])),
- "| AMPL Balance = " + f'{my_balance[x, s]:,.0f}',
- "| AMPL Value = $" + str('%.3f' % (ampl_value[x, s])),
- "| Rebase = " + str('%.3f' % (100 * rebase[x, s])) + "%",
- "| Supply = " + f'{supply[x, s]:,.0f}',
- "| Market Cap = $" + f'{market_cap[x, s]:,.0f}')
- if plot_results and s < max_plots:
- fig, (ax1, ax2, ax3, ax4, ax5) = plt.subplots(5, figsize=(10, 8), constrained_layout=True)
- fig.suptitle('Simulation ' + str(s + 1))
- ax1.plot(ampl_price[:, s])
- ax1.set_title('AMPL Price (USD)')
- ax1.grid(b=True, which='both', axis='both')
- ax2.plot(market_cap[:, s], 'tab:orange')
- ax2.set_title('Market Cap')
- ax2.grid(b=True, which='both', axis='both')
- ax3.plot(supply[:, s], 'tab:cyan')
- ax3.set_title('Supply')
- ax3.grid(b=True, which='both', axis='both')
- ax4.plot(my_balance[:, s], 'tab:green')
- ax4.set_title('Amount of AMPL Held in Wallet')
- ax4.grid(b=True, which='both', axis='both')
- ax5.plot(ampl_value[:, s], 'tab:red')
- ax5.set_title('USD Value of AMPL in Wallet')
- ax5.grid(b=True, which='both', axis='both')
- if print_daily == False:
- percent_complete = s / sim_number * 100
- if percent_complete % 1 == 0:
- print('\r', str(int(percent_complete)) + '% of simulations performed', end='')
- else:
- print('-------------------------------------------------------------------------------------------------------'
- '-----------------------------------------------------------------------------')
- print('\r', 'All simulations performed', end='')
- ############################################### CALCULATE STATISTICS ##################################################
- price_up = 0
- supply_up = 0
- balance_up = 0
- value_up = 0
- mc_up = 0
- price_diff_percent = np.zeros(sim_number)
- price_diff_dollar = np.zeros(sim_number)
- supply_diff = np.zeros(sim_number)
- supply_diff_percent = np.zeros(sim_number)
- balance_diff_percent = np.zeros(sim_number)
- balance_diff = np.zeros(sim_number)
- value_diff_percent = np.zeros(sim_number)
- value_diff_dollar = np.zeros(sim_number)
- mc_diff_percent = np.zeros(sim_number)
- mc_diff_dollar = np.zeros(sim_number)
- drawdown = np.zeros(sim_number)
- recovery = np.zeros(sim_number)
- for s in range(sim_number):
- if ampl_price[-1, s] > ampl_price[0, s]:
- price_up += 1
- if supply[-1, s] > supply[0, s]:
- supply_up += 1
- if my_balance[-1, s] > my_balance[0, s]:
- balance_up += 1
- if ampl_value[-1, s] > ampl_value[0, s]:
- value_up += 1
- if market_cap[-1, s] > market_cap[0, s]:
- mc_up += 1
- price_diff_percent[s] = (ampl_price[-1, s] / ampl_price[0, s] * 100) - 100
- price_diff_dollar[s] = ampl_price[-1, s] - ampl_price[0, s]
- supply_diff_percent[s] = (supply[-1, s] / [supply[0, s]] * 100) - 100
- supply_diff[s] = supply[-1, s] - supply[0, s]
- balance_diff_percent[s] = (my_balance[-1, s] / my_balance[0, s] * 100) - 100
- balance_diff[s] = my_balance[-1, s] - my_balance[0, s]
- value_diff_percent[s] = (ampl_value[-1, s] / ampl_value[0, s] * 100) - 100
- value_diff_dollar[s] = ampl_value[-1, s] - ampl_value[0, s]
- mc_diff_percent[s] = (market_cap[-1, s] / market_cap[0, s] * 100) - 100
- mc_diff_dollar[s] = market_cap[-1, s] - market_cap[0, s]
- min_market_cap = min(market_cap[:, s])
- drawdown[s] = max(0, 100 - (min_market_cap / init_market_cap * 100))
- max_drawdown_index = np.argmax(drawdown)
- print(f'\n**************************************** OVERALL STATISTICS *****************************************')
- print(str(price_up) + ' out of ' + str(sim_number) + ' (' + str(price_up / sim_number * 100)
- + '%) simulations ended with AMPL price higher than the initial price')
- print(str(supply_up) + ' out of ' + str(sim_number) + ' (' + str(supply_up / sim_number * 100)
- + '%) simulations ended with AMPL supply higher than the initial amount')
- print(str(mc_up) + ' out of ' + str(sim_number) + ' (' + str(mc_up / sim_number * 100)
- + '%) simulations ended with market cap higher than the initial value')
- print(str(balance_up) + ' out of ' + str(sim_number) + ' (' + str(balance_up / sim_number * 100)
- + '%) simulations ended with amount of AMPL in wallet higher than the initial amount')
- print(str(value_up) + ' out of ' + str(sim_number) + ' (' + str(value_up / sim_number * 100)
- + '%) simulations ended with value of AMPL (USD) in wallet higher than the initial value')
- # AMPL Price
- print(f'\nAMPL Price Changes:\n' + 'The mean price on the last day was $' + f'{stat.mean(ampl_price[-1, :]):,.2f}'
- + str('. This is a difference of $')
- + str('%.2f' % stat.mean(price_diff_dollar)) + ' ('
- + str('%.2f' % stat.mean(price_diff_percent)) + '%) from the initial price of $' + str('%.2f' % init_ampl_price))
- print('The median price on the last day was $' + f'{stat.median(ampl_price[-1, :]):,.2f}'
- + str('. This is a difference of $')
- + str('%.2f' % stat.median(price_diff_dollar)) + ' ('
- + str('%.2f' % stat.median(price_diff_percent)) + '%) from the initial price of $'
- + str('%.2f' % init_ampl_price))
- # AMPL Supply
- print(f'\nAMPL Supply Changes:\n'
- + 'The mean supply at the end of ' + str(days - 1) + ' days was ' + f'{stat.mean(supply[-1, :]):,.0f}'
- + '. This is a change of ' + f'{stat.mean(supply_diff):,.0f}'
- + ' (' + f'{stat.mean(supply_diff_percent):,.2f}'
- + '%) from the initial supply of ' + f'{init_supply:,.0f}')
- print('The median supply at the end of ' + str(days - 1)
- + ' days was ' + f'{stat.median(supply[-1, :]):,.0f}'
- + '. This is a change of ' + f'{stat.median(supply_diff):,.0f}'
- + ' (' + f'{stat.median(supply_diff_percent):,.2f}'
- + '%) from the initial supply of ' + f'{init_supply:,.0f}')
- # Market Cap
- print(f'\nMarket Cap Changes:\n'
- + 'The mean market cap at the end of ' + str(days - 1) + ' days was $' + f'{stat.mean(market_cap[-1, :]):,.0f}'
- + '. This is a change of $' + f'{stat.mean(mc_diff_dollar):,.0f}'
- + ' (' + f'{stat.mean(mc_diff_percent):,.2f}'
- + '%) from the initial amount of $' + f'{init_market_cap:,.0f}')
- print('The median market cap at the end of ' + str(days - 1) + ' days was $' + f'{stat.median(market_cap[-1, :]):,.0f}'
- + '. This is a change of $' + f'{stat.median(mc_diff_dollar):,.0f}'
- + ' (' + f'{stat.median(mc_diff_percent):,.2f}'
- + '%) from the initial amount of $' + f'{init_market_cap:,.0f}')
- # Amount of AMPL in Wallet
- print(f'\nAMPL Wallet Balance Changes:\n' + 'The mean amount of held AMPL at the end of ' + str(
- days - 1) + ' days was ' + f'{stat.mean(my_balance[-1, :]):,.2f}'
- + ' AMPL. This is a change of ' + f'{stat.mean(balance_diff):,.2f}'
- + ' (' + f'{stat.mean(balance_diff_percent):,.2f}'
- + '%) from the initial amount of ' + f'{init_ampl_balance:,.2f}' + ' AMPL.')
- print('The median amount of held AMPL at the end of ' + str(
- days - 1) + ' days was ' + f'{stat.median(my_balance[-1, :]):,.2f}'
- + ' AMPL. This is a change of ' + f'{stat.median(balance_diff):,.2f}'
- + ' (' + f'{stat.median(balance_diff_percent):,.2f}'
- + '%) from the initial amount of ' + f'{init_ampl_balance:,.2f}' + ' AMPL')
- # USD Value of AMPL in Wallet
- print(f'\nAMPL Wallet USD Value Changes:\n' + 'The mean amount of USD value of held AMPL at the end of ' + str(
- days - 1) + ' days was $' + f'{stat.mean(ampl_value[-1, :]):,.2f}'
- + '. This is a change of $' + f'{stat.mean(value_diff_dollar):,.2f}'
- + ' (' + f'{stat.mean(value_diff_percent):,.2f}'
- + '%) from the initial amount of $' + f'{init_ampl_value:,.2f}')
- print('The median amount of USD value held AMPL at the end of ' + str(days - 1) + ' days was $'
- + f'{stat.median(ampl_value[-1, :]):,.2f}'
- + '. This is a change of $' + f'{stat.median((ampl_value[-1, :]) - init_ampl_value):,.2f}'
- + ' (' + f'{stat.median(value_diff_percent):,.2f}'
- + '%) from the initial amount of $' + f'{init_ampl_value:,.2f}')
- # Drawdown
- print(f'\nMarket Cap Drawdown % from the Initial USD Value (equivalent to drawdown % of USD value of AMPL in wallet):\n'
- + 'The mean percentage drawdown during the ' + str(days - 1)
- + ' day period was -' + f'{stat.mean(drawdown):,.2f}' + '%')
- print('The median percentage drawdown during the ' + str(days - 1)
- + ' day period was -' + f'{stat.median(drawdown):,.2f}' + '%')
- print('The largest drawndown out of all the simulations was -' + f'{(max(drawdown)):,.2f}' + '%'
- + ' in simulation #' + str(max_drawdown_index + 1))
- print('Simulation #' + str(max_drawdown_index + 1) + ' ended with a market cap of $'
- + f'{market_cap[-1, max_drawdown_index]:,.0f}' + ' which is a change of $'
- + f'{market_cap[-1, max_drawdown_index] - init_market_cap:,.0f}'
- + ' (' + f'{(market_cap[-1, max_drawdown_index] / market_cap[0, max_drawdown_index] * 100) - 100:,.2f}'
- + '%) from the initial market cap of $' + f'{init_market_cap:,.0f}')
- if plot_results:
- plt.show()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement